Skip to content

Commit 68c71ae

Browse files
ci: add auto-publish workflow with CalVer versioning (#2)
1 parent 45e8e93 commit 68c71ae

1 file changed

Lines changed: 160 additions & 0 deletions

File tree

.github/workflows/publish.yml

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
name: Publish to PyPI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
workflow_dispatch:
7+
8+
concurrency:
9+
group: publish-${{ github.ref }}
10+
cancel-in-progress: false
11+
12+
jobs:
13+
build:
14+
name: Build distribution
15+
runs-on: ubuntu-latest
16+
outputs:
17+
version: ${{ steps.version.outputs.version }}
18+
permissions:
19+
contents: read
20+
steps:
21+
- uses: actions/checkout@v6
22+
with:
23+
fetch-depth: 0
24+
25+
- name: Set up Python
26+
uses: actions/setup-python@v6
27+
with:
28+
python-version: '3.12'
29+
30+
- name: Generate date-based version
31+
id: version
32+
env:
33+
PACKAGE_NAME: acedatacloud-scaffold
34+
run: |
35+
python - <<'PY'
36+
import json
37+
import os
38+
import urllib.request
39+
from datetime import datetime, timezone
40+
41+
package_name = os.environ['PACKAGE_NAME']
42+
date_prefix = datetime.now(timezone.utc).strftime('%Y.%-m.%-d')
43+
next_build = 0
44+
45+
try:
46+
with urllib.request.urlopen(f'https://pypi.org/pypi/{package_name}/json', timeout=10) as response:
47+
releases = json.load(response).get('releases', {})
48+
builds = []
49+
for release in releases:
50+
if not release.startswith(f'{date_prefix}.'):
51+
continue
52+
parts = release.split('.')
53+
if len(parts) != 4:
54+
continue
55+
try:
56+
builds.append(int(parts[3]))
57+
except ValueError:
58+
continue
59+
if builds:
60+
next_build = max(builds) + 1
61+
except Exception:
62+
next_build = 0
63+
64+
version = f'{date_prefix}.{next_build}'
65+
with open(os.environ['GITHUB_OUTPUT'], 'a', encoding='utf-8') as fh:
66+
fh.write(f'version={version}\n')
67+
print(f'Generated version: {version}')
68+
PY
69+
70+
- name: Update package version
71+
env:
72+
VERSION: ${{ steps.version.outputs.version }}
73+
run: |
74+
python - <<'PY'
75+
import os
76+
import pathlib
77+
import re
78+
79+
version = os.environ['VERSION']
80+
version_file = pathlib.Path('acedatacloud_scaffold/__version__.py')
81+
content = version_file.read_text(encoding='utf-8')
82+
updated = re.sub(
83+
r'^VERSION = \([^\n]+\)$',
84+
f'VERSION = ({", ".join(version.split("."))})',
85+
content,
86+
count=1,
87+
flags=re.MULTILINE,
88+
)
89+
if updated == content:
90+
raise SystemExit('Failed to update VERSION tuple in acedatacloud_scaffold/__version__.py')
91+
version_file.write_text(updated, encoding='utf-8')
92+
print(version_file.read_text(encoding='utf-8'))
93+
PY
94+
95+
- name: Install build dependencies
96+
run: |
97+
python -m pip install --upgrade pip
98+
pip install build "twine>=6.1.0,<7.0.0"
99+
100+
- name: Build package
101+
run: python -m build
102+
103+
- name: Check package metadata
104+
run: twine check dist/*
105+
106+
- name: Upload distribution artifacts
107+
uses: actions/upload-artifact@v7
108+
with:
109+
name: python-package-distributions
110+
path: dist/
111+
112+
publish-pypi:
113+
name: Publish to PyPI
114+
needs: build
115+
runs-on: ubuntu-latest
116+
environment:
117+
name: pypi
118+
url: https://pypi.org/project/acedatacloud-scaffold/${{ needs.build.outputs.version }}
119+
permissions:
120+
contents: read
121+
steps:
122+
- name: Download distribution artifacts
123+
uses: actions/download-artifact@v8
124+
with:
125+
name: python-package-distributions
126+
path: dist/
127+
128+
- name: Publish to PyPI
129+
env:
130+
TWINE_USERNAME: __token__
131+
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
132+
run: |
133+
python -m pip install --upgrade pip
134+
pip install "twine>=6.1.0,<7.0.0"
135+
twine upload dist/*
136+
137+
create-release:
138+
name: Create GitHub Release
139+
if: github.event_name == 'push'
140+
needs: [build, publish-pypi]
141+
runs-on: ubuntu-latest
142+
permissions:
143+
contents: write
144+
steps:
145+
- uses: actions/checkout@v6
146+
147+
- name: Download distribution artifacts
148+
uses: actions/download-artifact@v8
149+
with:
150+
name: python-package-distributions
151+
path: dist/
152+
153+
- name: Create Release
154+
env:
155+
GITHUB_TOKEN: ${{ github.token }}
156+
run: |
157+
gh release create "v${{ needs.build.outputs.version }}" dist/* \
158+
--title "v${{ needs.build.outputs.version }}" \
159+
--generate-notes \
160+
--repo '${{ github.repository }}' || echo "Release already exists, skipping"

0 commit comments

Comments
 (0)