Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
ab456fb
馃懛 ci(news): validate bot fragments
gaborbernat Oct 20, 2026
36b5a89
馃敡 build(deps): lock all project groups
gaborbernat Oct 20, 2026
c12a2bf
馃敡 build(docs): preserve RST section anchors
gaborbernat Oct 20, 2026
dea87aa
馃懛 ci(release): use shared RST pipeline
gaborbernat Oct 20, 2026
49db88b
馃摑 docs(changelog): correct release history
gaborbernat Oct 20, 2026
f85ae23
馃敡 chore: ignore uv lock files
gaborbernat Oct 20, 2026
0bac3e8
馃敡 build(readme): render PyPI description
gaborbernat Oct 20, 2026
6854e3b
馃悰 fix(meta): correct package metadata
gaborbernat Oct 20, 2026
f9b337d
馃懛 ci: refresh shared release actions
gaborbernat Oct 21, 2026
322ffb7
馃摑 docs: correct interpreter release history
gaborbernat Oct 21, 2026
d7a8eab
fix: avoid duplicate issue links
gaborbernat Oct 21, 2026
d210e87
馃懛 ci: scope bot label token to job
gaborbernat Oct 21, 2026
4f58f95
馃懛 ci: isolate release App key from tools
gaborbernat Oct 21, 2026
c66160d
馃懛 ci(release): separate notes from publishing
gaborbernat Oct 21, 2026
f904fb5
馃敡 build: update pinned formatting hooks
gaborbernat Oct 21, 2026
07d946d
馃拕 style(ci): wrap release commands
gaborbernat Oct 21, 2026
365dd52
馃摑 docs(changelog): fix category headings
gaborbernat Oct 21, 2026
8c4f962
馃懛 ci(release): lock and check artifacts
gaborbernat Oct 21, 2026
0ac47d5
馃懛 ci: select checksum-known uv
gaborbernat Oct 21, 2026
3ed8c4e
馃懛 ci(release): verify retry artifacts
gaborbernat Oct 21, 2026
7d2cc87
fix: gate hook updates in release checks
gaborbernat Oct 21, 2026
240da8a
style: format workflow shell blocks
gaborbernat Oct 21, 2026
0135d68
馃懛 ci: use named shared Action steps
gaborbernat Oct 21, 2026
f3e9f81
馃敡 chore(release): use live workflow
gaborbernat Oct 22, 2026
44d670d
馃懛 ci(release): use published tooling
gaborbernat Oct 22, 2026
cddcd7a
馃懛 ci: adopt shared release controls
gaborbernat Oct 22, 2026
79ced76
馃悰 fix(release): lock caller build backends
gaborbernat Oct 22, 2026
287938a
馃悰 fix(release): pin corrected shared actions
gaborbernat Oct 22, 2026
13d633e
馃悰 fix(release): pin portable shared actions
gaborbernat Oct 22, 2026
a70c90c
馃懛 ci: narrow release tool installs
gaborbernat Oct 22, 2026
aef87fe
馃懛 ci: adopt shared release pipeline
gaborbernat Oct 23, 2026
b7ca4e5
馃懛 ci: run news checks separately
gaborbernat Oct 23, 2026
dad18c2
馃懛 ci: align release jobs with shared actions
gaborbernat Oct 23, 2026
d63f264
馃懛 ci: pin released release tools
gaborbernat Oct 23, 2026
5d5ef02
馃懛 ci: remove duplicate release PATH setup
gaborbernat Oct 23, 2026
ffceed7
馃懛 ci: reuse previous tag for release notes
gaborbernat Oct 23, 2026
c54dcb6
build: refresh release tool lock
gaborbernat Oct 23, 2026
b070e6f
fix: match released tool cutoff
gaborbernat Oct 23, 2026
917a31f
馃敡 build: adopt release tooling 2.0.0
gaborbernat Oct 24, 2026
c21fa2f
馃懛 ci(release): use full project lock
gaborbernat Oct 24, 2026
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
20 changes: 20 additions & 0 deletions .github/dependabot.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,23 @@ updates:
- "*"
cooldown:
default-days: 7
- package-ecosystem: "pre-commit"
directory: "/"
allow:
- dependency-name: "mdformat-gfm"
- dependency-name: "mdformat-ruff"
- dependency-name: "sphinx"
labels:
- dependencies
- skip news
schedule:
interval: "weekly"
day: "tuesday"
groups:
formatting-plugins:
patterns:
- "mdformat-gfm"
- "mdformat-ruff"
- "sphinx"
cooldown:
default-days: 7
1 change: 1 addition & 0 deletions .github/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ changelog:
exclude:
authors:
- dependabot[bot]
- github-actions[bot]
- pre-commit-ci[bot]
46 changes: 25 additions & 21 deletions .github/workflows/check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on:
branches: ["main"]
tags-ignore: ["**"]
pull_request:
types: [opened, synchronize, reopened, labeled, unlabeled]
types: [opened, synchronize, reopened]
schedule:
- cron: "0 8 * * *"
concurrency:
Expand Down Expand Up @@ -37,9 +37,10 @@ jobs:
with:
fetch-depth: 0
persist-credentials: false
- name: Install the latest version of uv
- name: Set up uv
uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
with:
version: latest-known
python-version: "3.15"
enable-cache: false
cache-dependency-glob: "pyproject.toml"
Expand All @@ -63,9 +64,10 @@ jobs:
with:
fetch-depth: 0
persist-credentials: false
- name: Install the latest version of uv
- name: Set up uv
uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
with:
version: latest-known
python-version: "3.15"
enable-cache: false
cache-dependency-glob: "pyproject.toml"
Expand All @@ -81,32 +83,34 @@ jobs:
run: tasks/old_target_check.sh 3.5 rejected
- name: Reject Python 2.7
run: tasks/old_target_check.sh 2.7 rejected
changelog:
if: github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'skip news')
runs-on: ubuntu-24.04
hook-cooldown:
name: Hook update cooldown
if: github.event_name == 'pull_request'
runs-on: ubuntu-26.04
permissions:
actions: read
contents: read
pull-requests: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false
- uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
- uses: tox-dev/github-workflows/check-hook-update-cooldown@55f51f9b5cc0b40f280155a95de2d4f0ecbf7be1 # v3.0.0
with:
python-version: "3.15"
enable-cache: false
- run: uvx towncrier check --compare-with "origin/${GITHUB_BASE_REF}"
release-app-client-id: ${{ vars.RELEASE_APP_CLIENT_ID }}
env:
GH_TOKEN: ${{ github.token }}
gate:
name: Required checks pass
if: always()
needs: [test, old-target, changelog]
runs-on: ubuntu-24.04
name: ${{ github.event_name == 'pull_request' && 'Required checks pass' || 'Non-PR checks pass' }}
if: ${{ !cancelled() }} # codespell:ignore cancelled
needs: [test, old-target, hook-cooldown]
runs-on: ubuntu-26.04
steps:
- env:
NEEDS_JSON: ${{ toJSON(needs) }}
EVENT_NAME: ${{ github.event_name }}
run: |
jq -e '
jq -e --arg event "$EVENT_NAME" '
all(
to_entries[];
.value.result == "success" or
(.key == "changelog" and .value.result == "skipped")
((.key == "hook-cooldown") and .value.result == "skipped" and $event != "pull_request")
)
' <<< "$NEEDS_JSON"
' <<<"$NEEDS_JSON"
29 changes: 29 additions & 0 deletions .github/workflows/news.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Changelog
on:
pull_request:
types: [opened, reopened, synchronize, labeled, unlabeled]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: true
permissions:
contents: read
jobs:
changelog:
if: github.event_name == 'pull_request'
runs-on: ubuntu-26.04
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false
- uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
with:
version: latest-known
python-version: "3.15"
enable-cache: false
- name: Install locked release tools
uses: tox-dev/github-workflows/install-locked-tools@55f51f9b5cc0b40f280155a95de2d4f0ecbf7be1 # v3.0.0
with:
groups: release-news
venv: ${{ runner.temp }}/release-tools
- uses: tox-dev/github-workflows/validate-news@55f51f9b5cc0b40f280155a95de2d4f0ecbf7be1 # v3.0.0
158 changes: 12 additions & 146 deletions .github/workflows/prepare-release.yaml
Original file line number Diff line number Diff line change
@@ -1,156 +1,22 @@
name: Prepare Release
name: Prepare release
on:
workflow_dispatch:
inputs:
bump:
description: "Version bump type"
description: Version bump type
required: true
type: choice
options:
- auto
- major
- minor
- patch
options: [auto, major, minor, patch]
default: auto
permissions:
contents: read
env:
FORCE_COLOR: 1
permissions: {}
jobs:
assemble:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-24.04
prepare:
uses: tox-dev/github-workflows/.github/workflows/prepare-towncrier-release.yaml@55f51f9b5cc0b40f280155a95de2d4f0ecbf7be1 # v3.0.0
permissions:
contents: read
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0 # The next version comes from the tags.
persist-credentials: false
- name: Install uv
uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
with:
python-version: "3.15"
enable-cache: false
- name: Require a news fragment
run: |
if ! compgen -G 'docs/changelog/*.*.rst' > /dev/null; then
echo '::error::add a docs/changelog/*.rst fragment before preparing a release'
exit 1
fi
- name: Set up remote tracking
run: |
git remote -v
git fetch origin
git branch -a
- name: Calculate next version
id: version
env:
BUMP: ${{ inputs.bump }}
run: |
current=$(git describe --tags --abbrev=0 2>/dev/null || echo "0.0.0")
echo "Current version: $current"

IFS='.' read -r major minor patch <<< "$current"

bump_type="$BUMP"
if [ "$bump_type" = "auto" ]; then
feature_count=$(find docs/changelog -name "*.feature.rst" 2>/dev/null | wc -l)
breaking_count=$(find docs/changelog -name "*.breaking.rst" 2>/dev/null | wc -l)
if [ "$breaking_count" -gt 0 ]; then
bump_type="major"
echo "Auto-detected: major bump (found $breaking_count breaking changelog(s))"
elif [ "$feature_count" -gt 0 ]; then
bump_type="minor"
echo "Auto-detected: minor bump (found $feature_count feature changelog(s))"
else
bump_type="patch"
echo "Auto-detected: patch bump (no feature changelogs)"
fi
fi

case "$bump_type" in
major)
next="$((major + 1)).0.0"
;;
minor)
next="$major.$((minor + 1)).0"
;;
patch)
next="$major.$minor.$((patch + 1))"
;;
esac

echo "Next version: $next"
echo "version=$next" >> "$GITHUB_OUTPUT"
- name: Build release patch
env:
VERSION: ${{ steps.version.outputs.version }}
run: |
set -euo pipefail
uvx towncrier build --yes --version "$VERSION"
uvx --with pre-commit-uv pre-commit run --files docs/changelog.rst ||
uvx --with pre-commit-uv pre-commit run --files docs/changelog.rst
git diff HEAD --binary > "$RUNNER_TEMP/release.patch"
test -s "$RUNNER_TEMP/release.patch"
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: release-patch
path: ${{ runner.temp }}/release.patch
if-no-files-found: error
push:
needs: assemble
runs-on: ubuntu-24.04
environment: release-auth
permissions:
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
name: release-patch
path: ${{ runner.temp }}/release-patch
- name: Validate release patch
env:
VERSION: ${{ needs.assemble.outputs.version }}
run: |
set -euo pipefail
git fetch origin main
git reset --hard origin/main
git apply --check "$RUNNER_TEMP/release-patch/release.patch"
git apply --index "$RUNNER_TEMP/release-patch/release.patch"
while IFS= read -r path; do
case "$path" in
docs/changelog.rst|docs/changelog/*.rst) ;;
*) echo "::error::unexpected release path: $path"; exit 1 ;;
esac
done < <(git diff --cached --name-only)
grep -qE "^ v${VERSION//./\\.} \(" docs/changelog.rst
git diff --cached --check
- id: token
uses: actions/create-github-app-token@64ab729a6294000f5aa4a4bc0b73d1f32bc45510 # v3.3.0
with:
client-id: ${{ vars.RELEASE_APP_CLIENT_ID }}
private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
repositories: ${{ github.event.repository.name }}
permission-contents: write
- name: Commit and tag the release
env:
VERSION: ${{ needs.assemble.outputs.version }}
GH_TOKEN: ${{ steps.token.outputs.token }}
APP_SLUG: ${{ steps.token.outputs.app-slug }}
run: |
set -euo pipefail
app_user_id=$(gh api "/users/${APP_SLUG}[bot]" --jq .id)
git config user.name "${APP_SLUG}[bot]"
git config user.email "${app_user_id}+${APP_SLUG}[bot]@users.noreply.github.com"
git commit -m "release $VERSION"
git tag -a "$VERSION" -m "release $VERSION"
gh auth setup-git --hostname github.com --force
git push --atomic origin HEAD:main "refs/tags/$VERSION"
pull-requests: read
with:
bump: ${{ inputs.bump }}
annotated: true
secrets:
RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
18 changes: 18 additions & 0 deletions .github/workflows/recheck-hook-cooldown.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: Recheck hook cooldown
on:
schedule:
- cron: "17 7 * * *"
workflow_dispatch:
permissions: {}
jobs:
recheck:
runs-on: ubuntu-26.04
permissions:
actions: write
contents: read
pull-requests: read
steps:
- uses: tox-dev/github-workflows/recheck-hook-update-cooldown@55f51f9b5cc0b40f280155a95de2d4f0ecbf7be1 # v3.0.0
with:
workflow: check.yaml
job-name: Hook update cooldown
Loading
Loading