@catladder/pipeline 2.10.1 โ†’ 2.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1407 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`matches snapshot for override-secrets local pipeline YAML 1`] = `
4
+ "image: path/to/docker/jobs-default:the-version
5
+ stages:
6
+ - setup
7
+ - setup dev
8
+ - setup review
9
+ - setup stage
10
+ - setup prod
11
+ - test
12
+ - test dev
13
+ - test review
14
+ - test stage
15
+ - test prod
16
+ - build
17
+ - build dev
18
+ - build review
19
+ - build stage
20
+ - build prod
21
+ - deploy
22
+ - deploy dev
23
+ - deploy review
24
+ - deploy stage
25
+ - deploy prod
26
+ - verify
27
+ - verify dev
28
+ - verify review
29
+ - verify stage
30
+ - verify prod
31
+ - rollback
32
+ - rollback dev
33
+ - rollback review
34
+ - rollback stage
35
+ - rollback prod
36
+ - stop
37
+ - stop dev
38
+ - stop review
39
+ - stop stage
40
+ - stop prod
41
+ - release
42
+ variables:
43
+ FF_USE_FASTZIP: 'true'
44
+ ARTIFACT_COMPRESSION_LEVEL: fast
45
+ CACHE_COMPRESSION_LEVEL: fast
46
+ TRANSFER_METER_FREQUENCY: 5s
47
+ GIT_DEPTH: '1'
48
+ before_script:
49
+ - |-
50
+ function escapeForDotEnv () {
51
+ input="\${1:-$(cat)}"
52
+ input="\${input//$'\\n'/\\\\n}"
53
+ if [[ "$input" == *\\\\n* ]]; then
54
+ if [[ "$input" == *\\"* && "$input" == *\\'* && "$input" == *\\\`* ]]; then
55
+ printf "\\"%s\\"\\n" "$input"
56
+ elif [[ "$input" == *\\"* && "$input" == *\\'* ]]; then
57
+ printf "\`%s\`\\n" "$input"
58
+ elif [[ "$input" == *\\"* ]]; then
59
+ printf "'%s'\\n" "$input"
60
+ else
61
+ printf "\\"%s\\"\\n" "$input"
62
+ fi
63
+ else
64
+ printf "%s\\n" "$input"
65
+ fi
66
+ }
67
+ - |-
68
+ function collapseable_section_start () {
69
+ local section_title="\${1}"
70
+ local section_description="\${2:-$section_title}"
71
+ echo -e "section_start:\`date +%s\`:\${section_title}[collapsed=true]\\r\\e[0K\${section_description}"
72
+ }
73
+ - |-
74
+ function collapseable_section_end () {
75
+ local section_title="\${1}"
76
+ echo -e "section_end:\`date +%s\`:\${section_title}\\r\\e[0K"
77
+ }
78
+ my-app ๐Ÿ›ก audit:
79
+ stage: test
80
+ image: path/to/docker/jobs-default:the-version
81
+ variables:
82
+ KUBERNETES_CPU_REQUEST: '0.45'
83
+ KUBERNETES_MEMORY_REQUEST: 1Gi
84
+ KUBERNETES_MEMORY_LIMIT: 4Gi
85
+ script:
86
+ - collapseable_section_start "injectvars" "Injecting variables"
87
+ - export APP_PATH="app"
88
+ - collapseable_section_end "injectvars"
89
+ - cd app
90
+ - yarn npm audit --environment production
91
+ rules:
92
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_COMMIT_MESSAGE !~ /^chore\\(release\\).*/
93
+ - if: $CI_MERGE_REQUEST_ID
94
+ needs: []
95
+ retry: &a1
96
+ max: 2
97
+ when:
98
+ - runner_system_failure
99
+ - stuck_or_timeout_failure
100
+ interruptible: true
101
+ allow_failure: true
102
+ my-app ๐Ÿ‘ฎ lint:
103
+ stage: test
104
+ image: path/to/docker/jobs-default:the-version
105
+ variables:
106
+ KUBERNETES_CPU_REQUEST: '0.45'
107
+ KUBERNETES_MEMORY_REQUEST: 1Gi
108
+ KUBERNETES_MEMORY_LIMIT: 4Gi
109
+ script:
110
+ - collapseable_section_start "injectvars" "Injecting variables"
111
+ - export APP_PATH="app"
112
+ - collapseable_section_end "injectvars"
113
+ - collapseable_section_start "nodeinstall" "Ensure node version"
114
+ - if [ -f ~/.nvm/nvm.sh ]; then source ~/.nvm/nvm.sh; fi
115
+ - if command -v nvm &> /dev/null && [ -f ./.nvmrc ]; then nvm install; fi
116
+ - collapseable_section_end "nodeinstall"
117
+ - cd app
118
+ - collapseable_section_start "nodeinstall" "Ensure node version"
119
+ - if [ -f ~/.nvm/nvm.sh ]; then source ~/.nvm/nvm.sh; fi
120
+ - if command -v nvm &> /dev/null && [ -f ./.nvmrc ]; then nvm install; fi
121
+ - collapseable_section_end "nodeinstall"
122
+ - collapseable_section_start "yarninstall" "Yarn install"
123
+ - yarn install --immutable
124
+ - collapseable_section_end "yarninstall"
125
+ - yarn lint
126
+ cache:
127
+ - key: app-yarn
128
+ policy: pull-push
129
+ paths:
130
+ - app/.yarn
131
+ - key: app-node-modules
132
+ policy: pull-push
133
+ paths:
134
+ - app/node_modules
135
+ rules:
136
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_COMMIT_MESSAGE !~ /^chore\\(release\\).*/
137
+ - if: $CI_MERGE_REQUEST_ID
138
+ needs: []
139
+ retry: *a1
140
+ interruptible: true
141
+ my-app ๐Ÿงช test:
142
+ stage: test
143
+ image: path/to/docker/jobs-testing-chrome:the-version
144
+ variables:
145
+ KUBERNETES_CPU_REQUEST: '0.45'
146
+ KUBERNETES_MEMORY_REQUEST: 1Gi
147
+ KUBERNETES_MEMORY_LIMIT: 4Gi
148
+ script:
149
+ - collapseable_section_start "injectvars" "Injecting variables"
150
+ - export APP_PATH="app"
151
+ - collapseable_section_end "injectvars"
152
+ - collapseable_section_start "nodeinstall" "Ensure node version"
153
+ - if [ -f ~/.nvm/nvm.sh ]; then source ~/.nvm/nvm.sh; fi
154
+ - if command -v nvm &> /dev/null && [ -f ./.nvmrc ]; then nvm install; fi
155
+ - collapseable_section_end "nodeinstall"
156
+ - cd app
157
+ - collapseable_section_start "nodeinstall" "Ensure node version"
158
+ - if [ -f ~/.nvm/nvm.sh ]; then source ~/.nvm/nvm.sh; fi
159
+ - if command -v nvm &> /dev/null && [ -f ./.nvmrc ]; then nvm install; fi
160
+ - collapseable_section_end "nodeinstall"
161
+ - collapseable_section_start "yarninstall" "Yarn install"
162
+ - yarn install --immutable
163
+ - collapseable_section_end "yarninstall"
164
+ - yarn test
165
+ cache:
166
+ - key: app-yarn
167
+ policy: pull-push
168
+ paths:
169
+ - app/.yarn
170
+ - key: app-node-modules
171
+ policy: pull-push
172
+ paths:
173
+ - app/node_modules
174
+ rules:
175
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_COMMIT_MESSAGE !~ /^chore\\(release\\).*/
176
+ - if: $CI_MERGE_REQUEST_ID
177
+ needs: []
178
+ retry: *a1
179
+ interruptible: true
180
+ 'my-app ๐Ÿ”จ app | dev ':
181
+ stage: build
182
+ image: path/to/docker/jobs-default:the-version
183
+ variables:
184
+ KUBERNETES_CPU_REQUEST: '0.45'
185
+ KUBERNETES_MEMORY_REQUEST: 1Gi
186
+ KUBERNETES_MEMORY_LIMIT: 4Gi
187
+ script:
188
+ - collapseable_section_start "injectvars" "Injecting variables"
189
+ - export ENV_SHORT="dev"
190
+ - export APP_DIR="app"
191
+ - export ENV_TYPE="dev"
192
+ - export BUILD_INFO_BUILD_ID="$(git describe --tags 2>/dev/null || git rev-parse HEAD)"
193
+ - export BUILD_INFO_BUILD_TIME="$CI_JOB_STARTED_AT"
194
+ - export BUILD_INFO_CURRENT_VERSION="$(tag=$(git ls-remote origin "refs/tags/v*[0-9]" 2>/dev/null | cut -f 2- | sort -V | tail -1 | sed 's/refs\\/tags\\/v//'); [ -z "$tag" ] && echo "0.0.0" || echo "$tag")"
195
+ - export HOSTNAME="$(printf %s "pan-test-app-dev-my-app-$CL_dev_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
196
+ - export ROOT_URL="https://$(printf %s "pan-test-app-dev-my-app-$CL_dev_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
197
+ - export HOSTNAME_INTERNAL="$(printf %s "pan-test-app-dev-my-app-$CL_dev_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
198
+ - export ROOT_URL_INTERNAL="https://$(printf %s "pan-test-app-dev-my-app-$CL_dev_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
199
+ - export DEPLOY_CLOUD_RUN_PROJECT_ID="my-project-id"
200
+ - export DEPLOY_CLOUD_RUN_REGION="europe-west6"
201
+ - export MY_SECRET="$CL_dev_my_app_MY_SECRET"
202
+ - export GCLOUD_DEPLOY_credentialsKey="$CL_dev_my_app_GCLOUD_DEPLOY_credentialsKey"
203
+ - export GCLOUD_RUN_canonicalHostSuffix="$CL_dev_my_app_GCLOUD_RUN_canonicalHostSuffix"
204
+ - export _ALL_ENV_VAR_KEYS="[\\"ENV_SHORT\\",\\"APP_DIR\\",\\"ENV_TYPE\\",\\"BUILD_INFO_BUILD_ID\\",\\"BUILD_INFO_BUILD_TIME\\",\\"BUILD_INFO_CURRENT_VERSION\\",\\"HOSTNAME\\",\\"ROOT_URL\\",\\"HOSTNAME_INTERNAL\\",\\"ROOT_URL_INTERNAL\\",\\"DEPLOY_CLOUD_RUN_PROJECT_ID\\",\\"DEPLOY_CLOUD_RUN_REGION\\",\\"MY_SECRET\\",\\"GCLOUD_DEPLOY_credentialsKey\\",\\"GCLOUD_RUN_canonicalHostSuffix\\"]"
205
+ - collapseable_section_end "injectvars"
206
+ - collapseable_section_start "write-dotenv-my-app" "write dot env for my-app"
207
+ - |-
208
+ cat <<EOF > app/.env
209
+ ENV_SHORT=dev
210
+ APP_DIR=app
211
+ ENV_TYPE=dev
212
+ HOSTNAME=$(printf %s "$(printf %s "pan-test-app-dev-my-app-$CL_dev_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | escapeForDotEnv)
213
+ ROOT_URL=$(printf %s "https://$(printf %s "pan-test-app-dev-my-app-$CL_dev_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | escapeForDotEnv)
214
+ HOSTNAME_INTERNAL=$(printf %s "$(printf %s "pan-test-app-dev-my-app-$CL_dev_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | escapeForDotEnv)
215
+ ROOT_URL_INTERNAL=$(printf %s "https://$(printf %s "pan-test-app-dev-my-app-$CL_dev_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | escapeForDotEnv)
216
+ DEPLOY_CLOUD_RUN_PROJECT_ID=my-project-id
217
+ DEPLOY_CLOUD_RUN_REGION=europe-west6
218
+ MY_SECRET=$(printf %s "$CL_dev_my_app_MY_SECRET" | escapeForDotEnv)
219
+ GCLOUD_DEPLOY_credentialsKey=$(printf %s "$CL_dev_my_app_GCLOUD_DEPLOY_credentialsKey" | escapeForDotEnv)
220
+ GCLOUD_RUN_canonicalHostSuffix=$(printf %s "$CL_dev_my_app_GCLOUD_RUN_canonicalHostSuffix" | escapeForDotEnv)
221
+ _ALL_ENV_VAR_KEYS=["ENV_SHORT","APP_DIR","ENV_TYPE","BUILD_INFO_BUILD_ID","BUILD_INFO_BUILD_TIME","BUILD_INFO_CURRENT_VERSION","HOSTNAME","ROOT_URL","HOSTNAME_INTERNAL","ROOT_URL_INTERNAL","DEPLOY_CLOUD_RUN_PROJECT_ID","DEPLOY_CLOUD_RUN_REGION","MY_SECRET","GCLOUD_DEPLOY_credentialsKey","GCLOUD_RUN_canonicalHostSuffix"]
222
+ EOF
223
+ - collapseable_section_end "write-dotenv-my-app"
224
+ - echo '{"id":"$(git describe --tags 2>/dev/null || git rev-parse HEAD)","time":"$CI_JOB_STARTED_AT"}' > app/__build_info.json
225
+ - collapseable_section_start "nodeinstall" "Ensure node version"
226
+ - if [ -f ~/.nvm/nvm.sh ]; then source ~/.nvm/nvm.sh; fi
227
+ - if command -v nvm &> /dev/null && [ -f ./.nvmrc ]; then nvm install; fi
228
+ - collapseable_section_end "nodeinstall"
229
+ - cd app
230
+ - collapseable_section_start "nodeinstall" "Ensure node version"
231
+ - if [ -f ~/.nvm/nvm.sh ]; then source ~/.nvm/nvm.sh; fi
232
+ - if command -v nvm &> /dev/null && [ -f ./.nvmrc ]; then nvm install; fi
233
+ - collapseable_section_end "nodeinstall"
234
+ - collapseable_section_start "yarninstall" "Yarn install"
235
+ - yarn install --immutable
236
+ - collapseable_section_end "yarninstall"
237
+ - yarn build
238
+ cache:
239
+ - key: app-yarn
240
+ policy: pull-push
241
+ paths:
242
+ - app/.yarn
243
+ - key: app-node-modules
244
+ policy: pull-push
245
+ paths:
246
+ - app/node_modules
247
+ artifacts:
248
+ paths:
249
+ - app/__build_info.json
250
+ - app/.next
251
+ - app/dist
252
+ exclude:
253
+ - app/.env
254
+ expire_in: 1 day
255
+ when: always
256
+ reports: {}
257
+ rules:
258
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_COMMIT_MESSAGE !~ /^chore\\(release\\).*/
259
+ needs: []
260
+ retry: *a1
261
+ interruptible: true
262
+ 'my-app ๐Ÿ”จ docker | dev ':
263
+ stage: build
264
+ image: path/to/docker/docker-build:the-version
265
+ services:
266
+ - name: docker:24.0.6-dind
267
+ command:
268
+ - --tls=false
269
+ - --registry-mirror=https://mirror.gcr.io
270
+ variables:
271
+ DOCKER_HOST: tcp://0.0.0.0:2375
272
+ DOCKER_TLS_CERTDIR: ''
273
+ DOCKER_DRIVER: overlay2
274
+ DOCKER_BUILDKIT: '1'
275
+ KUBERNETES_CPU_REQUEST: '0.45'
276
+ KUBERNETES_MEMORY_REQUEST: 1Gi
277
+ KUBERNETES_MEMORY_LIMIT: 2Gi
278
+ script:
279
+ - collapseable_section_start "injectvars" "Injecting variables"
280
+ - export APP_DIR="app"
281
+ - export DOCKER_BUILD_CONTEXT="."
282
+ - export DOCKER_REGISTRY="europe-west6-docker.pkg.dev"
283
+ - export DOCKER_IMAGE="europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/dev/my-app"
284
+ - export DOCKER_CACHE_IMAGE="europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/caches/my-app"
285
+ - export DOCKER_IMAGE_TAG="$CI_COMMIT_SHA"
286
+ - |-
287
+ export DOCKER_COPY_AND_INSTALL_APP="COPY --chown=node:node $APP_DIR .
288
+ RUN yarn plugin import workspace-tools
289
+ RUN yarn workspaces focus --production && yarn rebuild"
290
+ - |-
291
+ export DOCKER_COPY_WORKSPACE_FILES="COPY --chown=node:node app/package.json /app/app/package.json
292
+ COPY --chown=node:node app/yarn.lock /app/app/yarn.lock
293
+ COPY --chown=node:node .yarnrc.yml /app/.yarnrc.yml
294
+ COPY --chown=node:node .yarn /app/.yarn"
295
+ - collapseable_section_end "injectvars"
296
+ - ensureNodeDockerfile
297
+ - collapseable_section_start "docker-login" "Docker Login"
298
+ - gcloud auth activate-service-account --key-file=<(echo "$CL_dev_my_app_GCLOUD_DEPLOY_credentialsKey")
299
+ - gcloud auth configure-docker europe-west6-docker.pkg.dev
300
+ - collapseable_section_end "docker-login"
301
+ - collapseable_section_start "docker-build" "Docker build"
302
+ - docker build --network host --cache-from $DOCKER_CACHE_IMAGE --tag $DOCKER_IMAGE:$DOCKER_IMAGE_TAG -f $APP_DIR/Dockerfile $DOCKER_BUILD_CONTEXT --build-arg BUILDKIT_INLINE_CACHE=1
303
+ - collapseable_section_end "docker-build"
304
+ - collapseable_section_start "docker-push" "Docker push and tag"
305
+ - docker push $DOCKER_IMAGE:$DOCKER_IMAGE_TAG
306
+ - docker tag $DOCKER_IMAGE:$DOCKER_IMAGE_TAG $DOCKER_CACHE_IMAGE
307
+ - docker push $DOCKER_CACHE_IMAGE
308
+ - collapseable_section_end "docker-push"
309
+ cache:
310
+ - key: app-yarn
311
+ policy: pull
312
+ paths:
313
+ - app/.yarn
314
+ rules:
315
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_COMMIT_MESSAGE !~ /^chore\\(release\\).*/
316
+ needs:
317
+ - 'my-app ๐Ÿ”จ app | dev '
318
+ retry: *a1
319
+ interruptible: true
320
+ 'my-app ๐Ÿงพ sbom | dev ':
321
+ stage: build
322
+ image: aquasec/trivy:0.38.3
323
+ variables: {}
324
+ script:
325
+ - collapseable_section_start "injectvars" "Injecting variables"
326
+ - collapseable_section_end "injectvars"
327
+ - trivy fs --quiet --format cyclonedx --output "__sbom.json" app
328
+ artifacts:
329
+ paths:
330
+ - __sbom.json
331
+ rules:
332
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_COMMIT_MESSAGE !~ /^chore\\(release\\).*/
333
+ needs: []
334
+ retry: *a1
335
+ interruptible: true
336
+ allow_failure: true
337
+ 'my-app ๐Ÿš€ Deploy | dev ':
338
+ stage: deploy dev
339
+ image: path/to/docker/gcloud:the-version
340
+ variables:
341
+ KUBERNETES_CPU_REQUEST: '0.22'
342
+ KUBERNETES_MEMORY_REQUEST: 200Mi
343
+ KUBERNETES_MEMORY_LIMIT: 400Mi
344
+ script:
345
+ - collapseable_section_start "injectvars" "Injecting variables"
346
+ - export ENV_SHORT="dev"
347
+ - export APP_DIR="app"
348
+ - export ENV_TYPE="dev"
349
+ - export BUILD_INFO_BUILD_ID="$(git describe --tags 2>/dev/null || git rev-parse HEAD)"
350
+ - export BUILD_INFO_BUILD_TIME="$CI_JOB_STARTED_AT"
351
+ - export BUILD_INFO_CURRENT_VERSION="$(tag=$(git ls-remote origin "refs/tags/v*[0-9]" 2>/dev/null | cut -f 2- | sort -V | tail -1 | sed 's/refs\\/tags\\/v//'); [ -z "$tag" ] && echo "0.0.0" || echo "$tag")"
352
+ - export HOSTNAME="$(printf %s "pan-test-app-dev-my-app-$CL_dev_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
353
+ - export ROOT_URL="https://$(printf %s "pan-test-app-dev-my-app-$CL_dev_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
354
+ - export HOSTNAME_INTERNAL="$(printf %s "pan-test-app-dev-my-app-$CL_dev_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
355
+ - export ROOT_URL_INTERNAL="https://$(printf %s "pan-test-app-dev-my-app-$CL_dev_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
356
+ - export DEPLOY_CLOUD_RUN_PROJECT_ID="my-project-id"
357
+ - export DEPLOY_CLOUD_RUN_REGION="europe-west6"
358
+ - export MY_SECRET="$CL_dev_my_app_MY_SECRET"
359
+ - export GCLOUD_DEPLOY_credentialsKey="$CL_dev_my_app_GCLOUD_DEPLOY_credentialsKey"
360
+ - export GCLOUD_RUN_canonicalHostSuffix="$CL_dev_my_app_GCLOUD_RUN_canonicalHostSuffix"
361
+ - export _ALL_ENV_VAR_KEYS="[\\"ENV_SHORT\\",\\"APP_DIR\\",\\"ENV_TYPE\\",\\"BUILD_INFO_BUILD_ID\\",\\"BUILD_INFO_BUILD_TIME\\",\\"BUILD_INFO_CURRENT_VERSION\\",\\"HOSTNAME\\",\\"ROOT_URL\\",\\"HOSTNAME_INTERNAL\\",\\"ROOT_URL_INTERNAL\\",\\"DEPLOY_CLOUD_RUN_PROJECT_ID\\",\\"DEPLOY_CLOUD_RUN_REGION\\",\\"MY_SECRET\\",\\"GCLOUD_DEPLOY_credentialsKey\\",\\"GCLOUD_RUN_canonicalHostSuffix\\"]"
362
+ - export DOCKER_REGISTRY="europe-west6-docker.pkg.dev"
363
+ - export DOCKER_IMAGE="europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/dev/my-app"
364
+ - export DOCKER_CACHE_IMAGE="europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/caches/my-app"
365
+ - export DOCKER_IMAGE_TAG="$CI_COMMIT_SHA"
366
+ - export CLOUDSDK_CORE_DISABLE_PROMPTS="1"
367
+ - collapseable_section_end "injectvars"
368
+ - collapseable_section_start "prepare" "Prepare..."
369
+ - gcloud auth activate-service-account --key-file=<(echo "$CL_dev_my_app_GCLOUD_DEPLOY_credentialsKey")
370
+ - export GCLOUD_PROJECT_NUMBER=$(gcloud projects describe my-project-id --format="value(projectNumber)")
371
+ - 'echo "GCLOUD_PROJECT_NUMBER: $GCLOUD_PROJECT_NUMBER"'
372
+ - collapseable_section_end "prepare"
373
+ - collapseable_section_start "writeenvvars" "Write env vars to file"
374
+ - |
375
+ cat > ____envvars.yaml <<EOF
376
+ ENV_SHORT: |-
377
+ dev
378
+ APP_DIR: |-
379
+ app
380
+ ENV_TYPE: |-
381
+ dev
382
+ BUILD_INFO_BUILD_ID: |-
383
+ $(printf %s "$(git describe --tags 2>/dev/null || git rev-parse HEAD)" | sed '1!s/^/ /')
384
+ BUILD_INFO_BUILD_TIME: |-
385
+ $(printf %s "$CI_JOB_STARTED_AT" | sed '1!s/^/ /')
386
+ BUILD_INFO_CURRENT_VERSION: |-
387
+ $(printf %s "$(tag=$(git ls-remote origin "refs/tags/v*[0-9]" 2>/dev/null | cut -f 2- | sort -V | tail -1 | sed 's/refs\\/tags\\/v//'); [ -z "$tag" ] && echo "0.0.0" || echo "$tag")" | sed '1!s/^/ /')
388
+ HOSTNAME: |-
389
+ $(printf %s "$(printf %s "pan-test-app-dev-my-app-$CL_dev_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | sed '1!s/^/ /')
390
+ ROOT_URL: |-
391
+ $(printf %s "https://$(printf %s "pan-test-app-dev-my-app-$CL_dev_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | sed '1!s/^/ /')
392
+ HOSTNAME_INTERNAL: |-
393
+ $(printf %s "$(printf %s "pan-test-app-dev-my-app-$CL_dev_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | sed '1!s/^/ /')
394
+ ROOT_URL_INTERNAL: |-
395
+ $(printf %s "https://$(printf %s "pan-test-app-dev-my-app-$CL_dev_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | sed '1!s/^/ /')
396
+ DEPLOY_CLOUD_RUN_PROJECT_ID: |-
397
+ my-project-id
398
+ DEPLOY_CLOUD_RUN_REGION: |-
399
+ europe-west6
400
+ MY_SECRET: |-
401
+ $(printf %s "$CL_dev_my_app_MY_SECRET" | sed '1!s/^/ /')
402
+ GCLOUD_RUN_canonicalHostSuffix: |-
403
+ $(printf %s "$CL_dev_my_app_GCLOUD_RUN_canonicalHostSuffix" | sed '1!s/^/ /')
404
+ _ALL_ENV_VAR_KEYS: |-
405
+ ["ENV_SHORT","APP_DIR","ENV_TYPE","BUILD_INFO_BUILD_ID","BUILD_INFO_BUILD_TIME","BUILD_INFO_CURRENT_VERSION","HOSTNAME","ROOT_URL","HOSTNAME_INTERNAL","ROOT_URL_INTERNAL","DEPLOY_CLOUD_RUN_PROJECT_ID","DEPLOY_CLOUD_RUN_REGION","MY_SECRET","GCLOUD_DEPLOY_credentialsKey","GCLOUD_RUN_canonicalHostSuffix"]
406
+
407
+ EOF
408
+ - collapseable_section_end "writeenvvars"
409
+ - collapseable_section_start "deploy" "Deploy to cloud run"
410
+ - gcloud run deploy pan-test-app-dev-my-app --command="yarn,start" --image=europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/dev/my-app:$DOCKER_IMAGE_TAG --project=my-project-id --region=europe-west6 --labels=customer-name=pan,component-name=my-app,app-name=test-app,env-type=dev,env-name=dev,build-type=node,cloud-run-service-name=pan-test-app-dev-my-app --env-vars-file=____envvars.yaml --min-instances=0 --max-instances=100 --cpu-throttling --allow-unauthenticated --ingress=all --cpu-boost
411
+ - collapseable_section_end "deploy"
412
+ - collapseable_section_start "cleanup" "Cleanup"
413
+ - gcloud run revisions list --project=my-project-id --region=europe-west6 --service=pan-test-app-dev-my-app --limit=unlimited --sort-by=metadata.creationTimestamp --format="value(name)" --filter='(status.conditions.status=False OR status.conditions.status=Unknown)' | while read -r revisionname; do gcloud run revisions delete --project=my-project-id --region=europe-west6 --quiet $revisionname ; done
414
+ - gcloud artifacts docker images list europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/dev/my-app --sort-by=~CREATE_TIME --format="value(version)" | tail -n +2 | while read -r version; do gcloud artifacts docker images delete europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/dev/my-app@$version --quiet --delete-tags; done
415
+ - gcloud artifacts docker images list europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/caches/my-app --sort-by=~CREATE_TIME --format="value(version)" | tail -n +2 | while read -r version; do gcloud artifacts docker images delete europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/caches/my-app@$version --quiet --delete-tags; done
416
+ - collapseable_section_end "cleanup"
417
+ - echo 'Uploading SBOM to Dependency Track'
418
+ - /dtrackuploader https://dep.panter.swiss/ "$DT_KEY_PROD" upload "pan-test-app/my-app" "$ROOT_URL" "__sbom.json" vex.json || true
419
+ - echo "CL_GITLAB_ENVIRONMENT_URL=$ROOT_URL" >> gitlab_environment.env
420
+ environment:
421
+ name: dev/my-app
422
+ url: $CL_GITLAB_ENVIRONMENT_URL
423
+ on_stop: 'my-app ๐Ÿ›‘ Stop โš ๏ธ | dev '
424
+ auto_stop_in: 4 weeks
425
+ artifacts:
426
+ reports:
427
+ dotenv: gitlab_environment.env
428
+ rules:
429
+ - when: on_success
430
+ if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_COMMIT_MESSAGE !~ /^chore\\(release\\).*/
431
+ needs:
432
+ - job: my-app ๐Ÿ‘ฎ lint
433
+ artifacts: false
434
+ - job: 'my-app ๐Ÿ”จ app | dev '
435
+ artifacts: false
436
+ - job: 'my-app ๐Ÿ”จ docker | dev '
437
+ artifacts: false
438
+ - job: my-app ๐Ÿงช test
439
+ artifacts: false
440
+ - job: 'my-app ๐Ÿงพ sbom | dev '
441
+ artifacts: true
442
+ - job: my-app ๐Ÿ›ก audit
443
+ artifacts: false
444
+ retry: *a1
445
+ interruptible: true
446
+ allow_failure: false
447
+ 'my-app ๐Ÿ›‘ Stop โš ๏ธ | dev ':
448
+ stage: stop dev
449
+ image: path/to/docker/gcloud:the-version
450
+ variables:
451
+ KUBERNETES_CPU_REQUEST: '0.22'
452
+ KUBERNETES_MEMORY_REQUEST: 200Mi
453
+ KUBERNETES_MEMORY_LIMIT: 400Mi
454
+ GIT_STRATEGY: none
455
+ script:
456
+ - collapseable_section_start "injectvars" "Injecting variables"
457
+ - export CLOUDSDK_CORE_DISABLE_PROMPTS="1"
458
+ - collapseable_section_end "injectvars"
459
+ - set +e
460
+ - gcloud auth activate-service-account --key-file=<(echo "$CL_dev_my_app_GCLOUD_DEPLOY_credentialsKey")
461
+ - gcloud run services delete pan-test-app-dev-my-app --project=my-project-id --region=europe-west6
462
+ - gcloud artifacts docker images delete europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/dev/my-app --quiet --delete-tags
463
+ - gcloud artifacts docker images list europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/caches/my-app --sort-by=~CREATE_TIME --format="value(version)" | tail -n +2 | while read -r version; do gcloud artifacts docker images delete europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/caches/my-app@$version --quiet --delete-tags; done
464
+ - echo 'Disabling component in Dependency Track'
465
+ - /dtrackuploader https://dep.panter.swiss/ "$DT_KEY_PROD" disable "pan-test-app/my-app" "$CI_ENVIRONMENT_URL" || true
466
+ - set -e
467
+ environment:
468
+ name: dev/my-app
469
+ action: stop
470
+ rules:
471
+ - if: $CI_COMMIT_BRANCH =~ /^[0-9]+\\.([0-9]+|x)\\.x$/
472
+ when: on_success
473
+ - when: manual
474
+ if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_COMMIT_MESSAGE !~ /^chore\\(release\\).*/
475
+ needs: []
476
+ retry: *a1
477
+ interruptible: true
478
+ allow_failure: true
479
+ 'my-app ๐Ÿ”จ app | review ':
480
+ stage: build
481
+ image: path/to/docker/jobs-default:the-version
482
+ variables:
483
+ KUBERNETES_CPU_REQUEST: '0.45'
484
+ KUBERNETES_MEMORY_REQUEST: 1Gi
485
+ KUBERNETES_MEMORY_LIMIT: 4Gi
486
+ script:
487
+ - collapseable_section_start "injectvars" "Injecting variables"
488
+ - export ENV_SHORT="review"
489
+ - export APP_DIR="app"
490
+ - export ENV_TYPE="review"
491
+ - export BUILD_INFO_BUILD_ID="$(git describe --tags 2>/dev/null || git rev-parse HEAD)"
492
+ - export BUILD_INFO_BUILD_TIME="$CI_JOB_STARTED_AT"
493
+ - export BUILD_INFO_CURRENT_VERSION="$(tag=$(git ls-remote origin "refs/tags/v*[0-9]" 2>/dev/null | cut -f 2- | sort -V | tail -1 | sed 's/refs\\/tags\\/v//'); [ -z "$tag" ] && echo "0.0.0" || echo "$tag")"
494
+ - export HOSTNAME="$(printf %s "pan-test-app-review-$([ -n "$CI_MERGE_REQUEST_IID" ] && echo "mr$CI_MERGE_REQUEST_IID" || { [ -n "$CI_COMMIT_REF_SLUG" ] && echo "$CI_COMMIT_REF_SLUG" || echo "unknown"; })-my-app-$CL_review_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
495
+ - export ROOT_URL="https://$(printf %s "pan-test-app-review-$([ -n "$CI_MERGE_REQUEST_IID" ] && echo "mr$CI_MERGE_REQUEST_IID" || { [ -n "$CI_COMMIT_REF_SLUG" ] && echo "$CI_COMMIT_REF_SLUG" || echo "unknown"; })-my-app-$CL_review_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
496
+ - export HOSTNAME_INTERNAL="$(printf %s "pan-test-app-review-$([ -n "$CI_MERGE_REQUEST_IID" ] && echo "mr$CI_MERGE_REQUEST_IID" || { [ -n "$CI_COMMIT_REF_SLUG" ] && echo "$CI_COMMIT_REF_SLUG" || echo "unknown"; })-my-app-$CL_review_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
497
+ - export ROOT_URL_INTERNAL="https://$(printf %s "pan-test-app-review-$([ -n "$CI_MERGE_REQUEST_IID" ] && echo "mr$CI_MERGE_REQUEST_IID" || { [ -n "$CI_COMMIT_REF_SLUG" ] && echo "$CI_COMMIT_REF_SLUG" || echo "unknown"; })-my-app-$CL_review_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
498
+ - export DEPLOY_CLOUD_RUN_PROJECT_ID="my-project-id"
499
+ - export DEPLOY_CLOUD_RUN_REGION="europe-west6"
500
+ - export MY_SECRET="$CL_review_my_app_MY_SECRET"
501
+ - export MY_REVIEW_SECRET="$CL_review_my_app_MY_REVIEW_SECRET"
502
+ - export GCLOUD_DEPLOY_credentialsKey="$CL_review_my_app_GCLOUD_DEPLOY_credentialsKey"
503
+ - export GCLOUD_RUN_canonicalHostSuffix="$CL_review_my_app_GCLOUD_RUN_canonicalHostSuffix"
504
+ - export _ALL_ENV_VAR_KEYS="[\\"ENV_SHORT\\",\\"APP_DIR\\",\\"ENV_TYPE\\",\\"BUILD_INFO_BUILD_ID\\",\\"BUILD_INFO_BUILD_TIME\\",\\"BUILD_INFO_CURRENT_VERSION\\",\\"HOSTNAME\\",\\"ROOT_URL\\",\\"HOSTNAME_INTERNAL\\",\\"ROOT_URL_INTERNAL\\",\\"DEPLOY_CLOUD_RUN_PROJECT_ID\\",\\"DEPLOY_CLOUD_RUN_REGION\\",\\"MY_SECRET\\",\\"MY_REVIEW_SECRET\\",\\"GCLOUD_DEPLOY_credentialsKey\\",\\"GCLOUD_RUN_canonicalHostSuffix\\"]"
505
+ - collapseable_section_end "injectvars"
506
+ - collapseable_section_start "write-dotenv-my-app" "write dot env for my-app"
507
+ - |-
508
+ cat <<EOF > app/.env
509
+ ENV_SHORT=review
510
+ APP_DIR=app
511
+ ENV_TYPE=review
512
+ HOSTNAME=$(printf %s "$(printf %s "pan-test-app-review-$([ -n "$CI_MERGE_REQUEST_IID" ] && echo "mr$CI_MERGE_REQUEST_IID" || { [ -n "$CI_COMMIT_REF_SLUG" ] && echo "$CI_COMMIT_REF_SLUG" || echo "unknown"; })-my-app-$CL_review_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | escapeForDotEnv)
513
+ ROOT_URL=$(printf %s "https://$(printf %s "pan-test-app-review-$([ -n "$CI_MERGE_REQUEST_IID" ] && echo "mr$CI_MERGE_REQUEST_IID" || { [ -n "$CI_COMMIT_REF_SLUG" ] && echo "$CI_COMMIT_REF_SLUG" || echo "unknown"; })-my-app-$CL_review_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | escapeForDotEnv)
514
+ HOSTNAME_INTERNAL=$(printf %s "$(printf %s "pan-test-app-review-$([ -n "$CI_MERGE_REQUEST_IID" ] && echo "mr$CI_MERGE_REQUEST_IID" || { [ -n "$CI_COMMIT_REF_SLUG" ] && echo "$CI_COMMIT_REF_SLUG" || echo "unknown"; })-my-app-$CL_review_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | escapeForDotEnv)
515
+ ROOT_URL_INTERNAL=$(printf %s "https://$(printf %s "pan-test-app-review-$([ -n "$CI_MERGE_REQUEST_IID" ] && echo "mr$CI_MERGE_REQUEST_IID" || { [ -n "$CI_COMMIT_REF_SLUG" ] && echo "$CI_COMMIT_REF_SLUG" || echo "unknown"; })-my-app-$CL_review_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | escapeForDotEnv)
516
+ DEPLOY_CLOUD_RUN_PROJECT_ID=my-project-id
517
+ DEPLOY_CLOUD_RUN_REGION=europe-west6
518
+ MY_SECRET=$(printf %s "$CL_review_my_app_MY_SECRET" | escapeForDotEnv)
519
+ MY_REVIEW_SECRET=$(printf %s "$CL_review_my_app_MY_REVIEW_SECRET" | escapeForDotEnv)
520
+ GCLOUD_DEPLOY_credentialsKey=$(printf %s "$CL_review_my_app_GCLOUD_DEPLOY_credentialsKey" | escapeForDotEnv)
521
+ GCLOUD_RUN_canonicalHostSuffix=$(printf %s "$CL_review_my_app_GCLOUD_RUN_canonicalHostSuffix" | escapeForDotEnv)
522
+ _ALL_ENV_VAR_KEYS=["ENV_SHORT","APP_DIR","ENV_TYPE","BUILD_INFO_BUILD_ID","BUILD_INFO_BUILD_TIME","BUILD_INFO_CURRENT_VERSION","HOSTNAME","ROOT_URL","HOSTNAME_INTERNAL","ROOT_URL_INTERNAL","DEPLOY_CLOUD_RUN_PROJECT_ID","DEPLOY_CLOUD_RUN_REGION","MY_SECRET","MY_REVIEW_SECRET","GCLOUD_DEPLOY_credentialsKey","GCLOUD_RUN_canonicalHostSuffix"]
523
+ EOF
524
+ - collapseable_section_end "write-dotenv-my-app"
525
+ - echo '{"id":"$(git describe --tags 2>/dev/null || git rev-parse HEAD)","time":"$CI_JOB_STARTED_AT"}' > app/__build_info.json
526
+ - collapseable_section_start "nodeinstall" "Ensure node version"
527
+ - if [ -f ~/.nvm/nvm.sh ]; then source ~/.nvm/nvm.sh; fi
528
+ - if command -v nvm &> /dev/null && [ -f ./.nvmrc ]; then nvm install; fi
529
+ - collapseable_section_end "nodeinstall"
530
+ - cd app
531
+ - collapseable_section_start "nodeinstall" "Ensure node version"
532
+ - if [ -f ~/.nvm/nvm.sh ]; then source ~/.nvm/nvm.sh; fi
533
+ - if command -v nvm &> /dev/null && [ -f ./.nvmrc ]; then nvm install; fi
534
+ - collapseable_section_end "nodeinstall"
535
+ - collapseable_section_start "yarninstall" "Yarn install"
536
+ - yarn install --immutable
537
+ - collapseable_section_end "yarninstall"
538
+ - yarn build
539
+ cache:
540
+ - key: app-yarn
541
+ policy: pull-push
542
+ paths:
543
+ - app/.yarn
544
+ - key: app-node-modules
545
+ policy: pull-push
546
+ paths:
547
+ - app/node_modules
548
+ artifacts:
549
+ paths:
550
+ - app/__build_info.json
551
+ - app/.next
552
+ - app/dist
553
+ exclude:
554
+ - app/.env
555
+ expire_in: 1 day
556
+ when: always
557
+ reports: {}
558
+ rules:
559
+ - if: $CI_MERGE_REQUEST_ID
560
+ needs: []
561
+ retry: *a1
562
+ interruptible: true
563
+ 'my-app ๐Ÿ”จ docker | review ':
564
+ stage: build
565
+ image: path/to/docker/docker-build:the-version
566
+ services:
567
+ - name: docker:24.0.6-dind
568
+ command:
569
+ - --tls=false
570
+ - --registry-mirror=https://mirror.gcr.io
571
+ variables:
572
+ DOCKER_HOST: tcp://0.0.0.0:2375
573
+ DOCKER_TLS_CERTDIR: ''
574
+ DOCKER_DRIVER: overlay2
575
+ DOCKER_BUILDKIT: '1'
576
+ KUBERNETES_CPU_REQUEST: '0.45'
577
+ KUBERNETES_MEMORY_REQUEST: 1Gi
578
+ KUBERNETES_MEMORY_LIMIT: 2Gi
579
+ script:
580
+ - collapseable_section_start "injectvars" "Injecting variables"
581
+ - export APP_DIR="app"
582
+ - export DOCKER_BUILD_CONTEXT="."
583
+ - export DOCKER_REGISTRY="europe-west6-docker.pkg.dev"
584
+ - export DOCKER_IMAGE="europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/review/my-app/$([ -n "$CI_MERGE_REQUEST_IID" ] && echo "mr$CI_MERGE_REQUEST_IID" || { [ -n "$CI_COMMIT_REF_SLUG" ] && echo "$CI_COMMIT_REF_SLUG" || echo "unknown"; })"
585
+ - export DOCKER_CACHE_IMAGE="europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/caches/my-app"
586
+ - export DOCKER_IMAGE_TAG="$CI_COMMIT_SHA"
587
+ - |-
588
+ export DOCKER_COPY_AND_INSTALL_APP="COPY --chown=node:node $APP_DIR .
589
+ RUN yarn plugin import workspace-tools
590
+ RUN yarn workspaces focus --production && yarn rebuild"
591
+ - |-
592
+ export DOCKER_COPY_WORKSPACE_FILES="COPY --chown=node:node app/package.json /app/app/package.json
593
+ COPY --chown=node:node app/yarn.lock /app/app/yarn.lock
594
+ COPY --chown=node:node .yarnrc.yml /app/.yarnrc.yml
595
+ COPY --chown=node:node .yarn /app/.yarn"
596
+ - collapseable_section_end "injectvars"
597
+ - ensureNodeDockerfile
598
+ - collapseable_section_start "docker-login" "Docker Login"
599
+ - gcloud auth activate-service-account --key-file=<(echo "$CL_review_my_app_GCLOUD_DEPLOY_credentialsKey")
600
+ - gcloud auth configure-docker europe-west6-docker.pkg.dev
601
+ - collapseable_section_end "docker-login"
602
+ - collapseable_section_start "docker-build" "Docker build"
603
+ - docker build --network host --cache-from $DOCKER_CACHE_IMAGE --tag $DOCKER_IMAGE:$DOCKER_IMAGE_TAG -f $APP_DIR/Dockerfile $DOCKER_BUILD_CONTEXT --build-arg BUILDKIT_INLINE_CACHE=1
604
+ - collapseable_section_end "docker-build"
605
+ - collapseable_section_start "docker-push" "Docker push and tag"
606
+ - docker push $DOCKER_IMAGE:$DOCKER_IMAGE_TAG
607
+ - docker tag $DOCKER_IMAGE:$DOCKER_IMAGE_TAG $DOCKER_CACHE_IMAGE
608
+ - docker push $DOCKER_CACHE_IMAGE
609
+ - collapseable_section_end "docker-push"
610
+ cache:
611
+ - key: app-yarn
612
+ policy: pull
613
+ paths:
614
+ - app/.yarn
615
+ rules:
616
+ - if: $CI_MERGE_REQUEST_ID
617
+ needs:
618
+ - 'my-app ๐Ÿ”จ app | review '
619
+ retry: *a1
620
+ interruptible: true
621
+ 'my-app ๐Ÿงพ sbom | review ':
622
+ stage: build
623
+ image: aquasec/trivy:0.38.3
624
+ variables: {}
625
+ script:
626
+ - collapseable_section_start "injectvars" "Injecting variables"
627
+ - collapseable_section_end "injectvars"
628
+ - trivy fs --quiet --format cyclonedx --output "__sbom.json" app
629
+ artifacts:
630
+ paths:
631
+ - __sbom.json
632
+ rules:
633
+ - if: $CI_MERGE_REQUEST_ID
634
+ needs: []
635
+ retry: *a1
636
+ interruptible: true
637
+ allow_failure: true
638
+ 'my-app ๐Ÿš€ Deploy | review ':
639
+ stage: deploy review
640
+ image: path/to/docker/gcloud:the-version
641
+ variables:
642
+ KUBERNETES_CPU_REQUEST: '0.22'
643
+ KUBERNETES_MEMORY_REQUEST: 200Mi
644
+ KUBERNETES_MEMORY_LIMIT: 400Mi
645
+ script:
646
+ - collapseable_section_start "injectvars" "Injecting variables"
647
+ - export ENV_SHORT="review"
648
+ - export APP_DIR="app"
649
+ - export ENV_TYPE="review"
650
+ - export BUILD_INFO_BUILD_ID="$(git describe --tags 2>/dev/null || git rev-parse HEAD)"
651
+ - export BUILD_INFO_BUILD_TIME="$CI_JOB_STARTED_AT"
652
+ - export BUILD_INFO_CURRENT_VERSION="$(tag=$(git ls-remote origin "refs/tags/v*[0-9]" 2>/dev/null | cut -f 2- | sort -V | tail -1 | sed 's/refs\\/tags\\/v//'); [ -z "$tag" ] && echo "0.0.0" || echo "$tag")"
653
+ - export HOSTNAME="$(printf %s "pan-test-app-review-$([ -n "$CI_MERGE_REQUEST_IID" ] && echo "mr$CI_MERGE_REQUEST_IID" || { [ -n "$CI_COMMIT_REF_SLUG" ] && echo "$CI_COMMIT_REF_SLUG" || echo "unknown"; })-my-app-$CL_review_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
654
+ - export ROOT_URL="https://$(printf %s "pan-test-app-review-$([ -n "$CI_MERGE_REQUEST_IID" ] && echo "mr$CI_MERGE_REQUEST_IID" || { [ -n "$CI_COMMIT_REF_SLUG" ] && echo "$CI_COMMIT_REF_SLUG" || echo "unknown"; })-my-app-$CL_review_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
655
+ - export HOSTNAME_INTERNAL="$(printf %s "pan-test-app-review-$([ -n "$CI_MERGE_REQUEST_IID" ] && echo "mr$CI_MERGE_REQUEST_IID" || { [ -n "$CI_COMMIT_REF_SLUG" ] && echo "$CI_COMMIT_REF_SLUG" || echo "unknown"; })-my-app-$CL_review_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
656
+ - export ROOT_URL_INTERNAL="https://$(printf %s "pan-test-app-review-$([ -n "$CI_MERGE_REQUEST_IID" ] && echo "mr$CI_MERGE_REQUEST_IID" || { [ -n "$CI_COMMIT_REF_SLUG" ] && echo "$CI_COMMIT_REF_SLUG" || echo "unknown"; })-my-app-$CL_review_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
657
+ - export DEPLOY_CLOUD_RUN_PROJECT_ID="my-project-id"
658
+ - export DEPLOY_CLOUD_RUN_REGION="europe-west6"
659
+ - export MY_SECRET="$CL_review_my_app_MY_SECRET"
660
+ - export MY_REVIEW_SECRET="$CL_review_my_app_MY_REVIEW_SECRET"
661
+ - export GCLOUD_DEPLOY_credentialsKey="$CL_review_my_app_GCLOUD_DEPLOY_credentialsKey"
662
+ - export GCLOUD_RUN_canonicalHostSuffix="$CL_review_my_app_GCLOUD_RUN_canonicalHostSuffix"
663
+ - export _ALL_ENV_VAR_KEYS="[\\"ENV_SHORT\\",\\"APP_DIR\\",\\"ENV_TYPE\\",\\"BUILD_INFO_BUILD_ID\\",\\"BUILD_INFO_BUILD_TIME\\",\\"BUILD_INFO_CURRENT_VERSION\\",\\"HOSTNAME\\",\\"ROOT_URL\\",\\"HOSTNAME_INTERNAL\\",\\"ROOT_URL_INTERNAL\\",\\"DEPLOY_CLOUD_RUN_PROJECT_ID\\",\\"DEPLOY_CLOUD_RUN_REGION\\",\\"MY_SECRET\\",\\"MY_REVIEW_SECRET\\",\\"GCLOUD_DEPLOY_credentialsKey\\",\\"GCLOUD_RUN_canonicalHostSuffix\\"]"
664
+ - export DOCKER_REGISTRY="europe-west6-docker.pkg.dev"
665
+ - export DOCKER_IMAGE="europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/review/my-app/$([ -n "$CI_MERGE_REQUEST_IID" ] && echo "mr$CI_MERGE_REQUEST_IID" || { [ -n "$CI_COMMIT_REF_SLUG" ] && echo "$CI_COMMIT_REF_SLUG" || echo "unknown"; })"
666
+ - export DOCKER_CACHE_IMAGE="europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/caches/my-app"
667
+ - export DOCKER_IMAGE_TAG="$CI_COMMIT_SHA"
668
+ - export CLOUDSDK_CORE_DISABLE_PROMPTS="1"
669
+ - collapseable_section_end "injectvars"
670
+ - collapseable_section_start "prepare" "Prepare..."
671
+ - gcloud auth activate-service-account --key-file=<(echo "$CL_review_my_app_GCLOUD_DEPLOY_credentialsKey")
672
+ - export GCLOUD_PROJECT_NUMBER=$(gcloud projects describe my-project-id --format="value(projectNumber)")
673
+ - 'echo "GCLOUD_PROJECT_NUMBER: $GCLOUD_PROJECT_NUMBER"'
674
+ - collapseable_section_end "prepare"
675
+ - collapseable_section_start "writeenvvars" "Write env vars to file"
676
+ - |
677
+ cat > ____envvars.yaml <<EOF
678
+ ENV_SHORT: |-
679
+ review
680
+ APP_DIR: |-
681
+ app
682
+ ENV_TYPE: |-
683
+ review
684
+ BUILD_INFO_BUILD_ID: |-
685
+ $(printf %s "$(git describe --tags 2>/dev/null || git rev-parse HEAD)" | sed '1!s/^/ /')
686
+ BUILD_INFO_BUILD_TIME: |-
687
+ $(printf %s "$CI_JOB_STARTED_AT" | sed '1!s/^/ /')
688
+ BUILD_INFO_CURRENT_VERSION: |-
689
+ $(printf %s "$(tag=$(git ls-remote origin "refs/tags/v*[0-9]" 2>/dev/null | cut -f 2- | sort -V | tail -1 | sed 's/refs\\/tags\\/v//'); [ -z "$tag" ] && echo "0.0.0" || echo "$tag")" | sed '1!s/^/ /')
690
+ HOSTNAME: |-
691
+ $(printf %s "$(printf %s "pan-test-app-review-$([ -n "$CI_MERGE_REQUEST_IID" ] && echo "mr$CI_MERGE_REQUEST_IID" || { [ -n "$CI_COMMIT_REF_SLUG" ] && echo "$CI_COMMIT_REF_SLUG" || echo "unknown"; })-my-app-$CL_review_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | sed '1!s/^/ /')
692
+ ROOT_URL: |-
693
+ $(printf %s "https://$(printf %s "pan-test-app-review-$([ -n "$CI_MERGE_REQUEST_IID" ] && echo "mr$CI_MERGE_REQUEST_IID" || { [ -n "$CI_COMMIT_REF_SLUG" ] && echo "$CI_COMMIT_REF_SLUG" || echo "unknown"; })-my-app-$CL_review_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | sed '1!s/^/ /')
694
+ HOSTNAME_INTERNAL: |-
695
+ $(printf %s "$(printf %s "pan-test-app-review-$([ -n "$CI_MERGE_REQUEST_IID" ] && echo "mr$CI_MERGE_REQUEST_IID" || { [ -n "$CI_COMMIT_REF_SLUG" ] && echo "$CI_COMMIT_REF_SLUG" || echo "unknown"; })-my-app-$CL_review_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | sed '1!s/^/ /')
696
+ ROOT_URL_INTERNAL: |-
697
+ $(printf %s "https://$(printf %s "pan-test-app-review-$([ -n "$CI_MERGE_REQUEST_IID" ] && echo "mr$CI_MERGE_REQUEST_IID" || { [ -n "$CI_COMMIT_REF_SLUG" ] && echo "$CI_COMMIT_REF_SLUG" || echo "unknown"; })-my-app-$CL_review_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | sed '1!s/^/ /')
698
+ DEPLOY_CLOUD_RUN_PROJECT_ID: |-
699
+ my-project-id
700
+ DEPLOY_CLOUD_RUN_REGION: |-
701
+ europe-west6
702
+ MY_SECRET: |-
703
+ $(printf %s "$CL_review_my_app_MY_SECRET" | sed '1!s/^/ /')
704
+ MY_REVIEW_SECRET: |-
705
+ $(printf %s "$CL_review_my_app_MY_REVIEW_SECRET" | sed '1!s/^/ /')
706
+ GCLOUD_RUN_canonicalHostSuffix: |-
707
+ $(printf %s "$CL_review_my_app_GCLOUD_RUN_canonicalHostSuffix" | sed '1!s/^/ /')
708
+ _ALL_ENV_VAR_KEYS: |-
709
+ ["ENV_SHORT","APP_DIR","ENV_TYPE","BUILD_INFO_BUILD_ID","BUILD_INFO_BUILD_TIME","BUILD_INFO_CURRENT_VERSION","HOSTNAME","ROOT_URL","HOSTNAME_INTERNAL","ROOT_URL_INTERNAL","DEPLOY_CLOUD_RUN_PROJECT_ID","DEPLOY_CLOUD_RUN_REGION","MY_SECRET","MY_REVIEW_SECRET","GCLOUD_DEPLOY_credentialsKey","GCLOUD_RUN_canonicalHostSuffix"]
710
+
711
+ EOF
712
+ - collapseable_section_end "writeenvvars"
713
+ - collapseable_section_start "deploy" "Deploy to cloud run"
714
+ - gcloud run deploy $(printf %s "pan-test-app-review-$([ -n "$CI_MERGE_REQUEST_IID" ] && echo "mr$CI_MERGE_REQUEST_IID" || { [ -n "$CI_COMMIT_REF_SLUG" ] && echo "$CI_COMMIT_REF_SLUG" || echo "unknown"; })-my-app" | awk '{print tolower($0)}') --command="yarn,start" --image=europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/review/my-app/$([ -n "$CI_MERGE_REQUEST_IID" ] && echo "mr$CI_MERGE_REQUEST_IID" || { [ -n "$CI_COMMIT_REF_SLUG" ] && echo "$CI_COMMIT_REF_SLUG" || echo "unknown"; }):$DOCKER_IMAGE_TAG --project=my-project-id --region=europe-west6 --labels=customer-name=pan,component-name=my-app,app-name=test-app,env-type=review,env-name=review,build-type=node,cloud-run-service-name=$(printf %s "pan-test-app-review-$([ -n "$CI_MERGE_REQUEST_IID" ] && echo "mr$CI_MERGE_REQUEST_IID" || { [ -n "$CI_COMMIT_REF_SLUG" ] && echo "$CI_COMMIT_REF_SLUG" || echo "unknown"; })-my-app" | awk '{print tolower($0)}') --env-vars-file=____envvars.yaml --min-instances=0 --max-instances=100 --cpu-throttling --allow-unauthenticated --ingress=all --cpu-boost
715
+ - collapseable_section_end "deploy"
716
+ - collapseable_section_start "cleanup" "Cleanup"
717
+ - gcloud run revisions list --project=my-project-id --region=europe-west6 --service=$(printf %s "pan-test-app-review-$([ -n "$CI_MERGE_REQUEST_IID" ] && echo "mr$CI_MERGE_REQUEST_IID" || { [ -n "$CI_COMMIT_REF_SLUG" ] && echo "$CI_COMMIT_REF_SLUG" || echo "unknown"; })-my-app" | awk '{print tolower($0)}') --limit=unlimited --sort-by=metadata.creationTimestamp --format="value(name)" --filter='(status.conditions.status=False OR status.conditions.status=Unknown)' | while read -r revisionname; do gcloud run revisions delete --project=my-project-id --region=europe-west6 --quiet $revisionname ; done
718
+ - gcloud artifacts docker images list europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/review/my-app/$([ -n "$CI_MERGE_REQUEST_IID" ] && echo "mr$CI_MERGE_REQUEST_IID" || { [ -n "$CI_COMMIT_REF_SLUG" ] && echo "$CI_COMMIT_REF_SLUG" || echo "unknown"; }) --sort-by=~CREATE_TIME --format="value(version)" | tail -n +2 | while read -r version; do gcloud artifacts docker images delete europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/review/my-app/$([ -n "$CI_MERGE_REQUEST_IID" ] && echo "mr$CI_MERGE_REQUEST_IID" || { [ -n "$CI_COMMIT_REF_SLUG" ] && echo "$CI_COMMIT_REF_SLUG" || echo "unknown"; })@$version --quiet --delete-tags; done
719
+ - gcloud artifacts docker images list europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/caches/my-app --sort-by=~CREATE_TIME --format="value(version)" | tail -n +2 | while read -r version; do gcloud artifacts docker images delete europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/caches/my-app@$version --quiet --delete-tags; done
720
+ - set +e
721
+ - gcloud artifacts docker images delete europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/review/my-app --quiet --delete-tags
722
+ - set -e
723
+ - collapseable_section_end "cleanup"
724
+ - echo 'Uploading SBOM to Dependency Track'
725
+ - /dtrackuploader https://dep.panter.swiss/ "$DT_KEY_PROD" upload "pan-test-app/my-app" "$ROOT_URL" "__sbom.json" vex.json || true
726
+ - echo "CL_GITLAB_ENVIRONMENT_URL=$ROOT_URL" >> gitlab_environment.env
727
+ environment:
728
+ name: review/$CI_COMMIT_REF_NAME/my-app
729
+ url: $CL_GITLAB_ENVIRONMENT_URL
730
+ on_stop: 'my-app ๐Ÿ›‘ Stop โš ๏ธ | review '
731
+ auto_stop_in: 1 week
732
+ artifacts:
733
+ reports:
734
+ dotenv: gitlab_environment.env
735
+ rules:
736
+ - when: on_success
737
+ if: $CI_MERGE_REQUEST_ID
738
+ needs:
739
+ - job: my-app ๐Ÿ‘ฎ lint
740
+ artifacts: false
741
+ - job: 'my-app ๐Ÿ”จ app | review '
742
+ artifacts: false
743
+ - job: 'my-app ๐Ÿ”จ docker | review '
744
+ artifacts: false
745
+ - job: my-app ๐Ÿงช test
746
+ artifacts: false
747
+ - job: 'my-app ๐Ÿงพ sbom | review '
748
+ artifacts: true
749
+ - job: my-app ๐Ÿ›ก audit
750
+ artifacts: false
751
+ retry: *a1
752
+ interruptible: true
753
+ allow_failure: false
754
+ 'my-app ๐Ÿ›‘ Stop โš ๏ธ | review ':
755
+ stage: stop review
756
+ image: path/to/docker/gcloud:the-version
757
+ variables:
758
+ KUBERNETES_CPU_REQUEST: '0.22'
759
+ KUBERNETES_MEMORY_REQUEST: 200Mi
760
+ KUBERNETES_MEMORY_LIMIT: 400Mi
761
+ GIT_STRATEGY: none
762
+ script:
763
+ - collapseable_section_start "injectvars" "Injecting variables"
764
+ - export CLOUDSDK_CORE_DISABLE_PROMPTS="1"
765
+ - collapseable_section_end "injectvars"
766
+ - set +e
767
+ - gcloud auth activate-service-account --key-file=<(echo "$CL_review_my_app_GCLOUD_DEPLOY_credentialsKey")
768
+ - gcloud run services delete $(printf %s "pan-test-app-review-$([ -n "$CI_MERGE_REQUEST_IID" ] && echo "mr$CI_MERGE_REQUEST_IID" || { [ -n "$CI_COMMIT_REF_SLUG" ] && echo "$CI_COMMIT_REF_SLUG" || echo "unknown"; })-my-app" | awk '{print tolower($0)}') --project=my-project-id --region=europe-west6
769
+ - gcloud artifacts docker images delete europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/review/my-app/$([ -n "$CI_MERGE_REQUEST_IID" ] && echo "mr$CI_MERGE_REQUEST_IID" || { [ -n "$CI_COMMIT_REF_SLUG" ] && echo "$CI_COMMIT_REF_SLUG" || echo "unknown"; }) --quiet --delete-tags
770
+ - gcloud artifacts docker images list europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/caches/my-app --sort-by=~CREATE_TIME --format="value(version)" | tail -n +2 | while read -r version; do gcloud artifacts docker images delete europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/caches/my-app@$version --quiet --delete-tags; done
771
+ - set +e
772
+ - gcloud artifacts docker images delete europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/review/my-app --quiet --delete-tags
773
+ - set -e
774
+ - echo 'Disabling component in Dependency Track'
775
+ - /dtrackuploader https://dep.panter.swiss/ "$DT_KEY_PROD" disable "pan-test-app/my-app" "$CI_ENVIRONMENT_URL" || true
776
+ - set -e
777
+ environment:
778
+ name: review/$CI_COMMIT_REF_NAME/my-app
779
+ action: stop
780
+ rules:
781
+ - if: $CI_COMMIT_BRANCH =~ /^[0-9]+\\.([0-9]+|x)\\.x$/
782
+ when: on_success
783
+ - when: manual
784
+ if: $CI_MERGE_REQUEST_ID
785
+ needs: []
786
+ retry: *a1
787
+ interruptible: true
788
+ allow_failure: true
789
+ 'my-app ๐Ÿ”จ app | stage ':
790
+ stage: build
791
+ image: path/to/docker/jobs-default:the-version
792
+ variables:
793
+ KUBERNETES_CPU_REQUEST: '0.45'
794
+ KUBERNETES_MEMORY_REQUEST: 1Gi
795
+ KUBERNETES_MEMORY_LIMIT: 4Gi
796
+ script:
797
+ - collapseable_section_start "injectvars" "Injecting variables"
798
+ - export ENV_SHORT="stage"
799
+ - export APP_DIR="app"
800
+ - export ENV_TYPE="stage"
801
+ - export BUILD_INFO_BUILD_ID="$(git describe --tags 2>/dev/null || git rev-parse HEAD)"
802
+ - export BUILD_INFO_BUILD_TIME="$CI_JOB_STARTED_AT"
803
+ - export BUILD_INFO_CURRENT_VERSION="$(tag=$(git ls-remote origin "refs/tags/v*[0-9]" 2>/dev/null | cut -f 2- | sort -V | tail -1 | sed 's/refs\\/tags\\/v//'); [ -z "$tag" ] && echo "0.0.0" || echo "$tag")"
804
+ - export HOSTNAME="$(printf %s "pan-test-app-stage-my-app-$CL_stage_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
805
+ - export ROOT_URL="https://$(printf %s "pan-test-app-stage-my-app-$CL_stage_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
806
+ - export HOSTNAME_INTERNAL="$(printf %s "pan-test-app-stage-my-app-$CL_stage_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
807
+ - export ROOT_URL_INTERNAL="https://$(printf %s "pan-test-app-stage-my-app-$CL_stage_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
808
+ - export DEPLOY_CLOUD_RUN_PROJECT_ID="my-project-id"
809
+ - export DEPLOY_CLOUD_RUN_REGION="europe-west6"
810
+ - export MY_SECRET="$CL_stage_my_app_MY_SECRET"
811
+ - export GCLOUD_DEPLOY_credentialsKey="$CL_stage_my_app_GCLOUD_DEPLOY_credentialsKey"
812
+ - export GCLOUD_RUN_canonicalHostSuffix="$CL_stage_my_app_GCLOUD_RUN_canonicalHostSuffix"
813
+ - export _ALL_ENV_VAR_KEYS="[\\"ENV_SHORT\\",\\"APP_DIR\\",\\"ENV_TYPE\\",\\"BUILD_INFO_BUILD_ID\\",\\"BUILD_INFO_BUILD_TIME\\",\\"BUILD_INFO_CURRENT_VERSION\\",\\"HOSTNAME\\",\\"ROOT_URL\\",\\"HOSTNAME_INTERNAL\\",\\"ROOT_URL_INTERNAL\\",\\"DEPLOY_CLOUD_RUN_PROJECT_ID\\",\\"DEPLOY_CLOUD_RUN_REGION\\",\\"MY_SECRET\\",\\"GCLOUD_DEPLOY_credentialsKey\\",\\"GCLOUD_RUN_canonicalHostSuffix\\"]"
814
+ - collapseable_section_end "injectvars"
815
+ - collapseable_section_start "write-dotenv-my-app" "write dot env for my-app"
816
+ - |-
817
+ cat <<EOF > app/.env
818
+ ENV_SHORT=stage
819
+ APP_DIR=app
820
+ ENV_TYPE=stage
821
+ HOSTNAME=$(printf %s "$(printf %s "pan-test-app-stage-my-app-$CL_stage_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | escapeForDotEnv)
822
+ ROOT_URL=$(printf %s "https://$(printf %s "pan-test-app-stage-my-app-$CL_stage_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | escapeForDotEnv)
823
+ HOSTNAME_INTERNAL=$(printf %s "$(printf %s "pan-test-app-stage-my-app-$CL_stage_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | escapeForDotEnv)
824
+ ROOT_URL_INTERNAL=$(printf %s "https://$(printf %s "pan-test-app-stage-my-app-$CL_stage_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | escapeForDotEnv)
825
+ DEPLOY_CLOUD_RUN_PROJECT_ID=my-project-id
826
+ DEPLOY_CLOUD_RUN_REGION=europe-west6
827
+ MY_SECRET=$(printf %s "$CL_stage_my_app_MY_SECRET" | escapeForDotEnv)
828
+ GCLOUD_DEPLOY_credentialsKey=$(printf %s "$CL_stage_my_app_GCLOUD_DEPLOY_credentialsKey" | escapeForDotEnv)
829
+ GCLOUD_RUN_canonicalHostSuffix=$(printf %s "$CL_stage_my_app_GCLOUD_RUN_canonicalHostSuffix" | escapeForDotEnv)
830
+ _ALL_ENV_VAR_KEYS=["ENV_SHORT","APP_DIR","ENV_TYPE","BUILD_INFO_BUILD_ID","BUILD_INFO_BUILD_TIME","BUILD_INFO_CURRENT_VERSION","HOSTNAME","ROOT_URL","HOSTNAME_INTERNAL","ROOT_URL_INTERNAL","DEPLOY_CLOUD_RUN_PROJECT_ID","DEPLOY_CLOUD_RUN_REGION","MY_SECRET","GCLOUD_DEPLOY_credentialsKey","GCLOUD_RUN_canonicalHostSuffix"]
831
+ EOF
832
+ - collapseable_section_end "write-dotenv-my-app"
833
+ - echo '{"id":"$(git describe --tags 2>/dev/null || git rev-parse HEAD)","time":"$CI_JOB_STARTED_AT"}' > app/__build_info.json
834
+ - collapseable_section_start "nodeinstall" "Ensure node version"
835
+ - if [ -f ~/.nvm/nvm.sh ]; then source ~/.nvm/nvm.sh; fi
836
+ - if command -v nvm &> /dev/null && [ -f ./.nvmrc ]; then nvm install; fi
837
+ - collapseable_section_end "nodeinstall"
838
+ - cd app
839
+ - collapseable_section_start "nodeinstall" "Ensure node version"
840
+ - if [ -f ~/.nvm/nvm.sh ]; then source ~/.nvm/nvm.sh; fi
841
+ - if command -v nvm &> /dev/null && [ -f ./.nvmrc ]; then nvm install; fi
842
+ - collapseable_section_end "nodeinstall"
843
+ - collapseable_section_start "yarninstall" "Yarn install"
844
+ - yarn install --immutable
845
+ - collapseable_section_end "yarninstall"
846
+ - yarn build
847
+ cache:
848
+ - key: app-yarn
849
+ policy: pull-push
850
+ paths:
851
+ - app/.yarn
852
+ - key: app-node-modules
853
+ policy: pull-push
854
+ paths:
855
+ - app/node_modules
856
+ artifacts:
857
+ paths:
858
+ - app/__build_info.json
859
+ - app/.next
860
+ - app/dist
861
+ exclude:
862
+ - app/.env
863
+ expire_in: 1 day
864
+ when: always
865
+ reports: {}
866
+ rules:
867
+ - if: $CI_COMMIT_TAG
868
+ needs: []
869
+ retry: *a1
870
+ interruptible: true
871
+ 'my-app ๐Ÿ”จ docker | stage ':
872
+ stage: build
873
+ image: path/to/docker/docker-build:the-version
874
+ services:
875
+ - name: docker:24.0.6-dind
876
+ command:
877
+ - --tls=false
878
+ - --registry-mirror=https://mirror.gcr.io
879
+ variables:
880
+ DOCKER_HOST: tcp://0.0.0.0:2375
881
+ DOCKER_TLS_CERTDIR: ''
882
+ DOCKER_DRIVER: overlay2
883
+ DOCKER_BUILDKIT: '1'
884
+ KUBERNETES_CPU_REQUEST: '0.45'
885
+ KUBERNETES_MEMORY_REQUEST: 1Gi
886
+ KUBERNETES_MEMORY_LIMIT: 2Gi
887
+ script:
888
+ - collapseable_section_start "injectvars" "Injecting variables"
889
+ - export APP_DIR="app"
890
+ - export DOCKER_BUILD_CONTEXT="."
891
+ - export DOCKER_REGISTRY="europe-west6-docker.pkg.dev"
892
+ - export DOCKER_IMAGE="europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/stage/my-app"
893
+ - export DOCKER_CACHE_IMAGE="europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/caches/my-app"
894
+ - export DOCKER_IMAGE_TAG="$CI_COMMIT_SHA"
895
+ - |-
896
+ export DOCKER_COPY_AND_INSTALL_APP="COPY --chown=node:node $APP_DIR .
897
+ RUN yarn plugin import workspace-tools
898
+ RUN yarn workspaces focus --production && yarn rebuild"
899
+ - |-
900
+ export DOCKER_COPY_WORKSPACE_FILES="COPY --chown=node:node app/package.json /app/app/package.json
901
+ COPY --chown=node:node app/yarn.lock /app/app/yarn.lock
902
+ COPY --chown=node:node .yarnrc.yml /app/.yarnrc.yml
903
+ COPY --chown=node:node .yarn /app/.yarn"
904
+ - collapseable_section_end "injectvars"
905
+ - ensureNodeDockerfile
906
+ - collapseable_section_start "docker-login" "Docker Login"
907
+ - gcloud auth activate-service-account --key-file=<(echo "$CL_stage_my_app_GCLOUD_DEPLOY_credentialsKey")
908
+ - gcloud auth configure-docker europe-west6-docker.pkg.dev
909
+ - collapseable_section_end "docker-login"
910
+ - collapseable_section_start "docker-build" "Docker build"
911
+ - docker build --network host --cache-from $DOCKER_CACHE_IMAGE --tag $DOCKER_IMAGE:$DOCKER_IMAGE_TAG -f $APP_DIR/Dockerfile $DOCKER_BUILD_CONTEXT --build-arg BUILDKIT_INLINE_CACHE=1
912
+ - collapseable_section_end "docker-build"
913
+ - collapseable_section_start "docker-push" "Docker push and tag"
914
+ - docker push $DOCKER_IMAGE:$DOCKER_IMAGE_TAG
915
+ - docker tag $DOCKER_IMAGE:$DOCKER_IMAGE_TAG $DOCKER_CACHE_IMAGE
916
+ - docker push $DOCKER_CACHE_IMAGE
917
+ - collapseable_section_end "docker-push"
918
+ cache:
919
+ - key: app-yarn
920
+ policy: pull
921
+ paths:
922
+ - app/.yarn
923
+ rules:
924
+ - if: $CI_COMMIT_TAG
925
+ needs:
926
+ - 'my-app ๐Ÿ”จ app | stage '
927
+ retry: *a1
928
+ interruptible: true
929
+ 'my-app ๐Ÿงพ sbom | stage ':
930
+ stage: build
931
+ image: aquasec/trivy:0.38.3
932
+ variables: {}
933
+ script:
934
+ - collapseable_section_start "injectvars" "Injecting variables"
935
+ - collapseable_section_end "injectvars"
936
+ - trivy fs --quiet --format cyclonedx --output "__sbom.json" app
937
+ artifacts:
938
+ paths:
939
+ - __sbom.json
940
+ rules:
941
+ - if: $CI_COMMIT_TAG
942
+ needs: []
943
+ retry: *a1
944
+ interruptible: true
945
+ allow_failure: true
946
+ 'my-app ๐Ÿš€ Deploy | stage ':
947
+ stage: deploy stage
948
+ image: path/to/docker/gcloud:the-version
949
+ variables:
950
+ KUBERNETES_CPU_REQUEST: '0.22'
951
+ KUBERNETES_MEMORY_REQUEST: 200Mi
952
+ KUBERNETES_MEMORY_LIMIT: 400Mi
953
+ script:
954
+ - collapseable_section_start "injectvars" "Injecting variables"
955
+ - export ENV_SHORT="stage"
956
+ - export APP_DIR="app"
957
+ - export ENV_TYPE="stage"
958
+ - export BUILD_INFO_BUILD_ID="$(git describe --tags 2>/dev/null || git rev-parse HEAD)"
959
+ - export BUILD_INFO_BUILD_TIME="$CI_JOB_STARTED_AT"
960
+ - export BUILD_INFO_CURRENT_VERSION="$(tag=$(git ls-remote origin "refs/tags/v*[0-9]" 2>/dev/null | cut -f 2- | sort -V | tail -1 | sed 's/refs\\/tags\\/v//'); [ -z "$tag" ] && echo "0.0.0" || echo "$tag")"
961
+ - export HOSTNAME="$(printf %s "pan-test-app-stage-my-app-$CL_stage_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
962
+ - export ROOT_URL="https://$(printf %s "pan-test-app-stage-my-app-$CL_stage_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
963
+ - export HOSTNAME_INTERNAL="$(printf %s "pan-test-app-stage-my-app-$CL_stage_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
964
+ - export ROOT_URL_INTERNAL="https://$(printf %s "pan-test-app-stage-my-app-$CL_stage_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
965
+ - export DEPLOY_CLOUD_RUN_PROJECT_ID="my-project-id"
966
+ - export DEPLOY_CLOUD_RUN_REGION="europe-west6"
967
+ - export MY_SECRET="$CL_stage_my_app_MY_SECRET"
968
+ - export GCLOUD_DEPLOY_credentialsKey="$CL_stage_my_app_GCLOUD_DEPLOY_credentialsKey"
969
+ - export GCLOUD_RUN_canonicalHostSuffix="$CL_stage_my_app_GCLOUD_RUN_canonicalHostSuffix"
970
+ - export _ALL_ENV_VAR_KEYS="[\\"ENV_SHORT\\",\\"APP_DIR\\",\\"ENV_TYPE\\",\\"BUILD_INFO_BUILD_ID\\",\\"BUILD_INFO_BUILD_TIME\\",\\"BUILD_INFO_CURRENT_VERSION\\",\\"HOSTNAME\\",\\"ROOT_URL\\",\\"HOSTNAME_INTERNAL\\",\\"ROOT_URL_INTERNAL\\",\\"DEPLOY_CLOUD_RUN_PROJECT_ID\\",\\"DEPLOY_CLOUD_RUN_REGION\\",\\"MY_SECRET\\",\\"GCLOUD_DEPLOY_credentialsKey\\",\\"GCLOUD_RUN_canonicalHostSuffix\\"]"
971
+ - export DOCKER_REGISTRY="europe-west6-docker.pkg.dev"
972
+ - export DOCKER_IMAGE="europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/stage/my-app"
973
+ - export DOCKER_CACHE_IMAGE="europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/caches/my-app"
974
+ - export DOCKER_IMAGE_TAG="$CI_COMMIT_SHA"
975
+ - export CLOUDSDK_CORE_DISABLE_PROMPTS="1"
976
+ - collapseable_section_end "injectvars"
977
+ - collapseable_section_start "prepare" "Prepare..."
978
+ - gcloud auth activate-service-account --key-file=<(echo "$CL_stage_my_app_GCLOUD_DEPLOY_credentialsKey")
979
+ - export GCLOUD_PROJECT_NUMBER=$(gcloud projects describe my-project-id --format="value(projectNumber)")
980
+ - 'echo "GCLOUD_PROJECT_NUMBER: $GCLOUD_PROJECT_NUMBER"'
981
+ - collapseable_section_end "prepare"
982
+ - collapseable_section_start "writeenvvars" "Write env vars to file"
983
+ - |
984
+ cat > ____envvars.yaml <<EOF
985
+ ENV_SHORT: |-
986
+ stage
987
+ APP_DIR: |-
988
+ app
989
+ ENV_TYPE: |-
990
+ stage
991
+ BUILD_INFO_BUILD_ID: |-
992
+ $(printf %s "$(git describe --tags 2>/dev/null || git rev-parse HEAD)" | sed '1!s/^/ /')
993
+ BUILD_INFO_BUILD_TIME: |-
994
+ $(printf %s "$CI_JOB_STARTED_AT" | sed '1!s/^/ /')
995
+ BUILD_INFO_CURRENT_VERSION: |-
996
+ $(printf %s "$(tag=$(git ls-remote origin "refs/tags/v*[0-9]" 2>/dev/null | cut -f 2- | sort -V | tail -1 | sed 's/refs\\/tags\\/v//'); [ -z "$tag" ] && echo "0.0.0" || echo "$tag")" | sed '1!s/^/ /')
997
+ HOSTNAME: |-
998
+ $(printf %s "$(printf %s "pan-test-app-stage-my-app-$CL_stage_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | sed '1!s/^/ /')
999
+ ROOT_URL: |-
1000
+ $(printf %s "https://$(printf %s "pan-test-app-stage-my-app-$CL_stage_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | sed '1!s/^/ /')
1001
+ HOSTNAME_INTERNAL: |-
1002
+ $(printf %s "$(printf %s "pan-test-app-stage-my-app-$CL_stage_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | sed '1!s/^/ /')
1003
+ ROOT_URL_INTERNAL: |-
1004
+ $(printf %s "https://$(printf %s "pan-test-app-stage-my-app-$CL_stage_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | sed '1!s/^/ /')
1005
+ DEPLOY_CLOUD_RUN_PROJECT_ID: |-
1006
+ my-project-id
1007
+ DEPLOY_CLOUD_RUN_REGION: |-
1008
+ europe-west6
1009
+ MY_SECRET: |-
1010
+ $(printf %s "$CL_stage_my_app_MY_SECRET" | sed '1!s/^/ /')
1011
+ GCLOUD_RUN_canonicalHostSuffix: |-
1012
+ $(printf %s "$CL_stage_my_app_GCLOUD_RUN_canonicalHostSuffix" | sed '1!s/^/ /')
1013
+ _ALL_ENV_VAR_KEYS: |-
1014
+ ["ENV_SHORT","APP_DIR","ENV_TYPE","BUILD_INFO_BUILD_ID","BUILD_INFO_BUILD_TIME","BUILD_INFO_CURRENT_VERSION","HOSTNAME","ROOT_URL","HOSTNAME_INTERNAL","ROOT_URL_INTERNAL","DEPLOY_CLOUD_RUN_PROJECT_ID","DEPLOY_CLOUD_RUN_REGION","MY_SECRET","GCLOUD_DEPLOY_credentialsKey","GCLOUD_RUN_canonicalHostSuffix"]
1015
+
1016
+ EOF
1017
+ - collapseable_section_end "writeenvvars"
1018
+ - collapseable_section_start "deploy" "Deploy to cloud run"
1019
+ - gcloud run deploy pan-test-app-stage-my-app --command="yarn,start" --image=europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/stage/my-app:$DOCKER_IMAGE_TAG --project=my-project-id --region=europe-west6 --labels=customer-name=pan,component-name=my-app,app-name=test-app,env-type=stage,env-name=stage,build-type=node,cloud-run-service-name=pan-test-app-stage-my-app --env-vars-file=____envvars.yaml --min-instances=0 --max-instances=100 --cpu-throttling --allow-unauthenticated --ingress=all --cpu-boost
1020
+ - collapseable_section_end "deploy"
1021
+ - collapseable_section_start "cleanup" "Cleanup"
1022
+ - gcloud run revisions list --project=my-project-id --region=europe-west6 --service=pan-test-app-stage-my-app --limit=unlimited --sort-by=metadata.creationTimestamp --format="value(name)" --filter='(status.conditions.status=False OR status.conditions.status=Unknown)' | while read -r revisionname; do gcloud run revisions delete --project=my-project-id --region=europe-west6 --quiet $revisionname ; done
1023
+ - gcloud artifacts docker images list europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/stage/my-app --sort-by=~CREATE_TIME --format="value(version)" | tail -n +2 | while read -r version; do gcloud artifacts docker images delete europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/stage/my-app@$version --quiet --delete-tags; done
1024
+ - gcloud artifacts docker images list europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/caches/my-app --sort-by=~CREATE_TIME --format="value(version)" | tail -n +2 | while read -r version; do gcloud artifacts docker images delete europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/caches/my-app@$version --quiet --delete-tags; done
1025
+ - collapseable_section_end "cleanup"
1026
+ - echo 'Uploading SBOM to Dependency Track'
1027
+ - /dtrackuploader https://dep.panter.swiss/ "$DT_KEY_PROD" upload "pan-test-app/my-app" "$ROOT_URL" "__sbom.json" vex.json || true
1028
+ - echo "CL_GITLAB_ENVIRONMENT_URL=$ROOT_URL" >> gitlab_environment.env
1029
+ environment:
1030
+ name: stage/my-app
1031
+ url: $CL_GITLAB_ENVIRONMENT_URL
1032
+ on_stop: 'my-app ๐Ÿ›‘ Stop โš ๏ธ | stage '
1033
+ artifacts:
1034
+ reports:
1035
+ dotenv: gitlab_environment.env
1036
+ rules:
1037
+ - when: on_success
1038
+ if: $CI_COMMIT_TAG
1039
+ needs:
1040
+ - job: 'my-app ๐Ÿ”จ app | stage '
1041
+ artifacts: false
1042
+ - job: 'my-app ๐Ÿ”จ docker | stage '
1043
+ artifacts: false
1044
+ - job: 'my-app ๐Ÿงพ sbom | stage '
1045
+ artifacts: true
1046
+ retry: *a1
1047
+ interruptible: true
1048
+ allow_failure: false
1049
+ 'my-app ๐Ÿ›‘ Stop โš ๏ธ | stage ':
1050
+ stage: stop stage
1051
+ image: path/to/docker/gcloud:the-version
1052
+ variables:
1053
+ KUBERNETES_CPU_REQUEST: '0.22'
1054
+ KUBERNETES_MEMORY_REQUEST: 200Mi
1055
+ KUBERNETES_MEMORY_LIMIT: 400Mi
1056
+ GIT_STRATEGY: none
1057
+ script:
1058
+ - collapseable_section_start "injectvars" "Injecting variables"
1059
+ - export CLOUDSDK_CORE_DISABLE_PROMPTS="1"
1060
+ - collapseable_section_end "injectvars"
1061
+ - set +e
1062
+ - gcloud auth activate-service-account --key-file=<(echo "$CL_stage_my_app_GCLOUD_DEPLOY_credentialsKey")
1063
+ - gcloud run services delete pan-test-app-stage-my-app --project=my-project-id --region=europe-west6
1064
+ - gcloud artifacts docker images delete europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/stage/my-app --quiet --delete-tags
1065
+ - gcloud artifacts docker images list europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/caches/my-app --sort-by=~CREATE_TIME --format="value(version)" | tail -n +2 | while read -r version; do gcloud artifacts docker images delete europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/caches/my-app@$version --quiet --delete-tags; done
1066
+ - echo 'Disabling component in Dependency Track'
1067
+ - /dtrackuploader https://dep.panter.swiss/ "$DT_KEY_PROD" disable "pan-test-app/my-app" "$CI_ENVIRONMENT_URL" || true
1068
+ - set -e
1069
+ environment:
1070
+ name: stage/my-app
1071
+ action: stop
1072
+ rules:
1073
+ - if: $CI_COMMIT_BRANCH =~ /^[0-9]+\\.([0-9]+|x)\\.x$/
1074
+ when: on_success
1075
+ - when: manual
1076
+ if: $CI_COMMIT_TAG
1077
+ needs: []
1078
+ retry: *a1
1079
+ interruptible: true
1080
+ allow_failure: true
1081
+ 'my-app ๐Ÿ”จ app | prod ':
1082
+ stage: build
1083
+ image: path/to/docker/jobs-default:the-version
1084
+ variables:
1085
+ KUBERNETES_CPU_REQUEST: '0.45'
1086
+ KUBERNETES_MEMORY_REQUEST: 1Gi
1087
+ KUBERNETES_MEMORY_LIMIT: 4Gi
1088
+ script:
1089
+ - collapseable_section_start "injectvars" "Injecting variables"
1090
+ - export ENV_SHORT="prod"
1091
+ - export APP_DIR="app"
1092
+ - export ENV_TYPE="prod"
1093
+ - export BUILD_INFO_BUILD_ID="$(git describe --tags 2>/dev/null || git rev-parse HEAD)"
1094
+ - export BUILD_INFO_BUILD_TIME="$CI_JOB_STARTED_AT"
1095
+ - export BUILD_INFO_CURRENT_VERSION="$(tag=$(git ls-remote origin "refs/tags/v*[0-9]" 2>/dev/null | cut -f 2- | sort -V | tail -1 | sed 's/refs\\/tags\\/v//'); [ -z "$tag" ] && echo "0.0.0" || echo "$tag")"
1096
+ - export HOSTNAME="$(printf %s "pan-test-app-prod-my-app-$CL_prod_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
1097
+ - export ROOT_URL="https://$(printf %s "pan-test-app-prod-my-app-$CL_prod_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
1098
+ - export HOSTNAME_INTERNAL="$(printf %s "pan-test-app-prod-my-app-$CL_prod_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
1099
+ - export ROOT_URL_INTERNAL="https://$(printf %s "pan-test-app-prod-my-app-$CL_prod_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
1100
+ - export DEPLOY_CLOUD_RUN_PROJECT_ID="my-project-id"
1101
+ - export DEPLOY_CLOUD_RUN_REGION="europe-west6"
1102
+ - export MY_SECRET="$CL_prod_my_app_MY_SECRET"
1103
+ - export GCLOUD_DEPLOY_credentialsKey="$CL_prod_my_app_GCLOUD_DEPLOY_credentialsKey"
1104
+ - export GCLOUD_RUN_canonicalHostSuffix="$CL_prod_my_app_GCLOUD_RUN_canonicalHostSuffix"
1105
+ - export _ALL_ENV_VAR_KEYS="[\\"ENV_SHORT\\",\\"APP_DIR\\",\\"ENV_TYPE\\",\\"BUILD_INFO_BUILD_ID\\",\\"BUILD_INFO_BUILD_TIME\\",\\"BUILD_INFO_CURRENT_VERSION\\",\\"HOSTNAME\\",\\"ROOT_URL\\",\\"HOSTNAME_INTERNAL\\",\\"ROOT_URL_INTERNAL\\",\\"DEPLOY_CLOUD_RUN_PROJECT_ID\\",\\"DEPLOY_CLOUD_RUN_REGION\\",\\"MY_SECRET\\",\\"GCLOUD_DEPLOY_credentialsKey\\",\\"GCLOUD_RUN_canonicalHostSuffix\\"]"
1106
+ - collapseable_section_end "injectvars"
1107
+ - collapseable_section_start "write-dotenv-my-app" "write dot env for my-app"
1108
+ - |-
1109
+ cat <<EOF > app/.env
1110
+ ENV_SHORT=prod
1111
+ APP_DIR=app
1112
+ ENV_TYPE=prod
1113
+ HOSTNAME=$(printf %s "$(printf %s "pan-test-app-prod-my-app-$CL_prod_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | escapeForDotEnv)
1114
+ ROOT_URL=$(printf %s "https://$(printf %s "pan-test-app-prod-my-app-$CL_prod_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | escapeForDotEnv)
1115
+ HOSTNAME_INTERNAL=$(printf %s "$(printf %s "pan-test-app-prod-my-app-$CL_prod_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | escapeForDotEnv)
1116
+ ROOT_URL_INTERNAL=$(printf %s "https://$(printf %s "pan-test-app-prod-my-app-$CL_prod_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | escapeForDotEnv)
1117
+ DEPLOY_CLOUD_RUN_PROJECT_ID=my-project-id
1118
+ DEPLOY_CLOUD_RUN_REGION=europe-west6
1119
+ MY_SECRET=$(printf %s "$CL_prod_my_app_MY_SECRET" | escapeForDotEnv)
1120
+ GCLOUD_DEPLOY_credentialsKey=$(printf %s "$CL_prod_my_app_GCLOUD_DEPLOY_credentialsKey" | escapeForDotEnv)
1121
+ GCLOUD_RUN_canonicalHostSuffix=$(printf %s "$CL_prod_my_app_GCLOUD_RUN_canonicalHostSuffix" | escapeForDotEnv)
1122
+ _ALL_ENV_VAR_KEYS=["ENV_SHORT","APP_DIR","ENV_TYPE","BUILD_INFO_BUILD_ID","BUILD_INFO_BUILD_TIME","BUILD_INFO_CURRENT_VERSION","HOSTNAME","ROOT_URL","HOSTNAME_INTERNAL","ROOT_URL_INTERNAL","DEPLOY_CLOUD_RUN_PROJECT_ID","DEPLOY_CLOUD_RUN_REGION","MY_SECRET","GCLOUD_DEPLOY_credentialsKey","GCLOUD_RUN_canonicalHostSuffix"]
1123
+ EOF
1124
+ - collapseable_section_end "write-dotenv-my-app"
1125
+ - echo '{"id":"$(git describe --tags 2>/dev/null || git rev-parse HEAD)","time":"$CI_JOB_STARTED_AT"}' > app/__build_info.json
1126
+ - collapseable_section_start "nodeinstall" "Ensure node version"
1127
+ - if [ -f ~/.nvm/nvm.sh ]; then source ~/.nvm/nvm.sh; fi
1128
+ - if command -v nvm &> /dev/null && [ -f ./.nvmrc ]; then nvm install; fi
1129
+ - collapseable_section_end "nodeinstall"
1130
+ - cd app
1131
+ - collapseable_section_start "nodeinstall" "Ensure node version"
1132
+ - if [ -f ~/.nvm/nvm.sh ]; then source ~/.nvm/nvm.sh; fi
1133
+ - if command -v nvm &> /dev/null && [ -f ./.nvmrc ]; then nvm install; fi
1134
+ - collapseable_section_end "nodeinstall"
1135
+ - collapseable_section_start "yarninstall" "Yarn install"
1136
+ - yarn install --immutable
1137
+ - collapseable_section_end "yarninstall"
1138
+ - yarn build
1139
+ cache:
1140
+ - key: app-yarn
1141
+ policy: pull-push
1142
+ paths:
1143
+ - app/.yarn
1144
+ - key: app-node-modules
1145
+ policy: pull-push
1146
+ paths:
1147
+ - app/node_modules
1148
+ artifacts:
1149
+ paths:
1150
+ - app/__build_info.json
1151
+ - app/.next
1152
+ - app/dist
1153
+ exclude:
1154
+ - app/.env
1155
+ expire_in: 1 day
1156
+ when: always
1157
+ reports: {}
1158
+ rules:
1159
+ - if: $CI_COMMIT_TAG
1160
+ needs: []
1161
+ retry: *a1
1162
+ interruptible: true
1163
+ 'my-app ๐Ÿ”จ docker | prod ':
1164
+ stage: build
1165
+ image: path/to/docker/docker-build:the-version
1166
+ services:
1167
+ - name: docker:24.0.6-dind
1168
+ command:
1169
+ - --tls=false
1170
+ - --registry-mirror=https://mirror.gcr.io
1171
+ variables:
1172
+ DOCKER_HOST: tcp://0.0.0.0:2375
1173
+ DOCKER_TLS_CERTDIR: ''
1174
+ DOCKER_DRIVER: overlay2
1175
+ DOCKER_BUILDKIT: '1'
1176
+ KUBERNETES_CPU_REQUEST: '0.45'
1177
+ KUBERNETES_MEMORY_REQUEST: 1Gi
1178
+ KUBERNETES_MEMORY_LIMIT: 2Gi
1179
+ script:
1180
+ - collapseable_section_start "injectvars" "Injecting variables"
1181
+ - export APP_DIR="app"
1182
+ - export DOCKER_BUILD_CONTEXT="."
1183
+ - export DOCKER_REGISTRY="europe-west6-docker.pkg.dev"
1184
+ - export DOCKER_IMAGE="europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/prod/my-app"
1185
+ - export DOCKER_CACHE_IMAGE="europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/caches/my-app"
1186
+ - export DOCKER_IMAGE_TAG="$CI_COMMIT_SHA"
1187
+ - |-
1188
+ export DOCKER_COPY_AND_INSTALL_APP="COPY --chown=node:node $APP_DIR .
1189
+ RUN yarn plugin import workspace-tools
1190
+ RUN yarn workspaces focus --production && yarn rebuild"
1191
+ - |-
1192
+ export DOCKER_COPY_WORKSPACE_FILES="COPY --chown=node:node app/package.json /app/app/package.json
1193
+ COPY --chown=node:node app/yarn.lock /app/app/yarn.lock
1194
+ COPY --chown=node:node .yarnrc.yml /app/.yarnrc.yml
1195
+ COPY --chown=node:node .yarn /app/.yarn"
1196
+ - collapseable_section_end "injectvars"
1197
+ - ensureNodeDockerfile
1198
+ - collapseable_section_start "docker-login" "Docker Login"
1199
+ - gcloud auth activate-service-account --key-file=<(echo "$CL_prod_my_app_GCLOUD_DEPLOY_credentialsKey")
1200
+ - gcloud auth configure-docker europe-west6-docker.pkg.dev
1201
+ - collapseable_section_end "docker-login"
1202
+ - collapseable_section_start "docker-build" "Docker build"
1203
+ - docker build --network host --cache-from $DOCKER_CACHE_IMAGE --tag $DOCKER_IMAGE:$DOCKER_IMAGE_TAG -f $APP_DIR/Dockerfile $DOCKER_BUILD_CONTEXT --build-arg BUILDKIT_INLINE_CACHE=1
1204
+ - collapseable_section_end "docker-build"
1205
+ - collapseable_section_start "docker-push" "Docker push and tag"
1206
+ - docker push $DOCKER_IMAGE:$DOCKER_IMAGE_TAG
1207
+ - docker tag $DOCKER_IMAGE:$DOCKER_IMAGE_TAG $DOCKER_CACHE_IMAGE
1208
+ - docker push $DOCKER_CACHE_IMAGE
1209
+ - collapseable_section_end "docker-push"
1210
+ cache:
1211
+ - key: app-yarn
1212
+ policy: pull
1213
+ paths:
1214
+ - app/.yarn
1215
+ rules:
1216
+ - if: $CI_COMMIT_TAG
1217
+ needs:
1218
+ - 'my-app ๐Ÿ”จ app | prod '
1219
+ retry: *a1
1220
+ interruptible: true
1221
+ 'my-app ๐Ÿงพ sbom | prod ':
1222
+ stage: build
1223
+ image: aquasec/trivy:0.38.3
1224
+ variables: {}
1225
+ script:
1226
+ - collapseable_section_start "injectvars" "Injecting variables"
1227
+ - collapseable_section_end "injectvars"
1228
+ - trivy fs --quiet --format cyclonedx --output "__sbom.json" app
1229
+ artifacts:
1230
+ paths:
1231
+ - __sbom.json
1232
+ rules:
1233
+ - if: $CI_COMMIT_TAG
1234
+ needs: []
1235
+ retry: *a1
1236
+ interruptible: true
1237
+ allow_failure: true
1238
+ 'my-app ๐Ÿš€ Deploy | prod ':
1239
+ stage: deploy prod
1240
+ image: path/to/docker/gcloud:the-version
1241
+ variables:
1242
+ KUBERNETES_CPU_REQUEST: '0.22'
1243
+ KUBERNETES_MEMORY_REQUEST: 200Mi
1244
+ KUBERNETES_MEMORY_LIMIT: 400Mi
1245
+ script:
1246
+ - collapseable_section_start "injectvars" "Injecting variables"
1247
+ - export ENV_SHORT="prod"
1248
+ - export APP_DIR="app"
1249
+ - export ENV_TYPE="prod"
1250
+ - export BUILD_INFO_BUILD_ID="$(git describe --tags 2>/dev/null || git rev-parse HEAD)"
1251
+ - export BUILD_INFO_BUILD_TIME="$CI_JOB_STARTED_AT"
1252
+ - export BUILD_INFO_CURRENT_VERSION="$(tag=$(git ls-remote origin "refs/tags/v*[0-9]" 2>/dev/null | cut -f 2- | sort -V | tail -1 | sed 's/refs\\/tags\\/v//'); [ -z "$tag" ] && echo "0.0.0" || echo "$tag")"
1253
+ - export HOSTNAME="$(printf %s "pan-test-app-prod-my-app-$CL_prod_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
1254
+ - export ROOT_URL="https://$(printf %s "pan-test-app-prod-my-app-$CL_prod_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
1255
+ - export HOSTNAME_INTERNAL="$(printf %s "pan-test-app-prod-my-app-$CL_prod_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
1256
+ - export ROOT_URL_INTERNAL="https://$(printf %s "pan-test-app-prod-my-app-$CL_prod_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
1257
+ - export DEPLOY_CLOUD_RUN_PROJECT_ID="my-project-id"
1258
+ - export DEPLOY_CLOUD_RUN_REGION="europe-west6"
1259
+ - export MY_SECRET="$CL_prod_my_app_MY_SECRET"
1260
+ - export GCLOUD_DEPLOY_credentialsKey="$CL_prod_my_app_GCLOUD_DEPLOY_credentialsKey"
1261
+ - export GCLOUD_RUN_canonicalHostSuffix="$CL_prod_my_app_GCLOUD_RUN_canonicalHostSuffix"
1262
+ - export _ALL_ENV_VAR_KEYS="[\\"ENV_SHORT\\",\\"APP_DIR\\",\\"ENV_TYPE\\",\\"BUILD_INFO_BUILD_ID\\",\\"BUILD_INFO_BUILD_TIME\\",\\"BUILD_INFO_CURRENT_VERSION\\",\\"HOSTNAME\\",\\"ROOT_URL\\",\\"HOSTNAME_INTERNAL\\",\\"ROOT_URL_INTERNAL\\",\\"DEPLOY_CLOUD_RUN_PROJECT_ID\\",\\"DEPLOY_CLOUD_RUN_REGION\\",\\"MY_SECRET\\",\\"GCLOUD_DEPLOY_credentialsKey\\",\\"GCLOUD_RUN_canonicalHostSuffix\\"]"
1263
+ - export DOCKER_REGISTRY="europe-west6-docker.pkg.dev"
1264
+ - export DOCKER_IMAGE="europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/prod/my-app"
1265
+ - export DOCKER_CACHE_IMAGE="europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/caches/my-app"
1266
+ - export DOCKER_IMAGE_TAG="$CI_COMMIT_SHA"
1267
+ - export CLOUDSDK_CORE_DISABLE_PROMPTS="1"
1268
+ - collapseable_section_end "injectvars"
1269
+ - collapseable_section_start "prepare" "Prepare..."
1270
+ - gcloud auth activate-service-account --key-file=<(echo "$CL_prod_my_app_GCLOUD_DEPLOY_credentialsKey")
1271
+ - export GCLOUD_PROJECT_NUMBER=$(gcloud projects describe my-project-id --format="value(projectNumber)")
1272
+ - 'echo "GCLOUD_PROJECT_NUMBER: $GCLOUD_PROJECT_NUMBER"'
1273
+ - collapseable_section_end "prepare"
1274
+ - collapseable_section_start "writeenvvars" "Write env vars to file"
1275
+ - |
1276
+ cat > ____envvars.yaml <<EOF
1277
+ ENV_SHORT: |-
1278
+ prod
1279
+ APP_DIR: |-
1280
+ app
1281
+ ENV_TYPE: |-
1282
+ prod
1283
+ BUILD_INFO_BUILD_ID: |-
1284
+ $(printf %s "$(git describe --tags 2>/dev/null || git rev-parse HEAD)" | sed '1!s/^/ /')
1285
+ BUILD_INFO_BUILD_TIME: |-
1286
+ $(printf %s "$CI_JOB_STARTED_AT" | sed '1!s/^/ /')
1287
+ BUILD_INFO_CURRENT_VERSION: |-
1288
+ $(printf %s "$(tag=$(git ls-remote origin "refs/tags/v*[0-9]" 2>/dev/null | cut -f 2- | sort -V | tail -1 | sed 's/refs\\/tags\\/v//'); [ -z "$tag" ] && echo "0.0.0" || echo "$tag")" | sed '1!s/^/ /')
1289
+ HOSTNAME: |-
1290
+ $(printf %s "$(printf %s "pan-test-app-prod-my-app-$CL_prod_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | sed '1!s/^/ /')
1291
+ ROOT_URL: |-
1292
+ $(printf %s "https://$(printf %s "pan-test-app-prod-my-app-$CL_prod_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | sed '1!s/^/ /')
1293
+ HOSTNAME_INTERNAL: |-
1294
+ $(printf %s "$(printf %s "pan-test-app-prod-my-app-$CL_prod_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | sed '1!s/^/ /')
1295
+ ROOT_URL_INTERNAL: |-
1296
+ $(printf %s "https://$(printf %s "pan-test-app-prod-my-app-$CL_prod_my_app_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | sed '1!s/^/ /')
1297
+ DEPLOY_CLOUD_RUN_PROJECT_ID: |-
1298
+ my-project-id
1299
+ DEPLOY_CLOUD_RUN_REGION: |-
1300
+ europe-west6
1301
+ MY_SECRET: |-
1302
+ $(printf %s "$CL_prod_my_app_MY_SECRET" | sed '1!s/^/ /')
1303
+ GCLOUD_RUN_canonicalHostSuffix: |-
1304
+ $(printf %s "$CL_prod_my_app_GCLOUD_RUN_canonicalHostSuffix" | sed '1!s/^/ /')
1305
+ _ALL_ENV_VAR_KEYS: |-
1306
+ ["ENV_SHORT","APP_DIR","ENV_TYPE","BUILD_INFO_BUILD_ID","BUILD_INFO_BUILD_TIME","BUILD_INFO_CURRENT_VERSION","HOSTNAME","ROOT_URL","HOSTNAME_INTERNAL","ROOT_URL_INTERNAL","DEPLOY_CLOUD_RUN_PROJECT_ID","DEPLOY_CLOUD_RUN_REGION","MY_SECRET","GCLOUD_DEPLOY_credentialsKey","GCLOUD_RUN_canonicalHostSuffix"]
1307
+
1308
+ EOF
1309
+ - collapseable_section_end "writeenvvars"
1310
+ - collapseable_section_start "deploy" "Deploy to cloud run"
1311
+ - gcloud run deploy pan-test-app-prod-my-app --command="yarn,start" --image=europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/prod/my-app:$DOCKER_IMAGE_TAG --project=my-project-id --region=europe-west6 --labels=customer-name=pan,component-name=my-app,app-name=test-app,env-type=prod,env-name=prod,build-type=node,cloud-run-service-name=pan-test-app-prod-my-app --env-vars-file=____envvars.yaml --min-instances=0 --max-instances=100 --cpu-throttling --allow-unauthenticated --ingress=all --cpu-boost
1312
+ - collapseable_section_end "deploy"
1313
+ - collapseable_section_start "cleanup" "Cleanup"
1314
+ - gcloud run revisions list --project=my-project-id --region=europe-west6 --service=pan-test-app-prod-my-app --limit=unlimited --sort-by=metadata.creationTimestamp --format="value(name)" --filter='(status.conditions.status=False OR status.conditions.status=Unknown)' | tail -n +6 | while read -r revisionname; do gcloud run revisions delete --project=my-project-id --region=europe-west6 --quiet $revisionname ; done
1315
+ - gcloud artifacts docker images list europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/prod/my-app --sort-by=~CREATE_TIME --format="value(version)" | tail -n +7 | while read -r version; do gcloud artifacts docker images delete europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/prod/my-app@$version --quiet --delete-tags; done
1316
+ - gcloud artifacts docker images list europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/caches/my-app --sort-by=~CREATE_TIME --format="value(version)" | tail -n +2 | while read -r version; do gcloud artifacts docker images delete europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/caches/my-app@$version --quiet --delete-tags; done
1317
+ - collapseable_section_end "cleanup"
1318
+ - echo 'Uploading SBOM to Dependency Track'
1319
+ - /dtrackuploader https://dep.panter.swiss/ "$DT_KEY_PROD" upload "pan-test-app/my-app" "$ROOT_URL" "__sbom.json" vex.json || true
1320
+ - echo "CL_GITLAB_ENVIRONMENT_URL=$ROOT_URL" >> gitlab_environment.env
1321
+ environment:
1322
+ name: prod/my-app
1323
+ url: $CL_GITLAB_ENVIRONMENT_URL
1324
+ on_stop: 'my-app ๐Ÿ›‘ Stop โš ๏ธ | prod '
1325
+ artifacts:
1326
+ reports:
1327
+ dotenv: gitlab_environment.env
1328
+ rules:
1329
+ - when: manual
1330
+ if: $CI_COMMIT_TAG
1331
+ needs:
1332
+ - job: 'my-app ๐Ÿ”จ app | prod '
1333
+ artifacts: false
1334
+ - job: 'my-app ๐Ÿ”จ docker | prod '
1335
+ artifacts: false
1336
+ - job: 'my-app ๐Ÿงพ sbom | prod '
1337
+ artifacts: true
1338
+ retry: *a1
1339
+ interruptible: true
1340
+ allow_failure: true
1341
+ 'my-app ๐Ÿ›‘ Stop โš ๏ธ | prod ':
1342
+ stage: stop prod
1343
+ image: path/to/docker/gcloud:the-version
1344
+ variables:
1345
+ KUBERNETES_CPU_REQUEST: '0.22'
1346
+ KUBERNETES_MEMORY_REQUEST: 200Mi
1347
+ KUBERNETES_MEMORY_LIMIT: 400Mi
1348
+ GIT_STRATEGY: none
1349
+ script:
1350
+ - collapseable_section_start "injectvars" "Injecting variables"
1351
+ - export CLOUDSDK_CORE_DISABLE_PROMPTS="1"
1352
+ - collapseable_section_end "injectvars"
1353
+ - set +e
1354
+ - gcloud auth activate-service-account --key-file=<(echo "$CL_prod_my_app_GCLOUD_DEPLOY_credentialsKey")
1355
+ - gcloud run services delete pan-test-app-prod-my-app --project=my-project-id --region=europe-west6
1356
+ - gcloud artifacts docker images delete europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/prod/my-app --quiet --delete-tags
1357
+ - gcloud artifacts docker images list europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/caches/my-app --sort-by=~CREATE_TIME --format="value(version)" | tail -n +2 | while read -r version; do gcloud artifacts docker images delete europe-west6-docker.pkg.dev/my-project-id/catladder-deploy/pan-test-app/caches/my-app@$version --quiet --delete-tags; done
1358
+ - echo 'Disabling component in Dependency Track'
1359
+ - /dtrackuploader https://dep.panter.swiss/ "$DT_KEY_PROD" disable "pan-test-app/my-app" "$CI_ENVIRONMENT_URL" || true
1360
+ - set -e
1361
+ environment:
1362
+ name: prod/my-app
1363
+ action: stop
1364
+ rules:
1365
+ - if: $CI_COMMIT_BRANCH =~ /^[0-9]+\\.([0-9]+|x)\\.x$/
1366
+ when: on_success
1367
+ - when: manual
1368
+ if: $CI_COMMIT_TAG
1369
+ needs: []
1370
+ retry: *a1
1371
+ interruptible: true
1372
+ allow_failure: true
1373
+ create release:
1374
+ stage: release
1375
+ image: path/to/docker/semantic-release:the-version
1376
+ script:
1377
+ - semanticRelease
1378
+ - echo '๐Ÿ‘‰ The project access token might be invald - run \`project-renew-token\` in catladder CLI to fix.'
1379
+ rules:
1380
+ - &a2
1381
+ if: $CI_COMMIT_MESSAGE =~ /^chore\\(release\\).*/
1382
+ when: never
1383
+ - &a3
1384
+ if: $CI_PIPELINE_SOURCE == "schedule"
1385
+ when: never
1386
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $AUTO_RELEASE == "true"
1387
+ when: on_success
1388
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
1389
+ when: manual
1390
+ - if: $CI_COMMIT_BRANCH =~ /^[0-9]+.([0-9]+|x).x$/
1391
+ when: manual
1392
+ โš ๏ธ force create release:
1393
+ stage: release
1394
+ image: path/to/docker/semantic-release:the-version
1395
+ script:
1396
+ - semanticRelease
1397
+ - echo '๐Ÿ‘‰ The project access token might be invald - run \`project-renew-token\` in catladder CLI to fix.'
1398
+ rules:
1399
+ - *a2
1400
+ - *a3
1401
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
1402
+ when: manual
1403
+ - if: $CI_COMMIT_BRANCH =~ /^[0-9]+.([0-9]+|x).x$/
1404
+ when: manual
1405
+ needs: []
1406
+ "
1407
+ `;