@@ -2,8 +2,12 @@ const core = require('@actions/core');
2
2
const github = require ( '@actions/github' ) ;
3
3
const AdmZip = require ( 'adm-zip' ) ;
4
4
5
+ let verbose = false ;
6
+ let log = null ;
7
+ let debug = ( msg ) => { if ( verbose ) { log ( msg ) ; } }
8
+
5
9
async function analyze ( name , count , token , owner , repo , branch ) {
6
- console . log ( `Analyzing ${ name } for the last ${ count } successful runs.\n` ) ;
10
+ log ( `Analyzing ${ name } for the last ${ count } successful runs.\n` ) ;
7
11
const octokit = github . getOctokit ( token )
8
12
9
13
const runs = await octokit . rest . actions . listWorkflowRuns ( {
@@ -19,65 +23,55 @@ async function analyze(name, count, token, owner, repo, branch) {
19
23
let permissions = new Map ( ) ;
20
24
21
25
for ( const run of runs . data . workflow_runs ) {
22
- if ( process . env . RUNNER_DEBUG )
23
- console . log ( `Analyzing run ${ run . id } ...` ) ;
26
+ debug ( `Analyzing run ${ run . id } ...` ) ;
24
27
25
28
const jobs = await octokit . rest . actions . listJobsForWorkflowRun ( {
26
29
owner : owner ,
27
30
repo : repo ,
28
31
run_id : run . id ,
29
32
} ) ;
30
33
31
- if ( process . env . RUNNER_DEBUG )
32
- console . log ( `Found ${ jobs . data . jobs . length } jobs.` )
34
+ debug ( `Found ${ jobs . data . jobs . length } jobs.` )
33
35
34
36
const artifacts = await octokit . rest . actions . listWorkflowRunArtifacts ( {
35
37
owner : owner ,
36
38
repo : repo ,
37
39
run_id : run . id ,
38
40
} ) ;
39
41
40
- if ( process . env . RUNNER_DEBUG )
41
- console . log ( `${ artifacts . data . artifacts . length } artifacts...` )
42
+ debug ( `${ artifacts . data . artifacts . length } artifacts...` )
42
43
43
44
for ( const job of jobs . data . jobs ) {
44
45
if ( job . conclusion !== 'success' )
45
46
continue ;
46
47
47
- if ( process . env . RUNNER_DEBUG ) {
48
- console . log ( `${ job . name } ${ job . id } was successful...` ) ;
49
- console . log ( `Downloading logs for job id ${ job . id } ...` ) ;
50
- }
48
+ debug ( `${ job . name } ${ job . id } was successful...` ) ;
49
+ debug ( `Downloading logs for job id ${ job . id } ...` ) ;
51
50
52
- let log = null ;
51
+ let workflowRunLog = null ;
53
52
try {
54
- log = await octokit . rest . actions . downloadJobLogsForWorkflowRun ( {
53
+ workflowRunLog = await octokit . rest . actions . downloadJobLogsForWorkflowRun ( {
55
54
owner : owner ,
56
55
repo : repo ,
57
56
job_id : job . id ,
58
57
} ) ;
59
58
} catch ( e ) {
60
- if ( process . env . RUNNER_DEBUG )
61
- console . log ( `Logs for the job ${ job . id } are not available.` ) ;
59
+ debug ( `Logs for the job ${ job . id } are not available.` ) ;
62
60
continue ;
63
61
}
64
62
65
- const logUploadMatch = log . data . match ( / ( [ ^ " ] + - p e r m i s s i o n s - [ a - z 0 - 9 ] { 32 } ) / m) ;
63
+ const logUploadMatch = workflowRunLog . data . match ( / ( [ ^ " ] + - p e r m i s s i o n s - [ a - z 0 - 9 ] { 32 } ) / m) ;
66
64
if ( ! logUploadMatch ) {
67
- if ( process . env . RUNNER_DEBUG ) {
68
- console . log ( `Cannot find the magic string. Skipping.` ) ;
69
- }
65
+ debug ( `Cannot find the magic string. Skipping.` ) ;
70
66
continue ;
71
67
}
72
68
const artifactName = logUploadMatch [ 1 ] ;
73
- if ( process . env . RUNNER_DEBUG )
74
- console . log ( `Looking for artifactName ${ artifactName } ` ) ;
69
+ debug ( `Looking for artifactName ${ artifactName } ` ) ;
75
70
const jobName = artifactName . split ( '-' ) . slice ( 0 , - 2 ) . join ( '-' ) ;
76
71
77
72
for ( const artifact of artifacts . data . artifacts ) {
78
73
if ( artifact . name === artifactName ) {
79
- if ( process . env . RUNNER_DEBUG )
80
- console . log ( `Downloading artifact id ${ artifact . id } ` ) ;
74
+ debug ( `Downloading artifact id ${ artifact . id } ` ) ;
81
75
const download = await octokit . rest . actions . downloadArtifact ( {
82
76
owner : owner ,
83
77
repo : repo ,
@@ -112,58 +106,101 @@ async function analyze(name, count, token, owner, repo, branch) {
112
106
return permissions ;
113
107
}
114
108
115
- async function run ( name , count , token , owner , repo , branch ) {
109
+ async function run ( token , name , count , owner , repo , branch , format ) {
116
110
const permissions = await analyze ( name , count , token , owner , repo , branch ) ;
117
111
118
112
let summary = core . summary . addHeading ( `Minimal required permissions for ${ name } :` ) ;
119
- console . log ( `Minimal required permissions for ${ name } :` ) ;
120
-
121
- if ( permissions . size === 0 ) {
122
- summary = summary . addRaw ( 'No permissions logs were found.' ) ;
123
- console . log ( 'No permissions logs were found.' ) ;
124
- } else {
125
- for ( const [ jobName , jobPermissions ] of permissions ) {
126
- summary = summary . addHeading ( `${ jobName } :` , 2 ) ;
127
- console . log ( `---------------------= ${ jobName } =---------------------` ) ;
128
-
129
- let codeBlock = '' ;
130
- if ( jobPermissions . size === 0 ) {
131
- codeBlock += 'permissions: {}' ;
132
- console . log ( 'permissions: {}' ) ;
133
- } else {
134
- codeBlock += 'permissions:\n' ;
135
- console . log ( 'permissions:' ) ;
136
- for ( const [ kind , perm ] of jobPermissions ) {
137
- codeBlock += ` ${ kind } : ${ perm } \n` ;
138
- console . log ( ` ${ kind } : ${ perm } ` ) ;
113
+ log ( `Minimal required permissions for ${ name } :` ) ;
114
+
115
+ try {
116
+ if ( permissions . size === 0 ) {
117
+ summary = summary . addRaw ( 'No permissions logs were found.' ) ;
118
+ throw new Error ( 'No permissions logs were found.' ) ;
119
+ } else {
120
+ let additionalIndent = '' ;
121
+ if ( format )
122
+ additionalIndent = ' ' ;
123
+
124
+ for ( const [ jobName , jobPermissions ] of permissions ) {
125
+ summary = summary . addHeading ( `${ jobName } :` , 2 ) ;
126
+ log ( `---------------------= ${ jobName } =---------------------` ) ;
127
+ if ( format )
128
+ console . log ( `${ jobName } :` ) ;
129
+
130
+ let codeBlock = '' ;
131
+ if ( jobPermissions . size === 0 ) {
132
+ codeBlock += `${ additionalIndent } permissions: {}` ;
133
+ } else {
134
+ codeBlock += `${ additionalIndent } permissions:\n` ;
135
+ for ( const [ kind , perm ] of jobPermissions ) {
136
+ codeBlock += `${ additionalIndent } ${ kind } : ${ perm } \n` ;
137
+ }
139
138
}
139
+
140
+ console . log ( codeBlock ) ; // write always
141
+ summary = summary . addCodeBlock ( codeBlock , 'yaml' ) ;
140
142
}
141
-
142
- summary = summary . addCodeBlock ( codeBlock , 'yaml' ) ;
143
143
}
144
- }
145
-
146
- if ( process . env . GITHUB_ACTIONS ) {
147
- await summary . write ( ) ;
144
+ } finally {
145
+ if ( process . env . GITHUB_ACTIONS ) {
146
+ await summary . write ( ) ;
147
+ }
148
148
}
149
149
}
150
150
151
- if ( ! process . env . GITHUB_ACTIONS && process . argv . length !== 7 ) {
152
- console . log ( 'Usage: node index.js <number_of_the_last_runs> <github_owner> <repo_name> <branch_name>' ) ;
153
- console . log ( 'For example: node index.js ci.yml 10 github actions-permissions main' ) ;
151
+ function printUsageAndExit ( ) {
152
+ console . log ( 'Usage: node index.js <number_of_the_last_runs> <github_owner> <repo_name> <branch_name> [--format yaml] [--verbose] ' ) ;
153
+ console . log ( 'For example: node index.js ci.yml 10 github actions-permissions main --format yaml --verbose ' ) ;
154
154
process . exit ( 1 ) ;
155
155
}
156
156
157
+ verbose = false ;
158
+ log = console . log ;
159
+
157
160
if ( process . env . GITHUB_ACTIONS ) {
158
161
const name = core . getInput ( 'name' ) ;
159
162
const count = core . getInput ( 'count' ) ;
160
163
const token = core . getInput ( 'token' ) ;
164
+ verbose = process . env . RUNNER_DEBUG ? true : false ;
165
+ const branch = github . context . ref . split ( '/' ) . slice ( - 1 ) [ 0 ] ;
166
+ const format = null ;
161
167
162
- run ( name , count , token , github . context . repo . owner , github . context . repo . repo , github . context . ref . split ( '/' ) . slice ( - 1 ) [ 0 ] ) . catch ( error => {
168
+ run ( token , name , count , github . context . repo . owner , github . context . repo . repo , branch , format ) . catch ( error => {
163
169
core . setFailed ( error . message ) ;
164
170
} ) ;
165
171
} else {
166
- run ( process . argv [ 2 ] , process . argv [ 3 ] , process . env . GITHUB_TOKEN , process . argv [ 4 ] , process . argv [ 5 ] , process . argv [ 6 ] ) . catch ( error => {
167
- console . log ( `Error: ${ error . message } ` ) ;
172
+ const args = process . argv . slice ( 2 ) ;
173
+ const outputIndex = args . indexOf ( '--format' ) ;
174
+ let format = null ;
175
+
176
+ if ( outputIndex !== - 1 ) {
177
+ if ( outputIndex + 1 >= args . length ) {
178
+ printUsageAndExit ( ) ;
179
+ }
180
+ format = args [ outputIndex + 1 ] ;
181
+ if ( ! format || ! [ 'yaml' ] . includes ( format ) {
182
+ printUsageAndExit ( ) ;
183
+ }
184
+ args . splice ( outputIndex , 2 ) ; // Remove --output and its value from args
185
+ }
186
+
187
+ const debugIndex = args . indexOf ( '--verbose' ) ;
188
+ if ( debugIndex !== - 1 ) {
189
+ verbose = true ;
190
+ args . splice ( debugIndex , 1 ) ; // Remove --verbose from args
191
+ }
192
+
193
+ if ( args . length !== 5 ) {
194
+ printUsageAndExit ( ) ;
195
+ }
196
+
197
+ const [ name , count , owner , repo , branch ] = args ;
198
+ if ( format !== null ) {
199
+ log = ( ) => { } ;
200
+ }
201
+
202
+ run ( process . env . GITHUB_TOKEN , name , count , owner , repo , branch , format ) . catch ( error => {
203
+ console . error ( `Error: ${ error . message } ` ) ;
204
+ exit ( 2 ) ;
168
205
} ) ;
169
206
}
0 commit comments