From ab1d8c0d28691b37200fd43f9a50eefc7a7e02de Mon Sep 17 00:00:00 2001 From: jmelovich Date: Sat, 10 Oct 2026 13:21:02 -0700 Subject: [PATCH] ci: attach the build to a release the web UI already created Cutting a release from GitHub's "Draft a new release" page would have produced a release with no app in it. Publishing there creates the tag and the release in one action, so by the time the tag event reaches the release job a release for that tag already exists. `gh release create` fails on that, the job errors, and the ZIP is never attached - leaving a published release that looks finished and contains nothing installable. The catalog would then have no artifact to pin. Check for an existing release first. If there is one, upload the assets into it with --clobber and leave its title and notes alone, since whoever wrote them in the UI meant them; otherwise create the draft as before. Both routes now end with the same three assets attached. The contentVersion rule is unchanged and still enforced either way: the web route means editing sce_sys/param.json in the browser and committing it before drafting the release, because the tag the UI creates points at the current head of the branch. For v1.0.0 that happens to need no edit, the committed baseline already being 01.000.000. Tested: make test passes (13 tests, including a new assertion that the workflow handles an existing release); the YAML parses and every run: block passes bash -n. The round trip is exercised against the real repository next. --- .github/workflows/build.yml | 22 +++++++++++++++++++++- README.md | 7 +++++++ tests/test_tools.py | 6 ++++++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 573e2f6..c30ff37 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -106,11 +106,31 @@ jobs: name: ${{ needs.build.outputs.title-id }} path: dist - - name: Publish a draft release + # Two ways a tag gets here, and both must work. + # + # tools/release.sh + git push - the tag arrives with no release, so + # create a draft for review. + # GitHub's "Draft a new release" - publishing in the web UI creates the + # tag AND the release together, so by + # the time this runs the release already + # exists. Creating it again would fail, + # and the ZIP would never be attached; + # upload into it instead and leave the + # notes the author wrote alone. + - name: Attach the build to its release env: GH_TOKEN: ${{ github.token }} ZIP: dist/${{ needs.build.outputs.title-id }}.zip run: | + if gh release view "$GITHUB_REF_NAME" >/dev/null 2>&1; then + echo "release $GITHUB_REF_NAME already exists; uploading assets into it" + gh release upload "$GITHUB_REF_NAME" \ + "$ZIP" LICENSE THIRD_PARTY_NOTICES.md --clobber + gh release view "$GITHUB_REF_NAME" --json isDraft,assets \ + --jq '"draft=\(.isDraft) assets=\([.assets[].name]|join(","))"' + exit 0 + fi + previous=$(git describe --tags --abbrev=0 "$GITHUB_REF_NAME^" 2>/dev/null || true) { printf 'Unpack `%s` into `/data/homebrew/` on the console, then launch\n' "$(basename "$ZIP")" diff --git a/README.md b/README.md index c356d78..aaf4efd 100644 --- a/README.md +++ b/README.md @@ -179,6 +179,13 @@ git push origin v1.1.0 CI then builds and opens a **draft** release with the ZIP attached. **Publish it** from the Releases page — a draft cannot be downloaded, so stores and users can't see it. +You can do it entirely in the browser instead: edit `sce_sys/param.json` to raise +`contentVersion`, commit it to `main`, then **Releases → Draft a new release**, type the +matching new tag (`v1.1.0`), and **Publish release**. That creates the tag and the release +together; CI then verifies the version and uploads the ZIP into the release you just made, +leaving your notes untouched. Either route works — the only rule is that the committed +`contentVersion` and the tag agree, and CI fails the release if they don't. + Why the order matters: a PS5 decides an installed copy is out of date by comparing `sce_sys/param.json`'s `contentVersion`, and [ps5-homebrew-catalog][catalog] reads that value from the **committed** `param.json` at the release tag. If the bump isn't in the commit the tag diff --git a/tests/test_tools.py b/tests/test_tools.py index da67da5..7e2b174 100644 --- a/tests/test_tools.py +++ b/tests/test_tools.py @@ -303,6 +303,12 @@ class ToolTests(unittest.TestCase): # stamping it at build time would leave the committed value behind. self.assertIn("tools/set-content-version.sh --check", workflow) self.assertIn("--draft", workflow) + # Publishing from GitHub's web UI creates the tag and the release + # together, so the release can already exist when this job runs. + # Creating it again fails and the ZIP is never attached; the workflow + # has to upload into the existing release instead. + self.assertIn("gh release view", workflow) + self.assertIn("gh release upload", workflow) # Pinned, not floating: this toolchain needs the Clang 18 image, which # only ubuntu-24.04 carries. Ignore comments, which explain the pin. code = "\n".join(