Skip to content

Commit 77788df

Browse files
committed
🚧 Add repo reports
1 parent c11dc5a commit 77788df

File tree

1 file changed

+162
-136
lines changed

1 file changed

+162
-136
lines changed

cmd/actions.go

Lines changed: 162 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"time"
2828

2929
"github.com/MakeNowJust/heredoc"
30+
"github.com/cli/go-gh"
3031
"github.com/pterm/pterm"
3132
"github.com/shurcooL/graphql"
3233
"github.com/spf13/cobra"
@@ -59,6 +60,12 @@ var (
5960
} `graphql:"repositoryOwner(login: $owner)"`
6061
}
6162

63+
ActionRepositoryUsesQuery struct {
64+
Repository struct {
65+
ActionUsesRepository
66+
} `graphql:"repository(owner: $owner, name: $repo)"`
67+
}
68+
6269
aur []ActionUsesRepository
6370

6471
ce = map[string]bool{
@@ -150,11 +157,28 @@ func init() {
150157

151158
// GetActionsReport returns a report on GitHub Actions
152159
func GetActionsReport(cmd *cobra.Command, args []string) (err error) {
160+
sp.Start()
161+
153162
if repo != "" {
154-
return fmt.Errorf("Repository not (yet) supported for this report")
155-
}
163+
cr, _ := gh.CurrentRepository()
156164

157-
sp.Start()
165+
o := cr.Owner()
166+
r := cr.Name()
167+
168+
variables := map[string]interface{}{
169+
"owner": graphql.String(o),
170+
"repo": graphql.String(r),
171+
"ref": graphql.String("HEAD:.github/workflows"),
172+
}
173+
174+
sp.Suffix = fmt.Sprintf(
175+
" fetching actions report for %s",
176+
utils.HiBlack(o+"/"+r),
177+
)
178+
179+
graphqlClient.Query("ActionUses", &ActionRepositoryUsesQuery, variables)
180+
aur = append(aur, ActionRepositoryUsesQuery.Repository.ActionUsesRepository)
181+
}
158182

159183
if enterprise != "" {
160184
variables := map[string]interface{}{
@@ -174,173 +198,175 @@ func GetActionsReport(cmd *cobra.Command, args []string) (err error) {
174198
}
175199
}
176200

177-
if owner != "" {
201+
if owner != "" && repo == "" {
178202
organizations = append(organizations, Organization{Login: owner})
179203
}
180204

181205
var res = []ActionUsesReport{}
182206

183-
for _, o := range organizations {
184-
owner = o.Login
185-
variables := map[string]interface{}{
186-
"owner": graphql.String(owner),
187-
"page": (*graphql.String)(nil),
188-
"ref": graphql.String("HEAD:.github/workflows"),
189-
}
207+
if len(organizations) > 0 {
208+
for _, o := range organizations {
209+
owner = o.Login
210+
variables := map[string]interface{}{
211+
"owner": graphql.String(owner),
212+
"page": (*graphql.String)(nil),
213+
"ref": graphql.String("HEAD:.github/workflows"),
214+
}
190215

191-
var i = 1
192-
for {
193-
sp.Suffix = fmt.Sprintf(
194-
" fetching actions report %s %s",
195-
utils.Cyan(owner),
196-
utils.HiBlack(fmt.Sprintf("(page %d)", i)),
197-
)
216+
var i = 1
217+
for {
218+
sp.Suffix = fmt.Sprintf(
219+
" fetching actions report %s %s",
220+
utils.Cyan(owner),
221+
utils.HiBlack(fmt.Sprintf("(page %d)", i)),
222+
)
198223

199-
graphqlClient.Query("ActionUses", &ActionUsesQuery, variables)
200-
aur = append(aur, ActionUsesQuery.RepositoryOwner.Repositories.Nodes...)
224+
graphqlClient.Query("ActionUses", &ActionUsesQuery, variables)
225+
aur = append(aur, ActionUsesQuery.RepositoryOwner.Repositories.Nodes...)
201226

202-
if !ActionUsesQuery.RepositoryOwner.Repositories.PageInfo.HasNextPage {
203-
break
227+
if !ActionUsesQuery.RepositoryOwner.Repositories.PageInfo.HasNextPage {
228+
break
229+
}
230+
231+
// sleep for 1 second to avoid rate limiting
232+
time.Sleep(1 * time.Second)
233+
234+
variables["page"] = &ActionUsesQuery.RepositoryOwner.Repositories.PageInfo.EndCursor
235+
i++
204236
}
237+
}
238+
}
205239

206-
// sleep for 1 second to avoid rate limiting
207-
time.Sleep(1 * time.Second)
240+
for _, r := range aur {
241+
// skip if repo is archived or fork
242+
if r.IsArchived || r.IsFork {
243+
continue
244+
}
208245

209-
variables["page"] = &ActionUsesQuery.RepositoryOwner.Repositories.PageInfo.EndCursor
210-
i++
246+
// skip if repo has no workflows
247+
if len(r.Object.Tree.Entries) == 0 {
248+
continue
211249
}
212250

213-
for _, r := range aur {
214-
// skip if repo is archived or fork
215-
if r.IsArchived || r.IsFork {
251+
var wfs = []ActionWorkflow{}
252+
for _, e := range r.Object.Tree.Entries {
253+
// skip if not a yml|yaml file
254+
if _, ok := ce[e.Extension]; !ok {
216255
continue
217256
}
218257

219-
// skip if repo has no workflows
220-
if len(r.Object.Tree.Entries) == 0 {
221-
continue
258+
text := e.Object.Blob.Text
259+
260+
// get Action uses
261+
var wu WorkflowUses
262+
if err := yaml.Unmarshal([]byte(text), &wu); err != nil && !silent {
263+
fmt.Println(
264+
utils.Red(
265+
fmt.Sprintf(
266+
"\nerror: parsing https://%s/%s/blob/HEAD/%s",
267+
hostname,
268+
r.NameWithOwner, e.Path,
269+
),
270+
),
271+
)
222272
}
223273

224-
var wfs = []ActionWorkflow{}
225-
for _, e := range r.Object.Tree.Entries {
226-
// skip if not a yml|yaml file
227-
if _, ok := ce[e.Extension]; !ok {
228-
continue
229-
}
230-
231-
text := e.Object.Blob.Text
232-
233-
// get Action uses
234-
var wu WorkflowUses
235-
if err := yaml.Unmarshal([]byte(text), &wu); err != nil && !silent {
236-
fmt.Println(
237-
utils.Red(
238-
fmt.Sprintf(
239-
"\nerror: parsing https://%s/%s/blob/HEAD/%s",
274+
var uses []ActionUses
275+
for _, job := range wu.Jobs {
276+
for _, step := range job.Steps {
277+
if step.Uses != "" && excludeGitHubAuthored(step.Uses) {
278+
a := strings.Split(step.Uses, "@")
279+
280+
var an string
281+
var av string
282+
var url string
283+
284+
an = a[0]
285+
if len(a) == 2 {
286+
av = a[1]
287+
url = fmt.Sprintf(
288+
"https://%s/%s/tree/%s",
240289
hostname,
241-
r.NameWithOwner, e.Path,
242-
),
243-
),
244-
)
245-
}
290+
an,
291+
av,
292+
)
293+
} else {
294+
url = fmt.Sprintf(
295+
"https://%s/%s/tree/HEAD",
296+
hostname,
297+
an,
298+
)
299+
}
246300

247-
var uses []ActionUses
248-
for _, job := range wu.Jobs {
249-
for _, step := range job.Steps {
250-
if step.Uses != "" && excludeGitHubAuthored(step.Uses) {
251-
a := strings.Split(step.Uses, "@")
252-
253-
var an string
254-
var av string
255-
var url string
256-
257-
an = a[0]
258-
if len(a) == 2 {
259-
av = a[1]
260-
url = fmt.Sprintf(
261-
"https://%s/%s/tree/%s",
262-
hostname,
263-
an,
264-
av,
265-
)
266-
} else {
267-
url = fmt.Sprintf(
268-
"https://%s/%s/tree/HEAD",
269-
hostname,
270-
an,
271-
)
272-
}
273-
274-
if strings.Contains(url, "./") {
275-
url = fmt.Sprintf(
276-
"https://%s/%s/%s/tree/HEAD/%s",
277-
hostname,
278-
r.Owner.Login,
279-
r.Name,
280-
strings.ReplaceAll(an, "./", ""),
281-
)
282-
}
283-
284-
uses = append(uses, ActionUses{
285-
Action: an,
286-
Version: av,
287-
URL: url,
288-
})
301+
if strings.Contains(url, "./") {
302+
url = fmt.Sprintf(
303+
"https://%s/%s/%s/tree/HEAD/%s",
304+
hostname,
305+
r.Owner.Login,
306+
r.Name,
307+
strings.ReplaceAll(an, "./", ""),
308+
)
289309
}
310+
311+
uses = append(uses, ActionUses{
312+
Action: an,
313+
Version: av,
314+
URL: url,
315+
})
290316
}
291317
}
318+
}
292319

293-
// get Action permissions
294-
var wp ActionPermissions
295-
if err := yaml.Unmarshal([]byte(text), &wp); err != nil && !silent {
296-
fmt.Println(
297-
utils.Red(
298-
fmt.Sprintf(
299-
"\nerror: parsing https://%s/%s/blob/HEAD/%s",
300-
hostname,
301-
r.NameWithOwner, e.Path,
302-
),
320+
// get Action permissions
321+
var wp ActionPermissions
322+
if err := yaml.Unmarshal([]byte(text), &wp); err != nil && !silent {
323+
fmt.Println(
324+
utils.Red(
325+
fmt.Sprintf(
326+
"\nerror: parsing https://%s/%s/blob/HEAD/%s",
327+
hostname,
328+
r.NameWithOwner, e.Path,
303329
),
304-
)
305-
}
306-
307-
var permissions []string
308-
// if permissions are defined at the workflow level
309-
if wp.Permissions != nil {
310-
permissions = append(permissions, getPermissions(wp.Permissions)...)
311-
}
330+
),
331+
)
332+
}
312333

313-
// if permissions are defined at the job level
314-
for _, job := range wp.Jobs {
315-
permissions = append(permissions, getPermissions(job.Permissions)...)
316-
}
334+
var permissions []string
335+
// if permissions are defined at the workflow level
336+
if wp.Permissions != nil {
337+
permissions = append(permissions, getPermissions(wp.Permissions)...)
338+
}
317339

318-
// put it all together
319-
wfs = append(wfs, ActionWorkflow{
320-
Path: e.Path,
321-
URL: fmt.Sprintf(
322-
"https://%s/%s/%s/blob/HEAD/%s",
323-
hostname,
324-
r.Owner.Login,
325-
r.Name,
326-
e.Path,
327-
),
328-
Uses: uniqueUses(uses),
329-
Permissions: uniquePermissions(permissions),
330-
})
340+
// if permissions are defined at the job level
341+
for _, job := range wp.Jobs {
342+
permissions = append(permissions, getPermissions(job.Permissions)...)
331343
}
332344

333-
res = append(res, ActionUsesReport{
334-
Owner: r.Owner.Login,
335-
Repo: r.Name,
336-
Workflows: wfs,
345+
// put it all together
346+
wfs = append(wfs, ActionWorkflow{
347+
Path: e.Path,
348+
URL: fmt.Sprintf(
349+
"https://%s/%s/%s/blob/HEAD/%s",
350+
hostname,
351+
r.Owner.Login,
352+
r.Name,
353+
e.Path,
354+
),
355+
Uses: uniqueUses(uses),
356+
Permissions: uniquePermissions(permissions),
337357
})
338358
}
339359

340-
// sleep for 1 second to avoid rate limiting
341-
time.Sleep(1 * time.Second)
360+
res = append(res, ActionUsesReport{
361+
Owner: r.Owner.Login,
362+
Repo: r.Name,
363+
Workflows: wfs,
364+
})
342365
}
343366

367+
// sleep for 1 second to avoid rate limiting
368+
time.Sleep(1 * time.Second)
369+
344370
sp.Stop()
345371

346372
var td = pterm.TableData{

0 commit comments

Comments
 (0)