mirror of
https://github.com/temetro/temetro.git
synced 2026-07-26 11:58:14 +00:00
07cfd5d335
The release build emulated linux/arm64 with QEMU on the amd64 runner. A runner/QEMU update started crashing 'npm ci' under emulation (illegal instruction) and the build then hung for hours instead of failing, so v0.17.0 never published. Build each arch on its native runner instead (amd64 on ubuntu-24.04, arm64 on the free ubuntu-24.04-arm) and merge the per-arch digests into one manifest with buildx imagetools. Add per-job timeouts so a stuck build can never run for hours again. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
170 lines
5.8 KiB
YAML
170 lines
5.8 KiB
YAML
# Builds and publishes the temetro Docker images and cuts a GitHub Release.
|
||
#
|
||
# Trigger: push a semver tag, e.g.
|
||
# git tag v0.1.0 && git push origin v0.1.0
|
||
#
|
||
# Multi-arch (amd64 + arm64) is built on NATIVE runners — amd64 on ubuntu-24.04,
|
||
# arm64 on ubuntu-24.04-arm — and merged into a manifest. We do NOT emulate arm64
|
||
# with QEMU anymore: a runner/QEMU update started crashing `npm ci` under
|
||
# emulation ("illegal instruction") and hanging the build for hours.
|
||
#
|
||
# The frontend image bakes NO API URL — it resolves the backend from the host
|
||
# the browser uses at runtime — so one published image works for every clinic.
|
||
#
|
||
# Required repository secrets (Settings → Secrets and variables → Actions):
|
||
# DOCKERHUB_USERNAME — the Docker Hub account `khalidxv` (or one with push
|
||
# access to that namespace)
|
||
# DOCKERHUB_TOKEN — a Docker Hub access token for that account
|
||
# Without them the build/login step fails; the workflow is otherwise inert.
|
||
name: release
|
||
|
||
on:
|
||
push:
|
||
tags:
|
||
- "v*.*.*"
|
||
|
||
env:
|
||
REGISTRY_NAMESPACE: khalidxv
|
||
|
||
jobs:
|
||
# One build per (image × platform) on the platform's native runner, pushed to
|
||
# Docker Hub by digest (no tag yet). The merge job stitches the per-arch
|
||
# digests into a single tagged multi-arch manifest.
|
||
build:
|
||
name: Build ${{ matrix.image }} (${{ matrix.platform }})
|
||
runs-on: ${{ matrix.platform == 'linux/arm64' && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }}
|
||
timeout-minutes: 40
|
||
strategy:
|
||
fail-fast: false
|
||
matrix:
|
||
image: [backend, frontend]
|
||
platform: [linux/amd64, linux/arm64]
|
||
steps:
|
||
- name: Checkout
|
||
uses: actions/checkout@v4
|
||
|
||
- name: Prepare platform pair
|
||
run: |
|
||
platform="${{ matrix.platform }}"
|
||
echo "PLATFORM_PAIR=${platform//\//-}" >> "$GITHUB_ENV"
|
||
|
||
- name: Set up Buildx
|
||
uses: docker/setup-buildx-action@v3
|
||
|
||
- name: Log in to Docker Hub
|
||
uses: docker/login-action@v3
|
||
with:
|
||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||
|
||
- name: Build & push by digest
|
||
id: build
|
||
uses: docker/build-push-action@v6
|
||
with:
|
||
context: ./${{ matrix.image }}
|
||
platforms: ${{ matrix.platform }}
|
||
provenance: false
|
||
outputs: type=image,name=${{ env.REGISTRY_NAMESPACE }}/temetro-${{ matrix.image }},push-by-digest=true,name-canonical=true,push=true
|
||
|
||
- name: Export digest
|
||
run: |
|
||
mkdir -p "${{ runner.temp }}/digests"
|
||
digest="${{ steps.build.outputs.digest }}"
|
||
touch "${{ runner.temp }}/digests/${digest#sha256:}"
|
||
|
||
- name: Upload digest
|
||
uses: actions/upload-artifact@v4
|
||
with:
|
||
name: digests-${{ matrix.image }}-${{ env.PLATFORM_PAIR }}
|
||
path: ${{ runner.temp }}/digests/*
|
||
if-no-files-found: error
|
||
retention-days: 1
|
||
|
||
# Combine the per-arch digests for each image into one multi-arch manifest and
|
||
# tag it (X.Y.Z + latest).
|
||
merge:
|
||
name: Merge ${{ matrix.image }} manifest
|
||
runs-on: ubuntu-latest
|
||
timeout-minutes: 15
|
||
needs: build
|
||
strategy:
|
||
fail-fast: false
|
||
matrix:
|
||
image: [backend, frontend]
|
||
steps:
|
||
- name: Derive version from tag
|
||
id: meta
|
||
run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
|
||
|
||
- name: Download digests
|
||
uses: actions/download-artifact@v4
|
||
with:
|
||
path: ${{ runner.temp }}/digests
|
||
pattern: digests-${{ matrix.image }}-*
|
||
merge-multiple: true
|
||
|
||
- name: Set up Buildx
|
||
uses: docker/setup-buildx-action@v3
|
||
|
||
- name: Log in to Docker Hub
|
||
uses: docker/login-action@v3
|
||
with:
|
||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||
|
||
- name: Create manifest list and push
|
||
working-directory: ${{ runner.temp }}/digests
|
||
env:
|
||
IMAGE: ${{ env.REGISTRY_NAMESPACE }}/temetro-${{ matrix.image }}
|
||
VERSION: ${{ steps.meta.outputs.version }}
|
||
run: |
|
||
docker buildx imagetools create \
|
||
-t "$IMAGE:$VERSION" \
|
||
-t "$IMAGE:latest" \
|
||
$(printf "$IMAGE@sha256:%s " *)
|
||
|
||
- name: Inspect
|
||
env:
|
||
IMAGE: ${{ env.REGISTRY_NAMESPACE }}/temetro-${{ matrix.image }}
|
||
VERSION: ${{ steps.meta.outputs.version }}
|
||
run: docker buildx imagetools inspect "$IMAGE:$VERSION"
|
||
|
||
# Both images are published — now cut the GitHub Release with the changelog.
|
||
release:
|
||
name: GitHub Release
|
||
runs-on: ubuntu-latest
|
||
timeout-minutes: 10
|
||
needs: merge
|
||
permissions:
|
||
contents: write # create the GitHub Release (the update check reads this)
|
||
steps:
|
||
- name: Checkout
|
||
uses: actions/checkout@v4
|
||
|
||
- name: Derive version from tag
|
||
id: meta
|
||
run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
|
||
|
||
# Pull this version's section out of CHANGELOG.md so the release has real,
|
||
# human-written notes (the auto "Full Changelog" link is still appended
|
||
# below via generate_release_notes). Falls back to a generic line if the
|
||
# version has no CHANGELOG entry.
|
||
- name: Extract changelog notes
|
||
id: notes
|
||
run: |
|
||
version="${{ steps.meta.outputs.version }}"
|
||
awk -v v="$version" '
|
||
$0 ~ "^## \\[" v "\\]" {flag=1; next}
|
||
/^## \[/ {flag=0}
|
||
flag {print}
|
||
' CHANGELOG.md | sed '/./,$!d' > release-notes.md
|
||
if [ ! -s release-notes.md ]; then
|
||
echo "Release $version. See the changelog for details." > release-notes.md
|
||
fi
|
||
|
||
- name: Create GitHub Release
|
||
uses: softprops/action-gh-release@v2
|
||
with:
|
||
body_path: release-notes.md
|
||
generate_release_notes: true
|