Skip to content

Commit 55d7f3b

Browse files
committed
Enhance GitHub Actions workflow for PyPI release and add version synchronization script
1 parent c910cac commit 55d7f3b

File tree

2 files changed

+139
-18
lines changed

2 files changed

+139
-18
lines changed
Lines changed: 54 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,64 @@
1-
name: Release and Publish to PyPI
1+
name: Create a Release on Tag
2+
23
on:
34
push:
45
tags:
5-
- 'v*'
6+
- "v*"
7+
8+
permissions:
9+
contents: write
10+
packages: write
11+
612
jobs:
7-
publish:
13+
release:
814
runs-on: ubuntu-latest
15+
916
steps:
10-
- name: Checkout code
11-
uses: actions/checkout@v2
17+
- uses: actions/checkout@v4
18+
19+
- uses: actions/setup-python@v5
20+
with:
21+
python-version: 3.11
22+
23+
- name: Install dependencies
24+
run: pip install build tomli tomli-w
25+
26+
# Optional (run a python script to sync versions with the tag)
27+
- name: Extract tag version
28+
id: tag
29+
run: echo "version=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
30+
31+
- name: Set version from tag
32+
run: python sync_version.py --set-version ${{ steps.tag.outputs.version }}
33+
34+
- name: Check if there are changes
35+
id: diff
36+
run: |
37+
if git diff --quiet; then
38+
echo "changed=false" >> $GITHUB_OUTPUT
39+
else
40+
echo "changed=true" >> $GITHUB_OUTPUT
41+
fi
1242
13-
- name: Set up Python
14-
uses: actions/setup-python@v2
15-
with:
16-
python-version: '3.12'
43+
- name: Commit version sync (if needed)
44+
if: steps.diff.outputs.changed == 'true'
45+
run: |
46+
git config user.name "github-actions"
47+
git config user.email "[email protected]"
48+
git commit -am "sync version to ${{ steps.tag.outputs.version }}"
49+
git push origin HEAD:master
50+
# ---
1751

18-
- name: Install dependencies
19-
run: pip install -U build
52+
- name: Build distribution
53+
run: python -m build
2054

21-
- name: Build package
22-
run: python -m build
55+
- name: Create GitHub Release and upload artifacts
56+
uses: softprops/action-gh-release@v2
57+
with:
58+
files: dist/*.whl
2359

24-
- name: Publish to PyPI
25-
uses: pypa/[email protected]
26-
with:
27-
user: __token__
28-
password: ${{ secrets.PYPI_API_TOKEN }}
60+
- name: Publish to PyPI
61+
uses: pypa/[email protected]
62+
with:
63+
user: __token__
64+
password: ${{ secrets.PYPI_API_TOKEN }}

sync_version.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import os
2+
import sys
3+
import tomli
4+
import tomli_w
5+
import argparse
6+
7+
package_name = "pyIDI"
8+
9+
def synchronize_version():
10+
print("Synchronizing version (pyproject.toml and __init__.py)...")
11+
12+
# Read the version from pyproject.toml
13+
with open("pyproject.toml", "rb") as f:
14+
pyproject = tomli.load(f)
15+
16+
version_toml = pyproject["project"]["version"]
17+
18+
# Read the __init__.py
19+
with open(f"{package_name}/__init__.py", "r") as f:
20+
init = f.readlines()
21+
22+
# Replace the version with the one from pyproject.toml
23+
for i, line in enumerate(init):
24+
if "__version__" in line:
25+
init[i] = "__version__ = " + f'"{version_toml}"' + "\n"
26+
init = "".join(init)
27+
28+
# Write the new __init__.py
29+
with open(f"{package_name}/__init__.py", "w") as f:
30+
f.write(init)
31+
32+
# Update docs/source/conf.py
33+
with open("docs/source/conf.py", "r", encoding="utf8") as f:
34+
conf = f.readlines()
35+
36+
for i, line in enumerate(conf):
37+
if "version = " in line and not line.strip().startswith("#"):
38+
conf[i] = f"version = '{version_toml.rsplit('.', 1)[0]}'\n"
39+
elif "release = " in line and not line.strip().startswith("#"):
40+
conf[i] = f"release = '{version_toml}'\n"
41+
42+
# Write the new conf.py
43+
with open("docs/source/conf.py", "w", encoding="utf8") as f:
44+
f.write("".join(conf))
45+
46+
def set_version(version):
47+
with open("pyproject.toml", "rb") as f:
48+
pyproject = tomli.load(f)
49+
pyproject["project"]["version"] = version
50+
with open("pyproject.toml", "wb") as f:
51+
tomli_w.dump(pyproject, f)
52+
53+
def bump_version(bump):
54+
with open("pyproject.toml", "rb") as f:
55+
pyproject = tomli.load(f)
56+
version = pyproject["project"]["version"]
57+
version_parts = version.split(".")
58+
if bump == "patch":
59+
version_parts[2] = str(int(version_parts[2]) + 1)
60+
elif bump == "minor":
61+
version_parts[1] = str(int(version_parts[1]) + 1)
62+
version_parts[2] = "0"
63+
elif bump == "major":
64+
version_parts[0] = str(int(version_parts[0]) + 1)
65+
version_parts[1] = "0"
66+
version_parts[2] = "0"
67+
else:
68+
raise ValueError(f"Invalid bump type: {bump}")
69+
70+
version = ".".join(version_parts)
71+
set_version(version)
72+
73+
if __name__ == "__main__":
74+
parser = argparse.ArgumentParser()
75+
parser.add_argument("--bump", default="", choices=["patch", "minor", "major"], help="Bump the version of the package.")
76+
parser.add_argument("--set-version", type=str, help="Set the version of the package.")
77+
args = parser.parse_args()
78+
79+
if args.set_version:
80+
set_version(args.set_version)
81+
82+
elif args.bump:
83+
bump_version(args.bump)
84+
85+
synchronize_version()

0 commit comments

Comments
 (0)