From 3ac7f251c56d7bc0142b862d78a752718b1fcb57 Mon Sep 17 00:00:00 2001 From: Joseph Mearman Date: Sun, 13 Sep 2026 16:19:09 +0100 Subject: [PATCH] feat(release): commit the version bump and changelog back to main MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @semantic-release/git was a devDependency but never wired into the plugins array, so every release only ever bumped package.json inside the release job's own ephemeral working copy — nothing was ever committed back, and CHANGELOG.md was never written to the repo at all. Release notes existed only on the GitHub Release itself. Enables the plugin (assets: CHANGELOG.md, package.json), tagged by @semantic-release/github afterwards so the release tag lands on the commit that actually carries the bump and changelog, not the commit that triggered the release. Needs the exadev App's token available before checkout runs, not after, since the branch ruleset refuses a direct push to main from any other token — the app-token generation step and the checkout step are reordered accordingly. --- .github/workflows/ci.yml | 22 +++++++++++----------- release.config.ts | 11 +++++++++-- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6fb25f2..8a5a771 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -125,9 +125,19 @@ jobs: pull-requests: write id-token: write steps: + # Minted before checkout, not after: @semantic-release/git's changelog commit-back needs a real `git push` against main, which the branch ruleset refuses for the workflow's own token — only the exadev App is a permitted bypasser. Generating it first lets checkout itself configure git's credentials with it. + - name: Generate ExaDev App token + id: app-token + uses: actions/create-github-app-token@v2 + with: + app-id: ${{ secrets.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + owner: ExaDev + repositories: cc-peer + - uses: actions/checkout@v5 with: - persist-credentials: false + token: ${{ steps.app-token.outputs.token }} fetch-depth: 0 - uses: pnpm/action-setup@v4 @@ -144,16 +154,6 @@ jobs: - name: Install run: pnpm install --frozen-lockfile - # The changelog commit-back pushes directly to main, which the branch ruleset refuses for the workflow token. Mint an installation token for the exadev App (the ruleset's permitted bypasser) instead. - - name: Generate ExaDev App token - id: app-token - uses: actions/create-github-app-token@v2 - with: - app-id: ${{ secrets.APP_ID }} - private-key: ${{ secrets.APP_PRIVATE_KEY }} - owner: ExaDev - repositories: cc-peer - - name: Release env: GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} diff --git a/release.config.ts b/release.config.ts index 21d632c..6c25028 100644 --- a/release.config.ts +++ b/release.config.ts @@ -30,8 +30,15 @@ const config: GlobalConfig = { ], ["@semantic-release/changelog", { changelogFile: "CHANGELOG.md" }], ["@semantic-release/npm", { pkgRoot: "." }], - // @semantic-release/git is intentionally absent: its changelog commit-back - // pushes directly to main, which the branch ruleset refuses for any token that is not the exadev App bypasser. Re-add it together with the App-token minting in ci.yml once the App private key is available as a repo secret; until then release notes live on the GitHub release only. + // Pushes the version bump and changelog back to main as a real commit, tagged by @semantic-release/github below (which runs after, so the tag lands on this commit, not the one that triggered the release). Needs the exadev App's token, since the branch ruleset refuses a direct push to main from any other token — see ci.yml's own comment on generating it before checkout. + [ + "@semantic-release/git", + { + assets: ["CHANGELOG.md", "package.json"], + message: + "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}", + }, + ], ["@semantic-release/github", { addReleases: "bottom" }], ], };