pediatric-ai-scribe-v3/.github/workflows/auto-version.yml
Daniel 7ad0c84789 ci: multi-arch Docker via native runners + Node 24 opt-in + PAT for tag-trigger chain
docker-publish.yml:
  - Rewrote as matrix build + manifest merge.
  - amd64 on ubuntu-latest, arm64 on ubuntu-24.04-arm (free for public
    repos). No QEMU — argon2 and every other native dep compile on
    their target CPU, no more SIGILL / exit 132.
  - Per-arch GHA cache scopes so builds don't thrash each other.
  - Final step merges both digests under one tag (vX.Y.Z + latest),
    publishing a real multi-arch manifest. `docker pull` from either
    arch gets the right variant automatically.

auto-version.yml, version-bump.yml:
  - Checkout now uses `secrets.RELEASE_PAT || secrets.GITHUB_TOKEN`.
    With RELEASE_PAT set, the tag push this workflow does DOES
    trigger downstream (android-release, docker-publish). Without
    it, falls back to GITHUB_TOKEN (no downstream trigger, what we
    have today).

All workflows (auto-version, version-bump, android-release,
docker-publish):
  - Added FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: 'true' so actions
    still on Node 20 runtime (checkout/cache/setup-*) opt in to
    Node 24 early. GitHub makes Node 24 default 2026-06-02 and
    removes Node 20 2026-09-16.

To finish the chain (one-time user step): create a fine-grained
PAT with "Contents: Read and write" on this repo and add as
RELEASE_PAT secret. After that `feat:` / `fix:` commits auto-tag
AND auto-build with zero manual intervention.
2026-04-15 00:05:34 +02:00

148 lines
5.5 KiB
YAML

name: Auto version & release
# Fires on every push to main. Parses commit messages since the
# last semver tag, decides patch/minor/major bump, creates the
# tag, pushes. The tag push then triggers android-release.yml and
# docker-publish.yml. Fully hands-off — you never pick a version
# number; your commit messages do.
#
# Commit message grammar (Conventional Commits):
# feat: → minor bump (new feature, backward-compatible)
# fix: → patch bump (bug fix)
# feat!: / BREAKING CHANGE in body → major bump
# everything else (docs, refactor, chore, style, ci, test) → no bump
#
# Skip conditions (no new release created):
# - No commits match the above patterns
# - The most recent commit is itself a release commit ("Release v…")
# - [skip ci] appears in any commit message since the last tag
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
jobs:
version:
runs-on: ubuntu-latest
if: "!contains(github.event.head_commit.message, 'Release v') && !contains(github.event.head_commit.message, '[skip ci]')"
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
# 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
run: |
LAST=$(git tag --list 'v[0-9]*.[0-9]*.[0-9]*' --sort=-v:refname | head -1)
if [[ -z "$LAST" ]]; then
LAST="v0.0.0"
echo "no previous tag, starting from v0.0.0"
fi
echo "tag=$LAST"
echo "tag=$LAST" >> "$GITHUB_OUTPUT"
echo "version=${LAST#v}" >> "$GITHUB_OUTPUT"
- name: Decide bump type from commit messages
id: decide
env:
LAST: ${{ steps.last.outputs.tag }}
run: |
# All commits from the last tag → HEAD (exclusive of tag commit)
if [[ "$LAST" == "v0.0.0" ]]; then
MSGS=$(git log --format='%s%n%b%n---')
else
MSGS=$(git log "${LAST}..HEAD" --format='%s%n%b%n---')
fi
BUMP=none
if echo "$MSGS" | grep -qE '(^|\n)(BREAKING CHANGE:|[a-z]+(\([^)]+\))?!:)'; then
BUMP=major
elif echo "$MSGS" | grep -qE '(^|\n)feat(\([^)]+\))?: '; then
BUMP=minor
elif echo "$MSGS" | grep -qE '(^|\n)fix(\([^)]+\))?: '; then
BUMP=patch
fi
echo "Bump type decided: $BUMP"
echo "bump=$BUMP" >> "$GITHUB_OUTPUT"
{
echo "### Commits since $LAST"
echo '```'
if [[ "$LAST" == "v0.0.0" ]]; then
git log --oneline | head -20
else
git log "${LAST}..HEAD" --oneline
fi
echo '```'
echo ""
echo "**Bump decision**: \`$BUMP\`"
} >> "$GITHUB_STEP_SUMMARY"
- name: Stop if no release-worthy commits
if: steps.decide.outputs.bump == 'none'
run: |
echo "No feat / fix / BREAKING commits since last tag — not cutting a release."
echo "::notice::No release cut. Commit with 'feat:', 'fix:', or BREAKING CHANGE to trigger one."
- name: Compute next version
id: next
if: steps.decide.outputs.bump != 'none'
env:
CUR: ${{ steps.last.outputs.version }}
BUMP: ${{ steps.decide.outputs.bump }}
run: |
IFS='.' read -r MAJ MIN PAT <<< "$CUR"
case "$BUMP" in
major) NEXT="$((MAJ+1)).0.0" ;;
minor) NEXT="${MAJ}.$((MIN+1)).0" ;;
patch) NEXT="${MAJ}.${MIN}.$((PAT+1))" ;;
esac
echo "next=$NEXT" >> "$GITHUB_OUTPUT"
echo "### Next version: v$NEXT" >> "$GITHUB_STEP_SUMMARY"
- name: Configure git
if: steps.decide.outputs.bump != 'none'
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
- name: Bump version strings + tag + push
if: steps.decide.outputs.bump != 'none'
env:
V: ${{ steps.next.outputs.next }}
run: |
IFS='.' read -r MAJ MIN PAT <<< "$V"
ANDROID_CODE=$(( MAJ * 100000 + MIN * 1000 + PAT ))
sed -i -E "0,/(\"version\"[[:space:]]*:[[:space:]]*\")[^\"]+(\")/ s//\1${V}\2/" package.json
sed -i -E "0,/(\"version\"[[:space:]]*:[[:space:]]*\")[^\"]+(\")/ s//\1${V}\2/" mobile/package.json
sed -i -E \
-e "s/versionCode +[0-9]+/versionCode ${ANDROID_CODE}/" \
-e "s/versionName +\"[^\"]+\"/versionName \"${V}\"/" \
mobile/android/app/build.gradle
git add package.json mobile/package.json mobile/android/app/build.gradle
git commit -m "Release v${V}"
git tag -a "v${V}" -m "Release v${V}"
git push origin HEAD
git push origin "v${V}"
echo "### Released v$V" >> "$GITHUB_STEP_SUMMARY"
echo "android-release + docker-publish workflows will now run." >> "$GITHUB_STEP_SUMMARY"