From 6689d2332bf7fddd5da195dd1766a72733fa3914 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 29 May 2026 14:56:40 +0000 Subject: [PATCH 1/2] fix: generate release notes from default branch to include all PRs since last release --- .github/workflows/release.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 43ec43e0..51e1892c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -96,10 +96,20 @@ jobs: runs-on: ubuntu-latest needs: pypi-publish steps: + - name: Generate release notes + run: | + gh api repos/${{ github.repository }}/releases/generate-notes \ + --method POST \ + -f tag_name="${{ inputs.custom_version || github.ref_name }}" \ + -f target_commitish="${{ github.event.repository.default_branch }}" \ + --jq '.body' > release_notes.md + env: + GH_TOKEN: ${{ secrets.GH_RELEASE_PAT }} + - name: Publish release on GitHub uses: softprops/action-gh-release@v2 with: - generate_release_notes: true + body_path: release_notes.md tag_name: ${{ inputs.custom_version || github.ref_name }} env: GITHUB_TOKEN: ${{ secrets.GH_RELEASE_PAT }} From 74e74e48c2660775c605a393ce672be2f76f2e46 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 29 May 2026 22:23:28 +0000 Subject: [PATCH 2/2] fix: generate release notes from commit range, not default branch HEAD --- .github/workflows/release.yml | 91 ++++++++++++++++++++++++++++++++--- 1 file changed, 85 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 51e1892c..77b82b23 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -96,14 +96,93 @@ jobs: runs-on: ubuntu-latest needs: pypi-publish steps: - - name: Generate release notes + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Generate release notes from commit messages run: | - gh api repos/${{ github.repository }}/releases/generate-notes \ - --method POST \ - -f tag_name="${{ inputs.custom_version || github.ref_name }}" \ - -f target_commitish="${{ github.event.repository.default_branch }}" \ - --jq '.body' > release_notes.md + python3 - <<'EOF' + import json, os, re, subprocess, urllib.request + + tag = os.environ["TAG_NAME"] + repo = os.environ["REPO"] + token = os.environ["GH_TOKEN"] + + # Determine previous tag (version-sorted, so patch tags compare correctly) + all_tags = subprocess.run( + ["git", "tag", "--sort=-version:refname"], + capture_output=True, text=True, check=True, + ).stdout.strip().splitlines() + all_tags = [t for t in all_tags if t] + + try: + prev_tag = all_tags[all_tags.index(tag) + 1] + except (ValueError, IndexError): + prev_tag = None + + log_range = f"{prev_tag}..{tag}" if prev_tag else tag + subjects = subprocess.run( + ["git", "log", "--format=%s", log_range], + capture_output=True, text=True, check=True, + ).stdout.strip().splitlines() + + # Extract unique PR numbers preserving order (squash-merge: "(#NNN)") + seen, pr_numbers = set(), [] + for subject in subjects: + for num in re.findall(r'\(#(\d+)\)', subject): + if num not in seen: + pr_numbers.append(int(num)) + seen.add(num) + + def gh_get(url): + req = urllib.request.Request( + url, + headers={"Authorization": f"token {token}", "Accept": "application/vnd.github.v3+json"}, + ) + with urllib.request.urlopen(req) as resp: + return json.loads(resp.read()) + + # Category config mirrors .github/release.yml + label_to_category = { + "enhancement": "New Features 🎉", + "breaking-change": "Breaking Changes 🛠", + "bug": "Bug Fix 🐛", + } + ignore_labels = {"ignore-for-release"} + category_order = ["New Features 🎉", "Breaking Changes 🛠", "Bug Fix 🐛", "Other Changes"] + + prs_by_category: dict = {} + + for pr_num in pr_numbers: + pr = gh_get(f"https://api.github.com/repos/{repo}/pulls/{pr_num}") + labels = {lbl["name"] for lbl in pr.get("labels", [])} + if labels & ignore_labels: + continue + category = next( + (cat for lbl, cat in label_to_category.items() if lbl in labels), + "Other Changes", + ) + prs_by_category.setdefault(category, []).append(pr) + + lines = ["## What's Changed"] + for cat in category_order: + if cat not in prs_by_category: + continue + lines.append(f"### {cat}") + for pr in prs_by_category[cat]: + lines.append(f"* {pr['title']} by @{pr['user']['login']} in {pr['html_url']}") + + if prev_tag: + lines += ["", f"**Full Changelog**: https://github.com/{repo}/compare/{prev_tag}...{tag}"] + + notes = "\n".join(lines) + "\n" + print(notes) + open("release_notes.md", "w").write(notes) + EOF env: + TAG_NAME: ${{ inputs.custom_version || github.ref_name }} + REPO: ${{ github.repository }} GH_TOKEN: ${{ secrets.GH_RELEASE_PAT }} - name: Publish release on GitHub