@leverege/build-tools 2.102.0 → 2.104.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,415 @@
1
+ #!/usr/bin/env node
2
+ /* eslint-disable security/detect-non-literal-fs-filename */
3
+ import fs from 'node:fs'
4
+ import path from 'node:path'
5
+
6
+ import { program } from 'commander'
7
+ import chalk from 'chalk'
8
+ import { glob } from 'glob'
9
+ import ora from 'ora'
10
+ import pLimit from 'p-limit'
11
+ import simpleGit from 'simple-git'
12
+
13
+ import { clear, enableDebug, log, parseJsonFile } from './Utils.mjs'
14
+
15
+ // ---------- Symbols ----------
16
+
17
+ const SYM_GOOD = chalk.green( '✔' )
18
+ const SYM_BAD = chalk.red( '✘' )
19
+
20
+ // ---------- Checks ----------
21
+ // Each check: { label: string, fn: ({ dir, pkg, isWorkspace }) => { value: string } }
22
+ // Add new checks here — the table expands automatically.
23
+
24
+ const CHECKS = [
25
+ {
26
+ label : 'cir',
27
+ fn : ( { dir } ) => {
28
+ const cfgPath = path.join( dir, '.circleci', 'config.yml' )
29
+ if ( !fs.existsSync( cfgPath ) ) return { value : SYM_BAD }
30
+ try {
31
+ const content = fs.readFileSync( cfgPath, 'utf8' )
32
+ const match = content.match( /leverege\/circle-nodejs-ci@(\d+)\.\d+\.\d+/ )
33
+ if ( !match || parseInt( match[1], 10 ) === 0 ) return { value : chalk.hex( '#FFA500' )( 'L' ) }
34
+ const major = parseInt( match[1], 10 )
35
+ return { value : major === 1 ? chalk.yellow( '1' ) : chalk.green( `${major}` ) }
36
+ } catch {
37
+ return { value : chalk.hex( '#FFA500' )( 'L' ) }
38
+ }
39
+ },
40
+ },
41
+ {
42
+ label : 'ESM',
43
+ fn : ( { pkg } ) => {
44
+ const ok = pkg?.type === 'module'
45
+ return { value : ok ? SYM_GOOD : SYM_BAD }
46
+ },
47
+ },
48
+ {
49
+ label : 'har',
50
+ fn : ( { gitRoot } ) => {
51
+ const ok = fs.existsSync( path.join( gitRoot, '.har' ) )
52
+ return { value : ok ? SYM_GOOD : SYM_BAD }
53
+ },
54
+ },
55
+ {
56
+ label : 'lnt',
57
+ fn : ( { dir, pkg, gitRoot } ) => {
58
+ if ( !pkg?.scripts?.lint ) return { value : SYM_BAD }
59
+ try {
60
+ // Prefer package-local node_modules; fall back to monorepo root (hoisted)
61
+ const local = path.join( dir, 'node_modules', 'eslint', 'package.json' )
62
+ const hoisted = path.join( gitRoot, 'node_modules', 'eslint', 'package.json' )
63
+ const eslintPkg = JSON.parse( fs.readFileSync(
64
+ fs.existsSync( local ) ? local : hoisted, 'utf8'
65
+ ) )
66
+ const major = parseInt( eslintPkg.version.split( '.' )[0], 10 )
67
+ return { value : major <= 8 ? chalk.yellow( `${major}` ) : chalk.green( `${major}` ) }
68
+ } catch {
69
+ return { value : chalk.dim( '?' ) }
70
+ }
71
+ },
72
+ },
73
+ {
74
+ label : 'bbl',
75
+ fn : ( { dir, pkg } ) => {
76
+ const configFiles = [ '.babelrc', '.babelrc.js', '.babelrc.json', 'babel.config.js', 'babel.config.json', 'babel.config.cjs' ]
77
+ const hasConfig = configFiles.some( f => fs.existsSync( path.join( dir, f ) ) )
78
+ const allDeps = { ...( pkg?.dependencies ?? {} ), ...( pkg?.devDependencies ?? {} ) }
79
+ const hasDep = Object.keys( allDeps ).some( k => k.includes( 'babel' ) )
80
+ return { value : ( hasConfig || hasDep ) ? SYM_BAD : chalk.dim( '–' ) }
81
+ },
82
+ },
83
+ ]
84
+
85
+ // ---------- Helpers ----------
86
+
87
+ const ANSI_RE = /\x1B\[[0-9;]*m/g // eslint-disable-line no-control-regex
88
+
89
+ function visLen( str ) {
90
+ return str.replace( ANSI_RE, '' ).length
91
+ }
92
+
93
+ function pad( str, width ) {
94
+ return str + ' '.repeat( Math.max( 0, width - visLen( str ) ) )
95
+ }
96
+
97
+ function center( str, width ) {
98
+ const gap = Math.max( 0, width - visLen( str ) )
99
+ const left = Math.floor( gap / 2 )
100
+ return ' '.repeat( left ) + str + ' '.repeat( gap - left )
101
+ }
102
+
103
+ const NONSEMVER = '!SEMVER'
104
+
105
+ // Strict x.y.z only — pre-release and build metadata are flagged !SEMVER
106
+ function parseVersion( raw ) {
107
+ if ( !raw ) return null
108
+ const v = raw.startsWith( 'v' ) ? raw : `v${raw}`
109
+ return /^v\d+\.\d+\.\d+$/.test( v ) ? v : NONSEMVER
110
+ }
111
+
112
+ function fmtPkgVer( ver ) {
113
+ if ( !ver ) return chalk.dim( '?' )
114
+ if ( ver === NONSEMVER ) return chalk.yellow( NONSEMVER )
115
+ return chalk.green( ver )
116
+ }
117
+
118
+ function fmtGitVer( gitVer, pkgVer ) {
119
+ if ( !gitVer ) return chalk.bgRed.white( 'UNTAGGD' )
120
+ if ( gitVer === NONSEMVER ) return chalk.yellow( NONSEMVER )
121
+ if ( gitVer === pkgVer ) return chalk.green( gitVer )
122
+ return chalk.yellow( gitVer )
123
+ }
124
+
125
+ function fmtScope( pkg ) {
126
+ const name = pkg?.name ?? ''
127
+ const match = name.match( /^(@[^/]+)/ )
128
+ if ( match ) return chalk.green( match[1].slice( 0, 4 ) ) // '@' + 3 chars: @leverege → @lev
129
+ if ( pkg?.private === true ) return chalk.yellow( 'PRVT' )
130
+ return chalk.bgRed.white( 'PUBL' )
131
+ }
132
+
133
+ // Extracts { repoName, group } from a directory path.
134
+ // For workspace packages (gitRoot !== dir), group is the monorepo's org/name path
135
+ // and repoName is the package's own directory name.
136
+ // For root repos, group is the @xxx path component and repoName is relative to it.
137
+ function repoLabel( dir, gitRoot ) {
138
+ const parts = dir.split( path.sep )
139
+ const atIdx = parts.findIndex( p => /^@\w+$/.test( p ) )
140
+
141
+ if ( gitRoot && gitRoot !== dir ) {
142
+ // Workspace package — group under the monorepo's label
143
+ const rootParts = gitRoot.split( path.sep )
144
+ const rootAtIdx = rootParts.findIndex( p => /^@\w+$/.test( p ) )
145
+ const group = rootAtIdx === -1 ?
146
+ path.basename( gitRoot ) :
147
+ rootParts.slice( rootAtIdx ).join( '/' )
148
+ return { repoName : path.basename( dir ), group }
149
+ }
150
+
151
+ if ( atIdx === -1 ) return { repoName : path.basename( dir ), group : null }
152
+ const group = parts[atIdx]
153
+ const repoName = parts.slice( atIdx + 1 ).join( '/' )
154
+ return { repoName, group }
155
+ }
156
+
157
+ // ---------- Per-repo ----------
158
+
159
+ async function checkRepo( dir, { pull } ) {
160
+ if ( !fs.existsSync( path.join( dir, 'package.json' ) ) ) return null
161
+
162
+ let gitRoot
163
+ try {
164
+ gitRoot = ( await simpleGit( dir ).revparse( [ '--show-toplevel' ] ) ).trim()
165
+ } catch {
166
+ return null
167
+ }
168
+
169
+ const isWorkspace = gitRoot !== dir
170
+ const git = simpleGit( gitRoot )
171
+ const pkg = await parseJsonFile( path.join( dir, 'package.json' ) )
172
+
173
+ // Monorepo roots are represented by their workspace packages — skip the root itself
174
+ if ( !isWorkspace && pkg?.workspaces ) return null
175
+
176
+ const pkgVer = parseVersion( pkg?.version )
177
+
178
+ let syncOk = true
179
+ if ( isWorkspace ) {
180
+ try {
181
+ const relDir = path.relative( gitRoot, dir )
182
+ const status = await git.status( [ '--', relDir ] )
183
+ syncOk = status.files.length === 0
184
+ } catch {
185
+ syncOk = false
186
+ }
187
+ } else if ( pull ) {
188
+ try {
189
+ await git.pull()
190
+ await git.fetch( [ '--tags' ] )
191
+ } catch {
192
+ syncOk = false
193
+ }
194
+ }
195
+
196
+ let gitVer = null
197
+ if ( isWorkspace ) {
198
+ // Look for workspace-style tags: pkg-name/vX.Y.Z
199
+ const pkgBaseName = ( pkg?.name ?? path.basename( dir ) ).replace( /^@[^/]+\//, '' )
200
+ try {
201
+ const tagOutput = ( await git.raw( [ 'tag', '--list', `${pkgBaseName}/v*` ] ) ).trim()
202
+ if ( tagOutput ) {
203
+ const semverTags = tagOutput.split( '\n' )
204
+ .map( ( t ) => { const m = t.trim().match( /(?:^|\/)v(\d+\.\d+\.\d+)$/ ); return m ? m[1] : null } )
205
+ .filter( Boolean )
206
+ if ( semverTags.length ) {
207
+ semverTags.sort( ( a, b ) => {
208
+ const av = a.split( '.' ).map( Number )
209
+ const bv = b.split( '.' ).map( Number )
210
+ return ( bv[0] - av[0] ) || ( bv[1] - av[1] ) || ( bv[2] - av[2] )
211
+ } )
212
+ gitVer = `v${semverTags[0]}`
213
+ } else {
214
+ gitVer = NONSEMVER
215
+ }
216
+ }
217
+ } catch { /* no tags → null = UNTAGGD */ }
218
+ } else {
219
+ // git describe gives the nearest tag reachable from HEAD, matching original pkgck behavior
220
+ try {
221
+ const tag = ( await git.raw( [ 'describe', '--abbrev=0', '--tags' ] ) ).trim()
222
+ // Handles 'v1.2.3' and workspace-style 'pkg-name/v1.2.3'
223
+ const match = tag.match( /(?:^|\/)v(\d+\.\d+\.\d+)$/ )
224
+ gitVer = match ? `v${match[1]}` : NONSEMVER
225
+ } catch { /* no tags → null = UNTAGGD */ }
226
+ }
227
+
228
+ let needsPush = ''
229
+ if ( pkgVer && pkgVer !== NONSEMVER && gitVer === pkgVer ) {
230
+ try {
231
+ const pkgBaseName = ( pkg?.name ?? path.basename( dir ) ).replace( /^@[^/]+\//, '' )
232
+ const tagToCheck = isWorkspace ? `${pkgBaseName}/${pkgVer}` : pkgVer
233
+ const remote = await git.listRemote( [ '--tags', 'origin' ] )
234
+ if ( !remote.includes( tagToCheck ) ) needsPush = chalk.yellow( '!tags' )
235
+ } catch { /* ignore */ }
236
+ }
237
+
238
+ const isYarn = fs.existsSync( path.join( gitRoot, 'yarn.lock' ) ) || fs.existsSync( path.join( gitRoot, '.yarn' ) )
239
+ const pkgMgr = isYarn ? chalk.cyan( 'yrn' ) : chalk.red( 'npm' )
240
+
241
+ const { repoName, group } = repoLabel( dir, gitRoot )
242
+ return {
243
+ repoName,
244
+ group,
245
+ pkgMgr,
246
+ pkgVer : fmtPkgVer( pkgVer ),
247
+ gitVer : fmtGitVer( gitVer, pkgVer ),
248
+ dirty : !syncOk,
249
+ scope : fmtScope( pkg ),
250
+ isWorkspace,
251
+ checks : CHECKS.map( ( { label, fn } ) => ( { label, ...fn( { dir, pkg, isWorkspace, gitRoot } ) } ) ),
252
+ needsPush,
253
+ }
254
+ }
255
+
256
+ // ---------- Table ----------
257
+
258
+ function renderTable( rows ) {
259
+ const pkgW = Math.max( 3, ...rows.map( r => visLen( r.pkgVer ) ) )
260
+ const gitW = Math.max( 7, ...rows.map( r => visLen( r.gitVer ) ) )
261
+ const scopeW = Math.max( 4, ...rows.map( r => visLen( r.scope ) ) )
262
+
263
+ // Fixed width of all columns except name. Elements: mgr pkg git scope checks (no needsPush).
264
+ // join(' ') puts 2-space sep between N+5 elements = N+4 separators.
265
+ const checkLabelW = CHECKS.reduce( ( sum, c ) => sum + c.label.length, 0 )
266
+ const fixedW = 3 + pkgW + gitW + scopeW + checkLabelW + ( CHECKS.length + 4 ) * 2
267
+
268
+ // Name area: 2-space indent + repo name. Group label prints on its own line above each section.
269
+ const hasGroups = rows.some( r => r.group )
270
+ const indent = hasGroups ? 2 : 0
271
+ const maxRepoW = Math.min( 22, Math.max( 4, ...rows.map( r => r.repoName.length ) ) )
272
+ const nameW = Math.min( indent + maxRepoW, 80 - fixedW )
273
+ const repoW = nameW - indent
274
+
275
+ const nameHdr = pad( `${' '.repeat( indent )}name`, nameW )
276
+ const hdr = [
277
+ nameHdr,
278
+ center( 'mgr', 3 ),
279
+ center( 'pkg', pkgW ),
280
+ center( 'git', gitW ),
281
+ center( 'scop', scopeW ),
282
+ ...CHECKS.map( c => center( c.label, c.label.length ) ),
283
+ ].join( ' ' )
284
+
285
+ const separator = chalk.dim( '─'.repeat( visLen( hdr ) ) )
286
+
287
+ log( '' )
288
+ log( chalk.dim( hdr ) )
289
+ log( separator )
290
+
291
+ let currentGroup
292
+ for ( const row of rows ) {
293
+ if ( row.group !== currentGroup ) {
294
+ currentGroup = row.group
295
+ if ( hasGroups ) log( chalk.cyan( row.group ?? '' ) )
296
+ }
297
+ const nameStr = ' '.repeat( indent ) + row.repoName.slice( 0, repoW )
298
+ const nameCell = row.dirty ? chalk.hex( '#FFA500' )( nameStr ) : nameStr
299
+ const line = [
300
+ pad( nameCell, nameW ),
301
+ pad( row.pkgMgr, 3 ),
302
+ pad( row.pkgVer, pkgW ),
303
+ pad( row.gitVer, gitW ),
304
+ pad( row.scope, scopeW ),
305
+ ...row.checks.map( c => center( c.value, c.label.length ) ),
306
+ ].join( ' ' ) + ( row.needsPush ? ` ${row.needsPush}` : '' )
307
+ log( line )
308
+ }
309
+
310
+ log( '' )
311
+ }
312
+
313
+ // ---------- CLI ----------
314
+
315
+ program
316
+ .name( 'package-checker' )
317
+ .description( chalk.green( 'A panopticon for your git repos!' ) )
318
+ .argument( '<dirs...>', 'directories to check' )
319
+ .option( '--no-pull', 'skip git pull and tag fetch' )
320
+ .option( '--no-clear', 'do not clear the screen before output' )
321
+ .option( '--concurrency <n>', 'max parallel repos', '5' )
322
+ .option( '--limit <n>', 'max rows to display', '80' )
323
+ .option( '--debug', 'enable debug logging' )
324
+ .addHelpText( 'after', `
325
+ ${chalk.yellow( 'Columns:' )}
326
+ ${chalk.green( 'pkg' )} version from package.json
327
+ ${chalk.green( 'git' )} latest semver git tag (green=match, yellow=mismatch, red=untagged)
328
+ ${chalk.green( 'name' )} orange if dirty: pull/fetch failed (regular repos) or local modifications present (workspace packages)
329
+ ${chalk.green( 'scope' )} package scope: @org, PRVT, or PUBL
330
+ ${chalk.green( 'cir' )} CircleCI config: ✘=missing, L=legacy, 1=orb v1, 2=orb v2
331
+ ${chalk.green( 'ESM' )} "type": "module" in package.json
332
+ ${chalk.green( 'har' )} .har directory present at repo root
333
+ ${chalk.green( 'lnt' )} ESLint version from node_modules (✘=no lint script, ?=not installed, yellow=v8, green=v9+)
334
+
335
+ ${chalk.yellow( 'Monorepos:' )}
336
+ Workspace packages are discovered automatically — passing a monorepo root
337
+ expands its workspaces field so you never need to add packages/* globs.
338
+ Git tags are looked up as pkg-name/vX.Y.Z. Pull/fetch runs at the root.
339
+
340
+ ${chalk.yellow( 'Examples:' )}
341
+ ${chalk.green( 'package-checker ~/repos/my-service' )}
342
+ ${chalk.green( 'package-checker --no-pull ~/repos/*' )}
343
+ ${chalk.green( 'package-checker --concurrency 10 @plt/* @kud/* @srv/* @tpi/*' )}
344
+ ` )
345
+ .parse()
346
+
347
+ const dirs = program.args
348
+ const options = program.opts()
349
+ if ( options.debug ) { enableDebug() }
350
+
351
+ if ( options.clear ) { clear() }
352
+
353
+ // Auto-expand workspace packages from any monorepo roots in the input.
354
+ // Supports both array and yarn-style { packages: [...] } workspaces fields.
355
+ async function expandWorkspaces( dir ) {
356
+ try {
357
+ const pkg = await parseJsonFile( path.join( dir, 'package.json' ) )
358
+ const patterns = Array.isArray( pkg?.workspaces ) ?
359
+ pkg.workspaces :
360
+ ( pkg?.workspaces?.packages ?? [] )
361
+ if ( !patterns.length ) return []
362
+ const matches = await Promise.all(
363
+ patterns.map( p => glob( p, { cwd : dir, absolute : true } ) )
364
+ )
365
+ return matches.flat().filter( d => !/test|demo/i.test( path.basename( d ) ) )
366
+ } catch {
367
+ return []
368
+ }
369
+ }
370
+
371
+ const resolvedDirs = dirs.map( dir => path.resolve( dir ) )
372
+ const wsExpansions = ( await Promise.all( resolvedDirs.map( expandWorkspaces ) ) ).flat()
373
+ const allDirs = [ ...new Set( [ ...resolvedDirs, ...wsExpansions ] ) ]
374
+
375
+ const total = allDirs.length
376
+ let completed = 0
377
+ const spinner = ora( `Checking repos (0/${total})...` ).start()
378
+
379
+ process.on( 'SIGINT', () => { spinner.stop(); process.exit( 1 ) } )
380
+
381
+ const limit = pLimit( parseInt( options.concurrency, 10 ) )
382
+ const results = await Promise.all(
383
+ allDirs.map( dir => limit( async () => {
384
+ const result = await checkRepo( dir, { pull : options.pull } )
385
+ spinner.text = `Checking repos (${++completed}/${total})...`
386
+ return result
387
+ } ) )
388
+ )
389
+
390
+ spinner.stop()
391
+
392
+ const rows = results
393
+ .filter( Boolean )
394
+ .sort( ( a, b ) => {
395
+ const ga = a.group ?? ''
396
+ const gb = b.group ?? ''
397
+ if ( ga !== gb ) return ga.localeCompare( gb )
398
+ return a.repoName.localeCompare( b.repoName )
399
+ } )
400
+
401
+ if ( rows.length === 0 ) {
402
+ log( chalk.yellow( '\nNo valid repositories found.\n' ) )
403
+ process.exit( 0 )
404
+ }
405
+
406
+ const maxRows = parseInt( options.limit, 10 )
407
+ const checked = rows.length
408
+ const displayed = rows.slice( 0, maxRows )
409
+
410
+ renderTable( displayed )
411
+
412
+ const summary = checked > displayed.length ?
413
+ `total repositories checked: ${checked} (${displayed.length} displayed)\n` :
414
+ `total repositories checked: ${checked}\n`
415
+ log( summary )
@@ -94,12 +94,14 @@ const cliOptionList = [ // Use cliOptionList to tie into the Usage statements
94
94
  default : false,
95
95
  description : '{green display this help screen}',
96
96
  },
97
- { name : 'version',
97
+ {
98
+ name : 'version',
98
99
  type : Boolean,
99
100
  default : false,
100
101
  description : '{green returns the build-tools repo version}',
101
102
  },
102
- { name : 'verbose',
103
+ {
104
+ name : 'verbose',
103
105
  alias : 'v',
104
106
  type : Boolean,
105
107
  default : false,
@@ -114,7 +116,8 @@ const sections = [
114
116
  {green This utility attempts to ease the pain of managing IAM roles and the creation of service accounts for new clusters and services.}
115
117
  `,
116
118
  },
117
- { header : 'Options',
119
+ {
120
+ header : 'Options',
118
121
  optionList : cliOptionList,
119
122
  },
120
123
  ]
@@ -57,7 +57,7 @@ export default class Config {
57
57
  Remove => ` + chalk.yellow.bold( dumpDir ) )
58
58
  process.exit( 1 )
59
59
  }
60
- } catch ( err ) {
60
+ } catch ( err ) { // eslint-disable-line no-unused-vars
61
61
  // this file does not exist is a good thing
62
62
  }
63
63
 
@@ -24,7 +24,7 @@ export default class RolesManager {
24
24
  /* eslint-disable-next-line no-await-in-loop */
25
25
  await shellCmd( `gcloud iam roles ${iamVerb} ${roleName} --project ${k8sProject}` )
26
26
  iamVerb = 'update' // no err then the role exists - do an update
27
- } catch ( err ) {
27
+ } catch ( err ) { // eslint-disable-line no-unused-vars
28
28
  iamVerb = 'create' // failed call so role does not exist - create it
29
29
  }
30
30
 
@@ -42,7 +42,7 @@ export default class SecretsManager {
42
42
  try {
43
43
  await shellCmd( `gcloud secrets describe ${key} --project ${project}` )
44
44
  exists = true
45
- } catch ( err ) {
45
+ } catch ( err ) { // eslint-disable-line no-unused-vars
46
46
  exists = false
47
47
  }
48
48
 
@@ -72,7 +72,7 @@ export default class SecretsManager {
72
72
  if ( labelStr ) createCmd.push( `--labels=${labelStr}` )
73
73
  if ( annotationStr ) createCmd.push( `--set-annotations=${annotationStr}` )
74
74
  await shellCmd( createCmd, { input : value } )
75
- } catch ( err ) {
75
+ } catch ( err ) { // eslint-disable-line no-unused-vars
76
76
  log( chalk.red( `\nSM secret write failed for ${key}\n` ) )
77
77
  }
78
78
  }
@@ -136,7 +136,7 @@ ${dataLines}
136
136
  log( ` Applying ExternalSecret => ${chalk.green( name )} in ${chalk.yellow( namespace )}` )
137
137
  try {
138
138
  await shellCmd( [ 'kubectl', 'apply', '-f', '-' ], { input : yaml } ) // eslint-disable-line no-await-in-loop
139
- } catch ( err ) {
139
+ } catch ( err ) { // eslint-disable-line no-unused-vars
140
140
  log( chalk.red( `\nExternalSecret apply failed for ${name}\n` ) )
141
141
  }
142
142
  }
@@ -74,7 +74,7 @@ export default class ServiceAccountManager {
74
74
  try {
75
75
  await shellCmd( `${command} ${options}` ) // eslint-disable-line no-await-in-loop
76
76
  return true
77
- } catch ( err ) {
77
+ } catch ( err ) { // eslint-disable-line no-unused-vars
78
78
  log( ' IAM propagating => ', chalk.yellow( role ) )
79
79
  }
80
80
  await delayWithBackoff( retryCount ) // eslint-disable-line no-await-in-loop
@@ -108,7 +108,7 @@ export default class ServiceAccountManager {
108
108
  try {
109
109
  await shellCmd( `${command} ${options}` ) // eslint-disable-line no-await-in-loop
110
110
  return true
111
- } catch ( err ) {
111
+ } catch ( err ) { // eslint-disable-line no-unused-vars
112
112
  await delayWithBackoff( retryCount ) // eslint-disable-line no-await-in-loop
113
113
  }
114
114
  }
@@ -136,7 +136,7 @@ export default class ServiceAccountManager {
136
136
  if ( shellOut.match( `email: ${serviceName}` ) ) {
137
137
  return true
138
138
  }
139
- } catch ( err ) {
139
+ } catch ( err ) { // eslint-disable-line no-unused-vars
140
140
  log( ' SA propagating => ', chalk.yellow( serviceName ) )
141
141
  await delayWithBackoff( retryCount ) // eslint-disable-line no-await-in-loop
142
142
  }
@@ -220,7 +220,7 @@ export default class ServiceAccountManager {
220
220
  log( '\nSkip existing SvcAct =>', chalk.yellow( saName ) )
221
221
  continue
222
222
  }
223
- } catch ( err ) {
223
+ } catch ( err ) { // eslint-disable-line no-unused-vars
224
224
  log( '\nCreating new SvcAcct =>', chalk.green( saName ) )
225
225
  }
226
226
 
package/src/unleash.mjs CHANGED
@@ -39,7 +39,7 @@ const npmRunner = async ( script ) => {
39
39
  const cmd = `npm run ${script}`
40
40
  const results = await shellCmd( cmd, { stdio : 'inherit' } )
41
41
  return results
42
- } catch ( err ) {
42
+ } catch ( err ) { // eslint-disable-line no-unused-vars
43
43
  process.exit( 1 )
44
44
  }
45
45
  return undefined
package/src/pkgck.sh DELETED
@@ -1,158 +0,0 @@
1
- #!/bin/bash
2
-
3
- C_off='\e[0m'
4
- C_yellow='\e[93m'
5
- C_red='\e[101m'
6
- C_green='\e[92m'
7
-
8
- good() {
9
- printf "\e[32m✔${C_off}"
10
- }
11
-
12
- meh() {
13
- printf "\e[36m✩${C_off}"
14
- }
15
-
16
- bad() {
17
- printf "\e[31m✘${C_off}"
18
- }
19
-
20
- semver() {
21
- local version=$1
22
- local isSemver=`echo $version | egrep -e "^v\d+\.\d+\.\d+$"`
23
- if [ -z "$version" ];
24
- then
25
- printf "UNTAGGD"
26
- elif [ $isSemver ];
27
- then
28
- printf "$version"
29
- else
30
- printf "!SEMVER"
31
- fi
32
- }
33
-
34
- check_babel () {
35
- local C_stat=$(bad)
36
- [ -f .babelrc ] && grep --silent @leverege/babel-preset-leverege-node .babelrc
37
- [ $? -eq 0 ] && C_stat=$(good)
38
- [ ! -f .babelrc ] && C_stat=$(meh)
39
- printf $C_stat
40
- }
41
-
42
- check_har () {
43
- local C_stat=$(bad)
44
- local prep="`node -p \"require('./package.json').scripts.prepare\"`"
45
- local isHar=`echo $prep | egrep -e "hook-and-release"`
46
- [ ! -z "$isHar" ] && C_stat=$(good)
47
- printf $C_stat
48
- }
49
-
50
- check_circle () {
51
- local C_stat=$(bad)
52
- [ -f ".circleci/config.yml" ] && C_stat=$(good)
53
- printf $C_stat
54
- }
55
-
56
- check_eslint () {
57
- local C_stat=$(bad)
58
- [ -f .eslintrc ] && grep --silent @leverege/eslint-config-leverege .eslintrc
59
- [ $? -eq 0 ] && C_stat=$(good)
60
- printf $C_stat
61
- }
62
-
63
- check_license () {
64
- local C_stat=$(meh)
65
- local lic="`node -p \"require('./package.json').scripts.licenseCheck == undefined\"`"
66
- [ $lic == true ] && C_stat=$(good)
67
- printf $C_stat
68
- }
69
-
70
- # Invoke as: version_ck $GITTAG $NPMVER
71
- #
72
- check_git_version() {
73
- local tag=$1
74
- local pkg=$2
75
- local clr=$C_green
76
-
77
- if [ "$tag" == 'UNTAGGD' ];
78
- then
79
- clr=$C_red
80
- elif [ "$tag" != "$pkg" ];
81
- then
82
- clr=$C_yellow
83
- fi
84
-
85
- printf "$clr$tag$C_off"
86
- }
87
-
88
- #check_nodemon() {
89
- # nodemon="`getjson --file ./package.json --key nodemon`"
90
- #}
91
-
92
- check_scope() {
93
- private="`node -p \"require('./package.json').private == true\"`"
94
- scoped="`getjson --file ./package.json --key name --regex '^@\w{3}'`"
95
- result="${C_red}PUBL${C_off}"
96
- if [[ "$scoped" == "" ]] && [[ "$private" == "true" ]];
97
- then
98
- result="${C_yellow}PRVT"
99
- elif [[ "$scoped" != "" ]];
100
- then
101
- result="${C_green}${scoped}"
102
- elif [[ "$private" == "true" ]];
103
- then
104
- result="${C_green}prv"
105
- fi
106
- printf "${result}${C_off}"
107
- }
108
-
109
- check_ESM() {
110
- local C_stat=$(bad)
111
- jstype="`getjson --file package.json --key type`"
112
- [[ "$jstype" == "module" ]] && C_stat=$(good)
113
- printf $C_stat
114
- }
115
-
116
- repos=0
117
- check_repo() {
118
- local dir=$1
119
- [ ! -d $dir/.git ] || [ ! -f $dir/package.json ] && return
120
- cd $dir &> /dev/null
121
- local gperrs=0
122
- git pull -q &> /dev/null; [ $? -ne 0 ] && let "gperrs++"
123
- git pull -q --tags &> /dev/null; [ $? -ne 0 ] && let "gperrs++"
124
-
125
- # It is necessary to use the output from printf to set localmods in order
126
- # to get the ANSI escape codes expanded.
127
- local localmods=$(good)
128
- [ $gperrs -ne 0 ] && localmods=$(bad)
129
- pkgver=$(semver "v`node -p \"require('./package.json').version\"`")
130
- gitver=$(semver `git describe --abbrev=0 2>/dev/null`)
131
- [ $? -ne 0 ] && gitver='UNTAGGD'
132
- local needspush=
133
- if [ "$pkgver" == "$gitver" ];
134
- then
135
- git ls-remote --tags origin | grep $gitver &> /dev/null
136
- [ $? -ne 0 ] && needspush='!tags'
137
- fi
138
- local babel7=$(check_babel)
139
- local hookar=$(check_har)
140
- local circle=$(check_circle)
141
- local eslint=$(check_eslint)
142
- local esmlib=$(check_ESM)
143
- local license=$(check_license)
144
- local scoped=$(check_scope)
145
- [ $(( $repos % 15)) -eq 0 ] && printf "\n%35s pkg git cln scop cir lic ESM har\n"
146
- printf "%32s: %-8s %-16s %s %8s %s %s %s %s %s\n" ${dir:0:32} $pkgver $(check_git_version $gitver $pkgver) $localmods $scoped $circle $license $esmlib $hookar "$needspush"
147
- let "repos++"
148
- cd - &> /dev/null
149
- }
150
-
151
- clear
152
-
153
- pkgs="$@"
154
- for dir in $@; do
155
- check_repo $dir
156
- done
157
-
158
- printf "\ntotal repoitories checked: $repos\n\n"