Create release PR #1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Create release PR | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: "Version to release (e.g., 0.6.6)" | |
| required: true | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| jobs: | |
| release-pr: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| ref: main | |
| - name: Setup uv | |
| uses: astral-sh/setup-uv@v5 | |
| with: | |
| enable-cache: true | |
| - name: Fetch tags | |
| run: git fetch origin --tags --prune | |
| - name: Ensure release branch does not exist | |
| env: | |
| RELEASE_VERSION: ${{ inputs.version }} | |
| run: | | |
| branch="release/v${RELEASE_VERSION}" | |
| if git ls-remote --exit-code --heads origin "$branch" >/dev/null 2>&1; then | |
| echo "Branch $branch already exists on origin." >&2 | |
| exit 1 | |
| fi | |
| - name: Update version | |
| env: | |
| RELEASE_VERSION: ${{ inputs.version }} | |
| run: | | |
| python - <<'PY' | |
| import os | |
| import pathlib | |
| import re | |
| import sys | |
| version = os.environ["RELEASE_VERSION"] | |
| if version.startswith("v"): | |
| print("Version must not start with 'v' (use x.y.z...).", file=sys.stderr) | |
| sys.exit(1) | |
| if ".." in version: | |
| print("Version contains consecutive dots (use x.y.z...).", file=sys.stderr) | |
| sys.exit(1) | |
| if not re.match(r"^\d+\.\d+(\.\d+)*([a-zA-Z0-9\.-]+)?$", version): | |
| print( | |
| "Version must be semver-like (e.g., 0.6.6, 0.6.6-rc1, 0.6.6.dev1).", | |
| file=sys.stderr, | |
| ) | |
| sys.exit(1) | |
| path = pathlib.Path("pyproject.toml") | |
| text = path.read_text() | |
| updated, count = re.subn( | |
| r'(?m)^version\s*=\s*"[^\"]+"', | |
| f'version = "{version}"', | |
| text, | |
| ) | |
| if count != 1: | |
| print("Expected to update exactly one version line.", file=sys.stderr) | |
| sys.exit(1) | |
| if updated == text: | |
| print("Version already set; no changes made.", file=sys.stderr) | |
| sys.exit(1) | |
| path.write_text(updated) | |
| PY | |
| - name: Sync dependencies | |
| run: make sync | |
| - name: Configure git | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| - name: Create release branch and commit | |
| env: | |
| RELEASE_VERSION: ${{ inputs.version }} | |
| run: | | |
| branch="release/v${RELEASE_VERSION}" | |
| git checkout -b "$branch" | |
| git add pyproject.toml uv.lock | |
| if git diff --cached --quiet; then | |
| echo "No changes to commit." >&2 | |
| exit 1 | |
| fi | |
| git commit -m "Bump version to ${RELEASE_VERSION}" | |
| git push --set-upstream origin "$branch" | |
| - name: Run Codex release review | |
| uses: openai/codex-action@v1 | |
| with: | |
| openai-api-key: ${{ secrets.PROD_OPENAI_API_KEY }} | |
| prompt-file: .github/codex/prompts/release-review.md | |
| output-file: release-review.md | |
| safety-strategy: drop-sudo | |
| sandbox: read-only | |
| - name: Build PR body | |
| run: | | |
| python - <<'PY' | |
| import pathlib | |
| report = pathlib.Path("release-review.md").read_text() | |
| pathlib.Path("pr-body.md").write_text(report) | |
| PY | |
| - name: Create or update PR | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| RELEASE_VERSION: ${{ inputs.version }} | |
| run: | | |
| head_branch="release/v${RELEASE_VERSION}" | |
| pr_number="$(gh pr list --head "$head_branch" --base "main" --json number --jq '.[0].number // empty')" | |
| if [ -z "$pr_number" ]; then | |
| gh pr create \ | |
| --title "Release ${RELEASE_VERSION}" \ | |
| --body-file pr-body.md \ | |
| --base "main" \ | |
| --head "$head_branch" | |
| else | |
| gh pr edit "$pr_number" --title "Release ${RELEASE_VERSION}" --body-file pr-body.md | |
| fi |