diff --git a/.github/workflows/android-release.yml b/.github/workflows/android-release.yml index 2e82eae..724a547 100644 --- a/.github/workflows/android-release.yml +++ b/.github/workflows/android-release.yml @@ -13,6 +13,9 @@ on: description: 'Manual tag to build (e.g. v6.1.1)' required: true +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: 'true' + permissions: contents: write # needed to create GitHub releases from the runner diff --git a/.github/workflows/auto-version.yml b/.github/workflows/auto-version.yml index f720d25..f2256dc 100644 --- a/.github/workflows/auto-version.yml +++ b/.github/workflows/auto-version.yml @@ -21,6 +21,10 @@ on: push: branches: [main] +# Opt in to Node 24 runtime early (deprecation of Node 20 begins 2026-06-02) +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: 'true' + permissions: contents: write @@ -33,7 +37,14 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 - token: ${{ secrets.GITHUB_TOKEN }} + # Use RELEASE_PAT (a Personal Access Token you add as a repo + # secret) so the tag push this workflow performs actually + # triggers the downstream tag-based workflows (android-release, + # docker-publish). GITHUB_TOKEN pushes are deliberately + # blocked from triggering other workflows by GitHub. + # Fine-grained PAT with "Contents: Read and write" on this + # repo is enough. + token: ${{ secrets.RELEASE_PAT || secrets.GITHUB_TOKEN }} - name: Find last semver tag id: last diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 47b3ae2..a4756a6 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -1,27 +1,51 @@ name: Build & Push Docker Image +# Multi-arch build using NATIVE runners for each platform, then a +# manifest-list push. No QEMU emulation — amd64 builds on x86 runner, +# arm64 builds on ubuntu-24.04-arm runner. argon2 and every other +# native dep compile natively on their target arch. +# +# Result: `danielonyejesi/pediatric-ai-scribe-v3:X.Y.Z` (and :latest) +# is one tag serving the correct variant to amd64 or arm64 hosts. + on: push: tags: ['v*'] workflow_dispatch: inputs: tag: - description: 'Docker image tag (e.g. v8, latest)' + description: 'Tag to publish (e.g. v6.2.0)' required: false default: 'latest' +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: 'true' + IMAGE: danielonyejesi/pediatric-ai-scribe-v3 + jobs: build: - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - + # Build one variant per matrix entry, push by digest only. + name: Build ${{ matrix.platform }} + runs-on: ${{ matrix.runner }} + strategy: + fail-fast: false + matrix: + include: + - platform: linux/amd64 + runner: ubuntu-latest + - platform: linux/arm64 + runner: ubuntu-24.04-arm steps: - name: Checkout uses: actions/checkout@v4 - - name: Set up Docker Buildx + - name: Docker metadata (for labels) + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.IMAGE }} + + - name: Set up Buildx uses: docker/setup-buildx-action@v3 - name: Login to Docker Hub @@ -30,8 +54,56 @@ jobs: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Extract version tag - id: meta + - name: Build & push by digest + id: build + uses: docker/build-push-action@v5 + with: + context: . + 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=${{ matrix.platform }} + cache-to: type=gha,mode=max,scope=${{ matrix.platform }} + + - name: Export digest for the merge job + run: | + mkdir -p /tmp/digests + DIG="${{ steps.build.outputs.digest }}" + touch "/tmp/digests/${DIG#sha256:}" + + - name: Upload digest artifact + uses: actions/upload-artifact@v4 + with: + name: digests-${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }} + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 + + merge: + # Combine the two single-platform digests into one multi-arch manifest + # published under the real tags (vX.Y.Z and latest). + name: Merge manifests + needs: build + runs-on: ubuntu-latest + steps: + - name: Download digests + uses: actions/download-artifact@v4 + with: + path: /tmp/digests + pattern: digests-* + merge-multiple: true + + - name: Set up Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Resolve tag + id: tag run: | if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then echo "tag=${{ github.event.inputs.tag || 'latest' }}" >> $GITHUB_OUTPUT @@ -39,24 +111,27 @@ jobs: echo "tag=${GITHUB_REF_NAME}" >> $GITHUB_OUTPUT fi - - name: Build and Push - uses: docker/build-push-action@v5 + - name: Docker metadata + id: meta + uses: docker/metadata-action@v5 with: - context: . - push: true + images: ${{ env.IMAGE }} tags: | - danielonyejesi/pediatric-ai-scribe-v3:${{ steps.meta.outputs.tag }} - danielonyejesi/pediatric-ai-scribe-v3:latest - cache-from: type=gha - cache-to: type=gha,mode=max - # x86 only — argon2 native build fails under QEMU ARM64 - # emulation on a GitHub-hosted amd64 runner (SIGILL / exit 132). - # Add linux/arm64 back with a native ARM runner when/if you - # actually deploy to ARM hardware. - platforms: linux/amd64 + type=raw,value=${{ steps.tag.outputs.tag }} + type=raw,value=latest + + - name: Create manifest list & push + working-directory: /tmp/digests + run: | + docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf "${{ env.IMAGE }}@sha256:%s " *) + + - name: Inspect final image + run: docker buildx imagetools inspect ${{ env.IMAGE }}:${{ steps.tag.outputs.tag }} - name: Summary run: | - echo "### Docker image published" >> $GITHUB_STEP_SUMMARY - echo "- \`danielonyejesi/pediatric-ai-scribe-v3:${{ steps.meta.outputs.tag }}\`" >> $GITHUB_STEP_SUMMARY - echo "- \`danielonyejesi/pediatric-ai-scribe-v3:latest\`" >> $GITHUB_STEP_SUMMARY + echo "### Multi-arch image published" >> $GITHUB_STEP_SUMMARY + echo "- \`${{ env.IMAGE }}:${{ steps.tag.outputs.tag }}\`" >> $GITHUB_STEP_SUMMARY + echo "- \`${{ env.IMAGE }}:latest\`" >> $GITHUB_STEP_SUMMARY + echo "- Platforms: linux/amd64, linux/arm64 (built on native runners)" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/version-bump.yml b/.github/workflows/version-bump.yml index fe648c7..f988019 100644 --- a/.github/workflows/version-bump.yml +++ b/.github/workflows/version-bump.yml @@ -22,6 +22,9 @@ on: description: 'Or exact version (e.g. 7.0.0) — overrides bump' required: false +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: 'true' + permissions: contents: write @@ -33,7 +36,7 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 - token: ${{ secrets.GITHUB_TOKEN }} + token: ${{ secrets.RELEASE_PAT || secrets.GITHUB_TOKEN }} - name: Compute next version id: v