@catladder/pipeline 3.13.1 → 3.14.0

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.
Files changed (107) hide show
  1. package/dist/bash/bashEscape.d.ts +2 -0
  2. package/dist/bash/bashEscape.js +9 -1
  3. package/dist/constants.js +1 -1
  4. package/dist/pipeline/agent/createAgentContext.d.ts +6 -0
  5. package/dist/pipeline/agent/createAgentContext.js +141 -0
  6. package/dist/pipeline/agent/createAgentEventJob.d.ts +2 -0
  7. package/dist/pipeline/agent/createAgentEventJob.js +74 -0
  8. package/dist/pipeline/agent/createAgentReviewJob.d.ts +2 -0
  9. package/dist/pipeline/agent/createAgentReviewJob.js +69 -0
  10. package/dist/pipeline/agent/createJobsForAgentContext.d.ts +2 -0
  11. package/dist/pipeline/agent/createJobsForAgentContext.js +12 -0
  12. package/dist/pipeline/agent/prompts.d.ts +10 -0
  13. package/dist/pipeline/agent/prompts.js +66 -0
  14. package/dist/pipeline/agent/shared.d.ts +8 -0
  15. package/dist/pipeline/agent/shared.js +29 -0
  16. package/dist/pipeline/agent/utils.d.ts +3 -0
  17. package/dist/pipeline/agent/utils.js +16 -0
  18. package/dist/pipeline/createAllJobs.d.ts +5 -1
  19. package/dist/pipeline/createAllJobs.js +32 -6
  20. package/dist/pipeline/createMainPipeline.js +10 -5
  21. package/dist/pipeline/gitlab/createGitlabJobs.d.ts +3 -3
  22. package/dist/pipeline/gitlab/createGitlabJobs.js +13 -11
  23. package/dist/pipeline/gitlab/createGitlabPipeline.js +6 -0
  24. package/dist/rules/index.d.ts +1 -0
  25. package/dist/rules/index.js +8 -3
  26. package/dist/tsconfig.tsbuildinfo +1 -1
  27. package/dist/types/agent.d.ts +7 -0
  28. package/dist/types/agent.js +5 -0
  29. package/dist/types/config.d.ts +2 -0
  30. package/dist/types/context.d.ts +7 -0
  31. package/dist/types/index.d.ts +2 -1
  32. package/dist/types/index.js +2 -1
  33. package/dist/types/jobs.d.ts +5 -1
  34. package/dist/types/jobs.js +1 -1
  35. package/examples/__snapshots__/cloud-run-health-check-defaults.test.ts.snap +65 -0
  36. package/examples/__snapshots__/cloud-run-health-check-only-startup.test.ts.snap +65 -0
  37. package/examples/__snapshots__/cloud-run-health-check.test.ts.snap +65 -0
  38. package/examples/__snapshots__/cloud-run-http2.test.ts.snap +65 -0
  39. package/examples/__snapshots__/cloud-run-llama.test.ts.snap +29 -0
  40. package/examples/__snapshots__/cloud-run-memory-limit.test.ts.snap +65 -0
  41. package/examples/__snapshots__/cloud-run-meteor-with-worker.test.ts.snap +65 -0
  42. package/examples/__snapshots__/cloud-run-nextjs.test.ts.snap +65 -0
  43. package/examples/__snapshots__/cloud-run-no-cpu-throttling.test.ts.snap +65 -0
  44. package/examples/__snapshots__/cloud-run-no-service.test.ts.snap +65 -0
  45. package/examples/__snapshots__/cloud-run-non-public.test.ts.snap +65 -0
  46. package/examples/__snapshots__/cloud-run-post-stop-job.test.ts.snap +65 -0
  47. package/examples/__snapshots__/cloud-run-service-custom-vpc-connector.test.ts.snap +65 -0
  48. package/examples/__snapshots__/cloud-run-service-custom-vpc.test.ts.snap +65 -0
  49. package/examples/__snapshots__/cloud-run-service-gen2.test.ts.snap +65 -0
  50. package/examples/__snapshots__/cloud-run-service-increase-timout.test.ts.snap +65 -0
  51. package/examples/__snapshots__/cloud-run-service-with-volumes.test.ts.snap +65 -0
  52. package/examples/__snapshots__/cloud-run-storybook.test.ts.snap +53 -0
  53. package/examples/__snapshots__/cloud-run-with-agents.test.ts.snap +1576 -0
  54. package/examples/__snapshots__/cloud-run-with-gpu.test.ts.snap +65 -0
  55. package/examples/__snapshots__/cloud-run-with-ngnix.test.ts.snap +65 -0
  56. package/examples/__snapshots__/cloud-run-with-sql-legacy-jobs.test.ts.snap +65 -0
  57. package/examples/__snapshots__/cloud-run-with-sql-multiple-dbs.test.ts.snap +169 -0
  58. package/examples/__snapshots__/cloud-run-with-sql-reuse-db.test.ts.snap +117 -0
  59. package/examples/__snapshots__/cloud-run-with-sql.test.ts.snap +65 -0
  60. package/examples/__snapshots__/cloud-run-with-worker.test.ts.snap +65 -0
  61. package/examples/__snapshots__/custom-build-job-with-tests.test.ts.snap +65 -0
  62. package/examples/__snapshots__/custom-build-job.test.ts.snap +53 -0
  63. package/examples/__snapshots__/custom-deploy.test.ts.snap +59 -0
  64. package/examples/__snapshots__/custom-envs.test.ts.snap +63 -0
  65. package/examples/__snapshots__/custom-sbom-java.test.ts.snap +53 -0
  66. package/examples/__snapshots__/custom-verify-job.test.ts.snap +73 -0
  67. package/examples/__snapshots__/git-submodule.test.ts.snap +65 -0
  68. package/examples/__snapshots__/kubernetes-application-customization.test.ts.snap +73 -0
  69. package/examples/__snapshots__/kubernetes-with-cloud-sql.test.ts.snap +73 -0
  70. package/examples/__snapshots__/kubernetes-with-jobs.test.ts.snap +133 -0
  71. package/examples/__snapshots__/kubernetes-with-mongodb.test.ts.snap +73 -0
  72. package/examples/__snapshots__/local-dot-env.test.ts.snap +65 -0
  73. package/examples/__snapshots__/meteor-kubernetes.test.ts.snap +73 -0
  74. package/examples/__snapshots__/multiline-var.test.ts.snap +177 -0
  75. package/examples/__snapshots__/native-app.test.ts.snap +101 -0
  76. package/examples/__snapshots__/node-build-with-custom-image.test.ts.snap +65 -0
  77. package/examples/__snapshots__/node-build-with-docker-additions.test.ts.snap +65 -0
  78. package/examples/__snapshots__/override-secrets.test.ts.snap +65 -0
  79. package/examples/__snapshots__/rails-k8s-with-worker-dockerfile.test.ts.snap +65 -0
  80. package/examples/__snapshots__/rails-k8s-with-worker.test.ts.snap +65 -0
  81. package/examples/__snapshots__/referencing-other-vars.test.ts.snap +177 -0
  82. package/examples/__snapshots__/wait-for-other-deploy.test.ts.snap +85 -0
  83. package/examples/__snapshots__/workspace-api-www-turbo-cache.test.ts.snap +97 -0
  84. package/examples/__snapshots__/workspace-api-www.test.ts.snap +97 -0
  85. package/examples/cloud-run-with-agents.test.ts +11 -0
  86. package/examples/cloud-run-with-agents.ts +36 -0
  87. package/package.json +1 -1
  88. package/src/bash/bashEscape.ts +6 -0
  89. package/src/pipeline/__tests__/__snapshots__/getPipelineStages.test.ts.snap +9 -0
  90. package/src/pipeline/agent/createAgentContext.ts +19 -0
  91. package/src/pipeline/agent/createAgentEventJob.ts +35 -0
  92. package/src/pipeline/agent/createAgentReviewJob.ts +33 -0
  93. package/src/pipeline/agent/createJobsForAgentContext.ts +7 -0
  94. package/src/pipeline/agent/prompts.ts +233 -0
  95. package/src/pipeline/agent/shared.ts +36 -0
  96. package/src/pipeline/agent/utils.ts +9 -0
  97. package/src/pipeline/createAllJobs.ts +20 -1
  98. package/src/pipeline/createJobsForComponent.ts +1 -0
  99. package/src/pipeline/createMainPipeline.ts +19 -4
  100. package/src/pipeline/gitlab/createGitlabJobs.ts +39 -30
  101. package/src/pipeline/gitlab/createGitlabPipeline.ts +8 -0
  102. package/src/rules/index.ts +7 -0
  103. package/src/types/agent.ts +7 -0
  104. package/src/types/config.ts +3 -0
  105. package/src/types/context.ts +8 -0
  106. package/src/types/index.ts +1 -0
  107. package/src/types/jobs.ts +6 -0
@@ -0,0 +1,1576 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`matches snapshot for cloud-run-with-agents 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
+ - agents
32
+ - agents dev
33
+ - agents review
34
+ - agents stage
35
+ - agents prod
36
+ - rollback
37
+ - rollback dev
38
+ - rollback review
39
+ - rollback stage
40
+ - rollback prod
41
+ - stop
42
+ - stop dev
43
+ - stop review
44
+ - stop stage
45
+ - stop prod
46
+ - release
47
+ variables:
48
+ FF_USE_FASTZIP: 'true'
49
+ ARTIFACT_COMPRESSION_LEVEL: fast
50
+ CACHE_COMPRESSION_LEVEL: fast
51
+ TRANSFER_METER_FREQUENCY: 5s
52
+ GIT_DEPTH: '1'
53
+ workflow:
54
+ name: $PIPELINE_ICON $PIPELINE_NAME
55
+ rules:
56
+ - if: $CI_PIPELINE_SOURCE == "trigger"
57
+ variables:
58
+ PIPELINE_ICON: 🤖
59
+ PIPELINE_NAME: Thinking...
60
+ - if: $CI_MERGE_REQUEST_ID
61
+ variables:
62
+ PIPELINE_ICON: 🐱🔨
63
+ PIPELINE_NAME: Merge Request $CI_MERGE_REQUEST_IID
64
+ - if: $CI_COMMIT_TAG
65
+ variables:
66
+ PIPELINE_ICON: 🐱📦
67
+ PIPELINE_NAME: Release $CI_COMMIT_TAG
68
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_COMMIT_MESSAGE !~ /^chore\\(release\\).*/
69
+ variables:
70
+ PIPELINE_ICON: 🐱🔨
71
+ PIPELINE_NAME: Main
72
+ - when: always
73
+ variables:
74
+ PIPELINE_ICON: 🐱❓
75
+ PIPELINE_NAME: Default
76
+ before_script:
77
+ - |-
78
+ function escapeForDotEnv () {
79
+ input="\${1:-$(cat)}"
80
+ input="\${input//$'\\n'/\\\\n}"
81
+ if [[ "$input" == *\\\\n* ]]; then
82
+ if [[ "$input" == *\\"* && "$input" == *\\'* && "$input" == *\\\`* ]]; then
83
+ printf "\\"%s\\"\\n" "$input"
84
+ elif [[ "$input" == *\\"* && "$input" == *\\'* ]]; then
85
+ printf "\`%s\`\\n" "$input"
86
+ elif [[ "$input" == *\\"* ]]; then
87
+ printf "'%s'\\n" "$input"
88
+ else
89
+ printf "\\"%s\\"\\n" "$input"
90
+ fi
91
+ else
92
+ printf "%s\\n" "$input"
93
+ fi
94
+ }
95
+ - |-
96
+ function collapseable_section_start () {
97
+ local section_title="\${1}"
98
+ local section_description="\${2:-$section_title}"
99
+ echo -e "section_start:\`date +%s\`:\${section_title}[collapsed=true]\\r\\e[0K\${section_description}"
100
+ }
101
+ - |-
102
+ function collapseable_section_end () {
103
+ local section_title="\${1}"
104
+ echo -e "section_end:\`date +%s\`:\${section_title}\\r\\e[0K"
105
+ }
106
+ www 🛡 audit:
107
+ stage: test
108
+ image: path/to/docker/jobs-default:the-version
109
+ variables:
110
+ KUBERNETES_CPU_REQUEST: '0.45'
111
+ KUBERNETES_MEMORY_REQUEST: 1Gi
112
+ KUBERNETES_MEMORY_LIMIT: 4Gi
113
+ script:
114
+ - collapseable_section_start "injectvars" "Injecting variables"
115
+ - export APP_PATH="www"
116
+ - collapseable_section_end "injectvars"
117
+ - cd www
118
+ - yarn npm audit --environment production
119
+ rules:
120
+ - when: never
121
+ if: $CI_PIPELINE_SOURCE == "trigger"
122
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_COMMIT_MESSAGE !~ /^chore\\(release\\).*/
123
+ - when: never
124
+ if: $CI_PIPELINE_SOURCE == "trigger"
125
+ - if: $CI_MERGE_REQUEST_ID
126
+ needs: []
127
+ retry: &a1
128
+ max: 2
129
+ when:
130
+ - runner_system_failure
131
+ - stuck_or_timeout_failure
132
+ interruptible: true
133
+ allow_failure: true
134
+ www 👮 lint:
135
+ stage: test
136
+ image: path/to/docker/jobs-default:the-version
137
+ variables:
138
+ KUBERNETES_CPU_REQUEST: '0.45'
139
+ KUBERNETES_MEMORY_REQUEST: 1Gi
140
+ KUBERNETES_MEMORY_LIMIT: 4Gi
141
+ script:
142
+ - collapseable_section_start "injectvars" "Injecting variables"
143
+ - export APP_PATH="www"
144
+ - collapseable_section_end "injectvars"
145
+ - collapseable_section_start "nodeinstall" "Ensure node version"
146
+ - if [ -f ~/.nvm/nvm.sh ]; then source ~/.nvm/nvm.sh; fi
147
+ - if command -v nvm &> /dev/null && [ -f ./.nvmrc ]; then nvm install; fi
148
+ - collapseable_section_end "nodeinstall"
149
+ - cd www
150
+ - collapseable_section_start "nodeinstall" "Ensure node version"
151
+ - if [ -f ~/.nvm/nvm.sh ]; then source ~/.nvm/nvm.sh; fi
152
+ - if command -v nvm &> /dev/null && [ -f ./.nvmrc ]; then nvm install; fi
153
+ - collapseable_section_end "nodeinstall"
154
+ - collapseable_section_start "yarninstall" "Yarn install"
155
+ - yarn install --immutable
156
+ - collapseable_section_end "yarninstall"
157
+ - yarn lint
158
+ cache:
159
+ - key: www-yarn
160
+ policy: pull-push
161
+ paths:
162
+ - www/.yarn
163
+ - key: www-node-modules
164
+ policy: pull-push
165
+ paths:
166
+ - www/node_modules
167
+ rules:
168
+ - when: never
169
+ if: $CI_PIPELINE_SOURCE == "trigger"
170
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_COMMIT_MESSAGE !~ /^chore\\(release\\).*/
171
+ - when: never
172
+ if: $CI_PIPELINE_SOURCE == "trigger"
173
+ - if: $CI_MERGE_REQUEST_ID
174
+ needs: []
175
+ retry: *a1
176
+ interruptible: true
177
+ www 🧪 test:
178
+ stage: test
179
+ image: path/to/docker/jobs-testing-chrome:the-version
180
+ variables:
181
+ KUBERNETES_CPU_REQUEST: '0.45'
182
+ KUBERNETES_MEMORY_REQUEST: 1Gi
183
+ KUBERNETES_MEMORY_LIMIT: 4Gi
184
+ script:
185
+ - collapseable_section_start "injectvars" "Injecting variables"
186
+ - export APP_PATH="www"
187
+ - collapseable_section_end "injectvars"
188
+ - collapseable_section_start "nodeinstall" "Ensure node version"
189
+ - if [ -f ~/.nvm/nvm.sh ]; then source ~/.nvm/nvm.sh; fi
190
+ - if command -v nvm &> /dev/null && [ -f ./.nvmrc ]; then nvm install; fi
191
+ - collapseable_section_end "nodeinstall"
192
+ - cd www
193
+ - collapseable_section_start "nodeinstall" "Ensure node version"
194
+ - if [ -f ~/.nvm/nvm.sh ]; then source ~/.nvm/nvm.sh; fi
195
+ - if command -v nvm &> /dev/null && [ -f ./.nvmrc ]; then nvm install; fi
196
+ - collapseable_section_end "nodeinstall"
197
+ - collapseable_section_start "yarninstall" "Yarn install"
198
+ - yarn install --immutable
199
+ - collapseable_section_end "yarninstall"
200
+ - yarn test
201
+ cache:
202
+ - key: www-yarn
203
+ policy: pull-push
204
+ paths:
205
+ - www/.yarn
206
+ - key: www-node-modules
207
+ policy: pull-push
208
+ paths:
209
+ - www/node_modules
210
+ rules:
211
+ - when: never
212
+ if: $CI_PIPELINE_SOURCE == "trigger"
213
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_COMMIT_MESSAGE !~ /^chore\\(release\\).*/
214
+ - when: never
215
+ if: $CI_PIPELINE_SOURCE == "trigger"
216
+ - if: $CI_MERGE_REQUEST_ID
217
+ needs: []
218
+ retry: *a1
219
+ interruptible: true
220
+ 'www 🔨 app | dev ':
221
+ stage: build
222
+ image: path/to/docker/jobs-default:the-version
223
+ variables:
224
+ KUBERNETES_CPU_REQUEST: '0.45'
225
+ KUBERNETES_MEMORY_REQUEST: 1Gi
226
+ KUBERNETES_MEMORY_LIMIT: 4Gi
227
+ script:
228
+ - collapseable_section_start "injectvars" "Injecting variables"
229
+ - export ENV_SHORT="dev"
230
+ - export APP_DIR="www"
231
+ - export ENV_TYPE="dev"
232
+ - export BUILD_INFO_BUILD_ID="$(git describe --tags 2>/dev/null || git rev-parse HEAD)"
233
+ - export BUILD_INFO_BUILD_TIME="$CI_JOB_STARTED_AT"
234
+ - 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")"
235
+ - export HOSTNAME="$(printf %s "pan-agent-example-app-dev-www-$CL_dev_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
236
+ - export ROOT_URL="https://$(printf %s "pan-agent-example-app-dev-www-$CL_dev_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
237
+ - export HOSTNAME_INTERNAL="$(printf %s "pan-agent-example-app-dev-www-$CL_dev_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
238
+ - export ROOT_URL_INTERNAL="https://$(printf %s "pan-agent-example-app-dev-www-$CL_dev_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
239
+ - export DEPLOY_CLOUD_RUN_PROJECT_ID="google-project-id"
240
+ - export DEPLOY_CLOUD_RUN_REGION="europe-west6"
241
+ - export GCLOUD_DEPLOY_credentialsKey="$CL_dev_www_GCLOUD_DEPLOY_credentialsKey"
242
+ - export GCLOUD_RUN_canonicalHostSuffix="$CL_dev_www_GCLOUD_RUN_canonicalHostSuffix"
243
+ - 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\\",\\"GCLOUD_DEPLOY_credentialsKey\\",\\"GCLOUD_RUN_canonicalHostSuffix\\"]"
244
+ - collapseable_section_end "injectvars"
245
+ - collapseable_section_start "write-dotenv-www" "write dot env for www"
246
+ - |-
247
+ cat <<EOF > www/.env
248
+ ENV_SHORT=dev
249
+ APP_DIR=www
250
+ ENV_TYPE=dev
251
+ HOSTNAME=$(printf %s "$(printf %s "pan-agent-example-app-dev-www-$CL_dev_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | escapeForDotEnv)
252
+ ROOT_URL=$(printf %s "https://$(printf %s "pan-agent-example-app-dev-www-$CL_dev_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | escapeForDotEnv)
253
+ HOSTNAME_INTERNAL=$(printf %s "$(printf %s "pan-agent-example-app-dev-www-$CL_dev_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | escapeForDotEnv)
254
+ ROOT_URL_INTERNAL=$(printf %s "https://$(printf %s "pan-agent-example-app-dev-www-$CL_dev_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | escapeForDotEnv)
255
+ DEPLOY_CLOUD_RUN_PROJECT_ID=google-project-id
256
+ DEPLOY_CLOUD_RUN_REGION=europe-west6
257
+ GCLOUD_DEPLOY_credentialsKey=$(printf %s "$CL_dev_www_GCLOUD_DEPLOY_credentialsKey" | escapeForDotEnv)
258
+ GCLOUD_RUN_canonicalHostSuffix=$(printf %s "$CL_dev_www_GCLOUD_RUN_canonicalHostSuffix" | escapeForDotEnv)
259
+ _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","GCLOUD_DEPLOY_credentialsKey","GCLOUD_RUN_canonicalHostSuffix"]
260
+ EOF
261
+ - collapseable_section_end "write-dotenv-www"
262
+ - echo '{"id":"$(git describe --tags 2>/dev/null || git rev-parse HEAD)","time":"$CI_JOB_STARTED_AT"}' > www/__build_info.json
263
+ - collapseable_section_start "nodeinstall" "Ensure node version"
264
+ - if [ -f ~/.nvm/nvm.sh ]; then source ~/.nvm/nvm.sh; fi
265
+ - if command -v nvm &> /dev/null && [ -f ./.nvmrc ]; then nvm install; fi
266
+ - collapseable_section_end "nodeinstall"
267
+ - cd www
268
+ - collapseable_section_start "nodeinstall" "Ensure node version"
269
+ - if [ -f ~/.nvm/nvm.sh ]; then source ~/.nvm/nvm.sh; fi
270
+ - if command -v nvm &> /dev/null && [ -f ./.nvmrc ]; then nvm install; fi
271
+ - collapseable_section_end "nodeinstall"
272
+ - collapseable_section_start "yarninstall" "Yarn install"
273
+ - yarn install --immutable
274
+ - collapseable_section_end "yarninstall"
275
+ - yarn build
276
+ cache:
277
+ - key: www-yarn
278
+ policy: pull-push
279
+ paths:
280
+ - www/.yarn
281
+ - key: www-node-modules
282
+ policy: pull-push
283
+ paths:
284
+ - www/node_modules
285
+ - key: www-default
286
+ policy: pull-push
287
+ paths:
288
+ - www/.next/cache
289
+ artifacts:
290
+ paths:
291
+ - www/__build_info.json
292
+ - www/.next
293
+ - www/dist
294
+ exclude:
295
+ - www/.env
296
+ expire_in: 1 day
297
+ when: always
298
+ reports: {}
299
+ rules:
300
+ - when: never
301
+ if: $CI_PIPELINE_SOURCE == "trigger"
302
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_COMMIT_MESSAGE !~ /^chore\\(release\\).*/
303
+ needs: []
304
+ retry: *a1
305
+ interruptible: true
306
+ 'www 🔨 docker | dev ':
307
+ stage: build
308
+ image: path/to/docker/docker-build:the-version
309
+ services:
310
+ - name: docker:24.0.6-dind
311
+ command:
312
+ - --tls=false
313
+ - --registry-mirror=https://mirror.gcr.io
314
+ variables:
315
+ DOCKER_HOST: tcp://docker:2375
316
+ DOCKER_TLS_CERTDIR: ''
317
+ DOCKER_DRIVER: overlay2
318
+ DOCKER_BUILDKIT: '1'
319
+ KUBERNETES_CPU_REQUEST: '0.45'
320
+ KUBERNETES_MEMORY_REQUEST: 1Gi
321
+ KUBERNETES_MEMORY_LIMIT: 2Gi
322
+ script:
323
+ - collapseable_section_start "injectvars" "Injecting variables"
324
+ - export APP_DIR="www"
325
+ - export DOCKER_BUILD_CONTEXT="."
326
+ - export DOCKER_REGISTRY="europe-west6-docker.pkg.dev"
327
+ - export DOCKER_IMAGE="europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/dev/www"
328
+ - export DOCKER_CACHE_IMAGE="europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/caches/www"
329
+ - export DOCKER_IMAGE_TAG="$CI_COMMIT_SHA"
330
+ - |-
331
+ export DOCKER_COPY_AND_INSTALL_APP="COPY --chown=node:node $APP_DIR .
332
+ RUN yarn plugin import workspace-tools
333
+ RUN yarn workspaces focus --production && yarn rebuild"
334
+ - |-
335
+ export DOCKER_COPY_WORKSPACE_FILES="COPY --chown=node:node www/package.json /app/www/package.json
336
+ COPY --chown=node:node www/yarn.lock /app/www/yarn.lock
337
+ COPY --chown=node:node .yarnrc.yml /app/.yarnrc.yml
338
+ COPY --chown=node:node .yarn /app/.yarn"
339
+ - collapseable_section_end "injectvars"
340
+ - ensureNodeDockerfile
341
+ - collapseable_section_start "docker-login" "Docker Login"
342
+ - gcloud auth activate-service-account --key-file=<(echo "$CL_dev_www_GCLOUD_DEPLOY_credentialsKey")
343
+ - gcloud auth configure-docker europe-west6-docker.pkg.dev
344
+ - collapseable_section_end "docker-login"
345
+ - collapseable_section_start "docker-build" "Docker build"
346
+ - 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
347
+ - collapseable_section_end "docker-build"
348
+ - collapseable_section_start "docker-push" "Docker push and tag"
349
+ - docker push $DOCKER_IMAGE:$DOCKER_IMAGE_TAG
350
+ - docker tag $DOCKER_IMAGE:$DOCKER_IMAGE_TAG $DOCKER_CACHE_IMAGE
351
+ - docker push $DOCKER_CACHE_IMAGE
352
+ - collapseable_section_end "docker-push"
353
+ cache:
354
+ - key: www-yarn
355
+ policy: pull
356
+ paths:
357
+ - www/.yarn
358
+ rules:
359
+ - when: never
360
+ if: $CI_PIPELINE_SOURCE == "trigger"
361
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_COMMIT_MESSAGE !~ /^chore\\(release\\).*/
362
+ needs:
363
+ - 'www 🔨 app | dev '
364
+ retry: *a1
365
+ interruptible: true
366
+ 'www 🧾 sbom | dev ':
367
+ stage: build
368
+ image:
369
+ name: aquasec/trivy:0.58.2
370
+ entrypoint:
371
+ - ''
372
+ variables: {}
373
+ script:
374
+ - collapseable_section_start "injectvars" "Injecting variables"
375
+ - collapseable_section_end "injectvars"
376
+ - trivy fs --quiet --format cyclonedx --output "__sbom.json" www
377
+ artifacts:
378
+ paths:
379
+ - __sbom.json
380
+ rules:
381
+ - when: never
382
+ if: $CI_PIPELINE_SOURCE == "trigger"
383
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_COMMIT_MESSAGE !~ /^chore\\(release\\).*/
384
+ needs: []
385
+ retry: *a1
386
+ interruptible: true
387
+ allow_failure: true
388
+ 'www 🚀 Deploy | dev ':
389
+ stage: deploy dev
390
+ image: path/to/docker/gcloud:the-version
391
+ variables:
392
+ KUBERNETES_CPU_REQUEST: '0.22'
393
+ KUBERNETES_MEMORY_REQUEST: 200Mi
394
+ KUBERNETES_MEMORY_LIMIT: 400Mi
395
+ script:
396
+ - collapseable_section_start "injectvars" "Injecting variables"
397
+ - export ENV_SHORT="dev"
398
+ - export APP_DIR="www"
399
+ - export ENV_TYPE="dev"
400
+ - export BUILD_INFO_BUILD_ID="$(git describe --tags 2>/dev/null || git rev-parse HEAD)"
401
+ - export BUILD_INFO_BUILD_TIME="$CI_JOB_STARTED_AT"
402
+ - 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")"
403
+ - export HOSTNAME="$(printf %s "pan-agent-example-app-dev-www-$CL_dev_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
404
+ - export ROOT_URL="https://$(printf %s "pan-agent-example-app-dev-www-$CL_dev_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
405
+ - export HOSTNAME_INTERNAL="$(printf %s "pan-agent-example-app-dev-www-$CL_dev_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
406
+ - export ROOT_URL_INTERNAL="https://$(printf %s "pan-agent-example-app-dev-www-$CL_dev_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
407
+ - export DEPLOY_CLOUD_RUN_PROJECT_ID="google-project-id"
408
+ - export DEPLOY_CLOUD_RUN_REGION="europe-west6"
409
+ - export GCLOUD_DEPLOY_credentialsKey="$CL_dev_www_GCLOUD_DEPLOY_credentialsKey"
410
+ - export GCLOUD_RUN_canonicalHostSuffix="$CL_dev_www_GCLOUD_RUN_canonicalHostSuffix"
411
+ - 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\\",\\"GCLOUD_DEPLOY_credentialsKey\\",\\"GCLOUD_RUN_canonicalHostSuffix\\"]"
412
+ - export DOCKER_REGISTRY="europe-west6-docker.pkg.dev"
413
+ - export DOCKER_IMAGE="europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/dev/www"
414
+ - export DOCKER_CACHE_IMAGE="europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/caches/www"
415
+ - export DOCKER_IMAGE_TAG="$CI_COMMIT_SHA"
416
+ - export CLOUDSDK_CORE_DISABLE_PROMPTS="1"
417
+ - collapseable_section_end "injectvars"
418
+ - collapseable_section_start "prepare" "Prepare..."
419
+ - gcloud auth activate-service-account --key-file=<(echo "$CL_dev_www_GCLOUD_DEPLOY_credentialsKey")
420
+ - export GCLOUD_PROJECT_NUMBER=$(gcloud projects describe google-project-id --format="value(projectNumber)")
421
+ - 'echo "GCLOUD_PROJECT_NUMBER: $GCLOUD_PROJECT_NUMBER"'
422
+ - collapseable_section_end "prepare"
423
+ - collapseable_section_start "writeenvvars" "Write env vars to file"
424
+ - |
425
+ cat > ____envvars.yaml <<EOF
426
+ ENV_SHORT: |-
427
+ dev
428
+ APP_DIR: |-
429
+ www
430
+ ENV_TYPE: |-
431
+ dev
432
+ BUILD_INFO_BUILD_ID: |-
433
+ $(printf %s "$(git describe --tags 2>/dev/null || git rev-parse HEAD)" | sed '1!s/^/ /')
434
+ BUILD_INFO_BUILD_TIME: |-
435
+ $(printf %s "$CI_JOB_STARTED_AT" | sed '1!s/^/ /')
436
+ BUILD_INFO_CURRENT_VERSION: |-
437
+ $(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/^/ /')
438
+ HOSTNAME: |-
439
+ $(printf %s "$(printf %s "pan-agent-example-app-dev-www-$CL_dev_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | sed '1!s/^/ /')
440
+ ROOT_URL: |-
441
+ $(printf %s "https://$(printf %s "pan-agent-example-app-dev-www-$CL_dev_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | sed '1!s/^/ /')
442
+ HOSTNAME_INTERNAL: |-
443
+ $(printf %s "$(printf %s "pan-agent-example-app-dev-www-$CL_dev_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | sed '1!s/^/ /')
444
+ ROOT_URL_INTERNAL: |-
445
+ $(printf %s "https://$(printf %s "pan-agent-example-app-dev-www-$CL_dev_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | sed '1!s/^/ /')
446
+ DEPLOY_CLOUD_RUN_PROJECT_ID: |-
447
+ google-project-id
448
+ DEPLOY_CLOUD_RUN_REGION: |-
449
+ europe-west6
450
+ GCLOUD_RUN_canonicalHostSuffix: |-
451
+ $(printf %s "$CL_dev_www_GCLOUD_RUN_canonicalHostSuffix" | sed '1!s/^/ /')
452
+ _ALL_ENV_VAR_KEYS: |-
453
+ ["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","GCLOUD_DEPLOY_credentialsKey","GCLOUD_RUN_canonicalHostSuffix"]
454
+
455
+ EOF
456
+ - collapseable_section_end "writeenvvars"
457
+ - collapseable_section_start "deploy" "Deploy to cloud run"
458
+ - gcloud run deploy pan-agent-example-app-dev-www --command="yarn,start" --image=europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/dev/www:$DOCKER_IMAGE_TAG --project=google-project-id --region=europe-west6 --labels=customer-name=pan,component-name=www,app-name=agent-example-app,env-type=dev,env-name=dev,build-type=node,cloud-run-service-name=pan-agent-example-app-dev-www --env-vars-file=____envvars.yaml --min-instances=0 --max-instances=100 --cpu-throttling --allow-unauthenticated --ingress=all --cpu-boost
459
+ - collapseable_section_end "deploy"
460
+ - collapseable_section_start "cleanup" "Cleanup"
461
+ - set +e
462
+ - gcloud run revisions list --project=google-project-id --region=europe-west6 --service=pan-agent-example-app-dev-www --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=google-project-id --region=europe-west6 --quiet $revisionname ; done
463
+ - gcloud artifacts docker images list europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/dev/www --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/google-project-id/catladder-deploy/pan-agent-example-app/dev/www@$version --quiet --delete-tags; done
464
+ - gcloud artifacts docker images list europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/caches/www --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/google-project-id/catladder-deploy/pan-agent-example-app/caches/www@$version --quiet --delete-tags; done
465
+ - set -e
466
+ - collapseable_section_end "cleanup"
467
+ - echo 'Uploading SBOM to Dependency Track'
468
+ - /dtrackuploader https://dep.panter.swiss/ "$DT_KEY_PROD" upload "pan-agent-example-app/www" "$ROOT_URL" "__sbom.json" vex.json || true
469
+ - echo "CL_GITLAB_ENVIRONMENT_URL=$ROOT_URL" >> gitlab_environment.env
470
+ environment:
471
+ name: dev/www
472
+ url: $CL_GITLAB_ENVIRONMENT_URL
473
+ on_stop: 'www 🛑 Stop ⚠️ | dev '
474
+ auto_stop_in: 4 weeks
475
+ artifacts:
476
+ reports:
477
+ dotenv: gitlab_environment.env
478
+ rules:
479
+ - when: never
480
+ if: $CI_PIPELINE_SOURCE == "trigger"
481
+ - when: on_success
482
+ if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_COMMIT_MESSAGE !~ /^chore\\(release\\).*/
483
+ needs:
484
+ - job: www 👮 lint
485
+ artifacts: false
486
+ - job: 'www 🔨 app | dev '
487
+ artifacts: false
488
+ - job: 'www 🔨 docker | dev '
489
+ artifacts: false
490
+ - job: www 🧪 test
491
+ artifacts: false
492
+ - job: 'www 🧾 sbom | dev '
493
+ artifacts: true
494
+ - job: www 🛡 audit
495
+ artifacts: false
496
+ retry: *a1
497
+ interruptible: true
498
+ allow_failure: false
499
+ 'www 🛑 Stop ⚠️ | dev ':
500
+ stage: stop dev
501
+ image: path/to/docker/gcloud:the-version
502
+ variables:
503
+ KUBERNETES_CPU_REQUEST: '0.22'
504
+ KUBERNETES_MEMORY_REQUEST: 200Mi
505
+ KUBERNETES_MEMORY_LIMIT: 400Mi
506
+ GIT_STRATEGY: none
507
+ script:
508
+ - collapseable_section_start "injectvars" "Injecting variables"
509
+ - export CLOUDSDK_CORE_DISABLE_PROMPTS="1"
510
+ - collapseable_section_end "injectvars"
511
+ - set +e
512
+ - gcloud auth activate-service-account --key-file=<(echo "$CL_dev_www_GCLOUD_DEPLOY_credentialsKey")
513
+ - gcloud run services delete pan-agent-example-app-dev-www --project=google-project-id --region=europe-west6
514
+ - gcloud artifacts docker images delete europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/dev/www --quiet --delete-tags
515
+ - gcloud artifacts docker images list europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/caches/www --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/google-project-id/catladder-deploy/pan-agent-example-app/caches/www@$version --quiet --delete-tags; done
516
+ - echo 'Disabling component in Dependency Track'
517
+ - /dtrackuploader https://dep.panter.swiss/ "$DT_KEY_PROD" disable "pan-agent-example-app/www" "$CI_ENVIRONMENT_URL" || true
518
+ - set -e
519
+ environment:
520
+ name: dev/www
521
+ action: stop
522
+ rules:
523
+ - if: $CI_COMMIT_BRANCH =~ /^[0-9]+\\.([0-9]+|x)\\.x$/
524
+ when: on_success
525
+ - when: never
526
+ if: $CI_PIPELINE_SOURCE == "trigger"
527
+ - when: manual
528
+ if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_COMMIT_MESSAGE !~ /^chore\\(release\\).*/
529
+ needs: []
530
+ retry: *a1
531
+ interruptible: true
532
+ allow_failure: true
533
+ 'www 🔨 app | review ':
534
+ stage: build
535
+ image: path/to/docker/jobs-default:the-version
536
+ variables:
537
+ KUBERNETES_CPU_REQUEST: '0.45'
538
+ KUBERNETES_MEMORY_REQUEST: 1Gi
539
+ KUBERNETES_MEMORY_LIMIT: 4Gi
540
+ script:
541
+ - collapseable_section_start "injectvars" "Injecting variables"
542
+ - export ENV_SHORT="review"
543
+ - export APP_DIR="www"
544
+ - export ENV_TYPE="review"
545
+ - export BUILD_INFO_BUILD_ID="$(git describe --tags 2>/dev/null || git rev-parse HEAD)"
546
+ - export BUILD_INFO_BUILD_TIME="$CI_JOB_STARTED_AT"
547
+ - 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")"
548
+ - export HOSTNAME="$(printf %s "pan-agent-example-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"; })-www-$CL_review_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
549
+ - export ROOT_URL="https://$(printf %s "pan-agent-example-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"; })-www-$CL_review_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
550
+ - export HOSTNAME_INTERNAL="$(printf %s "pan-agent-example-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"; })-www-$CL_review_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
551
+ - export ROOT_URL_INTERNAL="https://$(printf %s "pan-agent-example-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"; })-www-$CL_review_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
552
+ - export DEPLOY_CLOUD_RUN_PROJECT_ID="google-project-id"
553
+ - export DEPLOY_CLOUD_RUN_REGION="europe-west6"
554
+ - export GCLOUD_DEPLOY_credentialsKey="$CL_review_www_GCLOUD_DEPLOY_credentialsKey"
555
+ - export GCLOUD_RUN_canonicalHostSuffix="$CL_review_www_GCLOUD_RUN_canonicalHostSuffix"
556
+ - 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\\",\\"GCLOUD_DEPLOY_credentialsKey\\",\\"GCLOUD_RUN_canonicalHostSuffix\\"]"
557
+ - collapseable_section_end "injectvars"
558
+ - collapseable_section_start "write-dotenv-www" "write dot env for www"
559
+ - |-
560
+ cat <<EOF > www/.env
561
+ ENV_SHORT=review
562
+ APP_DIR=www
563
+ ENV_TYPE=review
564
+ HOSTNAME=$(printf %s "$(printf %s "pan-agent-example-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"; })-www-$CL_review_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | escapeForDotEnv)
565
+ ROOT_URL=$(printf %s "https://$(printf %s "pan-agent-example-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"; })-www-$CL_review_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | escapeForDotEnv)
566
+ HOSTNAME_INTERNAL=$(printf %s "$(printf %s "pan-agent-example-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"; })-www-$CL_review_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | escapeForDotEnv)
567
+ ROOT_URL_INTERNAL=$(printf %s "https://$(printf %s "pan-agent-example-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"; })-www-$CL_review_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | escapeForDotEnv)
568
+ DEPLOY_CLOUD_RUN_PROJECT_ID=google-project-id
569
+ DEPLOY_CLOUD_RUN_REGION=europe-west6
570
+ GCLOUD_DEPLOY_credentialsKey=$(printf %s "$CL_review_www_GCLOUD_DEPLOY_credentialsKey" | escapeForDotEnv)
571
+ GCLOUD_RUN_canonicalHostSuffix=$(printf %s "$CL_review_www_GCLOUD_RUN_canonicalHostSuffix" | escapeForDotEnv)
572
+ _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","GCLOUD_DEPLOY_credentialsKey","GCLOUD_RUN_canonicalHostSuffix"]
573
+ EOF
574
+ - collapseable_section_end "write-dotenv-www"
575
+ - echo '{"id":"$(git describe --tags 2>/dev/null || git rev-parse HEAD)","time":"$CI_JOB_STARTED_AT"}' > www/__build_info.json
576
+ - collapseable_section_start "nodeinstall" "Ensure node version"
577
+ - if [ -f ~/.nvm/nvm.sh ]; then source ~/.nvm/nvm.sh; fi
578
+ - if command -v nvm &> /dev/null && [ -f ./.nvmrc ]; then nvm install; fi
579
+ - collapseable_section_end "nodeinstall"
580
+ - cd www
581
+ - collapseable_section_start "nodeinstall" "Ensure node version"
582
+ - if [ -f ~/.nvm/nvm.sh ]; then source ~/.nvm/nvm.sh; fi
583
+ - if command -v nvm &> /dev/null && [ -f ./.nvmrc ]; then nvm install; fi
584
+ - collapseable_section_end "nodeinstall"
585
+ - collapseable_section_start "yarninstall" "Yarn install"
586
+ - yarn install --immutable
587
+ - collapseable_section_end "yarninstall"
588
+ - yarn build
589
+ cache:
590
+ - key: www-yarn
591
+ policy: pull-push
592
+ paths:
593
+ - www/.yarn
594
+ - key: www-node-modules
595
+ policy: pull-push
596
+ paths:
597
+ - www/node_modules
598
+ - key: www-default
599
+ policy: pull-push
600
+ paths:
601
+ - www/.next/cache
602
+ artifacts:
603
+ paths:
604
+ - www/__build_info.json
605
+ - www/.next
606
+ - www/dist
607
+ exclude:
608
+ - www/.env
609
+ expire_in: 1 day
610
+ when: always
611
+ reports: {}
612
+ rules:
613
+ - when: never
614
+ if: $CI_PIPELINE_SOURCE == "trigger"
615
+ - if: $CI_MERGE_REQUEST_ID
616
+ needs: []
617
+ retry: *a1
618
+ interruptible: true
619
+ 'www 🔨 docker | review ':
620
+ stage: build
621
+ image: path/to/docker/docker-build:the-version
622
+ services:
623
+ - name: docker:24.0.6-dind
624
+ command:
625
+ - --tls=false
626
+ - --registry-mirror=https://mirror.gcr.io
627
+ variables:
628
+ DOCKER_HOST: tcp://docker:2375
629
+ DOCKER_TLS_CERTDIR: ''
630
+ DOCKER_DRIVER: overlay2
631
+ DOCKER_BUILDKIT: '1'
632
+ KUBERNETES_CPU_REQUEST: '0.45'
633
+ KUBERNETES_MEMORY_REQUEST: 1Gi
634
+ KUBERNETES_MEMORY_LIMIT: 2Gi
635
+ script:
636
+ - collapseable_section_start "injectvars" "Injecting variables"
637
+ - export APP_DIR="www"
638
+ - export DOCKER_BUILD_CONTEXT="."
639
+ - export DOCKER_REGISTRY="europe-west6-docker.pkg.dev"
640
+ - export DOCKER_IMAGE="europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/review/www/$([ -n "$CI_MERGE_REQUEST_IID" ] && echo "mr$CI_MERGE_REQUEST_IID" || { [ -n "$CI_COMMIT_REF_SLUG" ] && echo "$CI_COMMIT_REF_SLUG" || echo "unknown"; })"
641
+ - export DOCKER_CACHE_IMAGE="europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/caches/www"
642
+ - export DOCKER_IMAGE_TAG="$CI_COMMIT_SHA"
643
+ - |-
644
+ export DOCKER_COPY_AND_INSTALL_APP="COPY --chown=node:node $APP_DIR .
645
+ RUN yarn plugin import workspace-tools
646
+ RUN yarn workspaces focus --production && yarn rebuild"
647
+ - |-
648
+ export DOCKER_COPY_WORKSPACE_FILES="COPY --chown=node:node www/package.json /app/www/package.json
649
+ COPY --chown=node:node www/yarn.lock /app/www/yarn.lock
650
+ COPY --chown=node:node .yarnrc.yml /app/.yarnrc.yml
651
+ COPY --chown=node:node .yarn /app/.yarn"
652
+ - collapseable_section_end "injectvars"
653
+ - ensureNodeDockerfile
654
+ - collapseable_section_start "docker-login" "Docker Login"
655
+ - gcloud auth activate-service-account --key-file=<(echo "$CL_review_www_GCLOUD_DEPLOY_credentialsKey")
656
+ - gcloud auth configure-docker europe-west6-docker.pkg.dev
657
+ - collapseable_section_end "docker-login"
658
+ - collapseable_section_start "docker-build" "Docker build"
659
+ - 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
660
+ - collapseable_section_end "docker-build"
661
+ - collapseable_section_start "docker-push" "Docker push and tag"
662
+ - docker push $DOCKER_IMAGE:$DOCKER_IMAGE_TAG
663
+ - docker tag $DOCKER_IMAGE:$DOCKER_IMAGE_TAG $DOCKER_CACHE_IMAGE
664
+ - docker push $DOCKER_CACHE_IMAGE
665
+ - collapseable_section_end "docker-push"
666
+ cache:
667
+ - key: www-yarn
668
+ policy: pull
669
+ paths:
670
+ - www/.yarn
671
+ rules:
672
+ - when: never
673
+ if: $CI_PIPELINE_SOURCE == "trigger"
674
+ - if: $CI_MERGE_REQUEST_ID
675
+ needs:
676
+ - 'www 🔨 app | review '
677
+ retry: *a1
678
+ interruptible: true
679
+ 'www 🧾 sbom | review ':
680
+ stage: build
681
+ image:
682
+ name: aquasec/trivy:0.58.2
683
+ entrypoint:
684
+ - ''
685
+ variables: {}
686
+ script:
687
+ - collapseable_section_start "injectvars" "Injecting variables"
688
+ - collapseable_section_end "injectvars"
689
+ - trivy fs --quiet --format cyclonedx --output "__sbom.json" www
690
+ artifacts:
691
+ paths:
692
+ - __sbom.json
693
+ rules:
694
+ - when: never
695
+ if: $CI_PIPELINE_SOURCE == "trigger"
696
+ - if: $CI_MERGE_REQUEST_ID
697
+ needs: []
698
+ retry: *a1
699
+ interruptible: true
700
+ allow_failure: true
701
+ 'www 🚀 Deploy | review ':
702
+ stage: deploy review
703
+ image: path/to/docker/gcloud:the-version
704
+ variables:
705
+ KUBERNETES_CPU_REQUEST: '0.22'
706
+ KUBERNETES_MEMORY_REQUEST: 200Mi
707
+ KUBERNETES_MEMORY_LIMIT: 400Mi
708
+ script:
709
+ - collapseable_section_start "injectvars" "Injecting variables"
710
+ - export ENV_SHORT="review"
711
+ - export APP_DIR="www"
712
+ - export ENV_TYPE="review"
713
+ - export BUILD_INFO_BUILD_ID="$(git describe --tags 2>/dev/null || git rev-parse HEAD)"
714
+ - export BUILD_INFO_BUILD_TIME="$CI_JOB_STARTED_AT"
715
+ - 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")"
716
+ - export HOSTNAME="$(printf %s "pan-agent-example-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"; })-www-$CL_review_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
717
+ - export ROOT_URL="https://$(printf %s "pan-agent-example-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"; })-www-$CL_review_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
718
+ - export HOSTNAME_INTERNAL="$(printf %s "pan-agent-example-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"; })-www-$CL_review_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
719
+ - export ROOT_URL_INTERNAL="https://$(printf %s "pan-agent-example-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"; })-www-$CL_review_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
720
+ - export DEPLOY_CLOUD_RUN_PROJECT_ID="google-project-id"
721
+ - export DEPLOY_CLOUD_RUN_REGION="europe-west6"
722
+ - export GCLOUD_DEPLOY_credentialsKey="$CL_review_www_GCLOUD_DEPLOY_credentialsKey"
723
+ - export GCLOUD_RUN_canonicalHostSuffix="$CL_review_www_GCLOUD_RUN_canonicalHostSuffix"
724
+ - 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\\",\\"GCLOUD_DEPLOY_credentialsKey\\",\\"GCLOUD_RUN_canonicalHostSuffix\\"]"
725
+ - export DOCKER_REGISTRY="europe-west6-docker.pkg.dev"
726
+ - export DOCKER_IMAGE="europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/review/www/$([ -n "$CI_MERGE_REQUEST_IID" ] && echo "mr$CI_MERGE_REQUEST_IID" || { [ -n "$CI_COMMIT_REF_SLUG" ] && echo "$CI_COMMIT_REF_SLUG" || echo "unknown"; })"
727
+ - export DOCKER_CACHE_IMAGE="europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/caches/www"
728
+ - export DOCKER_IMAGE_TAG="$CI_COMMIT_SHA"
729
+ - export CLOUDSDK_CORE_DISABLE_PROMPTS="1"
730
+ - collapseable_section_end "injectvars"
731
+ - collapseable_section_start "prepare" "Prepare..."
732
+ - gcloud auth activate-service-account --key-file=<(echo "$CL_review_www_GCLOUD_DEPLOY_credentialsKey")
733
+ - export GCLOUD_PROJECT_NUMBER=$(gcloud projects describe google-project-id --format="value(projectNumber)")
734
+ - 'echo "GCLOUD_PROJECT_NUMBER: $GCLOUD_PROJECT_NUMBER"'
735
+ - collapseable_section_end "prepare"
736
+ - collapseable_section_start "writeenvvars" "Write env vars to file"
737
+ - |
738
+ cat > ____envvars.yaml <<EOF
739
+ ENV_SHORT: |-
740
+ review
741
+ APP_DIR: |-
742
+ www
743
+ ENV_TYPE: |-
744
+ review
745
+ BUILD_INFO_BUILD_ID: |-
746
+ $(printf %s "$(git describe --tags 2>/dev/null || git rev-parse HEAD)" | sed '1!s/^/ /')
747
+ BUILD_INFO_BUILD_TIME: |-
748
+ $(printf %s "$CI_JOB_STARTED_AT" | sed '1!s/^/ /')
749
+ BUILD_INFO_CURRENT_VERSION: |-
750
+ $(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/^/ /')
751
+ HOSTNAME: |-
752
+ $(printf %s "$(printf %s "pan-agent-example-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"; })-www-$CL_review_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | sed '1!s/^/ /')
753
+ ROOT_URL: |-
754
+ $(printf %s "https://$(printf %s "pan-agent-example-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"; })-www-$CL_review_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | sed '1!s/^/ /')
755
+ HOSTNAME_INTERNAL: |-
756
+ $(printf %s "$(printf %s "pan-agent-example-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"; })-www-$CL_review_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | sed '1!s/^/ /')
757
+ ROOT_URL_INTERNAL: |-
758
+ $(printf %s "https://$(printf %s "pan-agent-example-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"; })-www-$CL_review_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | sed '1!s/^/ /')
759
+ DEPLOY_CLOUD_RUN_PROJECT_ID: |-
760
+ google-project-id
761
+ DEPLOY_CLOUD_RUN_REGION: |-
762
+ europe-west6
763
+ GCLOUD_RUN_canonicalHostSuffix: |-
764
+ $(printf %s "$CL_review_www_GCLOUD_RUN_canonicalHostSuffix" | sed '1!s/^/ /')
765
+ _ALL_ENV_VAR_KEYS: |-
766
+ ["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","GCLOUD_DEPLOY_credentialsKey","GCLOUD_RUN_canonicalHostSuffix"]
767
+
768
+ EOF
769
+ - collapseable_section_end "writeenvvars"
770
+ - collapseable_section_start "deploy" "Deploy to cloud run"
771
+ - gcloud run deploy $(printf %s "pan-agent-example-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"; })-www" | awk '{print tolower($0)}') --command="yarn,start" --image=europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/review/www/$([ -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=google-project-id --region=europe-west6 --labels=customer-name=pan,component-name=www,app-name=agent-example-app,env-type=review,env-name=review,build-type=node,cloud-run-service-name=$(printf %s "pan-agent-example-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"; })-www" | awk '{print tolower($0)}') --env-vars-file=____envvars.yaml --min-instances=0 --max-instances=100 --cpu-throttling --allow-unauthenticated --ingress=all --cpu-boost
772
+ - collapseable_section_end "deploy"
773
+ - collapseable_section_start "cleanup" "Cleanup"
774
+ - set +e
775
+ - gcloud run revisions list --project=google-project-id --region=europe-west6 --service=$(printf %s "pan-agent-example-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"; })-www" | 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=google-project-id --region=europe-west6 --quiet $revisionname ; done
776
+ - gcloud artifacts docker images list europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/review/www/$([ -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/google-project-id/catladder-deploy/pan-agent-example-app/review/www/$([ -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
777
+ - gcloud artifacts docker images list europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/caches/www --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/google-project-id/catladder-deploy/pan-agent-example-app/caches/www@$version --quiet --delete-tags; done
778
+ - set +e
779
+ - gcloud artifacts docker images delete europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/review/www --quiet --delete-tags
780
+ - set -e
781
+ - set -e
782
+ - collapseable_section_end "cleanup"
783
+ - echo 'Uploading SBOM to Dependency Track'
784
+ - /dtrackuploader https://dep.panter.swiss/ "$DT_KEY_PROD" upload "pan-agent-example-app/www" "$ROOT_URL" "__sbom.json" vex.json || true
785
+ - echo "CL_GITLAB_ENVIRONMENT_URL=$ROOT_URL" >> gitlab_environment.env
786
+ environment:
787
+ name: review/$CI_COMMIT_REF_NAME/www
788
+ url: $CL_GITLAB_ENVIRONMENT_URL
789
+ on_stop: 'www 🛑 Stop ⚠️ | review '
790
+ auto_stop_in: 1 week
791
+ artifacts:
792
+ reports:
793
+ dotenv: gitlab_environment.env
794
+ rules:
795
+ - when: never
796
+ if: $CI_PIPELINE_SOURCE == "trigger"
797
+ - when: on_success
798
+ if: $CI_MERGE_REQUEST_ID
799
+ needs:
800
+ - job: www 👮 lint
801
+ artifacts: false
802
+ - job: 'www 🔨 app | review '
803
+ artifacts: false
804
+ - job: 'www 🔨 docker | review '
805
+ artifacts: false
806
+ - job: www 🧪 test
807
+ artifacts: false
808
+ - job: 'www 🧾 sbom | review '
809
+ artifacts: true
810
+ - job: www 🛡 audit
811
+ artifacts: false
812
+ retry: *a1
813
+ interruptible: true
814
+ allow_failure: false
815
+ 'www 🛑 Stop ⚠️ | review ':
816
+ stage: stop review
817
+ image: path/to/docker/gcloud:the-version
818
+ variables:
819
+ KUBERNETES_CPU_REQUEST: '0.22'
820
+ KUBERNETES_MEMORY_REQUEST: 200Mi
821
+ KUBERNETES_MEMORY_LIMIT: 400Mi
822
+ GIT_STRATEGY: none
823
+ script:
824
+ - collapseable_section_start "injectvars" "Injecting variables"
825
+ - export CLOUDSDK_CORE_DISABLE_PROMPTS="1"
826
+ - collapseable_section_end "injectvars"
827
+ - set +e
828
+ - gcloud auth activate-service-account --key-file=<(echo "$CL_review_www_GCLOUD_DEPLOY_credentialsKey")
829
+ - gcloud run services delete $(printf %s "pan-agent-example-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"; })-www" | awk '{print tolower($0)}') --project=google-project-id --region=europe-west6
830
+ - gcloud artifacts docker images delete europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/review/www/$([ -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
831
+ - gcloud artifacts docker images list europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/caches/www --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/google-project-id/catladder-deploy/pan-agent-example-app/caches/www@$version --quiet --delete-tags; done
832
+ - set +e
833
+ - gcloud artifacts docker images delete europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/review/www --quiet --delete-tags
834
+ - set -e
835
+ - echo 'Disabling component in Dependency Track'
836
+ - /dtrackuploader https://dep.panter.swiss/ "$DT_KEY_PROD" disable "pan-agent-example-app/www" "$CI_ENVIRONMENT_URL" || true
837
+ - set -e
838
+ environment:
839
+ name: review/$CI_COMMIT_REF_NAME/www
840
+ action: stop
841
+ rules:
842
+ - if: $CI_COMMIT_BRANCH =~ /^[0-9]+\\.([0-9]+|x)\\.x$/
843
+ when: on_success
844
+ - when: never
845
+ if: $CI_PIPELINE_SOURCE == "trigger"
846
+ - when: manual
847
+ if: $CI_MERGE_REQUEST_ID
848
+ needs: []
849
+ retry: *a1
850
+ interruptible: true
851
+ allow_failure: true
852
+ 'www 🔨 app | stage ':
853
+ stage: build
854
+ image: path/to/docker/jobs-default:the-version
855
+ variables:
856
+ KUBERNETES_CPU_REQUEST: '0.45'
857
+ KUBERNETES_MEMORY_REQUEST: 1Gi
858
+ KUBERNETES_MEMORY_LIMIT: 4Gi
859
+ script:
860
+ - collapseable_section_start "injectvars" "Injecting variables"
861
+ - export ENV_SHORT="stage"
862
+ - export APP_DIR="www"
863
+ - export ENV_TYPE="stage"
864
+ - export BUILD_INFO_BUILD_ID="$(git describe --tags 2>/dev/null || git rev-parse HEAD)"
865
+ - export BUILD_INFO_BUILD_TIME="$CI_JOB_STARTED_AT"
866
+ - 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")"
867
+ - export HOSTNAME="$(printf %s "pan-agent-example-app-stage-www-$CL_stage_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
868
+ - export ROOT_URL="https://$(printf %s "pan-agent-example-app-stage-www-$CL_stage_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
869
+ - export HOSTNAME_INTERNAL="$(printf %s "pan-agent-example-app-stage-www-$CL_stage_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
870
+ - export ROOT_URL_INTERNAL="https://$(printf %s "pan-agent-example-app-stage-www-$CL_stage_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
871
+ - export DEPLOY_CLOUD_RUN_PROJECT_ID="google-project-id"
872
+ - export DEPLOY_CLOUD_RUN_REGION="europe-west6"
873
+ - export GCLOUD_DEPLOY_credentialsKey="$CL_stage_www_GCLOUD_DEPLOY_credentialsKey"
874
+ - export GCLOUD_RUN_canonicalHostSuffix="$CL_stage_www_GCLOUD_RUN_canonicalHostSuffix"
875
+ - 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\\",\\"GCLOUD_DEPLOY_credentialsKey\\",\\"GCLOUD_RUN_canonicalHostSuffix\\"]"
876
+ - collapseable_section_end "injectvars"
877
+ - collapseable_section_start "write-dotenv-www" "write dot env for www"
878
+ - |-
879
+ cat <<EOF > www/.env
880
+ ENV_SHORT=stage
881
+ APP_DIR=www
882
+ ENV_TYPE=stage
883
+ HOSTNAME=$(printf %s "$(printf %s "pan-agent-example-app-stage-www-$CL_stage_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | escapeForDotEnv)
884
+ ROOT_URL=$(printf %s "https://$(printf %s "pan-agent-example-app-stage-www-$CL_stage_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | escapeForDotEnv)
885
+ HOSTNAME_INTERNAL=$(printf %s "$(printf %s "pan-agent-example-app-stage-www-$CL_stage_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | escapeForDotEnv)
886
+ ROOT_URL_INTERNAL=$(printf %s "https://$(printf %s "pan-agent-example-app-stage-www-$CL_stage_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | escapeForDotEnv)
887
+ DEPLOY_CLOUD_RUN_PROJECT_ID=google-project-id
888
+ DEPLOY_CLOUD_RUN_REGION=europe-west6
889
+ GCLOUD_DEPLOY_credentialsKey=$(printf %s "$CL_stage_www_GCLOUD_DEPLOY_credentialsKey" | escapeForDotEnv)
890
+ GCLOUD_RUN_canonicalHostSuffix=$(printf %s "$CL_stage_www_GCLOUD_RUN_canonicalHostSuffix" | escapeForDotEnv)
891
+ _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","GCLOUD_DEPLOY_credentialsKey","GCLOUD_RUN_canonicalHostSuffix"]
892
+ EOF
893
+ - collapseable_section_end "write-dotenv-www"
894
+ - echo '{"id":"$(git describe --tags 2>/dev/null || git rev-parse HEAD)","time":"$CI_JOB_STARTED_AT"}' > www/__build_info.json
895
+ - collapseable_section_start "nodeinstall" "Ensure node version"
896
+ - if [ -f ~/.nvm/nvm.sh ]; then source ~/.nvm/nvm.sh; fi
897
+ - if command -v nvm &> /dev/null && [ -f ./.nvmrc ]; then nvm install; fi
898
+ - collapseable_section_end "nodeinstall"
899
+ - cd www
900
+ - collapseable_section_start "nodeinstall" "Ensure node version"
901
+ - if [ -f ~/.nvm/nvm.sh ]; then source ~/.nvm/nvm.sh; fi
902
+ - if command -v nvm &> /dev/null && [ -f ./.nvmrc ]; then nvm install; fi
903
+ - collapseable_section_end "nodeinstall"
904
+ - collapseable_section_start "yarninstall" "Yarn install"
905
+ - yarn install --immutable
906
+ - collapseable_section_end "yarninstall"
907
+ - yarn build
908
+ cache:
909
+ - key: www-yarn
910
+ policy: pull-push
911
+ paths:
912
+ - www/.yarn
913
+ - key: www-node-modules
914
+ policy: pull-push
915
+ paths:
916
+ - www/node_modules
917
+ - key: www-default
918
+ policy: pull-push
919
+ paths:
920
+ - www/.next/cache
921
+ artifacts:
922
+ paths:
923
+ - www/__build_info.json
924
+ - www/.next
925
+ - www/dist
926
+ exclude:
927
+ - www/.env
928
+ expire_in: 1 day
929
+ when: always
930
+ reports: {}
931
+ rules:
932
+ - when: never
933
+ if: $CI_PIPELINE_SOURCE == "trigger"
934
+ - if: $CI_COMMIT_TAG
935
+ needs: []
936
+ retry: *a1
937
+ interruptible: true
938
+ 'www 🔨 docker | stage ':
939
+ stage: build
940
+ image: path/to/docker/docker-build:the-version
941
+ services:
942
+ - name: docker:24.0.6-dind
943
+ command:
944
+ - --tls=false
945
+ - --registry-mirror=https://mirror.gcr.io
946
+ variables:
947
+ DOCKER_HOST: tcp://docker:2375
948
+ DOCKER_TLS_CERTDIR: ''
949
+ DOCKER_DRIVER: overlay2
950
+ DOCKER_BUILDKIT: '1'
951
+ KUBERNETES_CPU_REQUEST: '0.45'
952
+ KUBERNETES_MEMORY_REQUEST: 1Gi
953
+ KUBERNETES_MEMORY_LIMIT: 2Gi
954
+ script:
955
+ - collapseable_section_start "injectvars" "Injecting variables"
956
+ - export APP_DIR="www"
957
+ - export DOCKER_BUILD_CONTEXT="."
958
+ - export DOCKER_REGISTRY="europe-west6-docker.pkg.dev"
959
+ - export DOCKER_IMAGE="europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/stage/www"
960
+ - export DOCKER_CACHE_IMAGE="europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/caches/www"
961
+ - export DOCKER_IMAGE_TAG="$CI_COMMIT_SHA"
962
+ - |-
963
+ export DOCKER_COPY_AND_INSTALL_APP="COPY --chown=node:node $APP_DIR .
964
+ RUN yarn plugin import workspace-tools
965
+ RUN yarn workspaces focus --production && yarn rebuild"
966
+ - |-
967
+ export DOCKER_COPY_WORKSPACE_FILES="COPY --chown=node:node www/package.json /app/www/package.json
968
+ COPY --chown=node:node www/yarn.lock /app/www/yarn.lock
969
+ COPY --chown=node:node .yarnrc.yml /app/.yarnrc.yml
970
+ COPY --chown=node:node .yarn /app/.yarn"
971
+ - collapseable_section_end "injectvars"
972
+ - ensureNodeDockerfile
973
+ - collapseable_section_start "docker-login" "Docker Login"
974
+ - gcloud auth activate-service-account --key-file=<(echo "$CL_stage_www_GCLOUD_DEPLOY_credentialsKey")
975
+ - gcloud auth configure-docker europe-west6-docker.pkg.dev
976
+ - collapseable_section_end "docker-login"
977
+ - collapseable_section_start "docker-build" "Docker build"
978
+ - 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
979
+ - collapseable_section_end "docker-build"
980
+ - collapseable_section_start "docker-push" "Docker push and tag"
981
+ - docker push $DOCKER_IMAGE:$DOCKER_IMAGE_TAG
982
+ - docker tag $DOCKER_IMAGE:$DOCKER_IMAGE_TAG $DOCKER_CACHE_IMAGE
983
+ - docker push $DOCKER_CACHE_IMAGE
984
+ - collapseable_section_end "docker-push"
985
+ cache:
986
+ - key: www-yarn
987
+ policy: pull
988
+ paths:
989
+ - www/.yarn
990
+ rules:
991
+ - when: never
992
+ if: $CI_PIPELINE_SOURCE == "trigger"
993
+ - if: $CI_COMMIT_TAG
994
+ needs:
995
+ - 'www 🔨 app | stage '
996
+ retry: *a1
997
+ interruptible: true
998
+ 'www 🧾 sbom | stage ':
999
+ stage: build
1000
+ image:
1001
+ name: aquasec/trivy:0.58.2
1002
+ entrypoint:
1003
+ - ''
1004
+ variables: {}
1005
+ script:
1006
+ - collapseable_section_start "injectvars" "Injecting variables"
1007
+ - collapseable_section_end "injectvars"
1008
+ - trivy fs --quiet --format cyclonedx --output "__sbom.json" www
1009
+ artifacts:
1010
+ paths:
1011
+ - __sbom.json
1012
+ rules:
1013
+ - when: never
1014
+ if: $CI_PIPELINE_SOURCE == "trigger"
1015
+ - if: $CI_COMMIT_TAG
1016
+ needs: []
1017
+ retry: *a1
1018
+ interruptible: true
1019
+ allow_failure: true
1020
+ 'www 🚀 Deploy | stage ':
1021
+ stage: deploy stage
1022
+ image: path/to/docker/gcloud:the-version
1023
+ variables:
1024
+ KUBERNETES_CPU_REQUEST: '0.22'
1025
+ KUBERNETES_MEMORY_REQUEST: 200Mi
1026
+ KUBERNETES_MEMORY_LIMIT: 400Mi
1027
+ script:
1028
+ - collapseable_section_start "injectvars" "Injecting variables"
1029
+ - export ENV_SHORT="stage"
1030
+ - export APP_DIR="www"
1031
+ - export ENV_TYPE="stage"
1032
+ - export BUILD_INFO_BUILD_ID="$(git describe --tags 2>/dev/null || git rev-parse HEAD)"
1033
+ - export BUILD_INFO_BUILD_TIME="$CI_JOB_STARTED_AT"
1034
+ - 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")"
1035
+ - export HOSTNAME="$(printf %s "pan-agent-example-app-stage-www-$CL_stage_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
1036
+ - export ROOT_URL="https://$(printf %s "pan-agent-example-app-stage-www-$CL_stage_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
1037
+ - export HOSTNAME_INTERNAL="$(printf %s "pan-agent-example-app-stage-www-$CL_stage_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
1038
+ - export ROOT_URL_INTERNAL="https://$(printf %s "pan-agent-example-app-stage-www-$CL_stage_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
1039
+ - export DEPLOY_CLOUD_RUN_PROJECT_ID="google-project-id"
1040
+ - export DEPLOY_CLOUD_RUN_REGION="europe-west6"
1041
+ - export GCLOUD_DEPLOY_credentialsKey="$CL_stage_www_GCLOUD_DEPLOY_credentialsKey"
1042
+ - export GCLOUD_RUN_canonicalHostSuffix="$CL_stage_www_GCLOUD_RUN_canonicalHostSuffix"
1043
+ - 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\\",\\"GCLOUD_DEPLOY_credentialsKey\\",\\"GCLOUD_RUN_canonicalHostSuffix\\"]"
1044
+ - export DOCKER_REGISTRY="europe-west6-docker.pkg.dev"
1045
+ - export DOCKER_IMAGE="europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/stage/www"
1046
+ - export DOCKER_CACHE_IMAGE="europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/caches/www"
1047
+ - export DOCKER_IMAGE_TAG="$CI_COMMIT_SHA"
1048
+ - export CLOUDSDK_CORE_DISABLE_PROMPTS="1"
1049
+ - collapseable_section_end "injectvars"
1050
+ - collapseable_section_start "prepare" "Prepare..."
1051
+ - gcloud auth activate-service-account --key-file=<(echo "$CL_stage_www_GCLOUD_DEPLOY_credentialsKey")
1052
+ - export GCLOUD_PROJECT_NUMBER=$(gcloud projects describe google-project-id --format="value(projectNumber)")
1053
+ - 'echo "GCLOUD_PROJECT_NUMBER: $GCLOUD_PROJECT_NUMBER"'
1054
+ - collapseable_section_end "prepare"
1055
+ - collapseable_section_start "writeenvvars" "Write env vars to file"
1056
+ - |
1057
+ cat > ____envvars.yaml <<EOF
1058
+ ENV_SHORT: |-
1059
+ stage
1060
+ APP_DIR: |-
1061
+ www
1062
+ ENV_TYPE: |-
1063
+ stage
1064
+ BUILD_INFO_BUILD_ID: |-
1065
+ $(printf %s "$(git describe --tags 2>/dev/null || git rev-parse HEAD)" | sed '1!s/^/ /')
1066
+ BUILD_INFO_BUILD_TIME: |-
1067
+ $(printf %s "$CI_JOB_STARTED_AT" | sed '1!s/^/ /')
1068
+ BUILD_INFO_CURRENT_VERSION: |-
1069
+ $(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/^/ /')
1070
+ HOSTNAME: |-
1071
+ $(printf %s "$(printf %s "pan-agent-example-app-stage-www-$CL_stage_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | sed '1!s/^/ /')
1072
+ ROOT_URL: |-
1073
+ $(printf %s "https://$(printf %s "pan-agent-example-app-stage-www-$CL_stage_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | sed '1!s/^/ /')
1074
+ HOSTNAME_INTERNAL: |-
1075
+ $(printf %s "$(printf %s "pan-agent-example-app-stage-www-$CL_stage_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | sed '1!s/^/ /')
1076
+ ROOT_URL_INTERNAL: |-
1077
+ $(printf %s "https://$(printf %s "pan-agent-example-app-stage-www-$CL_stage_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | sed '1!s/^/ /')
1078
+ DEPLOY_CLOUD_RUN_PROJECT_ID: |-
1079
+ google-project-id
1080
+ DEPLOY_CLOUD_RUN_REGION: |-
1081
+ europe-west6
1082
+ GCLOUD_RUN_canonicalHostSuffix: |-
1083
+ $(printf %s "$CL_stage_www_GCLOUD_RUN_canonicalHostSuffix" | sed '1!s/^/ /')
1084
+ _ALL_ENV_VAR_KEYS: |-
1085
+ ["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","GCLOUD_DEPLOY_credentialsKey","GCLOUD_RUN_canonicalHostSuffix"]
1086
+
1087
+ EOF
1088
+ - collapseable_section_end "writeenvvars"
1089
+ - collapseable_section_start "deploy" "Deploy to cloud run"
1090
+ - gcloud run deploy pan-agent-example-app-stage-www --command="yarn,start" --image=europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/stage/www:$DOCKER_IMAGE_TAG --project=google-project-id --region=europe-west6 --labels=customer-name=pan,component-name=www,app-name=agent-example-app,env-type=stage,env-name=stage,build-type=node,cloud-run-service-name=pan-agent-example-app-stage-www --env-vars-file=____envvars.yaml --min-instances=0 --max-instances=100 --cpu-throttling --allow-unauthenticated --ingress=all --cpu-boost
1091
+ - collapseable_section_end "deploy"
1092
+ - collapseable_section_start "cleanup" "Cleanup"
1093
+ - set +e
1094
+ - gcloud run revisions list --project=google-project-id --region=europe-west6 --service=pan-agent-example-app-stage-www --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=google-project-id --region=europe-west6 --quiet $revisionname ; done
1095
+ - gcloud artifacts docker images list europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/stage/www --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/google-project-id/catladder-deploy/pan-agent-example-app/stage/www@$version --quiet --delete-tags; done
1096
+ - gcloud artifacts docker images list europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/caches/www --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/google-project-id/catladder-deploy/pan-agent-example-app/caches/www@$version --quiet --delete-tags; done
1097
+ - set -e
1098
+ - collapseable_section_end "cleanup"
1099
+ - echo 'Uploading SBOM to Dependency Track'
1100
+ - /dtrackuploader https://dep.panter.swiss/ "$DT_KEY_PROD" upload "pan-agent-example-app/www" "$ROOT_URL" "__sbom.json" vex.json || true
1101
+ - echo "CL_GITLAB_ENVIRONMENT_URL=$ROOT_URL" >> gitlab_environment.env
1102
+ environment:
1103
+ name: stage/www
1104
+ url: $CL_GITLAB_ENVIRONMENT_URL
1105
+ on_stop: 'www 🛑 Stop ⚠️ | stage '
1106
+ artifacts:
1107
+ reports:
1108
+ dotenv: gitlab_environment.env
1109
+ rules:
1110
+ - when: never
1111
+ if: $CI_PIPELINE_SOURCE == "trigger"
1112
+ - when: on_success
1113
+ if: $CI_COMMIT_TAG
1114
+ needs:
1115
+ - job: 'www 🔨 app | stage '
1116
+ artifacts: false
1117
+ - job: 'www 🔨 docker | stage '
1118
+ artifacts: false
1119
+ - job: 'www 🧾 sbom | stage '
1120
+ artifacts: true
1121
+ retry: *a1
1122
+ interruptible: true
1123
+ allow_failure: false
1124
+ 'www 🛑 Stop ⚠️ | stage ':
1125
+ stage: stop stage
1126
+ image: path/to/docker/gcloud:the-version
1127
+ variables:
1128
+ KUBERNETES_CPU_REQUEST: '0.22'
1129
+ KUBERNETES_MEMORY_REQUEST: 200Mi
1130
+ KUBERNETES_MEMORY_LIMIT: 400Mi
1131
+ GIT_STRATEGY: none
1132
+ script:
1133
+ - collapseable_section_start "injectvars" "Injecting variables"
1134
+ - export CLOUDSDK_CORE_DISABLE_PROMPTS="1"
1135
+ - collapseable_section_end "injectvars"
1136
+ - set +e
1137
+ - gcloud auth activate-service-account --key-file=<(echo "$CL_stage_www_GCLOUD_DEPLOY_credentialsKey")
1138
+ - gcloud run services delete pan-agent-example-app-stage-www --project=google-project-id --region=europe-west6
1139
+ - gcloud artifacts docker images delete europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/stage/www --quiet --delete-tags
1140
+ - gcloud artifacts docker images list europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/caches/www --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/google-project-id/catladder-deploy/pan-agent-example-app/caches/www@$version --quiet --delete-tags; done
1141
+ - echo 'Disabling component in Dependency Track'
1142
+ - /dtrackuploader https://dep.panter.swiss/ "$DT_KEY_PROD" disable "pan-agent-example-app/www" "$CI_ENVIRONMENT_URL" || true
1143
+ - set -e
1144
+ environment:
1145
+ name: stage/www
1146
+ action: stop
1147
+ rules:
1148
+ - if: $CI_COMMIT_BRANCH =~ /^[0-9]+\\.([0-9]+|x)\\.x$/
1149
+ when: on_success
1150
+ - when: never
1151
+ if: $CI_PIPELINE_SOURCE == "trigger"
1152
+ - when: manual
1153
+ if: $CI_COMMIT_TAG
1154
+ needs: []
1155
+ retry: *a1
1156
+ interruptible: true
1157
+ allow_failure: true
1158
+ 'www 🔨 app | prod ':
1159
+ stage: build
1160
+ image: path/to/docker/jobs-default:the-version
1161
+ variables:
1162
+ KUBERNETES_CPU_REQUEST: '0.45'
1163
+ KUBERNETES_MEMORY_REQUEST: 1Gi
1164
+ KUBERNETES_MEMORY_LIMIT: 4Gi
1165
+ script:
1166
+ - collapseable_section_start "injectvars" "Injecting variables"
1167
+ - export ENV_SHORT="prod"
1168
+ - export APP_DIR="www"
1169
+ - export ENV_TYPE="prod"
1170
+ - export BUILD_INFO_BUILD_ID="$(git describe --tags 2>/dev/null || git rev-parse HEAD)"
1171
+ - export BUILD_INFO_BUILD_TIME="$CI_JOB_STARTED_AT"
1172
+ - 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")"
1173
+ - export HOSTNAME="$(printf %s "pan-agent-example-app-prod-www-$CL_prod_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
1174
+ - export ROOT_URL="https://$(printf %s "pan-agent-example-app-prod-www-$CL_prod_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
1175
+ - export HOSTNAME_INTERNAL="$(printf %s "pan-agent-example-app-prod-www-$CL_prod_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
1176
+ - export ROOT_URL_INTERNAL="https://$(printf %s "pan-agent-example-app-prod-www-$CL_prod_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
1177
+ - export DEPLOY_CLOUD_RUN_PROJECT_ID="google-project-id"
1178
+ - export DEPLOY_CLOUD_RUN_REGION="europe-west6"
1179
+ - export GCLOUD_DEPLOY_credentialsKey="$CL_prod_www_GCLOUD_DEPLOY_credentialsKey"
1180
+ - export GCLOUD_RUN_canonicalHostSuffix="$CL_prod_www_GCLOUD_RUN_canonicalHostSuffix"
1181
+ - 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\\",\\"GCLOUD_DEPLOY_credentialsKey\\",\\"GCLOUD_RUN_canonicalHostSuffix\\"]"
1182
+ - collapseable_section_end "injectvars"
1183
+ - collapseable_section_start "write-dotenv-www" "write dot env for www"
1184
+ - |-
1185
+ cat <<EOF > www/.env
1186
+ ENV_SHORT=prod
1187
+ APP_DIR=www
1188
+ ENV_TYPE=prod
1189
+ HOSTNAME=$(printf %s "$(printf %s "pan-agent-example-app-prod-www-$CL_prod_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | escapeForDotEnv)
1190
+ ROOT_URL=$(printf %s "https://$(printf %s "pan-agent-example-app-prod-www-$CL_prod_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | escapeForDotEnv)
1191
+ HOSTNAME_INTERNAL=$(printf %s "$(printf %s "pan-agent-example-app-prod-www-$CL_prod_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | escapeForDotEnv)
1192
+ ROOT_URL_INTERNAL=$(printf %s "https://$(printf %s "pan-agent-example-app-prod-www-$CL_prod_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | escapeForDotEnv)
1193
+ DEPLOY_CLOUD_RUN_PROJECT_ID=google-project-id
1194
+ DEPLOY_CLOUD_RUN_REGION=europe-west6
1195
+ GCLOUD_DEPLOY_credentialsKey=$(printf %s "$CL_prod_www_GCLOUD_DEPLOY_credentialsKey" | escapeForDotEnv)
1196
+ GCLOUD_RUN_canonicalHostSuffix=$(printf %s "$CL_prod_www_GCLOUD_RUN_canonicalHostSuffix" | escapeForDotEnv)
1197
+ _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","GCLOUD_DEPLOY_credentialsKey","GCLOUD_RUN_canonicalHostSuffix"]
1198
+ EOF
1199
+ - collapseable_section_end "write-dotenv-www"
1200
+ - echo '{"id":"$(git describe --tags 2>/dev/null || git rev-parse HEAD)","time":"$CI_JOB_STARTED_AT"}' > www/__build_info.json
1201
+ - collapseable_section_start "nodeinstall" "Ensure node version"
1202
+ - if [ -f ~/.nvm/nvm.sh ]; then source ~/.nvm/nvm.sh; fi
1203
+ - if command -v nvm &> /dev/null && [ -f ./.nvmrc ]; then nvm install; fi
1204
+ - collapseable_section_end "nodeinstall"
1205
+ - cd www
1206
+ - collapseable_section_start "nodeinstall" "Ensure node version"
1207
+ - if [ -f ~/.nvm/nvm.sh ]; then source ~/.nvm/nvm.sh; fi
1208
+ - if command -v nvm &> /dev/null && [ -f ./.nvmrc ]; then nvm install; fi
1209
+ - collapseable_section_end "nodeinstall"
1210
+ - collapseable_section_start "yarninstall" "Yarn install"
1211
+ - yarn install --immutable
1212
+ - collapseable_section_end "yarninstall"
1213
+ - yarn build
1214
+ cache:
1215
+ - key: www-yarn
1216
+ policy: pull-push
1217
+ paths:
1218
+ - www/.yarn
1219
+ - key: www-node-modules
1220
+ policy: pull-push
1221
+ paths:
1222
+ - www/node_modules
1223
+ - key: www-default
1224
+ policy: pull-push
1225
+ paths:
1226
+ - www/.next/cache
1227
+ artifacts:
1228
+ paths:
1229
+ - www/__build_info.json
1230
+ - www/.next
1231
+ - www/dist
1232
+ exclude:
1233
+ - www/.env
1234
+ expire_in: 1 day
1235
+ when: always
1236
+ reports: {}
1237
+ rules:
1238
+ - when: never
1239
+ if: $CI_PIPELINE_SOURCE == "trigger"
1240
+ - if: $CI_COMMIT_TAG
1241
+ needs: []
1242
+ retry: *a1
1243
+ interruptible: true
1244
+ 'www 🔨 docker | prod ':
1245
+ stage: build
1246
+ image: path/to/docker/docker-build:the-version
1247
+ services:
1248
+ - name: docker:24.0.6-dind
1249
+ command:
1250
+ - --tls=false
1251
+ - --registry-mirror=https://mirror.gcr.io
1252
+ variables:
1253
+ DOCKER_HOST: tcp://docker:2375
1254
+ DOCKER_TLS_CERTDIR: ''
1255
+ DOCKER_DRIVER: overlay2
1256
+ DOCKER_BUILDKIT: '1'
1257
+ KUBERNETES_CPU_REQUEST: '0.45'
1258
+ KUBERNETES_MEMORY_REQUEST: 1Gi
1259
+ KUBERNETES_MEMORY_LIMIT: 2Gi
1260
+ script:
1261
+ - collapseable_section_start "injectvars" "Injecting variables"
1262
+ - export APP_DIR="www"
1263
+ - export DOCKER_BUILD_CONTEXT="."
1264
+ - export DOCKER_REGISTRY="europe-west6-docker.pkg.dev"
1265
+ - export DOCKER_IMAGE="europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/prod/www"
1266
+ - export DOCKER_CACHE_IMAGE="europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/caches/www"
1267
+ - export DOCKER_IMAGE_TAG="$CI_COMMIT_SHA"
1268
+ - |-
1269
+ export DOCKER_COPY_AND_INSTALL_APP="COPY --chown=node:node $APP_DIR .
1270
+ RUN yarn plugin import workspace-tools
1271
+ RUN yarn workspaces focus --production && yarn rebuild"
1272
+ - |-
1273
+ export DOCKER_COPY_WORKSPACE_FILES="COPY --chown=node:node www/package.json /app/www/package.json
1274
+ COPY --chown=node:node www/yarn.lock /app/www/yarn.lock
1275
+ COPY --chown=node:node .yarnrc.yml /app/.yarnrc.yml
1276
+ COPY --chown=node:node .yarn /app/.yarn"
1277
+ - collapseable_section_end "injectvars"
1278
+ - ensureNodeDockerfile
1279
+ - collapseable_section_start "docker-login" "Docker Login"
1280
+ - gcloud auth activate-service-account --key-file=<(echo "$CL_prod_www_GCLOUD_DEPLOY_credentialsKey")
1281
+ - gcloud auth configure-docker europe-west6-docker.pkg.dev
1282
+ - collapseable_section_end "docker-login"
1283
+ - collapseable_section_start "docker-build" "Docker build"
1284
+ - 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
1285
+ - collapseable_section_end "docker-build"
1286
+ - collapseable_section_start "docker-push" "Docker push and tag"
1287
+ - docker push $DOCKER_IMAGE:$DOCKER_IMAGE_TAG
1288
+ - docker tag $DOCKER_IMAGE:$DOCKER_IMAGE_TAG $DOCKER_CACHE_IMAGE
1289
+ - docker push $DOCKER_CACHE_IMAGE
1290
+ - collapseable_section_end "docker-push"
1291
+ cache:
1292
+ - key: www-yarn
1293
+ policy: pull
1294
+ paths:
1295
+ - www/.yarn
1296
+ rules:
1297
+ - when: never
1298
+ if: $CI_PIPELINE_SOURCE == "trigger"
1299
+ - if: $CI_COMMIT_TAG
1300
+ needs:
1301
+ - 'www 🔨 app | prod '
1302
+ retry: *a1
1303
+ interruptible: true
1304
+ 'www 🧾 sbom | prod ':
1305
+ stage: build
1306
+ image:
1307
+ name: aquasec/trivy:0.58.2
1308
+ entrypoint:
1309
+ - ''
1310
+ variables: {}
1311
+ script:
1312
+ - collapseable_section_start "injectvars" "Injecting variables"
1313
+ - collapseable_section_end "injectvars"
1314
+ - trivy fs --quiet --format cyclonedx --output "__sbom.json" www
1315
+ artifacts:
1316
+ paths:
1317
+ - __sbom.json
1318
+ rules:
1319
+ - when: never
1320
+ if: $CI_PIPELINE_SOURCE == "trigger"
1321
+ - if: $CI_COMMIT_TAG
1322
+ needs: []
1323
+ retry: *a1
1324
+ interruptible: true
1325
+ allow_failure: true
1326
+ 'www 🚀 Deploy | prod ':
1327
+ stage: deploy prod
1328
+ image: path/to/docker/gcloud:the-version
1329
+ variables:
1330
+ KUBERNETES_CPU_REQUEST: '0.22'
1331
+ KUBERNETES_MEMORY_REQUEST: 200Mi
1332
+ KUBERNETES_MEMORY_LIMIT: 400Mi
1333
+ script:
1334
+ - collapseable_section_start "injectvars" "Injecting variables"
1335
+ - export ENV_SHORT="prod"
1336
+ - export APP_DIR="www"
1337
+ - export ENV_TYPE="prod"
1338
+ - export BUILD_INFO_BUILD_ID="$(git describe --tags 2>/dev/null || git rev-parse HEAD)"
1339
+ - export BUILD_INFO_BUILD_TIME="$CI_JOB_STARTED_AT"
1340
+ - 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")"
1341
+ - export HOSTNAME="$(printf %s "pan-agent-example-app-prod-www-$CL_prod_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
1342
+ - export ROOT_URL="https://$(printf %s "pan-agent-example-app-prod-www-$CL_prod_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
1343
+ - export HOSTNAME_INTERNAL="$(printf %s "pan-agent-example-app-prod-www-$CL_prod_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
1344
+ - export ROOT_URL_INTERNAL="https://$(printf %s "pan-agent-example-app-prod-www-$CL_prod_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')"
1345
+ - export DEPLOY_CLOUD_RUN_PROJECT_ID="google-project-id"
1346
+ - export DEPLOY_CLOUD_RUN_REGION="europe-west6"
1347
+ - export GCLOUD_DEPLOY_credentialsKey="$CL_prod_www_GCLOUD_DEPLOY_credentialsKey"
1348
+ - export GCLOUD_RUN_canonicalHostSuffix="$CL_prod_www_GCLOUD_RUN_canonicalHostSuffix"
1349
+ - 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\\",\\"GCLOUD_DEPLOY_credentialsKey\\",\\"GCLOUD_RUN_canonicalHostSuffix\\"]"
1350
+ - export DOCKER_REGISTRY="europe-west6-docker.pkg.dev"
1351
+ - export DOCKER_IMAGE="europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/prod/www"
1352
+ - export DOCKER_CACHE_IMAGE="europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/caches/www"
1353
+ - export DOCKER_IMAGE_TAG="$CI_COMMIT_SHA"
1354
+ - export CLOUDSDK_CORE_DISABLE_PROMPTS="1"
1355
+ - collapseable_section_end "injectvars"
1356
+ - collapseable_section_start "prepare" "Prepare..."
1357
+ - gcloud auth activate-service-account --key-file=<(echo "$CL_prod_www_GCLOUD_DEPLOY_credentialsKey")
1358
+ - export GCLOUD_PROJECT_NUMBER=$(gcloud projects describe google-project-id --format="value(projectNumber)")
1359
+ - 'echo "GCLOUD_PROJECT_NUMBER: $GCLOUD_PROJECT_NUMBER"'
1360
+ - collapseable_section_end "prepare"
1361
+ - collapseable_section_start "writeenvvars" "Write env vars to file"
1362
+ - |
1363
+ cat > ____envvars.yaml <<EOF
1364
+ ENV_SHORT: |-
1365
+ prod
1366
+ APP_DIR: |-
1367
+ www
1368
+ ENV_TYPE: |-
1369
+ prod
1370
+ BUILD_INFO_BUILD_ID: |-
1371
+ $(printf %s "$(git describe --tags 2>/dev/null || git rev-parse HEAD)" | sed '1!s/^/ /')
1372
+ BUILD_INFO_BUILD_TIME: |-
1373
+ $(printf %s "$CI_JOB_STARTED_AT" | sed '1!s/^/ /')
1374
+ BUILD_INFO_CURRENT_VERSION: |-
1375
+ $(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/^/ /')
1376
+ HOSTNAME: |-
1377
+ $(printf %s "$(printf %s "pan-agent-example-app-prod-www-$CL_prod_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | sed '1!s/^/ /')
1378
+ ROOT_URL: |-
1379
+ $(printf %s "https://$(printf %s "pan-agent-example-app-prod-www-$CL_prod_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | sed '1!s/^/ /')
1380
+ HOSTNAME_INTERNAL: |-
1381
+ $(printf %s "$(printf %s "pan-agent-example-app-prod-www-$CL_prod_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | sed '1!s/^/ /')
1382
+ ROOT_URL_INTERNAL: |-
1383
+ $(printf %s "https://$(printf %s "pan-agent-example-app-prod-www-$CL_prod_www_GCLOUD_RUN_canonicalHostSuffix" | awk '{print tolower($0)}')" | sed '1!s/^/ /')
1384
+ DEPLOY_CLOUD_RUN_PROJECT_ID: |-
1385
+ google-project-id
1386
+ DEPLOY_CLOUD_RUN_REGION: |-
1387
+ europe-west6
1388
+ GCLOUD_RUN_canonicalHostSuffix: |-
1389
+ $(printf %s "$CL_prod_www_GCLOUD_RUN_canonicalHostSuffix" | sed '1!s/^/ /')
1390
+ _ALL_ENV_VAR_KEYS: |-
1391
+ ["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","GCLOUD_DEPLOY_credentialsKey","GCLOUD_RUN_canonicalHostSuffix"]
1392
+
1393
+ EOF
1394
+ - collapseable_section_end "writeenvvars"
1395
+ - collapseable_section_start "deploy" "Deploy to cloud run"
1396
+ - gcloud run deploy pan-agent-example-app-prod-www --command="yarn,start" --image=europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/prod/www:$DOCKER_IMAGE_TAG --project=google-project-id --region=europe-west6 --labels=customer-name=pan,component-name=www,app-name=agent-example-app,env-type=prod,env-name=prod,build-type=node,cloud-run-service-name=pan-agent-example-app-prod-www --env-vars-file=____envvars.yaml --min-instances=0 --max-instances=100 --cpu-throttling --allow-unauthenticated --ingress=all --cpu-boost
1397
+ - collapseable_section_end "deploy"
1398
+ - collapseable_section_start "cleanup" "Cleanup"
1399
+ - set +e
1400
+ - gcloud run revisions list --project=google-project-id --region=europe-west6 --service=pan-agent-example-app-prod-www --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=google-project-id --region=europe-west6 --quiet $revisionname ; done
1401
+ - gcloud artifacts docker images list europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/prod/www --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/google-project-id/catladder-deploy/pan-agent-example-app/prod/www@$version --quiet --delete-tags; done
1402
+ - gcloud artifacts docker images list europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/caches/www --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/google-project-id/catladder-deploy/pan-agent-example-app/caches/www@$version --quiet --delete-tags; done
1403
+ - set -e
1404
+ - collapseable_section_end "cleanup"
1405
+ - echo 'Uploading SBOM to Dependency Track'
1406
+ - /dtrackuploader https://dep.panter.swiss/ "$DT_KEY_PROD" upload "pan-agent-example-app/www" "$ROOT_URL" "__sbom.json" vex.json || true
1407
+ - echo "CL_GITLAB_ENVIRONMENT_URL=$ROOT_URL" >> gitlab_environment.env
1408
+ environment:
1409
+ name: prod/www
1410
+ url: $CL_GITLAB_ENVIRONMENT_URL
1411
+ on_stop: 'www 🛑 Stop ⚠️ | prod '
1412
+ artifacts:
1413
+ reports:
1414
+ dotenv: gitlab_environment.env
1415
+ rules:
1416
+ - when: never
1417
+ if: $CI_PIPELINE_SOURCE == "trigger"
1418
+ - when: manual
1419
+ if: $CI_COMMIT_TAG
1420
+ needs:
1421
+ - job: 'www 🔨 app | prod '
1422
+ artifacts: false
1423
+ - job: 'www 🔨 docker | prod '
1424
+ artifacts: false
1425
+ - job: 'www 🧾 sbom | prod '
1426
+ artifacts: true
1427
+ retry: *a1
1428
+ interruptible: true
1429
+ allow_failure: true
1430
+ 'www 🛑 Stop ⚠️ | prod ':
1431
+ stage: stop prod
1432
+ image: path/to/docker/gcloud:the-version
1433
+ variables:
1434
+ KUBERNETES_CPU_REQUEST: '0.22'
1435
+ KUBERNETES_MEMORY_REQUEST: 200Mi
1436
+ KUBERNETES_MEMORY_LIMIT: 400Mi
1437
+ GIT_STRATEGY: none
1438
+ script:
1439
+ - collapseable_section_start "injectvars" "Injecting variables"
1440
+ - export CLOUDSDK_CORE_DISABLE_PROMPTS="1"
1441
+ - collapseable_section_end "injectvars"
1442
+ - set +e
1443
+ - gcloud auth activate-service-account --key-file=<(echo "$CL_prod_www_GCLOUD_DEPLOY_credentialsKey")
1444
+ - gcloud run services delete pan-agent-example-app-prod-www --project=google-project-id --region=europe-west6
1445
+ - gcloud artifacts docker images delete europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/prod/www --quiet --delete-tags
1446
+ - gcloud artifacts docker images list europe-west6-docker.pkg.dev/google-project-id/catladder-deploy/pan-agent-example-app/caches/www --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/google-project-id/catladder-deploy/pan-agent-example-app/caches/www@$version --quiet --delete-tags; done
1447
+ - echo 'Disabling component in Dependency Track'
1448
+ - /dtrackuploader https://dep.panter.swiss/ "$DT_KEY_PROD" disable "pan-agent-example-app/www" "$CI_ENVIRONMENT_URL" || true
1449
+ - set -e
1450
+ environment:
1451
+ name: prod/www
1452
+ action: stop
1453
+ rules:
1454
+ - if: $CI_COMMIT_BRANCH =~ /^[0-9]+\\.([0-9]+|x)\\.x$/
1455
+ when: on_success
1456
+ - when: never
1457
+ if: $CI_PIPELINE_SOURCE == "trigger"
1458
+ - when: manual
1459
+ if: $CI_COMMIT_TAG
1460
+ needs: []
1461
+ retry: *a1
1462
+ interruptible: true
1463
+ allow_failure: true
1464
+ claude claude-agent-event:
1465
+ stage: agents
1466
+ image: node:24-alpine3.21
1467
+ variables: {}
1468
+ script:
1469
+ - collapseable_section_start "injectvars" "Injecting variables"
1470
+ - export MAX_MCP_OUTPUT_TOKENS="75000"
1471
+ - export GITLAB_PERSONAL_ACCESS_TOKEN="$AGENT_GITLAB_PERSONAL_ACCESS_TOKEN"
1472
+ - export GITLAB_API_URL="$CI_API_V4_URL"
1473
+ - collapseable_section_end "injectvars"
1474
+ - apk update
1475
+ - apk add --no-cache git curl bash
1476
+ - npm install -g @anthropic-ai/claude-code
1477
+ - claude mcp add gitlab --env GITLAB_PERSONAL_ACCESS_TOKEN=$GITLAB_PERSONAL_ACCESS_TOKEN --env GITLAB_API_URL=$GITLAB_API_URL -- npx -y @zereight/mcp-gitlab
1478
+ - 'export PROMPT="\\nYou are a GitLab assistant bot. You receive ONE raw GitLab webhook JSON payload.\\n\\n\\nProject ID: $CI_PROJECT_ID\\nGitLab Host: $CI_SERVER_URL\\n\\n---\\nevent_json:\\n$(cat $TRIGGER_PAYLOAD)\\n---\\n\\n\\n## Identity\\n- Your GitLab username is \\"agent.claude\\".\\n\\n\\n## Golden Rules\\n- Use the \\\`gitlab-mcp\\\` tool for ALL GitLab actions. If a needed action is missing, use GitLab REST/GraphQL API directly as a fallback.\\n- NEVER mention yourself (\\"@agent.claude\\").\\n- NEVER push to main/default or any protected branch. Always create a new branch and open a Merge Request (MR).\\n- Do not create an MR for a **closed** issue.\\n- Keep actions minimal and idempotent. Avoid duplicate comments or duplicate MRs.\\n- Use ONE stable \\\`source_branch\\\` per run; do not regenerate its name later.\\n\\n\\n## Self-Parse the Raw Payload (no preprocessing available)\\nFrom \\\`event_json\\\`, extract:\\n- kind: \\"issue\\" | \\"merge_request\\" | \\"note\\"\\n- target + iid from URL:\\n - \\\`/-/issues/<n>\\\` → target=\\"issue\\", iid=<n>\\n - \\\`/-/merge_requests/<n>\\\` → target=\\"mr\\", iid=<n>\\n- note_id if present (\\\`#note_<id>\\\`)\\n- description/body text, state, author \\\`user_username\\\`, timestamps\\n- project id/path; detect default branch via tool/API when needed\\n\\nIf any key is missing, choose the safest minimal action or briefly explain via a comment.\\n\\n\\n## High-Reliability Workflow (sequence + postconditions)\\nFollow this order for any change work:\\n\\n1) **Acknowledge** with a short comment on the issue/MR thread.\\n2) **Discover default branch** (e.g., \\"main\\") via MCP or API.\\n3) **Create a working branch** from default (stable name, e.g., \\\`fix/issue-<iid>-<slug>\\\` or \\\`feat/issue-<iid>-<slug>\\\`).\\n4) **Write changes → commit → push to remote branch.**\\n5) **Verify push landed**:\\n - Fetch latest commit on \\\`source_branch\\\`; record its short SHA.\\n - Compare default vs \\\`source_branch\\\` and ensure \\\`diffs.length > 0\\\`.\\n6) **Create or update MR** ONLY if there is a non-empty diff.\\n - Include \\\`Closes #<issue_iid>\\\` in MR description when applicable.\\n - Assign yourself to the MR.\\n7) **Follow-up comment** with branch name, commit short SHA, files changed count, and MR link.\\n8) **If verification fails**:\\n - Do NOT create the MR.\\n - Comment the exact failure and retry once with a fresh branch name. If still failing, comment and stop.\\n\\nFor Q&A-only (no code changes), just post a concise, helpful answer on the same issue/MR.\\n\\n\\n## Comment Guidelines (flexible, not verbatim)\\n- Keep tone professional, friendly, and concise.\\n- Always @-mention the human author when replying; never mention yourself.\\n- Acknowledgements: confirm you saw the request and you’ll handle it.\\n- MR updates: acknowledge feedback and say you’ll apply/have applied the change.\\n- Q&A: answer directly first; add context/links only if useful.\\n- Avoid repeating identical boilerplate across comments.\\n\\n\\n## Tools & API (MCP-first, REST/GraphQL fallback)\\nUse these \\\`gitlab-mcp\\\` capabilities when available (names illustrative—match the actual tool schema):\\n\\n- **Comments**\\n - \\\`gitlab-mcp.comment.create({ project_id: $CI_PROJECT_ID, target: \\"issue\\"|\\"mr\\", iid, body })\\\`\\n\\n- **Branch**\\n - \\\`gitlab-mcp.branch.create({ project_id: $CI_PROJECT_ID, from: \\"<default_branch>\\", name: \\"<source_branch>\\" })\\\`\\n\\n- **Commits & push**\\n - \\\`gitlab-mcp.commit.push({ project_id: $CI_PROJECT_ID, branch: \\"<source_branch>\\", message, files: [{ path, content | patch }] })\\\`\\n\\n- **Merge Requests**\\n - \\\`gitlab-mcp.merge_request.create({ project_id: $CI_PROJECT_ID, source_branch, target_branch: \\"<default_branch>\\", title, description, assign_to_self: true })\\\`\\n - \\\`gitlab-mcp.merge_request.update({ project_id: $CI_PROJECT_ID, mr_iid, ... })\\\`\\n - \\\`gitlab-mcp.merge_request.rebase({ project_id: $CI_PROJECT_ID, mr_iid, onto: \\"<default_branch>\\" })\\\`\\n\\n- **Read/verify**\\n - \\\`gitlab-mcp.project.get({ project_id: $CI_PROJECT_ID })\\\` → default branch\\n - \\\`gitlab-mcp.repo.compare({ project_id: $CI_PROJECT_ID, from: \\"<default_branch>\\", to: \\"<source_branch>\\" })\\\`\\n - \\\`gitlab-mcp.repo.branch.get({ project_id: $CI_PROJECT_ID, name: \\"<source_branch>\\" })\\\`\\n - \\\`gitlab-mcp.repo.commits.list({ project_id: $CI_PROJECT_ID, ref_name: \\"<source_branch>\\", per_page: 1 })\\\`\\n\\n### Fallback: Direct GitLab API\\nIf MCP lacks an operation, call GitLab’s REST/GraphQL API directly.\\n\\n- **Authentication** \\n Use the environment variable \\\`GITLAB_PERSONAL_ACCESS_TOKEN\\\`. \\n Send it in the HTTP header:\\n \\\`\\\`\\\`\\n Private-Token: $GITLAB_PERSONAL_ACCESS_TOKEN\\n \\\`\\\`\\\`\\n\\n- **Host & project variables**\\n - API base URL: \\\`$CI_SERVER_URL/api/v4\\\`\\n - Project ID: \\\`$CI_PROJECT_ID\\\`\\n\\n- **Examples**\\n - Get project (default branch): \\n \\\`GET $CI_SERVER_URL/api/v4/projects/$CI_PROJECT_ID\\\`\\n - Get/create branch: \\n \\\`GET|POST $CI_SERVER_URL/api/v4/projects/$CI_PROJECT_ID/repository/branches\\\`\\n - Compare refs: \\n \\\`GET $CI_SERVER_URL/api/v4/projects/$CI_PROJECT_ID/repository/compare?from=<default>&to=<source>\\\`\\n - List commits: \\n \\\`GET $CI_SERVER_URL/api/v4/projects/$CI_PROJECT_ID/repository/commits?ref_name=<branch>&per_page=1\\\`\\n - Create comment on issue/MR: \\n \\\`POST $CI_SERVER_URL/api/v4/projects/$CI_PROJECT_ID/issues/:iid/notes\\\` \\n \\\`POST $CI_SERVER_URL/api/v4/projects/$CI_PROJECT_ID/merge_requests/:iid/notes\\\`\\n - Create MR: \\n \\\`POST $CI_SERVER_URL/api/v4/projects/$CI_PROJECT_ID/merge_requests\\\`\\n - Get MR changes: \\n \\\`GET $CI_SERVER_URL/api/v4/projects/$CI_PROJECT_ID/merge_requests/:iid/changes\\\`\\n\\n\\n## Output Discipline\\n- Prefer \\\`gitlab-mcp\\\` tool calls. If unavailable, output direct API requests (endpoint, method, headers, JSON body).\\n- Keep comments concise and professional.\\n- Never include \\"@agent.claude\\" in any body.\\n\\n"'
1479
+ - claude -p "$PROMPT" --permission-mode acceptEdits --allowedTools "Bash(*) Read(*) Edit(*) Write(*) mcp__gitlab" --verbose --debug
1480
+ rules:
1481
+ - if: $CI_PIPELINE_SOURCE == "trigger" && ($ASSIGNEE_USER_ID == $DEFAULT_AGENT_USER_ID || $OBJECT_DESCRIPTION =~ /@agent.claude/)
1482
+ when: always
1483
+ - when: never
1484
+ - when: never
1485
+ if: $CI_PIPELINE_SOURCE == "trigger"
1486
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_COMMIT_MESSAGE !~ /^chore\\(release\\).*/
1487
+ - if: $CI_PIPELINE_SOURCE == "trigger" && ($ASSIGNEE_USER_ID == $DEFAULT_AGENT_USER_ID || $OBJECT_DESCRIPTION =~ /@agent.claude/)
1488
+ when: always
1489
+ - when: never
1490
+ - when: never
1491
+ if: $CI_PIPELINE_SOURCE == "trigger"
1492
+ - if: $CI_MERGE_REQUEST_ID
1493
+ - if: $CI_PIPELINE_SOURCE == "trigger" && ($ASSIGNEE_USER_ID == $DEFAULT_AGENT_USER_ID || $OBJECT_DESCRIPTION =~ /@agent.claude/)
1494
+ when: always
1495
+ - when: never
1496
+ - when: never
1497
+ if: $CI_PIPELINE_SOURCE == "trigger"
1498
+ - if: $CI_COMMIT_TAG
1499
+ retry: *a1
1500
+ interruptible: false
1501
+ claude claude-agent-review:
1502
+ stage: agents
1503
+ image: node:24-alpine3.21
1504
+ variables: {}
1505
+ script:
1506
+ - collapseable_section_start "injectvars" "Injecting variables"
1507
+ - export MAX_MCP_OUTPUT_TOKENS="75000"
1508
+ - export GITLAB_PERSONAL_ACCESS_TOKEN="$AGENT_GITLAB_PERSONAL_ACCESS_TOKEN"
1509
+ - export GITLAB_API_URL="$CI_API_V4_URL"
1510
+ - collapseable_section_end "injectvars"
1511
+ - apk update
1512
+ - apk add --no-cache git curl bash
1513
+ - npm install -g @anthropic-ai/claude-code
1514
+ - claude mcp add gitlab --env GITLAB_PERSONAL_ACCESS_TOKEN=$GITLAB_PERSONAL_ACCESS_TOKEN --env GITLAB_API_URL=$GITLAB_API_URL -- npx -y @zereight/mcp-gitlab
1515
+ - 'export PROMPT="\\nYou are a GitLab assistant bot reviewing and updating a single Merge Request (MR).\\n\\n\\nProject ID: $CI_PROJECT_ID\\nGitLab Host: $CI_SERVER_URL\\n\\n---\\nmerge_request_iid: $CI_MERGE_REQUEST_IID\\ntitle: $CI_MERGE_REQUEST_TITLE\\ndescription: $CI_MERGE_REQUEST_DESCRIPTION\\n---\\n\\n\\n## Identity & Scope\\n- Your GitLab username is \\"agent.claude\\".\\n- This prompt runs in the context of ONE MR (no webhook).\\n- You may review, comment, rebase, and push updates **to the MR''s source branch**.\\n- You must **never merge** the MR yourself.\\n\\n\\n## Golden Rules\\n- Use the \\\`gitlab-mcp\\\` tool for ALL GitLab actions. If a needed action is missing, use GitLab REST/GraphQL API directly as a fallback.\\n- NEVER mention yourself (\\"@agent.claude\\").\\n- NEVER push to main/default or any protected branch. Always create a new branch and open a Merge Request (MR).\\n- Do not create an MR for a **closed** issue.\\n- Keep actions minimal and idempotent. Avoid duplicate comments or duplicate MRs.\\n- Use ONE stable \\\`source_branch\\\` per run; do not regenerate its name later.\\n\\n\\n## High-Reliability Review Workflow\\nFollow this sequence with verification at each step:\\n\\n1) **Collect context**\\n - Get MR metadata (source_branch, target_branch, state, draft/WIP).\\n - Fetch the full changeset/diffs and open discussions (notes, threads, unresolved discussions).\\n - Read existing reviews/comments to avoid duplication.\\n - (Optional) Fetch recent CI pipeline(s) for this MR SHA/branch).\\n\\n2) **Code review**\\n - Identify required changes (bugs, tests, style, security, perf, docs).\\n - If no meaningful changes are needed:\\n - Post a concise review comment summarizing findings.\\n - Ask for review by a **recent active human contributor** (not you).\\n\\n3) **If changes are needed**\\n - Post a short acknowledgment comment on the MR.\\n - **Rebase** the MR onto the target/default branch (resolve trivial conflicts).\\n - Implement minimal, safe changes; keep commits small and clear.\\n - **Push** to the MR''s **source_branch**.\\n - **Verify push landed** (latest commit short SHA; compare target vs source shows diffs > 0).\\n - Comment summarizing what changed and why.\\n\\n4) **CI pipeline**\\n - Check pipeline status for the new commit on the MR branch.\\n - Retry/re-run if allowed on flaky failures; fix minimal issues; push again if needed.\\n - If still failing, comment with failure summary and next steps.\\n\\n5) **Assign human reviewer if ready**\\n - If discussions are resolved and CI is passing (or running), request review from a recent active human contributor (not you).\\n\\n6) **Stdout summary**\\n - Print concise summary: commits pushed (short SHAs), files changed count, discussions resolved/left, CI status, and requested reviewers.\\n\\n\\n## Comment Guidelines (flexible, not verbatim)\\n- Keep tone professional, friendly, and concise.\\n- Always @-mention the human author when replying; never mention yourself.\\n- Acknowledgements: confirm you saw the request and you’ll handle it.\\n- MR updates: acknowledge feedback and say you’ll apply/have applied the change.\\n- Q&A: answer directly first; add context/links only if useful.\\n- Avoid repeating identical boilerplate across comments.\\n\\n\\n## Tools & API (MCP-first, REST/GraphQL fallback)\\nUse these \\\`gitlab-mcp\\\` capabilities when available (names illustrative—match the actual tool schema):\\n\\n- **Comments**\\n - \\\`gitlab-mcp.comment.create({ project_id: $CI_PROJECT_ID, target: \\"issue\\"|\\"mr\\", iid, body })\\\`\\n\\n- **Branch**\\n - \\\`gitlab-mcp.branch.create({ project_id: $CI_PROJECT_ID, from: \\"<default_branch>\\", name: \\"<source_branch>\\" })\\\`\\n\\n- **Commits & push**\\n - \\\`gitlab-mcp.commit.push({ project_id: $CI_PROJECT_ID, branch: \\"<source_branch>\\", message, files: [{ path, content | patch }] })\\\`\\n\\n- **Merge Requests**\\n - \\\`gitlab-mcp.merge_request.create({ project_id: $CI_PROJECT_ID, source_branch, target_branch: \\"<default_branch>\\", title, description, assign_to_self: true })\\\`\\n - \\\`gitlab-mcp.merge_request.update({ project_id: $CI_PROJECT_ID, mr_iid, ... })\\\`\\n - \\\`gitlab-mcp.merge_request.rebase({ project_id: $CI_PROJECT_ID, mr_iid, onto: \\"<default_branch>\\" })\\\`\\n\\n- **Read/verify**\\n - \\\`gitlab-mcp.project.get({ project_id: $CI_PROJECT_ID })\\\` → default branch\\n - \\\`gitlab-mcp.repo.compare({ project_id: $CI_PROJECT_ID, from: \\"<default_branch>\\", to: \\"<source_branch>\\" })\\\`\\n - \\\`gitlab-mcp.repo.branch.get({ project_id: $CI_PROJECT_ID, name: \\"<source_branch>\\" })\\\`\\n - \\\`gitlab-mcp.repo.commits.list({ project_id: $CI_PROJECT_ID, ref_name: \\"<source_branch>\\", per_page: 1 })\\\`\\n\\n### Fallback: Direct GitLab API\\nIf MCP lacks an operation, call GitLab’s REST/GraphQL API directly.\\n\\n- **Authentication** \\n Use the environment variable \\\`GITLAB_PERSONAL_ACCESS_TOKEN\\\`. \\n Send it in the HTTP header:\\n \\\`\\\`\\\`\\n Private-Token: $GITLAB_PERSONAL_ACCESS_TOKEN\\n \\\`\\\`\\\`\\n\\n- **Host & project variables**\\n - API base URL: \\\`$CI_SERVER_URL/api/v4\\\`\\n - Project ID: \\\`$CI_PROJECT_ID\\\`\\n\\n- **Examples**\\n - Get project (default branch): \\n \\\`GET $CI_SERVER_URL/api/v4/projects/$CI_PROJECT_ID\\\`\\n - Get/create branch: \\n \\\`GET|POST $CI_SERVER_URL/api/v4/projects/$CI_PROJECT_ID/repository/branches\\\`\\n - Compare refs: \\n \\\`GET $CI_SERVER_URL/api/v4/projects/$CI_PROJECT_ID/repository/compare?from=<default>&to=<source>\\\`\\n - List commits: \\n \\\`GET $CI_SERVER_URL/api/v4/projects/$CI_PROJECT_ID/repository/commits?ref_name=<branch>&per_page=1\\\`\\n - Create comment on issue/MR: \\n \\\`POST $CI_SERVER_URL/api/v4/projects/$CI_PROJECT_ID/issues/:iid/notes\\\` \\n \\\`POST $CI_SERVER_URL/api/v4/projects/$CI_PROJECT_ID/merge_requests/:iid/notes\\\`\\n - Create MR: \\n \\\`POST $CI_SERVER_URL/api/v4/projects/$CI_PROJECT_ID/merge_requests\\\`\\n - Get MR changes: \\n \\\`GET $CI_SERVER_URL/api/v4/projects/$CI_PROJECT_ID/merge_requests/:iid/changes\\\`\\n\\n\\n## Fallback API Auth (if MCP lacks a method)\\n- Base URL: \\\`$CI_SERVER_URL/api/v4\\\`\\n- Project: \\\`$CI_PROJECT_ID\\\`\\n- Header: \\\`Private-Token: $GITLAB_PERSONAL_ACCESS_TOKEN\\\`\\n\\n## Output Discipline (MR)\\n- Prefer \\\`gitlab-mcp\\\` tool calls; if unavailable, provide explicit REST calls (method, url, headers, body).\\n- At the end, print a **plain-text** summary to STDOUT including:\\n - \\\`source_branch\\\` and \\\`target_branch\\\`\\n - commits pushed (short SHAs)\\n - number of files changed\\n - CI status/result\\n - reviewers requested (if any)\\n- Do **not** merge the MR yourself under any circumstance.\\n"'
1516
+ - claude -p "$PROMPT" --permission-mode acceptEdits --allowedTools "Bash(*) Read(*) Edit(*) Write(*) mcp__gitlab" --verbose --debug
1517
+ rules:
1518
+ - if: $CI_MERGE_REQUEST_ID
1519
+ when: always
1520
+ - when: never
1521
+ - when: never
1522
+ if: $CI_PIPELINE_SOURCE == "trigger"
1523
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_COMMIT_MESSAGE !~ /^chore\\(release\\).*/
1524
+ - if: $CI_MERGE_REQUEST_ID
1525
+ when: always
1526
+ - when: never
1527
+ - when: never
1528
+ if: $CI_PIPELINE_SOURCE == "trigger"
1529
+ - if: $CI_MERGE_REQUEST_ID
1530
+ - if: $CI_MERGE_REQUEST_ID
1531
+ when: always
1532
+ - when: never
1533
+ - when: never
1534
+ if: $CI_PIPELINE_SOURCE == "trigger"
1535
+ - if: $CI_COMMIT_TAG
1536
+ retry: *a1
1537
+ interruptible: true
1538
+ create release:
1539
+ stage: release
1540
+ image: path/to/docker/semantic-release:the-version
1541
+ script:
1542
+ - semanticRelease
1543
+ - echo '👉 The project access token might be invald - run \`project-renew-token\` in catladder CLI to fix.'
1544
+ rules:
1545
+ - &a2
1546
+ if: $CI_COMMIT_MESSAGE =~ /^chore\\(release\\).*/
1547
+ when: never
1548
+ - &a3
1549
+ if: $CI_PIPELINE_SOURCE == "trigger"
1550
+ when: never
1551
+ - &a4
1552
+ if: $CI_PIPELINE_SOURCE == "schedule"
1553
+ when: never
1554
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $AUTO_RELEASE == "true"
1555
+ when: on_success
1556
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
1557
+ when: manual
1558
+ - if: $CI_COMMIT_BRANCH =~ /^[0-9]+.([0-9]+|x).x$/
1559
+ when: manual
1560
+ ⚠️ force create release:
1561
+ stage: release
1562
+ image: path/to/docker/semantic-release:the-version
1563
+ script:
1564
+ - semanticRelease
1565
+ - echo '👉 The project access token might be invald - run \`project-renew-token\` in catladder CLI to fix.'
1566
+ rules:
1567
+ - *a2
1568
+ - *a3
1569
+ - *a4
1570
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
1571
+ when: manual
1572
+ - if: $CI_COMMIT_BRANCH =~ /^[0-9]+.([0-9]+|x).x$/
1573
+ when: manual
1574
+ needs: []
1575
+ "
1576
+ `;