diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 00cc801..68f2cb1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,6 +18,7 @@ concurrency: permissions: contents: write + pull-requests: write jobs: publish-rust: @@ -107,16 +108,30 @@ jobs: perl -0pi -e 's/(\[package\][\s\S]*?\nversion = ")[^"]+(")/$1$ENV{NEXT_VERSION}$2/' Cargo.toml cargo update -p "$CRATE_NAME" --precise "$NEXT_VERSION" - - name: Commit version bump and tag + # `main` is protected by a repository ruleset that requires all + # changes to land through a pull request (no direct pushes), and the + # workflow's GITHUB_TOKEN is not on that ruleset's bypass list. So the + # version-bump commit is pushed to a throwaway release branch and + # landed on `main` via an auto-merged PR instead of `git push`ing + # `HEAD` straight at `main` (which the ruleset rejects with GH013). + - name: Commit version bump + id: commit env: NEXT_VERSION: ${{ steps.version.outputs.next_version }} RELEASE_TAG: ${{ steps.version.outputs.tag }} run: | + set -euo pipefail + git config user.name "github-actions[bot]" git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + + release_branch="release/${RELEASE_TAG}" + git checkout -b "${release_branch}" git add Cargo.toml Cargo.lock git commit -m "Release ${RELEASE_TAG}" - git tag -a "${RELEASE_TAG}" -m "Release ${RELEASE_TAG}" + git push origin "${release_branch}" + + echo "branch=${release_branch}" >> "$GITHUB_OUTPUT" # `$CRATE_NAME` (and its path dependency `tinycortex-api`) both carry # `publish = false` right now: `tinycortex-api` depends on `tinymemory-api` @@ -144,11 +159,36 @@ jobs: if: steps.publishable.outputs.publishable == 'true' run: cargo package --locked -p "$CRATE_NAME" - - name: Push release commit and tag + - name: Open and merge release PR + id: merge env: + GH_TOKEN: ${{ github.token }} RELEASE_TAG: ${{ steps.version.outputs.tag }} + RELEASE_BRANCH: ${{ steps.commit.outputs.branch }} run: | - git push origin "HEAD:${GITHUB_REF_NAME}" + set -euo pipefail + + pr_url="$(gh pr create \ + --base "${GITHUB_REF_NAME}" \ + --head "${RELEASE_BRANCH}" \ + --title "Release ${RELEASE_TAG}" \ + --body "Automated version bump for ${RELEASE_TAG}.")" + # This repository allows merge commits only (squash and rebase are + # both disabled), so the release PR must be merged with --merge. + gh pr merge "${pr_url}" --merge --delete-branch + + git fetch origin "${GITHUB_REF_NAME}" + merge_sha="$(git rev-parse "origin/${GITHUB_REF_NAME}")" + echo "sha=${merge_sha}" >> "$GITHUB_OUTPUT" + + - name: Tag and push release + env: + RELEASE_TAG: ${{ steps.version.outputs.tag }} + MERGE_SHA: ${{ steps.merge.outputs.sha }} + run: | + set -euo pipefail + + git tag -a "${RELEASE_TAG}" -m "Release ${RELEASE_TAG}" "${MERGE_SHA}" git push origin "${RELEASE_TAG}" - name: Publish to crates.io