Skip to content

Commit c7cfe0a

Browse files
Setup workflow to create release and publish to PyPi.
1 parent cd29883 commit c7cfe0a

2 files changed

Lines changed: 170 additions & 2 deletions

File tree

.github/workflows/build-test-release.yml

Lines changed: 169 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ on:
77
tags:
88
- "[0-9]+.[0-9]+.[0-9]+"
99
- "[0-9]+.[0-9]+.[0-9]+rc[0-9]+"
10-
- "[0-9]+.[0-9]+.[0-9]+dev[0-9]+"
10+
- "[0-9]+.[0-9]+.[0-9]+.dev[0-9]+"
1111

1212
jobs:
1313
test_linux:
@@ -283,3 +283,171 @@ jobs:
283283
with:
284284
name: dist-${{ matrix.os }}-${{ matrix.arch }}
285285
path: dist/*.whl
286+
287+
release:
288+
name: Publish GitHub release
289+
runs-on: ubuntu-latest
290+
needs:
291+
- sdist
292+
- bdist_wheel
293+
if: startsWith(github.ref, 'refs/tags/')
294+
permissions:
295+
contents: write
296+
steps:
297+
- name: Checkout code
298+
uses: actions/checkout@v6
299+
300+
- name: Resolve version and prerelease status
301+
id: meta
302+
run: |
303+
TAG="${GITHUB_REF_NAME}"
304+
VERSION="${TAG}"
305+
BASE_VERSION="$(echo "$VERSION" | sed -E 's/\.?(dev|rc)[0-9]+$//')"
306+
ANCHOR="version-$(echo "$BASE_VERSION" | tr '.' '-')"
307+
if [[ "$VERSION" == *dev* || "$VERSION" == *rc* ]]; then
308+
PRERELEASE="true"
309+
else
310+
PRERELEASE="false"
311+
fi
312+
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
313+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
314+
echo "base_version=$BASE_VERSION" >> "$GITHUB_OUTPUT"
315+
echo "anchor=$ANCHOR" >> "$GITHUB_OUTPUT"
316+
echo "prerelease=$PRERELEASE" >> "$GITHUB_OUTPUT"
317+
318+
- name: Verify version matches tag
319+
run: |
320+
EXPECTED="${{ steps.meta.outputs.version }}"
321+
ACTUAL="$(python -c "import ast, re; src=open('src/wrapt/__init__.py').read(); m=re.search(r'__version_info__\s*=\s*(\([^)]+\))', src); parts=ast.literal_eval(m.group(1)); print(''.join(p if p.startswith('.') else '.'+p for p in parts).lstrip('.'))")"
322+
if [ "$ACTUAL" != "$EXPECTED" ]; then
323+
echo "Tag version ($EXPECTED) does not match __version__ ($ACTUAL) in src/wrapt/__init__.py" >&2
324+
exit 1
325+
fi
326+
echo "Version match: $ACTUAL"
327+
328+
- name: Download all built artifacts
329+
uses: actions/download-artifact@v8
330+
with:
331+
path: dist
332+
merge-multiple: true
333+
334+
- name: List collected artifacts
335+
run: ls -las dist
336+
337+
- name: Generate SHA256SUMS
338+
run: |
339+
cd dist
340+
sha256sum * > SHA256SUMS
341+
cat SHA256SUMS
342+
343+
- name: Write release notes body
344+
run: |
345+
VERSION="${{ steps.meta.outputs.version }}"
346+
BASE_VERSION="${{ steps.meta.outputs.base_version }}"
347+
ANCHOR="${{ steps.meta.outputs.anchor }}"
348+
DOCS_URL="https://wrapt.readthedocs.io/en/latest/changes.html#${ANCHOR}"
349+
if [[ "$VERSION" == *dev* ]]; then
350+
cat > body.md <<EOF
351+
Development snapshot. Not normally published to PyPi
352+
(occasionally uploaded to exercise the release pipeline).
353+
354+
Release notes for the upcoming ${BASE_VERSION} final (work in
355+
progress): ${DOCS_URL}
356+
357+
Platform wheels and the source distribution are attached. To
358+
test against your Python install, either grab a matching wheel
359+
or build from the source distribution:
360+
361+
pip install wrapt-${VERSION}-<python>-<abi>-<platform>.whl
362+
363+
or
364+
365+
tar xf wrapt-${VERSION}.tar.gz
366+
cd wrapt-${VERSION}
367+
pip install .
368+
369+
\`SHA256SUMS\` is attached for verification of the archives.
370+
EOF
371+
elif [[ "$VERSION" == *rc* ]]; then
372+
cat > body.md <<EOF
373+
Release candidate. Release notes for the upcoming
374+
${BASE_VERSION} final (work in progress): ${DOCS_URL}
375+
376+
May be installable from PyPi:
377+
378+
pip install wrapt==${VERSION}
379+
380+
If \`pip\` reports the version is unavailable, this candidate
381+
either has not been uploaded yet or is not being published to
382+
PyPi. Use the attached wheels or build from the source
383+
distribution instead:
384+
385+
tar xf wrapt-${VERSION}.tar.gz
386+
cd wrapt-${VERSION}
387+
pip install .
388+
389+
\`SHA256SUMS\` is attached for verification of the archives.
390+
EOF
391+
else
392+
cat > body.md <<EOF
393+
Full release notes: ${DOCS_URL}
394+
395+
Install from PyPi (recommended):
396+
397+
pip install wrapt==${VERSION}
398+
399+
PyPi uploads follow each GitHub release; if \`pip\` reports the
400+
version is unavailable, the matching PyPi upload may not have
401+
happened yet.
402+
403+
Pre-built wheels are provided for a range of Python versions
404+
and platforms (Linux x86_64/aarch64/riscv64, macOS x86_64 and
405+
arm64, Windows x86_64 and arm64, plus PyPy and free-threaded
406+
builds). The source distribution is also attached together
407+
with \`SHA256SUMS\` for verification.
408+
EOF
409+
fi
410+
cat body.md
411+
412+
- name: Create GitHub release
413+
env:
414+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
415+
GH_REPO: ${{ github.repository }}
416+
run: |
417+
FLAGS=()
418+
if [[ "${{ steps.meta.outputs.prerelease }}" == "true" ]]; then
419+
FLAGS+=("--prerelease")
420+
fi
421+
gh release create "${{ steps.meta.outputs.tag }}" \
422+
--title "wrapt ${{ steps.meta.outputs.version }}" \
423+
--notes-file body.md \
424+
"${FLAGS[@]}" \
425+
dist/*
426+
427+
publish-wrapt:
428+
name: Publish wrapt to PyPi
429+
runs-on: ubuntu-latest
430+
needs:
431+
- release
432+
if: startsWith(github.ref, 'refs/tags/')
433+
environment: pypi-wrapt
434+
permissions:
435+
id-token: write
436+
steps:
437+
- name: Download all built artifacts
438+
uses: actions/download-artifact@v8
439+
with:
440+
path: dist
441+
merge-multiple: true
442+
443+
- name: Stage wrapt sdist and wheels
444+
run: |
445+
mkdir -p stage
446+
cp dist/wrapt-[0-9]*.tar.gz stage/
447+
cp dist/wrapt-[0-9]*.whl stage/
448+
ls -las stage
449+
450+
- name: Publish wrapt to PyPi
451+
uses: pypa/gh-action-pypi-publish@release/v1
452+
with:
453+
packages-dir: stage/

src/wrapt/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
Wrapt is a library for decorators, wrappers and monkey patching.
33
"""
44

5-
__version_info__ = ("2", "2", "0", "rc11")
5+
__version_info__ = ("2", "2", "0", ".dev1")
66
__version__ = ".".join(__version_info__)
77

88
from .__wrapt__ import (

0 commit comments

Comments
 (0)