Release pipeline, and a footer that stops mislabelling the day - #2
Merged
Conversation
The combined line summed each store's newest reported day and labelled the result "today". Those days are rarely the same one — App Store figures for 5 Aug were being added to Play figures for 23 Jul — and the sum then sat unchanged for as long as the newer store took to publish its next report, which reads as a frozen number rather than a quiet day. The tiles already name the day each figure covers, and say why in a comment right beside this code. The footer now carries the lifetime total only. AppRow.today went with it: the footer was its only caller. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ2Y7A3ZjdPCNSRzWDYVha
The repository had CI but no way to ship: no tags, no releases, and an empty appcast, while three comments in the tree already referred to a release workflow as though it existed. Sparkle was checking a feed that could never carry an item, and `make app` signs ad-hoc, which Gatekeeper refuses on any machine but the one that built it. Pushing a v* tag now builds, signs with the Developer ID, notarises, staples, signs the DMG for Sparkle, rewrites the appcast and publishes the release — the same shape as the other widgets in this family. The preflight is the part worth reading. It refuses the release when CoreInfo.version, CFBundleShortVersionString and the tag disagree, when SUPublicEDKey is missing, or when CFBundleVersion has not moved past the one already in the appcast. Each of those failures ships a release that looks healthy and silently updates nobody, so they are worth catching before the build rather than after the complaints. Info.plist gains this app's own Ed25519 public key. The private half lives only in the repository secret the workflow signs with, deliberately not in any Keychain, so it cannot collide with the single key Sparkle's generate_keys stores per machine for another app. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ2Y7A3ZjdPCNSRzWDYVha
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.
Two independent changes, one per commit.
Footer
LayoutMode.combinedTotalsummed each store'stoday— which is that store's newest reported day, not the current one — and labelled the result "today". In practice App Store figures for 5 Aug were added to Play figures for 23 Jul. The sum then stayed put until the newer store published again, so a real "+1" and a stale "+1" looked identical.StoreTilealready names the day each figure covers, and explains why in a comment beside this code. The footer now shows the lifetime total alone.AppRow.todayis removed with it — the footer was its only caller.Release pipeline
The repository had CI but no way to ship: no tags, no releases, an empty appcast, and
make appsigning ad-hoc. Three comments in the tree already spoke of a release workflow that did not exist.release.ymltriggers onv*and does what the sibling widgets do: build, Developer ID signing, DMG, notarisation, staple, Sparkle EdDSA signature, appcast rewrite, GitHub release.The preflight is new. It fails the release when:
CoreInfo.version,CFBundleShortVersionStringand the tag disagreeSUPublicEDKeyis missing fromInfo.plistCFBundleVersionhas not moved past the one already published inappcast.xmlEach of those ships a release that publishes cleanly and updates nobody.
Info.plistgains this app's own Ed25519 public key andSUEnableAutomaticChecks. The private half exists only as theSPARKLE_PRIVATE_KEYsecret — never in a Keychain, so it cannot collide with the one keygenerate_keysstores per machine for another app.Verification
make test— 140 tests, all passingCoreInfodrift, missingSUPublicEDKey, unbumpedCFBundleVersion. Each failed or passed as intended.plutil -lint Resources/Info.plist— OKEd25519PrivateKey.from_private_bytes), on a throwaway pair.All six repository secrets are set.
🤖 Generated with Claude Code
https://claude.ai/code/session_01EZ2Y7A3ZjdPCNSRzWDYVha