-
Notifications
You must be signed in to change notification settings - Fork 8
434 lines (392 loc) · 17.3 KB
/
Copy pathdocker-build-push.yml
File metadata and controls
434 lines (392 loc) · 17.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
# Auto-triggered on merge to `test`. Builds changed service images, pushes to
# ghcr.io, then updates image tags in icipe-official/VA-Cube-Configs.
#
# Repository secrets used by this workflow:
# GITHUB_TOKEN - auto-provided by Actions; do not set manually
# TOKEN_KEY_UAT - baked into the `ui` image at build time as
# NEXT_PUBLIC_TOKEN_KEY. Rotating requires a UI rebuild.
# REPO_ACCESS_TOKEN - PAT with contents:write on icipe-official/VA-Cube-Configs.
# Used by the update-configs job to push the image-tag commit.
#
# Edit secrets at: Settings -> Secrets and variables -> Actions.
# Full reference + rotation steps: docs/SMG/08-deployment.md
# ("Managing the test/UAT secrets").
name: Build and Push Docker Images
on:
push:
branches:
- test
- main
pull_request:
types: [closed]
branches:
- test
- main
workflow_dispatch:
inputs:
branch:
description: "Branch to check for changes"
required: true
default: "test"
services:
description: 'Comma-separated list of services to build (e.g., ui,api,help,tileserver,umami,ingestionapi,nginx,occurrencegeojob) or "all"'
required: true
default: "all"
jobs:
set-deployment-environment:
name: Set the GitHub deployment environment to use based on git branch.
runs-on: ubuntu-latest
outputs:
deployment_environment: ${{ steps.determine-env.outputs.deployment_environment }}
steps:
- id: determine-env
run: |
# For pull_request events, use base_ref (target branch)
# For push events, use ref_name (current branch)
# For workflow_dispatch, use the branch input
if [ "${{ github.event_name }}" = "pull_request" ]; then
TARGET_BRANCH="${{ github.base_ref }}"
elif [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
TARGET_BRANCH="${{ github.event.inputs.branch }}"
else
TARGET_BRANCH="${{ github.ref_name }}"
fi
if [ "$TARGET_BRANCH" = "main" ]; then
echo "deployment_environment=production" >> $GITHUB_OUTPUT
elif [ "$TARGET_BRANCH" = "test" ]; then
echo "deployment_environment=test" >> $GITHUB_OUTPUT
fi
detect-changes:
name: Detect changes for ${{ needs.set-deployment-environment.outputs.deployment_environment }} deployment environment
needs: set-deployment-environment
runs-on: ubuntu-latest
environment: ${{ needs.set-deployment-environment.outputs.deployment_environment }}
outputs:
changed_services: ${{ steps.detect-changes.outputs.changed_services }}
api_changed: ${{ steps.detect-changes.outputs.api_changed }}
ui_changed: ${{ steps.detect-changes.outputs.ui_changed }}
occurrencegeojob_changed: ${{ steps.detect-changes.outputs.occurrencegeojob_changed }}
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set Diff Range
id: diff-range
run: |
if [[ "${{ github.event_name }}" == "pull_request" && "${{ github.event.pull_request.merged }}" == "true" ]]; then
echo "HEAD_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV
echo "BASE_SHA=$(git rev-parse HEAD^1)" >> $GITHUB_ENV
else
echo "HEAD_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV
echo "BASE_SHA=$(git rev-parse HEAD^1)" >> $GITHUB_ENV
fi
- name: Detect Changed Services
id: detect-changes
run: |
declare -A SERVICES=(
["ui"]="src/UI"
["api"]="src/API"
["help"]="src/Help"
["tileserver"]="src/TileServer"
["docker-umami"]="src/Docker/umami" # changed to docker-umami for avaialable public ghcr
["ingestionapi"]="src/IngestionAPI"
["nginx"]="src/Docker/nginx"
["occurrencegeojob"]="src/OccurrenceGeoJob"
)
CHANGED_SERVICES=""
API_CHANGED="false"
UI_CHANGED="false"
OCCURRENCEGEOJOB_CHANGED="false"
for service in "${!SERVICES[@]}"; do
if git diff --name-only "$BASE_SHA" "$HEAD_SHA" | grep -q "^${SERVICES[$service]}/"; then
CHANGED_SERVICES+="$service,"
if [[ "$service" == "api" ]]; then API_CHANGED="true"; fi
if [[ "$service" == "ui" ]]; then UI_CHANGED="true"; fi
if [[ "$service" == "occurrencegeojob" ]]; then OCCURRENCEGEOJOB_CHANGED="true"; fi
fi
done
echo "changed_services=${CHANGED_SERVICES%,}" >> $GITHUB_OUTPUT
echo "api_changed=$API_CHANGED" >> $GITHUB_OUTPUT
echo "ui_changed=$UI_CHANGED" >> $GITHUB_OUTPUT
echo "occurrencegeojob_changed=$OCCURRENCEGEOJOB_CHANGED" >> $GITHUB_OUTPUT
api-ci:
name: API CI for ${{ needs.set-deployment-environment.outputs.deployment_environment }} deployment environment
runs-on: ubuntu-latest
needs: [set-deployment-environment, detect-changes]
environment: ${{ needs.set-deployment-environment.outputs.deployment_environment }}
if: |
needs.detect-changes.outputs.api_changed == 'true' ||
(
github.event_name == 'workflow_dispatch' &&
(
contains(github.event.inputs.services, 'api') ||
github.event.inputs.services == 'all'
)
)
defaults:
run:
working-directory: src/API
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 22
cache: "npm"
- run: npm ci
- run: npm run build
- run: npm run lint
ui-ci:
name: UI CI for ${{ needs.set-deployment-environment.outputs.deployment_environment }} deployment environment
runs-on: ubuntu-latest
needs: [set-deployment-environment, detect-changes]
environment: ${{ needs.set-deployment-environment.outputs.deployment_environment }}
if: |
needs.detect-changes.outputs.ui_changed == 'true' ||
(
github.event_name == 'workflow_dispatch' &&
(
contains(github.event.inputs.services, 'ui') ||
github.event.inputs.services == 'all'
)
)
defaults:
run:
working-directory: src/UI
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
cache: "npm"
- run: npm ci
- run: npm run build
- run: npm run lint
occurrencegeojob-ci:
name: OccurrenceGeoJob CI for ${{ needs.set-deployment-environment.outputs.deployment_environment }} deployment environment
runs-on: ubuntu-latest
needs: [set-deployment-environment, detect-changes]
environment: ${{ needs.set-deployment-environment.outputs.deployment_environment }}
if: |
needs.detect-changes.outputs.occurrencegeojob_changed == 'true' ||
(
github.event_name == 'workflow_dispatch' &&
(
contains(github.event.inputs.services, 'occurrencegeojob') ||
github.event.inputs.services == 'all'
)
)
defaults:
run:
working-directory: src/OccurrenceGeoJob
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 20
cache: "npm"
- run: npm ci
- run: npm run build
- run: npm run lint
build-and-push:
name: Build and Push Docker Images for ${{ needs.set-deployment-environment.outputs.deployment_environment }} deployment environment
runs-on: ubuntu-latest
environment: ${{ needs.set-deployment-environment.outputs.deployment_environment }}
needs:
[
set-deployment-environment,
detect-changes,
api-ci,
ui-ci,
occurrencegeojob-ci,
]
if: |
always() &&
(
github.event_name == 'workflow_dispatch' ||
needs.detect-changes.outputs.changed_services != ''
) &&
(
needs.api-ci.result != 'failure' &&
needs.ui-ci.result != 'failure' &&
needs.occurrencegeojob-ci.result != 'failure'
)
# --- ADD OR UPDATE THIS OUTPUTS SECTION ---
outputs:
short_sha: ${{ steps.build-push-step.outputs.short_sha }}
built_services_with_sha: ${{ steps.build-push-step.outputs.built_services_with_sha }} # <--- NEW OUTPUT HERE
# -------------------------------------------
steps:
- name: Checkout Code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Log in to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Determine SHA prefix based on environment
id: sha-prefix
run: |
if [ "${{ needs.set-deployment-environment.outputs.deployment_environment }}" = "production" ]; then
echo "SHA_PREFIX=production-" >> $GITHUB_OUTPUT
elif [ "${{ needs.set-deployment-environment.outputs.deployment_environment }}" = "test" ]; then
echo "SHA_PREFIX=test-" >> $GITHUB_OUTPUT
else
echo "SHA_PREFIX=" >> $GITHUB_OUTPUT
fi
- name: Build and Push Images
id: build-push-step # Make sure this step has an ID
run: |
declare -A SERVICES=(
["ui"]="src/UI"
["api"]="src/API"
["help"]="src/Help"
["tileserver"]="src/TileServer"
["docker-umami"]="src/Docker/umami" # changed to docker-umami for avaialable public ghcr
["ingestionapi"]="src/IngestionAPI"
["nginx"]="src/Docker/nginx"
["occurrencegeojob"]="src/OccurrenceGeoJob"
)
SELECTED="${{ needs.detect-changes.outputs.changed_services }}"
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
SELECTED="${{ github.event.inputs.services }}"
if [[ "$SELECTED" == "all" ]]; then
SELECTED=$(IFS=','; echo "${!SERVICES[*]}" | tr ' ' ',')
fi
fi
IFS=',' read -ra TO_BUILD <<< "$SELECTED"
SHORT_SHA=$(git rev-parse --short HEAD)
echo "Detected SHORT_SHA: $SHORT_SHA"
echo "short_sha=$SHORT_SHA" >> $GITHUB_OUTPUT # This exports the overall SHA
# --- NEW LOGIC: Prepare output for built services and their SHAs ---
BUILT_SERVICES_OUTPUT=""
first_service=true
cd src
chmod +x buildVersionFiles.sh
./buildVersionFiles.sh
cd ..
# Get the SHA prefix based on environment
SHA_PREFIX="${{ steps.sha-prefix.outputs.SHA_PREFIX }}"
echo "Using SHA prefix: $SHA_PREFIX"
for image_name in "${TO_BUILD[@]}"; do
dir="${SERVICES[$image_name]}"
echo "Building and pushing $image_name from $dir"
LATEST_TAG="ghcr.io/${{ github.repository_owner }}/${image_name}:latest"
PREFIXED_SHA="${SHA_PREFIX}${SHORT_SHA}"
SHA_TAG="ghcr.io/${{ github.repository_owner }}/${image_name}:${PREFIXED_SHA}"
if [[ "$image_name" == "ui" ]]; then
docker build \
--build-arg NEXT_PUBLIC_TOKEN_KEY="${{ secrets.TOKEN_KEY_UAT }}" \
--build-arg NEXT_PUBLIC_AUTH_ENDPOINT="${{ secrets.NEXT_PUBLIC_AUTH_ENDPOINT }}" \
--build-arg NEXT_PUBLIC_ANALYTICS_ID="${{ secrets.NEXT_PUBLIC_ANALYTICS_ID }}" \
--build-arg NEXT_PUBLIC_ANALYTICS_URL="${{ secrets.NEXT_PUBLIC_ANALYTICS_URL }}" \
--build-arg NEXT_PUBLIC_MAX_UPLOAD_SIZE="${{ secrets.NEXT_PUBLIC_MAX_UPLOAD_SIZE }}" \
--no-cache \
-t "$LATEST_TAG" -t "$SHA_TAG" "$dir"
elif [[ "$image_name" == "docker-umami" ]]; then
docker build \
--build-arg BASE_PATH="${{ secrets.UMAMI_BUILD_ARG_BASE_PATH }}" \
--no-cache \
-t "$LATEST_TAG" -t "$SHA_TAG" "$dir"
else
docker build -t "$LATEST_TAG" -t "$SHA_TAG" "$dir"
fi
docker push "$LATEST_TAG"
docker push "$SHA_TAG"
# Append to output string in 'service_name:sha' format with prefix
if [ "$first_service" = true ]; then
BUILT_SERVICES_OUTPUT+="${image_name}:${PREFIXED_SHA}"
first_service=false
else
BUILT_SERVICES_OUTPUT+=",${image_name}:${PREFIXED_SHA}"
fi
done
# Export the list of built services and their specific SHAs
echo "built_services_with_sha=$BUILT_SERVICES_OUTPUT" >> $GITHUB_OUTPUT
# -----------------------------------------------------------
update-configs:
name: Update Values YAML with SHA Tags for ${{ needs.set-deployment-environment.outputs.deployment_environment }} deployment environment
runs-on: ubuntu-latest
needs: [set-deployment-environment, build-and-push]
if: always() # Keep this as 'always()' for now for continued debugging.
permissions:
contents: write
steps:
- name: Checkout VA-Cube-Configs repository
uses: actions/checkout@v4
with:
repository: icipe-official/VA-Cube-Configs
ssh-key: ${{ secrets.VA_CUBE_CONFIG_SSH_KEY }} # Switch to deploy keys
path: VA-Cube-Configs # Checkout into this subdirectory
fetch-depth: 0
- name: Set up YQ (YAML processor)
run: |
sudo wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/local/bin/yq && sudo chmod +x /usr/local/bin/yq
- name: Determine helm values file path and SHA prefix
id: helm-path
run: |
if [ "${{ needs.set-deployment-environment.outputs.deployment_environment }}" = "production" ]; then
echo "HELM_VALUES_PATH=app-prod/helm-values.yaml" >> $GITHUB_OUTPUT
echo "SHA_PREFIX=production-" >> $GITHUB_OUTPUT
elif [ "${{ needs.set-deployment-environment.outputs.deployment_environment }}" = "test" ]; then
echo "HELM_VALUES_PATH=app/helm-values.yaml" >> $GITHUB_OUTPUT
echo "SHA_PREFIX=test-" >> $GITHUB_OUTPUT
else
echo "HELM_VALUES_PATH=values.yaml" >> $GITHUB_OUTPUT
echo "SHA_PREFIX=" >> $GITHUB_OUTPUT
fi
echo "GIT_BRANCH=main" >> $GITHUB_OUTPUT
- name: Update values.yaml with new SHA Tags
run: |
set -euo pipefail
updated_any=0
# Get the helm values file path and SHA prefix based on environment
HELM_FILE="${{ steps.helm-path.outputs.HELM_VALUES_PATH }}"
GIT_BRANCH="${{ steps.helm-path.outputs.GIT_BRANCH }}"
SHA_PREFIX="${{ steps.helm-path.outputs.SHA_PREFIX }}"
echo "Updating helm values file: $HELM_FILE"
echo "Target branch: $GIT_BRANCH"
echo "SHA prefix: $SHA_PREFIX"
# --- Get the new output from build-and-push job ---
BUILT_SERVICES_WITH_SHA="${{ needs.build-and-push.outputs.built_services_with_sha }}"
echo "Services built and their SHAs received: ${BUILT_SERVICES_WITH_SHA}"
# Exit gracefully if no services were built/pushed
if [ -z "$BUILT_SERVICES_WITH_SHA" ]; then
echo "No services reported as built in the previous job. No values.yaml updates will be performed."
exit 0 # Exit with success
fi
# Loop through the 'service_name:sha' pairs and update only those tags
IFS=',' read -ra BUILT_SERVICE_PAIRS <<< "$BUILT_SERVICES_WITH_SHA"
for pair in "${BUILT_SERVICE_PAIRS[@]}"; do
img_key=$(echo "$pair" | cut -d':' -f1) # Extract service name
current_image_sha=$(echo "$pair" | cut -d':' -f2) # Extract SHA which already includes prefix
if [[ "$img_key" == "docker-umami" ]]; then
img_key="umami"
fi
yq_path=".images.${img_key}.tag"
# Reference the appropriate helm-values.yaml file
EXISTING_TAG=$(yq e "${yq_path}" VA-Cube-Configs/$HELM_FILE || echo "NOT_FOUND")
if [[ "$EXISTING_TAG" != "$current_image_sha" ]]; then
echo "Updating ${yq_path} from '${EXISTING_TAG}' to '${current_image_sha}'"
# Reference the appropriate helm-values.yaml file
yq e "${yq_path} = \"${current_image_sha}\"" -i VA-Cube-Configs/$HELM_FILE
updated_any=1
else
echo "${img_key} tag in $HELM_FILE is already up to date: ${current_image_sha}"
fi
done
if [ "$updated_any" -eq 1 ]; then
echo "Changes detected in $HELM_FILE. Committing and pushing."
# Change directory to the checked-out repo before git commands
cd VA-Cube-Configs
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add $HELM_FILE
git commit -m "chore(deps): Update image tags to latest SHAs for ${{ needs.set-deployment-environment.outputs.deployment_environment }} deployment environment" || echo "No changes to commit"
# Push using the SSH deploy key to the other repository
git push git@github.com:/icipe-official/VA-Cube-Configs.git HEAD:$GIT_BRANCH
else
echo "No image tag updates required."
fi