diff --git a/.github/workflows/dev-version-bump.yml b/.github/workflows/dev-version-bump.yml index 45ecd4ae3f..b884b04ace 100644 --- a/.github/workflows/dev-version-bump.yml +++ b/.github/workflows/dev-version-bump.yml @@ -14,18 +14,35 @@ name: Dev version bump # sign-off that a bot cannot supply. Until that merge the red persists. This converts a # forgotten chore into a queued, reviewable change - not into an automatic repair. # -# A `release` event resolves this workflow file from the repository DEFAULT branch -# (`main`), not from `dev` - the same trap documented in cleanup-closed-pr-branches.yml. -# So merging this file to `dev` installs it but arms nothing; it first fires after an -# ordinary dev -> main promotion carries it there. +# WHY THIS IS CALLED, NOT TRIGGERED. It used to listen for `release: published`, and in +# that form it ran ZERO times across v2.37.0, v2.38.0 and v2.39.0 - every one of those +# bumps was still opened by hand (#3045, #3076, #3127). The workflow was not broken; the +# event never existed. `release.yml` creates the GitHub release with +# `GH_TOKEN: ${{ github.token }}`, and GitHub does not start workflow runs from events +# raised by the default `GITHUB_TOKEN`. A `release: published` listener therefore cannot +# observe a release this repository publishes itself, no matter which branch it sits on. +# +# The fix keeps the credential surface unchanged: no PAT, no app token, no +# `contents: write` on the release job. `release.yml` CALLS this workflow directly after +# a successful publish, so the run is a child of the release run instead of a reaction to +# an event that is never delivered. +# +# A `workflow_call` body resolves from the CALLER's ref, and `release.yml` only ever runs +# on `main` or `preview` (its own branch gate). So this file must be on `main` to take +# effect - the same promotion requirement the old comment described, now for a different +# reason. # # There is deliberately no `workflow_dispatch`: a branch-selected manual run executes # THAT branch body with `contents: write`. Re-drive a missed run by running # `bun scripts/bump-dev-version.ts package.json` locally and opening the pull # request normally. on: - release: - types: [published] + workflow_call: + inputs: + released-version: + description: "The tag that just published, e.g. v2.39.0" + required: true + type: string permissions: {} @@ -69,7 +86,7 @@ jobs: - name: Decide the version dev should carry id: decide env: - RELEASED_VERSION: ${{ github.event.release.tag_name }} + RELEASED_VERSION: ${{ inputs.released-version }} run: | set -euo pipefail bun scripts/bump-dev-version.ts "${RELEASED_VERSION}" package.json @@ -88,7 +105,7 @@ jobs: env: GH_TOKEN: ${{ github.token }} NEXT_VERSION: ${{ steps.decide.outputs.version }} - RELEASED_VERSION: ${{ github.event.release.tag_name }} + RELEASED_VERSION: ${{ inputs.released-version }} run: | set -euo pipefail diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 31ede9ab9d..458bb67e0a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -36,6 +36,41 @@ concurrency: cancel-in-progress: false jobs: + # Move `dev` past the version that just published. + # + # This is a CALL, not a `release: published` listener. The release is created with + # `github.token`, and GitHub does not start workflow runs from events that token + # raises - so a listener cannot observe a release this repository publishes itself. In + # that form it ran ZERO times across v2.37.0, v2.38.0 and v2.39.0 while every one of + # those bumps was opened by hand (#3045, #3076, #3127). + # + # `needs: publish` means this is skipped unless the publish job succeeded, so a failed + # publish or a failed release creation never opens a bump pull request; the explicit + # condition only adds the dry-run case. The called workflow declares its own + # `contents: write` / `pull-requests: write` for its own job, so nothing here gains + # write access. + # + # Both channels call this, and the double-call is safe because `bump-dev-version.ts` + # compares against what `dev` already carries. In the usual train `dev` is already at + # the stable core when the preview publishes, so that call returns `changed=false` + # ("dev already carries 2.40.0, which is ahead of the published 2.40.0-preview.*") and + # every later step is gated on that output. The stable call returns `changed=true` and + # opens the one pull request. A preview publishing while `dev` is genuinely behind + # still bumps it, which is the point. + # + # It is declared FIRST in this file, ahead of the jobs it depends on, because + # tests/ci-workflows.test.ts splits the workflow on `- name:` and reads each `run:` + # block to the start of the next one when it checks that dispatch inputs never + # interpolate into shell source. A job declared between two steps lands inside that + # window and reads as shell. Job order in YAML carries no execution meaning - `needs` + # does - so declaring it before its own dependency costs nothing. + bump-dev-version: + needs: publish + if: ${{ inputs.dry-run != true }} + uses: ./.github/workflows/dev-version-bump.yml + with: + released-version: v${{ inputs.version }} + validate-dispatch: runs-on: ubuntu-latest permissions: