A lost merge run left an Android fix unpublished, and no re-run could ship it #237

Merged
enricobuehler merged 1 commits from worktree-android-dispatch-publish-hatch into main 2026-08-14 21:03:13 +00:00
Owner

Merging two PRs seconds apart can leave the older merge sha with no run at all — Gitea attributes the window's runs to the newer head. 1e5dca4c (PR #235, the pad Select/KEYCODE_BACK fix, 20:10:04Z) lost its run to b5cace3a 12 s later, and since #236 touches only Swift and docs, android's paths: correctly declined to fire for it. Net effect: the fix reached main having never been built, and no canary carries it — Play beta+alpha is still on versionCode 13728 (36e133ae).

Re-running the PR run cannot recover that. A re-run replays the original event, so run #13731 stayed pull_request and all four publish steps skipped again — verified on its 20:47 re-run, which went green with Version + channel, Build Release, Publish to generic registry and Upload to Google Play all skipped. (Its first attempt hadn't skipped at all: it died before step 0 on failed to create container: No such image: 192.168.1.58:5010/punktfunk-android-ci:latest, which paints every step cancelled and reads like a code failure.)

Until now the only cure was inventing a filler push touching one of android.yml's paths.

What this does

workflow_dispatch gains a publish input, default "false", and the four publish gates widen to accept a dispatch that opts in:

if: >-
  (github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.publish == 'true'))
  && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
  • A plain manual run stays build-only, exactly as today — a stray click cannot reach testers.
  • The input is string-typed and compared against 'true', matching apple.yml's testflight, which is the form proven to evaluate on this Gitea. Not a YAML boolean.
  • All four gates move together on purpose: PLAY_TRACK/PLAY_ALSO_TRACK are exported by the Version + channel step, so un-gating only the upload would run it with an empty --track.
  • Dispatching a tag with publish=true reaches production at 100%, same as a tag push. Deliberate — it's the same recovery path when a release run dies on a runner flake. The release-notes gate still guards it (ref-based, not event-based).

docs/releases/README.md gets the recovery note, including the "match your own merge sha in the run list" check — CI ran is not the same as your commit ran.

Note on merging

workflow_dispatch runs the workflow file from the selected ref, so the hatch only becomes usable once it's on main. The merge push touches .gitea/workflows/android.yml, which is in android's own paths: — so merging this triggers a normal canary run that carries the Select fix to beta+alpha on its own. The hatch is insurance for next time rather than the tool needed for this instance.

Validated by parsing the YAML and printing each resolved if (the folded block scalar collapses to one line); the tag-only notes gate and the always() artifact step are untouched.

Merging two PRs seconds apart can leave the older merge sha with **no run at all** — Gitea attributes the window's runs to the newer head. `1e5dca4c` (PR #235, the pad Select/`KEYCODE_BACK` fix, 20:10:04Z) lost its run to `b5cace3a` 12 s later, and since #236 touches only Swift and docs, android's `paths:` correctly declined to fire for it. Net effect: the fix reached `main` having never been built, and no canary carries it — Play beta+alpha is still on versionCode 13728 (`36e133ae`). Re-running the PR run cannot recover that. A re-run replays the *original* event, so run #13731 stayed `pull_request` and all four publish steps skipped again — verified on its 20:47 re-run, which went green with `Version + channel`, `Build Release`, `Publish to generic registry` and `Upload to Google Play` all skipped. (Its first attempt hadn't skipped at all: it died before step 0 on `failed to create container: No such image: 192.168.1.58:5010/punktfunk-android-ci:latest`, which paints every step `cancelled` and reads like a code failure.) Until now the only cure was inventing a filler push touching one of `android.yml`'s paths. ## What this does `workflow_dispatch` gains a `publish` input, **default `"false"`**, and the four publish gates widen to accept a dispatch that opts in: ```yaml if: >- (github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.publish == 'true')) && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')) ``` - A plain manual run stays **build-only**, exactly as today — a stray click cannot reach testers. - The input is **string-typed and compared against `'true'`**, matching `apple.yml`'s `testflight`, which is the form proven to evaluate on this Gitea. Not a YAML boolean. - All four gates move together on purpose: `PLAY_TRACK`/`PLAY_ALSO_TRACK` are exported by the `Version + channel` step, so un-gating only the upload would run it with an empty `--track`. - Dispatching a **tag** with `publish=true` reaches production at 100%, same as a tag push. Deliberate — it's the same recovery path when a release run dies on a runner flake. The release-notes gate still guards it (ref-based, not event-based). `docs/releases/README.md` gets the recovery note, including the "match your own merge sha in the run list" check — *CI ran* is not the same as *your commit ran*. ## Note on merging `workflow_dispatch` runs the workflow file from the selected ref, so the hatch only becomes usable once it's on `main`. The merge push touches `.gitea/workflows/android.yml`, which is in android's own `paths:` — so **merging this triggers a normal canary run that carries the Select fix to beta+alpha on its own**. The hatch is insurance for next time rather than the tool needed for this instance. Validated by parsing the YAML and printing each resolved `if` (the folded block scalar collapses to one line); the tag-only notes gate and the `always()` artifact step are untouched.
enricobuehler added 1 commit 2026-08-14 20:58:56 +00:00
ci(android): a manual dispatch can publish, so a lost merge run is not a dead end
ci / web (pull_request) Successful in 1m1s
ci / docs-site (pull_request) Successful in 1m18s
ci / bun-nix (pull_request) Successful in 1m37s
android / android (pull_request) Successful in 4m33s
ci / rust-arm64 (pull_request) Successful in 12m3s
ci / rust (pull_request) Canceled after 29m33s
91b8f1a939
Merging two PRs seconds apart can leave the older merge sha with no run at all -
Gitea attributes the window's runs to the newer head. 1e5dca4c (PR #235, the pad
Select/KEYCODE_BACK fix) lost its run to b5cace3a 12 s later and reached main
having never been built, so no canary carries it.

Re-running the PR run cannot recover that: a re-run replays the original
pull_request event, and all four publish steps are gated on a push, so they stay
skipped. Until now the only cure was inventing a filler push touching one of
android.yml's paths.

Add a workflow_dispatch 'publish' input, default false, and widen the four gates
to accept a dispatch that opts in. A plain manual run stays build-only, so a
stray click still cannot reach testers. String-typed and compared against 'true'
to match apple.yml's testflight input, the form proven on this Gitea.
enricobuehler merged commit 588962f696 into main 2026-08-14 21:03:13 +00:00
enricobuehler deleted branch worktree-android-dispatch-publish-hatch 2026-08-14 21:03:14 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: unom/punktfunk#237