-
Notifications
You must be signed in to change notification settings - Fork 1
170 lines (146 loc) · 5.96 KB
/
publish-pypi.yml
File metadata and controls
170 lines (146 loc) · 5.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
name: Publish to PyPI
on:
release:
types: [published]
workflow_dispatch:
inputs:
confirm:
description: 'Confirm production PyPI publishing'
required: true
type: choice
options:
- 'No'
- 'Yes'
default: 'No'
jobs:
build:
name: Build distributions
runs-on: ubuntu-latest
if: github.event_name == 'release' || github.event.inputs.confirm == 'Yes'
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.10'
- name: Install build tools
run: pip install --upgrade build
- name: Build all packages
run: |
for pkg_dir in packages/*/; do
echo "Building $(basename $pkg_dir)..."
cd "$pkg_dir"
python -m build --wheel --sdist
cd ../..
done
- name: Collect distributions
run: |
mkdir -p dist-all
find packages -name '*.whl' -o -name '*.tar.gz' | while read file; do
cp "$file" dist-all/
done
- name: Upload distributions
uses: actions/upload-artifact@v4
with:
name: distributions
path: dist-all/
publish-pypi:
name: Publish to PyPI
needs: build
runs-on: ubuntu-latest
environment: pypi
permissions:
id-token: write
steps:
- name: Download distributions
uses: actions/download-artifact@v4
with:
name: distributions
path: dist/
- name: Check for version changes vs PyPI
run: |
pip install requests packaging
python << 'EOF'
import os
import json
import requests
from pathlib import Path
from packaging import version
dist_dir = Path('dist')
errors = []
print("=" * 70)
print("CHECKING: Built versions vs PyPI published versions")
print("=" * 70)
for wheel in dist_dir.glob('*.whl'):
# Extract package name and version from wheel filename
# Format: {distribution}-{version}(-{build tag})?-{python tag}-{abi tag}-{platform tag}.whl
parts = wheel.name.split('-')
pkg_name = parts[0].replace('_', '-').lower()
pkg_version = parts[1]
print(f"\nChecking {pkg_name} (built: {pkg_version})...")
# Check PyPI API
try:
response = requests.get(
f'https://pypi.org/pypi/{pkg_name}/json',
timeout=10
)
if response.status_code == 404:
print(f" [NEW] Not on PyPI yet (will publish)")
continue
elif response.status_code != 200:
print(f" [WARN] PyPI API error: {response.status_code}")
continue
pypi_data = response.json()
pypi_versions = list(pypi_data['releases'].keys())
latest_pypi = max(pypi_versions, key=version.parse) if pypi_versions else None
if pkg_version in pypi_versions:
# Version exists on PyPI - check if code changed
print(f" [EXISTS] Version {pkg_version} already on PyPI")
# Get git commit hash for this package
import subprocess
try:
result = subprocess.run(
['git', 'log', '-1', '--format=%h', '--', f'packages/{pkg_name.replace("-", "_")}'],
capture_output=True, text=True, timeout=10
)
current_commit = result.stdout.strip()
if current_commit:
print(f" Current commit: {current_commit}")
print(f" [ERROR] Code changed but version not bumped!")
errors.append(
f"{pkg_name}: Built version {pkg_version} already on PyPI "
f"but code has changed (commit {current_commit}). "
f"Bump version in pyproject.toml"
)
else:
print(f" [WARN] Cannot determine git changes")
except Exception as e:
print(f" [WARN] Could not check git history: {e}")
else:
print(f" [NEW VERSION] {pkg_version} (will publish)")
if latest_pypi:
print(f" Latest on PyPI: {latest_pypi}")
except requests.RequestException as e:
print(f" [WARN] Could not check PyPI: {e}")
print("\n" + "=" * 70)
if errors:
print("[FAILED] VERSION CHECK FAILED")
print("\nErrors:")
for error in errors:
print(f" - {error}")
print("\nAction required:")
print(" 1. Bump version in package's pyproject.toml")
print(" 2. Commit the version change")
print(" 3. Re-run this workflow")
exit(1)
else:
print("[PASSED] VERSION CHECK PASSED")
print("\nAll packages either:")
print(" - Are new (not on PyPI yet)")
print(" - Have new versions not yet published")
print("\nProceeding with publication...")
EOF
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
skip-existing: true