@leverege/build-tools 2.61.7 → 2.62.0-alpha.1

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.61.7",
3
+ "version": "2.62.0-alpha.1",
4
4
  "description": "A collection of build / support tools for Leverege developers",
5
5
  "main": "index.js",
6
6
  "repository": {
@@ -16,13 +16,14 @@
16
16
  "bin": {
17
17
  "build-tools": "src/build-tools.mjs",
18
18
  "build-and-push": "src/build-and-push.sh",
19
- "build-cnpg-image": "src/build-cnpg-image.mjs",
20
19
  "chart-to-registry": "src/chart-to-registry.mjs",
21
20
  "circleate": "src/circleate.sh",
21
+ "cnpg-backup": "src/cnpg-backup.mjs",
22
22
  "decrypt-secrets": "src/decrypt-secrets.sh",
23
23
  "dirty-git": "src/dirty-git.sh",
24
24
  "dockreate": "src/dockreate.sh",
25
25
  "docker-to-registry": "src/docker-to-registry.mjs",
26
+ "docker-to-registry.sh": "src/docker-to-registry.sh",
26
27
  "encrypt-secrets": "src/encrypt-secrets.sh",
27
28
  "firebaseDeploy": "src/firebaseDeploy.mjs",
28
29
  "firebaseServe": "src/firebaseServe.mjs",
@@ -36,7 +37,9 @@
36
37
  "helminit": "src/helmup.sh",
37
38
  "helmwhat": "src/helmup.sh",
38
39
  "hook-and-release": "src/hook-and-release.mjs",
40
+ "k8cryo": "src/k8cryo.sh",
39
41
  "k8scale": "src/k8scale.sh",
42
+ "k8thaw": "src/k8cryo.sh",
40
43
  "k8x": "src/k8x.sh",
41
44
  "klog": "src/klog.sh",
42
45
  "npm-link": "src/npm-link.sh",
@@ -50,7 +53,6 @@
50
53
  "refresh-npm-token": "src/refresh-npm-token.mjs",
51
54
  "refresh-py-idx": "src/refresh-py-idx.sh",
52
55
  "send-to-slack": "src/send-to-slack.mjs",
53
- "snapshot-cnpg": "src/snapshot-cnpg.mjs",
54
56
  "tag-release": "src/tag-release.mjs",
55
57
  "unleash": "src/unleash.mjs"
56
58
  },
@@ -59,28 +61,31 @@
59
61
  "dependencies": {
60
62
  "@google-cloud/artifact-registry": "^3.5.0",
61
63
  "@leverege/jsdoc-template": "^1.0.1",
64
+ "ansi-colors": "^4.1.3",
62
65
  "chalk": "^5.4.1",
63
66
  "command-line-args": "^6.0.1",
64
67
  "command-line-usage": "^7.0.3",
65
68
  "deepmerge": "^4.3.1",
66
69
  "enquirer": "^2.4.1",
67
70
  "execa": "^9.5.2",
68
- "glob": "^11.0.1",
71
+ "glob": "^11.0.0",
69
72
  "handlebars": "^4.7.8",
70
- "inquirer": "^12.4.1",
73
+ "inquirer": "^12.3.0",
71
74
  "js-yaml": "^4.1.0",
72
75
  "jsdoc": "^4.0.4",
73
76
  "ms": "^2.1.3",
74
77
  "npm-registry-fetch": "^18.0.2",
75
78
  "package-up": "^5.0.0",
76
79
  "parse-gitignore": "^2.0.0",
80
+ "read-pkg": "^9.0.1",
77
81
  "readline-sync": "^1.4.10",
78
- "semver": "^7.7.1",
82
+ "semver": "^7.6.3",
79
83
  "simple-git": "^3.27.0",
80
- "zx": "^8.3.2"
84
+ "toml": "^3.0.0",
85
+ "zx": "^8.3.0"
81
86
  },
82
87
  "devDependencies": {
83
88
  "@leverege/eslint-config-leverege": "^5.0.1",
84
- "npm": "^11.1.0"
89
+ "npm": "^11.0.0"
85
90
  }
86
91
  }
package/src/Docker.mjs CHANGED
@@ -24,7 +24,7 @@ const dockerfileNodeVersion = 'jod-alpine'
24
24
  // the build-tools repository, but it just became simpler to pull the contents
25
25
  // directly into these variables and forego the file loading.
26
26
  //
27
- const dockerfilePluginTemplate = `
27
+ const pluginTemplate = `
28
28
  # Dockerfile.plugin - optionally extend the service Docker image
29
29
  #
30
30
  # This file may be used to run additional docker commands during the image
@@ -38,14 +38,6 @@ const dockerfilePluginTemplate = `
38
38
  # Keep in mind that the Alpine Linux base image is used to keep image
39
39
  # footprints small, so adding packages "just because" is not considered
40
40
  # a best practice.
41
- `
42
- const bashrcPluginTemplate = `
43
-
44
- # Bashrc.plugin - optionally extend the image .bashrc file
45
- #
46
- # This plugin file may contain additional .bashrc settigns / functions to
47
- # provide on the target image.
48
-
49
41
  `
50
42
  const dockerfileTemplate = fs.readFileSync( path.join( DIRNAME, './templates/dockerfileTemplate.hbs' ), 'utf8' )
51
43
  const bashrcTemplate = fs.readFileSync( path.join( DIRNAME, './templates/bashrcTemplate.hbs' ), 'utf8' )
@@ -74,10 +66,9 @@ const setPreviousBuild = ( version ) => {
74
66
  fs.writeFileSync( previousFile, version )
75
67
  }
76
68
 
77
- const generateDockerfile = async ( options ) => {
69
+ const generateDockerfile = ( options ) => {
78
70
 
79
- const gitReference = await shellCmd( 'git rev-parse --short HEAD' )
80
- const settings = { gitReference, ...defaultSettings, ...options }
71
+ const settings = { ...defaultSettings, ...options }
81
72
 
82
73
  // defaults to the current "official" version of node unless it gets
83
74
  // overridden in the leverege.nodeimg package.json stanza
@@ -94,31 +85,24 @@ const generateDockerfile = async ( options ) => {
94
85
  fs.mkdirSync( './docker' ) // TODO: blindly assumes the mkdir succeeds
95
86
  }
96
87
 
97
- // Create a bashrc plugin file if one does not already exist
98
- const bashrcPluginFile = './docker/Bashrc.plugin'
99
- if ( !fs.existsSync( bashrcPluginFile ) ) {
100
- warning( `creating the missing ${bashrcPluginFile} file in the docker directory\n` )
101
- fs.writeFileSync( bashrcPluginFile, bashrcPluginTemplate )
102
- }
103
- const bashrcPlugin = fs.readFileSync( bashrcPluginFile )
104
-
105
- // Build the target bashrc file by using the template plus Bashrc.plugin
106
88
  const bashrcFile = './docker/bashrc'
107
- if ( fs.existsSync( bashrcFile ) ) {
108
- fs.rmSync( bashrcFile ) // start with a clean bashrc
109
- }
110
-
111
- try {
112
- fs.writeFileSync( bashrcFile, bashrcTemplate )
113
- fs.appendFileSync( bashrcFile, bashrcPlugin )
114
- } catch ( err ) {
115
- errorExit( `***ERROR: failed creation of the ${bashrcFile} file` )
89
+ // DISABLING exists check. With addition of Bashrc.plugin, the file needs to
90
+ // always be created or we encounter errors
91
+ if ( true ) { // !fs.existsSync( bashrcFile ) ) {
92
+ let bf = bashrcTemplate
93
+ const bashrcFilePlugin = './docker/Bashrc.plugin'
94
+ if ( fs.existsSync( bashrcFilePlugin ) ) {
95
+ const bashrcAdditions = fs.readFileSync( bashrcFilePlugin )
96
+ bf = `${bf}\n${bashrcAdditions}`
97
+ }
98
+ warning( `creating the missing ${bashrcFile} file in the docker directory` )
99
+ fs.writeFileSync( bashrcFile, bf )
116
100
  }
117
101
 
118
102
  const dockerfilePlugin = './docker/Dockerfile.plugin'
119
103
  if ( !fs.existsSync( dockerfilePlugin ) ) {
120
104
  warning( `creating the missing ${dockerfilePlugin} file in the docker directory` )
121
- fs.writeFileSync( dockerfilePlugin, dockerfilePluginTemplate )
105
+ fs.writeFileSync( dockerfilePlugin, pluginTemplate )
122
106
  }
123
107
 
124
108
  try {
@@ -130,7 +114,7 @@ const generateDockerfile = async ( options ) => {
130
114
  errorExit( `***ERROR: expected the ./build directory to exist - ${chalk.yellow( 'npm run build' )}` )
131
115
  }
132
116
 
133
- // At this point the docker plugin file better exist.
117
+ // At this point the plugin template better exist.
134
118
  if ( fs.existsSync( dockerfilePlugin ) ) {
135
119
  settings.pluginfile = fs.readFileSync( dockerfilePlugin )
136
120
  } else {
@@ -189,22 +173,12 @@ const buildContainerImage = async ( {
189
173
  // TODO: This is janky - I'll clean it up later
190
174
  // NOTE: this is dealing with raw filesystem interactions, meaning there
191
175
  // isn't a shell performing file globbing and what not
192
- //
193
- // Steps taken here attempt to minimize impact on legacy build setups
194
- // 1. rename build dir to workspace
195
- // 2. create the actual build dir and move workspace into it
196
- // 3. move the Dockerfile into build and make a copy for image root
197
- // 4. copy the bashrc file into build and .bashrc on the image root
198
- // 5. drop a copy of dev's npmrc to use for build process
199
- // 6. drop a copy of package.json and the lock into the image root
200
- //
201
176
  fs.renameSync( './build', './workspace' )
202
177
  fs.mkdirSync( './build' )
203
178
  fs.renameSync( './workspace', buildWorkspace )
204
179
  fs.renameSync( './docker/Dockerfile', './build/Dockerfile' )
205
- fs.cpSync( './build/Dockerfile', `${buildWorkspace}/Dockerfile` )
206
- fs.renameSync( './docker/bashrc', './build/bashrc' )
207
180
  fs.cpSync( `${process.env.HOME}/.npmrc`, './build/.npmrc' )
181
+ fs.cpSync( './docker/bashrc', './build/bashrc' )
208
182
  fs.cpSync( './package.json', `${buildWorkspace}/package.json` )
209
183
  fs.cpSync( './package-lock.json', `${buildWorkspace}/package-lock.json` )
210
184
  if ( isNpmWorkspace ) {
@@ -214,7 +188,7 @@ const buildContainerImage = async ( {
214
188
  setPreviousBuild( imageVersion ) // update docker/.previous file
215
189
 
216
190
  const { fullName : builderName } = await getGcpAccount()
217
- const gcloudBuild = `gcloud builds submit --project ${artifactProject}`
191
+ const gcloudBuild = `time gcloud builds submit --project ${artifactProject}`
218
192
  const gcloudLogs = `--gcs-log-dir ${formCloudBuildBucketName( artifactProject )}/log`
219
193
  let gcloudTags = `--tag ${imageName}:${imageVersion}`
220
194
 
@@ -0,0 +1,257 @@
1
+ import fs from 'node:fs'
2
+ import path from 'node:path'
3
+ import url from 'node:url'
4
+
5
+ import chalk from 'chalk'
6
+ import handlebars from 'handlebars'
7
+
8
+ import {
9
+ errorExit,
10
+ getDateTimestamp,
11
+ getGcpAccount,
12
+ log,
13
+ proceed,
14
+ shellCmd,
15
+ warning
16
+ } from './Utils.mjs'
17
+
18
+ const DIRNAME = path.dirname( url.fileURLToPath( import.meta.url ) )
19
+
20
+ // The contents of these variables were initially located in files that live in
21
+ // the build-tools repository, but it just became simpler to pull the contents
22
+ // directly into these variables and forego the file loading.
23
+ //
24
+ const pluginTemplate = `
25
+ # Dockerfile.plugin - optionally extend the service Docker image
26
+ #
27
+ # This file may be used to run additional docker commands during the image
28
+ # build process without needing to maintain a local custom Dockerfile. For
29
+ # example, uncommenting the following docker RUN command will cause the
30
+ # curl and vim packages to be added to the deployed image thus making them
31
+ # available from the pod's command line on k8s:
32
+ #
33
+ # RUN apk update && apk add --no-cache curl vim
34
+ #
35
+ # Keep in mind that the Alpine Linux base image is used to keep image
36
+ # footprints small, so adding packages "just because" is not considered
37
+ # a best practice.
38
+ `
39
+ const dockerfileTemplate = fs.readFileSync( path.join( DIRNAME, './templates/dockerfileTemplatePy.hbs' ), 'utf8' )
40
+ const cloudBuildSteps = fs.readFileSync( path.join( DIRNAME, './templates/cloudBuildSteps.hbs' ), 'utf8' )
41
+ let bashrcTemplate = fs.readFileSync( path.join( DIRNAME, './templates/bashrcTemplate.hbs' ), 'utf8' )
42
+ const bashrcPyTemplate = fs.readFileSync( path.join( DIRNAME, './templates/bashrcTemplatePy.hbs' ), 'utf8' )
43
+ bashrcTemplate = `${bashrcTemplate}\n${bashrcPyTemplate}`
44
+
45
+ const defaultSettings = {
46
+ apkadds : '',
47
+ date : getDateTimestamp(),
48
+ nodeimage : 'jod-alpine',
49
+ imageBase : 'node:jod-alpine',
50
+ npmlogging : process.env.VERBOSE_NPM_LOGGING ? '--ddd' : '--silent',
51
+ npmVersion : 'npm@11',
52
+ pluginfile : '# NO PLUGIN',
53
+ preInstallPluginfile : '# NO PRE-INSTALL PLUGIN',
54
+ regvers : 'package.version',
55
+ runuser : 'python',
56
+ }
57
+
58
+ const previousFile = './docker/.previous'
59
+
60
+ function getPreviousBuild() {
61
+ return fs.existsSync( previousFile ) ? fs.readFileSync( previousFile ) : 'FIRST BUILD'
62
+ }
63
+
64
+ const setPreviousBuild = ( version ) => {
65
+ fs.writeFileSync( previousFile, version )
66
+ }
67
+
68
+ function generateDockerfile( options ) {
69
+
70
+ const settings = { ...defaultSettings, ...options }
71
+
72
+ if ( !settings.imageBase ) {
73
+ warning( 'using the default image python:3.12.8-slim-bookworm' )
74
+ settings.image = 'python:3.12.8-slim-bookworm'
75
+ } else {
76
+ settings.image = settings.imageBase
77
+ }
78
+ // Ensure the presence of the docker dir with plugin and bashrc - this code
79
+ // could probably be tightened up a little.
80
+ try {
81
+ fs.readdirSync( './docker' )
82
+ } catch ( err ) {
83
+ warning( 'creating the missing ./docker directory' )
84
+ fs.mkdirSync( './docker' ) // TODO: blindly assumes the mkdir succeeds
85
+ }
86
+
87
+ const bashrcFile = './docker/bashrc'
88
+ let bf = bashrcTemplate
89
+ const bashrcFilePlugin = './docker/Bashrc.plugin'
90
+ if ( fs.existsSync( bashrcFilePlugin ) ) {
91
+ const bashrcAdditions = fs.readFileSync( bashrcFilePlugin )
92
+ bf = `${bf}\n${bashrcAdditions}`
93
+ }
94
+ fs.writeFileSync( bashrcFile, bf )
95
+
96
+ const dockerfilePlugin = './docker/Dockerfile.plugin'
97
+ if ( !fs.existsSync( dockerfilePlugin ) ) {
98
+ warning( `creating the missing ${dockerfilePlugin} file in the docker directory` )
99
+ fs.writeFileSync( dockerfilePlugin, pluginTemplate )
100
+ }
101
+
102
+ try {
103
+ const build = fs.readdirSync( './build' )
104
+ if ( build.length === 0 ) {
105
+ errorExit( `***ERROR: the build dir is empty - ${chalk.yellow( 'npm run build' )}` )
106
+ }
107
+ } catch ( err ) {
108
+ errorExit( `***ERROR: expected the ./build directory to exist - ${chalk.yellow( 'npm run build' )}` )
109
+ }
110
+
111
+ // At this point the plugin template better exist.
112
+ if ( fs.existsSync( dockerfilePlugin ) ) {
113
+ settings.pluginfile = fs.readFileSync( dockerfilePlugin )
114
+ } else {
115
+ errorExit( `***ERROR: something went wrong with ${dockerfilePlugin} plugin creation` )
116
+ }
117
+
118
+ const dockerfilePrePlugin = './docker/DockerfilePreInstall.plugin'
119
+ if ( fs.existsSync( dockerfilePrePlugin ) ) {
120
+ settings.preInstallPluginfile = fs.readFileSync( dockerfilePrePlugin )
121
+ }
122
+
123
+ const compiled = handlebars.compile( dockerfileTemplate, { noEscape : true } )
124
+ const replaced = compiled( settings )
125
+ // temporarily write the Dockerfile to the docker subdir - the container
126
+ // image builder will then move it over to the build subdir
127
+ const dockerfile = './docker/Dockerfile'
128
+ try {
129
+ fs.writeFileSync( dockerfile, replaced )
130
+ } catch ( err ) {
131
+ errorExit( `***ERROR: failed to write ${dockerfile}\n${err}` )
132
+ }
133
+
134
+ const previousBuild = getPreviousBuild()
135
+ const dockerInfo = { dockerfile, previousBuild, ...settings }
136
+ delete dockerInfo.pluginfile
137
+ return dockerInfo
138
+ }
139
+
140
+ function formCloudBuildBucketName( artifactProject ) {
141
+ return `gs://${artifactProject}_cloudbuild`
142
+ }
143
+
144
+ async function validateCloudBuildBucket( artifactProject ) {
145
+ const bucketName = formCloudBuildBucketName( artifactProject )
146
+ log( chalk.green.bold( `Verifying the build bucket exists => ${bucketName}\n` ) )
147
+ try {
148
+ await shellCmd( `gsutil ls -p ${artifactProject} -b ${bucketName}` )
149
+ } catch ( error ) {
150
+ errorExit( `***Error: from Docker.validateCloudBuildBucket\n\n${chalk.bold.yellow( error )}` )
151
+ }
152
+ }
153
+
154
+ async function buildContainerImage( {
155
+ artifactProject, artifactRegistry, containerName,
156
+ imageVersion, isNpmWorkspace, options
157
+ } ) {
158
+
159
+ const useCloudBuildFile = true
160
+ const buildWorkspace = './build/workspace' // passed to Cloud Build
161
+ const imageName = `${artifactRegistry}/images/${containerName}`
162
+
163
+ if ( fs.existsSync( buildWorkspace ) ) {
164
+ fs.renameSync( buildWorkspace, `${buildWorkspace}-junk` )
165
+ try {
166
+ fs.rmSync( `${buildWorkspace}-junk`, { recursive : true } )
167
+ } catch ( err ) {
168
+ log( `***Error: from Docker.buildContainerImage\n\n${chalk.bold.yellow( err )}` )
169
+ }
170
+ }
171
+
172
+ // TODO: This is janky - I'll clean it up later
173
+ // NOTE: this is dealing with raw filesystem interactions, meaning there
174
+ // isn't a shell performing file globbing and what not
175
+ fs.renameSync( './build', './workspace' )
176
+ fs.mkdirSync( './build' )
177
+ fs.renameSync( './workspace', buildWorkspace )
178
+ fs.renameSync( './docker/Dockerfile', './build/Dockerfile' )
179
+ // fs.cpSync( `${process.env.HOME}/.npmrc`, './build/.npmrc' )
180
+ fs.cpSync( './docker/bashrc', './build/bashrc' )
181
+ // fs.cpSync( './package.json', `${buildWorkspace}/package.json` )
182
+ // fs.cpSync( './package-lock.json', `${buildWorkspace}/package-lock.json` )
183
+
184
+ setPreviousBuild( imageVersion ) // update docker/.previous file
185
+
186
+ const { fullName : builderName } = await getGcpAccount()
187
+ const gcloudBuild = `time gcloud builds submit --project ${artifactProject}`
188
+ const gcloudLogs = `--gcs-log-dir ${formCloudBuildBucketName( artifactProject )}/log`
189
+ let gcloudTags = `--tag ${imageName}:${imageVersion}`
190
+
191
+ if ( useCloudBuildFile ) {
192
+ const cloudBuildFile = './docker/cloudbuild.yaml'
193
+ gcloudTags = `--config=${cloudBuildFile}`
194
+ const cbst = handlebars.compile( cloudBuildSteps, { noEscape : true } )
195
+ const cbs = cbst( { artifactProject, artifactRegistry, imageName, imageVersion } )
196
+
197
+ fs.writeFileSync( cloudBuildFile, cbs )
198
+ }
199
+
200
+ log( chalk.green.bold( `
201
+ *** Submitting Build as ${builderName} ***
202
+ ${gcloudBuild} \\
203
+ ${gcloudLogs} \\
204
+ ${gcloudTags}
205
+ ` ) )
206
+
207
+ if ( process.env.DRY_RUN === '1' ) {
208
+ log( '\n***Exiting from DRY_RUN\n' )
209
+ process.exit( 0 )
210
+ }
211
+
212
+ await shellCmd( `${gcloudBuild} ${gcloudLogs} ${gcloudTags} ./build`, { stdio : 'inherit' } )
213
+
214
+ const imageTag = `${defaultSettings.date}-${defaultSettings.nodeimage}-${builderName}`
215
+ await shellCmd(
216
+ `gcloud container images add-tag --quiet ${imageName}:${imageVersion} ${imageName}:${imageTag} ${imageName}:latest`
217
+ )
218
+ }
219
+
220
+ async function repoCleanup() {
221
+ // remove garbage from the repo
222
+ const garbage = [
223
+ 'build',
224
+ 'dist',
225
+ 'docker/.keep',
226
+ 'docker/.npmrc',
227
+ 'docker/.gitignore',
228
+ 'docker/.previous',
229
+ 'docker/Dockerfile',
230
+ 'docker/workspace',
231
+ ]
232
+ garbage.forEach( trash => fs.rmSync( trash, { recursive : true, force : true } ) )
233
+
234
+ fs.writeFileSync( 'docker/.gitignore', '.previous\nDockerfile' )
235
+
236
+ await shellCmd( 'git add -f docker' )
237
+
238
+ log( `
239
+ ${chalk.yellow.bold( '***IMPORTANT***' )}
240
+
241
+ Please make the following .gitignore modifications:
242
+ change /dist to ${chalk.green.bold( '/build' )}
243
+ remove ${chalk.red.bold( '/docker' )}
244
+ ` )
245
+
246
+ await proceed( 'Acknowledge the .gitignore mods were made?' )
247
+ }
248
+
249
+ export default {
250
+ getPreviousBuild,
251
+ setPreviousBuild,
252
+ generateDockerfile,
253
+ formCloudBuildBucketName,
254
+ validateCloudBuildBucket,
255
+ buildContainerImage,
256
+ repoCleanup,
257
+ }
package/src/Utils.mjs CHANGED
@@ -54,10 +54,6 @@ export const isString = ( s ) => {
54
54
  * General "yes" to proceed function.
55
55
  */
56
56
  export const proceed = async ( query = 'Do you wish to proceed?' ) => {
57
- if ( process.env.CICD_PIPELINE === '1' ) {
58
- log( '\n*** CICD Pipeline - skipping user prompts' )
59
- return
60
- }
61
57
  await inquirer.prompt( [
62
58
  {
63
59
  type : 'confirm',
@@ -403,7 +399,6 @@ export const getRepositoryDescr = async () => {
403
399
  const currentDir = process.cwd()
404
400
  const workingDir = process.env.PWD
405
401
  const gitRoot = await getGitRootDirectory()
406
- const isGitRepo = gitRoot !== undefined
407
402
  const gitHooksPath = await getGitHooksPath()
408
403
  const { branch : gitBranch, upstream : gitUpstream } = await getGitBranchAndUpstream()
409
404
  const subPkgs = await glob( `${gitRoot}/packages/**/package.json`, { ignore : '/**/node_modules/**' } )
@@ -425,7 +420,6 @@ export const getRepositoryDescr = async () => {
425
420
  gitRoot,
426
421
  gitUpstream,
427
422
  helmChart,
428
- isGitRepo,
429
423
  isMonoRepo,
430
424
  isNpmWorkspace,
431
425
  rootPackageJson,
package/src/bash-funcs CHANGED
@@ -42,10 +42,6 @@ function clearlyWarn() {
42
42
  CLEARWARN
43
43
  }
44
44
 
45
- function warning() {
46
- clearlyWarn DO_NOT_CLEAR
47
- }
48
-
49
45
  function warnOnError() {
50
46
  [ $1 -ne 0 ] && printf "\n$YELO_WARN $2\n"
51
47
  }