18
18
const cp = require ( 'child_process' ) ;
19
19
const fs = require ( 'fs' ) ;
20
20
const path = require ( 'path' ) ;
21
- const { env, argv } = require ( 'process' ) ;
22
21
const readline = require ( 'readline' ) ;
22
+ const kSECRET = Symbol ( 'secret' ) ;
23
+
23
24
// Submit any suspicious dependencies for review by the Eclipse Foundation, using dash-license "review" mode?
24
- const autoReviewMode = ( process . argv . slice ( 2 ) ) [ 0 ] == "--review" ? true :false
25
+ const autoReviewMode = process . argv . includes ( '--review' ) ;
26
+ const project = process . argv . find ( arg => / - - p r o j e c t = ( \S + ) / . exec ( arg ) ?. [ 1 ] ) ?? 'ecd.theia' ;
25
27
26
28
const NO_COLOR = Boolean ( process . env [ 'NO_COLOR' ] ) ;
27
29
const dashLicensesJar = path . resolve ( __dirname , 'download/dash-licenses.jar' ) ;
28
30
const dashLicensesSummary = path . resolve ( __dirname , '../dependency-check-summary.txt' ) ;
29
31
const dashLicensesBaseline = path . resolve ( __dirname , '../dependency-check-baseline.json' ) ;
30
32
const dashLicensesUrl = 'https://repo.eclipse.org/service/local/artifact/maven/redirect?r=dash-licenses&g=org.eclipse.dash&a=org.eclipse.dash.licenses&v=LATEST' ;
31
- const project = "ecd.theia" ;
32
33
33
34
// A Eclipse Foundation Gitlab Personal Access Token, generated by an Eclipse committer,
34
- // is required to use dash-licenses in "review" mode. For more information see:
35
+ // is required to use dash-licenses in "review" mode. For more information see:
35
36
// https://github.com/eclipse/dash-licenses#automatic-ip-team-review-requests
36
- // e.g. Set the token like so (bash shell):
37
+ // e.g. Set the token like so (bash shell):
37
38
// $> export DASH_LICENSES_PAT="<PAT>"
38
- const gitlabTokenDefined = env . DASH_LICENSES_PAT ? true : false ;
39
-
40
- if ( autoReviewMode && ! gitlabTokenDefined ) {
41
- console . error ( "Please setup an Eclipse Foundation Gitlab Personal Access Token to run the license check in 'review' mode" ) ;
42
- console . error ( "It should be set in an environment variable named 'DASH_LICENSES_PAT'" ) ;
43
- process . exit ( 1 ) ;
44
- }
39
+ const personalAccessToken = secret ( process . env . DASH_LICENSES_PAT ) ;
45
40
46
41
main ( ) . catch ( error => {
47
42
console . error ( error ) ;
48
43
process . exit ( 1 ) ;
49
44
} ) ;
50
45
51
46
async function main ( ) {
47
+ if ( autoReviewMode && ! personalAccessToken ) {
48
+ error ( 'Please setup an Eclipse Foundation Gitlab Personal Access Token to run the license check in "review" mode' ) ;
49
+ error ( 'It should be set in an environment variable named "DASH_LICENSES_PAT"' ) ;
50
+ process . exit ( 1 ) ;
51
+ }
52
52
if ( ! fs . existsSync ( dashLicensesJar ) ) {
53
53
info ( 'Fetching dash-licenses...' ) ;
54
54
fs . mkdirSync ( path . dirname ( dashLicensesJar ) , { recursive : true } ) ;
@@ -65,20 +65,14 @@ async function main() {
65
65
fs . renameSync ( dashLicensesSummary , `${ dashLicensesSummary } .old` ) ;
66
66
}
67
67
info ( 'Running dash-licenses...' ) ;
68
- var args = [ '-jar' , dashLicensesJar , 'yarn.lock' , '-batch' , '50' , '-timeout' , '240' , '-summary' , dashLicensesSummary ]
69
- if ( autoReviewMode && gitlabTokenDefined ) {
70
- info ( 'using "review" mode' ) ;
71
- args . push ( '-review' , '-token' , '$DASH_LICENSES_PAT' , '-project' , project ) ;
68
+ const args = [ '-jar' , dashLicensesJar , 'yarn.lock' , '-batch' , '50' , '-timeout' , '240' , '-summary' , dashLicensesSummary ] ;
69
+ if ( autoReviewMode && personalAccessToken ) {
70
+ info ( `Using "review" mode for project: ${ project } ` ) ;
71
+ args . push ( '-review' , '-token' , personalAccessToken , '-project' , project ) ;
72
72
}
73
-
74
- // note: "shell:true" is required so we can reference the
75
- // Gitlab Personal Access Token through an environment variable
76
- // at invocation of "dash-license". This is necessary to avoid
77
- // leaking the token's value
78
- const dashError = getErrorFromStatus ( spawn (
79
- 'java' , args ,
80
- { stdio : [ 'ignore' , 'ignore' , 'inherit' ] , shell : true }
81
- ) ) ;
73
+ const dashError = getErrorFromStatus ( spawn ( 'java' , args , {
74
+ stdio : [ 'ignore' , 'ignore' , 'inherit' ]
75
+ } ) ) ;
82
76
if ( dashError ) {
83
77
warn ( dashError ) ;
84
78
}
@@ -172,25 +166,62 @@ function readBaseline(baseline) {
172
166
process . exit ( 1 ) ;
173
167
}
174
168
169
+ /**
170
+ * @param {any } value
171
+ * @returns {object | undefined }
172
+ */
173
+ function secret ( value ) {
174
+ if ( value ) {
175
+ return { [ kSECRET ] : value } ;
176
+ }
177
+ }
178
+
179
+ /**
180
+ * @param {(string | object)[] } array
181
+ * @returns {string[] }
182
+ */
183
+ function withSecrets ( array ) {
184
+ return array . map ( element => element [ kSECRET ] ?? element ) ;
185
+ }
186
+
187
+ /**
188
+ * @param {(string | object)[] } array
189
+ * @returns {string[] }
190
+ */
191
+ function withoutSecrets ( array ) {
192
+ return array . map ( element => element [ kSECRET ] ? '***' : element ) ;
193
+ }
194
+
175
195
/**
176
196
* Spawn a process. Exits with code 1 on spawn error (e.g. file not found).
177
197
* @param {string } bin
178
- * @param {string[] } args
198
+ * @param {( string | object) [] } args
179
199
* @param {import('child_process').SpawnSyncOptions } [opts]
180
200
* @returns {import('child_process').SpawnSyncReturns }
181
201
*/
182
202
function spawn ( bin , args , opts = { } ) {
183
203
opts = { stdio : 'inherit' , ...opts } ;
204
+ function abort ( spawnError , spawnBin , spawnArgs ) {
205
+ if ( spawnBin && spawnArgs ) {
206
+ error ( `Command: ${ prettyCommand ( { bin : spawnBin , args : spawnArgs } ) } ` ) ;
207
+ }
208
+ error ( spawnError . stack ?? spawnError . message ) ;
209
+ process . exit ( 1 ) ;
210
+ }
184
211
/** @type {any } */
185
- const status = cp . spawnSync ( bin , args , opts ) ;
212
+ let status ;
213
+ try {
214
+ status = cp . spawnSync ( bin , withSecrets ( args ) , opts ) ;
215
+ } catch ( spawnError ) {
216
+ abort ( spawnError , bin , withoutSecrets ( args ) ) ;
217
+ }
186
218
// Add useful fields to the returned status object:
187
219
status . bin = bin ;
188
- status . args = args ;
220
+ status . args = withoutSecrets ( args ) ;
189
221
status . opts = opts ;
190
222
// Abort on spawn error:
191
223
if ( status . error ) {
192
- console . error ( status . error ) ;
193
- process . exit ( 1 ) ;
224
+ abort ( status . error , status . bin , status . args ) ;
194
225
}
195
226
return status ;
196
227
}
0 commit comments