Skip to content

Commit a625979

Browse files
committed
Fix python-semver#205: Make PyPI releases easier
* Add a release.yml GitHub Action * Add [[tool.uv.index]] to configure "uv publish" * Currently, using TestPyPI Idea taken from ArjanCodes (https://www.youtube.com/watch?v=NMQwzI9hprg) and https://github.com/ArjanCodes/bragir/blob/main/.github/workflows/release.yaml
1 parent 7b7304b commit a625979

File tree

2 files changed

+202
-0
lines changed

2 files changed

+202
-0
lines changed

.github/workflows/release.yml

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
---
2+
name: release
3+
4+
# Taken from arjancodes/bragir/.github/workflows/test.yaml@main
5+
6+
on:
7+
push:
8+
tags:
9+
- "[0-9]+.[0-9]+.[0-9]+"
10+
- "[0-9]+.[0-9]+.[0-9]+a[0-9]+"
11+
- "[0-9]+.[0-9]+.[0-9]+b[0-9]+"
12+
- "[0-9]+.[0-9]+.[0-9]+rc.?[0-9]+"
13+
14+
env:
15+
PACKAGE_NAME: "semver"
16+
OWNER: "python-semver"
17+
18+
jobs:
19+
details:
20+
runs-on: ubuntu-latest
21+
# needs: unit-test
22+
outputs:
23+
new_version: ${{ steps.release.outputs.new_version }}
24+
suffix: ${{ steps.release.outputs.suffix }}
25+
tag_name: ${{ steps.release.outputs.tag_name }}
26+
steps:
27+
- uses: actions/checkout@v2
28+
29+
- name: Extract tag and Details
30+
id: release
31+
run: |
32+
echo "::notice::Extracting tag and new version"
33+
if [ "${{ github.ref_type }}" = "tag" ]; then
34+
TAG_NAME=${GITHUB_REF#refs/tags/}
35+
NEW_VERSION=$(echo $TAG_NAME | awk -F'-' '{print $1}')
36+
SUFFIX=$(echo $TAG_NAME | grep -oP '[a-z]+[0-9]+' || echo "")
37+
echo "new_version=$NEW_VERSION" >> "$GITHUB_OUTPUT"
38+
echo "suffix=$SUFFIX" >> "$GITHUB_OUTPUT"
39+
echo "tag_name=$TAG_NAME" >> "$GITHUB_OUTPUT"
40+
echo "Version is $NEW_VERSION"
41+
echo "Suffix is $SUFFIX"
42+
echo "Tag name is $TAG_NAME"
43+
else
44+
echo "::error,line=43::No tag found"
45+
exit 1
46+
fi
47+
48+
check_pypi:
49+
needs: details
50+
runs-on: ubuntu-latest
51+
steps:
52+
- name: Fetch information from PyPI
53+
run: |
54+
response=$(curl -s https://pypi.org/pypi/${{ env.PACKAGE_NAME }}/json || echo '{"releases": {"0.0.0": []}}' )
55+
# We need to find the latest release in the "releases" key:
56+
latest_previous_version=$(echo $response | jq -r '
57+
.releases
58+
| keys
59+
| map(
60+
split(".")
61+
| map(select(test("^[0-9]+$")) | tonumber)
62+
| .[0:3]
63+
)
64+
| sort_by(.[0], .[1], .[2])
65+
| last
66+
| join(".")
67+
' )
68+
# This is actually not really needed; if the curl command fails,
69+
# it creates an artifical "0.0.0" release which is an error.
70+
#if [ -z "$latest_previous_version" ]; then
71+
# echo "Package not found on PyPI."
72+
# latest_previous_version="0.0.0"
73+
#fi
74+
if [[ $latest_previous_version = "0.0.0" ]]; then
75+
echo "::error::semver release cannot be 0.0.0. Package not found on PyPI"
76+
exit 10
77+
fi
78+
echo "::notice::Latest version on PyPI: $latest_previous_version"
79+
echo "latest_previous_version=$latest_previous_version" >> $GITHUB_ENV
80+
81+
- name: Compare versions and exit if not newer
82+
run: |
83+
NEW_VERSION=${{ needs.details.outputs.new_version }}
84+
PREV_VERSION=$latest_previous_version
85+
if [ "$(printf '%s\n' "$PREV_VERSION" "$NEW_VERSION" | sort -rV | head -n 1)" != "$NEW_VERSION" ] || [ "$NEW_VERSION" == "$PREV_VERSION" ]; then
86+
echo "::error::[ERROR] The new version $NEW_VERSION is NOT greater than the latest version $PREV_VERSION on PyPI."
87+
exit 1
88+
else
89+
echo "::notice::The new version $NEW_VERSION is greater than the latest version $PREV_VERSION on PyPI."
90+
fi
91+
92+
setup_and_build:
93+
needs: [details, check_pypi]
94+
runs-on: ubuntu-latest
95+
steps:
96+
- uses: actions/checkout@v4
97+
98+
- name: Set up Python
99+
uses: actions/setup-python@v5
100+
with:
101+
python-version: "3.12"
102+
103+
- name: Install uv
104+
uses: astral-sh/setup-uv@v3
105+
106+
- name: Bump version
107+
run: |
108+
NEW_VERSION="${{ needs.details.outputs.new_version }}"
109+
sed -i "s/version = \"[0-9]*\.[0-9]*\.[0-9]*\"/version = \"$NEW_VERSION\"/" $GITHUB_WORKSPACE/pyproject.toml
110+
111+
- name: Install dependencies
112+
run: uv sync
113+
114+
- name: Build source and wheel distribution
115+
run: |
116+
uv build
117+
118+
- name: Upload artifacts
119+
uses: actions/upload-artifact@v4
120+
with:
121+
name: dist
122+
path: dist/
123+
124+
pypi_publish:
125+
name: Upload release to PyPI
126+
needs: [setup_and_build, details]
127+
runs-on: ubuntu-latest
128+
environment:
129+
name: release
130+
permissions:
131+
id-token: write
132+
steps:
133+
- name: Download artifacts
134+
uses: actions/download-artifact@v4
135+
with:
136+
name: dist
137+
path: dist/
138+
139+
- name: Install uv
140+
uses: astral-sh/setup-uv@v3
141+
142+
- name: Publish to PyPI
143+
run: |
144+
# See Settings > Environments > release
145+
# https://github.com/python-semver/python-semver/settings/environments/5171753885/
146+
uv publish --index testpypi \
147+
--username ${{ vars.UV_PUBLISH_USERNAME }} \
148+
--password ${{ secrets.UV_PUBLISH_TOKEN }}
149+
150+
github_release:
151+
name: Create GitHub Release
152+
needs: [setup_and_build, details]
153+
runs-on: ubuntu-latest
154+
permissions:
155+
contents: write
156+
steps:
157+
- name: Checkout Code
158+
uses: actions/checkout@v3
159+
with:
160+
fetch-depth: 0 # Fetch full history to avoid issues with tags and branches
161+
162+
- name: Download artifacts
163+
uses: actions/download-artifact@v3
164+
with:
165+
name: dist
166+
path: dist/
167+
168+
- name: Create GitHub Release
169+
id: create_release
170+
env:
171+
GH_TOKEN: ${{ github.token }}
172+
run: |
173+
gh release create ${{ needs.details.outputs.tag_name }} dist/* --title ${{ needs.details.outputs.tag_name }} --generate-notes
174+
175+
176+
# bump_version:
177+
# needs: [details, github_release, pypi_publish]
178+
# runs-on: ubuntu-latest
179+
# steps:
180+
# - name: Checkout Code
181+
# uses: actions/checkout@v3
182+
# with:
183+
# fetch-depth: 0 # Fetch full history to avoid issues with tags and branches
184+
185+
# - name: Bump version
186+
# run: |
187+
# NEW_VERSION="${{ needs.details.outputs.new_version }}"
188+
# sed -i "s/version = \"[0-9]*\.[0-9]*\.[0-9]*\"/version = \"$NEW_VERSION\"/" $GITHUB_WORKSPACE/pyproject.toml
189+
190+
# #- uses: stefanzweifel/git-auto-commit-action@v5
191+
# # with:
192+
# # commit_message: Bumping version to ${{ needs.details.outputs.new_version }}
193+
# # branch: bump-version-${{ needs.details.outputs.new_version }}
194+
# # file_pattern: "pyproject.toml"
195+
# # skip_dirty_check: true
196+
# # create_branch: true

pyproject.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,12 @@ version = {attr = "semver.__about__.__version__"}
129129
version_scheme = "post-release"
130130
local_scheme = "dirty-tag"
131131

132+
# ------------
133+
[[tool.uv.index]]
134+
name = "testpypi"
135+
url = "https://test.pypi.org/semver/"
136+
publish-url = "https://test.pypi.org/legacy/"
137+
132138

133139
[tool.mypy]
134140
# ignore_missing_imports = true

0 commit comments

Comments
 (0)