11name : Build and publish package
22on :
3+ pull_request :
34 push :
4- tags :
5- - " v*.*.* "
5+ branches :
6+ - main
67 workflow_dispatch :
78
9+
810jobs :
11+ check_package_version :
12+ runs-on : ubuntu-latest
13+ outputs :
14+ is_newer : ${{ steps.cmp.outputs.is_newer }}
15+ latest : ${{ steps.cmp.outputs.latest }}
16+ steps :
17+ - uses : actions/checkout@v4
18+ with :
19+ fetch-depth : 0
20+ fetch-tags : true
21+
22+ - name : Install uv
23+ uses : astral-sh/setup-uv@v6
24+
25+ - name : Compare versions
26+ id : cmp
27+ shell : bash
28+ run : |
29+ set -euo pipefail
30+
31+ # Latest tag version (e.g. v1.2.3 → 1.2.3)
32+ tag=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
33+ prev=${tag#v}
34+ curr=$(uv version --short)
35+
36+ echo "prev=$prev"
37+ echo "curr=$curr"
38+
39+ # Default outputs
40+ echo "is_newer=false" >> "$GITHUB_OUTPUT"
41+ echo "latest=" >> "$GITHUB_OUTPUT"
42+
43+ # Determine which is higher: prev or curr
44+ latest_v=$(printf '%s\n%s\n' "$curr" "$prev" | sort -V | tail -1)
45+ echo "latest_v=$latest_v"
46+
47+ # Case 1: current version is newer → publish
48+ if [ "$curr" = "$latest_v" ] && [ "$curr" != "$prev" ]; then
49+ echo "Newer version detected, will publish: $curr"
50+ echo "latest=$curr" >> "$GITHUB_OUTPUT"
51+ echo "is_newer=true" >> "$GITHUB_OUTPUT"
52+ exit 0
53+ fi
54+
55+ # Case 2: versions are equal → skip
56+ if [ "$curr" = "$prev" ]; then
57+ echo "No new version ($curr), skipping publish."
58+ exit 0
59+ fi
60+
61+ # Case 3: current version is older than latest tag → error
62+ echo "Error: pyproject version ($curr) is older than latest tag ($prev)." >&2
63+ exit 1
64+
965 build :
1066 name : Build package
67+ needs :
68+ - check_package_version
69+ if : >
70+ (
71+ github.event_name == 'push' &&
72+ needs.check_package_version.outputs.is_newer == 'true'
73+ ) || github.event_name == 'workflow_dispatch'
1174 runs-on : ubuntu-latest
1275
1376 steps :
14- - uses : actions/checkout@v4
15- with :
16- persist-credentials : false
77+ - uses : actions/checkout@v4
78+ with :
79+ persist-credentials : false
1780
18- - name : Install uv
19- uses : astral-sh/setup-uv@v6
81+ - name : Install uv
82+ uses : astral-sh/setup-uv@v6
2083
21- - name : Build project
22- run : uv build
84+ - name : Build project
85+ run : uv build
2386
24- - name : Store the distribution packages
25- uses : actions/upload-artifact@v4
26- with :
27- name : python-package-distributions
28- path : dist/
87+ - name : Store the distribution packages
88+ uses : actions/upload-artifact@v4
89+ with :
90+ name : python-package-distributions
91+ path : dist/
2992
3093 publish-to-pypi :
3194 name : Publish to PyPI
3295 needs :
33- - build
96+ - build
97+ - check_package_version
98+ if : >
99+ github.ref == 'refs/heads/main' &&
100+ needs.check_package_version.outputs.is_newer == 'true'
34101 runs-on : ubuntu-latest
35102 environment :
36103 name : pypi
@@ -39,10 +106,30 @@ jobs:
39106 id-token : write # IMPORTANT: mandatory for trusted publishing
40107
41108 steps :
42- - name : Download artifacts
43- uses : actions/download-artifact@v4
44- with :
45- name : python-package-distributions
46- path : dist/
47- - name : Publish to PyPI
48- uses : pypa/gh-action-pypi-publish@release/v1
109+ - name : Download artifacts
110+ uses : actions/download-artifact@v4
111+ with :
112+ name : python-package-distributions
113+ path : dist/
114+ - name : Publish to PyPI
115+ uses : pypa/gh-action-pypi-publish@release/v1
116+
117+
118+ create_tag :
119+ name : Create and push tag for new version
120+ needs :
121+ - check_package_version
122+ if : >
123+ github.ref == 'refs/heads/main' &&
124+ needs.check_package_version.outputs.latest != ''
125+ runs-on : ubuntu-latest
126+ permissions :
127+ contents : write
128+ steps :
129+ - uses : actions/checkout@v4
130+ - name : Create and push tag for new version
131+ run : |
132+ version='${{ needs.check_package_version.outputs.latest }}'
133+ echo "Tagging v$version"
134+ git tag "v$version"
135+ git push origin "v$version"
0 commit comments