@leverege/build-tools 2.61.6 → 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.6",
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,25 +61,28 @@
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.3.3",
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.0",
82
+ "semver": "^7.6.3",
79
83
  "simple-git": "^3.27.0",
80
- "zx": "^8.3.1"
84
+ "toml": "^3.0.0",
85
+ "zx": "^8.3.0"
81
86
  },
82
87
  "devDependencies": {
83
88
  "@leverege/eslint-config-leverege": "^5.0.1",
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' )
@@ -93,31 +85,24 @@ const generateDockerfile = ( options ) => {
93
85
  fs.mkdirSync( './docker' ) // TODO: blindly assumes the mkdir succeeds
94
86
  }
95
87
 
96
- // Create a bashrc plugin file if one does not already exist
97
- const bashrcPluginFile = './docker/Bashrc.plugin'
98
- if ( !fs.existsSync( bashrcPluginFile ) ) {
99
- warning( `creating the missing ${bashrcPluginFile} file in the docker directory\n` )
100
- fs.writeFileSync( bashrcPluginFile, bashrcPluginTemplate )
101
- }
102
- const bashrcPlugin = fs.readFileSync( bashrcPluginFile )
103
-
104
- // Build the target bashrc file by using the template plus Bashrc.plugin
105
88
  const bashrcFile = './docker/bashrc'
106
- if ( fs.existsSync( bashrcFile ) ) {
107
- fs.rmSync( bashrcFile ) // start with a clean bashrc
108
- }
109
-
110
- try {
111
- fs.writeFileSync( bashrcFile, bashrcTemplate )
112
- fs.appendFileSync( bashrcFile, bashrcPlugin )
113
- } catch ( err ) {
114
- 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 )
115
100
  }
116
101
 
117
102
  const dockerfilePlugin = './docker/Dockerfile.plugin'
118
103
  if ( !fs.existsSync( dockerfilePlugin ) ) {
119
104
  warning( `creating the missing ${dockerfilePlugin} file in the docker directory` )
120
- fs.writeFileSync( dockerfilePlugin, dockerfilePluginTemplate )
105
+ fs.writeFileSync( dockerfilePlugin, pluginTemplate )
121
106
  }
122
107
 
123
108
  try {
@@ -129,7 +114,7 @@ const generateDockerfile = ( options ) => {
129
114
  errorExit( `***ERROR: expected the ./build directory to exist - ${chalk.yellow( 'npm run build' )}` )
130
115
  }
131
116
 
132
- // At this point the docker plugin file better exist.
117
+ // At this point the plugin template better exist.
133
118
  if ( fs.existsSync( dockerfilePlugin ) ) {
134
119
  settings.pluginfile = fs.readFileSync( dockerfilePlugin )
135
120
  } else {
@@ -192,8 +177,8 @@ const buildContainerImage = async ( {
192
177
  fs.mkdirSync( './build' )
193
178
  fs.renameSync( './workspace', buildWorkspace )
194
179
  fs.renameSync( './docker/Dockerfile', './build/Dockerfile' )
195
- fs.renameSync( './docker/bashrc', './build/bashrc' )
196
180
  fs.cpSync( `${process.env.HOME}/.npmrc`, './build/.npmrc' )
181
+ fs.cpSync( './docker/bashrc', './build/bashrc' )
197
182
  fs.cpSync( './package.json', `${buildWorkspace}/package.json` )
198
183
  fs.cpSync( './package-lock.json', `${buildWorkspace}/package-lock.json` )
199
184
  if ( isNpmWorkspace ) {
@@ -203,7 +188,7 @@ const buildContainerImage = async ( {
203
188
  setPreviousBuild( imageVersion ) // update docker/.previous file
204
189
 
205
190
  const { fullName : builderName } = await getGcpAccount()
206
- const gcloudBuild = `gcloud builds submit --project ${artifactProject}`
191
+ const gcloudBuild = `time gcloud builds submit --project ${artifactProject}`
207
192
  const gcloudLogs = `--gcs-log-dir ${formCloudBuildBucketName( artifactProject )}/log`
208
193
  let gcloudTags = `--tag ${imageName}:${imageVersion}`
209
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
  }
@@ -0,0 +1,291 @@
1
+ #!/usr/bin/env node
2
+ /*
3
+ * docker-to-registry-py will...
4
+ */
5
+ import fs from 'node:fs'
6
+ import toml from 'toml'
7
+ import chalk from 'chalk'
8
+ import semver from 'semver'
9
+
10
+ import {
11
+ debug, log,
12
+ errorExit,
13
+ getGitBranchAndUpstream,
14
+ gitRepoIsDirty,
15
+ parseHelmChart,
16
+ proceed,
17
+ shellCmd } from './Utils.mjs'
18
+
19
+ import Docker from './DockerPy.mjs'
20
+ import { version } from 'node:os'
21
+
22
+ // refresh-npm-token does not throw so no need to try, but it emits in debug
23
+ const refreshErr = await shellCmd( 'refresh-npm-token' )
24
+ if ( refreshErr && !process.env.BUILD_TOOLS_DEBUG ) {
25
+ log( refreshErr ) // most likely the token refreshed message
26
+ }
27
+
28
+ const options = {}
29
+ let imageVersion = null
30
+ // Expected to be invoked like docker-to-registry-py v1.2.3
31
+ for ( let n = 2; n < process.argv.length; n++ ) {
32
+ if ( process.argv[n].startsWith( '-' ) ) {
33
+ const str = process.argv[n].slice( 1 )
34
+ if ( str.indexOf( '=' ) > 0 ) {
35
+ const [ key, value ] = str.split( '=' )
36
+ options[key] = value
37
+ } else {
38
+ options[str] = true
39
+ }
40
+ } else {
41
+ imageVersion = process.argv[n]
42
+ }
43
+ }
44
+ if ( !imageVersion ) {
45
+ errorExit( '***Error: docker-to-registry-py requires an image version' )
46
+ }
47
+
48
+ // may use guide-me or guideme to ask for update guidance
49
+ const giveGuidance = imageVersion.match( /^guide-*me$/ ) !== null
50
+
51
+ const willGitTag = imageVersion.match( /^v\d+\.\d+\.\d+$/ )
52
+ const tagInfo = willGitTag ?
53
+ chalk.yellow.bold( 'will be git tagged' ) :
54
+ chalk.red( 'BETA RELEASE WILL NOT BE GIT TAGGED' )
55
+
56
+ const repoIsDirty = await gitRepoIsDirty()
57
+
58
+ if ( willGitTag && repoIsDirty ) {
59
+ log( `
60
+ ${chalk.red.bold( '***ERROR: attempting to tag a non-beta dirty git repository' )}
61
+
62
+ You are attempting to create a tagged release image for pushing to the
63
+ artifact registry, but there are locally modified files. This is not
64
+ allowed since the applied tag will not be relevant to the image version
65
+ due to the pending commits.
66
+
67
+ Available options for proceeding:
68
+
69
+ ${chalk.green.bold( '1) cleanly commit all local mods assuming relevance' )}
70
+ ${chalk.yellow( '2) eliminate unwanted local modifications' )}
71
+ ${chalk.red( '3) stash anything that is irrelevant to this release' )}
72
+
73
+ ` )
74
+ process.exit( 1 )
75
+ }
76
+
77
+ if ( !fs.existsSync( './helm' ) ) {
78
+ log( `
79
+ ${chalk.red.bold( '***Error: docker-to-registry-py requires a helm chart directory' )}
80
+
81
+ The docker-to-registry-py script expects to run in the root directory of a k8s
82
+ service, which requires a helm chart directory. It also expects a docker
83
+ directory but will build that if it does not exist.
84
+
85
+ ` )
86
+ process.exit( 1 )
87
+ }
88
+
89
+ const tomlStr = fs.readFileSync( './pyproject.toml' )
90
+ const pyproject = toml.parse( tomlStr )
91
+ const repoDescr = {
92
+ artifactProject : pyproject.leverege.project || 'leverege-registry',
93
+ containerName : pyproject.project.name,
94
+ packageVersion : pyproject.project.version,
95
+ artifactRegistry : pyproject.leverege.registry || 'us-docker.pkg.dev/leverege-registry/stack',
96
+ registryFolder : `${pyproject.leverege.registryFolder}/images/${pyproject.project.name}`,
97
+ imageBase : pyproject.leverege.imageBase,
98
+ helmChart : await parseHelmChart(),
99
+ }
100
+
101
+ debug( { repoDescr }, '<==The Repo Description' )
102
+
103
+ const dockerInfo = await Docker.generateDockerfile( {
104
+ regvers : repoDescr.packageVersion,
105
+ imageBase : repoDescr.imageBase,
106
+ } )
107
+
108
+ debug( { dockerInfo }, '<==The Docker Info' )
109
+
110
+ const {
111
+ artifactProject,
112
+ artifactRegistry,
113
+ packageVersion,
114
+ containerName,
115
+ helmChart,
116
+ } = repoDescr
117
+
118
+ if ( giveGuidance ) {
119
+ await Docker.validateCloudBuildBucket( artifactProject )
120
+ }
121
+
122
+ const registryFolder = `${artifactRegistry}/images/${containerName}`
123
+
124
+ // Update the dependencies...
125
+ log( chalk.green.bold( 'Updating dependencies and workspace...' ) )
126
+ await shellCmd( 'npm install', { stdio : 'inherit' } )
127
+
128
+ if ( giveGuidance ) {
129
+ await Docker.repoCleanup() // adjusts gitignore files and removes cruft
130
+ log( `
131
+
132
+
133
+
134
+ ${chalk.green.bold( '-------------------- Potential Helm Chart Mods --------------------' )}
135
+
136
+ Moving to the new artifact-registry for docker image storage may also require
137
+ helm chart changes depending on how old the current charts are. Charts that
138
+ contain helm/values.yaml files resembling this:
139
+
140
+ ${chalk.yellow.bold( `serviceConfig:
141
+ VERSION: v1.2.3
142
+ PREEMPTIBLE: true` )}
143
+
144
+ are pre-ignition era charts and should be replaced with the latest helm chart
145
+ templates available from ignition. Either dive in or ask devops for a hand
146
+ when converting these legacy / deprecated charts.
147
+
148
+
149
+ More recently updated helm charts that have already started the migration to
150
+ the new approach may already have registry entries like this:
151
+
152
+ ${chalk.yellow.bold( `image:
153
+ registry: gcr.io/leverege-docker-images
154
+ tag: ""` )}
155
+
156
+ The above registry statement references the deprecated container registry and
157
+ must be adjusted accordingly to resemble:
158
+
159
+ ${chalk.green.bold( 'registry: us-docker.pkg.dev/leverege-registry/<registry folder>/images' )}
160
+
161
+ There may also be a corresponding modification needed in the helm template
162
+ deployment.yaml file in the container image spec:
163
+
164
+ ${chalk.green.bold( 'image: {{ .Values.image.registry }}/{{ .Chart.Name }}:{{ default .Chart.AppVersion .Values.image.tag }}' )}
165
+
166
+
167
+ ${chalk.magenta.bold( `Upgrading all service charts to the latest ignition template chart structure
168
+ is the preferred approach to making the transition to the artifact registry.` )}
169
+
170
+ ` )
171
+ log( chalk.green.bold( '*** docker-to-registry-py guidance complete - ready for dockerization ***' ) )
172
+ process.exit( 0 )
173
+ }
174
+
175
+ // do chart checks too
176
+ let chart
177
+ if ( options?.helmChecks !== 'false' ) {
178
+ chart = helmChart?.yaml['Chart.yaml']
179
+ const values = helmChart?.yaml['values.yaml']
180
+ const expectedChartRegistry = `${artifactRegistry}/images`
181
+
182
+ if ( expectedChartRegistry !== values.image?.registry ) {
183
+ log( `
184
+ ${chalk.red.bold( '***Error: mismatched package.json registry and helm/values.yaml' )}
185
+
186
+ The registry specified in the package.json leverege stanza does not line up
187
+ with the image registry in helm/values.yaml. The naming convention expects
188
+ the '/images' suffix to be added to the package.json registry string and then
189
+ stored as the image.registry in the helm/values.yaml file.
190
+
191
+ Current settings:
192
+ package.json registry => ${chalk.yellow.bold( artifactRegistry )}
193
+ values.yaml registry => ${chalk.red.bold( values.image?.registry )}
194
+
195
+ Expected settings:
196
+ values.yaml registry => ${chalk.green.bold( expectedChartRegistry )}
197
+ ` )
198
+
199
+ if ( !values.image ) {
200
+ log( `
201
+ ${chalk.yellow.bold( '***DEPRECATED: legacy helm charts detected' )}
202
+
203
+ The helm chart structure appears to be based on the pre-ignition helm chart
204
+ layouts. The charts must be upgraded before docker-to-registry-py can complete
205
+ its job.
206
+
207
+ ` )
208
+ }
209
+
210
+ process.exit( 1 )
211
+ }
212
+ }
213
+
214
+ // Give the summary and the user a chance to proceed or not
215
+ log( `
216
+ ${chalk.green.bold( 'Build Information:' )}
217
+ Container: ${chalk.green.bold( containerName )}
218
+ Version: ${chalk.green.bold( imageVersion )} ${tagInfo}
219
+ Registry: ${chalk.green.bold( artifactRegistry )}
220
+ Image Folder: ${chalk.yellow.bold( registryFolder )}
221
+
222
+ ${chalk.green.bold( 'Docker Information:' )}
223
+ NodeImage: ${chalk.green.bold( dockerInfo.imageBase || `node:${dockerInfo.nodeimage}` )}
224
+ Docker Env: ${chalk.green.bold( dockerInfo.buildEnv || 'alpine' )}
225
+ AddedPkgs: ${chalk.green.bold( dockerInfo.apkadds )}
226
+ Run User: ${chalk.green.bold( dockerInfo.runuser )}
227
+ Previous: ${chalk.yellow.bold( dockerInfo.previousBuild )}
228
+ DateStamp: ${chalk.green.bold( dockerInfo.date )}
229
+ NPM Logs: ${chalk.green.bold( dockerInfo.npmlogging )}
230
+ NPM Version: ${chalk.green.bold( dockerInfo.npmVersion )}
231
+ ` )
232
+
233
+ if ( imageVersion !== packageVersion ) {
234
+ log( `
235
+ ${chalk.yellow.bold( '***WARNING: specified version does not match project version' )}
236
+ pyproject.toml => ${chalk.green.bold( packageVersion )}
237
+ specified => ${chalk.red.bold( imageVersion )}
238
+ ` )
239
+
240
+ if ( willGitTag ) {
241
+ log( chalk.red.bold( '... and you are attempting to release so NOPE!\n' ) )
242
+ process.exit( 1 )
243
+ }
244
+ }
245
+
246
+ const repoInfo = await getGitBranchAndUpstream()
247
+
248
+ if ( willGitTag && !repoInfo.upstream ) {
249
+ log( `
250
+ ${chalk.red.bold( '***ERROR: the current branch must have an upstream' )}
251
+
252
+ You are attempting to create a tagged release image for pushing to the
253
+ container registry, but the current branch does not have an upstream to
254
+ push to. This is not allowed since the applied tag will be stranded here
255
+ in your local repository, which is what we are trying to avoid.
256
+
257
+ Available options for proceeding:` )
258
+ log( chalk.green.bold( `
259
+ 1) set an upstream for this branch via:
260
+ git push --set-upstream origin ${repoInfo.branch}` ) )
261
+ log( chalk.yellow.bold( `
262
+ 2) rebase, squash and merge onto a branch with an upstream` ) )
263
+
264
+ process.exit( 1 )
265
+ }
266
+
267
+ if ( willGitTag ) {
268
+ if ( chart.appVersion !== imageVersion ) {
269
+ log( `
270
+ ${chalk.yellow.bold( '***WARNING: the helm/Chart.yaml appVersion does not align with the build version' )}
271
+ chart appVersion => ${chalk.yellow.bold( chart.appVersion )}
272
+ build version => ${chalk.green.bold( imageVersion )}
273
+ ` )
274
+ }
275
+ }
276
+
277
+ await proceed()
278
+
279
+ log( chalk.green.bold( 'Building the Docker Image...' ) )
280
+ await Docker.buildContainerImage( { ...repoDescr, options, imageVersion } )
281
+ log( chalk.blue.bold( 'Done Building the Docker Image...' ) )
282
+
283
+ if ( willGitTag ) {
284
+ const tagDescription = `docker_${imageVersion}`
285
+ const fullImageTag = repoDescr.isMonoRepo ? `${repoDescr.containerName}/${imageVersion}` : imageVersion
286
+ log( chalk.green.bold( `Tagging and Pushing ${fullImageTag}\n` ) )
287
+ await shellCmd( `git tag -f ${fullImageTag} -m ${tagDescription}` )
288
+ await shellCmd( 'git push --follow-tags' )
289
+ } else {
290
+ log( chalk.yellow.bold( '\n*** Skipped git tagging - beta release' ) )
291
+ }
@@ -19,7 +19,7 @@ cat<<DEPRECATED_TOOL
19
19
  `color y "***DEPRECATED docker-to-registry.sh - upgrade to docker-to-registry.mjs***"`
20
20
 
21
21
  DEPRECATED_TOOL
22
- exit 1
22
+ sleep 3
23
23
 
24
24
  PKGTOP="$npm_config_local_prefix"
25
25
  cd $PKGTOP/docker
@@ -1,3 +1,5 @@
1
+ # Artifact Chart => https://artifacthub.io/packages/helm/cloudnative-pg/cloudnative-pg
2
+ # Examples Charts => https://cloudnative-pg.io/documentation/current/samples/
1
3
  apiVersion: postgresql.cnpg.io/v1
2
4
  kind: Cluster
3
5
  metadata:
@@ -8,7 +10,7 @@ spec:
8
10
  logLevel: info # warning debug
9
11
 
10
12
  description: "Leverege PG Bench Timescale DB"
11
- imageName: us-docker.pkg.dev/leverege-registry/system/images/leverege-pgsql:17.2-cnpg-lvrg-rel.2
13
+ imageName: us-docker.pkg.dev/leverege-registry/system/images/leverege-pgsql:16.1-cnpg-tsdb2-beta.6
12
14
  bootstrap:
13
15
  initdb:
14
16
  postInitTemplateSQL:
@@ -58,7 +60,6 @@ spec:
58
60
  # - supervised: requires manual supervision to perform
59
61
  # the switchover of the primary
60
62
  primaryUpdateStrategy: unsupervised
61
- primaryUpdateMethod: switchover
62
63
 
63
64
  serviceAccountTemplate:
64
65
  metadata:
@@ -1,3 +1,5 @@
1
+ # Artifact Chart => https://artifacthub.io/packages/helm/cloudnative-pg/cloudnative-pg
2
+ # Examples Charts => https://cloudnative-pg.io/documentation/current/samples/
1
3
  apiVersion: postgresql.cnpg.io/v1
2
4
  kind: Cluster
3
5
  metadata:
@@ -11,7 +13,7 @@ spec:
11
13
  enablePodMonitor: false # set true once monitoring is setup
12
14
 
13
15
  description: "Leverege Stack PostgreSQL DB"
14
- imageName: us-docker.pkg.dev/leverege-registry/system/images/leverege-pgsql:17.2-cnpg-lvrg-rel.2
16
+ imageName: us-docker.pkg.dev/leverege-registry/system/images/leverege-pgsql:16.4-cnpg-tsdb2-rel.1
15
17
  bootstrap:
16
18
  initdb:
17
19
  # database: models # do not set - let it default to cnpg app db
@@ -64,7 +66,6 @@ spec:
64
66
  # - supervised: requires manual supervision to perform
65
67
  # the switchover of the primary
66
68
  primaryUpdateStrategy: unsupervised
67
- primaryUpdateMethod: switchover
68
69
 
69
70
  serviceAccountTemplate:
70
71
  metadata:
@@ -1,3 +1,5 @@
1
+ # Artifact Chart => https://artifacthub.io/packages/helm/cloudnative-pg/cloudnative-pg
2
+ # Examples Charts => https://cloudnative-pg.io/documentation/current/samples/
1
3
  apiVersion: postgresql.cnpg.io/v1
2
4
  kind: Cluster
3
5
  metadata:
@@ -11,7 +13,7 @@ spec:
11
13
  enablePodMonitor: false # set true once monitoring is setup
12
14
 
13
15
  description: "Leverege CNPG DB (recovered)"
14
- imageName: us-docker.pkg.dev/leverege-registry/system/images/leverege-pgsql:17.2-cnpg-lvrg-rel.2
16
+ imageName: us-docker.pkg.dev/leverege-registry/system/images/leverege-pgsql:16.4-cnpg-tsdb2-rel.1
15
17
  bootstrap:
16
18
  recovery:
17
19
  volumeSnapshots:
@@ -59,7 +61,6 @@ spec:
59
61
  # - supervised: requires manual supervision to perform
60
62
  # the switchover of the primary
61
63
  primaryUpdateStrategy: unsupervised
62
- primaryUpdateMethod: switchover
63
64
 
64
65
  serviceAccountTemplate:
65
66
  metadata:
@@ -1,3 +1,5 @@
1
+ # Artifact Chart => https://artifacthub.io/packages/helm/cloudnative-pg/cloudnative-pg
2
+ # Examples Charts => https://cloudnative-pg.io/documentation/current/samples/
1
3
  apiVersion: postgresql.cnpg.io/v1
2
4
  kind: Cluster
3
5
  metadata:
@@ -11,7 +13,7 @@ spec:
11
13
  enablePodMonitor: false # set true once monitoring is setup
12
14
 
13
15
  description: "Leverege Plain Timescale DB"
14
- imageName: us-docker.pkg.dev/leverege-registry/system/images/leverege-pgsql:17.2-cnpg-lvrg-rel.2
16
+ imageName: us-docker.pkg.dev/leverege-registry/system/images/leverege-pgsql:16.4-cnpg-tsdb2-rel.1
15
17
  bootstrap:
16
18
  initdb:
17
19
  # database: imagine # let it default to cnpg app db
@@ -72,7 +74,6 @@ spec:
72
74
  # - supervised: requires manual supervision to perform
73
75
  # the switchover of the primary
74
76
  primaryUpdateStrategy: unsupervised
75
- primaryUpdateMethod: switchover
76
77
 
77
78
  serviceAccountTemplate:
78
79
  metadata:
@@ -1,3 +1,5 @@
1
+ # Artifact Chart => https://artifacthub.io/packages/helm/cloudnative-pg/cloudnative-pg
2
+ # Examples Charts => https://cloudnative-pg.io/documentation/current/samples/
1
3
  apiVersion: postgresql.cnpg.io/v1
2
4
  kind: Cluster
3
5
  metadata:
@@ -11,7 +13,7 @@ spec:
11
13
  enablePodMonitor: false # set true once monitoring is setup
12
14
 
13
15
  description: "Leverege Dense Timescale DB"
14
- imageName: us-docker.pkg.dev/leverege-registry/system/images/leverege-pgsql:17.2-cnpg-lvrg-rel.2
16
+ imageName: us-docker.pkg.dev/leverege-registry/system/images/leverege-pgsql:16.4-cnpg-tsdb2-rel.1
15
17
  bootstrap:
16
18
  initdb:
17
19
  postInitTemplateSQL:
@@ -67,7 +69,6 @@ spec:
67
69
  # - supervised: requires manual supervision to perform
68
70
  # the switchover of the primary
69
71
  primaryUpdateStrategy: unsupervised
70
- primaryUpdateMethod: switchover
71
72
 
72
73
  serviceAccountTemplate:
73
74
  metadata:
@@ -4,23 +4,20 @@ showInstalling "The Prometheus Operator and Components"
4
4
  addHelmRepo prometheus-community https://prometheus-community.github.io/helm-charts
5
5
 
6
6
  showInstalling "The Prometheus Operator (kube-prometheus-stack)"
7
- [ -z "$PROMETHEUS_STACK_CHART_VERSION" ] && PROMETHEUS_STACK_CHART_VERSION="68"
7
+ [ -z "$PROMETHEUS_STACK_CHART_VERSION" ] && PROMETHEUS_STACK_CHART_VERSION="67"
8
8
 
9
9
  NS="--namespace prometheus"
10
10
 
11
- # https://artifacthub.io/packages/helm/prometheus-community/kube-prometheus-stack
12
11
  helm upgrade $NS --install prometheus-stack prometheus-community/kube-prometheus-stack \
13
12
  --values prom-operator/prometheus-stack.yaml \
14
13
  --version $PROMETHEUS_STACK_CHART_VERSION $HELM_WHAT
15
14
 
16
- # https://artifacthub.io/packages/helm/prometheus-community/prometheus-elasticsearch-exporter
17
15
  showInstalling "The Elasticsearch Exporter (prom-operator)"
18
16
  [ -z "$ELASTICSEARCH_EXPORTER_CHART_VERSION" ] && ELASTICSEARCH_EXPORTER_CHART_VERSION="6"
19
17
  helm upgrade $NS --install elasticsearch8-exporter prometheus-community/prometheus-elasticsearch-exporter \
20
18
  --values prom-operator/elasticsearch-exporter.yaml \
21
19
  --version $ELASTICSEARCH_EXPORTER_CHART_VERSION $HELM_WHAT
22
20
 
23
- # https://artifacthub.io/packages/helm/prometheus-community/prometheus-stackdriver-exporter
24
21
  showInstalling "The Stackdriver Exporter (prom-operator)"
25
22
  [ -z "$STACKDRIVER_EXPORTER_CHART_VERSION" ] && STACKDRIVER_EXPORTER_CHART_VERSION="4"
26
23
  helm upgrade $NS --install stackdriver-exporter prometheus-community/prometheus-stackdriver-exporter \
@@ -128,15 +128,6 @@ export default class Config {
128
128
 
129
129
  async bootstrapHookAndRelease() {
130
130
  const repoDescr = await getRepositoryDescr()
131
- if ( !repoDescr.isGitRepo ) {
132
- const notGitRepo = `
133
- The hook-and-release script only works with git repositories. Try running:
134
-
135
- git init && hook-and-release --init
136
-
137
- to initialize git and hook-and-release.`
138
- errorExit( notGitRepo )
139
- }
140
131
  this.gitRoot = repoDescr.gitRoot
141
132
  this.gitBranch = repoDescr.gitBranch
142
133
  this.gitHooksPath = repoDescr.gitHooksPath
@@ -0,0 +1 @@
1
+ export PYTHONPYCACHEPREFIX=/tmp/pycache
@@ -25,11 +25,11 @@ COPY ./.npmrc ${NPM_CONFIG_USERCONFIG}
25
25
  RUN if [ "${BUILD_ENV}" = "debian" ]; then \
26
26
  apt-get update && \
27
27
  apt-get install -y wget openssh-client build-essential && \
28
- npm install -g {{npmVersion}}; \
28
+ npm install -g npm@10; \
29
29
  else \
30
30
  apk --no-cache add openssh-client && \
31
31
  apk --update add --no-cache --virtual build-dep g++ gcc libgcc libstdc++ linux-headers make {{apkadds}} && \
32
- npm install -g {{npmVersion}}; \
32
+ npm install -g npm@10; \
33
33
  fi
34
34
 
35
35
  # Use SKIP_PREPARE to disable hook-and-release from running
@@ -58,13 +58,13 @@ COPY ./.npmrc ${NPM_CONFIG_USERCONFIG}
58
58
  RUN if [ "$BUILD_ENV" = "debian" ]; then \
59
59
  apt-get update && \
60
60
  apt-get install -y tini bash curl vim {{apkadds}} && \
61
- npm install -g {{npmVersion}} && \
61
+ npm install -g npm@10 && \
62
62
  rm /bin/sh && ln -s /bin/bash /bin/sh && \
63
63
  mkdir -p /usr/src/app /tmp/levlog && chown node:node /usr/src/app; \
64
64
  else \
65
65
  apk update && \
66
66
  apk add --no-cache bash curl tini vim {{apkadds}} && \
67
- npm install -g {{npmVersion}} && \
67
+ npm install -g npm@10 && \
68
68
  rm /bin/sh && ln -s /bin/bash /bin/sh && \
69
69
  mkdir -p /usr/src/app /tmp/levlog && chown node:node /usr/src/app; \
70
70
  fi
@@ -83,4 +83,4 @@ COPY --chown=node:node --from=intermediate /usr/src/app /usr/src/app
83
83
 
84
84
  USER {{runuser}}
85
85
  COPY ./bashrc /home/node/.bashrc
86
- CMD [ "/bin/bash", "-c", "source /home/node/.bashrc && node index.js" ]
86
+ CMD [ "/bin/bash", "-c", "source /home/node/.bashrc && node index.js" ]
@@ -0,0 +1,75 @@
1
+ # Version {{regvers}} @ {{date}}
2
+
3
+ # The FROM directive sets the Base Image for subsequent instructions
4
+ FROM {{image}} as intermediate
5
+
6
+ ARG BUILD_ENV="{{buildEnv}}"
7
+
8
+ RUN apt-get update && apt-get install -y \
9
+ wget
10
+ # gcc \
11
+ # git \
12
+ # libgl1 \
13
+ # libglib2.0-0 \
14
+ # && rm -rf /var/lib/apt/lists/*
15
+
16
+ # Copy uv binary from the official distroless Docker image.
17
+ COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv
18
+
19
+ # Define the working directory.
20
+ WORKDIR /usr/src/app
21
+
22
+ #ENV NODE_ENV production
23
+ #ENV NPM_CONFIG_USERCONFIG /usr/src/app/.npmrc
24
+
25
+ RUN mkdir -p /usr/src/app
26
+ WORKDIR /usr/src/app
27
+
28
+ # Install app dependencies
29
+ COPY ./workspace/ /usr/src/app/
30
+ ENV GRPC_VERBOSITY ERROR
31
+
32
+
33
+ # Setup pip.conf for Google Artifact Registry.
34
+ RUN mkdir -p ~/.config/pip
35
+ RUN echo "[global]" >> ~/.config/pip/pip.conf && \
36
+ echo "break-system-packages = true" >> ~/.config/pip/pip.conf
37
+
38
+
39
+ # Set up the virtual environment.
40
+ RUN uv venv
41
+ ENV VIRTUAL_ENV=/usr/src/app/.venv
42
+ ENV PATH="$VIRTUAL_ENV/bin:$PATH"
43
+
44
+ # Setup keyring for Google Artifact Registry.
45
+ RUN uv pip install keyring
46
+ RUN uv pip install keyrings.google-artifactregistry-auth
47
+
48
+ RUN echo "extra-index-url = https://oauth2accesstoken@us-python.pkg.dev/leverege-registry/leverege-python-packages/simple" >> ~/.config/pip/pip.conf
49
+
50
+ ENV UV_EXTRA_INDEX_URL "https://oauth2accesstoken@us-python.pkg.dev/leverege-registry/leverege-python-packages/simple"
51
+
52
+
53
+ {{preInstallPluginfile}}
54
+
55
+ RUN cat
56
+
57
+ RUN ls -al
58
+ # Install uv
59
+ RUN uv sync --keyring-provider subprocess --extra-index-url https://oauth2accesstoken@us-python.pkg.dev/leverege-registry/leverege-python-packages/simple
60
+
61
+
62
+ # Pull in the Dockerfile.plugin file here
63
+ {{pluginfile}}
64
+
65
+ # Eliminate the sensitive info from the final stage image
66
+ #RUN rm -f ${NPM_CONFIG_USERCONFIG}
67
+
68
+ # ENTRYPOINT [ "tini", "--" ]
69
+ #WORKDIR /usr/src/app
70
+
71
+ #COPY --chown=node:node --from=intermediate /usr/src/app /usr/src/app
72
+
73
+ USER {{runuser}}
74
+ COPY ./bashrc /home/{{runuser}}/.bashrc
75
+ CMD [ "/bin/bash", "-c", "source /home/{{runuser}}/.bashrc && python scripts/server.py" ]
@@ -1,20 +0,0 @@
1
- registry:
2
- - root: us-docker.pkg.dev
3
- - repositories:
4
- - name: stack
5
- charts:
6
- - api-server
7
- - authz-server
8
- - emailer
9
- - message-processor
10
- - name: leverege
11
- charts:
12
- - pubsub-pulse
13
- - pusher
14
- - overdose
15
- - name: cox-health
16
- charts:
17
- - actions-server
18
- - analytics-server
19
- - centrak-healthz
20
- - centrak-ingestor
@@ -1,176 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // A simple utility for easily building CNPG based psql images. The resultant
4
- // image will contain PostgreSQL, the JS query and Timescale extensions, and
5
- // the extensions that are required by CNPG like barman, pgaudit, pgvector and
6
- // pg-failover-slots.
7
- //
8
- // Latest Versions:
9
- // postgres => https://www.postgresql.org/
10
- // timescale => https://docs.timescale.com/about/latest/
11
- // CNPG images => https://github.com/cloudnative-pg/postgres-containers/pkgs/container/postgresql
12
-
13
- import fs from 'node:fs'
14
- import path from 'node:path'
15
-
16
- import chalk from 'chalk'
17
- import cliArgs from 'command-line-args'
18
- import cliHelp from 'command-line-usage'
19
- import Handlebars from 'handlebars'
20
-
21
- import {
22
- debug,
23
- log,
24
- err,
25
- errorExit,
26
- shellCmd,
27
- } from './Utils.mjs'
28
-
29
- // Define CLI options
30
- const optionList = [
31
- { name : 'sub-tag', type : String, description : '{green sub-tag to add to the image tag (required)}', defaultOption : true },
32
- { name : 'pg-version', type : String, description : '{green pgsql version (default: 16.6)}' },
33
- { name : 'version', type : Boolean, description : '{green show script version}' },
34
- { name : 'help', type : Boolean, description : '{green display this help screen}' },
35
- ]
36
-
37
- const sections = [
38
- {
39
- header : 'Leverege CNPG Docker Image Builder',
40
- content : `{green This tool will build a PostgreSQL based image that is suitable for
41
- deployment by the CNPG operator. It builds the docker image by using an
42
- official CNPG docker image as a base and added the jsquery and timescale
43
- extensions for use within a Leverege k8s cluster. The resultant image may be
44
- used in the standard PostgreSQL configuration which is used by the stack
45
- components, as well as timescale based services like transponder tsdb and
46
- dense history.}`
47
- },
48
- {
49
- header : 'Options',
50
- optionList
51
- },
52
- {
53
- header : 'Leverege Registry Image Tag',
54
- content : `{green The resultant image will be tagged with a label comprised of the PG version,
55
- the specified --sub-tag and a fixed string:
56
-
57
- {yellow <PG ver>-cnpg-lvrg-<sub tag>}
58
-
59
- For example, version {yellow 16.6} with a sub tag of {yellow rel.1} will be tagged:
60
-
61
- {yellow 16.6-cnpg-lvrg-rel.1}}`
62
- },
63
- ]
64
- const args = cliArgs( optionList, { camelCase : true, partial : true } )
65
- const help = cliHelp( sections )
66
-
67
- debug( { args, help }, '<==Command Line Info?' )
68
-
69
- // Show help if needed
70
- if ( args.help ) {
71
- log( help )
72
- process.exit( 0 )
73
- }
74
-
75
- // Define defaults
76
- const PG_VERSION = args.pgVersion || '16.6'
77
- const { subTag } = args
78
- if ( !subTag ) {
79
- errorExit( 'Error: An image version must be specified.' )
80
- }
81
-
82
- const LEVEREGE_REGISTRY = 'us-docker.pkg.dev/leverege-registry/system/images/leverege-pgsql'
83
- const LEVEREGE_IMAGE_TAG = `${PG_VERSION}-cnpg-lvrg-${subTag}`
84
- const LEVEREGE_IMAGE_NAME_WITH_TAG = `${LEVEREGE_REGISTRY}:${LEVEREGE_IMAGE_TAG}`
85
-
86
- const DOCKERFILE_TEMPLATE = `
87
- FROM ghcr.io/cloudnative-pg/postgresql:{{PG_VERSION}}-bookworm
88
-
89
- USER root
90
-
91
- RUN set -xe; \\
92
- apt-get update; \\
93
- apt-get install -y --no-install-recommends \\
94
- "postgresql-\${PG_MAJOR}-jsquery"; \\
95
- rm -fr /tmp/*; \\
96
- rm -rf /var/lib/apt/lists/*;
97
-
98
- RUN apt-get update \\
99
- && apt-get install -y lsb-release wget \\
100
- && echo "deb https://packagecloud.io/timescale/timescaledb/debian/ $(lsb_release -c -s) main" | tee /etc/apt/sources.list.d/timescaledb.list \\
101
- && wget --quiet -O - https://packagecloud.io/timescale/timescaledb/gpgkey | apt-key add - \\
102
- && apt-get update \\
103
- && apt-get install -y "timescaledb-2-postgresql-\${PG_MAJOR}" \\
104
- && apt-get remove -y lsb-release wget \\
105
- && rm -fr /tmp/* \\
106
- && rm -rf /var/lib/apt/lists/*;
107
-
108
- RUN usermod -u 26 postgres
109
- USER 26
110
- `
111
-
112
- // Check for existing image
113
- const checkExistingImage = async ( imageName ) => {
114
- const dockerResults = await shellCmd( `docker image list ${imageName} --quiet` )
115
- debug( { imageName, dockerResults }, '<==docker image list' )
116
- return dockerResults
117
- }
118
-
119
- // Build and push Docker image
120
- const buildAndPushImage = async () => {
121
- const template = Handlebars.compile( DOCKERFILE_TEMPLATE )
122
- const renderedDockerfile = template( { PG_VERSION } )
123
- debug( { renderedDockerfile }, '<==Dockerfile' )
124
-
125
- // Write the Dockerfile to a temporary location
126
- const dockerfilePath = path.resolve( 'Dockerfile.temp' )
127
- fs.writeFileSync( dockerfilePath, renderedDockerfile )
128
-
129
- // Build the image
130
- log( chalk.yellow( '\nBuilding Docker image...' ) )
131
- await shellCmd( `docker build --file ${dockerfilePath} --tag ${LEVEREGE_IMAGE_NAME_WITH_TAG} .`, { stdio : 'inherit' } )
132
-
133
- // Push the image
134
- log( chalk.green( '\nPushing Docker image...' ) )
135
- await shellCmd( `docker push ${LEVEREGE_IMAGE_NAME_WITH_TAG}`, { stdio : 'inherit' } )
136
-
137
- // Clean up the temporary Dockerfile
138
- fs.unlinkSync( dockerfilePath )
139
- }
140
-
141
- // Main execution flow
142
- try {
143
- if ( await checkExistingImage( LEVEREGE_IMAGE_NAME_WITH_TAG ) ) {
144
- err(
145
- `${chalk.red( '*** ERROR ***' )} The image already exists:\n` +
146
- ` Image : ${chalk.yellow( LEVEREGE_IMAGE_NAME_WITH_TAG )}\n` +
147
- ` Registry: ${chalk.green( LEVEREGE_REGISTRY )}\n` +
148
- ` Tag : ${chalk.green( LEVEREGE_IMAGE_TAG )}\n`
149
- )
150
- process.exit( 1 )
151
- }
152
-
153
- log( `${chalk.cyan( '\nAbout to build a new Docker image:\n' )}
154
- PostgreSQL => ${chalk.green( PG_VERSION )}
155
- Image Name => ${chalk.green( LEVEREGE_IMAGE_NAME_WITH_TAG )}\n` )
156
-
157
- log( `Enter "${chalk.green( 'yes' )}" to proceed or anything else to exit.` )
158
- const confirmation = await new Promise( ( resolve ) => {
159
- process.stdin.once( 'data', data => resolve( data.toString().trim() ) )
160
- } )
161
-
162
- if ( confirmation !== 'yes' ) {
163
- log( chalk.red( 'Aborted by user.' ) )
164
- process.exit( 1 )
165
- }
166
-
167
- await buildAndPushImage()
168
- log(
169
- chalk.green( '\nImage built and successfully pushed - tagged => ' ) +
170
- chalk.yellow( `${LEVEREGE_IMAGE_TAG}` )
171
- )
172
- process.exit( 0 )
173
- } catch ( error ) {
174
- err( chalk.red( 'An error occurred:' ), error.message )
175
- process.exit( 1 )
176
- }
@@ -1,97 +0,0 @@
1
- #!/usr/bin/env node
2
- /* eslint-disable */
3
- /*
4
- * chart-to-registry will...
5
- */
6
- import fs from 'node:fs'
7
-
8
- import chalk from 'chalk'
9
- import commandLineArgs from 'command-line-args'
10
- import commandLineUsage from 'command-line-usage'
11
- import { lt as semverLt } from 'semver'
12
- import YAML from 'js-yaml'
13
-
14
- import {
15
- condir,
16
- debug,
17
- errorExit,
18
- log,
19
- warning,
20
- getGitRootDirectory,
21
- parsePackageJson,
22
- parseHelmChart,
23
- shellCmd } from './Utils.mjs'
24
-
25
- const commandLineOptions = [ // Use commandLineOptions to tie into the Usage statements
26
-
27
- {
28
- name : 'location',
29
- type : String,
30
- description : '{green the location of the artifact registry the chart will be pushed to (default us-docker.pkg.dev)}',
31
- },
32
- {
33
- name : 'project',
34
- type : String,
35
- description : '{green the name of the google project containing the npmrc and slack config secrets (default leverege-registry)}',
36
- },
37
- {
38
- name : 'repository',
39
- type : String,
40
- description : '{green the target repository to receive the pushed chart}',
41
- },
42
- {
43
- name : 'dry-run',
44
- type : Boolean,
45
- description : '{yellow perform everything except the actual chart push}',
46
- },
47
- {
48
- name : 'help',
49
- type : Boolean,
50
- description : '{green display this help screen}',
51
- },
52
-
53
- ]
54
-
55
- const sections = [
56
- {
57
- header : 'Leverege Helm Chart Compass (for helmup)',
58
- content : `{green This tool helps helmup navigate the helm charts stored in the
59
- artifact-registries.}`
60
- },
61
- { header : 'Options',
62
- optionList : commandLineOptions,
63
- },
64
- ]
65
-
66
- const args = commandLineArgs( commandLineOptions, { camelCase : true, partial : true } )
67
- const usage = commandLineUsage( sections )
68
-
69
- if ( args.help ) {
70
- log( usage )
71
- process.exit( 0 )
72
- }
73
-
74
- /* eslint-disable no-underscore-dangle */
75
- if ( args._unknown ) {
76
- log( usage )
77
- log( `\nUnrecognized argument [${chalk.bold.red( args._unknown )}]\n` )
78
- process.exit( 1 )
79
- }
80
- /* eslint-enable no-underscore-dangle */
81
-
82
- const minNodejsVersion = '18.0.0'
83
- if ( semverLt( process.version, minNodejsVersion ) ) {
84
- errorExit( `\n***ERROR: must be running at least node ${minNodejsVersion}\n` )
85
- }
86
-
87
- // First of all, fail if we are not in a git repository
88
- let gitRoot
89
- try {
90
- gitRoot = await getGitRootDirectory()
91
- } catch ( error ) {
92
- errorExit( chalk.red.bold( error ), { errorCode : 5 } )
93
- }
94
-
95
- const chartCompass = YAML.load( fs.readFileSync( './registry-compass.yaml', 'utf8' ) )
96
-
97
- condir( { chartCompass }, '<==Navigation' )