Skip to content

Commit 3e6d5c9

Browse files
authored
ci(docker): images should have independent major minor tags (#3406)
This PR refactors the image building, tagging and pushing github actions so that an appropriate hierarchy of tags are created. These changes was extensively tested on a fork under my personal github account. You can view the actions logs here. Changes proposed in this pull request Tag independent minor and major docker images on releases Refactoring of CI workflow Performance test CI job modified to skip automatic commenting if PR is from a fork like this one On releasing of new version v1.1.1 images created and pushed for the following tags package_name v1.1.1 package_name v1.1 package_name v1 On releasing of new version v1.1.1-beta images created and pushed for the following tags package_name v1.1.1-beta package_name v1.1-beta package_name v1-beta If any of the of the minor or major tags already exist we will simply override them.
1 parent f5b325f commit 3e6d5c9

File tree

4 files changed

+219
-42
lines changed

4 files changed

+219
-42
lines changed
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
name: "Version hierarchy image pusher"
2+
description: "Will re-tag the docker image to create images for parent versions. For example, if the image is tagged 1.2.3, it will create a tag for 1.2 and 1.0 as well."
3+
4+
inputs:
5+
app_name:
6+
description: "The name of the application."
7+
required: true
8+
package:
9+
required: true
10+
description: "Package we are building, for example, 'rafiki-auth' or 'rafiki-backend'."
11+
platform_name:
12+
required: true
13+
description: "Platform we are building for, for example, 'amd64' or 'arm64'."
14+
gh_token:
15+
description: "GitHub token to use for authentication."
16+
required: true
17+
version:
18+
required: true
19+
description: "Version we are tagging as, for example v1.2.3 or v1.2.3-rc1"
20+
21+
22+
runs:
23+
using: "composite"
24+
steps:
25+
- name: Calculate version hierarchy
26+
id: hierarchy
27+
uses: ./.github/actions/parent-versions
28+
with:
29+
version: ${{ inputs.version }}
30+
- name: Fetch docker image from cache
31+
uses: actions/cache/restore@v4
32+
with:
33+
path: /tmp/${{ github.sha }}-${{ inputs.package }}-${{ inputs.platform_name }}-${{ inputs.version }}.tar
34+
key: ${{ github.sha }}-${{ inputs.package }}-${{ inputs.platform_name }}-${{ inputs.version }}
35+
fail-on-cache-miss: true
36+
- name: Set up QEMU
37+
uses: docker/setup-qemu-action@v3
38+
- name: Set up Docker Buildx
39+
uses: docker/setup-buildx-action@v3
40+
- name: Login to GHCR
41+
uses: docker/login-action@v3
42+
with:
43+
registry: ghcr.io
44+
username: ${{ github.repository_owner }}
45+
password: ${{ inputs.gh_token }}
46+
- name: Load image into Docker
47+
shell: bash
48+
run: |
49+
docker load --input /tmp/${{ github.sha }}-${{ inputs.package }}-${{ inputs.platform_name }}-${{ inputs.version }}.tar
50+
- name: List docker images
51+
shell: bash
52+
run: docker images
53+
- name: Push to registry
54+
shell: bash
55+
run: |
56+
echo "Pushing image to registry"
57+
docker push ghcr.io/${{ github.repository_owner }}/${{ inputs.app_name }}-${{ inputs.package }}-${{ inputs.platform_name }}:${{ inputs.version }}
58+
- name: Tag and push parent versions
59+
shell: bash
60+
if: ${{ steps.hierarchy.outputs.has_hierarchy == 'true' }}
61+
run: |
62+
echo "Tagging parent versions with ${{ inputs.version }}, ${{ steps.hierarchy.outputs.minor_parent }} and ${{ steps.hierarchy.outputs.major_parent }}"
63+
docker tag ghcr.io/${{ github.repository_owner }}/${{ inputs.app_name }}-${{ inputs.package }}-${{ inputs.platform_name }}:${{ inputs.version }} ghcr.io/${{ github.repository_owner }}/${{ inputs.app_name}}-${{ inputs.package }}-${{ inputs.platform_name }}:${{ steps.hierarchy.outputs.major_parent }}
64+
docker tag ghcr.io/${{ github.repository_owner }}/${{ inputs.app_name }}-${{ inputs.package }}-${{ inputs.platform_name }}:${{ inputs.version }} ghcr.io/${{ github.repository_owner }}/${{ inputs.app_name}}-${{ inputs.package }}-${{ inputs.platform_name }}:${{ steps.hierarchy.outputs.minor_parent }}
65+
66+
echo "Pushing parent tagged images to registry"
67+
docker push ghcr.io/${{ github.repository_owner }}/${{ inputs.app_name }}-${{ inputs.package }}-${{ inputs.platform_name }}:${{ steps.hierarchy.outputs.major_parent }}
68+
docker push ghcr.io/${{ github.repository_owner }}/${{ inputs.app_name }}-${{ inputs.package }}-${{ inputs.platform_name }}:${{ steps.hierarchy.outputs.minor_parent }}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
name: "Push manifest list for arm64 and amd64"
2+
3+
inputs:
4+
app_name:
5+
description: "The name of the application."
6+
required: true
7+
package:
8+
required: true
9+
gh_token:
10+
description: "GitHub token to use for authentication."
11+
required: true
12+
version:
13+
required: true
14+
description: "Version we are tagging as, for example v1.2.3 or v1.2.3-rc1"
15+
16+
runs:
17+
using: "composite"
18+
steps:
19+
- name: Calculate version hierarchy
20+
id: hierarchy
21+
uses: ./.github/actions/parent-versions
22+
with:
23+
version: ${{ inputs.version }}
24+
25+
- name: Login to GHCR
26+
uses: docker/login-action@v3
27+
with:
28+
registry: ghcr.io
29+
username: ${{ github.repository_owner }}
30+
password: ${{ inputs.gh_token }}
31+
- name: Create manifest list with parent versions
32+
if: steps.hierarchy.outputs.has_hierarchy == 'true'
33+
shell: bash
34+
run: |
35+
docker manifest create ghcr.io/${{ github.repository_owner }}/${{ inputs.app_name }}-${{ inputs.package }}:${{ inputs.version }} \
36+
--amend ghcr.io/${{ github.repository_owner }}/${{ inputs.app_name }}-${{ inputs.package }}-amd64:${{ inputs.version }} \
37+
--amend ghcr.io/${{ github.repository_owner }}/${{ inputs.app_name }}-${{ inputs.package }}-arm64:${{ inputs.version }}
38+
39+
docker manifest create ghcr.io/${{ github.repository_owner }}/${{ inputs.app_name }}-${{ inputs.package }}:${{ steps.hierarchy.outputs.minor_parent }} \
40+
--amend ghcr.io/${{ github.repository_owner }}/${{ inputs.app_name }}-${{ inputs.package }}-amd64:${{ steps.hierarchy.outputs.minor_parent }} \
41+
--amend ghcr.io/${{ github.repository_owner }}/${{ inputs.app_name }}-${{ inputs.package }}-arm64:${{ steps.hierarchy.outputs.minor_parent }}
42+
43+
docker manifest create ghcr.io/${{ github.repository_owner }}/${{ inputs.app_name }}-${{ inputs.package }}:${{ steps.hierarchy.outputs.major_parent }} \
44+
--amend ghcr.io/${{ github.repository_owner }}/${{ inputs.app_name }}-${{ inputs.package }}-amd64:${{ steps.hierarchy.outputs.major_parent }} \
45+
--amend ghcr.io/${{ github.repository_owner }}/${{ inputs.app_name }}-${{ inputs.package }}-arm64:${{ steps.hierarchy.outputs.major_parent }}
46+
- name: Create manifest list without parent versions
47+
if: steps.hierarchy.outputs.has_hierarchy != 'true'
48+
shell: bash
49+
run: |
50+
docker manifest create ghcr.io/${{ github.repository_owner }}/${{ inputs.app_name }}-${{ inputs.package }}:${{ inputs.version }} \
51+
--amend ghcr.io/${{ github.repository_owner }}/${{ inputs.app_name }}-${{ inputs.package }}-amd64:${{ inputs.version }} \
52+
--amend ghcr.io/${{ github.repository_owner }}/${{ inputs.app_name }}-${{ inputs.package }}-arm64:${{ inputs.version }}
53+
- name: Push manifest list
54+
shell: bash
55+
run: |
56+
docker manifest push ghcr.io/${{ github.repository_owner }}/${{ inputs.app_name }}-${{ inputs.package }}:${{ inputs.version }}
57+
- name: Push manifests of parent versions
58+
if: steps.hierarchy.outputs.has_hierarchy == 'true'
59+
shell: bash
60+
run: |
61+
docker manifest push ghcr.io/${{ github.repository_owner }}/${{ inputs.app_name }}-${{ inputs.package }}:${{ steps.hierarchy.outputs.minor_parent }}
62+
docker manifest push ghcr.io/${{ github.repository_owner }}/${{ inputs.app_name }}-${{ inputs.package }}:${{ steps.hierarchy.outputs.major_parent }}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
name: Version hierarchy calculator
2+
3+
inputs:
4+
version:
5+
description: "Version we are tagging as, for example v1.2.3 or v1.2.3-rc1, but it can also be 'nightly' in which case no hierarchy will be generated"
6+
required: true
7+
8+
outputs:
9+
has_hierarchy:
10+
description: "Whether this version has a parent hierarchy"
11+
value: ${{ steps.calc.outputs.has_hierarchy }}
12+
version:
13+
description: "Same version string as provided as input, here for convenience"
14+
value: ${{ inputs.version }}
15+
major_parent:
16+
description: "The major parent tag (e.g. v1 or v1-rc1), empty string if no hierarchy"
17+
value: ${{ steps.calc.outputs.major_parent }}
18+
minor_parent:
19+
description: "The minor parent tag (e.g. v1.2 or v1.2-rc1), empty string if no hierarchy"
20+
value: ${{ steps.calc.outputs.minor_parent }}
21+
runs:
22+
using: "composite"
23+
steps:
24+
- name: Calculate version hierarchy
25+
id: calc
26+
shell: bash
27+
run: |
28+
# If the version is 'nightly' or some other unstructured string, we don't want to create a hierarchy
29+
if ! [[ ${{ inputs.version }} =~ ^v[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+ ]];
30+
then
31+
echo "has_hierarchy=false" >> $GITHUB_OUTPUT
32+
echo "major_parent=" >> $GITHUB_OUTPUT
33+
echo "minor_parent=" >> $GITHUB_OUTPUT
34+
exit 0
35+
fi
36+
37+
# strip leading 'v'
38+
version="${{ inputs.version }}"
39+
raw="${version#v}"
40+
# extract parts
41+
major_num="${raw%%.*}"
42+
minor_num="$(echo "$raw" | cut -d'.' -f2)"
43+
pre_release="$(echo "$raw" | grep -oP '(?<=-).*' || echo "")"
44+
45+
# build parents
46+
minor_label="v${major_num}.${minor_num}"
47+
major_label="v${major_num}"
48+
if [[ -n "$pre_release" ]]; then
49+
minor_label+="-$pre_release"
50+
major_label+="-$pre_release"
51+
fi
52+
53+
# emit outputs
54+
echo "has_hierarchy=true" >> $GITHUB_OUTPUT
55+
echo "major_parent=$major_label" >> $GITHUB_OUTPUT
56+
echo "minor_parent=$minor_label" >> $GITHUB_OUTPUT

.github/workflows/node-build.yml

Lines changed: 33 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -206,11 +206,25 @@ jobs:
206206
pnpm --filter performance run-tests:testenv -k -q --vus 4 --duration 1m | tee performance.log
207207
208208
- name: Post/Update Performance Test Results as PR Comment
209-
if: always()
209+
if: ${{ github.event_name == 'pull_request' }}
210210
uses: actions/github-script@v7
211211
with:
212212
github-token: ${{ secrets.GITHUB_TOKEN }}
213213
script: |
214+
const pr = context.payload.pull_request;
215+
if (!pr) {
216+
console.log("No PR detected, skipping comment.");
217+
return;
218+
}
219+
220+
const sourceOwner = pr.head.repo.owner.login;
221+
const targetOwner = pr.base.repo.owner.login;
222+
223+
if (sourceOwner !== targetOwner) {
224+
console.log("PR is from a fork, skipping automatic comment for security reasons.");
225+
return;
226+
}
227+
214228
const fs = require('fs');
215229
const summaryPath = './test/performance/k6-test-summary.txt';
216230
const logPath = './performance.log';
@@ -236,7 +250,6 @@ jobs:
236250
const maxLogSize = 60000;
237251
const truncatedLogs = logContent.length > maxLogSize ? `...(truncated)...\n${logContent.slice(-maxLogSize)}` : logContent;
238252
239-
240253
const commentBody = `
241254
### 🚀 Performance Test Results
242255
@@ -466,10 +479,10 @@ jobs:
466479
run: |
467480
docker images
468481
/tmp/trivy image --db-repository ghcr.io/aquasecurity/trivy-db,public.ecr.aws/aquasecurity/trivy-db --java-db-repository ghcr.io/aquasecurity/trivy-java-db,public.ecr.aws/aquasecurity/trivy-java-db --ignore-unfixed --format table --vuln-type os,library --exit-code 1 --severity HIGH --input /tmp/${{ github.sha }}-${{ matrix.package }}-${{ matrix.platform.name }}-${{ needs.version-generator.outputs.version }}.tar
469-
482+
470483
push:
471484
name: Push to registry
472-
needs: [version-generator, docker-grype, docker-trivy, version-generator, node-build]
485+
needs: [version-generator, docker-grype, docker-trivy, node-build]
473486
runs-on: ubuntu-latest
474487
if: needs.version-generator.outputs.dockerPush == 'true'
475488
strategy:
@@ -484,34 +497,18 @@ jobs:
484497
- backend
485498
- frontend
486499
steps:
487-
- name: Fetch docker image from cache
488-
uses: actions/cache/restore@v4
489-
with:
490-
path: /tmp/${{ github.sha }}-${{ matrix.package }}-${{ matrix.platform.name }}-${{ needs.version-generator.outputs.version }}.tar
491-
key: ${{ github.sha }}-${{ matrix.package }}-${{ matrix.platform.name }}-${{ needs.version-generator.outputs.version }}
492-
fail-on-cache-miss: true
493-
- name: Set up QEMU
494-
uses: docker/setup-qemu-action@v3
495-
- name: Set up Docker Buildx
496-
uses: docker/setup-buildx-action@v3
497-
- name: Login to GHCR
498-
uses: docker/login-action@v3
500+
- uses: actions/checkout@v4
501+
- uses: ./.github/actions/image-push
499502
with:
500-
registry: ghcr.io
501-
username: ${{ github.repository_owner }}
502-
password: ${{ secrets.GITHUB_TOKEN }}
503-
- name: Load image into Docker
504-
run: |
505-
docker load --input /tmp/${{ github.sha }}-${{ matrix.package }}-${{ matrix.platform.name }}-${{ needs.version-generator.outputs.version }}.tar
506-
- name: List docker images
507-
run: docker images
508-
- name: Push to registry
509-
run: |
510-
docker push ghcr.io/${{ github.repository_owner }}/rafiki-${{ matrix.package }}-${{ matrix.platform.name }}:${{ needs.version-generator.outputs.version }}
503+
app_name: rafiki
504+
package: ${{ matrix.package }}
505+
platform_name: ${{ matrix.platform.name }}
506+
version: ${{ needs.version-generator.outputs.version }}
507+
gh_token: ${{ secrets.GITHUB_TOKEN }}
511508

512509
push-manifest:
513510
name: Push multi-arch manifest list
514-
needs: [version-generator, push]
511+
needs: [version-generator,push]
515512
runs-on: ubuntu-latest
516513
if: needs.version-generator.outputs.dockerPush == 'true'
517514
strategy:
@@ -521,20 +518,14 @@ jobs:
521518
- backend
522519
- frontend
523520
steps:
524-
- name: Login to GHCR
525-
uses: docker/login-action@v3
526-
with:
527-
registry: ghcr.io
528-
username: ${{ github.repository_owner }}
529-
password: ${{ secrets.GITHUB_TOKEN }}
530-
- name: Create manifest list
531-
run: |
532-
docker manifest create ghcr.io/${{ github.repository_owner }}/rafiki-${{ matrix.package }}:${{ needs.version-generator.outputs.version }} \
533-
--amend ghcr.io/${{ github.repository_owner }}/rafiki-${{ matrix.package }}-amd64:${{ needs.version-generator.outputs.version }} \
534-
--amend ghcr.io/${{ github.repository_owner }}/rafiki-${{ matrix.package }}-arm64:${{ needs.version-generator.outputs.version }}
521+
- uses: actions/checkout@v4
535522
- name: Push manifest list
536-
run: |
537-
docker manifest push ghcr.io/${{ github.repository_owner }}/rafiki-${{ matrix.package }}:${{ needs.version-generator.outputs.version }}
523+
uses: ./.github/actions/manifest-push
524+
with:
525+
app_name: rafiki
526+
package: ${{ matrix.package }}
527+
gh_token: ${{ secrets.GITHUB_TOKEN }}
528+
version: ${{ needs.version-generator.outputs.version }}
538529

539530
generate-release:
540531
runs-on: ubuntu-latest
@@ -551,7 +542,7 @@ jobs:
551542
tag: ${{ needs.version-generator.outputs.version }}
552543
includeRefIssues: false
553544
- name: Create Release
554-
uses: ncipollo/release-action@v1.15.0
545+
uses: ncipollo/release-action@v1.16.0
555546
with:
556547
allowUpdates: true
557548
draft: false

0 commit comments

Comments
 (0)