From fd19c464d5f60903d8608f05608a3d3ca78af1cb Mon Sep 17 00:00:00 2001 From: Alexander Ng Date: Sun, 27 Sep 2026 03:05:53 -0700 Subject: [PATCH 1/2] fix: publish releases only after every asset is uploaded release-please published the GitHub release before CD built and uploaded archives, so /releases/latest pointed at a release with no assets for several minutes and both installers failed. Releases are now created as drafts (with the tag forced immediately so changelogs still find it), assets upload to the draft via gh, and a final job publishes it once every target has uploaded. A failed build leaves the draft unpublished. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/cd.yml | 32 +++++++++++++++++++++++++------- .release-please-manifest.json | 3 +++ release-please-config.json | 11 +++++++++++ 3 files changed, 39 insertions(+), 7 deletions(-) create mode 100644 .release-please-manifest.json create mode 100644 release-please-config.json diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 7e2e423..1adc0ef 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -15,12 +15,16 @@ jobs: envx_version: ${{ env.ENVX_VERSION }} build: ${{ env.BUILD }} steps: + # Releases start as drafts so /releases/latest never points at a release + # without assets; publish-release below makes it public. The tag is still + # created immediately (force-tag-creation) so changelogs find it. - name: Release Please - uses: GoogleCloudPlatform/release-please-action@v4 + uses: googleapis/release-please-action@v4 id: release with: token: ${{ secrets.GITHUB_TOKEN }} - release-type: rust + config-file: release-please-config.json + manifest-file: .release-please-manifest.json - name: Set SemVer String id: set-semver @@ -139,13 +143,12 @@ jobs: fi done + # gh resolves draft releases by tag; the REST get-by-tag lookup does not. - name: Upload release archive - uses: softprops/action-gh-release@v1 + shell: bash env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: v${{ needs.release-please.outputs.envx_version }} - files: envx-${{ needs.release-please.outputs.envx_version }}-${{ matrix.target }}* + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: gh release upload "v${{ needs.release-please.outputs.envx_version }}" envx-${{ needs.release-please.outputs.envx_version }}-${{ matrix.target }}* --clobber --repo "$GITHUB_REPOSITORY" # - name: Install cargo-deb # if: matrix.target == 'x86_64-unknown-linux-musl' @@ -161,3 +164,18 @@ jobs: # with: # tag: ${{ needs.release-please.outputs.envx_version }} # file: envx-${{ needs.release-please.outputs.envx_version }}-amd64.deb + + publish-release: + name: Publish Release + needs: [release-please, build-release] + # Only publish when every target uploaded; a failed build leaves the draft. + if: needs.release-please.outputs.build == 'true' + permissions: + contents: write + runs-on: ubuntu-latest + steps: + - name: Publish draft release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TAG: v${{ needs.release-please.outputs.envx_version }} + run: gh release edit "$TAG" --draft=false --latest --repo "$GITHUB_REPOSITORY" diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 0000000..9a61761 --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "2.17.0" +} diff --git a/release-please-config.json b/release-please-config.json new file mode 100644 index 0000000..6460c15 --- /dev/null +++ b/release-please-config.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", + "packages": { + ".": { + "release-type": "rust", + "include-component-in-tag": false, + "draft": true, + "force-tag-creation": true + } + } +} From 3114244d6a3684254ad6ce7c12ceb2e01c86e024 Mon Sep 17 00:00:00 2001 From: Alexander Ng Date: Sun, 27 Sep 2026 03:12:43 -0700 Subject: [PATCH 2/2] fix: publish releases without forcing them to latest Publishing with --latest let a delayed or re-run older release displace a newer one. Publish through the API with make_latest=legacy so GitHub chooses latest by version and date. Also drop the redundant job condition (needs already gates on every build succeeding) and document the recovery path. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/cd.yml | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 1adc0ef..a91bc73 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -15,9 +15,9 @@ jobs: envx_version: ${{ env.ENVX_VERSION }} build: ${{ env.BUILD }} steps: - # Releases start as drafts so /releases/latest never points at a release - # without assets; publish-release below makes it public. The tag is still - # created immediately (force-tag-creation) so changelogs find it. + # release-please-config.json keeps releases draft until publish-release + # has every asset, so /releases/latest stays installable, and forces the + # tag immediately so the next changelog can find it. - name: Release Please uses: googleapis/release-please-action@v4 id: release @@ -143,12 +143,14 @@ jobs: fi done - # gh resolves draft releases by tag; the REST get-by-tag lookup does not. + # gh finds draft releases by tag; the REST releases/tags/{tag} endpoint cannot. - name: Upload release archive shell: bash env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: gh release upload "v${{ needs.release-please.outputs.envx_version }}" envx-${{ needs.release-please.outputs.envx_version }}-${{ matrix.target }}* --clobber --repo "$GITHUB_REPOSITORY" + VERSION: ${{ needs.release-please.outputs.envx_version }} + TARGET: ${{ matrix.target }} + run: gh release upload "v$VERSION" envx-"$VERSION"-"$TARGET"* --clobber --repo "$GITHUB_REPOSITORY" # - name: Install cargo-deb # if: matrix.target == 'x86_64-unknown-linux-musl' @@ -165,17 +167,22 @@ jobs: # tag: ${{ needs.release-please.outputs.envx_version }} # file: envx-${{ needs.release-please.outputs.envx_version }}-amd64.deb + # Skipped unless every build-release leg succeeded, leaving the draft + # unpublished. Recover with "Re-run failed jobs"; a full re-run does not + # re-emit release_created for an existing release. publish-release: name: Publish Release needs: [release-please, build-release] - # Only publish when every target uploaded; a failed build leaves the draft. - if: needs.release-please.outputs.build == 'true' permissions: contents: write runs-on: ubuntu-latest steps: + # make_latest=legacy picks latest by version and date, so a delayed + # older release cannot displace a newer one. - name: Publish draft release env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} TAG: v${{ needs.release-please.outputs.envx_version }} - run: gh release edit "$TAG" --draft=false --latest --repo "$GITHUB_REPOSITORY" + run: | + id=$(gh release view "$TAG" --json databaseId --jq .databaseId --repo "$GITHUB_REPOSITORY") + gh api --method PATCH "repos/$GITHUB_REPOSITORY/releases/$id" -F draft=false -f make_latest=legacy