contensis-cli 1.0.0-beta.95 → 1.0.0-beta.97

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.
@@ -1,13 +1,14 @@
1
1
  import inquirer from 'inquirer';
2
2
  import { JSONPath, JSONPathOptions } from 'jsonpath-plus';
3
+ import { Document } from 'yaml';
3
4
  import {
4
5
  GitHubActionPushBlockJob,
5
6
  GitHubActionPushBlockJobStep,
7
+ GitLabPushBlockJobStage,
6
8
  } from '~/models/DevService';
7
9
  import { readFile } from '~/providers/file-provider';
8
10
  import ContensisDev from '~/services/ContensisDevService';
9
11
  import { diffFileContent } from '~/util/diff';
10
- import { GitHelper } from '~/util/git';
11
12
  import { logError } from '~/util/logger';
12
13
  import { normaliseLineEndings } from '~/util/os';
13
14
  import { parseYamlDocument, validateWorkflowYaml } from '~/util/yaml';
@@ -19,144 +20,328 @@ type MappedWorkflowOutput = {
19
20
  };
20
21
 
21
22
  export const mapCIWorkflowContent = async (
22
- cli: ContensisDev,
23
- git: GitHelper
23
+ cli: ContensisDev
24
24
  ): Promise<MappedWorkflowOutput | undefined> => {
25
25
  // get existing workflow file
26
- const workflowFile = readFile(git.ciFilePath);
26
+ const workflowFile = readFile(cli.git.ciFilePath);
27
27
  if (!workflowFile) return undefined;
28
28
 
29
- const blockId = git.name;
30
- if (git.type === 'github') {
31
- const addGitHubActionJobStep: GitHubActionPushBlockJobStep = {
32
- name: 'Push block to Contensis',
33
- id: 'push-block',
34
- uses: 'contensis/block-push@v1',
35
- with: {
36
- 'block-id': blockId,
37
- // 'image-uri': '${{ steps.build.outputs.image-uri }}',
38
- alias: cli.currentEnv,
39
- 'project-id': cli.currentProject,
40
- 'client-id': '${{ secrets.CONTENSIS_CLIENT_ID }}',
41
- 'shared-secret': '${{ secrets.CONTENSIS_SHARED_SECRET }}',
42
- },
43
- };
29
+ const blockId = cli.git.name;
44
30
 
45
- // parse yaml to js
46
- const workflowDoc = parseYamlDocument(workflowFile);
47
- const workflowJS = workflowDoc.toJS();
48
- const setWorkflowElement = (path: string | any[], value: any) => {
49
- const findPath =
50
- typeof path === 'string' && path.includes('.')
51
- ? path
52
- .split('.')
53
- .map(p => (Number(p) || Number(p) !== 0 ? p : Number(p)))
54
- : path;
55
-
56
- if (workflowDoc.hasIn(findPath)) {
57
- workflowDoc.setIn(findPath, value);
58
- } else {
59
- workflowDoc.addIn(findPath, value);
60
- // }
61
- }
31
+ // parse yaml to js
32
+ const workflowDoc = parseYamlDocument(workflowFile);
33
+ const workflowJS = workflowDoc.toJS();
34
+
35
+ if (cli.git.type === 'github') {
36
+ const newWorkflow = await mapGitHubActionCIWorkflowContent(
37
+ cli,
38
+ blockId,
39
+ workflowDoc,
40
+ workflowJS
41
+ );
42
+ return {
43
+ existingWorkflow: workflowFile,
44
+ newWorkflow,
45
+ diff: diffFileContent(workflowFile, newWorkflow),
62
46
  };
63
- const findExistingJobSteps = (
64
- path: string,
65
- resultType: JSONPathOptions['resultType']
66
- ) => {
67
- const existingJobStep = JSONPath({
68
- path,
69
- json: workflowJS,
70
- resultType: resultType,
71
- });
72
-
73
- return existingJobStep;
47
+ } else if (cli.git.type === 'gitlab') {
48
+ const newWorkflow = await mapGitLabCIWorkflowContent(
49
+ cli,
50
+ blockId,
51
+ workflowDoc,
52
+ workflowJS
53
+ );
54
+ return {
55
+ existingWorkflow: workflowFile,
56
+ newWorkflow,
57
+ diff: diffFileContent(workflowFile, newWorkflow),
74
58
  };
59
+ }
60
+ };
75
61
 
76
- // look for line in job
77
- // jobs.x.steps[uses: contensis/block-push]
78
- const existingJobStep = findExistingJobSteps(
79
- git.type === 'github'
80
- ? '$.jobs..steps.*[?(@property === "uses" && @.match(/^contensis\\/block-push/i))]^'
81
- : // TODO: add jsonpath for gitlab file
82
- '',
83
- 'all'
62
+ const findExistingJobSteps = (
63
+ path: string,
64
+ json: any,
65
+ resultType: JSONPathOptions['resultType']
66
+ ) => {
67
+ const existingJobStep = JSONPath({
68
+ path,
69
+ json,
70
+ resultType: resultType,
71
+ });
72
+
73
+ return existingJobStep;
74
+ };
75
+
76
+ const setWorkflowElement = (
77
+ workflowDoc: Document,
78
+ path: string | any[],
79
+ value: any
80
+ ) => {
81
+ const findPath =
82
+ typeof path === 'string' && path.includes('.')
83
+ ? path.split('.').map(p => (Number(p) || Number(p) !== 0 ? p : Number(p)))
84
+ : path;
85
+
86
+ if (workflowDoc.hasIn(findPath)) {
87
+ workflowDoc.setIn(findPath, value);
88
+ } else {
89
+ workflowDoc.addIn(findPath, value);
90
+ }
91
+ };
92
+
93
+ const mapGitLabCIWorkflowContent = async (
94
+ cli: ContensisDev,
95
+ blockId: string,
96
+ workflowDoc: Document,
97
+ workflowJS: any
98
+ ) => {
99
+ const addGitLabJobStage: GitLabPushBlockJobStage = {
100
+ stage: 'push-block',
101
+ variables: {
102
+ block_id: blockId,
103
+ alias: cli.currentEnv,
104
+ project_id: cli.currentProject,
105
+ client_id:
106
+ cli.clientDetailsLocation === 'env'
107
+ ? cli.clientId
108
+ : '$CONTENSIS_CLIENT_ID',
109
+ shared_secret:
110
+ cli.clientDetailsLocation === 'env'
111
+ ? cli.clientSecret
112
+ : '$CONTENSIS_SHARED_SECRET',
113
+ },
114
+ };
115
+
116
+ const addAppImageUri = async () => {
117
+ // Look in document level "variables"
118
+ const appImageUri = await determineAppImageUri(
119
+ cli,
120
+ Object.entries(workflowJS.variables || {}),
121
+ '$CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME/app:build-$CI_PIPELINE_IID'
84
122
  );
85
123
 
86
- const addAppImageUri = async () => {
87
- // Look in document level "env" vars
88
- const appImageUri = await determineAppImageUri(
89
- cli,
90
- Object.entries(workflowJS.env || {})
124
+ if (appImageUri.addVar)
125
+ setWorkflowElement(
126
+ workflowDoc,
127
+ `variables.${appImageUri.var}`,
128
+ appImageUri.uri
91
129
  );
92
130
 
93
- if (appImageUri.addVar)
94
- setWorkflowElement(`env.${appImageUri.var}`, appImageUri.uri);
95
- // workflowDoc.addIn(['env'], { [appImageUri.var]: appImageUri.uri });
131
+ if (appImageUri.var)
132
+ addGitLabJobStage.variables['image_uri'] = `\$${appImageUri.var}`;
133
+ };
96
134
 
97
- if (appImageUri.var)
98
- addGitHubActionJobStep.with[
99
- 'image-uri'
100
- ] = `\${{ env.${appImageUri.var} }}`;
101
- };
135
+ // look for line in job
136
+ // jobname[stage: push-block]
137
+ const existingJobStep = findExistingJobSteps(
138
+ '$..[?(@property === "stage" && @.match(/^push-block/i))]^',
139
+ workflowJS,
140
+ 'all'
141
+ );
102
142
 
103
- // update job step
104
- if (existingJobStep.length) {
105
- //cli.log.json(existingJobStep);
143
+ // update job step
144
+ if (existingJobStep.length) {
145
+ // cli.log.json(existingJobStep);
146
+
147
+ // The [0] index means we're only looking at updating the first instance in the file
148
+ const step = existingJobStep[0];
149
+
150
+ // Path looks like this "$['job_name']"
151
+ // We want it to look like this "job_name"
152
+ const stepPath = step.path
153
+ .replace('$[', '')
154
+ .replaceAll('][', '.')
155
+ .replace(']', '')
156
+ .replaceAll("'", '');
157
+
158
+ cli.log.info(
159
+ `Found existing Job step:
160
+ ${stepPath}
161
+ stage: ${step.value.stage}\n`
162
+ );
106
163
 
107
- // The [0] index means we're only looking at updating the first instance in the file
108
- const step = existingJobStep[0];
164
+ setWorkflowElement(
165
+ workflowDoc,
166
+ `${stepPath}.variables.alias`,
167
+ cli.currentEnv
168
+ );
169
+ setWorkflowElement(
170
+ workflowDoc,
171
+ `${stepPath}.variables.project_id`,
172
+ cli.currentProject
173
+ );
174
+ setWorkflowElement(workflowDoc, `${stepPath}.variables.block_id`, blockId);
175
+
176
+ // This is likely not needed when updating an existing push-block job step
177
+ // we are assuming this is a forked/copied workflow with an already working image-uri reference
178
+ // await addAppImageUri();
179
+
180
+ setWorkflowElement(
181
+ workflowDoc,
182
+ `${stepPath}.variables.client_id`,
183
+ cli.clientDetailsLocation === 'env'
184
+ ? cli.clientId
185
+ : '$CONTENSIS_CLIENT_ID'
186
+ );
187
+ setWorkflowElement(
188
+ workflowDoc,
189
+ `${stepPath}.variables.shared_secret`,
190
+ cli.clientDetailsLocation === 'env'
191
+ ? cli.clientSecret
192
+ : '$CONTENSIS_SHARED_SECRET'
193
+ );
194
+ } else {
195
+ // create job with push step
196
+
197
+ // Does a series of checks and prompts to determine the correct image-uri
198
+ // for the app container build
199
+ await addAppImageUri();
200
+
201
+ // Add the new "job" to the Yaml Document
202
+ workflowDoc.addIn(['stages'], 'push-block');
203
+ workflowDoc.addIn([], {
204
+ key: 'push-to-contensis',
205
+ value: addGitLabJobStage,
206
+ });
207
+ setWorkflowElement(
208
+ workflowDoc,
209
+ `include`,
210
+ 'https://gitlab.zengenti.com/ops/contensis-ci/-/raw/main/push-block.yml'
211
+ );
212
+ }
109
213
 
110
- // Path looks like this "$['jobs']['build']['steps'][3]"
111
- // We want it to look like this "jobs.build.steps.3"
112
- const stepPath = step.path
113
- .replace('$[', '')
114
- .replaceAll('][', '.')
115
- .replace(']', '')
116
- .replaceAll("'", '');
214
+ cli.log.debug(`New file content to write\n\n${workflowDoc}`);
117
215
 
118
- cli.log.info(
119
- `Found existing Job step: ${stepPath}
120
- - name: ${step.value.name}
121
- id: ${step.value.id}\n`
122
- );
216
+ const newWorkflow = normaliseLineEndings(
217
+ workflowDoc.toString({ lineWidth: 0 })
218
+ );
123
219
 
124
- setWorkflowElement(`${stepPath}.with.alias`, cli.currentEnv);
125
- setWorkflowElement(`${stepPath}.with.project-id`, cli.currentProject);
126
- setWorkflowElement(`${stepPath}.with.block-id`, blockId);
220
+ return newWorkflow;
221
+ };
127
222
 
128
- // This is likely not needed when updating an existing push-block job step
129
- // we are assuming this is a forked/copied workflow with an already working image-uri reference
130
- // await addAppImageUri();
223
+ const mapGitHubActionCIWorkflowContent = async (
224
+ cli: ContensisDev,
225
+ blockId: string,
226
+ workflowDoc: Document,
227
+ workflowJS: any
228
+ ) => {
229
+ const addGitHubActionJobStep: GitHubActionPushBlockJobStep = {
230
+ name: 'Push block to Contensis',
231
+ id: 'push-block',
232
+ uses: 'contensis/block-push@v1',
233
+ with: {
234
+ 'block-id': blockId,
235
+ // 'image-uri': '${{ steps.build.outputs.image-uri }}',
236
+ alias: cli.currentEnv,
237
+ 'project-id': cli.currentProject,
238
+ 'client-id':
239
+ cli.clientDetailsLocation === 'env'
240
+ ? '${{ env.CONTENSIS_CLIENT_ID }}'
241
+ : '${{ secrets.CONTENSIS_CLIENT_ID }}',
242
+ 'shared-secret':
243
+ cli.clientDetailsLocation === 'env'
244
+ ? '${{ env.CONTENSIS_SHARED_SECRET }}'
245
+ : '${{ secrets.CONTENSIS_SHARED_SECRET }}',
246
+ },
247
+ };
131
248
 
249
+ const addAppImageUri = async () => {
250
+ // Look in document level "env" vars
251
+ const appImageUri = await determineAppImageUri(
252
+ cli,
253
+ Object.entries(workflowJS.env || {}),
254
+ 'ghcr.io/${{ github.repository }}/${{ github.ref_name }}/app:build-${{ github.run_number }}'
255
+ );
256
+
257
+ if (appImageUri.addVar)
132
258
  setWorkflowElement(
133
- `${stepPath}.with.client-id`,
134
- '${{ secrets.CONTENSIS_CLIENT_ID }}'
135
- );
136
- setWorkflowElement(
137
- `${stepPath}.with.shared-secret`,
138
- '${{ secrets.CONTENSIS_SHARED_SECRET }}'
259
+ workflowDoc,
260
+ `env.${appImageUri.var}`,
261
+ appImageUri.uri
139
262
  );
140
- } else {
141
- // create job with push step
142
-
143
- // is there already a job with a property name containing "build"?
144
- const existingBuildJobStep = findExistingJobSteps(
145
- git.type === 'github'
146
- ? '$.jobs[?(@property.match(/build/i))]'
147
- : // TODO: add jsonpath for gitlab file
148
- '',
149
- 'all'
150
- ) as JSONPathOptions[]; // This isn't the correct type for this object
151
-
152
- let needs: string | undefined;
153
- // There are multiple jobs called *build*
154
- if (existingBuildJobStep.length > 1) {
155
- // prompt which build job we should depend on before pushing the block
156
- const choices = existingBuildJobStep.map(s => s.parentProperty);
157
- choices.push(new inquirer.Separator() as any);
158
- choices.push('none');
263
+ // workflowDoc.addIn(['env'], { [appImageUri.var]: appImageUri.uri });
264
+
265
+ if (appImageUri.var)
266
+ addGitHubActionJobStep.with[
267
+ 'image-uri'
268
+ ] = `\${{ env.${appImageUri.var} }}`;
269
+ };
270
+
271
+ // look for line in job
272
+ // jobs.x.steps[uses: contensis/block-push]
273
+ const existingJobStep = findExistingJobSteps(
274
+ '$.jobs..steps.*[?(@property === "uses" && @.match(/^contensis\\/block-push/i))]^',
275
+ workflowJS,
276
+ 'all'
277
+ );
278
+
279
+ // update job step
280
+ if (existingJobStep.length) {
281
+ //cli.log.json(existingJobStep);
282
+
283
+ // The [0] index means we're only looking at updating the first instance in the file
284
+ const step = existingJobStep[0];
285
+
286
+ // Path looks like this "$['jobs']['build']['steps'][3]"
287
+ // We want it to look like this "jobs.build.steps.3"
288
+ const stepPath = step.path
289
+ .replace('$[', '')
290
+ .replaceAll('][', '.')
291
+ .replace(']', '')
292
+ .replaceAll("'", '');
293
+
294
+ cli.log.info(
295
+ `Found existing Job step: ${stepPath}
296
+ - name: ${step.value.name}
297
+ id: ${step.value.id}\n`
298
+ );
159
299
 
300
+ setWorkflowElement(workflowDoc, `${stepPath}.with.alias`, cli.currentEnv);
301
+ setWorkflowElement(
302
+ workflowDoc,
303
+ `${stepPath}.with.project-id`,
304
+ cli.currentProject
305
+ );
306
+ setWorkflowElement(workflowDoc, `${stepPath}.with.block-id`, blockId);
307
+
308
+ // This is likely not needed when updating an existing push-block job step
309
+ // we are assuming this is a forked/copied workflow with an already working image-uri reference
310
+ // await addAppImageUri();
311
+
312
+ setWorkflowElement(
313
+ workflowDoc,
314
+ `${stepPath}.with.client-id`,
315
+ cli.clientDetailsLocation === 'env'
316
+ ? '${{ env.CONTENSIS_CLIENT_ID }}'
317
+ : '${{ secrets.CONTENSIS_CLIENT_ID }}'
318
+ );
319
+ setWorkflowElement(
320
+ workflowDoc,
321
+ `${stepPath}.with.shared-secret`,
322
+ cli.clientDetailsLocation === 'env'
323
+ ? '${{ env.CONTENSIS_SHARED_SECRET }}'
324
+ : '${{ secrets.CONTENSIS_SHARED_SECRET }}'
325
+ );
326
+ } else {
327
+ // create job with push step
328
+
329
+ // is there already a job with a property name containing "build"?
330
+ const existingBuildJobStep = findExistingJobSteps(
331
+ '$.jobs[?(@property.match(/build/i))]',
332
+ workflowJS,
333
+ 'all'
334
+ ) as JSONPathOptions[]; // This isn't the correct type for this object
335
+
336
+ let needs: string | undefined;
337
+ // There are multiple jobs called *build*
338
+ if (existingBuildJobStep.length > 1) {
339
+ // prompt which build job we should depend on before pushing the block
340
+ const choices = existingBuildJobStep.map(s => s.parentProperty);
341
+ choices.push(new inquirer.Separator() as any);
342
+ choices.push('none');
343
+ if (choices.includes('build-app')) needs = 'build-app';
344
+ else {
160
345
  ({ needs } = await inquirer.prompt([
161
346
  {
162
347
  type: 'list',
@@ -169,102 +354,102 @@ export const mapCIWorkflowContent = async (
169
354
  ),
170
355
  },
171
356
  ]));
172
- cli.log.raw('');
173
- } else if (existingBuildJobStep.length === 1)
174
- // Exactly one job step found containing a property name of *build*
175
- // we'll assume that is the one the push-block job depends on
176
- needs = existingBuildJobStep[0].parentProperty;
177
-
178
- if (existingBuildJobStep.length === 0 || needs === 'none') {
179
- // No existing build step found or chosen, offer all job steps in prompt
180
- const choices = Object.keys(workflowJS.jobs);
181
- choices.push(new inquirer.Separator() as any);
182
- choices.push('none');
183
-
184
- ({ needs } = await inquirer.prompt([
185
- {
186
- type: 'list',
187
- prefix: 'āŒ›',
188
- message: cli.messages.devinit.ciMultipleJobChoices(),
189
- name: 'needs',
190
- choices,
191
- default: choices.find(
192
- j => typeof j === 'string' && j.includes('docker')
193
- ),
194
- },
195
- ]));
196
- if (needs === 'none') needs = undefined;
197
- cli.log.raw('');
198
357
  }
199
358
 
200
- // Does a series of checks and prompts to determine the correct image-uri
201
- // for the app container build
202
- await addAppImageUri();
203
-
204
- const newJob: GitHubActionPushBlockJob = {
205
- name: 'Deploy container image to Contensis',
206
- 'runs-on': 'ubuntu-latest',
207
- needs,
208
- steps: [addGitHubActionJobStep],
209
- };
210
-
211
- // Add the new "job" to the Yaml Document
212
- workflowDoc.addIn(['jobs'], {
213
- key: 'deploy',
214
- value: newJob,
215
- });
216
- }
217
-
218
- // Workflow validation provided by @action-validator/core package
219
- const workflowIsValid = validateWorkflowYaml(workflowDoc.toString());
220
-
221
- // We could expand validation to check for having a build step to wait for
222
- // or if a valid image-uri attribute is set
223
- if (workflowIsValid === true) {
224
- cli.log.success(`GitHub workflow YAML is valid`);
225
- cli.log.debug(
226
- `New file content to write to ${git.ciFilePath}\n\n${workflowDoc}`
227
- );
228
- } else if (Array.isArray(workflowIsValid)) {
229
- // Errors
230
- logError(
231
- [
232
- ...workflowIsValid.map(
233
- res => new Error(`${res.code}: ${res.detail || res.title}`)
359
+ cli.log.raw('');
360
+ } else if (existingBuildJobStep.length === 1)
361
+ // Exactly one job step found containing a property name of *build*
362
+ // we'll assume that is the one the push-block job depends on
363
+ needs = existingBuildJobStep[0].parentProperty;
364
+
365
+ if (existingBuildJobStep.length === 0 || needs === 'none') {
366
+ // No existing build step found or chosen, offer all job steps in prompt
367
+ const choices = Object.keys(workflowJS.jobs);
368
+ choices.push(new inquirer.Separator() as any);
369
+ choices.push('none');
370
+
371
+ ({ needs } = await inquirer.prompt([
372
+ {
373
+ type: 'list',
374
+ prefix: 'āŒ›',
375
+ message: cli.messages.devinit.ciMultipleJobChoices(),
376
+ name: 'needs',
377
+ choices,
378
+ default: choices.find(
379
+ j => typeof j === 'string' && j.includes('docker')
234
380
  ),
235
- workflowDoc.toString(),
236
- ],
237
- `GitHub workflow YAML did not pass validation check`
238
- );
381
+ },
382
+ ]));
383
+ if (needs === 'none') needs = undefined;
384
+ cli.log.raw('');
239
385
  }
240
- const newWorkflow = normaliseLineEndings(
241
- workflowDoc.toString({ lineWidth: 0 })
242
- );
243
386
 
244
- return {
245
- existingWorkflow: workflowFile,
246
- newWorkflow,
247
- diff: diffFileContent(workflowFile, newWorkflow),
387
+ // Does a series of checks and prompts to determine the correct image-uri
388
+ // for the app container build
389
+ await addAppImageUri();
390
+
391
+ const newJob: GitHubActionPushBlockJob = {
392
+ name: 'Deploy container image to Contensis',
393
+ 'runs-on': 'ubuntu-latest',
394
+ needs,
395
+ steps: [addGitHubActionJobStep],
248
396
  };
397
+
398
+ // Add the new "job" to the Yaml Document
399
+ workflowDoc.addIn(['jobs'], {
400
+ key: 'deploy',
401
+ value: newJob,
402
+ });
249
403
  }
404
+
405
+ // Workflow validation provided by @action-validator/core package
406
+ const workflowIsValid = validateWorkflowYaml(workflowDoc.toString());
407
+
408
+ // We could expand validation to check for having a build step to wait for
409
+ // or if a valid image-uri attribute is set
410
+ if (workflowIsValid === true) {
411
+ cli.log.success(`GitHub workflow YAML is valid`);
412
+ cli.log.debug(`New file content to write\n\n${workflowDoc}`);
413
+ } else if (Array.isArray(workflowIsValid)) {
414
+ // Errors
415
+ logError(
416
+ [
417
+ ...workflowIsValid.map(
418
+ res => new Error(`${res.code}: ${res.detail || res.title}`)
419
+ ),
420
+ workflowDoc.toString(),
421
+ ],
422
+ `GitHub workflow YAML did not pass validation check`
423
+ );
424
+ }
425
+
426
+ // const newWorkflow = normaliseLineEndings(
427
+ // workflowDoc.toString({ lineWidth: 0 })
428
+ // );
429
+
430
+ const newWorkflow = workflowDoc.toString();
431
+
432
+ return newWorkflow;
250
433
  };
251
434
 
252
435
  const determineAppImageUri = async (
253
436
  cli: ContensisDev,
254
- vars: [string, string][]
437
+ vars: [string, string][],
438
+ defaultUri: string
255
439
  ) => {
256
440
  // Determine container image-uri via variables and/or prompts
257
441
 
258
442
  // Find vars including the word "image"
259
- const imageVars = vars.filter(([varname, value]) =>
443
+ const imageVars = vars.filter(([varname]) =>
260
444
  varname.toLowerCase().includes('image')
261
445
  );
262
446
  // Find vars named "image" that include the word "app"
263
447
  const appImageVars = imageVars.filter(
264
448
  ([varname, value]) =>
265
- varname.toLowerCase().includes('app_') ||
266
- varname.toLowerCase().includes('build_') ||
267
- value?.toLowerCase().includes('/app')
449
+ !varname.toLowerCase().includes('builder_') &&
450
+ (varname.toLowerCase().includes('app_') ||
451
+ varname.toLowerCase().includes('build_') ||
452
+ value?.toLowerCase().includes('/app'))
268
453
  );
269
454
 
270
455
  const appImageUriGuess = appImageVars?.[0];
@@ -286,8 +471,7 @@ const determineAppImageUri = async (
286
471
  // prompt for an app image uri
287
472
  const choices = vars.map(v => v[0]);
288
473
  const enterOwnMsg = 'enter my own / use default';
289
- const defaultUri =
290
- 'ghcr.io/${{ github.repository }}/${{ github.ref_name }}/app:build-${{ github.run_number }}';
474
+
291
475
  choices.push(new inquirer.Separator() as any);
292
476
  choices.push(enterOwnMsg);
293
477
  choices.push(defaultUri);
@@ -312,7 +496,7 @@ const determineAppImageUri = async (
312
496
  return [enterOwnMsg, defaultUri].includes(answers.appImageVar);
313
497
  },
314
498
  prefix: `\n \nšŸ”—`,
315
- message: cli.messages.devinit.ciEnterOwnAppImagePrompt(),
499
+ message: cli.messages.devinit.ciEnterOwnAppImagePrompt(cli.git),
316
500
  name: 'appImageUri',
317
501
  default: defaultUri,
318
502
  },
@@ -326,7 +510,13 @@ const determineAppImageUri = async (
326
510
  appImageVar = undefined;
327
511
  }
328
512
 
329
- if (appImageVar) appImageUri = `\${{ env.${appImageVar} }}`;
513
+ if (appImageVar)
514
+ appImageUri =
515
+ cli.git.type === 'github'
516
+ ? `\${{ env.${appImageVar} }}`
517
+ : `\$${appImageVar}`;
518
+
519
+ // TODO: prompt further for image tag
330
520
 
331
521
  return {
332
522
  addVar: !appImageVar,