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
88 changes: 88 additions & 0 deletions .github/release-drafter.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
name-template: 'v$RESOLVED_VERSION'
tag-template: 'v$RESOLVED_VERSION'

categories:
- type: 'pre-exclude'
when:
label: 'skip-changelog'

- title: '🚀 Added'
when:
labels:
- 'feature'
- 'enhancement'

- title: '🔄 Changed'
when:
label: 'changed'

- title: '🐛 Fixed'
when:
labels:
- 'bug'
- 'fix'

- title: '📚 Documentation'
when:
label: 'documentation'

- title: '🧰 Internal'
when:
labels:
- 'internal'
- 'chore'
- 'dependencies'

- type: 'version-resolver'
semver-increment: 'major'
when:
label: 'major'

- type: 'version-resolver'
semver-increment: 'minor'
when:
labels:
- 'feature'
- 'enhancement'

- type: 'version-resolver'
semver-increment: 'patch'
when:
labels:
- 'fix'
- 'bug'
- 'changed'
- 'chore'
- 'internal'
- 'dependencies'
- 'documentation'

autolabeler:
- label: 'feature'
title:
- '/^feat(\(.+\))?!?:/i'
- label: 'fix'
title:
- '/^fix(\(.+\))?!?:/i'
- label: 'changed'
title:
- '/^refactor(\(.+\))?!?:/i'
- label: 'documentation'
title:
- '/^docs(\(.+\))?!?:/i'
- label: 'dependencies'
title:
- '/^chore\(deps\)(\(.+\))?!?:/i'
- label: 'internal'
title:
- '/^(chore|ci|test|build)(\(.+\))?!?:/i'

category-template: '### $TITLE'
change-template: '- $TITLE (#$NUMBER) @$AUTHOR'
change-title-escapes: '\<*_&'

version-resolver:
default: patch

template: |
$CHANGES
47 changes: 47 additions & 0 deletions .github/scripts/update_changelog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""Prepend a published GitHub release's notes to CHANGELOG.md.

Run by .github/workflows/changelog.yaml on the `release: published` event.
Drops the leading `## Unreleased` section, if present, since it's
superseded by the version being inserted, then adds a `## [tag] - date`
section built from the release body right after the `# Changelog` title.
"""

from __future__ import annotations

import os
from pathlib import Path

CHANGELOG = Path("CHANGELOG.md")
UNRELEASED_HEADING = "## Unreleased"


def main() -> None:
tag = os.environ["RELEASE_TAG"]
date = os.environ["RELEASE_DATE"][:10] # YYYY-MM-DD from an ISO 8601 timestamp
body = os.environ["RELEASE_BODY"].strip()

lines = CHANGELOG.read_text().splitlines(keepends=True)
if lines[0].strip() != "# Changelog":
msg = f"unexpected first line: {lines[0]!r}"
raise ValueError(msg)

# Skip blank lines right after the title.
start = 1
while start < len(lines) and not lines[start].strip():
start += 1

# Drop a leading "## Unreleased" section: its content is superseded by
# the version we're about to insert.
end = start
if start < len(lines) and lines[start].strip() == UNRELEASED_HEADING:
end = start + 1
while end < len(lines) and not lines[end].startswith("## "):
end += 1

section = f"## [{tag}] - {date}\n\n{body}\n"
new_lines = [*lines[:1], "\n", section, "\n", *lines[end:]]
CHANGELOG.write_text("".join(new_lines))


if __name__ == "__main__":
main()
57 changes: 57 additions & 0 deletions .github/workflows/changelog.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: Changelog

on:
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false

permissions: {}

jobs:
update-changelog:
name: Update CHANGELOG.md
runs-on: ubuntu-24.04
permissions:
contents: write # for the create-pull-request branch push
pull-requests: write # to open the PR
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false

- name: Update CHANGELOG.md from the current draft release
id: draft
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
run: |
draft="$(gh api "repos/${GH_REPO}/releases" --jq '[.[] | select(.draft == true)] | first')"
if [ -z "$draft" ] || [ "$draft" = "null" ]; then
echo "::error::No draft release found. Push to main first so release-drafter creates one."
exit 1
fi

tag="$(jq -r '.tag_name' <<< "$draft")"
url="$(jq -r '.html_url' <<< "$draft")"
echo "tag=$tag" >> "$GITHUB_OUTPUT"
echo "url=$url" >> "$GITHUB_OUTPUT"

RELEASE_TAG="$tag" \
RELEASE_DATE="$(date -u +%Y-%m-%d)" \
RELEASE_BODY="$(jq -r '.body' <<< "$draft")" \
python3 .github/scripts/update_changelog.py

- uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
# zizmor: ignore[superfluous-actions]
with:
commit-message: "docs: Update changelog for ${{ steps.draft.outputs.tag }}"
title: "docs: Update changelog for ${{ steps.draft.outputs.tag }}"
body: >-
Automated update of `CHANGELOG.md` ahead of publishing
[${{ steps.draft.outputs.tag }}](${{ steps.draft.outputs.url }}).
Merge this before publishing the release so the tag includes
the updated changelog.
branch: changelog/${{ steps.draft.outputs.tag }}
add-paths: CHANGELOG.md
26 changes: 26 additions & 0 deletions .github/workflows/release-drafter.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Release Drafter

on:
push:
branches:
- main
pull_request:
types: [opened, reopened, synchronize]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions: {}

jobs:
update_release_draft:
name: Update release draft
runs-on: ubuntu-24.04
permissions:
contents: write # to create/update the draft release
pull-requests: write # to autolabel PRs
steps:
- uses: release-drafter/release-drafter@34d80673e067bdc0c24568d3af899c216adcfaa9 # v7.7.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Loading