Skip to content

Commit 9a08373

Browse files
committed
Watch workflows after starting them.
1 parent e5cf52a commit 9a08373

File tree

4 files changed

+131
-4
lines changed

4 files changed

+131
-4
lines changed

cmd/root.go

+34
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,14 @@ package cmd
33
import (
44
"context"
55
"fmt"
6+
"os"
7+
"os/exec"
8+
"strconv"
69

710
"github.com/AlecAivazis/survey/v2"
811
"github.com/chrisgavin/gh-dispatch/internal/dispatcher"
912
"github.com/chrisgavin/gh-dispatch/internal/locator"
13+
"github.com/chrisgavin/gh-dispatch/internal/run"
1014
"github.com/chrisgavin/gh-dispatch/internal/version"
1115
"github.com/cli/go-gh"
1216
"github.com/go-git/go-git/v5"
@@ -16,6 +20,7 @@ import (
1620
)
1721

1822
type rootFlagFields struct {
23+
noWatch bool
1924
}
2025

2126
var rootFlags = rootFlagFields{}
@@ -82,10 +87,37 @@ var rootCmd = &cobra.Command{
8287
}
8388
reference := head.Name().String()
8489

90+
log.Info("Dispatching workflow...")
8591
err = dispatcher.DispatchWorkflow(currentRepository, reference, workflowName, inputAnswers)
8692
if err != nil {
8793
return err
8894
}
95+
96+
if !rootFlags.noWatch {
97+
log.Info("Waiting for workflow to start...")
98+
workflowRun, err := run.LocateRun(currentRepository, reference)
99+
if err != nil {
100+
return err
101+
}
102+
103+
command := exec.CommandContext(cmd.Context(), "gh", "run", "watch", strconv.FormatInt(workflowRun.ID, 10))
104+
command.Stdout = os.Stdout
105+
command.Stderr = os.Stderr
106+
err = command.Run()
107+
if err != nil {
108+
return errors.Wrap(err, "Unable to watch workflow progress.")
109+
}
110+
111+
workflowRun, err = run.GetRun(currentRepository, workflowRun.ID)
112+
if err != nil {
113+
return err
114+
}
115+
log.Infof("Workflow completed with conclusion %s.", workflowRun.Conclusion)
116+
if workflowRun.Conclusion != "success" {
117+
os.Exit(1)
118+
}
119+
}
120+
89121
return nil
90122
},
91123
}
@@ -102,6 +134,8 @@ func (f *rootFlagFields) Init(cmd *cobra.Command) error {
102134
}
103135

104136
func Execute(ctx context.Context) error {
137+
rootCmd.Flags().BoolVar(&rootFlags.noWatch, "no-watch", false, "Do not wait for the workflow to complete.")
138+
105139
err := rootFlags.Init(rootCmd)
106140
if err != nil {
107141
return err

internal/client/client.go

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package client
2+
3+
import (
4+
"github.com/cli/go-gh"
5+
"github.com/cli/go-gh/pkg/api"
6+
"github.com/pkg/errors"
7+
)
8+
9+
func NewClient(host string) (api.RESTClient, error) {
10+
client, err := gh.RESTClient(&api.ClientOptions{Host: host})
11+
if err != nil {
12+
return nil, errors.Wrap(err, "Unable to create GitHub client.")
13+
}
14+
return client, nil
15+
}

internal/dispatcher/dispatcher.go

+3-4
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,15 @@ import (
55
"encoding/json"
66
"fmt"
77

8-
"github.com/cli/go-gh"
9-
"github.com/cli/go-gh/pkg/api"
8+
"github.com/chrisgavin/gh-dispatch/internal/client"
109
"github.com/cli/go-gh/pkg/repository"
1110
"github.com/pkg/errors"
1211
)
1312

1413
func DispatchWorkflow(repository repository.Repository, reference string, workflowName string, inputs map[string]interface{}) error {
15-
client, err := gh.RESTClient(&api.ClientOptions{Host: repository.Host()})
14+
client, err := client.NewClient(repository.Host())
1615
if err != nil {
17-
return errors.Wrap(err, "Unable to create GitHub client.")
16+
return err
1817
}
1918

2019
body := map[string]interface{}{

internal/run/run.go

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package run
2+
3+
import (
4+
"fmt"
5+
"net/url"
6+
"strings"
7+
"time"
8+
9+
"github.com/chrisgavin/gh-dispatch/internal/client"
10+
"github.com/cli/go-gh/pkg/api"
11+
"github.com/cli/go-gh/pkg/repository"
12+
"github.com/pkg/errors"
13+
)
14+
15+
type WorkflowRun struct {
16+
ID int64 `json:"id"`
17+
Conclusion string `json:"conclusion"`
18+
}
19+
20+
type WorkflowRuns struct {
21+
WorkflowRuns []WorkflowRun `json:"workflow_runs"`
22+
}
23+
24+
func findRun(client api.RESTClient, repository repository.Repository, reference string, after time.Time, before time.Time) (*WorkflowRun, error) {
25+
urlParameters := url.Values{}
26+
//urlParameters.Add("actor", "TODO")
27+
urlParameters.Add("branch", strings.TrimPrefix(reference, "refs/heads/"))
28+
urlParameters.Add("event", "workflow_dispatch")
29+
createdRange := fmt.Sprintf("%s..%s", after.Format(time.RFC3339), before.Format(time.RFC3339))
30+
urlParameters.Add("created", createdRange)
31+
32+
workflowRuns := WorkflowRuns{}
33+
if err := client.Get(fmt.Sprintf("repos/%s/%s/actions/runs?%s", repository.Owner(), repository.Name(), urlParameters.Encode()), &workflowRuns); err != nil {
34+
return nil, errors.Wrap(err, "Unable to get list of recent runs.")
35+
}
36+
37+
for _, run := range workflowRuns.WorkflowRuns {
38+
return &run, nil
39+
}
40+
return nil, nil
41+
}
42+
43+
func LocateRun(repository repository.Repository, reference string) (*WorkflowRun, error) {
44+
client, err := client.NewClient(repository.Host())
45+
if err != nil {
46+
return nil, err
47+
}
48+
49+
currentTime := time.Now()
50+
after := currentTime.Add(-1 * time.Minute)
51+
before := currentTime.Add(1 * time.Minute)
52+
53+
for {
54+
run, err := findRun(client, repository, reference, after, before)
55+
if err != nil {
56+
return nil, err
57+
}
58+
if run != nil {
59+
return run, nil
60+
}
61+
if time.Now().After(currentTime.Add(1 * time.Minute)) {
62+
return nil, errors.New("Workflow did not start within 1 minute.")
63+
}
64+
time.Sleep(3 * time.Second)
65+
}
66+
}
67+
68+
func GetRun(repository repository.Repository, id int64) (*WorkflowRun, error) {
69+
client, err := client.NewClient(repository.Host())
70+
if err != nil {
71+
return nil, err
72+
}
73+
74+
workflowRun := WorkflowRun{}
75+
if err := client.Get(fmt.Sprintf("repos/%s/%s/actions/runs/%d", repository.Owner(), repository.Name(), id), &workflowRun); err != nil {
76+
return nil, errors.Wrap(err, "Unable to get workflow run.")
77+
}
78+
return &workflowRun, nil
79+
}

0 commit comments

Comments
 (0)