ci(release): stop publishing packages from inside the build matrix - #561
Merged
Conversation
Four things went wrong in the v2.7.2 release, and they share two causes: an irreversible side effect placed before the decision it depends on, and a failure that was configured not to be one. Chocolatey's markpad-app 2.7.2 was published at 15:37 UTC on 2026-08-07 by run 31192564528, which then failed on Linux and produced no release. The release users got came out of a different run three hours later. A Chocolatey version cannot be un-pushed. The snap build has failed since v2.6.11 -- snapcraft's rust plugin cannot find rustup unless a part named `rust-deps` provides it -- under `continue-on-error: true`, so the job reported success for three months and six versions while the Snap Store served 2.6.11 and every release told people to `sudo snap install markpad`. So both pushes move to publish-packages.yml, triggered by `release: published`: a human clicking Publish on a draft whose assets they have checked. Neither job swallows a failure. The Chocolatey package now wraps the release's own Markpad_<version>_x64.exe instead of a second build, which is what VERIFICATION.txt promises; the file now says so and carries the checksum. The AppImage strip -- which failed in two of the three v2.7.2 attempts -- moves to scripts/strip-appimage.sh, runnable against any downloaded AppImage without a signing key, and now verifies the repacked artifact rather than the AppDir. A CI smoke test cannot catch this defect: the runner's Mesa is the one the libraries came from, so nothing mismatches there and #498 had to be found by a user on Arch. "These libraries are absent" is the only property checkable before release. Its re-sign step was spelling the same secret the deprecated way (TAURI_PRIVATE_KEY) because the lockfile resolved @tauri-apps/cli to 2.9.6, which predates the v2 names. Floored at ^2.11.4, which also fixes the AppImage bundler writing absolute symlinks for .desktop and .DirIcon -- the same artifact this repacks. See #497. Verified: `TAURI_SIGNING_PRIVATE_KEY` + `_PASSWORD` produce a .sig on 2.11.4 (they produce nothing on 2.9.6). Seven assertions added to scripts/releaseWorkflow.test.ts hold the properties above; 948 tests pass. Not verifiable from a pull request: snapcraft needs LXD and the store credentials, and the strip needs a Linux runner -- `workflow_dispatch` on publish-packages.yml exists to exercise the snap half against an existing tag before the next release depends on it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
PathGao
added a commit
that referenced
this pull request
Aug 10, 2026
…es that do not exist (#566) * fix(release): make the recovery path usable, and stop promising updates that do not exist Two things #561 left behind, both about the pipeline telling the truth. `publish-packages.yml` has a `workflow_dispatch` escape hatch whose only possible use is a tag that is already published -- recovering after the snap job failed, or exercising the workflow without cutting a release. But Chocolatey accepts a version exactly once, so on that path the Chocolatey job always fails, on a duplicate that is expected rather than wrong. The escape hatch reported a failure that meant nothing, which is the same disease #561 treated: a signal nobody can act on. The job now asks the feed first and skips a version already on it. A check that cannot answer falls through to the push, which is the real gate -- the point is to drop a known non-event, not to make publishing conditional on a lookup succeeding. Separately, the README told `.deb` and `.rpm` users they "continue to update through their distribution channels". There is no apt or dnf repository, and tauri-plugin-updater supports neither format, so those users have no update path at all: they install once, and nothing ever tells them a new version exists. RELEASING.md carried the same claim. Both now say what is true. The Chocolatey half of that sentence was correct and stays. The Snap half is a live question in #562 and is untouched here. Two assertions added. One holds the README, the release-body download table and the publishing workflow to the same set of package managers, in both directions -- the snap went dead for three months while both documents kept recommending it, and retiring the snap would make the same drift possible with the arrow reversed. The other holds the Chocolatey skip to gating the push rather than merely existing. Both were checked by mutation: deleting `snapcraft push` fails the first and not the second; dropping the `if:` fails the second and not the first. 953 tests pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs: say what Check for Updates actually does on .deb and .rpm The sentence added a moment ago said nothing in Markpad would tell a package-managed install that a new version exists. It does tell them, and then fails to install it -- #570 traces that to __TAURI_BUNDLE_TYPE not being patched into the Linux binary, which sends deb, rpm and snap down the AppImage install path. Both documents now point at it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: PathGao <gaoyanbo@gaoyanbodeMacBook-Air.local> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This was referenced Aug 10, 2026
PathGao
added a commit
that referenced
this pull request
Aug 12, 2026
…ts own (#612) Two things in build.yml, both about the release build being the one workflow nothing else guards. It had no `concurrency` at all, so dispatching twice gave two runs writing to the same draft release. Not hypothetical: publish-packages.yml records markpad-app 2.7.2 reaching Chocolatey at 15:37 UTC on 2026-08-07 from run 31192564528 -- a run that then failed on Linux and produced no release -- while the release users actually got came out of a different run three hours later. #561 moved the package pushes out of the build matrix, which fixed the irreversible half of that story. This is the other half. Keyed on the ref, not the version: the version is read from package.json inside `create-release`, and a concurrency group is evaluated before any job starts. A release is always dispatched from master, so the two are the same key in practice. `cancel-in-progress: false` deliberately. A second dispatch waits rather than killing the first, because a half-cancelled run leaves a draft holding some platforms' assets and not others -- which looks exactly like a build that has not finished yet, and RELEASING.md step 5 is a human comparing that list against an expected one. And `generate-update-feed` ran on `ubuntu-latest` while every other runner in the pipeline is pinned. It only runs gh and jq, so the version buys little on its own; what it buys is that the image moving becomes something that happens to us with a commit rather than without one. Both halves checked by mutation, each failing alone: flipping cancel-in-progress to true, and putting ubuntu-latest back on that job. The assertion is on `cancel-in-progress: false` rather than on the group string, because that is the part that carries the reasoning. 1006 tests pass. Co-authored-by: PathGao <gaoyanbo@gaoyanbodeMacBook-Air.local>
This was referenced Aug 24, 2026
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.
Problem
Four things went wrong around the v2.7.2 release. They are not four bugs — they share two causes.
An irreversible side effect placed before the decision it depends on.
choco pushandsnapcraft pushran insidebuild.yml's platform matrix. Chocolatey'smarkpad-app2.7.2 was published at 15:37 UTC on 2026-08-07 by run31192564528— a run that then failed on Linux and produced no release. The release users actually got came out of a different run three hours later. A Chocolatey version cannot be un-pushed.A failure configured not to be one. Both pushes carried
continue-on-error: true. The snap build has failed since v2.6.11:That line is from the successful 2.7.2 run. The job reported success for three months and six versions while the Snap Store went on serving 2.6.11 (
api.snapcraft.io, rev 15, 2026-06-03) and every release told people tosudo snap install markpad. Nobody reported it, because from the outside it looks like there is nothing to report — snapd checks for updates daily and tells those users they are current.And the AppImage strip step failed in two of the three v2.7.2 release attempts (runs
31192564528,31204367106), once on a stray-kand once on signing env vars, in a heredoc that can only be exercised by cutting a release.Changes
Package managers publish after the release, not during the build — new
publish-packages.yml, triggered byrelease: published, which is a human clicking Publish on a draft whose assets they have checked (RELEASING.md step 6). Two independent jobs, neither swallowing a failure. Also takesworkflow_dispatchwith a tag, so the snap and Chocolatey halves can be exercised against an existing release without cutting a new one — neither is reachable from a pull request otherwise.The Chocolatey package now wraps the release's own
Markpad_<version>_x64.exeinstead of a second build.VERIFICATION.txtpromised "copied directly" from a build; a rebuild from the same commit is not guaranteed to be the same bytes. It now describes what actually happens and carries the SHA256 and the exact URL, which is what a Chocolatey moderator can check.The snap can find rustup — a
rust-depspart, which is the one place other than PATH that snapcraft's rust plugin looks. The name comes from snapcraft, so it is asserted literally in the tests.The AppImage strip is
scripts/strip-appimage.sh— runnable against any downloaded AppImage, no signing key needed (signing stays in the workflow, which is what keeps the script runnable). It now verifies the repacked artifact rather than the AppDir: appimagetool packing the wrong directory would pass the weaker check. The excludelist has one home instead of two.Worth being explicit about why the check is shaped that way: a CI smoke test cannot catch this defect. The runner's Mesa is the one the libraries were copied from, so nothing mismatches there and the AppImage starts fine — #498 had to be found by a user on Arch. "These libraries are absent" is the only property that can be checked before a release.
@tauri-apps/clifloored at^2.11.4— the lockfile resolved^2to 2.9.6, which predates theTAURI_SIGNING_*names, so the re-sign step had to spell the same secret the deprecated way whiletauri buildused the current one. 2.11.4 also fixes the AppImage bundler writing absolute symlinks for.desktopand.DirIcon— the same artifact this repacks. Both halves of the case are @PathGao's, in #497.Verification
Measured, not assumed:
TAURI_SIGNING_PRIVATE_KEY+_PASSWORDon 2.11.4.sigUnable to find the private key(#497)npm testnpm run checkbash -n scripts/strip-appimage.sh, YAML parse of all three changed filesSeven assertions added to
scripts/releaseWorkflow.test.ts, each holding a property rather than a step name — the build matrix has nochoco push/snapcraft push; publishing triggers only onrelease: published; nocontinue-on-errorin either file;rust-depsexists and is depended on; the strip is a script and the excludelist is not duplicated; the verification runs after the repack; the CLI floor is high enough for the env vars the workflow uses.What cannot be verified from a pull request, and how to close it: snapcraft needs LXD and store credentials, and the strip needs a Linux runner with the signing secret. After merging, run
Publish Packagesby hand againstv2.7.2— that exercises the snap fix end to end (including the store push) without cutting a release. If it goes green, the next release is the first one in six where the snap is real.Not in this PR
Whether Markpad should keep the snap at all, plus code signing on macOS and Windows and the Linux distribution surface — #562.
🤖 Generated with Claude Code