Skip to content

Commit 134dada

Browse files
committed
ci: add build+smoke workflows and gate PyPI publish on main
1 parent 7aa8972 commit 134dada

File tree

4 files changed

+380
-5
lines changed

4 files changed

+380
-5
lines changed

.github/workflows/ci.yml

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
name: ci
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches:
7+
- "**"
8+
tags-ignore:
9+
- "v*"
10+
- "test-v*"
11+
12+
jobs:
13+
build_wheels:
14+
name: Build wheels (${{ matrix.os }})
15+
runs-on: ${{ matrix.os }}
16+
strategy:
17+
fail-fast: false
18+
matrix:
19+
os: [ubuntu-latest, macos-latest, windows-latest]
20+
21+
steps:
22+
- uses: actions/checkout@v4
23+
24+
- name: Set up Python
25+
uses: actions/setup-python@v5
26+
with:
27+
python-version: "3.12"
28+
29+
- name: Install build tooling
30+
run: |
31+
python -m pip install --upgrade pip
32+
python -m pip install cibuildwheel==2.*
33+
34+
# Build dependencies (CGAL headers + GMP/MPFR libs) into a local prefix via micromamba.
35+
# The wheel build will link against these, and repair tools will bundle the runtime libs.
36+
- name: Install micromamba (Unix)
37+
if: runner.os != 'Windows'
38+
shell: bash
39+
run: |
40+
set -euxo pipefail
41+
curl -Ls https://micro.mamba.pm/api/micromamba/$(uname)/$(uname -m)/latest | tar -xvj bin/micromamba
42+
sudo mv bin/micromamba /usr/local/bin/micromamba
43+
44+
- name: Install micromamba (Windows)
45+
if: runner.os == 'Windows'
46+
shell: pwsh
47+
run: |
48+
Invoke-WebRequest -Uri "https://micro.mamba.pm/api/micromamba/win-64/latest" -OutFile micromamba.tar.bz2
49+
tar -xjf micromamba.tar.bz2
50+
echo "${PWD}\\Library\\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
51+
52+
- name: Build wheels
53+
env:
54+
# Use a local prefix so setup.py can find include/lib without relying on system installs.
55+
# cibuildwheel will run these on the build machine (and inside manylinux containers on Linux).
56+
CIBW_ENVIRONMENT: "OCEANMESH_PREFIX=/opt/om"
57+
CIBW_BEFORE_ALL_LINUX: |
58+
set -eux
59+
curl -Ls https://micro.mamba.pm/api/micromamba/Linux/x86_64/latest | tar -xvj bin/micromamba
60+
mv bin/micromamba /usr/local/bin/micromamba
61+
micromamba create -y -p /opt/om -c conda-forge \
62+
cgal boost-cpp gmp mpfr eigen
63+
CIBW_BEFORE_ALL_MACOS: |
64+
set -eux
65+
micromamba create -y -p /opt/om -c conda-forge \
66+
cgal boost-cpp gmp mpfr eigen
67+
CIBW_BEFORE_ALL_WINDOWS: |
68+
micromamba create -y -p C:\\om -c conda-forge cgal boost-cpp gmp mpfr eigen
69+
CIBW_ENVIRONMENT_WINDOWS: "OCEANMESH_PREFIX=C:\\om"
70+
# Repair wheels to bundle shared libs.
71+
CIBW_REPAIR_WHEEL_COMMAND_MACOS: "python -m pip install delocate && delocate-wheel -w {dest_dir} -v {wheel}"
72+
CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: "python -m pip install delvewheel && delvewheel repair -w {dest_dir} {wheel}"
73+
run: |
74+
python -m cibuildwheel --output-dir dist
75+
76+
- name: Upload wheel artifacts
77+
uses: actions/upload-artifact@v4
78+
with:
79+
name: wheels-${{ matrix.os }}
80+
path: dist/*.whl
81+
82+
build_sdist:
83+
name: Build sdist
84+
runs-on: ubuntu-latest
85+
steps:
86+
- uses: actions/checkout@v4
87+
- uses: actions/setup-python@v5
88+
with:
89+
python-version: "3.12"
90+
- name: Build sdist
91+
run: |
92+
python -m pip install --upgrade pip
93+
python -m pip install build
94+
python -m build --sdist
95+
- name: Upload sdist artifact
96+
uses: actions/upload-artifact@v4
97+
with:
98+
name: sdist
99+
path: dist/*.tar.gz
100+
101+
smoke_test:
102+
name: Smoke test install (${{ matrix.os }})
103+
needs: [build_wheels]
104+
runs-on: ${{ matrix.os }}
105+
strategy:
106+
fail-fast: false
107+
matrix:
108+
os: [ubuntu-latest, macos-latest, windows-latest]
109+
110+
steps:
111+
- name: Set up Python
112+
uses: actions/setup-python@v5
113+
with:
114+
python-version: "3.12"
115+
116+
- name: Download wheel artifacts
117+
uses: actions/download-artifact@v4
118+
with:
119+
name: wheels-${{ matrix.os }}
120+
path: dist
121+
122+
- name: Install wheel into fresh venv and import
123+
shell: bash
124+
run: |
125+
set -euxo pipefail
126+
python -m venv .venv
127+
if [ -f .venv/bin/activate ]; then
128+
source .venv/bin/activate
129+
else
130+
source .venv/Scripts/activate
131+
fi
132+
133+
python -m pip install --upgrade pip packaging
134+
135+
python - <<'PY'
136+
import glob
137+
import os
138+
import sys
139+
import subprocess
140+
141+
from packaging import tags
142+
from packaging.utils import parse_wheel_filename
143+
144+
wheels = sorted(glob.glob(os.path.join("dist", "*.whl")))
145+
if not wheels:
146+
raise SystemExit("No wheels found in dist/")
147+
148+
supported = set(tags.sys_tags())
149+
150+
def is_compatible(wheel_path: str) -> bool:
151+
_, _, _, wheel_tags = parse_wheel_filename(os.path.basename(wheel_path))
152+
return any(t in supported for t in wheel_tags)
153+
154+
selected = next((w for w in wheels if is_compatible(w)), None)
155+
if not selected:
156+
raise SystemExit(f"No compatible wheel found. Found wheels: {wheels}")
157+
158+
print(f"Selected wheel: {selected}")
159+
subprocess.check_call([sys.executable, "-m", "pip", "install", selected])
160+
PY
161+
162+
python -c "import oceanmesh; print(oceanmesh.__version__)"
163+
python -c "import oceanmesh; oceanmesh.Region((0, 1, 0, 1), 'EPSG:4326'); print('ok')"
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
name: publish-testpypi
2+
3+
on:
4+
workflow_dispatch:
5+
push:
6+
tags:
7+
- "test-v*"
8+
9+
jobs:
10+
build_wheels:
11+
name: Build wheels (${{ matrix.os }})
12+
runs-on: ${{ matrix.os }}
13+
strategy:
14+
fail-fast: false
15+
matrix:
16+
os: [ubuntu-latest, macos-latest, windows-latest]
17+
18+
steps:
19+
- uses: actions/checkout@v4
20+
21+
- name: Set up Python
22+
uses: actions/setup-python@v5
23+
with:
24+
python-version: "3.12"
25+
26+
- name: Install build tooling
27+
run: |
28+
python -m pip install --upgrade pip
29+
python -m pip install cibuildwheel==2.*
30+
31+
# Build dependencies (CGAL headers + GMP/MPFR libs) into a local prefix via micromamba.
32+
# The wheel build will link against these, and repair tools will bundle the runtime libs.
33+
- name: Install micromamba (Unix)
34+
if: runner.os != 'Windows'
35+
shell: bash
36+
run: |
37+
set -euxo pipefail
38+
curl -Ls https://micro.mamba.pm/api/micromamba/$(uname)/$(uname -m)/latest | tar -xvj bin/micromamba
39+
sudo mv bin/micromamba /usr/local/bin/micromamba
40+
41+
- name: Install micromamba (Windows)
42+
if: runner.os == 'Windows'
43+
shell: pwsh
44+
run: |
45+
Invoke-WebRequest -Uri "https://micro.mamba.pm/api/micromamba/win-64/latest" -OutFile micromamba.tar.bz2
46+
tar -xjf micromamba.tar.bz2
47+
echo "${PWD}\\Library\\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
48+
49+
- name: Build wheels
50+
env:
51+
# Use a local prefix so setup.py can find include/lib without relying on system installs.
52+
# cibuildwheel will run these on the build machine (and inside manylinux containers on Linux).
53+
CIBW_ENVIRONMENT: "OCEANMESH_PREFIX=/opt/om"
54+
CIBW_BEFORE_ALL_LINUX: |
55+
set -eux
56+
curl -Ls https://micro.mamba.pm/api/micromamba/Linux/x86_64/latest | tar -xvj bin/micromamba
57+
mv bin/micromamba /usr/local/bin/micromamba
58+
micromamba create -y -p /opt/om -c conda-forge \
59+
cgal boost-cpp gmp mpfr eigen
60+
CIBW_BEFORE_ALL_MACOS: |
61+
set -eux
62+
micromamba create -y -p /opt/om -c conda-forge \
63+
cgal boost-cpp gmp mpfr eigen
64+
CIBW_BEFORE_ALL_WINDOWS: |
65+
micromamba create -y -p C:\\om -c conda-forge cgal boost-cpp gmp mpfr eigen
66+
CIBW_ENVIRONMENT_WINDOWS: "OCEANMESH_PREFIX=C:\\om"
67+
# Repair wheels to bundle shared libs.
68+
CIBW_REPAIR_WHEEL_COMMAND_MACOS: "python -m pip install delocate && delocate-wheel -w {dest_dir} -v {wheel}"
69+
CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: "python -m pip install delvewheel && delvewheel repair -w {dest_dir} {wheel}"
70+
run: |
71+
python -m cibuildwheel --output-dir dist
72+
73+
- name: Upload wheel artifacts
74+
uses: actions/upload-artifact@v4
75+
with:
76+
name: wheels-${{ matrix.os }}
77+
path: dist/*.whl
78+
79+
smoke_test:
80+
name: Smoke test install (${{ matrix.os }})
81+
needs: [build_wheels]
82+
runs-on: ${{ matrix.os }}
83+
strategy:
84+
fail-fast: false
85+
matrix:
86+
os: [ubuntu-latest, macos-latest, windows-latest]
87+
88+
steps:
89+
- name: Set up Python
90+
uses: actions/setup-python@v5
91+
with:
92+
python-version: "3.12"
93+
94+
- name: Download wheel artifacts
95+
uses: actions/download-artifact@v4
96+
with:
97+
name: wheels-${{ matrix.os }}
98+
path: dist
99+
100+
- name: Install wheel into fresh venv and import
101+
shell: bash
102+
run: |
103+
set -euxo pipefail
104+
python -m venv .venv
105+
if [ -f .venv/bin/activate ]; then
106+
source .venv/bin/activate
107+
else
108+
source .venv/Scripts/activate
109+
fi
110+
111+
python -m pip install --upgrade pip packaging
112+
113+
python - <<'PY'
114+
import glob
115+
import os
116+
import sys
117+
import subprocess
118+
119+
from packaging import tags
120+
from packaging.utils import parse_wheel_filename
121+
122+
wheels = sorted(glob.glob(os.path.join("dist", "*.whl")))
123+
if not wheels:
124+
raise SystemExit("No wheels found in dist/")
125+
126+
supported = set(tags.sys_tags())
127+
128+
def is_compatible(wheel_path: str) -> bool:
129+
_, _, _, wheel_tags = parse_wheel_filename(os.path.basename(wheel_path))
130+
return any(t in supported for t in wheel_tags)
131+
132+
selected = next((w for w in wheels if is_compatible(w)), None)
133+
if not selected:
134+
raise SystemExit(f"No compatible wheel found. Found wheels: {wheels}")
135+
136+
print(f"Selected wheel: {selected}")
137+
subprocess.check_call([sys.executable, "-m", "pip", "install", selected])
138+
PY
139+
140+
python -c "import oceanmesh; print(oceanmesh.__version__)"
141+
python -c "import oceanmesh; oceanmesh.Region((0, 1, 0, 1), 'EPSG:4326'); print('ok')"
142+
143+
build_sdist:
144+
name: Build sdist
145+
runs-on: ubuntu-latest
146+
steps:
147+
- uses: actions/checkout@v4
148+
- uses: actions/setup-python@v5
149+
with:
150+
python-version: "3.12"
151+
- name: Build sdist
152+
run: |
153+
python -m pip install --upgrade pip
154+
python -m pip install build
155+
python -m build --sdist
156+
- name: Upload sdist artifact
157+
uses: actions/upload-artifact@v4
158+
with:
159+
name: sdist
160+
path: dist/*.tar.gz
161+
162+
publish_testpypi:
163+
name: Publish to TestPyPI
164+
needs: [build_wheels, build_sdist, smoke_test]
165+
runs-on: ubuntu-latest
166+
permissions:
167+
id-token: write
168+
contents: read
169+
steps:
170+
- name: Download all artifacts
171+
uses: actions/download-artifact@v4
172+
with:
173+
path: dist
174+
175+
- name: Flatten dist directory
176+
shell: bash
177+
run: |
178+
set -eux
179+
mkdir -p upload
180+
find dist -type f \( -name "*.whl" -o -name "*.tar.gz" \) -maxdepth 3 -print -exec cp {} upload/ \;
181+
182+
- name: Publish
183+
uses: pypa/gh-action-pypi-publish@release/v1
184+
with:
185+
repository-url: https://test.pypi.org/legacy/
186+
packages-dir: upload
187+
skip-existing: true

0 commit comments

Comments
 (0)