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
name: Python Wheels (PyPI)
# On tag push (or manual dispatch with a tag), builds wheels for every
# supported (os, arch) combination plus an sdist, then publishes all of
# them to PyPI as one atomic release. CI is the canonical source for
# PyPI wheels; the locally-built dist/wheels/ artifacts in
# scripts/publish-release.sh are uploaded to the GitHub/Forgejo release
# pages as a convenience but are not what `pip install graphdblite`
# resolves to.
#
# Publishing uses PyPI trusted publishing (OIDC) via the `pypi`
# environment. To enable for the first release:
# 1. PyPI → Account → Publishing → Add pending publisher:
# owner=ds7n, repo=graphdblite, workflow=python-wheels.yml,
# environment=pypi.
# 2. GitHub → Settings → Environments → New environment "pypi".
# Token-based fallback: set PYPI_API_TOKEN as a secret and add
# `password: ${{ secrets.PYPI_API_TOKEN }}` to the publish step.
on:
push:
tags:
- "v*"
workflow_dispatch:
inputs:
tag:
description: "Tag to publish (e.g. v0.1.0). Required for manual runs."
required: true
permissions:
contents: read
concurrency:
group: python-wheels-${{ github.ref }}
cancel-in-progress: false
jobs:
build-wheels:
name: build (${{ matrix.os }}, ${{ matrix.target }}, ${{ matrix.manylinux }})
strategy:
fail-fast: false
matrix:
include:
# Linux glibc (manylinux_2_28)
- os: ubuntu-latest
target: x86_64
manylinux: "2_28"
- os: ubuntu-latest
target: aarch64
manylinux: "2_28"
# Linux musl (musllinux_1_2)
- os: ubuntu-latest
target: x86_64
manylinux: musllinux_1_2
- os: ubuntu-latest
target: aarch64
manylinux: musllinux_1_2
# macOS (universal2 would be ideal but maturin builds per-arch)
- os: macos-latest
target: x86_64
manylinux: auto
- os: macos-latest
target: aarch64
manylinux: auto
# Windows
- os: windows-latest
target: x64
manylinux: auto
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v6
- uses: astral-sh/setup-uv@v8.1.0
# PyO3/maturin-action drives cibuildwheel (brings its own per-target
# Pythons), but a host Python is needed for the action prelude.
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
args: --release --out dist --manifest-path bindings/python/Cargo.toml
manylinux: ${{ matrix.manylinux }}
- uses: actions/upload-artifact@v7
with:
name: wheels-${{ matrix.os }}-${{ matrix.target }}-${{ matrix.manylinux }}
path: dist/*.whl
build-sdist:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Build sdist
uses: PyO3/maturin-action@v1
with:
command: sdist
args: --out dist --manifest-path bindings/python/Cargo.toml
- uses: actions/upload-artifact@v7
with:
name: sdist
path: dist/*.tar.gz
publish:
needs:
runs-on: ubuntu-latest
environment: pypi
permissions:
id-token: write # trusted publishing — no token needed
steps:
- uses: actions/download-artifact@v8
with:
pattern: wheels-*
merge-multiple: true
path: dist/
- uses: actions/download-artifact@v8
with:
name: sdist
path: dist/
- name: List artifacts to publish
run: ls -lh dist/
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
# Allow re-runs against an already-published version to no-op
# instead of failing (e.g. when re-firing a moved tag).
skip-existing: true