Skip to content

Tag what a release uploaded instead of what it was meant to upload - #568

Open
andiwand wants to merge 1 commit into
mainfrom
tag-what-a-release-uploaded
Open

Tag what a release uploaded instead of what it was meant to upload#568
andiwand wants to merge 1 commit into
mainfrom
tag-what-a-release-uploaded

Conversation

@andiwand

@andiwand andiwand commented Aug 4, 2026

Copy link
Copy Markdown
Member

Follows #567.

A version tag had to be pushed before the run it named, which is a promise the run can fail to keep. v4.9.0 is the case in point: its tag push run failed, and the upload that shipped came from a dispatched run instead. Same commit that time, but nothing made it so — a dispatch off main builds whatever main is at, and there is a successful release run on the fix-play-store-upload branch with no tag naming it anywhere.

So the tag stops being the trigger and becomes the record.

What changes

release.yml is dispatch-only. The push: tags: trigger is gone; version is the only source.

gh workflow run release.yml -f version=v4.14.0 -f uploads=both

It tags what it uploaded, as build/<flavor>/<version>, at the commit it built. Written as each lane lands rather than once at the end — the half uploaded release is the case the record exists for, and a lite failure must not take pro's tag down with it. Per flavor for the same reason: the two halves get finished from different commits. Needs contents: write.

The Android version code is derived (v4.14.040800), not counted from the store, so unlike the iOS version of this there is no build number to carry and no second build of a version to disambiguate — Play refuses a version code it has already accepted. That also gives a free fast-fail: a version already tagged as uploaded is now caught in seconds instead of six minutes in.

The plain v* tag stays manual, pushed once the release is actually live, and no longer builds anything:

git tag v4.14.0 build/pro/v4.14.0^{} && git push origin v4.14.0

attach-apk.yml is the old attach job moved into a workflow of its own, triggered by that tag. It had to move — it keyed off a trigger tag that no longer exists — but it is better off here:

  • it attaches the APK that actually went to Play, fetched from that upload's own run, rather than one built alongside it;
  • it refuses a version tag that does not sit on the commit build/pro/<version> names, which is the one thing that catches the two drifting apart, and errors if lite never went out at all;
  • the GitHub release still has to exist already, the way it always has.

Run artifacts are kept 90 days, so a version tag written much later has no APK left to attach; that is checked with a message rather than left to download-artifact.

resolve-version.py loses its --tag arm and the tag/input agreement check. The "only a dry run may go without a version" guard is untouched.

CHANGELOG.md gets an Unreleased heading and the matching rule: the heading is cut when the version is dispatched, not when it is tagged, because a version code can only be uploaded once and no later commit can ever ship under that version. It also now says it is not the store copy — skip_upload_changelogs: true, so what Play shows is written in the Console.

Notes

The v4.7 tag that reached origin on the 3rd and started a full release run of a week-old commit cannot happen after this: a v* tag now runs attach-apk, which fails in seconds on a missing build tag instead of building and signing anything.

A lane run from a laptop still leaves no tag, so an upload made by hand is not recorded. That is the same as before, and seemed worse to paper over than to state in the README.

Untested end to end, since a real run uploads to the Play Store. Both workflows parse, the run: blocks are shellcheck clean apart from env:-supplied variables it cannot see, the tag round trip and the flavor loop were exercised in a scratch repo, and resolve-version.py was run across all its cases.

🤖 Generated with Claude Code

A tag had to be pushed before the run it named, which is a promise the
run can fail to keep. v4.9.0 is the case in point: its tag push run
failed and the upload came from a dispatched run instead. The same
commit that time, but nothing made it so - a dispatch off main builds
whatever main is at, and a release uploaded from the
fix-play-store-upload branch has no tag naming it anywhere.

So the tag stops being the trigger and becomes the record. release.yml
is dispatch-only, and writes build/<flavor>/<version> at the commit it
uploaded, as each lane lands rather than once at the end: the half
uploaded release is the case the record exists for, and a lite failure
must not take pro's tag down with it. Per flavor for the same reason -
the two halves get finished from different commits.

The plain v* tag stays a human decision, taken once the release is
actually live, and no longer builds anything. What it does run is
attach-apk.yml, which is the old attach job moved out: it fetches the
pro apk from the run that uploaded it and puts it on the github
release. Attaching had to move anyway, since it keyed off a trigger tag
that no longer exists, and it is better placed here - it now attaches
the apk that went to play rather than one built alongside it, and it
refuses a version tag that does not sit on the commit
build/pro/<version> names.

resolve-version.py loses its tag arm; the input is the only source.
CHANGELOG.md gets the matching rule: the heading is cut when the
version is dispatched, not when it is tagged, because a version code
can only be uploaded once and no later commit can ever ship under it.

Untested end to end, since a real run uploads to the play store. Both
workflows parse, the run blocks are shellcheck clean, the tag round
trip and the flavor loop were exercised in a scratch repo, and
resolve-version.py was run across all its cases.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RsdTta67FZ4KeNfPPw5BVL
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant