From ea5a100a744a73f0aaa62f2606296d8193935c59 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Wed, 4 Mar 2026 10:29:05 -0800 Subject: [PATCH] Defer release commit+tag to finalize job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the version bump commit and tag creation out of the preflight job into a new finalize job that runs only after build, publish, and release all succeed. This prevents orphaned version commits and tags on main when downstream jobs fail. - Preflight: validate version, lint/test only — no commit/tag/push - Release: softprops/action-gh-release creates tag for workflow_dispatch - Finalize: bump package.json versions, refresh lockfile, commit to main Co-Authored-By: Claude Opus 4.6 --- .github/workflows/release.yml | 134 ++++++++++++++++++---------------- 1 file changed, 72 insertions(+), 62 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2000f98b9cd3cd6a1528c0d4c2e806cc8c9f985c..e17bf553ef6a948e9271f6707bbd124de451a855 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -22,12 +22,10 @@ jobs: outputs: version: ${{ steps.release_meta.outputs.version }} tag: ${{ steps.release_meta.outputs.tag }} - ref: ${{ steps.release_ref.outputs.value }} + ref: ${{ github.sha }} steps: - name: Checkout uses: actions/checkout@v4 - with: - fetch-depth: 0 - id: release_meta name: Resolve release version @@ -58,32 +56,6 @@ jobs: with: node-version-file: package.json - - name: Update version strings - if: github.event_name == 'workflow_dispatch' - env: - RELEASE_VERSION: ${{ steps.release_meta.outputs.version }} - run: | - node --input-type=module -e ' - import { readFileSync, writeFileSync } from "node:fs"; - - const files = [ - "apps/server/package.json", - "apps/desktop/package.json", - "apps/web/package.json", - "packages/contracts/package.json", - ]; - - for (const file of files) { - const packageJson = JSON.parse(readFileSync(file, "utf8")); - packageJson.version = process.env.RELEASE_VERSION; - writeFileSync(file, `${JSON.stringify(packageJson, null, 2)}\n`); - } - ' - - - name: Refresh lockfile - if: github.event_name == 'workflow_dispatch' - run: bun install - - name: Install dependencies run: bun install --frozen-lockfile @@ -96,39 +68,6 @@ jobs: - name: Test run: bun run test - - name: Commit and push release version + tag - if: github.event_name == 'workflow_dispatch' - shell: bash - env: - RELEASE_TAG: ${{ steps.release_meta.outputs.tag }} - run: | - if git ls-remote --exit-code --tags origin "$RELEASE_TAG" >/dev/null 2>&1; then - echo "Tag $RELEASE_TAG already exists on origin." >&2 - exit 1 - fi - - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - - if ! git diff --quiet -- apps/server/package.json apps/desktop/package.json apps/web/package.json packages/contracts/package.json bun.lock; then - git add apps/server/package.json apps/desktop/package.json apps/web/package.json packages/contracts/package.json bun.lock - git commit -m "chore(release): prepare $RELEASE_TAG" -m "Co-authored-by: codex " - fi - - git tag "$RELEASE_TAG" - git push origin "HEAD:${GITHUB_REF_NAME}" - git push origin "refs/tags/$RELEASE_TAG" - - - id: release_ref - name: Resolve source ref - shell: bash - run: | - if [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then - echo "value=refs/tags/${{ steps.release_meta.outputs.tag }}" >> "$GITHUB_OUTPUT" - else - echo "value=${GITHUB_SHA}" >> "$GITHUB_OUTPUT" - fi - build: name: Build ${{ matrix.label }} needs: preflight @@ -320,6 +259,7 @@ jobs: tag_name: ${{ needs.preflight.outputs.tag }} name: T3 Code v${{ needs.preflight.outputs.version }} generate_release_notes: true + make_latest: true files: | release-assets/*.dmg release-assets/*.zip @@ -328,3 +268,73 @@ jobs: release-assets/*.blockmap release-assets/latest*.yml fail_on_unmatched_files: true + + finalize: + name: Finalize release + needs: [preflight, release] + runs-on: ubuntu-24.04 + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: main + fetch-depth: 0 + + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version-file: package.json + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version-file: package.json + + - name: Update version strings + env: + RELEASE_VERSION: ${{ needs.preflight.outputs.version }} + run: | + node --input-type=module -e ' + import { readFileSync, writeFileSync } from "node:fs"; + + const files = [ + "apps/server/package.json", + "apps/desktop/package.json", + "apps/web/package.json", + "packages/contracts/package.json", + ]; + + let changed = false; + for (const file of files) { + const packageJson = JSON.parse(readFileSync(file, "utf8")); + if (packageJson.version !== process.env.RELEASE_VERSION) { + packageJson.version = process.env.RELEASE_VERSION; + writeFileSync(file, `${JSON.stringify(packageJson, null, 2)}\n`); + changed = true; + } + } + + if (!changed) { + console.log("All package.json versions already match release version."); + } + ' + + - name: Refresh lockfile + run: bun install + + - name: Commit and push version bump + shell: bash + env: + RELEASE_TAG: ${{ needs.preflight.outputs.tag }} + run: | + if git diff --quiet -- apps/server/package.json apps/desktop/package.json apps/web/package.json packages/contracts/package.json bun.lock; then + echo "No version changes to commit." + exit 0 + fi + + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + + git add apps/server/package.json apps/desktop/package.json apps/web/package.json packages/contracts/package.json bun.lock + git commit -m "chore(release): prepare $RELEASE_TAG" + git push origin HEAD:main -- 2.54.0