From 42217565ff57e26e3a6fc6d9afbc56b8981b570b Mon Sep 17 00:00:00 2001 From: Ankur-singh Date: Thu, 28 May 2026 19:31:20 -0700 Subject: [PATCH 1/3] Add workflow: auto-release on PR merge to main Creates a GitHub Release every time a PR is merged into main. The version bumps the patch of the latest GitHub Release; on the first run (no release yet) it seeds the starting point from pyproject.toml (v0.3.0). Release versioning is independent of the in-code version after the seed, and the workflow never commits back to main (no trigger loop). Each release is tagged at the merge commit with auto-generated notes from the merged PRs. --- .github/workflows/release.yaml | 51 ++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 .github/workflows/release.yaml diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 00000000..550f5900 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,51 @@ +name: Release + +on: + pull_request: + types: [closed] + branches: [main] + +permissions: + contents: write + +concurrency: + group: release + cancel-in-progress: false + +jobs: + release: + if: github.event.pull_request.merged == true + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 # need full tag history + + - name: Compute next version + id: ver + env: + GH_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + # Bump from the latest GitHub Release (independent of the in-code version). + # First run only (no release yet): seed the start from pyproject.toml. + latest=$(gh release list --limit 1 --json tagName --jq '.[0].tagName // ""') + if [ -z "$latest" ]; then + next="v$(grep -m1 -E '^version = ' pyproject.toml | sed -E 's/^version = "([^"]+)".*/\1/')" + else + core=${latest#v}; core=${core%%.post*}; core=${core%%-*} + IFS='.' read -r major minor patch <<< "$core" + next="v${major}.${minor}.$((patch + 1))" + fi + echo "Latest release: ${latest:-none} Next: $next" + echo "tag=$next" >> "$GITHUB_OUTPUT" + + - name: Create release + env: + GH_TOKEN: ${{ github.token }} + run: | + gh release create "${{ steps.ver.outputs.tag }}" \ + --target "${{ github.event.pull_request.merge_commit_sha }}" \ + --title "${{ steps.ver.outputs.tag }}" \ + --generate-notes From 64840a234bbe07b58dab20af7236e90273c6b088 Mon Sep 17 00:00:00 2001 From: Ankur-singh Date: Thu, 28 May 2026 22:40:25 -0700 Subject: [PATCH 2/3] Seed first release at v1.0.0 Start the release series at v1.0.0 instead of seeding from pyproject.toml; subsequent merges bump the patch (v1.0.1, v1.0.2, ...). --- .github/workflows/release.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 550f5900..b8f7692c 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -29,10 +29,10 @@ jobs: run: | set -euo pipefail # Bump from the latest GitHub Release (independent of the in-code version). - # First run only (no release yet): seed the start from pyproject.toml. + # First run only (no release yet): seed the start at v1.0.0. latest=$(gh release list --limit 1 --json tagName --jq '.[0].tagName // ""') if [ -z "$latest" ]; then - next="v$(grep -m1 -E '^version = ' pyproject.toml | sed -E 's/^version = "([^"]+)".*/\1/')" + next="v1.0.0" else core=${latest#v}; core=${core%%.post*}; core=${core%%-*} IFS='.' read -r major minor patch <<< "$core" From c46e495b30ece8bb60fb86fab72d52ec5b61291f Mon Sep 17 00:00:00 2001 From: Ankur-singh Date: Thu, 28 May 2026 22:43:48 -0700 Subject: [PATCH 3/3] Bump patch from highest release, supporting manual minor bumps Select the highest existing release with 'sort -V' instead of the most recently created one. Only the patch is incremented, so publishing a higher major/minor by hand (e.g. v1.1.0) makes the next merge continue from there (v1.1.1). Also fixes numeric ordering (v1.0.10 > v1.0.9). --- .github/workflows/release.yaml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index b8f7692c..978c5f1d 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -28,9 +28,11 @@ jobs: GH_TOKEN: ${{ github.token }} run: | set -euo pipefail - # Bump from the latest GitHub Release (independent of the in-code version). - # First run only (no release yet): seed the start at v1.0.0. - latest=$(gh release list --limit 1 --json tagName --jq '.[0].tagName // ""') + # Bump the patch of the HIGHEST existing GitHub Release (independent of + # the in-code version). Only the patch increments, so you can publish a + # higher major/minor by hand (e.g. v1.1.0) and the next merge continues + # from there (-> v1.1.1). First run only (no release yet): seed v1.0.0. + latest=$(gh release list --limit 1000 --json tagName --jq '.[].tagName' | sort -V | tail -n1) if [ -z "$latest" ]; then next="v1.0.0" else