From 3ff08f93f62ad2c5afcb3c8a85680b490dc9d52c Mon Sep 17 00:00:00 2001 From: Krzysztof kuhy Rudnicki Date: Sun, 9 Aug 2026 18:15:34 +0200 Subject: [PATCH] Derive versionCode from the commit count, not github.run_number run_number counts workflow RUNS, not code. Two failure modes, one of which already bit: it resets to 1 if this file is renamed (the existing NOTE warned about that), and it can fall BEHIND a build produced outside this workflow. On 2026-08-09 diet-guard's phone held a manually sideloaded vc 8 while CI's next build was vc 6, so `adb install -r` refused every CI build with INSTALL_FAILED_VERSION_DOWNGRADE. The only non-destructive escape was re-running the workflow until the counter passed 8 -- forcing a downgrade needs an uninstall, which wipes app data. `git rev-list --count HEAD` only ever increases, tracks the code rather than the CI file, and is already far ahead of every installed build (diet-guard 62 vs 9, screen-locker 118 vs 5, wake-alarm 41 vs 5, todo 51). Needs fetch-depth: 0 -- checkout@v4 is shallow by default and would count 1. Verified the count is identical from the repo root and from app/, so the job's `working-directory: app` default does not affect it. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01GZH89WEqAjuJT8WZdqc7AP --- .github/workflows/release-apk.yml | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/.github/workflows/release-apk.yml b/.github/workflows/release-apk.yml index d921901..94d9495 100644 --- a/.github/workflows/release-apk.yml +++ b/.github/workflows/release-apk.yml @@ -15,9 +15,13 @@ concurrency: group: release-apk-${{ github.ref }} cancel-in-progress: false -# NOTE: versionCode is github.run_number, which is per-workflow-FILE. Never -# rename or replace this file — the counter resets to 1, versionCode goes -# backwards, and Android silently refuses every future update. +# NOTE: versionCode is the commit count (`git rev-list --count HEAD`), which +# only ever increases and tracks the code rather than the CI file. It replaced +# github.run_number on 2026-08-09: run_number counts workflow RUNS, so it +# resets to 1 if this file is renamed AND it can fall behind a build made +# outside this workflow — which happened, leaving CI unable to install over a +# manually sideloaded APK (INSTALL_FAILED_VERSION_DOWNGRADE). The checkout +# below therefore needs fetch-depth: 0; a shallow clone counts 1 commit. # # This job is NOT gated on a test suite: this repo has no Flutter analyze/test # job to depend on, so a broken commit still publishes. The build failing is @@ -31,6 +35,13 @@ jobs: working-directory: app steps: - uses: actions/checkout@v4 + with: + # versionCode is the commit count; a shallow clone would report 1. + fetch-depth: 0 + + - name: Derive versionCode from the commit count + id: vc + run: echo "code=$(git rev-list --count HEAD)" >> "$GITHUB_OUTPUT" - uses: actions/setup-java@v4 with: @@ -87,7 +98,7 @@ jobs: run: | flutter build apk --release \ --build-name="${{ steps.ver.outputs.semver }}" \ - --build-number="${{ github.run_number }}" + --build-number="${{ steps.vc.outputs.code }}" # Fail closed. `findByName("release") ?: debug` silently falls back to # the debug key if key.properties is misplaced, producing a green build @@ -115,7 +126,7 @@ jobs: id: art run: | set -euo pipefail - out="diet-guard-${{ steps.ver.outputs.semver }}-build.${{ github.run_number }}.apk" + out="diet-guard-${{ steps.ver.outputs.semver }}-build.${{ steps.vc.outputs.code }}.apk" cp build/app/outputs/flutter-apk/app-release.apk "$out" echo "path=$out" >> "$GITHUB_OUTPUT" @@ -124,12 +135,12 @@ jobs: GH_TOKEN: ${{ github.token }} run: | set -euo pipefail - tag="v${{ steps.ver.outputs.semver }}-build.${{ github.run_number }}" + tag="v${{ steps.ver.outputs.semver }}-build.${{ steps.vc.outputs.code }}" gh release create "$tag" "${{ steps.art.outputs.path }}" \ --prerelease \ --target "${{ github.sha }}" \ --title "$tag" \ - --notes "Automated build of ${{ github.sha }} (versionCode ${{ github.run_number }})." + --notes "Automated build of ${{ github.sha }} (versionCode ${{ steps.vc.outputs.code }})." # Cut a clean vX.Y.Z the first time a pubspec version is seen. A failing # `gh release view` is the "not published yet" signal, which also covers @@ -149,4 +160,4 @@ jobs: gh release create "$tag" "${{ steps.art.outputs.path }}" \ --target "${{ github.sha }}" \ --title "$tag" \ - --notes "Release $tag (versionCode ${{ github.run_number }})." + --notes "Release $tag (versionCode ${{ steps.vc.outputs.code }})."