Lock the Android tag to versionName, the way the exporter's is - #59
Merged
Merged
Conversation
The exporter cannot be released under a tag that disagrees with its source - the check runs before either binary builds. The Android app had no equivalent, so an android-app-v* tag could claim any version while the APK reported another. That asymmetry existed only because the exporter was the release being cut when the check was written. exporter_version.py is now release_version.py with a --kind, rather than a second copy of the same idea. Both releases work the same way: the version lives in the source, the tag is derived from it, and a disagreement fails the release with instructions naming the file to edit. exporter -> VERSION in python/main/wizard.py android -> versionName in app/build.gradle.kts build-release.yml now runs that check instead of parsing the tag by hand with awk and cut, and takes the version from the source. It runs before the Gradle build, so a mismatch costs seconds rather than a full signed build. The failure messages differ per kind because the reasons differ: the exporter's VERSION is stamped into every export as `via:`, while versionName is what the app reports in Settings and in bug reports. Both are baked in at build time by something no later step rewrites, which is why the tag alone cannot be trusted. Tests cover the Android side including the trap that makes a naive regex wrong - versionNameSuffix = "-debug" sits four lines below versionName - and assert the two tag prefixes cannot overlap, since both releases live in one repository and a shared prefix would let either check the other. CONTRIBUTING gains a Releasing the Android app section, which the new error message points at. It says to bump versionCode as well: Android refuses an APK whose code is not higher than the installed one, so a versionName-only bump leaves existing users unable to update, and it fails on their phone rather than in any build. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
parawanderer
temporarily deployed
to
Android Build
August 9, 2026 19:31 — with
GitHub Actions
Inactive
parawanderer
temporarily deployed
to
Android Build
August 9, 2026 19:31 — with
GitHub Actions
Inactive
This branch was previously deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The exporter cannot be released under a tag that disagrees with its source — that check runs before either binary builds. The Android app had no equivalent, so an
android-app-v*tag could claim any version while the APK reported another.That asymmetry existed for no better reason than the exporter being the release that was being cut when the check was written.
One mechanism, not two
exporter_version.pybecomesrelease_version.pywith a--kind, rather than a second copy of the same idea:exporterVERSIONinpython/main/wizard.pymacos-exporter-v*androidversionNameinapp/build.gradle.ktsandroid-app-v*Both work the same way: the version lives in the source, the tag is derived from it, and a disagreement fails the release with instructions naming the file to edit.
The messages differ per kind because the reasons differ — the exporter's
VERSIONis stamped into every export asvia:, whileversionNameis what users and bug reports quote.In the workflow
build-release.ymlnow runs the check instead of parsing the tag by hand withawkandcut, and takes the version from the source. It runs before the Gradle build, so a mismatch costs seconds rather than a full signed build.Tests
Cover the Android side, including the trap that makes a naive regex wrong —
versionNameSuffix = "-debug"sits four lines belowversionName— and assert the two tag prefixes cannot overlap, since both releases live in one repository and a shared prefix would let either check the other.Docs
CONTRIBUTING gains a Releasing the Android app section, which the new error message points at. It says to bump
versionCodeas well: Android refuses an APK whose code is not higher than the installed one, so aversionName-only bump leaves existing users unable to update — and that fails on their phone, never in any build.It also notes the signing secrets the Android release needs, which are separate from the exporter's token and have not been exercised since July 2025.
Note
Depends on nothing, but overlaps #58 (the token fix in the same workflow, different region) and #53 (
release_notes.pyimports the renamed module — I will rebase that branch once this lands).🤖 Generated with Claude Code