Skip to content

Commit 0c0f1d1

Browse files
committed
feat: Introduce GitHub Actions CI/CD workflows and a smoke test, while updating build configurations and release documentation.
1 parent 71213d3 commit 0c0f1d1

8 files changed

Lines changed: 250 additions & 13 deletions

File tree

.github/workflows/ci.yml

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
name: CI
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- main
7+
8+
jobs:
9+
typecheck:
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
- uses: actions/checkout@v4
14+
15+
- uses: actions/setup-python@v5
16+
with:
17+
python-version: "3.12"
18+
19+
- uses: astral-sh/setup-uv@v7
20+
with:
21+
enable-cache: true
22+
23+
- name: Sync runtime dependencies
24+
run: uv sync --locked
25+
26+
- name: Run pyright
27+
run: uvx pyright
28+
29+
sdist:
30+
runs-on: ubuntu-latest
31+
32+
steps:
33+
- uses: actions/checkout@v4
34+
35+
- uses: actions/setup-python@v5
36+
with:
37+
python-version: "3.12"
38+
39+
- uses: astral-sh/setup-uv@v7
40+
with:
41+
enable-cache: true
42+
43+
- name: Build sdist
44+
run: uv build --sdist --no-sources
45+
46+
- name: Check sdist metadata
47+
run: uvx --from twine twine check dist/*.tar.gz
48+
49+
- name: Smoke test sdist
50+
run: uv run --isolated --no-project --with dist/*.tar.gz tests/smoke_test.py
51+
52+
wheels:
53+
runs-on: ${{ matrix.os }}
54+
strategy:
55+
fail-fast: false
56+
matrix:
57+
os:
58+
- ubuntu-latest
59+
- windows-latest
60+
61+
steps:
62+
- uses: actions/checkout@v4
63+
64+
- uses: pypa/cibuildwheel@v3.2.1
65+
with:
66+
output-dir: wheelhouse
67+
68+
- uses: actions/setup-python@v5
69+
with:
70+
python-version: "3.12"
71+
72+
- name: Install twine
73+
run: python -m pip install twine
74+
75+
- name: Check wheel metadata
76+
shell: bash
77+
run: python -m twine check wheelhouse/*.whl

.github/workflows/release.yml

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
name: Release Artifacts
2+
3+
on:
4+
push:
5+
tags:
6+
- "v*"
7+
workflow_dispatch:
8+
9+
jobs:
10+
typecheck:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- uses: actions/checkout@v4
15+
16+
- uses: actions/setup-python@v5
17+
with:
18+
python-version: "3.12"
19+
20+
- uses: astral-sh/setup-uv@v7
21+
with:
22+
enable-cache: true
23+
24+
- name: Sync runtime dependencies
25+
run: uv sync --locked
26+
27+
- name: Run pyright
28+
run: uvx pyright
29+
30+
sdist:
31+
runs-on: ubuntu-latest
32+
needs: typecheck
33+
34+
steps:
35+
- uses: actions/checkout@v4
36+
37+
- uses: actions/setup-python@v5
38+
with:
39+
python-version: "3.12"
40+
41+
- uses: astral-sh/setup-uv@v7
42+
with:
43+
enable-cache: true
44+
45+
- name: Build sdist
46+
run: uv build --sdist --no-sources
47+
48+
- name: Check sdist metadata
49+
run: uvx --from twine twine check dist/*.tar.gz
50+
51+
- name: Smoke test sdist
52+
run: uv run --isolated --no-project --with dist/*.tar.gz tests/smoke_test.py
53+
54+
- name: Upload sdist artifact
55+
uses: actions/upload-artifact@v4
56+
with:
57+
name: rapidobj-sdist
58+
path: dist/*.tar.gz
59+
60+
wheels:
61+
runs-on: ${{ matrix.os }}
62+
needs: typecheck
63+
strategy:
64+
fail-fast: false
65+
matrix:
66+
os:
67+
- ubuntu-latest
68+
- windows-latest
69+
70+
steps:
71+
- uses: actions/checkout@v4
72+
73+
- uses: pypa/cibuildwheel@v3.2.1
74+
with:
75+
output-dir: wheelhouse
76+
77+
- uses: actions/setup-python@v5
78+
with:
79+
python-version: "3.12"
80+
81+
- name: Install twine
82+
run: python -m pip install twine
83+
84+
- name: Check wheel metadata
85+
shell: bash
86+
run: python -m twine check wheelhouse/*.whl
87+
88+
- name: Upload wheel artifacts
89+
uses: actions/upload-artifact@v4
90+
with:
91+
name: rapidobj-wheels-${{ matrix.os }}
92+
path: wheelhouse/*.whl

CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ project(rapidobj LANGUAGES CXX)
44
set(CMAKE_CXX_STANDARD 17)
55
set(CMAKE_CXX_STANDARD_REQUIRED ON)
66

7-
# Find Python and nanobind
8-
find_package(Python 3.12 COMPONENTS Interpreter Development.Module REQUIRED)
7+
# Bind against whichever interpreter the build frontend selected.
8+
find_package(Python COMPONENTS Interpreter Development.Module REQUIRED)
99

1010
# Fetch nanobind
1111
include(FetchContent)

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,14 @@ From source:
1616

1717
```bash
1818
uv sync
19-
uv build
19+
uv build --wheel --python 3.12 --no-sources
2020
python -m pip install dist/rapidobj-0.1.0-cp312-cp312-*.whl
2121
```
2222

23+
For release builds, GitHub Actions is the authoritative wheel pipeline. Pull
24+
requests validate the package, and version tags build Linux and Windows wheels
25+
for CPython 3.12, 3.13, and 3.14.
26+
2327
## Minimal Usage
2428

2529
```python

RELEASE.md

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,46 @@
44

55
Use semantic version tags: `vX.Y.Z`.
66

7-
## Build and Validate
7+
## Local Validation
88

99
1. Clean old artifacts.
1010
- `rm -rf dist/`
11-
2. Build distributions.
12-
- `uv build`
13-
3. Validate metadata and artifacts.
14-
- `uvx --from twine twine check dist/*`
15-
4. Smoke test wheel in a clean environment.
11+
2. Build and validate the source distribution.
12+
- `uv build --sdist --no-sources`
13+
3. Validate sdist metadata.
14+
- `uvx --from twine twine check dist/*.tar.gz`
15+
4. Smoke test the sdist install path.
16+
- `uv run --isolated --no-project --with dist/*.tar.gz tests/smoke_test.py`
17+
5. Optionally validate a local single-interpreter wheel.
18+
- `uv build --wheel --python 3.12 --no-sources`
19+
6. Smoke test wheel in a clean environment.
1620
- Install wheel from `dist/`
1721
- Import `rapidobj`
1822
- Parse a small `.obj` file and assert `result.ok`
1923

24+
## GitHub CI
25+
26+
1. Pull requests run:
27+
- `pyright`
28+
- `sdist` build and smoke test
29+
- Linux and Windows wheel builds for CPython `3.12`, `3.13`, and `3.14`
30+
2. Version tags (`vX.Y.Z`) run the release workflow:
31+
- build the `sdist`
32+
- build Linux and Windows wheel artifacts
33+
- run metadata checks and smoke tests
34+
- upload artifacts to GitHub Actions
35+
2036
## GitHub Source Release
2137

2238
1. Push commit to `main`.
2339
2. Create and push tag.
2440
- `git tag vX.Y.Z`
2541
- `git push origin vX.Y.Z`
26-
3. Create GitHub release from the tag and include changelog notes.
42+
3. Wait for the release workflow to finish and download the generated artifacts if needed.
43+
4. Create GitHub release from the tag and include changelog notes.
2744

2845
## PyPI Publish
2946

30-
1. Upload validated artifacts:
47+
1. Upload validated artifacts from the GitHub release workflow:
3148
- `uvx --from twine twine upload dist/*`
3249
2. Verify package page metadata and install command.

pyproject.toml

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ classifiers = [
1414
"License :: OSI Approved :: MIT License",
1515
"Programming Language :: Python :: 3",
1616
"Programming Language :: Python :: 3.12",
17+
"Programming Language :: Python :: 3.13",
18+
"Programming Language :: Python :: 3.14",
1719
"Programming Language :: C++",
1820
"Topic :: Multimedia :: Graphics :: 3D Modeling",
1921
"Typing :: Typed",
@@ -35,7 +37,7 @@ dev = [
3537
]
3638

3739
[build-system]
38-
requires = ["scikit-build-core>=0.10", "nanobind>=2.4.0"]
40+
requires = ["scikit-build-core>=0.12", "nanobind>=2.4.0"]
3941
build-backend = "scikit_build_core.build"
4042

4143
[tool.scikit-build]
@@ -54,6 +56,7 @@ sdist.include = [
5456
"rapidobj.pyi",
5557
"src/rapidobj.hpp",
5658
"src/rapidobj_ext.cpp",
59+
"tests/smoke_test.py",
5760
]
5861
sdist.exclude = [
5962
".git/*",
@@ -87,3 +90,15 @@ torchvision = [{ index = "pytorch-cu129", marker = "sys_platform == 'linux'" }]
8790
name = "pytorch-cu129"
8891
url = "https://download.pytorch.org/whl/cu129"
8992
explicit = true
93+
94+
[tool.cibuildwheel]
95+
build = "cp312-* cp313-* cp314-*"
96+
skip = "pp* *-musllinux_*"
97+
build-verbosity = 1
98+
test-command = "python {project}/tests/smoke_test.py"
99+
100+
[tool.cibuildwheel.linux]
101+
archs = ["x86_64"]
102+
103+
[tool.cibuildwheel.windows]
104+
archs = ["AMD64"]

pyrightconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
"rapidobj.pyi",
44
"examples",
55
"benchmark.py",
6-
"benchmark_overhead.py"
6+
"benchmark_overhead.py",
7+
"tests/smoke_test.py"
78
],
89
"exclude": [
910
"build",

tests/smoke_test.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"""Minimal wheel smoke test for CI and release validation."""
2+
3+
from __future__ import annotations
4+
5+
from pathlib import Path
6+
import tempfile
7+
8+
from rapidobj import parse_obj
9+
10+
11+
def main() -> None:
12+
with tempfile.TemporaryDirectory() as tmpdir:
13+
obj_path = Path(tmpdir) / "tri.obj"
14+
obj_path.write_text(
15+
"v 0.0 0.0 0.0\n"
16+
"v 1.0 0.0 0.0\n"
17+
"v 0.0 1.0 0.0\n"
18+
"f 1 2 3\n",
19+
encoding="utf-8",
20+
)
21+
22+
result = parse_obj(str(obj_path))
23+
if not result.ok:
24+
raise RuntimeError(result.error_message)
25+
26+
assert result.vertices.shape == (3, 3)
27+
assert result.faces.shape == (1, 3)
28+
29+
30+
if __name__ == "__main__":
31+
main()

0 commit comments

Comments
 (0)