X Tutup
Skip to content

Commit b06cdf0

Browse files
vilmibmvilmibm
authored andcommitted
gh workflow view
1 parent 9b0f706 commit b06cdf0

File tree

8 files changed

+818
-71
lines changed

8 files changed

+818
-71
lines changed

pkg/cmd/workflow/list/list.go

Lines changed: 3 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,14 @@ import (
66

77
"github.com/cli/cli/api"
88
"github.com/cli/cli/internal/ghrepo"
9+
"github.com/cli/cli/pkg/cmd/workflow/shared"
910
"github.com/cli/cli/pkg/cmdutil"
1011
"github.com/cli/cli/pkg/iostreams"
1112
"github.com/cli/cli/utils"
1213
"github.com/spf13/cobra"
1314
)
1415

15-
const (
16-
defaultLimit = 10
17-
18-
Active WorkflowState = "active"
19-
DisabledManually WorkflowState = "disabled_manually"
20-
)
16+
const defaultLimit = 10
2117

2218
type ListOptions struct {
2319
IO *iostreams.IOStreams
@@ -79,7 +75,7 @@ func listRun(opts *ListOptions) error {
7975
client := api.NewClientFromHTTP(httpClient)
8076

8177
opts.IO.StartProgressIndicator()
82-
workflows, err := getWorkflows(client, repo, opts.Limit)
78+
workflows, err := shared.GetWorkflows(client, repo, opts.Limit)
8379
opts.IO.StopProgressIndicator()
8480
if err != nil {
8581
return fmt.Errorf("could not get workflows: %w", err)
@@ -107,55 +103,3 @@ func listRun(opts *ListOptions) error {
107103

108104
return tp.Render()
109105
}
110-
111-
type WorkflowState string
112-
113-
type Workflow struct {
114-
Name string
115-
ID int
116-
State WorkflowState
117-
}
118-
119-
func (w *Workflow) Disabled() bool {
120-
return w.State != Active
121-
}
122-
123-
type WorkflowsPayload struct {
124-
Workflows []Workflow
125-
}
126-
127-
func getWorkflows(client *api.Client, repo ghrepo.Interface, limit int) ([]Workflow, error) {
128-
perPage := limit
129-
page := 1
130-
if limit > 100 {
131-
perPage = 100
132-
}
133-
134-
workflows := []Workflow{}
135-
136-
for len(workflows) < limit {
137-
var result WorkflowsPayload
138-
139-
path := fmt.Sprintf("repos/%s/actions/workflows?per_page=%d&page=%d", ghrepo.FullName(repo), perPage, page)
140-
141-
err := client.REST(repo.RepoHost(), "GET", path, nil, &result)
142-
if err != nil {
143-
return nil, err
144-
}
145-
146-
for _, workflow := range result.Workflows {
147-
workflows = append(workflows, workflow)
148-
if len(workflows) == limit {
149-
break
150-
}
151-
}
152-
153-
if len(result.Workflows) < perPage {
154-
break
155-
}
156-
157-
page++
158-
}
159-
160-
return workflows, nil
161-
}

pkg/cmd/workflow/list/list_test.go

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"testing"
99

1010
"github.com/cli/cli/internal/ghrepo"
11+
"github.com/cli/cli/pkg/cmd/workflow/shared"
1112
"github.com/cli/cli/pkg/cmdutil"
1213
"github.com/cli/cli/pkg/httpmock"
1314
"github.com/cli/cli/pkg/iostreams"
@@ -97,24 +98,24 @@ func Test_NewCmdList(t *testing.T) {
9798
}
9899

99100
func TestListRun(t *testing.T) {
100-
workflows := []Workflow{
101+
workflows := []shared.Workflow{
101102
{
102103
Name: "Go",
103-
State: Active,
104+
State: shared.Active,
104105
ID: 707,
105106
},
106107
{
107108
Name: "Linter",
108-
State: Active,
109+
State: shared.Active,
109110
ID: 666,
110111
},
111112
{
112113
Name: "Release",
113-
State: DisabledManually,
114+
State: shared.DisabledManually,
114115
ID: 451,
115116
},
116117
}
117-
payload := WorkflowsPayload{Workflows: workflows}
118+
payload := shared.WorkflowsPayload{Workflows: workflows}
118119

119120
tests := []struct {
120121
name string
@@ -146,22 +147,22 @@ func TestListRun(t *testing.T) {
146147
Limit: 101,
147148
},
148149
stubs: func(reg *httpmock.Registry) {
149-
workflows := []Workflow{}
150+
workflows := []shared.Workflow{}
150151
for flowID := 0; flowID < 103; flowID++ {
151-
workflows = append(workflows, Workflow{
152+
workflows = append(workflows, shared.Workflow{
152153
ID: flowID,
153154
Name: fmt.Sprintf("flow %d", flowID),
154-
State: Active,
155+
State: shared.Active,
155156
})
156157
}
157158
reg.Register(
158159
httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows"),
159-
httpmock.JSONResponse(WorkflowsPayload{
160+
httpmock.JSONResponse(shared.WorkflowsPayload{
160161
Workflows: workflows[0:100],
161162
}))
162163
reg.Register(
163164
httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows"),
164-
httpmock.JSONResponse(WorkflowsPayload{
165+
httpmock.JSONResponse(shared.WorkflowsPayload{
165166
Workflows: workflows[100:],
166167
}))
167168
},
@@ -176,7 +177,7 @@ func TestListRun(t *testing.T) {
176177
stubs: func(reg *httpmock.Registry) {
177178
reg.Register(
178179
httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows"),
179-
httpmock.JSONResponse(WorkflowsPayload{}),
180+
httpmock.JSONResponse(shared.WorkflowsPayload{}),
180181
)
181182
},
182183
wantOut: "",
@@ -190,7 +191,7 @@ func TestListRun(t *testing.T) {
190191
stubs: func(reg *httpmock.Registry) {
191192
reg.Register(
192193
httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows"),
193-
httpmock.JSONResponse(WorkflowsPayload{}),
194+
httpmock.JSONResponse(shared.WorkflowsPayload{}),
194195
)
195196
},
196197
wantOut: "",

pkg/cmd/workflow/shared/shared.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package shared
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/cli/cli/api"
7+
"github.com/cli/cli/internal/ghrepo"
8+
)
9+
10+
const (
11+
Active WorkflowState = "active"
12+
DisabledManually WorkflowState = "disabled_manually"
13+
)
14+
15+
type WorkflowState string
16+
17+
type Workflow struct {
18+
Name string
19+
ID int
20+
Path string
21+
State WorkflowState
22+
}
23+
24+
type WorkflowsPayload struct {
25+
Workflows []Workflow
26+
}
27+
28+
func (w *Workflow) Disabled() bool {
29+
return w.State != Active
30+
}
31+
32+
func GetWorkflows(client *api.Client, repo ghrepo.Interface, limit int) ([]Workflow, error) {
33+
perPage := limit
34+
page := 1
35+
if limit > 100 {
36+
perPage = 100
37+
}
38+
39+
workflows := []Workflow{}
40+
41+
for len(workflows) < limit {
42+
var result WorkflowsPayload
43+
44+
path := fmt.Sprintf("repos/%s/actions/workflows?per_page=%d&page=%d", ghrepo.FullName(repo), perPage, page)
45+
46+
err := client.REST(repo.RepoHost(), "GET", path, nil, &result)
47+
if err != nil {
48+
return nil, err
49+
}
50+
51+
for _, workflow := range result.Workflows {
52+
workflows = append(workflows, workflow)
53+
if len(workflows) == limit {
54+
break
55+
}
56+
}
57+
58+
if len(result.Workflows) < perPage {
59+
break
60+
}
61+
62+
page++
63+
}
64+
65+
return workflows, nil
66+
}

pkg/cmd/workflow/view/http.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package view
2+
3+
import (
4+
"encoding/base64"
5+
"fmt"
6+
"strings"
7+
8+
"github.com/cli/cli/api"
9+
"github.com/cli/cli/internal/ghrepo"
10+
"github.com/cli/cli/pkg/cmd/workflow/shared"
11+
)
12+
13+
func getWorkflowByID(client *api.Client, repo ghrepo.Interface, workflowID string) (*shared.Workflow, error) {
14+
var workflow shared.Workflow
15+
16+
err := client.REST(repo.RepoHost(), "GET",
17+
fmt.Sprintf("repos/%s/actions/workflows/%s", ghrepo.FullName(repo), workflowID),
18+
nil, &workflow)
19+
20+
if err != nil {
21+
return nil, err
22+
}
23+
24+
return &workflow, nil
25+
}
26+
27+
func getWorkflowsByName(client *api.Client, repo ghrepo.Interface, workflowName string) ([]shared.Workflow, error) {
28+
workflows, err := shared.GetWorkflows(client, repo, 100)
29+
if err != nil {
30+
return nil, fmt.Errorf("couldn't fetch workflows for %s: %w", ghrepo.FullName(repo), err)
31+
}
32+
filtered := []shared.Workflow{}
33+
34+
for _, workflow := range workflows {
35+
if workflow.Disabled() {
36+
continue
37+
}
38+
// TODO consider fuzzy or prefix match
39+
if strings.EqualFold(workflow.Name, workflowName) {
40+
filtered = append(filtered, workflow)
41+
}
42+
}
43+
44+
return filtered, nil
45+
}
46+
47+
func getWorkflowContent(client *api.Client, repo ghrepo.Interface, workflow *shared.Workflow) (string, error) {
48+
path := fmt.Sprintf("repos/%s/contents/%s", ghrepo.FullName(repo), workflow.Path)
49+
50+
type Result struct {
51+
Content string
52+
}
53+
54+
var result Result
55+
err := client.REST(repo.RepoHost(), "GET", path, nil, &result)
56+
if err != nil {
57+
return "", err
58+
}
59+
60+
// TODO NB
61+
// Because any random person can open a PR adding a workflow and that
62+
// workflow by default shows up in the list of workflows for a repo, it's
63+
// possible to try and request content for a workflow that doesn't actually
64+
// exist in the base repo, but instead exists on a fork with the same branch
65+
// name. This results in a 404. It's hard to justify doing work to make this
66+
// not 404 as it seems to just be a spam loophole. Further, I'm not even sure
67+
// /how/ to make it not 404 since workflows don't report what repo they
68+
// originate from.
69+
70+
decoded, err := base64.StdEncoding.DecodeString(result.Content)
71+
if err != nil {
72+
return "", fmt.Errorf("failed to decode workflow file: %w", err)
73+
}
74+
75+
return string(decoded), nil
76+
}

0 commit comments

Comments
 (0)
X Tutup