πŸš€ ci: PyPI publishing via OIDC trusted publishing β€” fixed uv publish command, GH release in-pipeline, removed dead publish.yml

swadhinbiswas committed 2 months ago
bf007b1
1 parent 0598cf5
commit bf007b1
3 files changed
+44 -109
β–Ό.github/workflows/publish.yml
+0-98
1
-name: Publish to PyPI
2
-
3
-on:
4
- release:
5
- types: [published]
6
- workflow_dispatch:
7
- inputs:
8
- version:
9
- description: 'Version to publish (e.g., 2.0.8)'
10
- required: true
11
-
12
-jobs:
13
- build:
14
- name: Build Wheel
15
- runs-on: ubuntu-latest
16
- steps:
17
- - uses: actions/checkout@v4
18
-
19
- - name: Install Rust toolchain
20
- uses: dtolnay/rust-toolchain@stable
21
-
22
- - name: Install Python (for PyO3)
23
- uses: actions/setup-python@v5
24
- with:
25
- python-version: "3.12"
26
-
27
- - name: Cache cargo registry
28
- uses: actions/cache@v4
29
- with:
30
- path: |
31
- ~/.cargo/registry
32
- ~/.cargo/git
33
- target
34
- key: ${{ runner.os }}-publish-${{ hashFiles('**/Cargo.lock') }}
35
- restore-keys: |
36
- ${{ runner.os }}-publish-
37
-
38
- - name: Install maturin
39
- run: pip install maturin
40
-
41
- - name: Build wheel
42
- run: maturin build --release -m crates/justapi-py/Cargo.toml -o wheels/
43
-
44
- - name: Verify wheel
45
- run: |
46
- pip install wheels/*.whl --break-system-packages
47
- python -c "import justapi; print(f'JustAPI installed successfully')"
48
-
49
- - name: Upload wheel artifact
50
- uses: actions/upload-artifact@v4
51
- with:
52
- name: wheels
53
- path: wheels/*.whl
54
-
55
- publish-pypi:
56
- name: Publish to PyPI
57
- runs-on: ubuntu-latest
58
- needs: [build]
59
- environment: pypi
60
- permissions:
61
- id-token: write
62
- # PyPI upload is owned by wheels.yml (7-platform matrix on tag push).
63
- # This job only builds + verifies; the release assets come from wheels.yml.
64
- if: false
65
- steps:
66
- - name: Download wheel artifact
67
- uses: actions/download-artifact@v4
68
- with:
69
- name: wheels
70
- path: wheels/
71
-
72
- - name: Publish to PyPI
73
- uses: pypa/gh-action-pypi-publish@release/v1
74
- with:
75
- packages-dir: wheels/
76
-
77
- create-github-release:
78
- name: Create GitHub Release
79
- runs-on: ubuntu-latest
80
- # PyPI upload is owned by wheels.yml (7-platform matrix). This job only
81
- # builds + verifies the wheel, then creates the GitHub Release with it.
82
- needs: [build]
83
- permissions:
84
- contents: write
85
- steps:
86
- - uses: actions/checkout@v4
87
-
88
- - name: Download wheel artifact
89
- uses: actions/download-artifact@v4
90
- with:
91
- name: wheels
92
- path: wheels/
93
-
94
- - name: Create GitHub Release
95
- uses: softprops/action-gh-release@v2
96
- with:
97
- files: wheels/*.whl
98
- generate_release_notes: true
99
0
β–Ό.github/workflows/wheels.yml
+34-4
6
6
tags: [ 'v*' ]
7
7
pull_request:
8
8
branches: [ main, master ]
9
+ workflow_dispatch:
9
10
10
11
permissions:
11
12
contents: read
95
96
- name: Install wheel & test
96
97
shell: bash
97
98
run: |
99
+ uv venv
98
100
uv pip install dist/*.whl pytest
99
- python -m pytest crates/justapi-py/tests/ -v --tb=short
101
+ uv run python -m pytest crates/justapi-py/tests/ -v --tb=short
100
102
- name: Upload Wheels
101
103
uses: actions/upload-artifact@v4
102
104
with:
104
106
path: dist/*.whl
105
107
106
108
publish:
107
- name: Publish to PyPI
109
+ name: Publish to PyPI + GitHub Release
108
110
runs-on: ubuntu-latest
109
111
needs: build-wheels
110
112
if: startsWith(github.ref, 'refs/tags/v')
113
+ # OIDC trusted publishing β€” NO token needed. Requires the PyPI project's
114
+ # trusted publisher to be configured once at pypi.org (see setup note at
115
+ # the bottom of this file). The `pypi` environment is auto-created by
116
+ # GitHub on first run.
111
117
environment: pypi
112
118
permissions:
113
119
id-token: write
120
+ contents: write
114
121
steps:
115
122
- uses: actions/checkout@v4
116
123
- uses: astral-sh/setup-uv@v5
121
128
pattern: wheels-*
122
129
merge-multiple: true
123
130
path: dist
124
- - name: Publish
125
- run: uv publish --package-dir crates/justapi-py --trusted-publishing always --verbose
131
+ - name: Publish to PyPI (trusted publishing)
132
+ # `uv publish` defaults to dist/*.whl; `--trusted-publishing always`
133
+ # uses the OIDC token from the `pypi` environment β€” no API token.
134
+ run: uv publish --trusted-publishing always
135
+ - name: Create GitHub Release
136
+ uses: softprops/action-gh-release@v2
137
+ with:
138
+ files: dist/*.whl
139
+ generate_release_notes: true
140
+
141
+# --- One-time setup (required once, then publishing is fully automated) ---
142
+#
143
+# 1. At pypi.org β†’ Account β†’ Publishing β†’ "Add a new pending publisher":
144
+# β€’ Publisher: GitHub
145
+# β€’ Owner: swadhinbiswas
146
+# β€’ Repository: JustAPI
147
+# β€’ Environment: pypi (must match the job's `environment:`)
148
+# β€’ Workflow name: wheels.yml
149
+# (Trusted publishing auto-creates the `justapi` project on first upload.)
150
+#
151
+# 2. Push a tag: `git tag v2.0.8 && git push origin v2.0.8`
152
+#
153
+# That's it β€” no MATURIN_PYPI_TOKEN, no secrets. The wheels.yml `publish` job
154
+# then builds the 7-platform matrix, uploads to PyPI via OIDC, and creates the
155
+# GitHub Release with the wheels attached.
126
156
β–Όscripts/publish.sh
+10-7
1
1
#!/usr/bin/env bash
2
-# scripts/publish.sh β€” build + verify + publish the justapi PyPI wheels.
2
+# scripts/publish.sh β€” local build + verify (the RELEASE path is CI).
3
3
#
4
-# The only missing piece for a real release is the PyPI token
5
-# (MATURIN_PYPI_TOKEN / TWINE_PASSWORD). Everything else β€” portable
6
-# manylinux + musllinux builds for x86_64 + aarch64 (via maturin --zig),
7
-# twine check, fresh-venv install smoke β€” is done here so
8
-# `bash scripts/publish.sh` is the single release command.
4
+# PRIMARY RELEASE PATH (no token): push a `v*` tag β†’ .github/workflows/wheels.yml
5
+# builds the 7-platform matrix and publishes to PyPI via OIDC trusted
6
+# publishing (see the setup note at the bottom of wheels.yml). This script is
7
+# the local pre-release verification: portable manylinux + musllinux builds
8
+# (maturin --zig), twine check, fresh-venv install smoke.
9
+#
10
+# Legacy token path (kept for emergencies): MATURIN_PYPI_TOKEN=... bash scripts/publish.sh --upload
9
11
#
10
12
# Prereqs: maturin (with --zig; requires zig on PATH), rustup with the
11
13
# target stds installed (aarch64-unknown-linux-gnu, aarch64-unknown-linux-musl,
73
75
echo "[publish] DONE β€” justapi is on PyPI (4 platforms)"
74
76
else
75
77
echo "[publish] build + verify OK. To release:"
76
- echo " MATURIN_PYPI_TOKEN=... bash scripts/publish.sh --upload"
78
+ echo " (preferred) git tag v2.0.8 && git push origin v2.0.8 # CI publishes via OIDC"
79
+ echo " (emergency) MATURIN_PYPI_TOKEN=... bash scripts/publish.sh --upload"
77
80
fi
78
81