Files
reader/.github/workflows/release.yml
T
hectorqinandClaude Opus 5.5 4e149c73d7 ci: release only for v* tags or manual runs; CI on main; Android SDK packages
- main is the long-lived development branch: release.yml no longer runs on
  a push to it, only on v* tags and workflow_dispatch. ci.yml now runs on
  every branch push, main included.
- android-actions/setup-android's default package list includes `tools`,
  which current command-line tools no longer carry, so sdkmanager failed;
  install exactly platform-tools, android-35 and build-tools 35.0.1.
- reader-chrome.test.ts left its React roots mounted; a scheduled commit
  could land after jsdom teardown and fail the run with an unhandled
  "Right-hand side of 'instanceof' is not an object" (all tests passing).
  Unmount in afterEach.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 10:19:56 +00:00

125 lines
4.1 KiB
YAML

# Release the single-container image (server + web) to Docker Hub for amd64 and arm64.
#
# tag v1.2.3 -> hectorqin/reader-pro:1.2.3, :1.2, :latest, :sha-<short>
# manual run -> the chosen branch's name (e.g. :main) and :sha-<short>
#
# Never on a plain push: main is the long-lived development branch, and a release
# is a decision (a tag, or "Run workflow" in the Actions tab), not a side effect.
#
# CI (ci.yml) runs first; nothing is published from a red build. Each architecture
# is built on its own native runner — the arm64 image under QEMU would run npm ci
# and the Vite build emulated, which is many times slower — and pushed by digest,
# then one job stitches the digests into the multi-arch tags.
#
# Needs repository secrets DOCKER_USERNAME and DOCKER_PASSWORD (a Docker Hub
# password or access token with read/write on hectorqin/reader-pro).
name: Release
on:
push:
tags: ['v*']
workflow_dispatch:
permissions:
contents: read
concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false
env:
IMAGE: hectorqin/reader-pro
jobs:
ci:
uses: ./.github/workflows/ci.yml
build:
name: Image · ${{ matrix.platform }}
needs: ci
strategy:
fail-fast: true
matrix:
include:
- platform: linux/amd64
runner: ubuntu-24.04
- platform: linux/arm64
runner: ubuntu-24.04-arm
runs-on: ${{ matrix.runner }}
steps:
- name: Platform slug
run: echo "PLATFORM_PAIR=${PLATFORM//\//-}" >> "$GITHUB_ENV"
env:
PLATFORM: ${{ matrix.platform }}
- uses: actions/checkout@v5
- id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.IMAGE }}
- uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- uses: docker/setup-buildx-action@v3
- id: build
uses: docker/build-push-action@v6
with:
context: .
file: server/Dockerfile
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,name=${{ env.IMAGE }},push-by-digest=true,name-canonical=true,push=true
cache-from: type=gha,scope=${{ env.PLATFORM_PAIR }}
cache-to: type=gha,mode=max,scope=${{ env.PLATFORM_PAIR }}
- name: Record digest
run: |
mkdir -p "$RUNNER_TEMP/digests"
touch "$RUNNER_TEMP/digests/${DIGEST#sha256:}"
env:
DIGEST: ${{ steps.build.outputs.digest }}
- uses: actions/upload-artifact@v4
with:
name: digests-${{ env.PLATFORM_PAIR }}
path: ${{ runner.temp }}/digests/*
if-no-files-found: error
retention-days: 1
publish:
name: Image · multi-arch tags
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
path: ${{ runner.temp }}/digests
pattern: digests-*
merge-multiple: true
- id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.IMAGE }}
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha
flavor: |
latest=${{ startsWith(github.ref, 'refs/tags/v') }}
- uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- uses: docker/setup-buildx-action@v3
- name: Create manifest list and push
working-directory: ${{ runner.temp }}/digests
run: |
tags=()
while read -r tag; do tags+=(-t "$tag"); done < <(jq -r '.tags[]' <<< "$DOCKER_METADATA_OUTPUT_JSON")
refs=()
for digest in *; do refs+=("$IMAGE@sha256:$digest"); done
docker buildx imagetools create "${tags[@]}" "${refs[@]}"
- name: Inspect
run: docker buildx imagetools inspect "$IMAGE:$VERSION"
env:
VERSION: ${{ steps.meta.outputs.version }}