-
Notifications
You must be signed in to change notification settings - Fork 1
151 lines (133 loc) · 5.14 KB
/
python-publish.yml
File metadata and controls
151 lines (133 loc) · 5.14 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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
name: Publish Python package
on:
push:
tags:
- "v*"
workflow_dispatch:
inputs:
target:
description: "Where to publish"
required: true
default: "testpypi"
type: choice
options:
- testpypi
- pypi
# Default least-privilege; publish-* jobs override with id-token: write.
permissions:
contents: read
jobs:
build:
name: Build distributions
runs-on: ubuntu-latest
steps:
- name: Check out source
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
with:
python-version: "3.12"
# Fail-fast before build/publish if (a) pyproject.toml declares a pre-release
# version (e.g. 1.0.0.dev0, 1.0.0a1) when a final-version tag (vX.Y.Z) was
# pushed, or (b) the tag version doesn't match pyproject.toml. PyPI rejects
# duplicate versions server-side, but a local guard surfaces the operator
# error before the upload phase. See runcycles/.github#61.
- name: Verify pyproject version matches tag
if: startsWith(github.ref, 'refs/tags/v')
run: |
python -c "import tomllib,sys; v=tomllib.load(open('pyproject.toml','rb'))['project']['version']; print(v)" > /tmp/pyproject_version
PYPROJECT_VERSION=$(cat /tmp/pyproject_version)
TAG_VERSION="${GITHUB_REF_NAME#v}"
echo "pyproject.toml version: ${PYPROJECT_VERSION}"
echo "Git tag version: ${TAG_VERSION}"
if [ "${PYPROJECT_VERSION}" != "${TAG_VERSION}" ]; then
echo "::error::Version mismatch: pyproject.toml has '${PYPROJECT_VERSION}' but tag is 'v${TAG_VERSION}'. Bump pyproject.toml or retag."
exit 1
fi
- name: Install build tool
run: python -m pip install --upgrade pip build
- name: Build sdist and wheel
run: python -m build
- name: Upload distribution artifacts
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: python-package-distributions
path: dist/
publish-to-testpypi:
name: Publish to TestPyPI
needs: build
runs-on: ubuntu-latest
if: github.event_name == 'workflow_dispatch' && inputs.target == 'testpypi'
environment:
name: testpypi
url: https://test.pypi.org/p/runcycles
permissions:
id-token: write
contents: read
steps:
- name: Download distribution artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: python-package-distributions
path: dist/
- name: Publish to TestPyPI
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # release/v1
with:
repository-url: https://test.pypi.org/legacy/
publish-to-pypi:
name: Publish to PyPI
needs: build
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v') || (github.event_name == 'workflow_dispatch' && inputs.target == 'pypi')
environment:
name: pypi
url: https://pypi.org/p/runcycles
permissions:
id-token: write
contents: read
steps:
- name: Download distribution artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: python-package-distributions
path: dist/
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # release/v1
create-release:
name: Create GitHub Release
needs: publish-to-pypi
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
permissions:
contents: write
steps:
- name: Check out source
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Extract release notes from CHANGELOG
id: notes
run: |
version="${GITHUB_REF_NAME#v}"
# Extract the section between this version's heading and the next "## [" heading.
# Uses string functions instead of regex to stay portable across awk variants.
notes=$(awk -v v="$version" '
BEGIN { start = "## [" v "]"; flag = 0 }
substr($0, 1, length(start)) == start { flag = 1; next }
substr($0, 1, 4) == "## [" { flag = 0 }
flag { print }
' CHANGELOG.md)
if [ -z "$(printf '%s' "$notes" | tr -d '[:space:]')" ]; then
echo "::warning::No CHANGELOG entry found for v${version} — using fallback body"
notes="Release v${version}. See commit history for changes."
fi
{
echo "notes<<EOF_GH_OUTPUT"
printf '%s\n' "$notes"
echo "EOF_GH_OUTPUT"
} >> "$GITHUB_OUTPUT"
- name: Create GitHub Release
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
with:
name: ${{ github.ref_name }}
body: ${{ steps.notes.outputs.notes }}
draft: false
prerelease: ${{ contains(github.ref_name, '-') }}