Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions .ci/changelog-notes
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/usr/bin/env python3
"""Extract release notes for a version from CHANGELOG.md.

Reads the matching ``## <version>`` section, converts RST-style underlined
category headers to Markdown ``###`` headers, and prints the result.

Usage::

.ci/changelog-notes <version> [changelog-path]
.ci/changelog-notes 0.1.1
"""

import re
import sys
from pathlib import Path


def extract_notes(changelog: str, version: str) -> str | None:
"""Return the release-notes section for *version*, or ``None``."""
header = re.compile(rf"^## {re.escape(version)}\b[^\n]*$", re.MULTILINE)
match = header.search(changelog)
if not match:
return None

start = match.end() + 1 # skip past header line's newline

# The section ends at the next version header or ``<a id=`` anchor.
boundary = re.compile(r"^(?:## |<a id=)", re.MULTILINE)
end_match = boundary.search(changelog, start)
raw = changelog[start : end_match.start()] if end_match else changelog[start:]

# Convert RST underlined headers (``Category\n-----``) → ``### Category``
notes = re.sub(r"^(.+)\n-{3,}$", r"### \1", raw, flags=re.MULTILINE)
return notes.strip()


def main() -> int:
if len(sys.argv) < 2:
print("usage: changelog-notes <version> [changelog]", file=sys.stderr)
return 2

version = sys.argv[1]
path = Path(sys.argv[2]) if len(sys.argv) > 2 else Path("CHANGELOG.md")

if not path.is_file():
print(f"error: {path} not found", file=sys.stderr)
return 1

notes = extract_notes(path.read_text(), version)
if notes is None:
print(f"error: version {version} not found in {path}", file=sys.stderr)
return 1

print(notes)
return 0


if __name__ == "__main__":
sys.exit(main())
21 changes: 21 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,24 @@ permissions:
contents: read

jobs:
release-notes:
name: Populate release notes from CHANGELOG.md
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Update release body
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ github.event.release.tag_name }}
run: |
version="${TAG#v}"
python3 .ci/changelog-notes "$version" > /tmp/release-notes.md
gh release edit "$TAG" --notes-file /tmp/release-notes.md

build:
name: Build distribution packages
runs-on: ubuntu-latest
Expand Down Expand Up @@ -40,6 +58,9 @@ jobs:
permissions:
contents: read
id-token: write
environment:
name: release
url: https://pypi.org/project/wslshot/
steps:
- name: Download build artifacts
uses: actions/download-artifact@v4
Expand Down