From 4858f945a365c62415f91ce1b9e242226a19545a Mon Sep 17 00:00:00 2001 From: Pavlo Strunkin Date: Sat, 24 Oct 2026 10:41:26 +0300 Subject: [PATCH 1/3] ci(docker): build and publish the ui image for amd64 and arm64 The published ui image is linux/amd64 only, so on Apple Silicon and other arm64 hosts it runs under emulation. Add a workflow that builds it with buildx/QEMU for linux/amd64 and linux/arm64, publishes it on v* tags (or a manual run for an existing tag) and only builds it on pull requests that touch the image. The builder stage runs on the build platform, since its output is static files. Refs Visual-Regression-Tracker/Visual-Regression-Tracker#351 Co-Authored-By: Claude Opus 5.5 --- .github/workflows/docker.yml | 72 ++++++++++++++++++++++++++++++++++++ Dockerfile | 3 +- 2 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/docker.yml diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 00000000..a8b6e06d --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,72 @@ +name: Docker image + +# Builds visualregressiontracker/ui for linux/amd64 and linux/arm64 (Apple Silicon, +# Graviton), so docker compose runs it natively instead of under emulation. +# - pushing a vX.Y.Z tag publishes the image as X.Y.Z +# - "Run workflow" with an existing tag (re)publishes it, e.g. to add arm64 to a released version +# - pull requests that touch the image only build it, without pushing +# Publishing needs the DOCKERHUB_USERNAME and DOCKERHUB_TOKEN repository secrets. + +on: + push: + tags: + - 'v*' + pull_request: + branches: [master] + paths: + - Dockerfile + - env.sh + - nginx/** + - .github/workflows/docker.yml + workflow_dispatch: + inputs: + tag: + description: Existing tag to publish, e.g. v5.6.0 + required: true + +jobs: + docker: + runs-on: ubuntu-latest + + steps: + - name: Resolve version + id: version + env: + TAG: ${{ inputs.tag || github.ref_name }} + run: | + if [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then + echo "push=false" >> "$GITHUB_OUTPUT" + elif [ "${TAG#v}" != "$TAG" ]; then + echo "push=true" >> "$GITHUB_OUTPUT" + echo "version=${TAG#v}" >> "$GITHUB_OUTPUT" + else + echo "::error::Tag $TAG does not look like vX.Y.Z" + exit 1 + fi + + - uses: actions/checkout@v4 + with: + ref: ${{ inputs.tag || github.ref }} + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Docker Hub + if: steps.version.outputs.push == 'true' + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: . + platforms: linux/amd64,linux/arm64 + push: ${{ steps.version.outputs.push == 'true' }} + tags: visualregressiontracker/ui:${{ steps.version.outputs.version || 'ci' }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/Dockerfile b/Dockerfile index 83d49312..16485a46 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,7 @@ ### STAGE 1: Build ### # This image is around 50 megabytes -FROM node:20-alpine AS builder +# The built ui is static files, so build it once on the native platform for every target platform +FROM --platform=$BUILDPLATFORM node:20-alpine AS builder # Create app directory WORKDIR /app From efac18b622c5cb86b2fda88500bebc1113649a94 Mon Sep 17 00:00:00 2001 From: Pavlo Strunkin Date: Sat, 24 Oct 2026 10:53:07 +0300 Subject: [PATCH 2/3] ci(docker): pin the docker actions to commit SHAs Co-Authored-By: Claude Opus 5.5 --- .github/workflows/docker.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index a8b6e06d..843e096c 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -49,20 +49,20 @@ jobs: ref: ${{ inputs.tag || github.ref }} - name: Set up QEMU - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 - name: Log in to Docker Hub if: steps.version.outputs.push == 'true' - uses: docker/login-action@v3 + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push - uses: docker/build-push-action@v6 + uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 with: context: . platforms: linux/amd64,linux/arm64 From 4a1dcb4bd7a9ebf7e1a2433bcb69a4161bf97c01 Mon Sep 17 00:00:00 2001 From: Pavlo Strunkin Date: Sat, 24 Oct 2026 12:01:57 +0300 Subject: [PATCH 3/3] ci(docker): check out release tags explicitly and drop token persistence - workflow_dispatch checks out refs/tags/, so a branch with the same name can't be published under a release version - persist-credentials: false keeps GITHUB_TOKEN out of .git/config, which is part of the build context - permissions: contents: read; pushes use the Docker Hub secrets Addresses CodeRabbit review on backend#412. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/docker.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 843e096c..bbf66619 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -24,6 +24,10 @@ on: description: Existing tag to publish, e.g. v5.6.0 required: true +# GITHUB_TOKEN is only used to check out the code; image pushes use the Docker Hub secrets +permissions: + contents: read + jobs: docker: runs-on: ubuntu-latest @@ -46,7 +50,10 @@ jobs: - uses: actions/checkout@v4 with: - ref: ${{ inputs.tag || github.ref }} + # a manual run checks out the tag itself, never a branch with the same name + ref: ${{ inputs.tag && format('refs/tags/{0}', inputs.tag) || github.ref }} + # keep the token out of .git/config, which is part of the build context + persist-credentials: false - name: Set up QEMU uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0