From 767ed3786831802f8be6c8552e9399d1ee955104 Mon Sep 17 00:00:00 2001 From: nicodes Date: Mon, 3 Aug 2026 12:58:04 -0600 Subject: [PATCH] Tell the marketplace when a game is released MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cutting a release built the package, tagged it and uploaded it, and stopped. Somebody then had to run `termcade publish` by hand, or the catalog never learned the release existed — which is how a marketplace ends up behind its own games. The workflow publishes now, after the GitHub release rather than before: publishing is a claim that a package is at these coordinates and the registry verifies it by fetching, so claiming first would have it fetch something not yet uploaded. It uses a scoped key, not a password. The key publishes as aviorstudio and can do nothing else, so what a leak costs is bounded by one handle. Without the secret the release still cuts and the step warns with the command to run by hand — a release that failed after tagging is much harder to unpick than one the registry has not been told about. The secret is read into the environment and the step decides from there. `secrets` in a step-level `if` evaluates to something unhelpful rather than failing loudly, and a publish that silently never ran is exactly the failure this exists to prevent. Also fixes the install line in every release note and in the README. Both said `termcade add aviorstudio/@`, and pinning was removed — so the instruction shipped with each release was one the arcade now refuses. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/release.yml | 37 ++++++++++++++++++++++++++++++++++- README.md | 17 +++++++++++++++- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 66f94e8..ef5b6df 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -113,7 +113,7 @@ jobs: Install it from the marketplace: \`\`\`sh - termcade add aviorstudio/$GAME@$VERSION + termcade add aviorstudio/$GAME \`\`\` \`\`\` @@ -128,3 +128,38 @@ jobs: "$GAME/build/$GAME.tcade" \ "$GAME/build/$GAME.tcade.sha256" \ --target "$GITHUB_SHA" --title "$GAME $VERSION" --notes-file notes.md + + # Tell the marketplace the release exists. + # + # After the GitHub release, not before: publishing is a claim that a + # package is at these coordinates, and the registry verifies it by + # fetching. Claiming first would have it fetch something that is not + # there yet. + # + # A scoped publish key rather than a password. It publishes as + # aviorstudio and can do nothing else — not read a library, not mint + # another key, not touch an account — so what a leak costs is bounded by + # this one handle. + # + # Skipped when the secret is absent, so a release still cuts on a fork or + # before the key exists. The registry can always be told later; a release + # that failed after tagging is much harder to unpick. + # + # The secret is read into the environment and the step decides from + # there, rather than through a step-level `if` on the secrets context — + # that is the kind of expression that evaluates to something unhelpful + # instead of failing loudly, and a publish step which silently never ran + # would leave the marketplace quietly out of date. + - name: Publish to the marketplace + env: + TERMCADE_TOKEN: ${{ secrets.TERMCADE_TOKEN }} + GAME: ${{ inputs.game }} + TAG: ${{ steps.version.outputs.tag }} + run: | + set -euo pipefail + if [ -z "${TERMCADE_TOKEN:-}" ]; then + echo "::warning::TERMCADE_TOKEN is not set — the release exists on GitHub, but the marketplace has not been told about it. Publish it by hand with: termcade publish https://github.com/$GITHUB_REPOSITORY $TAG $GAME.tcade" + exit 0 + fi + go run github.com/aviorstudio/termcade@v0.0.4 publish \ + "https://github.com/$GITHUB_REPOSITORY" "$TAG" "$GAME.tcade" diff --git a/README.md b/README.md index ff5516d..e51bad0 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ before it has an account or a network. They install the ordinary way too: ```sh termcade add aviorstudio/asteroid termcade add aviorstudio/tetris -termcade add aviorstudio/brickough@0.0.1 # or pin a version +termcade add aviorstudio/brickough ``` The source stays here rather than in the arcade so the two move separately — @@ -26,6 +26,21 @@ these three happening to use it. To refresh the vendored packs after changing a game, from a termcade checkout beside this one: `go generate ./internal/starter`. +## Releasing + +`release.yml` builds a game, tags it, cuts a GitHub release, and tells the +marketplace about it — in that order, because publishing is a claim the +registry verifies by fetching, so the asset has to exist first. + +That last step needs a `TERMCADE_TOKEN` secret: a publish key scoped to the +`aviorstudio` handle, made with `termcade keys new`. It publishes and nothing +else — it cannot read a library, mint another key, or touch an account — so a +leak is bounded by this one handle. + +Without the secret the release still cuts and the workflow warns, with the +command to publish by hand. A release that failed after tagging is much harder +to unpick than one the registry has not heard about yet. + ## The games | Game | What it is |