From d49d18a93cef8aec133fbfadb4130d53c29d2c88 Mon Sep 17 00:00:00 2001 From: JeffreyChen Date: Tue, 21 Apr 2026 18:34:56 +0800 Subject: [PATCH] Switch stable publish to PR-based version bump Signed commit pushed to release/bump-v branch, PR opened against main and auto-merged when possible. Release tag targets the bump commit SHA so it survives branch deletion. --- .github/workflows/ci-stable.yml | 61 ++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-stable.yml b/.github/workflows/ci-stable.yml index 59fe7f9..b2d5c36 100644 --- a/.github/workflows/ci-stable.yml +++ b/.github/workflows/ci-stable.yml @@ -104,7 +104,8 @@ jobs: print(f"stable.toml -> {stable_version}") print(f"dev.toml -> {dev_version}") PY - - name: Commit bumped versions back to main (signed via GitHub API) + - name: Push signed bump commit to a release branch + id: bump_commit env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} VERSION: ${{ steps.version.outputs.version }} @@ -114,12 +115,39 @@ jobs: import json import os import subprocess + import urllib.error import urllib.request head_oid = subprocess.check_output(["git", "rev-parse", "HEAD"], text=True).strip() repo = os.environ["GITHUB_REPOSITORY"] token = os.environ["GH_TOKEN"] version = os.environ["VERSION"] + branch = f"release/bump-v{version}" + + def api(path, method="GET", body=None): + req = urllib.request.Request( + f"https://api.github.com/{path}", + data=(json.dumps(body).encode("utf-8") if body is not None else None), + headers={ + "Authorization": f"Bearer {token}", + "Accept": "application/vnd.github+json", + "Content-Type": "application/json", + }, + method=method, + ) + with urllib.request.urlopen(req) as resp: + raw = resp.read() + return json.loads(raw) if raw else None + + try: + api( + f"repos/{repo}/git/refs", + method="POST", + body={"ref": f"refs/heads/{branch}", "sha": head_oid}, + ) + except urllib.error.HTTPError as error: + if error.code != 422: # 422 = ref already exists; OK to reuse + raise def b64(path: str) -> str: with open(path, "rb") as fp: @@ -139,7 +167,7 @@ jobs: "input": { "branch": { "repositoryNameWithOwner": repo, - "branchName": "main", + "branchName": branch, }, "message": { "headline": f"Bump version to v{version} [skip ci]", @@ -169,8 +197,31 @@ jobs: body = json.loads(resp.read()) if body.get("errors"): raise SystemExit(f"GraphQL error: {body['errors']}") - print(body["data"]["createCommitOnBranch"]["commit"]) + commit = body["data"]["createCommitOnBranch"]["commit"] + print(f"bump commit: {commit['oid']} -> {commit['url']}") + + with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as fp: + fp.write(f"branch={branch}\n") + fp.write(f"oid={commit['oid']}\n") PY + - name: Open PR for the version bump + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VERSION: ${{ steps.version.outputs.version }} + BRANCH: ${{ steps.bump_commit.outputs.branch }} + run: | + gh pr create \ + --base main \ + --head "$BRANCH" \ + --title "Bump version to v${VERSION} [skip ci]" \ + --body "Automated patch bump emitted by the stable publish workflow. [skip ci]" + - name: Try to auto-merge the bump PR + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BRANCH: ${{ steps.bump_commit.outputs.branch }} + run: | + gh pr merge "$BRANCH" --squash --auto --delete-branch \ + || echo "auto-merge unavailable; PR left open for manual merge" - name: Use stable.toml as pyproject.toml run: cp stable.toml pyproject.toml - name: Build sdist and wheel @@ -185,7 +236,9 @@ jobs: - name: Create GitHub Release env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BUMP_OID: ${{ steps.bump_commit.outputs.oid }} run: | gh release create "v${{ steps.version.outputs.version }}" dist/* \ --title "v${{ steps.version.outputs.version }}" \ - --generate-notes + --generate-notes \ + --target "$BUMP_OID"