GithubHelp home page GithubHelp logo

tektoncd / dashboard Goto Github PK

View Code? Open in Web Editor NEW
849.0 20.0 256.0 58.5 MB

A dashboard for Tekton!

License: Apache License 2.0

JavaScript 89.45% HTML 0.03% Go 2.08% Shell 2.43% SCSS 5.45% Dockerfile 0.16% MDX 0.41%
tekton pipeline dashboard ui hacktoberfest

dashboard's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dashboard's Issues

Improve front-end state management

The front end currently presents data from a number of APIs in most of its views. The logic required to correlate the pieces from different sources is subtly different between e.g. Pipeline and PipelineRun vs Task and TaskRun. This leads to unwanted complexity, additional maintenance overhead, and increases the risk of bugs.

So far we have used a small number of top-level container components which are responsible for making API calls and manipulating the responses into a form suitable for consumption by the presentation components. This approach will not scale long-term, especially as the data needs to be combined / presented in new and subtly different ways for other features / views.

Introducing a consistent state management layer which normalises the data received from the APIs and is isolated from the presentational layer will allow for greater flexibility, improved consistency, and easier testing.

Plan:

  • redux (with react-redux + redux-thunk for async actions) as a single source of truth
    • container components bound to store via react-redux's connect, and provide relevant view of state as props to pure presentational components
  • normalizr to ensure consistent and efficient storage of the data according to a simple schema
    • shelving this for now
  • Pipeline, Task, PipelineResource, etc., indexed by name/id as appropriate
  • action creators responsible for API calls (thunks that make API calls and dispatch actions)
    • view triggers action creators (use mapDispatchToProps to bind to store)
  • selectors (using reselect or similar) to retrieve content from the store, containers/components shouldn't know the shape of the store
    • use mapStateToProps to provide appropriate inputs to the containers
  • utilities for generating common reducer + action creator patterns
    • shelving this for now

Web panelling for 'manually create a pipelinerun'

We have a REST API that supports the manual creation of pipelineruns.

The parameters that a user must provide will be specific to the pipeline they're creating a run for - luckily they're all defined in the pipeline.

The UI will need to obtain and parse the desired pipeline before populating the fields that need user entry.

Install new pipelines from Git

Extend the dashboard so that a user can specify the Git coordinates of new Pipeline, Task and other definitions that should be installed into the target namespace. We can use the API delivered under #24 to run a simple git clone / kubectl apply pipeline to achieve this.

In this first instance, any git credentials must be set up by the user separately. We can add in credential support once we've fleshed that out.

PUT 204 test doesn't check for all PUTs

We think we have a test bug here.

https://github.com/tektoncd/dashboard/pull/48/files#diff-d5fa729f55b16ff94238fa6931ff4724R82

Background
@jessm12 and I are adding PipelineRun creation code and Jess noticed when adding a new POST endpoint, that it's tested and we don't have a fake PipelineRun or fake Pipeline. In noticing this, she's picked up the Put204 method has a double post check in there instead of puts.

This means that when we run the unit tests as they are now on master, the existing PUT method for updating a PipelineRun (changing its status) is untested (because we don't have a fake PipelineRun or fake Pipeline).

Code
We think the problematic code is here:

func TestPut204(t *testing.T) {
	t.Log("Checking 204 for PUT Routes")
	// Creating resources first, then update
	var resourceLocations []string
	postFunc := func(t *testing.T, request *http.Request, response *http.Response) {
		contentLocation, ok := response.Header["Content-Location"]
		if !ok {
			t.Errorf("Content-Location header not provided in %s method for resource type: %s",request.Method,getResourceType(request.URL.Path, request.Method))
		} else {
			// "Content-Location" header is only set with single value
			resourceLocations = append(resourceLocations,contentLocation[0])
		}
	}
	makeRequests(t,methodMap[http.MethodPost],http.MethodPost,postFunc) << should be .MethodPut

The unit tests give us:

--- PASS: TestPut204 (0.00s)
    routes_test.go:70: Checking 204 for PUT Routes
    routes_test.go:95: POST method: /v1/namespaces/fake/credential
    routes_test.go:103: Response from server: &{201 Created 201 HTTP/1.1 1 1 map[Content-Length:[0] Content-Location:[/v1/namespaces/fake/credential/a309a104-3134-43d7-a142-9487fe86390b] Date:[Wed, 17 Apr 2019 09:25:38 GMT]] {} 0 [] false false map[] 0xc000480200 <nil>}
    routes_test.go:95: PUT method: /v1/namespaces/fake/credential/a309a104-3134-43d7-a142-9487fe86390b
    routes_test.go:103: Response from server: &{204 No Content 204 HTTP/1.1 1 1 map[Date:[Wed, 17 Apr 2019 09:25:38 GMT]] {} 0 [] false false map[] 0xc000558100 <nil>}

which isn't picking up the PipelineRun PUT API.

When we make it use PUTS we get:

--- FAIL: TestPut204 (0.00s)
    routes_test.go:68: Checking 204 for PUT Routes
    routes_test.go:93: PUT method: /v1/namespaces/fake/pipelinerun/{name}
    routes_test.go:164: Fake template does not exist for crdType: pipelinerun
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
        panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x8 pc=0x6e3a5f]

Deployment should be labelled

Under install/tekton-dashboard-deployment.yaml, the deployment should have a label that allows for easier manipulation of it, such as getting and deleting the deployment

Associate credentials with service account

Credential REST API provides CURD operation for the secrets. The secrets must be patched into the service account used by the PipelineRun or TaskRun. It must be done manually now. This issue enhances the credential REST API to patch the service account automatically when the secret is created or deleted.

Credentials API needs to consider taking a service account as input

When patching secrets onto the service account, we might want to think about the fact that the user should be able to choose/specify a service account.

One reason why we might want to do this and move away from an environment variable, is because I think that you will restrict access to repositories.... this might need to be validated, but I believe you cannot have multiple secrets on a service account where the annotation on the secrets are for the same git server. This would mean you would need to use an account that can access all repos you might be interested in using from the git server.

Might it not be the case that for security reasons, different users might have to use different service accounts patched with their own secrets/credentials?

Add Pipeline Run Cancel Selection

Any running pipeline in the pipeline runs list will have a cancel selection at the end of the line

Screen Shot 2019-04-16 at 17 34 39

When selected the actor will be presented with a modal dialog to confirm.

Screen Shot 2019-04-16 at 17 34 58

REST API for creating PipelineRuns

Under this issue add a REST API endpoint that will take parameters and create a new PipelineRun for a specified Pipeline

When creating a new PipelineRun the information that will need to be provided to the POST method is as follows:

  • The name of the Pipeline to use for that PipelineRun
  • Information relating to the PipelineResources for a PipelineRun, if required
  • Information relating to the repository for that PipelineRun
  • Helm and Registry secret names, if required

The request will be namespaced and this is the namespace that the PipelineRun will occur in

Automate running of go tests

There are a number of test files for the go code, but no automation kicking off these tests.

Automated testing of the code is a pretty fundamental requirement.... this may mean working out how to integrate with prow which much of tekton seems to use already?

Support for non-default namespaces

Currently if your installation is not in default you must edit index.js:

export function getAPI(type, id = '', namespace = 'default') {

and change 'default' to the target namespace. That's not great! Since the dashboard is expected to be deployed to the tekton-pipelines namespace it should be able to manage pipelines installed to any valid and accessible namespace on the cluster. At the very least, the user should be able to select the current namespace from a pull-down list of valid options.

Much more detailed getting started section

Currently at the getting started section just says build image and run it.
But if you visit the localhost:9097 url (port-forwarding) you cannot see anything.

You need to run npm install & npm start to access web ui locally

Expose tasks as a top level construct

Expose tasks as a top level construct with navigation to tasks and task runs.

New root navigation

Screen Shot 2019-04-13 at 15 40 49

Tasks view. This show all tasks.

Screen Shot 2019-04-13 at 15 41 00

Task Runs for the task selected in the previous navigation with no selected task run.

Screen Shot 2019-04-13 at 15 41 18

Selected task no selected step. Header updates with task run name and task run time for the given selected task

Screen Shot 2019-04-13 at 15 41 26

Task and step selection. Similar to pipeline run navigation

Screen Shot 2019-04-13 at 15 41 34

Notification where the selected task has never run.

Screen Shot 2019-04-13 at 15 42 22

@skaegi for review on the above. Alan and Myself iterated on it Thursday and Friday and settled on this layout. It Does add some of the navigation outlined in the design tickets.

Add development docs

We should have a DEVELOPMENT.md document that's likely going to share many steps from here but with any known limitations documented, and an easy to use development cycle for anyone to follow.

Currently we've not tested this using GKE and we don't yet support ko (but these would be awesome to have!) and so any such gotchas should be made clear.

Logs are not displayed when clicking on a step in a PipelineRun

The front-end and back-end handling of TaskRun logs are not currently in sync and need to be aligned to ensure the new combined project works as expected. The front-end Log container and presentational components should be updated to handle the changed taskrunlog response format returned by the API.

UX & Visual Design for Tekton Dashboard

  • Create the proposed user flow for a scalable UI that will house Tekton capabilities. First address pipeline view with monitoring (dashboard). Design should be scalable to include eventing etc. moving forward.

  • Using the IBM DL, apply visual design to the experience outlined above.
    Consider this look and feel may eventually need to wrap into the overall design of ICAP.

Linking to Simon's issues in their dev repo:/
#35
#37
#38

Websocket test is flaky

dibbles fixed this, we've got assigning problems atm

Run the Go unit tests in our Dockerfile several times in a row, sometimes you observe:

DeletionsRecorded not equal to 10, recorded only 9--- FAIL: TestPipelineRunWebsocket (17.00s)
    websocket_test.go:75: Enter TestPipelineRunWebsocket...
    websocket_test.go:239: DeletionsRecorded not equal to 10, recorded only 9
FAIL
exit status 1
FAIL	github.com/tektoncd/dashboard/pkg/endpoints	24.096s
The command '/bin/sh -c CGO_ENABLED=0 NAMESPACE=default GOOS=linux go test -v' returned a non-zero code: 1

I ran this in a loop with the following straight from a stackoverflow Bash example.

I saw the failure twice in 18 failures, then stopped my script to make said issue.

i=0
output_file=tests.txt
rm -f $output_file
touch $output_file

while [ $i -lt 20 ] ; do
  echo "Running test $i"
  docker build -t foo -f Dockerfile_test . >> $output_file.txt
  i=$[$i+1]
done

First seen here. @dibbles thinks this may be due to incrementing the counter variables in a non-atomic way and as such it's a test problem.

Interesting code in question: https://github.com/tektoncd/dashboard/blob/master/pkg/endpoints/websocket_test.go#L126 and the vars are declared:

// Counters for pipelineruns websocket test
var CreationsRecorded = 0
var UpdatesRecorded = 0
var DeletionsRecorded = 0

Dashboard extension support

It would be great if the dashboard offered an extension mechanism. 'Extensions' could be packaged behind Kube services, with labels of the form,

label: tekton-dashboard-extension: true
label: tekton-dashboard-endpoints: greatThings

The extension should then be able to supply panelling into a react component on the dashboard - perhaps a new tab? - whose .js code would be able to interact with the extension via the /greatThings proxied endpoint. Extensions could support managing web hooks, log archiving, or integrations with other third party product.

Update front end to handle relative paths

At the moment if the front end app is deployed to for example /tekton-dashboard it will fail to load parts of the UI. Similarly this means it can't be accessed using kube proxy at its context http://localhost:8001/api/v1/namespaces/tekton-pipelines/services/https:tekton-dashboard:/proxy/

Document API definitions

Now that we have DEVELOPMENT.md we should document our APIs. We'll want return codes, paths, any errors that can happen, and bonus points for any json snippets!

Allow namespace selection

At the moment the dashboard will only show resources in the default namespace.

This effort is to track listing namespaces and selecting a namespace for the pipeline and task runs views

API GET /v1/namespaces

Investigate ko for building

While adding #27 @vdemeester asked a question in a review comment: Out of curiosity, what doesn't work with ko ?, and I've honestly not tried using ko before with this project.

Prove we can use ko to build and push and update DEVELOPMENT.md if so.

For tektoncd/pipeline I see lots of kodata folders (e.g. here).

It would be very cool to recommend doing a ko apply and it'll just build and deploy our containers; at the least for now we can make sure it builds and deploys the backend using what's at install.

Useful resources:

We've had success building and pushing knative repositories and tektoncd/pipeline both locally and to public Dockerhub, including updating the readme for tektoncd/pipeline to use a local registry. It's likely we can be more inline with what's done for tektoncd/pipeline and if so let's advocate that.

Document compatible versions (pipeline with dashboard) in our readme

To avoid any surprises we should include a table of known good versions into our main readme, right at the top.

I've tested that we work with Tekton pipelines 0.2, I'd be interested to see if we work with master currently and if Tekton 0.1.

It would be very cool to have a compatibility table that's automatically updated, or we have public builds/tests available to all that just makes sure our code builds against master, so we know when something is broken. We should also look into having an equivalent to https://github.com/tektoncd/pipeline/blob/master/api_compatibility_policy.md.

For anyone who wants to work on this above point in particular, I do have a bunch of scripts I'm happy to share that iterates over each version of Tekton pipelines we care for, and any branches/versions of this dashboard, and knative for any extensions we want to make, and simply runs the Go tests after installing each component. I know a colleague is working on a real "app test" as well that would be awesome to use as the source for this compatibility table eventually.

Dashboard information architecture

Here is a first pass at the information architecture for the dashboard. Please provide feedback.

Tekton

  • Pipeline
  • PipelineRun
  • PipelineResource
  • Task
  • TaskRun

Namespace

Extension Category 1 [from Service metadata] Knative Eventing

  • Extension topic 1
  • Extension topic 2

Extension Category 2 [from Service metadata] Native worker agent

  • Extension topic 1
  • Extension topic 2

Document APIs using Swagger / OpenAPI spec

This would allow us to provide richer documentation in a standard format, as well as interactive examples that would ease development.

Open API spec: https://swagger.io/specification/
Swagger UI example: https://petstore.swagger.io/

Something like:

openapi: 3.0.0
info:
  title: Tekton Dashboard
  description: Optional multiline or single-line description in [CommonMark](http://commonmark.org/help/) or HTML.
  version: 0.0.1
servers:
  - url: '{protocol}://{host}:{port}/v1/namespaces/{namespace}'
    description: Optional server description, e.g. Main (production) server
    variables:
      protocol:
        enum:
          - http
          - https
        default: http
      host:
        default: localhost
      port:
        default: 9097
      namespace:
        default: tekton-pipelines
        description: namespace where the Tekton resources (Pipelines, Tasks, etc.) are installed
paths:
  /pipeline/:
    get:
      summary: Returns a list of Pipelines
      description: Optional extended description in CommonMark or HTML.
      parameters:
        - in: path
          name: namespace
          schema:
            type: string
            example: tekton-pipelines
          required: true
          description: namespace in which the Pipelines are installed
      responses:
        '200':
          description: A JSON array of Pipelines
          content:
            application/json:
              schema: 
                type: array
                items: 
                  type: string
  /pipeline/{name}:
    get:
      summary: Returns a sinlge Pipeline
      description: Optional extended description in CommonMark or HTML.
      parameters:
        - in: path
          name: name
          schema:
            type: string
            example: demo-pipeline
          required: true
          description: name of the Pipeline to retrieve
      responses:
        '200':
          description: A JSON object representing the requested Pipeline
          content:
            application/json:
              schema: 
                type: object

will produce:
image

image

Does Dashboard backend need to define its own REST API

I was looking at the dashboard and I am wondering If there is a need for REST endpoints on the dashboard backend? Kubernetes already has an API server and tekton does everything as CRDs, wouldn't it be easier and more portable to develop the UI against kubernetes API server and tekton CRDs? What is the added value of the new REST endpoints?

Top-level GUI layout

Posting a proposed image of the Top-level GUI layout to begin iterating on a design.

k8s-bw

Run any pipeline endpoint

The purpose of this issue is to provide an endpoint that creates a PipelineRun for any existing Pipeline, and to discuss how to go about implementing this endpoint.

The Pull Request for issue #24 is a good start to creating PipelineRuns. But it was limited to creating specific PipelineRuns for the Pipeline templates within our templates repository https://github.com/pipeline-hotel/example-pipelines (here's a reference to the comment: #33 (comment))

Moving forward, the user should be able to start PipelineRuns for any Pipeline definition they have created. To do this, they must be able to specify the following (according to the Tekton docs https://github.com/tektoncd/pipeline/blob/master/docs/pipelineruns.md):

  • pipelineRef
  • trigger
  • resources
  • params
  • serviceAccount
  • timeout
  • [nodeSelector]
  • [affinity]

If we assume that the PipelineResources, Secrets, ServiceAccount, etc. that the PipelineRun uses already exist, then we do not need to do very much work to create the PipelineRun. All we have to do is convert the input JSON to the Go client PipelineRun (and PipelineRunSpec), then create the PipelineRun resource. The input JSON would look very similar to a K8s JSON definition of a PipelineRun. With this approach, the user would create all the resources required for the PipelineRun individually.

If we create PipelineRuns in this simplified manner, then it frees up our code to focus on verification. We can add checks to verify that all the required resources specified by the PipelineRun actually do exist and play nicely with each other. For example, we could verify that if a PipelineRun uses a private Git PipelineResource, then the ServiceAccount must have a Secret with the proper annotation for https://github.com (and if it doesn't, then our UI can prompt the user to create & patch the secret).

This approach is different from that in issue #24, which creates all the resources necessary for the PipelineRun, and then creates the PipelineRun, knowing that everything is set up properly. While it works well for specific Pipelines, I think it will be hard to extend to work for any type of Pipeline.

I think the approach of creating resources individually with an emphasis on verification that I outlined above will work well for creating general PipelineRuns. What do you think @jessm12 @a-roberts ? Is there an alternate implementation that you have in mind? @skaegi What are the front-end concerns for this kind of PipelineRun endpoint?

Adjust extension context root handling

This issue proposes a slight change to the context root handling mechanism for extensions introduced under #34.

The initial design mounts a context root /foo in an extension onto /foo at the main dashboard. This could become a problem: extensions could clash with each other, or the main dashboard. Instead we propose that:

  • Each extension is mounted onto /v1/extension/extension-name/ at the dashboard
  • Requests to /v1/extension/extension-name/ are routed to / at the extension in question. / at the extension is always exposed in the expectation that many extensions will only need one endpoint.
  • If tekton.dashboard.endpoints is set to foo then /v1/extension/extension-name/foo is routed to /foo at the extension
  • Multiple context roots can be specified by using the . character to separate them: e.g. if tekton.dashboard.endpoints: foo.bar then /v1/extension/extension-name/foo is routed to /foo and /v1/extension/extension-name/bar is routed to /bar at the extension.

Go test race conditions on `./pkg/endpoints`

There is some data race (caught by go test -race) on ./pkg/endpoints.

  • on TestLogWebsocket
{"level":"info","msg":"Adding API for websocket"}
{"level":"debug","msg":"Upgrading connection to websocket..."}
{"level":"debug","msg":"Upgrading connection to websocket..."}
{"level":"debug","msg":"Upgrading connection to websocket..."}
{"level":"debug","msg":"Upgrading connection to websocket..."}
{"level":"debug","msg":"Upgrading connection to websocket..."}
{"level":"debug","msg":"Upgrading connection to websocket..."}
{"level":"debug","msg":"Upgrading connection to websocket..."}
{"level":"debug","msg":"Upgrading connection to websocket..."}
{"level":"debug","msg":"Upgrading connection to websocket..."}
{"level":"debug","msg":"Upgrading connection to websocket..."}
==================
WARNING: DATA RACE
Read at 0x00c00047aee0 by goroutine 86:
  github.com/tektoncd/dashboard/pkg/websocket.poll()
      /go/src/github.com/tektoncd/dashboard/pkg/websocket/websocket.go:73 +0x1ca

Previous write at 0x00c00047aee0 by goroutine 85:
  github.com/tektoncd/dashboard/pkg/websocket.poll.func1()
      /go/src/github.com/tektoncd/dashboard/pkg/websocket/websocket.go:63 +0x46
  github.com/tektoncd/dashboard/vendor/github.com/gorilla/websocket.(*Conn).advanceFrame()
      /go/src/github.com/tektoncd/dashboard/vendor/github.com/gorilla/websocket/conn.go:892 +0xac3
  github.com/tektoncd/dashboard/vendor/github.com/gorilla/websocket.(*Conn).NextReader()
      /go/src/github.com/tektoncd/dashboard/vendor/github.com/gorilla/websocket/conn.go:947 +0x10a
  github.com/tektoncd/dashboard/vendor/github.com/gorilla/websocket.(*Conn).ReadMessage()
      /go/src/github.com/tektoncd/dashboard/vendor/github.com/gorilla/websocket/conn.go:1028 +0x50
  github.com/tektoncd/dashboard/pkg/websocket.readControl()
      /go/src/github.com/tektoncd/dashboard/pkg/websocket/websocket.go:51 +0x50

Goroutine 86 (running) created at:
  github.com/tektoncd/dashboard/pkg/websocket.WriteOnlyWebsocket()
      /go/src/github.com/tektoncd/dashboard/pkg/websocket/websocket.go:45 +0x99
  github.com/tektoncd/dashboard/pkg/endpoints.Resource.establishPipelineLogsWebsocket()
      /go/src/github.com/tektoncd/dashboard/pkg/endpoints/websocket.go:37 +0xa0
  github.com/tektoncd/dashboard/pkg/endpoints.Resource.establishPipelineLogsWebsocket-fm()
      /go/src/github.com/tektoncd/dashboard/pkg/endpoints/websocket.go:32 +0x70
  github.com/tektoncd/dashboard/vendor/github.com/emicklei/go-restful.(*Container).dispatch()
      /go/src/github.com/tektoncd/dashboard/vendor/github.com/emicklei/go-restful/container.go:288 +0x108a
  github.com/tektoncd/dashboard/vendor/github.com/emicklei/go-restful.(*Container).dispatch-fm()
      /go/src/github.com/tektoncd/dashboard/vendor/github.com/emicklei/go-restful/container.go:203 +0x5f
  net/http.HandlerFunc.ServeHTTP()
      /usr/local/go/src/net/http/server.go:1995 +0x51
  net/http.(*ServeMux).ServeHTTP()
      /usr/local/go/src/net/http/server.go:2375 +0x28a
  github.com/tektoncd/dashboard/vendor/github.com/emicklei/go-restful.(*Container).ServeHTTP()
      /go/src/github.com/tektoncd/dashboard/vendor/github.com/emicklei/go-restful/container.go:303 +0x6e
  net/http.serverHandler.ServeHTTP()
      /usr/local/go/src/net/http/server.go:2774 +0xc4
  net/http.(*conn).serve()
      /usr/local/go/src/net/http/server.go:1878 +0x807

Goroutine 85 (running) created at:
  github.com/tektoncd/dashboard/pkg/websocket.WriteOnlyWebsocket()
      /go/src/github.com/tektoncd/dashboard/pkg/websocket/websocket.go:44 +0x77
  github.com/tektoncd/dashboard/pkg/endpoints.Resource.establishPipelineLogsWebsocket()
      /go/src/github.com/tektoncd/dashboard/pkg/endpoints/websocket.go:37 +0xa0
  github.com/tektoncd/dashboard/pkg/endpoints.Resource.establishPipelineLogsWebsocket-fm()
      /go/src/github.com/tektoncd/dashboard/pkg/endpoints/websocket.go:32 +0x70
  github.com/tektoncd/dashboard/vendor/github.com/emicklei/go-restful.(*Container).dispatch()
      /go/src/github.com/tektoncd/dashboard/vendor/github.com/emicklei/go-restful/container.go:288 +0x108a
  github.com/tektoncd/dashboard/vendor/github.com/emicklei/go-restful.(*Container).dispatch-fm()
      /go/src/github.com/tektoncd/dashboard/vendor/github.com/emicklei/go-restful/container.go:203 +0x5f
  net/http.HandlerFunc.ServeHTTP()
      /usr/local/go/src/net/http/server.go:1995 +0x51
  net/http.(*ServeMux).ServeHTTP()
      /usr/local/go/src/net/http/server.go:2375 +0x28a
  github.com/tektoncd/dashboard/vendor/github.com/emicklei/go-restful.(*Container).ServeHTTP()
      /go/src/github.com/tektoncd/dashboard/vendor/github.com/emicklei/go-restful/container.go:303 +0x6e
  net/http.serverHandler.ServeHTTP()
      /usr/local/go/src/net/http/server.go:2774 +0xc4
  net/http.(*conn).serve()
      /usr/local/go/src/net/http/server.go:1878 +0x807
==================
{"level":"error","msg":"websocket connection to client lost: websocket: close 1005 (no status)"}
==================
WARNING: DATA RACE
Write at 0x00c0000b11c0 by goroutine 88:
  github.com/tektoncd/dashboard/pkg/broadcaster.(*Broadcaster).Unsubscribe()
      /go/src/github.com/tektoncd/dashboard/pkg/broadcaster/broadcaster.go:123 +0xd7
  github.com/tektoncd/dashboard/pkg/websocket.readControl()
      /go/src/github.com/tektoncd/dashboard/pkg/websocket/websocket.go:53 +0x121

Previous read at 0x00c0000b11c0 by goroutine 74:
  github.com/tektoncd/dashboard/pkg/websocket.write()
      /go/src/github.com/tektoncd/dashboard/pkg/broadcaster/broadcaster.go:51 +0x53
  github.com/tektoncd/dashboard/pkg/websocket.WriteOnlyWebsocket()
      /go/src/github.com/tektoncd/dashboard/pkg/websocket/websocket.go:46 +0xb1
  github.com/tektoncd/dashboard/pkg/endpoints.Resource.establishPipelineLogsWebsocket()
      /go/src/github.com/tektoncd/dashboard/pkg/endpoints/websocket.go:37 +0xa0
  github.com/tektoncd/dashboard/pkg/endpoints.Resource.establishPipelineLogsWebsocket-fm()
      /go/src/github.com/tektoncd/dashboard/pkg/endpoints/websocket.go:32 +0x70
  github.com/tektoncd/dashboard/vendor/github.com/emicklei/go-restful.(*Container).dispatch()
      /go/src/github.com/tektoncd/dashboard/vendor/github.com/emicklei/go-restful/container.go:288 +0x108a
  github.com/tektoncd/dashboard/vendor/github.com/emicklei/go-restful.(*Container).dispatch-fm()
      /go/src/github.com/tektoncd/dashboard/vendor/github.com/emicklei/go-restful/container.go:203 +0x5f
  net/http.HandlerFunc.ServeHTTP()
      /usr/local/go/src/net/http/server.go:1995 +0x51
  net/http.(*ServeMux).ServeHTTP()
      /usr/local/go/src/net/http/server.go:2375 +0x28a
  github.com/tektoncd/dashboard/vendor/github.com/emicklei/go-restful.(*Container).ServeHTTP()
      /go/src/github.com/tektoncd/dashboard/vendor/github.com/emicklei/go-restful/container.go:303 +0x6e
  net/http.serverHandler.ServeHTTP()
      /usr/local/go/src/net/http/server.go:2774 +0xc4
  net/http.(*conn).serve()
      /usr/local/go/src/net/http/server.go:1878 +0x807

Goroutine 88 (running) created at:
  github.com/tektoncd/dashboard/pkg/websocket.WriteOnlyWebsocket()
      /go/src/github.com/tektoncd/dashboard/pkg/websocket/websocket.go:44 +0x77
  github.com/tektoncd/dashboard/pkg/endpoints.Resource.establishPipelineLogsWebsocket()
      /go/src/github.com/tektoncd/dashboard/pkg/endpoints/websocket.go:37 +0xa0
  github.com/tektoncd/dashboard/pkg/endpoints.Resource.establishPipelineLogsWebsocket-fm()
      /go/src/github.com/tektoncd/dashboard/pkg/endpoints/websocket.go:32 +0x70
  github.com/tektoncd/dashboard/vendor/github.com/emicklei/go-restful.(*Container).dispatch()
      /go/src/github.com/tektoncd/dashboard/vendor/github.com/emicklei/go-restful/container.go:288 +0x108a
  github.com/tektoncd/dashboard/vendor/github.com/emicklei/go-restful.(*Container).dispatch-fm()
      /go/src/github.com/tektoncd/dashboard/vendor/github.com/emicklei/go-restful/container.go:203 +0x5f
  net/http.HandlerFunc.ServeHTTP()
      /usr/local/go/src/net/http/server.go:1995 +0x51
  net/http.(*ServeMux).ServeHTTP()
      /usr/local/go/src/net/http/server.go:2375 +0x28a
  github.com/tektoncd/dashboard/vendor/github.com/emicklei/go-restful.(*Container).ServeHTTP()
      /go/src/github.com/tektoncd/dashboard/vendor/github.com/emicklei/go-restful/container.go:303 +0x6e
  net/http.serverHandler.ServeHTTP()
      /usr/local/go/src/net/http/server.go:2774 +0xc4
  net/http.(*conn).serve()
      /usr/local/go/src/net/http/server.go:1878 +0x807

Goroutine 74 (running) created at:
  net/http.(*Server).Serve()
      /usr/local/go/src/net/http/server.go:2884 +0x4c4
  net/http/httptest.(*Server).goServe.func1()
      /usr/local/go/src/net/http/httptest/server.go:298 +0xac
==================
{"level":"error","msg":"websocket connection to client lost: websocket: close 1005 (no status)"}
{"level":"error","msg":"websocket connection to client lost: websocket: close 1005 (no status)"}
{"level":"error","msg":"websocket connection to client lost: websocket: close 1005 (no status)"}
{"level":"error","msg":"websocket connection to client lost: websocket: close 1005 (no status)"}
{"level":"error","msg":"websocket connection to client lost: websocket: close 1005 (no status)"}
{"level":"error","msg":"websocket connection to client lost: websocket: close 1005 (no status)"}
{"level":"error","msg":"websocket connection to client lost: websocket: close 1005 (no status)"}
{"level":"error","msg":"websocket connection to client lost: websocket: close 1005 (no status)"}
{"level":"error","msg":"websocket connection to client lost: websocket: close 1005 (no status)"}
websocket_test.go:49: Enter TestLogWebsocket...
websocket_test.go:64: Waiting for clients to terminate...
websocket_test.go:74: Exit TestLogWebsocket
testing.go:809: race detected during execution of test
  • on TestPipelineRunWebsocket
{"level":"info","msg":"Adding API for websocket"}
{"level":"debug","msg":"Into StartPipelineRunController"}
{"level":"info","msg":"PipelineRun Controller Started"}
{"level":"debug","msg":"Upgrading connection to websocket..."}
{"level":"debug","msg":"Upgrading connection to websocket..."}
{"level":"debug","msg":"Upgrading connection to websocket..."}
{"level":"debug","msg":"Upgrading connection to websocket..."}
{"level":"debug","msg":"Upgrading connection to websocket..."}
{"level":"debug","msg":"Upgrading connection to websocket..."}
{"level":"debug","msg":"Upgrading connection to websocket..."}
{"level":"debug","msg":"Upgrading connection to websocket..."}
{"level":"debug","msg":"Upgrading connection to websocket..."}
{"level":"debug","msg":"Upgrading connection to websocket..."}
Creating pipelinerun
{"level":"debug","msg":"In pipelineRunCreated"}
{PipelineRunCreated map[metadata:map[creationTimestamp:<nil> name:WebsocketPipelinerun namespace:ns1 resourceVersion:123456] spec:map[Status: params:<nil> pipelineRef:map[name:] resources:<nil> serviceAccount: trigger:map[type:]] status:map[conditions:<nil>]]}
{PipelineRunCreated map[metadata:map[creationTimestamp:<nil> name:WebsocketPipelinerun namespace:ns1 resourceVersion:123456] spec:map[Status: params:<nil> pipelineRef:map[name:] resources:<nil> serviceAccount: trigger:map[type:]] status:map[conditions:<nil>]]}
{PipelineRunCreated map[metadata:map[creationTimestamp:<nil> name:WebsocketPipelinerun namespace:ns1 resourceVersion:123456] spec:map[Status: params:<nil> pipelineRef:map[name:] resources:<nil> serviceAccount: trigger:map[type:]] status:map[conditions:<nil>]]}
{PipelineRunCreated map[metadata:map[creationTimestamp:<nil> name:WebsocketPipelinerun namespace:ns1 resourceVersion:123456] spec:map[Status: params:<nil> pipelineRef:map[name:] resources:<nil> serviceAccount: trigger:map[type:]] status:map[conditions:<nil>]]}
{PipelineRunCreated map[metadata:map[creationTimestamp:<nil> name:WebsocketPipelinerun namespace:ns1 resourceVersion:123456] spec:map[Status: params:<nil> pipelineRef:map[name:] resources:<nil> serviceAccount: trigger:map[type:]] status:map[conditions:<nil>]]}
{PipelineRunCreated map[metadata:map[creationTimestamp:<nil> name:WebsocketPipelinerun namespace:ns1 resourceVersion:123456] spec:map[Status: params:<nil> pipelineRef:map[name:] resources:<nil> serviceAccount: trigger:map[type:]] status:map[conditions:<nil>]]}
{PipelineRunCreated map[metadata:map[creationTimestamp:<nil> name:WebsocketPipelinerun namespace:ns1 resourceVersion:123456] spec:map[Status: params:<nil> pipelineRef:map[name:] resources:<nil> serviceAccount: trigger:map[type:]] status:map[conditions:<nil>]]}
{PipelineRunCreated map[metadata:map[creationTimestamp:<nil> name:WebsocketPipelinerun namespace:ns1 resourceVersion:123456] spec:map[Status: params:<nil> pipelineRef:map[name:] resources:<nil> serviceAccount: trigger:map[type:]] status:map[conditions:<nil>]]}
{PipelineRunCreated map[metadata:map[creationTimestamp:<nil> name:WebsocketPipelinerun namespace:ns1 resourceVersion:123456] spec:map[Status: params:<nil> pipelineRef:map[name:] resources:<nil> serviceAccount: trigger:map[type:]] status:map[conditions:<nil>]]}
{PipelineRunCreated map[metadata:map[creationTimestamp:<nil> name:WebsocketPipelinerun namespace:ns1 resourceVersion:123456] spec:map[Status: params:<nil> pipelineRef:map[name:] resources:<nil> serviceAccount: trigger:map[type:]] status:map[conditions:<nil>]]}
Updating pipelinerun WebsocketPipelinerun
{PipelineRunUpdated map[metadata:map[creationTimestamp:<nil> name:WebsocketPipelinerun namespace:ns1 resourceVersion:654321] spec:map[Status: params:<nil> pipelineRef:map[name:] resources:<nil> serviceAccount: trigger:map[type:]] status:map[conditions:<nil>]]}
{PipelineRunUpdated map[metadata:map[creationTimestamp:<nil> name:WebsocketPipelinerun namespace:ns1 resourceVersion:654321] spec:map[Status: params:<nil> pipelineRef:map[name:] resources:<nil> serviceAccount: trigger:map[type:]] status:map[conditions:<nil>]]}
{PipelineRunUpdated map[metadata:map[creationTimestamp:<nil> name:WebsocketPipelinerun namespace:ns1 resourceVersion:654321] spec:map[Status: params:<nil> pipelineRef:map[name:] resources:<nil> serviceAccount: trigger:map[type:]] status:map[conditions:<nil>]]}
{PipelineRunUpdated map[metadata:map[creationTimestamp:<nil> name:WebsocketPipelinerun namespace:ns1 resourceVersion:654321] spec:map[Status: params:<nil> pipelineRef:map[name:] resources:<nil> serviceAccount: trigger:map[type:]] status:map[conditions:<nil>]]}
{PipelineRunUpdated map[metadata:map[creationTimestamp:<nil> name:WebsocketPipelinerun namespace:ns1 resourceVersion:654321] spec:map[Status: params:<nil> pipelineRef:map[name:] resources:<nil> serviceAccount: trigger:map[type:]] status:map[conditions:<nil>]]}
{PipelineRunUpdated map[metadata:map[creationTimestamp:<nil> name:WebsocketPipelinerun namespace:ns1 resourceVersion:654321] spec:map[Status: params:<nil> pipelineRef:map[name:] resources:<nil> serviceAccount: trigger:map[type:]] status:map[conditions:<nil>]]}
{PipelineRunUpdated map[metadata:map[creationTimestamp:<nil> name:WebsocketPipelinerun namespace:ns1 resourceVersion:654321] spec:map[Status: params:<nil> pipelineRef:map[name:] resources:<nil> serviceAccount: trigger:map[type:]] status:map[conditions:<nil>]]}
{PipelineRunUpdated map[metadata:map[creationTimestamp:<nil> name:WebsocketPipelinerun namespace:ns1 resourceVersion:654321] spec:map[Status: params:<nil> pipelineRef:map[name:] resources:<nil> serviceAccount: trigger:map[type:]] status:map[conditions:<nil>]]}
{PipelineRunUpdated map[metadata:map[creationTimestamp:<nil> name:WebsocketPipelinerun namespace:ns1 resourceVersion:654321] spec:map[Status: params:<nil> pipelineRef:map[name:] resources:<nil> serviceAccount: trigger:map[type:]] status:map[conditions:<nil>]]}
{PipelineRunUpdated map[metadata:map[creationTimestamp:<nil> name:WebsocketPipelinerun namespace:ns1 resourceVersion:654321] spec:map[Status: params:<nil> pipelineRef:map[name:] resources:<nil> serviceAccount: trigger:map[type:]] status:map[conditions:<nil>]]}
Deleting pipelinerun: WebsocketPipelinerun
{"level":"debug","msg":"In pipelineRunDeleted"}
{PipelineRunDeleted map[metadata:map[creationTimestamp:<nil> name:WebsocketPipelinerun namespace:ns1 resourceVersion:654321] spec:map[Status: params:<nil> pipelineRef:map[name:] resources:<nil> serviceAccount: trigger:map[type:]] status:map[conditions:<nil>]]}
{PipelineRunDeleted map[metadata:map[creationTimestamp:<nil> name:WebsocketPipelinerun namespace:ns1 resourceVersion:654321] spec:map[Status: params:<nil> pipelineRef:map[name:] resources:<nil> serviceAccount: trigger:map[type:]] status:map[conditions:<nil>]]}
{PipelineRunDeleted map[metadata:map[creationTimestamp:<nil> name:WebsocketPipelinerun namespace:ns1 resourceVersion:654321] spec:map[Status: params:<nil> pipelineRef:map[name:] resources:<nil> serviceAccount: trigger:map[type:]] status:map[conditions:<nil>]]}
{PipelineRunDeleted map[metadata:map[creationTimestamp:<nil> name:WebsocketPipelinerun namespace:ns1 resourceVersion:654321] spec:map[Status: params:<nil> pipelineRef:map[name:] resources:<nil> serviceAccount: trigger:map[type:]] status:map[conditions:<nil>]]}
{PipelineRunDeleted map[metadata:map[creationTimestamp:<nil> name:WebsocketPipelinerun namespace:ns1 resourceVersion:654321] spec:map[Status: params:<nil> pipelineRef:map[name:] resources:<nil> serviceAccount: trigger:map[type:]] status:map[conditions:<nil>]]}
{PipelineRunDeleted map[metadata:map[creationTimestamp:<nil> name:WebsocketPipelinerun namespace:ns1 resourceVersion:654321] spec:map[Status: params:<nil> pipelineRef:map[name:] resources:<nil> serviceAccount: trigger:map[type:]] status:map[conditions:<nil>]]}
{PipelineRunDeleted map[metadata:map[creationTimestamp:<nil> name:WebsocketPipelinerun namespace:ns1 resourceVersion:654321] spec:map[Status: params:<nil> pipelineRef:map[name:] resources:<nil> serviceAccount: trigger:map[type:]] status:map[conditions:<nil>]]}
{PipelineRunDeleted map[metadata:map[creationTimestamp:<nil> name:WebsocketPipelinerun namespace:ns1 resourceVersion:654321] spec:map[Status: params:<nil> pipelineRef:map[name:] resources:<nil> serviceAccount: trigger:map[type:]] status:map[conditions:<nil>]]}
{PipelineRunDeleted map[metadata:map[creationTimestamp:<nil> name:WebsocketPipelinerun namespace:ns1 resourceVersion:654321] spec:map[Status: params:<nil> pipelineRef:map[name:] resources:<nil> serviceAccount: trigger:map[type:]] status:map[conditions:<nil>]]}
{PipelineRunDeleted map[metadata:map[creationTimestamp:<nil> name:WebsocketPipelinerun namespace:ns1 resourceVersion:654321] spec:map[Status: params:<nil> pipelineRef:map[name:] resources:<nil> serviceAccount: trigger:map[type:]] status:map[conditions:<nil>]]}
==================
WARNING: DATA RACE
Read at 0x00000290c598 by goroutine 12:
  github.com/tektoncd/dashboard/pkg/endpoints.TestPipelineRunWebsocket()
      /go/src/github.com/tektoncd/dashboard/pkg/endpoints/websocket_test.go:115 +0x569
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:865 +0x163

Previous write at 0x00000290c598 by goroutine 140:
  github.com/tektoncd/dashboard/pkg/endpoints.clientWebsocket.func1()
      /go/src/github.com/tektoncd/dashboard/pkg/endpoints/websocket_test.go:172 +0x3ff

Goroutine 12 (running) created at:
  testing.(*T).Run()
      /usr/local/go/src/testing/testing.go:916 +0x699
  testing.runTests.func1()
      /usr/local/go/src/testing/testing.go:1157 +0xa8
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:865 +0x163
  testing.runTests()
      /usr/local/go/src/testing/testing.go:1155 +0x523
  testing.(*M).Run()
      /usr/local/go/src/testing/testing.go:1072 +0x2eb
  github.com/tektoncd/dashboard/pkg/endpoints.TestMain()
      /go/src/github.com/tektoncd/dashboard/pkg/endpoints/routes_test.go:82 +0xfba
  main.main()
      _testmain.go:86 +0x222

Goroutine 140 (running) created at:
  github.com/tektoncd/dashboard/pkg/endpoints.clientWebsocket()
      /go/src/github.com/tektoncd/dashboard/pkg/endpoints/websocket_test.go:143 +0x31c
==================
{"level":"error","msg":"websocket connection to client lost: websocket: close 1005 (no status)"}
{"level":"error","msg":"websocket connection to client lost: websocket: close 1005 (no status)"}
{"level":"error","msg":"websocket connection to client lost: websocket: close 1005 (no status)"}
{"level":"error","msg":"websocket connection to client lost: websocket: close 1005 (no status)"}
{"level":"error","msg":"websocket connection to client lost: websocket: close 1005 (no status)"}
{"level":"error","msg":"websocket connection to client lost: websocket: close 1005 (no status)"}
{"level":"error","msg":"websocket connection to client lost: websocket: close 1005 (no status)"}
{"level":"error","msg":"websocket connection to client lost: websocket: close 1005 (no status)"}
{"level":"error","msg":"websocket connection to client lost: websocket: close 1005 (no status)"}
{"level":"error","msg":"websocket connection to client lost: websocket: close 1005 (no status)"}
websocket_test.go:79: Enter TestPipelineRunWebsocket...
websocket_test.go:117: Waiting for clients to terminate...
websocket_test.go:127: Exit TestPipelineRunWebsocket
testing.go:809: race detected during execution of test

I disabled race detection on the CI for now (to bootstrap it), but this need to be fixed (so that we can re-enable race detections ๐Ÿ‘ผ )

cc @a-roberts

See https://tekton-releases.appspot.com/build/tekton-prow/pr-logs/pull/tektoncd_dashboard/72/pull-tekton-dashboard-tests/1120985522127245312/

Dashboard design that lets us navigate different objects

The current dashboard is simple and that's ok for now but will not let us do the full range of navigation that experience says will be valuable for this sort of tool. This issue is to track some ideas on what me might do with the dashboard UI

Fix URL handling for dev environment

The recent change to transparently handle non-root contexts in the URL is not fully compatible with the current webpack-dev-server configuration used in the dev environment. This can lead to API requests failing as they are not being rewritten correctly.

Add favicon

We're missing one, let's use the Tekton cat?

Support for actions on dashboard resources

Resources described by the dashboard should also permit "Actions". For example "deleting" a PipelineRun or "creating" a new PipelineRun from a Pipeline. To start we might use the universal kebab similar to...
image

Dashboard should display real time updates to status of resources

For example:

  • when viewing a list of PipelineRuns:
    • new PipelineRuns should be added to the list dynamically
    • the status of the displayed PipelinesRuns should be updated in real time
  • when viewing a single PipelineRun:
    • TaskRun / step status should be updated in realtime
    • logs should be updated in realtime
  • etc.

The back end should provide a websocket connection which publishes events to the front end.

Code exists today providing a dedicated websocket service for pipelineruns, and I have a test branch using that to dynamically update the PipelineRun list view in the front end.

The back end should provide a single websocket service through which all relevant events are sent, allowing the front end to maintain a single connection, rather than managing multiple parallel connections for various purposes.

Add development docs for front end

Update https://github.com/tektoncd/dashboard/blob/master/DEVELOPMENT.md to include instructions for developing / testing / running the front end code locally (i.e. outside the Tekton cluster) until #14 is complete.

Some relevant content from previous front end README for reference:

[![Build Status](buildStatusBadgeURL)](repoURL)
[![Component Storybook](https://img.shields.io/badge/component%20storybook-GHPages-blue.svg)](storybookURL)
[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat)](https://github.com/prettier/prettier)

# dashboard

React-based UI for Tekton pipelines

## Prerequisites

[Node.js & npm](https://nodejs.org/). See `engines` in [pacakge.json](./package.json) for versions used.

## Getting started

1. Fork and clone this repository locally.

   ```bash
   git clone [email protected]:/dashboard.git
   cd dashboard
   ```

1. Install dependencies.

   ```bash
   npm install
   ```

## Development server

Run `npm start` for a dev server. Navigate to `http://localhost:8000/` in your browser. The app will automatically hot-reload any changes to the source files, including CSS. If it is unable to hot-reload it will fallback to a full page refresh.

## Build

Run `npm run build` to build the project. The build artifacts will be stored in the `dist/` directory. This will perform a production build of the static resources. It correctly bundles React in production mode and optimizes the build for the best performance. Filenames include hashes to facilitate long-term caching.

## Running unit tests

Run `npm test` to execute the unit tests via [Jest](https://jestjs.io/) in interactive watch mode. This also generates a code coverage report by default.

Coverage threshold is set to 90%, if it falls below the threshold the test script will fail.

Tests are defined in `*.test.js` files alongside the code under test.

## Linting

Run `npm run lint` to execute the linter (eslint + prettier). This will ensure code follows the conventions and standards used by the project.

Run `npm run lint:fix` to automatically fix a number of types of problem including code style.

This project also uses `lint-staged` and `husky` to automatically run `eslint` and `prettier` on changed files in a pre-commit hook.

## Storybook

Run `npm run storybook` to start [storybook](https://storybook.js.org/) in development mode. Navigate to [`http://localhost:4000/`](http://localhost:4000/) in your browser. The app will automatically hot-reload any changes to the source files, including CSS.

Stories are defined in `*.stories.js` files alongside their components.

Run `npm run storybook:build` to build the static storybook files. The build artifacts will be stored in the `static-storybook/` directory and can be hosted on GitHub Pages or any other static resource server.



## Pipelines

[Travis](travisURL) will build all PRs and provide feedback on lint, build, and test results.

Push Tekton dashboard image on merge to master

Now that we have #13 in place (big shoutout to @vdemeester) for testing our code, we want to Docker build and push dashboard images: for example to gcr.io for anyone to pick up, test, experiment and use.

Important files to mention that I think will be of use: https://github.com/tektoncd/plumbing/blob/master/prow/config.yaml this denotes a "preSubmit" task that runs a script.

https://github.com/tektoncd/dashboard/blob/master/test/presubmit-tests.sh is how we currently run tests: this is said script for the "preSubmit" task.

If this was a Travis set up we would do the following, so we want to figure out how to do this with Prow.

script:
  # - BUILD IMAGE
  - export SHORT_COMMIT_ID=$(git rev-parse --short ${TRAVIS_COMMIT})
  - docker build -t ${IMAGE_NAME}:${SHORT_COMMIT_ID} -f Dockerfile .
  - docker build -t ${IMAGE_NAME}-test:${SHORT_COMMIT_ID} -f Dockerfile_test .
  # - TAG/PUSH IMAGE
  - if [[ "${TRAVIS_BRANCH}" == "master" ]] && [[ "${TRAVIS_PULL_REQUEST}" == "false" ]]; then
      docker login -u ${SOME_FUNCTIONAL_ID} -p ${SOME_API_KEY} ${REPO_NAME} ;
      docker tag ${IMAGE_NAME}:${SHORT_COMMIT_ID} ${REPO_NAME}/${IMAGE_NAME}:${SHORT_COMMIT_ID} ;
      docker push ${REPO_NAME}/${IMAGE_NAME}:${SHORT_COMMIT_ID} ;
      docker tag ${IMAGE_NAME}:${SHORT_COMMIT_ID} ${REPO_NAME}/${IMAGE_NAME}:latest ;
      docker push ${REPO_NAME}/${IMAGE_NAME}:latest ;
    fi

Perhaps we add a "post submit" task that does the pushing?

POST requests should return "201 Created"

Currently a POST request to create a new gitresource returns 204 No Content, whereas the general best practise for successful POST requests is to return 201 Created and to set the both data to the created data (ie, the POSTed data plus any additional fields like an ID that has been set).

An optional best practise is to also set the Location header to the URL that you would use to interact with that resource (ie. the URL you would use to GET or DELETE the resource).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.