Enhance release notes generation with commit range comparison

This commit is contained in:
Ben Meadors
2026-04-14 13:05:58 -05:00
parent 4587dc2d64
commit 9e182a595c
2 changed files with 58 additions and 31 deletions
+4 -2
View File
@@ -301,10 +301,12 @@ jobs:
id: release_notes id: release_notes
run: | run: |
chmod +x ./bin/generate_release_notes.py chmod +x ./bin/generate_release_notes.py
NOTES=$(./bin/generate_release_notes.py ${{ needs.version.outputs.long }}) NOTES=$(./bin/generate_release_notes.py ${{ needs.version.outputs.long }} --compare-ref HEAD 2>release_notes.log)
echo "notes<<EOF" >> $GITHUB_OUTPUT echo "notes<<EOF" >> $GITHUB_OUTPUT
echo "$NOTES" >> $GITHUB_OUTPUT echo "$NOTES" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT
echo "### Release note range" >> $GITHUB_STEP_SUMMARY
cat release_notes.log >> $GITHUB_STEP_SUMMARY
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -466,7 +468,7 @@ jobs:
- name: Generate release notes - name: Generate release notes
run: | run: |
chmod +x ./bin/generate_release_notes.py chmod +x ./bin/generate_release_notes.py
./bin/generate_release_notes.py ${{ needs.version.outputs.long }} > ./publish/release_notes.md ./bin/generate_release_notes.py ${{ needs.version.outputs.long }} --compare-ref HEAD > ./publish/release_notes.md
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+54 -29
View File
@@ -1,25 +1,31 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """Generate release notes from the actual release commit range."""
Generate release notes from merged PRs on develop and master branches.
Categorizes PRs into Enhancements and Bug Fixes/Maintenance sections.
"""
import subprocess import argparse
import re
import json import json
import re
import subprocess
import sys import sys
from datetime import datetime
def get_last_release_tag(): def get_last_release_tag(compare_ref, exclude_tag=None):
"""Get the most recent release tag.""" """Get the most recent version tag merged into compare_ref."""
result = subprocess.run( result = subprocess.run(
["git", "describe", "--tags", "--abbrev=0"], ["git", "tag", "--merged", compare_ref, "--sort=-version:refname", "v*"],
capture_output=True, capture_output=True,
text=True, text=True,
check=True, check=True,
) )
return result.stdout.strip()
for line in result.stdout.splitlines():
candidate = line.strip()
if not candidate:
continue
if exclude_tag and candidate == exclude_tag:
continue
return candidate
raise subprocess.CalledProcessError(result.returncode, result.args, output=result.stdout, stderr=result.stderr)
def get_tag_date(tag): def get_tag_date(tag):
@@ -33,18 +39,18 @@ def get_tag_date(tag):
return result.stdout.strip() return result.stdout.strip()
def get_merged_prs_since_tag(tag, branch): def get_merged_prs_in_range(tag, compare_ref):
"""Get all merged PRs since the given tag on the specified branch.""" """Get all merged PRs in the git range between tag and compare_ref."""
# Get commits since tag on the branch - look for PR numbers in parentheses
result = subprocess.run( result = subprocess.run(
[ [
"git", "git",
"log", "log",
f"{tag}..origin/{branch}", f"{tag}..{compare_ref}",
"--oneline", "--oneline",
], ],
capture_output=True, capture_output=True,
text=True, text=True,
check=True,
) )
prs = [] prs = []
@@ -65,6 +71,25 @@ def get_merged_prs_since_tag(tag, branch):
return prs return prs
def parse_args():
"""Parse CLI arguments."""
parser = argparse.ArgumentParser(
description="Generate release notes from the actual release commit range."
)
parser.add_argument("new_version", help="Version that will be tagged for this release")
parser.add_argument(
"--base-tag",
dest="base_tag",
help="Existing version tag to diff from. Defaults to the latest version tag merged into the compare ref.",
)
parser.add_argument(
"--compare-ref",
default="HEAD",
help="Git ref to diff to. Defaults to HEAD.",
)
return parser.parse_args()
def get_pr_details(pr_number): def get_pr_details(pr_number):
"""Get PR details from GitHub API via gh CLI.""" """Get PR details from GitHub API via gh CLI."""
try: try:
@@ -268,28 +293,28 @@ def get_new_contributors(pr_details_list, tag, repo="meshtastic/firmware"):
def main(): def main():
if len(sys.argv) < 2: args = parse_args()
print("Usage: generate_release_notes.py <new_version>", file=sys.stderr) new_version = args.new_version
sys.exit(1) compare_ref = args.compare_ref
current_tag = f"v{new_version}"
new_version = sys.argv[1]
# Get last release tag # Get last release tag
try: try:
last_tag = get_last_release_tag() last_tag = args.base_tag or get_last_release_tag(compare_ref, exclude_tag=current_tag)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
print("Error: Could not find last release tag", file=sys.stderr) print("Error: Could not find last release tag", file=sys.stderr)
sys.exit(1) sys.exit(1)
# Collect PRs from both branches print(
all_pr_numbers = set() f"Resolved release note range: {last_tag}..{compare_ref}",
file=sys.stderr,
)
for branch in ["develop", "master"]: try:
try: all_pr_numbers = set(get_merged_prs_in_range(last_tag, compare_ref))
prs = get_merged_prs_since_tag(last_tag, branch) except subprocess.CalledProcessError as e:
all_pr_numbers.update(prs) print(f"Error: Could not get PRs for range {last_tag}..{compare_ref}: {e}", file=sys.stderr)
except Exception as e: sys.exit(1)
print(f"Warning: Could not get PRs from {branch}: {e}", file=sys.stderr)
# Get details for all PRs # Get details for all PRs
enhancements = [] enhancements = []