Skip to content

Commit

Permalink
Merge pull request #21 from mdb/render-header
Browse files Browse the repository at this point in the history
render the run header in output
  • Loading branch information
mdb committed Nov 17, 2022
2 parents fb5911b + 9847dba commit b493ec1
Show file tree
Hide file tree
Showing 10 changed files with 350 additions and 145 deletions.
2 changes: 1 addition & 1 deletion Makefile
@@ -1,6 +1,6 @@
SOURCE=./...
GOFMT_FILES?=$$(find . -type f -name '*.go')
VERSION?=0.0.4
VERSION?=0.1.0

default: build

Expand Down
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -57,7 +57,7 @@ Install a locally built `gh-dispatch` for use as `gh dispatch`:
make install
```

Run acceptance tests against a local `gh-dispatch` installation:
Run acceptance tests against a local `gh-dispatch` installation, verifying the local `gh-dispatch` is able to trigger dispatch events and render the expected output:

```
make acc-test
Expand Down
Binary file modified demo.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion demo.tape
Expand Up @@ -46,7 +46,7 @@ Set FontSize 28
Set Width 1200
Set Height 650

Type 'gh dispatch repository --repo "mdb/gh-dispatch" --event-type "hello" --client-payload "{\"name\": \"mike\"}" --workflow "Hello"'
Type 'gh dispatch repository --event-type "hello" --client-payload "{\"name\": \"mike\"}" --workflow "Hello"'

Sleep 500ms

Expand Down
15 changes: 13 additions & 2 deletions internal/dispatch/fixtures_test.go
@@ -1,6 +1,14 @@
package dispatch

var (
currentUserResponse string = `{
"data": {
"viewer": {
"login": "mdb"
}
}
}`

getWorkflowsResponse string = `{
"total_count": 1,
"workflows": [{
Expand All @@ -10,17 +18,20 @@ var (
}`

getWorkflowResponse string = `{
"id": 456
"id": 456,
"name": "foo"
}`

getWorkflowRunsResponse string = `{
"total_count": 1,
"workflow_runs": [{
"id": 123,
"workflow_id": 456,
"event": "%s",
"name": "foo",
"status": "queued",
"conclusion": null
"conclusion": null,
"jobs_url": "https://api.github.com/repos/%s/actions/runs/123/jobs"
}]
}`

Expand Down
41 changes: 21 additions & 20 deletions internal/dispatch/repository.go
Expand Up @@ -4,13 +4,13 @@ import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"strings"

"github.com/MakeNowJust/heredoc"
cliapi "github.com/cli/cli/v2/api"
runShared "github.com/cli/cli/v2/pkg/cmd/run/shared"
"github.com/cli/cli/v2/pkg/cmd/workflow/shared"
"github.com/cli/cli/v2/pkg/iostreams"
"github.com/cli/go-gh"
"github.com/cli/go-gh/pkg/api"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -59,18 +59,25 @@ func NewCmdRepository() *cobra.Command {
--workflow Hello
`),
RunE: func(cmd *cobra.Command, args []string) error {
repo, _ := cmd.Flags().GetString("repo")
r, _ := cmd.Flags().GetString("repo")
repoParts := strings.Split(r, "/")
repo := &ghRepo{
Owner: repoParts[0],
Name: repoParts[1],
}

b := []byte(repositoryClientPayload)
var repoClientPayload interface{}
json.Unmarshal(b, &repoClientPayload)

ios := iostreams.System()

ghClient, _ := cliapi.NewHTTPClient(cliapi.HTTPClientOptions{
Config: &Conf{},
})
dOptions := dispatchOptions{
repo: repo,
httpTransport: http.DefaultTransport,
io: ios,
repo: repo,
httpClient: ghClient,
io: ios,
}

return repositoryDispatchRun(&repositoryDispatchOptions{
Expand Down Expand Up @@ -102,22 +109,16 @@ func repositoryDispatchRun(opts *repositoryDispatchOptions) error {
return err
}

client, err := gh.RESTClient(&api.ClientOptions{
Transport: opts.httpTransport,
AuthToken: opts.authToken,
})
if err != nil {
return err
}
ghClient := cliapi.NewClientFromHTTP(opts.httpClient)

var in interface{}
err = client.Post(fmt.Sprintf("repos/%s/dispatches", opts.repo), &buf, &in)
err = ghClient.REST(opts.repo.RepoHost(), "POST", fmt.Sprintf("repos/%s/dispatches", opts.repo.RepoFullName()), &buf, &in)
if err != nil {
return err
}

var wfs shared.WorkflowsPayload
err = client.Get(fmt.Sprintf("repos/%s/actions/workflows", opts.repo), &wfs)
err = ghClient.REST(opts.repo.RepoHost(), "GET", fmt.Sprintf("repos/%s/actions/workflows", opts.repo.RepoFullName()), nil, &wfs)
if err != nil {
return err
}
Expand All @@ -130,15 +131,15 @@ func repositoryDispatchRun(opts *repositoryDispatchOptions) error {
}
}

runID, err := getRunID(client, opts.repo, "repository_dispatch", workflowID)
runID, err := getRunID(ghClient, opts.repo, "repository_dispatch", workflowID)
if err != nil {
return err
}

run, err := getRun(client, opts.repo, runID)
run, err := runShared.GetRun(ghClient, opts.repo, fmt.Sprintf("%d", runID))
if err != nil {
return fmt.Errorf("failed to get run: %w", err)
}

return render(opts.io, client, opts.repo, run)
return render(opts.io, ghClient, opts.repo, run)
}
135 changes: 113 additions & 22 deletions internal/dispatch/repository_test.go
Expand Up @@ -2,6 +2,7 @@ package dispatch

import (
"fmt"
"net/http"
"net/url"
"testing"

Expand All @@ -11,7 +12,13 @@ import (
)

func TestRepositoryDispatchRun(t *testing.T) {
repo := "OWNER/REPO"
ghRepo := &ghRepo{
Name: "REPO",
Owner: "OWNER",
}
repo := ghRepo.RepoFullName()
event := "repository_dispatch"

tests := []struct {
name string
opts *repositoryDispatchOptions
Expand All @@ -35,36 +42,76 @@ func TestRepositoryDispatchRun(t *testing.T) {
httpmock.REST("GET", fmt.Sprintf("repos/%s/actions/workflows", repo)),
httpmock.StringResponse(getWorkflowsResponse))

reg.Register(
httpmock.GraphQL("query UserCurrent{viewer{login}}"),
httpmock.StringResponse(currentUserResponse))

v := url.Values{}
v.Set("event", "repository_dispatch")
v.Set("per_page", "50")

reg.Register(
httpmock.QueryMatcher("GET", fmt.Sprintf("repos/%s/actions/workflows/456/runs", repo), v),
httpmock.StringResponse(fmt.Sprintf(getWorkflowRunsResponse, event, repo)))

q := url.Values{}
q.Set("per_page", "100")
q.Set("page", "1")

reg.Register(
httpmock.QueryMatcher("GET", fmt.Sprintf("repos/%s/actions/workflows", repo), q),
httpmock.StringResponse(fmt.Sprintf(getWorkflowRunsResponse, event, repo)))

reg.Register(
httpmock.QueryMatcher("GET", fmt.Sprintf("repos/%s/actions/runs", repo), v),
httpmock.StringResponse(getWorkflowRunsResponse))
httpmock.REST("GET", fmt.Sprintf("repos/%s/actions/workflows/456", repo)),
httpmock.StringResponse(getWorkflowResponse))

reg.Register(
httpmock.REST("GET", fmt.Sprintf("repos/%s/actions/workflows/456", repo)),
httpmock.StringResponse(getWorkflowResponse))

reg.Register(
httpmock.REST("GET", fmt.Sprintf("repos/%s/actions/runs/123", repo)),
httpmock.StringResponse(`{
"id": 123
"id": 123,
"workflow_id": 456,
"event": "repository_dispatch"
}`))

reg.Register(
httpmock.REST("GET", fmt.Sprintf("repos/%s/actions/workflows/456", repo)),
httpmock.StringResponse(getWorkflowResponse))

reg.Register(
httpmock.REST("GET", fmt.Sprintf("repos/%s/actions/runs/123", repo)),
httpmock.StringResponse(`{
httpmock.StringResponse(fmt.Sprintf(`{
"id": 123,
"workflow_id": 456,
"status": "completed",
"conclusion": "success"
}`))
"event": "repository_dispatch",
"conclusion": "success",
"jobs_url": "https://api.github.com/repos/%s/actions/runs/123/jobs"
}`, repo)))

reg.Register(
httpmock.REST("GET", fmt.Sprintf("repos/%s/actions/runs/123/attempts/1/jobs", repo)),
httpmock.REST("GET", fmt.Sprintf("repos/%s/actions/runs/123/jobs", repo)),
httpmock.StringResponse(getJobsResponse))

reg.Register(
httpmock.REST("GET", fmt.Sprintf("repos/%s/check-runs/123/annotations", repo)),
httpmock.StringResponse("[]"))
},
wantOut: "Refreshing run status every 2 seconds. Press Ctrl+C to quit.\n\nhttps://github.com/OWNER/REPO/actions/runs/123\n\n\nJOBS\n✓ build in 1m59s (ID 123)\n ✓ Run actions/checkout@v2\n ✓ Test\n",
wantOut: `Refreshing run status every 2 seconds. Press Ctrl+C to quit.
https://github.com/OWNER/REPO/actions/runs/123
✓ foo · 123
Triggered via repository_dispatch
JOBS
✓ build in 1m59s (ID 123)
✓ Run actions/checkout@v2
✓ Test
`,
}, {
name: "unsuccessful workflow run",
opts: &repositoryDispatchOptions{
Expand All @@ -81,36 +128,79 @@ func TestRepositoryDispatchRun(t *testing.T) {
httpmock.REST("GET", fmt.Sprintf("repos/%s/actions/workflows", repo)),
httpmock.StringResponse(getWorkflowsResponse))

reg.Register(
httpmock.GraphQL("query UserCurrent{viewer{login}}"),
httpmock.StringResponse(currentUserResponse))

v := url.Values{}
v.Set("event", "repository_dispatch")
v.Set("per_page", "50")

reg.Register(
httpmock.QueryMatcher("GET", fmt.Sprintf("repos/%s/actions/workflows/456/runs", repo), v),
httpmock.StringResponse(fmt.Sprintf(getWorkflowRunsResponse, event, repo)))

q := url.Values{}
q.Set("per_page", "100")
q.Set("page", "1")

// TODO: is this correct? is it the correct response?
reg.Register(
httpmock.QueryMatcher("GET", fmt.Sprintf("repos/%s/actions/workflows", repo), q),
httpmock.StringResponse(fmt.Sprintf(getWorkflowRunsResponse, event, repo)))

// TODO: is this correct? is it the correct response?
reg.Register(
httpmock.REST("GET", fmt.Sprintf("repos/%s/actions/workflows/456", repo)),
httpmock.StringResponse(getWorkflowResponse))

// TODO: is this correct? is it the correct response?
reg.Register(
httpmock.QueryMatcher("GET", fmt.Sprintf("repos/%s/actions/runs", repo), v),
httpmock.StringResponse(getWorkflowRunsResponse))
httpmock.REST("GET", fmt.Sprintf("repos/%s/actions/workflows/456", repo)),
httpmock.StringResponse(getWorkflowResponse))

reg.Register(
httpmock.REST("GET", fmt.Sprintf("repos/%s/actions/runs/123", repo)),
httpmock.StringResponse(`{
"id": 123
"id": 123,
"workflow_id": 456,
"event": "repository_dispatch"
}`))

reg.Register(
httpmock.REST("GET", fmt.Sprintf("repos/%s/actions/workflows/456", repo)),
httpmock.StringResponse(getWorkflowResponse))

reg.Register(
httpmock.REST("GET", fmt.Sprintf("repos/%s/actions/runs/123", repo)),
httpmock.StringResponse(`{
httpmock.StringResponse(fmt.Sprintf(`{
"id": 123,
"workflow_id": 456,
"status": "completed",
"conclusion": "failure"
}`))
"event": "repository_dispatch",
"conclusion": "failure",
"jobs_url": "https://api.github.com/repos/%s/actions/runs/123/jobs"
}`, repo)))

reg.Register(
httpmock.REST("GET", fmt.Sprintf("repos/%s/actions/runs/123/attempts/1/jobs", repo)),
httpmock.REST("GET", fmt.Sprintf("repos/%s/actions/runs/123/jobs", repo)),
httpmock.StringResponse(getFailingJobsResponse))

reg.Register(
httpmock.REST("GET", fmt.Sprintf("repos/%s/check-runs/123/annotations", repo)),
httpmock.StringResponse("[]"))
},
wantOut: "Refreshing run status every 2 seconds. Press Ctrl+C to quit.\n\nhttps://github.com/OWNER/REPO/actions/runs/123\n\n\nJOBS\n✓ build in 1m59s (ID 123)\n ✓ Run actions/checkout@v2\n X Test\n",
wantOut: `Refreshing run status every 2 seconds. Press Ctrl+C to quit.
https://github.com/OWNER/REPO/actions/runs/123
X foo · 123
Triggered via repository_dispatch
JOBS
✓ build in 1m59s (ID 123)
✓ Run actions/checkout@v2
X Test
`,
wantErr: true,
errMsg: "SilentError",
}, {
Expand All @@ -136,10 +226,11 @@ func TestRepositoryDispatchRun(t *testing.T) {
ios.SetStdoutTTY(false)
ios.SetAlternateScreenBufferEnabled(false)

tt.opts.repo = repo
tt.opts.repo = ghRepo
tt.opts.io = ios
tt.opts.httpTransport = reg
tt.opts.authToken = "123"
tt.opts.httpClient = &http.Client{
Transport: reg,
}

t.Run(tt.name, func(t *testing.T) {
err := repositoryDispatchRun(tt.opts)
Expand Down

0 comments on commit b493ec1

Please sign in to comment.