@@ -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"
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
152159func 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+ "\n error: 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- "\n error: 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- "\n error: 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+ "\n error: 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