forked from bertiniteam/b2
-
Notifications
You must be signed in to change notification settings - Fork 0
196 lines (175 loc) · 7.76 KB
/
Copy pathpublish.yml
File metadata and controls
196 lines (175 loc) · 7.76 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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
name: Publish wheels 🐍 and deploy documentation 📝
on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
- 'v[0-9]+.[0-9]+.[0-9]+.dev[0-9]+'
- 'v[0-9]+.[0-9]+.[0-9]+a[0-9]+'
- 'v[0-9]+.[0-9]+.[0-9]+b[0-9]+'
- 'v[0-9]+.[0-9]+.[0-9]+rc[0-9]+'
concurrency:
group: publish-${{ github.ref }}
cancel-in-progress: true
jobs:
check_version:
name: Check VERSION file matches tag
runs-on: ubuntu-latest
outputs:
is_prerelease: ${{ steps.check.outputs.is_prerelease }}
steps:
- uses: actions/checkout@v5
- name: Check version matches tag
id: check
run: |
TAG="$GITHUB_REF_NAME"
# Validate tag is a well-formed PEP 440 version tag
if ! echo "$TAG" | grep -Eq '^v[0-9]+\.[0-9]+\.[0-9]+(\.dev[0-9]+|a[0-9]+|b[0-9]+|rc[0-9]+)?$'; then
echo "Error: tag '$TAG' is not a valid PEP 440 version tag (e.g. v1.2.3, v1.2.3.dev1, v1.2.3rc1)"
exit 1
fi
TAG_VERSION="${TAG#v}"
# The version is dynamic in pyproject.toml; its single source of truth
# is the top-level VERSION file (read by scikit-build-core and CMake).
FILE_VERSION=$(tr -d '[:space:]' < VERSION)
if [ "$TAG_VERSION" != "$FILE_VERSION" ]; then
echo "Error: tag '$TAG' does not match VERSION file '$FILE_VERSION'"
exit 1
fi
echo "OK: tag '$TAG' matches VERSION file '$FILE_VERSION'"
# Prerelease iff the tag carries a PEP 440 pre/dev suffix. Note only `.dev` takes a
# leading dot; `a`/`b`/`rc` attach directly (3.0.0rc1), so the alternation must mirror the
# validation regex above -- a naive `\.(dev|a|b|rc)` would misread rc1 as a FINAL release
# and route it to real PyPI + a GitHub Release instead of TestPyPI.
echo "$TAG" | grep -Eq '(\.dev[0-9]+|a[0-9]+|b[0-9]+|rc[0-9]+)$' && echo "is_prerelease=true" >> $GITHUB_OUTPUT || echo "is_prerelease=false" >> $GITHUB_OUTPUT
check_timing_freshness:
name: Check tutorial timings are fresh
needs: check_version
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
# Gate ONLY real releases. We keep this as a step-level `if` (not a job-level one) so the
# JOB always succeeds for prereleases instead of being *skipped*: a skipped `needs` would
# propagate a skip through `build_and_test` (a reusable-workflow caller) and silently skip
# every publish/docs job under the default `if: success()`. Prereleases (.dev/a/b/rc) are
# exactly when a timing refresh may not have happened yet, so for them this is a no-op pass.
- name: Verify the scaling-tutorial timings are not stale
if: needs.check_version.outputs.is_prerelease == 'false'
run: python tools/check_timing_freshness.py
build_and_test:
name: Build and test
# No job-level `if`: check_timing_freshness always *succeeds* for prereleases (its gate is a
# step), so the default success() gating here -- and, critically, in every downstream publish
# job -- works. A conditional on this reusable-workflow caller would skip all of them.
needs: [check_version, check_timing_freshness]
uses: ./.github/workflows/build_and_test.yml
publish-to-testpypi:
name: Publish to TestPyPI
if: needs.check_version.outputs.is_prerelease == 'true'
needs: [check_version, build_and_test]
runs-on: ubuntu-latest
environment:
name: testpypi
url: https://test.pypi.org/p/bertini2
permissions:
id-token: write # IMPORTANT: mandatory for trusted publishing
steps:
- name: Download all the dists
uses: actions/download-artifact@v5
with:
# ONLY the wheel artifacts. build_docs.yml's cpp_docs job also uploads a
# `docs-cpp` artifact (the whole Doxygen tree); without this pattern,
# merge-multiple would pull it into dist/ and it would be published /
# attached to the release (it polluted the v3.2.0 GitHub release with 509
# Doxygen files before dying mid-upload).
pattern: wheels-*
merge-multiple: true
path: dist/
- name: Publish distribution 📦 to TestPyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
skip-existing: true
verbose: true
repository-url: https://test.pypi.org/legacy/
publish-to-pypi:
name: Publish to PyPI
if: needs.check_version.outputs.is_prerelease == 'false'
needs: [check_version, build_and_test]
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/p/bertini2
permissions:
id-token: write # IMPORTANT: mandatory for trusted publishing
steps:
- name: Download all the dists
uses: actions/download-artifact@v5
with:
# ONLY the wheel artifacts. build_docs.yml's cpp_docs job also uploads a
# `docs-cpp` artifact (the whole Doxygen tree); without this pattern,
# merge-multiple would pull it into dist/ and it would be published /
# attached to the release (it polluted the v3.2.0 GitHub release with 509
# Doxygen files before dying mid-upload).
pattern: wheels-*
merge-multiple: true
path: dist/
- name: Publish distribution 📦 to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
skip-existing: true
verbose: true
github-release:
name: >-
Sign the Python 🐍 distribution 📦 with Sigstore
and upload them to GitHub Release
if: needs.check_version.outputs.is_prerelease == 'false'
needs:
- check_version
- publish-to-pypi
runs-on: ubuntu-latest
permissions:
contents: write # IMPORTANT: mandatory for making GitHub Releases
id-token: write # IMPORTANT: mandatory for sigstore
steps:
- name: Checkout Repository
uses: actions/checkout@v5
- name: Download Artifacts
uses: actions/download-artifact@v5
with:
# ONLY the wheel artifacts. build_docs.yml's cpp_docs job also uploads a
# `docs-cpp` artifact (the whole Doxygen tree); without this pattern,
# merge-multiple would pull it into dist/ and it would be published /
# attached to the release (it polluted the v3.2.0 GitHub release with 509
# Doxygen files before dying mid-upload).
pattern: wheels-*
merge-multiple: true
path: dist/
- name: Sign the dists with Sigstore
uses: sigstore/gh-action-sigstore-python@v3.0.0
with:
inputs: >-
./dist/*.whl
- name: Get Newest Changelog
run: |
python -c 'import re; from pathlib import Path; text=re.sub("<!--(.*?)-->", "", (Path.cwd() / "CHANGELOG.md").read_text(), flags=re.DOTALL); print(text); start=text.find("_" * 79); (Path.cwd() / "TEMP_CHANGELOG.md").write_text(text[start:text.find("_" * 79, start+1)])'
- name: Create GitHub Release
id: create_release
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
name: Release ${{ github.ref_name }}
draft: false
prerelease: false
body_path: ./TEMP_CHANGELOG.md
files: |
dist/*.*
build_and_deploy_docs:
name: Build and deploy docs
if: needs.check_version.outputs.is_prerelease == 'false'
needs: [check_version, build_and_test]
uses: ./.github/workflows/build_docs.yml
permissions:
# Pages serves docs-store directly (branch source), so publishing is just pushing the branch;
# no pages:/id-token: needed -- only write access to push the store.
contents: write # build_docs pushes the persistent docs-store branch (versioned docs)