Skip to content

Put the installers on the release page people actually open - #3

Merged
jwussler merged 4 commits into
mainfrom
release-assets
Sep 2, 2026
Merged

Put the installers on the release page people actually open#3
jwussler merged 4 commits into
mainfrom
release-assets

Conversation

@jwussler

@jwussler jwussler commented Sep 2, 2026

Copy link
Copy Markdown
Owner

Independent of #1 and #2 — branches off main, touches only .github/workflows/release.yml.

All 16 releases on this repo have zero assets, and they carry the full "download HamDeckPusher-win-Setup.exe" notes regardless — telling the reader to download a file that isn't there. v0.1.29's artifacts were on jwussler/hamdeck-releases; every tag before it has no downloadable installer anywhere.

Nothing ever failed. gh release create is perfectly happy to publish a release with an empty file list, and the job goes green.

Changes

  • Publish to both repos from the same step, with the same file list, so they can't drift. hamdeck-releases stays the canonical public download — this repo is private and Velopack's updater can't read it without a token that would be embedded in every copy handed to a friend. But the source repo is where its own author goes to find a build.
  • Refuse to publish an empty release, and read the asset count back from the API afterwards and fail if it's short. That's the check that was missing.
  • create-or-upload, so re-running a tag tops up an existing release instead of failing on "already exists" and leaving it half filled.
  • The macOS job uploads to both too and reads the .dmg back — it publishes the one asset that comes from a different job than the rest, so it can go missing without the publish gate noticing.
  • Two tokens, not one falling back to the other. The fine-grained PAT is scoped to hamdeck-releases and can't write here; github.token can't write there. One variable holding whichever exists fails on one of them.

Gate proven to fail

Stubbed gh, three cases:

case result
dist/ yielded no files refusing to publish an empty release, exit 1
files exist, release reports back 0 assets (the 16-release bug) has 0 assets, expected 3, exit 1
release reports back complete both repos pass, exit 0

Already done by hand

v0.1.29's 7 assets were mirrored onto this repo's release, so the link that prompted this isn't a dead end any more. The 15 older releases are left as they are — they were superseded before they had anything to attach.

🤖 Generated with Claude Code

https://claude.ai/code/session_01EqubrbjLXwz1GrVgmTcrf9

@jwussler

jwussler commented Sep 2, 2026

Copy link
Copy Markdown
Owner Author

Two more commits, from what the v0.1.29 page actually showed.

The Windows client was never missing — it was mislabelled. hamdeck-qml.exe (1.29 MB, signed) ships inside HamDeckPusher-win-Setup.exe. One installer, both apps, updated together — that part was deliberate. But the download is named after the Pusher, so the release page never said the client was in there. It is now HamDeck-win-Setup.exe, packTitle "HamDeck", and the notes say what it contains.

⚠️ The packId stays HamDeckPusher. It's Velopack's update identity — changing it orphans every existing install silently: they keep running and never see another update. Only the file name and display title move. The file name is safe to change precisely because the updater never fetches it: RELEASES points at the .nupkg; Setup.exe is only what a human downloads once, which is the whole problem being fixed.

The version was drifting. client/CMakeLists.txt hardcoded VERSION 0.1.15, so v0.1.29 shipped hamdeck-client_0.1.15_amd64.deb — built from the right commit, named from a literal nobody had touched in fourteen releases. The pusher took its version from the tag; the client didn't. It now comes from the tag on all three platforms, 0.0.0 fallback for a local build. Same number feeds CFBundleShortVersionString, so the Mac app would have told Get Info it was 0.1.15 as well.

New gate, proven to fail first:

file list result
the real v0.1.29 (hamdeck-client_0.1.15_amd64.deb) does not carry the release version 0.1.29, exit 1
corrected (_0.1.29_) passes

Still outstanding, not addressed here: the Windows arm64 leg fails at Stage the Qt runtime beside the binary, and it's continue-on-error, so releases publish without it and nothing says so. Windows on ARM runs the x64 build under emulation, so it's an optimisation rather than enablement — but the silence is the bad part.

jwussler and others added 4 commits September 2, 2026 15:46
All 16 releases on this repo have zero assets, and they carry the full
"download HamDeckPusher-win-Setup.exe" notes anyway - telling the reader to
download a file that is not there. The artifacts for v0.1.29 were on
jwussler/hamdeck-releases; every tag before it has no downloadable installer
anywhere. Nothing ever failed: gh release create is perfectly happy to publish
a release with an empty file list, and the job goes green.

- Publish to BOTH repos from the same step, with the same file list, so they
  cannot drift. hamdeck-releases stays the canonical public download - this
  repo is private and Velopack's updater cannot read it without a token that
  would have to be embedded in every copy handed to a friend. But the source
  repo is where its own author goes to find a build, and for 16 tags what he
  found was a page of instructions and a Source code (zip) link.
- Refuse to publish when dist/ yielded no files, and read the asset count back
  from the API afterwards and fail if it is short. That is the check that was
  missing: the failure mode is a release that publishes successfully with
  nothing attached.
- create-or-upload, so re-running a tag tops up an existing release instead of
  failing on "already exists" and leaving it half filled.
- The macOS job uploads to both too, and reads the .dmg back. It publishes the
  one asset that comes from a different job than the rest, so it can go missing
  without the publish job's count gate seeing it.
- Two tokens rather than one falling back to the other: the fine-grained PAT is
  scoped to hamdeck-releases and cannot write here, github.token cannot write
  there, and a single variable holding whichever exists fails on one of them.

Gate proven against a stubbed gh: an empty dist/ refuses, a release that
reports back 0 assets fails with the count, and a complete one passes.

v0.1.29's assets were mirrored onto this repo's release by hand, so the link
that prompted this is no longer a dead end.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EqubrbjLXwz1GrVgmTcrf9
…rifting

Two things the v0.1.29 page got wrong, both from the same habit of naming
things in one place and building them from another.

The Windows client was on the page all along - hamdeck-qml.exe ships inside
HamDeckPusher-win-Setup.exe, signed like everything else - but the download is
named after the Pusher, so nothing said the client was in there. The installer
is now HamDeck-win-Setup.exe with packTitle "HamDeck", and the notes say what
it contains.

⚠️ The packId stays HamDeckPusher. It is Velopack's update identity: changing
it orphans every existing install silently - they keep running and never see
another update. Only the file name and the display title move, and the file
name is safe precisely because the updater never fetches it. RELEASES points at
the .nupkg; Setup.exe is only what a human downloads once, which is the whole
problem being fixed.

The client version was hardcoded in client/CMakeLists.txt, so v0.1.29 shipped
hamdeck-client_0.1.15_amd64.deb - built from the right commit, named from a
literal nobody had touched in fourteen releases. The pusher took its version
from the tag and the client did not. It now comes from the tag on all three
platforms, with 0.0.0 as the fallback for a local build. The same number feeds
CFBundleShortVersionString, so the Mac app would have told Get Info it was
0.1.15 too.

Both gates proven to fail before being wired in: the version check rejects the
real v0.1.29 file list and passes the corrected one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EqubrbjLXwz1GrVgmTcrf9
Releasing as a group of apps only means something if they can be shown to carry
the same number. Filenames cannot show it: the DMG and HamDeck-win-Setup.exe
have no version in their names at all, so the publish job's filename check is
blind to exactly the two artifacts a person downloads.

- The .deb's control Version is read back with dpkg-deb after packaging. The
  filename is what CPack chose to call it; the control field is what dpkg and
  apt compare when deciding whether an upgrade is an upgrade.
- The Mac bundle's CFBundleShortVersionString is read out of the built
  Info.plist before it is signed. That is the only place the Mac build states
  its version, and it is what Get Info shows the operator.

Proven against real packages: one built at 0.1.15 and released as 0.1.30 is
refused with both numbers named; one built from the tag passes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EqubrbjLXwz1GrVgmTcrf9
A zip is not a deliverable. It asks the person downloading it to pick an exe
out of 1,369 files and make their own shortcut, and nobody using this project
is going to do that. Mac has a .dmg and Linux has .debs; Windows had the client
only as a folder inside somebody else's package.

- client/packaging/hamdeck-remote.iss builds HamDeckRemote-win-Setup.exe with
  Inno Setup: per-user, no admin prompt, Start Menu and optional desktop
  shortcut, uninstall entry. It packages the staged tree AFTER the signing step
  has run over it, so the files inside are signed, and the wrapper Inno produces
  is then signed itself - SmartScreen judges the wrapper, not its contents.
  It refuses to build if platforms\qwindows.dll is absent, because that installs
  cleanly and then fails to start with no clue which file is missing.
- Its own artifact name. Two uploads sharing one name is a race with an
  arbitrary winner, which would silently drop one of the two Windows installers.
- The publish job now refuses to release unless every platform has something to
  double-click, and rejects any artifact that is neither an installer nor one of
  the three named Velopack update-feed files. A new stray file is refused rather
  than quietly joining them.

Gate proven against four file lists: today's page (zip, no client installer)
fails, a missing client installer fails, a stray zip fails, and what 0.1.30 will
publish passes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EqubrbjLXwz1GrVgmTcrf9
@jwussler
jwussler merged commit c9593ed into main Sep 2, 2026
3 checks passed
@jwussler
jwussler deleted the release-assets branch September 2, 2026 15:50
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