-
Notifications
You must be signed in to change notification settings - Fork 3
106 lines (98 loc) · 3.71 KB
/
Copy pathrelease.yml
File metadata and controls
106 lines (98 loc) · 3.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
name: release
# The filename matters: `release.yml` is registered as the workflow name on the PyPI trusted
# publisher for this project. Renaming this file breaks publishing until PyPI is updated to match.
on:
push:
tags: ["v*"]
workflow_dispatch:
permissions:
contents: read
jobs:
build:
name: build the distribution
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
with:
enable-cache: true
- run: uv build
- name: twine check
run: uv run --with twine==7.0.0 twine check dist/*
- name: the tag and the packaged version must agree
run: |
uv run python - <<'PY'
import os
import pathlib
import sys
import tomllib
tag = os.environ["GITHUB_REF_NAME"].removeprefix("v")
pkg = tomllib.loads(pathlib.Path("pyproject.toml").read_text())["project"]["version"]
print(f"tag={tag} packaged={pkg}")
if tag != pkg:
sys.exit(f"::error::tag {tag} does not match packaged version {pkg}")
PY
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: dist
path: dist/
publish:
name: publish to PyPI
needs: build
runs-on: ubuntu-latest
# Registered on PyPI as the trusted publisher's environment. It carries a required-reviewer
# rule, so a publish waits for a human, and a v* tag policy, so it cannot run from a branch.
environment: pypi
permissions:
# Mandatory for trusted publishing: this is what lets the job prove its identity to PyPI.
# No API token is stored in the repository or anywhere else.
id-token: write
steps:
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: dist
path: dist/
- uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
github-release:
name: create the GitHub release
# Runs only after PyPI accepted the upload, so a GitHub release never claims a version that was
# not actually published.
needs: publish
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: dist
path: dist/
- name: extract this version's changelog section
run: |
python3 - <<'PY'
import os
import pathlib
import re
tag = os.environ["GITHUB_REF_NAME"]
version = tag.removeprefix("v")
changelog = pathlib.Path("CHANGELOG.md").read_text()
# everything from this version's heading up to the next one
match = re.search(
rf"^## \[{re.escape(version)}\].*?\n(.*?)(?=^## \[)",
changelog,
re.MULTILINE | re.DOTALL,
)
notes = match.group(1).strip() if match else f"See CHANGELOG.md for {version}."
pathlib.Path("release-notes.md").write_text(notes + "\n")
print(f"extracted {len(notes.splitlines())} lines of notes for {version}")
PY
# gh is preinstalled on GitHub runners, so this needs no third-party action.
- name: create the release
env:
GH_TOKEN: ${{ github.token }}
run: >
gh release create "${{ github.ref_name }}"
--title "${{ github.ref_name }}"
--notes-file release-notes.md
--verify-tag
dist/*