forked from vllm-project/agentic-api
-
Notifications
You must be signed in to change notification settings - Fork 0
327 lines (294 loc) · 12.3 KB
/
Copy pathrelease-python.yml
File metadata and controls
327 lines (294 loc) · 12.3 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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
name: Release Python
run-name: Release Python wheels (${{ inputs.publish && 'publish' || 'build only' }})
on:
pull_request:
paths:
- ".github/workflows/python.yml"
- ".github/workflows/release-crates.yml"
- ".github/workflows/release-python.yml"
- "Cargo.lock"
- "Cargo.toml"
- "rust-toolchain.toml"
- "crates/**"
- "README.md"
- "docs/**"
- "pyproject.toml"
- "python-build-constraints.txt"
- "python/**"
- "scripts/check-python-wheel.sh"
- "scripts/validate-python-release-version.sh"
- "tests/python/**"
merge_group:
push:
branches:
- main
paths:
- ".github/workflows/python.yml"
- ".github/workflows/release-crates.yml"
- ".github/workflows/release-python.yml"
- "Cargo.lock"
- "Cargo.toml"
- "rust-toolchain.toml"
- "crates/**"
- "README.md"
- "docs/**"
- "pyproject.toml"
- "python-build-constraints.txt"
- "python/**"
- "scripts/check-python-wheel.sh"
- "scripts/validate-python-release-version.sh"
- "tests/python/**"
workflow_dispatch:
inputs:
publish:
description: "Publish validated wheels to PyPI after all builds succeed"
required: true
type: boolean
default: false
concurrency:
# Keep publication serialized, without letting PR validation occupy its queue.
group: release-python-${{ inputs.publish && 'publish' || format('{0}-{1}', github.event_name, github.ref) }}
cancel-in-progress: ${{ !inputs.publish }}
permissions:
contents: read
jobs:
release-version:
name: Read declared workspace version
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' || !inputs.publish
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- name: Checkout release commit
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"
- name: Read Cargo workspace version
id: version
run: |
python3 - <<'PYTHON'
import os
import tomllib
from pathlib import Path
with Path("Cargo.toml").open("rb") as manifest:
version = tomllib.load(manifest)["workspace"]["package"]["version"]
if not isinstance(version, str) or not version or any(c in version for c in "\r\n"):
raise SystemExit("Invalid Cargo workspace version")
with open(os.environ["GITHUB_OUTPUT"], "a") as output:
output.write(f"version={version}\n")
print(f"Release version: {version}")
PYTHON
- name: Reject an existing PyPI release
if: inputs.publish
env:
AGENTIC_API_RELEASE_VERSION: ${{ steps.version.outputs.version }}
run: |
set -euo pipefail
status="$(curl --silent --show-error --output /dev/null --write-out '%{http_code}' \
--connect-timeout 10 --max-time 30 \
"https://pypi.org/pypi/agentic-api/${AGENTIC_API_RELEASE_VERSION}/json")"
case "$status" in
404) echo "Version $AGENTIC_API_RELEASE_VERSION is not published" ;;
200)
echo "::error::agentic-api $AGENTIC_API_RELEASE_VERSION is already published; bump the Cargo workspace version"
exit 1
;;
*)
echo "::error::Unable to check PyPI release availability (HTTP $status)"
exit 1
;;
esac
build-wheels:
name: Build ${{ matrix.target }} wheel artifact
needs: release-version
runs-on: ${{ matrix.runs-on }}
if: github.ref == 'refs/heads/main' || !inputs.publish
env:
AGENTIC_API_RELEASE_VERSION: ${{ needs.release-version.outputs.version }}
strategy:
fail-fast: false
matrix:
include:
- runs-on: ubuntu-22.04
os: linux
target: linux-x86_64
wheel-tag: py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64
- runs-on: macos-15-intel
os: macos
target: macos-x86_64
wheel-tag: py3-none-macosx_10_12_x86_64
deployment-target: "10.12"
- runs-on: macos-14
os: macos
target: macos-arm64
wheel-tag: py3-none-macosx_11_0_arm64
deployment-target: "11.0"
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Verify release version
run: scripts/validate-python-release-version.sh
- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"
cache: pip
cache-dependency-path: |
pyproject.toml
python-build-constraints.txt
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
with:
toolchain: 1.98.0
components: clippy, rustfmt
- name: Cache cargo registry and build
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target/release-python/${{ matrix.target }}
key: cargo-release-python-${{ runner.os }}-${{ matrix.target }}-${{ hashFiles('Cargo.lock', 'python-build-constraints.txt') }}
restore-keys: |
cargo-release-python-${{ runner.os }}-${{ matrix.target }}-
cargo-${{ runner.os }}-
- name: Install uv
run: python -m pip install --constraint python-build-constraints.txt uv
- name: Verify version agreement and prepare artifact directory
id: prepare
run: |
set -euo pipefail
scripts/validate-python-release-version.sh
requested_version="$AGENTIC_API_RELEASE_VERSION"
wheel_dir="target/release-python/${{ matrix.target }}/wheels"
cargo_version="$(cargo metadata --format-version 1 --no-deps \
| jq -r '.packages[] | select(.name == "agentic-server") | .version')"
core_version="$(cargo metadata --format-version 1 --no-deps \
| jq -r '.packages[] | select(.name == "agentic-server-core") | .version')"
if [ -z "$cargo_version" ] || [ "$cargo_version" = "null" ]; then
echo "::error::agentic-server package not found in workspace metadata"
exit 1
fi
if [ "$cargo_version" != "$core_version" ]; then
echo "::error::agentic-server ($cargo_version) and agentic-server-core ($core_version) versions differ"
exit 1
fi
if [ "$cargo_version" != "$requested_version" ]; then
echo "::error::workspace version $cargo_version does not match requested release version $requested_version"
exit 1
fi
rm -rf "$wheel_dir"
mkdir -p "$wheel_dir"
uv venv --python 3.12 .venv
uv pip install --python .venv/bin/python --constraint python-build-constraints.txt maturin pytest
echo "wheel_dir=$wheel_dir" >> "$GITHUB_OUTPUT"
- name: Build pinned manylinux2014 x86_64 wheel
if: matrix.os == 'linux'
uses: PyO3/maturin-action@86b9d133d34bc1b40018696f782949dac11bd380 # v1.49.4
with:
command: build
# The manylinux image omits OpenSSL headers. Build and statically link
# the Cargo.lock-pinned source so the wheel needs no system OpenSSL.
args: --release --locked --features vendored-openssl --out ${{ steps.prepare.outputs.wheel_dir }}
container: quay.io/pypa/manylinux2014_x86_64@sha256:95440e0e72dd3a81dc8d2cf59a84d57af661456620f5bc821ff92048d0e54ff9
manylinux: "2014"
maturin-version: v1.14.1
rust-toolchain: 1.98.0
target: x86_64-unknown-linux-gnu
# OpenSSL's Configure script needs core Perl modules (including
# IPC::Cmd) that are absent from the stripped-down manylinux image.
before-script-linux: yum install -y perl-core
- name: Build macOS wheel
if: matrix.os == 'macos'
env:
CARGO_TARGET_DIR: target/release-python/${{ matrix.target }}/cargo
MACOSX_DEPLOYMENT_TARGET: ${{ matrix.deployment-target }}
run: >-
.venv/bin/python -m maturin build --release --locked
--out "${{ steps.prepare.outputs.wheel_dir }}"
- name: Validate exact wheel artifact
id: build
run: |
set -euo pipefail
scripts/validate-python-release-version.sh
requested_version="$AGENTIC_API_RELEASE_VERSION"
wheel_dir="${{ steps.prepare.outputs.wheel_dir }}"
expected_wheel_tag="${{ matrix.wheel-tag }}"
wheel_path="$wheel_dir/agentic_api-${requested_version}-${expected_wheel_tag}.whl"
if [ ! -f "$wheel_path" ]; then
echo "::error::expected wheel not found: $wheel_path"
find "$wheel_dir" -maxdepth 1 -type f -name '*.whl' -print
exit 1
fi
wheel_count="$(find "$wheel_dir" -maxdepth 1 -type f -name '*.whl' | wc -l | tr -d ' ')"
if [ "$wheel_count" != "1" ]; then
echo "::error::expected exactly one wheel in $wheel_dir; found $wheel_count"
exit 1
fi
uv pip install --python .venv/bin/python "$wheel_path"
AGENTIC_API_TEST_WHEEL="$wheel_path" .venv/bin/python -m pytest tests/python -q
AGENTIC_API_CHECK_PYTHON=.venv/bin/python \
AGENTIC_API_CHECK_SCRIPTS_DIR=.venv/bin \
AGENTIC_API_EXPECTED_VERSION="$requested_version" \
AGENTIC_API_EXPECTED_WHEEL_TAG="$expected_wheel_tag" \
scripts/check-python-wheel.sh "$wheel_path"
echo "wheel_path=$wheel_path" >> "$GITHUB_OUTPUT"
- name: Check Linux wheel has no system OpenSSL dependency
if: matrix.os == 'linux'
run: |
set -euo pipefail
dependencies="$(ldd .venv/bin/agentic)"
printf '%s\n' "$dependencies"
case "$dependencies" in
*libssl.so*|*libcrypto.so*|*"not found"*)
echo "::error::wheel binary has a system OpenSSL dependency or an unresolved shared library"
exit 1
;;
esac
- name: Upload wheel artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: agentic-api-${{ needs.release-version.outputs.version }}-${{ matrix.target }}
path: ${{ steps.build.outputs.wheel_path }}
if-no-files-found: error
publish:
name: Publish validated wheels to PyPI
needs: [release-version, build-wheels]
if: github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main' && inputs.publish
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/project/agentic-api/
permissions:
id-token: write
steps:
- name: Download validated wheels from this run
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
pattern: agentic-api-${{ needs.release-version.outputs.version }}-*
merge-multiple: true
path: dist/
- name: Validate publication artifacts
env:
AGENTIC_API_RELEASE_VERSION: ${{ needs.release-version.outputs.version }}
run: |
python3 - <<'PYTHON'
import os
from pathlib import Path
version = os.environ["AGENTIC_API_RELEASE_VERSION"]
tags = (
"py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64",
"py3-none-macosx_10_12_x86_64",
"py3-none-macosx_11_0_arm64",
)
expected = {f"agentic_api-{version}-{tag}.whl" for tag in tags}
actual = {path.name for path in Path("dist").iterdir() if path.is_file()}
if actual != expected:
raise SystemExit(f"Expected exactly {sorted(expected)}, found {sorted(actual)}")
PYTHON
- name: Publish wheels using Trusted Publishing
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
with:
packages-dir: dist/