Skip to content

Release pipeline, and a footer that stops mislabelling the day - #2

Merged
TadelUnso merged 2 commits into
mainfrom
feature/release-workflow
Aug 7, 2026
Merged

Release pipeline, and a footer that stops mislabelling the day#2
TadelUnso merged 2 commits into
mainfrom
feature/release-workflow

Conversation

@TadelUnso

Copy link
Copy Markdown
Owner

Two independent changes, one per commit.

Footer

LayoutMode.combinedTotal summed each store's today — 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.

StoreTile already names the day each figure covers, and explains why in a comment beside this code. The footer now shows the lifetime total alone. AppRow.today is 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 app signing ad-hoc. Three comments in the tree already spoke of a release workflow that did not exist.

release.yml triggers on v* 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, CFBundleShortVersionString and the tag disagree
  • SUPublicEDKey is missing from Info.plist
  • CFBundleVersion has not moved past the one already published in appcast.xml

Each of those ships a release that publishes cleanly and updates nobody.

Info.plist gains this app's own Ed25519 public key and SUEnableAutomaticChecks. The private half exists only as the SPARKLE_PRIVATE_KEY secret — never in a Keychain, so it cannot collide with the one key generate_keys stores per machine for another app.

Verification

  • make test — 140 tests, all passing
  • Preflight extracted and run against five cases: matching tag, tag/plist mismatch, CoreInfo drift, missing SUPublicEDKey, unbumped CFBundleVersion. Each failed or passed as intended.
  • plutil -lint Resources/Info.plist — OK
  • Ed25519 key format verified against the exact call the workflow makes (Ed25519PrivateKey.from_private_bytes), on a throwaway pair.
  • Steps 2–12 are not exercised: they need the Developer ID and notarisation credentials, so the first tag is also their first real run.

All six repository secrets are set.

🤖 Generated with Claude Code

https://claude.ai/code/session_01EZ2Y7A3ZjdPCNSRzWDYVha

TadelUnso and others added 2 commits August 6, 2026 19:27
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
@TadelUnso
TadelUnso merged commit d1aeffa into main Aug 7, 2026
2 of 4 checks passed
@TadelUnso
TadelUnso deleted the feature/release-workflow branch August 7, 2026 02:05
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