Generate every package manifest at release time - #11
Merged
Merged
Conversation
Only the Homebrew formula and Scoop manifest were maintained by the release
workflow. The AUR PKGBUILD and winget manifest were frozen at 0.1.0, and winget
and Chocolatey both carried a literal `__CHECKSUM__`, so those three packages
could not be published from this repo at all. Bumping the Chocolatey nuspec by
hand during the v0.8.1 release was the symptom.
`scripts/update-manifests.sh <version>` now downloads that version's assets,
checksums them, and rewrites all six manifests. The release workflow calls it,
and it can be run by hand afterwards to repair one.
Moving the generation out of the workflow YAML fixed two bugs that the embedded
heredocs had caused:
- The formula's test block was emitted as `shell_output("\#{bin}/tilefeed --help")`.
The backslash was there to survive bash, but Ruby reads `\#{` as escaped
interpolation, so `brew test tilefeed` ran a command literally named
`#{bin}/tilefeed` and failed. Verified against the published v0.8.1 formula.
- The Scoop manifest's indentation was mangled by `sed 's/^ //'`
stripping ten spaces from every line regardless of depth.
Downloads now use `curl -f` and check each archive's type: previously a missing
asset would write GitHub's HTML error page to the file and publish the checksum
of that page as if it were the binary.
The packaging manifests in this commit are the script's own output for v0.8.1,
so they now match the release that is already published.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UDAsxXjaouazD2L4NhDxSb
muimsd
force-pushed
the
fix/packaging-manifests
branch
from
September 12, 2026 06:28
4bfa0be to
be840ac
Compare
The review's first finding was the important one: the script meant to stop
manifests rotting could rot the same way. A `perl -pi` substitution that matched
nothing rewrote the file unchanged, and the script still exited 0 reporting the
manifest as updated — resetting the rot once rather than preventing it. Every
targeted edit now fails loudly, naming the file and the pattern, when it matches
nothing. Verified by renaming a field and watching it exit 1; a whitespace
reformat is tolerated, and re-running for the same version stays a no-op success.
Also fixed:
- The .zip type guard always passed. `file x.zip` prints the filename before the
type, so grepping its output for "zip" matched the name — an HTML error page
served as a .zip sailed through. Now `file -b` with a case match, which also
removes a `pipefail` + `grep -q` SIGPIPE flake on the release path.
- `brew install` on Linux arm64 installed an x86_64 binary: the formula had no
on_arm branch under on_linux, though the aarch64 Linux asset has been built and
published all along. Both Linux architectures are now referenced.
- A prerelease tag would have overwritten the stable manifests with RC URLs, and
written a pkgver containing a hyphen, which makepkg rejects. The job is skipped
for such tags and the script refuses anything but MAJOR.MINOR.PATCH.
- Tag names permit backticks and $(...), and the job holds contents:write and the
tap token, so the version reaches the shell through env rather than `${{ }}`.
- `git diff --cached --quiet || git commit` hid the case where a release changes
no manifest at all. That is now an error in this repo; it stays tolerated for
the tap, where a no-op is expected.
- Downloads retry: assets are CDN-served and this job starts the moment the
release is published, so a blip failed the job with the release already public.
- The winget manifest is generated whole rather than patched. Patching installer
entries in place would rewrite an arm64 block's URL and hash to the x64 ones
the day someone adds it.
- REPO comes from $GITHUB_REPOSITORY, so a fork checksums its own assets.
- The source tarball goes through fetch() too, so it gets the same type check.
- KEEP_DOWNLOADS prints where it kept them.
- shellcheck is installed explicitly rather than relying on the runner image.
Kept the per-file `replace` calls separate rather than merging them into one
perl invocation: with each one verified, a format change names the exact line
that stopped matching.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UDAsxXjaouazD2L4NhDxSb
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 problem
The release workflow maintained two of six package manifests. The rest had rotted:
Formula/tilefeed.rbbucket/tilefeed.jsonpackaging/aur/PKGBUILDpkgver=0.1.0,sha256sums=('SKIP')packaging/winget/muimsd.tilefeed.yamlPackageVersion: 0.1.0, URL pointing at v0.1.0,InstallerSha256: __CHECKSUM__packaging/chocolatey/tools/chocolateyinstall.ps1checksum64 = '__CHECKSUM__'packaging/chocolatey/tilefeed.nuspecThose three could not be published as they stood. Having to hand-edit the nuspec while cutting v0.8.1 was the symptom.
The fix
scripts/update-manifests.sh <version>downloads that version's release assets, checksums them, and rewrites all six. The workflow's three inline steps collapse to one call, and the script can be run by hand afterwards to repair a manifest without cutting a release.Two bugs that fell out of moving generation into a script
The published Homebrew formula's test block is broken. The workflow emitted
shell_output("\#{bin}/tilefeed --help")— the backslash was there to survive the bash heredoc, but Ruby reads\#{as escaped interpolation:The published Scoop manifest's indentation is mangled, because
sed 's/^ //'strips exactly ten spaces from every line regardless of its depth. Valid JSON, but visibly wrong.Both are artifacts of writing file content in YAML heredocs; neither can recur in a real script file.
Downloads now use
curl -fand check each archive's type. Previously a missing asset wrote GitHub's HTML error page to the file and the job published the checksum of that page as if it were the binary.Verification
Formula/andbucket/came out identical to what the workflow generated except the two bugs above, which is the equivalence check I wanted.shellcheck scripts/*.shCI job — this script runs on the release path, where a mistake is only visible once a release is already published.🤖 Generated with Claude Code
https://claude.ai/code/session_01UDAsxXjaouazD2L4NhDxSb