@leverege/build-tools 2.66.5 → 2.66.7

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leverege/build-tools",
3
- "version": "2.66.5",
3
+ "version": "2.66.7",
4
4
  "description": "A collection of build / support tools for Leverege developers",
5
5
  "main": "index.js",
6
6
  "repository": {
@@ -34,6 +34,7 @@
34
34
  "getfbcfg": "src/getfbcfg.mjs",
35
35
  "getjson": "src/getjson.mjs",
36
36
  "git-tar": "src/git-tar.sh",
37
+ "helm-audit": "src/helm-audit.mjs",
37
38
  "helmcycle": "src/helmup.sh",
38
39
  "helmdn": "src/helmdn.sh",
39
40
  "helmup": "src/helmup.sh",
@@ -68,7 +69,7 @@
68
69
  "commander": "^13.1.0",
69
70
  "deepmerge": "^4.3.1",
70
71
  "enquirer": "^2.4.1",
71
- "execa": "^9.5.2",
72
+ "execa": "^9.5.3",
72
73
  "glob": "^11.0.2",
73
74
  "handlebars": "^4.7.8",
74
75
  "ignore": "^7.0.4",
@@ -78,12 +79,14 @@
78
79
  "ms": "^2.1.3",
79
80
  "npm-registry-fetch": "^18.0.2",
80
81
  "ora": "^8.2.0",
82
+ "p-limit": "^6.2.0",
81
83
  "package-up": "^5.0.0",
82
84
  "readline-sync": "^1.4.10",
83
85
  "semver": "^7.7.1",
86
+ "shell-quote": "^1.8.2",
84
87
  "simple-git": "^3.27.0",
85
88
  "toml": "^3.0.0",
86
- "zx": "^8.5.3"
89
+ "zx": "^8.5.4"
87
90
  },
88
91
  "devDependencies": {
89
92
  "@leverege/eslint-config-leverege": "^5.0.1",
package/src/.swo ADDED
Binary file
package/src/Docker.mjs CHANGED
@@ -215,6 +215,8 @@ const buildContainerImage = async ( {
215
215
 
216
216
  const { fullName : builderName } = await getGcpAccount()
217
217
  const gcloudBuild = `gcloud builds submit --project ${artifactProject}`
218
+ const gcloudProjectNumber = await shellCmd( `gcloud projects describe ${artifactProject} --format="value(projectNumber)"` )
219
+ const cloudBuildSA = `--service-account=${gcloudProjectNumber}-compute@cloudbuild.gserviceaccount.com`
218
220
  const gcloudLogs = `--gcs-log-dir ${formCloudBuildBucketName( artifactProject )}/log`
219
221
  let gcloudTags = `--tag ${imageName}:${imageVersion}`
220
222
 
@@ -231,7 +233,8 @@ const buildContainerImage = async ( {
231
233
  *** Submitting Build as ${builderName} ***
232
234
  ${gcloudBuild} \\
233
235
  ${gcloudLogs} \\
234
- ${gcloudTags}
236
+ ${gcloudTags} \\
237
+ ${cloudBuildSA}
235
238
  ` ) )
236
239
 
237
240
  if ( process.env.DRY_RUN === '1' ) {
package/src/DockerPy.mjs CHANGED
@@ -185,6 +185,8 @@ async function buildContainerImage( {
185
185
 
186
186
  const { fullName : builderName } = await getGcpAccount()
187
187
  const gcloudBuild = `gcloud builds submit --project ${artifactProject}`
188
+ const gcloudProjectNumber = await shellCmd( `gcloud projects describe ${artifactProject} --format="value(projectNumber)"` )
189
+ const cloudBuildSA = `--service-account=${gcloudProjectNumber}-compute@cloudbuild.gserviceaccount.com`
188
190
  const gcloudLogs = `--gcs-log-dir ${formCloudBuildBucketName( artifactProject )}/log`
189
191
  let gcloudTags = `--tag ${imageName}:${imageVersion}`
190
192
 
@@ -201,7 +203,8 @@ async function buildContainerImage( {
201
203
  *** Submitting Build as ${builderName} ***
202
204
  ${gcloudBuild} \\
203
205
  ${gcloudLogs} \\
204
- ${gcloudTags}
206
+ ${gcloudTags} \\
207
+ ${cloudBuildSA}
205
208
  ` ) )
206
209
 
207
210
  if ( process.env.DRY_RUN === '1' ) {
package/src/Utils.mjs CHANGED
@@ -8,6 +8,7 @@ import ignore from 'ignore'
8
8
  import inquirer from 'inquirer'
9
9
  import { glob } from 'glob'
10
10
  import { packageUp } from 'package-up'
11
+ import { parse } from 'shell-quote'
11
12
  import YAML from 'js-yaml'
12
13
 
13
14
  // __dirname goes away with ESM so we take this approach instead and
@@ -72,20 +73,25 @@ export const proceed = async ( query = 'Do you wish to proceed?' ) => {
72
73
  } )
73
74
  }
74
75
 
75
- export const shellCmd = async ( cmdstr, opts = {} ) => {
76
+ export const shellCmd = async ( cmd, opts = {} ) => {
76
77
  try {
77
- // due to the escaping rules we pull apart the cmdstr and invoke $ using
78
- // the (command, argsArray) or the escaped command sent to spawn will have
79
- // addition double quotes which causes fail
80
- const [ command, ...args ] = cmdstr.split( ' ' )
78
+ let command, args
79
+
80
+ if ( Array.isArray( cmd ) ) {
81
+ [ command, ...args ] = cmd
82
+ } else {
83
+ const parsed = parse( cmd ).filter( x => typeof x === 'string' )
84
+ // the leading ; forces a break from previous line otherwise trailing ) and leading [ collide
85
+ ;[ command, ...args ] = parsed // eslint-disable-line semi-style
86
+ }
81
87
 
82
- debug( { command, args }, '<==execa $ invoke' )
83
- const results = await $( opts )`${command} ${args}`
84
- debug( { results }, '<==execa $ results' )
88
+ debug( { command, args }, '<== execa $ invoke' )
89
+ const results = await $( opts )( command, args )
90
+ debug( { results }, '<== execa $ results' )
85
91
 
86
92
  return results.stdout
87
93
  } catch ( error ) {
88
- debug( { error }, '<==shellCmd' )
94
+ debug( { error }, '<== shellCmd' )
89
95
  throw error
90
96
  }
91
97
  }
@@ -1,71 +1,71 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // helm-audit.mjs
4
- // Node.js version of helm-audit.sh to display deployed chart/image/audit info
4
+ // kind of a better "helm list" but still experimental
5
5
 
6
- import { shellCmd, log, debug } from './Utils.mjs'
7
6
  import ora from 'ora'
8
7
  import pLimit from 'p-limit'
9
8
  import chalk from 'chalk'
9
+ import { shellCmd, log, errorExit } from './Utils.mjs'
10
10
 
11
- const spinner = ora('Gathering Helm release info...').start()
12
- const limit = pLimit(5) // limit concurrent shellCmds to avoid API overload
13
- const OMIT_NAMESPACES = new Set(['estafette'])
11
+ const spinner = ora( 'Gathering Helm release info...' ).start()
12
+ const limit = pLimit( 5 ) // limit concurrent shellCmds to avoid API overload
13
+ const OMIT_NAMESPACES = new Set( [ 'estafette' ] )
14
14
 
15
15
  async function getHelmReleases() {
16
- const json = await shellCmd('helm list -A -o json')
17
- return JSON.parse(json).filter(r => !OMIT_NAMESPACES.has(r.namespace))
16
+ const json = await shellCmd( 'helm list -A -o json' )
17
+ return JSON.parse( json ).filter( r => !OMIT_NAMESPACES.has( r.namespace ) )
18
18
  }
19
19
 
20
- async function getDeployedImageTag(ns, release) {
20
+ async function getDeployedImageTag( ns, release ) {
21
21
  try {
22
- const image = await shellCmd(`kubectl get deployment -n ${ns} -l app.kubernetes.io/instance=${release} -o jsonpath={.items[0].spec.template.spec.containers[0].image}`)
23
- const tag = image.trim().split(':')[1]
22
+ const image = await shellCmd( `kubectl get deployment -n ${ns} -l app.kubernetes.io/instance=${release} -o jsonpath={.items[0].spec.template.spec.containers[0].image}` )
23
+ const tag = image.trim().split( ':' )[1]
24
24
  return tag && tag !== 'not found' ? tag : ''
25
25
  } catch {
26
26
  return ''
27
27
  }
28
28
  }
29
29
 
30
- async function getChartAppVersion(ns, release) {
30
+ async function getChartAppVersion( ns, release ) {
31
31
  try {
32
- const metadata = await shellCmd(`helm get metadata ${release} -n ${ns}`)
33
- const match = metadata.match(/^APP_VERSION:\s*(.*?)\s*$/m)
32
+ const metadata = await shellCmd( `helm get metadata ${release} -n ${ns}` )
33
+ const match = metadata.match( /^APP_VERSION:\s*(.*?)\s*$/m )
34
34
  return match ? match[1].trim() : '(unknown)'
35
35
  } catch {
36
36
  return '(unknown)'
37
37
  }
38
38
  }
39
39
 
40
- async function getHelmValue(ns, release, key) {
40
+ async function getHelmValue( ns, release, key ) {
41
41
  try {
42
- const values = await shellCmd(`helm get values ${release} -n ${ns} -o json`)
43
- const parsed = JSON.parse(values)
42
+ const values = await shellCmd( `helm get values ${release} -n ${ns} -o json` )
43
+ const parsed = JSON.parse( values )
44
44
  return parsed.helmup?.[key] || ''
45
45
  } catch {
46
46
  return ''
47
47
  }
48
48
  }
49
49
 
50
- function normalizeTag(tag) {
51
- return tag?.replace(/^v/, '').toLowerCase() || ''
50
+ function normalizeTag( tag ) {
51
+ return tag?.replace( /^v/, '' ).toLowerCase() || ''
52
52
  }
53
53
 
54
- function formatRow(name, chartVersion, appVersion, imageTag, deployT, culprit) {
55
- const release = chalk.green(name.slice(0, 25).padEnd(32))
56
- const chartVer = chalk.cyan(chartVersion.padEnd(18))
57
- const appVer = chalk.cyan(appVersion.padEnd(18))
58
- const normApp = normalizeTag(appVersion)
59
- const normImage = normalizeTag(imageTag)
60
-
61
- let imageFormatted = imageTag.padEnd(20)
62
- if (normImage && normApp && normImage === normApp) {
63
- imageFormatted = chalk.green(imageFormatted)
64
- } else if (imageTag) {
65
- imageFormatted = chalk.red(imageFormatted)
54
+ function formatRow( name, chartVersion, appVersion, imageTag, deployT, culprit ) {
55
+ const release = chalk.green( name.slice( 0, 25 ).padEnd( 32 ) )
56
+ const chartVer = chalk.cyan( chartVersion.padEnd( 18 ) )
57
+ const appVer = chalk.cyan( appVersion.padEnd( 18 ) )
58
+ const normApp = normalizeTag( appVersion )
59
+ const normImage = normalizeTag( imageTag )
60
+
61
+ let imageFormatted = imageTag.padEnd( 20 )
62
+ if ( normImage && normApp && normImage === normApp ) {
63
+ imageFormatted = chalk.green( imageFormatted )
64
+ } else if ( imageTag ) {
65
+ imageFormatted = chalk.red( imageFormatted )
66
66
  }
67
67
 
68
- const deployInfo = deployT ? chalk.gray(`${deployT} by ${culprit || '(unknown)'}`) : ''
68
+ const deployInfo = deployT ? chalk.gray( `${deployT} by ${culprit || '(unknown)'}` ) : ''
69
69
  return ` ${release}${chartVer}${appVer}${imageFormatted}${deployInfo}`
70
70
  }
71
71
 
@@ -74,43 +74,42 @@ async function audit() {
74
74
  const releases = await getHelmReleases()
75
75
 
76
76
  // sort by namespace, then release name
77
- releases.sort((a, b) => {
78
- const nsCompare = a.namespace.localeCompare(b.namespace)
79
- return nsCompare !== 0 ? nsCompare : a.name.localeCompare(b.name)
80
- })
77
+ releases.sort( ( a, b ) => {
78
+ const nsCompare = a.namespace.localeCompare( b.namespace )
79
+ return nsCompare !== 0 ? nsCompare : a.name.localeCompare( b.name )
80
+ } )
81
81
 
82
82
  spinner.text = 'Gathering chart, image, and audit metadata...'
83
83
 
84
- const rows = await Promise.all(releases.map(({ name, namespace, chart }) => limit(async () => {
85
- const chartVersion = chart?.split('-').pop() || '(unknown)'
86
- const [appVersion, imageTag, deployT, culprit] = await Promise.all([
87
- getChartAppVersion(namespace, name),
88
- getDeployedImageTag(namespace, name),
89
- getHelmValue(namespace, name, 'deployT'),
90
- getHelmValue(namespace, name, 'culprit'),
91
- ])
84
+ const rows = await Promise.all( releases.map( ( { name, namespace, chart } ) => limit( async () => {
85
+ const chartVersion = chart?.split( '-' ).pop() || '(unknown)'
86
+ const [ appVersion, imageTag, deployT, culprit ] = await Promise.all( [
87
+ getChartAppVersion( namespace, name ),
88
+ getDeployedImageTag( namespace, name ),
89
+ getHelmValue( namespace, name, 'deployT' ),
90
+ getHelmValue( namespace, name, 'culprit' ),
91
+ ] )
92
92
  return {
93
- row: formatRow(name, chartVersion, appVersion, imageTag, deployT, culprit),
93
+ row : formatRow( name, chartVersion, appVersion, imageTag, deployT, culprit ),
94
94
  namespace
95
95
  }
96
- })))
96
+ } ) ) )
97
97
 
98
98
  spinner.stop()
99
- log(`${'RELEASE'.padEnd(34)}${'CHART VERSION'.padEnd(18)}${'APP VERSION'.padEnd(18)}${'IMAGE TAG'.padEnd(20)}DEPLOY INFO`)
99
+ log( `${'RELEASE'.padEnd( 34 )}${'CHART VERSION'.padEnd( 18 )}${'APP VERSION'.padEnd( 18 )}${'IMAGE TAG'.padEnd( 20 )}DEPLOY INFO` )
100
100
 
101
101
  let lastNamespace = ''
102
- for (const { row, namespace } of rows) {
103
- if (namespace !== lastNamespace) {
104
- if (lastNamespace !== '') log('')
105
- log(chalk.bold.green(namespace))
102
+ for ( const { row, namespace } of rows ) {
103
+ if ( namespace !== lastNamespace ) {
104
+ if ( lastNamespace !== '' ) log( '' )
105
+ log( chalk.bold.green( namespace ) )
106
106
  lastNamespace = namespace
107
107
  }
108
- log(row)
108
+ log( row )
109
109
  }
110
110
  }
111
111
 
112
- audit().catch(err => {
112
+ audit().catch( ( err ) => {
113
113
  spinner.stop()
114
- console.error(err)
115
- process.exit(1)
116
- })
114
+ errorExit( err )
115
+ } )
@@ -176,7 +176,7 @@ spec:
176
176
  # LABELS = {{ $labels }}
177
177
  - alert: KubernetesHpaMetricsUnavailability
178
178
  expr: kube_horizontalpodautoscaler_status_condition{status="false", condition="ScalingActive"} == 1
179
- for: 0m
179
+ for: 3m # awesome was => 0m
180
180
  labels:
181
181
  severity: warning
182
182
  annotations:
@@ -32,7 +32,7 @@ spec:
32
32
  LABELS = {{ $labels }}
33
33
  - alert: PrometheusAllTargetsMissing
34
34
  expr: sum by (job) (up) == 0
35
- for: 0m
35
+ for: 3m # awesome was => 0m
36
36
  labels:
37
37
  severity: critical
38
38
  annotations: