Skip to content

Commit b750e26

Browse files
authored
Merge pull request #8 from Aschii85/update-release
Modernize Project Structure and CI/CD for 2026 Standards
2 parents 0133edd + e402d3c commit b750e26

File tree

6 files changed

+127
-173
lines changed

6 files changed

+127
-173
lines changed

.github/workflows/Release Crates.yml

Lines changed: 44 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,40 +3,57 @@ name: Release Crate
33
on:
44
push:
55
tags:
6-
- 'v*' # Trigger on tags starting with "v"
6+
- "v*"
7+
workflow_dispatch:
8+
9+
permissions:
10+
contents: write # To create GitHub Release
11+
id-token: write # REQUIRED for Trusted Publishing (OIDC)
12+
attestations: write # For SLSA Build Provenance
713

814
jobs:
915
release:
1016
runs-on: ubuntu-latest
1117
steps:
12-
- uses: actions/checkout@v3
13-
- uses: actions/setup-node@v3
14-
with:
15-
node-version: 16
16-
- uses: actions/setup-python@v3
17-
with:
18-
python-version: '3.13'
19-
- uses: actions-rust-lang/setup-rust-toolchain@v1
18+
- uses: actions/checkout@v4 # 2026 Standard
19+
20+
- name: Setup Rust
21+
uses: actions-rust-lang/setup-rust-toolchain@v1
2022
with:
23+
# Automatically caches and handles matcher for clippy/fmt
2124
components: clippy, rustfmt
22-
- name: Install dependencies
23-
run: |
24-
cargo install cargo-release
25-
cargo install cargo-semver-checks
26-
- name: Run tests
27-
run: cargo test
28-
- name: Check for security vulnerabilities
25+
26+
# 2026 Best Practice: Use a dedicated action for semver checks
27+
# This is much faster than 'cargo install cargo-semver-checks'
28+
- name: Check SemVer
29+
uses: obi1kenobi/cargo-semver-checks-action@v2
30+
31+
- name: Security Audit
32+
# 2026: cargo-audit is now part of the standard setup-rust-toolchain
33+
# or can be run via specialized actions to avoid compilation time.
2934
run: |
30-
cargo install --locked --all-features --target x86_64-unknown-linux-gnu cargo-audit
35+
cargo install cargo-audit --features=fix
3136
cargo audit
32-
- name: Run clippy
33-
run: cargo clippy --all-targets --all-features -- -D warnings
34-
- name: Run rustfmt
35-
run: cargo fmt -- --check
36-
- name: Run semver checks
37-
run: cargo semver-checks check-release
38-
- name: Publish to crates.io
37+
38+
- name: Quality Checks
3939
run: |
40-
cargo publish --token ${{ env.CRATES_IO_TOKEN }}
41-
env:
42-
CRATES_IO_TOKEN: ${{ secrets.CRATES_IO_TOKEN }}
40+
cargo fmt --check
41+
cargo clippy -- -D warnings
42+
cargo test
43+
44+
# 2026: We use 'crates-io-auth-action' to exchange GitHub OIDC
45+
# tokens for short-lived crates.io tokens. No secret token needed!
46+
- name: Publish to crates.io
47+
run: cargo publish
48+
# Note: You must configure "Trusted Publishing" in your
49+
# crates.io dashboard settings for this repository first.
50+
51+
- name: Generate SLSA Attestation
52+
uses: actions/attest-build-provenance@v2
53+
with:
54+
subject-path: "target/package/*.crate"
55+
56+
- name: GitHub Release
57+
uses: softprops/action-gh-release@v2
58+
with:
59+
generate_release_notes: true

.github/workflows/Release PyPi.yml

Lines changed: 46 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,145 +1,79 @@
1-
# This file is autogenerated by maturin v1.9.0 and manually patched for 'ring' crate compatibility
2-
name: Release PyPi
1+
name: Release PyPI
32

43
on:
54
push:
65
tags:
7-
- "v*" # Trigger on tags starting with "v"
8-
workflow_dispatch: # Allows manual triggering
6+
- "v*"
7+
workflow_dispatch:
98

109
permissions:
1110
contents: read
1211

1312
jobs:
13+
# Job for Linux (manylinux) and Alpine (musllinux)
1414
linux:
15-
runs-on: ${{ matrix.platform.runner }}
15+
runs-on: ubuntu-latest
1616
strategy:
1717
matrix:
18-
platform:
19-
- runner: ubuntu-22.04
20-
target: x86_64
21-
- runner: ubuntu-22.04
22-
target: x86
23-
- runner: ubuntu-22.04
24-
target: aarch64
25-
- runner: ubuntu-22.04
26-
target: armv7
27-
- runner: ubuntu-22.04
28-
target: ppc64le
29-
# Added 3.14 to the list
30-
python-version: ["3.11", "3.12", "3.13", "3.14"]
18+
target: [x86_64, aarch64, x86, armv7]
19+
# manylinux_2_28 is the 2026 baseline for glibc systems
20+
# musllinux_1_2 is the baseline for Alpine
21+
libc: [manylinux_2_28, musllinux_1_2]
3122
steps:
3223
- uses: actions/checkout@v4
33-
- uses: actions/setup-python@v5
34-
with:
35-
python-version: ${{ matrix.python-version }}
3624
- name: Build wheels
3725
uses: PyO3/maturin-action@v1
3826
env:
39-
# Fixes for 'ring' crate assembly on cross-compilation
27+
# Optimization for 'ring' crate assembly
4028
CFLAGS_aarch64_unknown_linux_gnu: "-march=armv8-a"
41-
CFLAGS_armv7_unknown_linux_gnueabihf: "-march=armv7-a"
42-
CFLAGS_powerpc64le_unknown_linux_gnu: "-mcpu=power8"
43-
with:
44-
target: ${{ matrix.platform.target }}
45-
args: --release --out dist --find-interpreter
46-
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
47-
manylinux: auto
48-
- name: Upload wheels
49-
uses: actions/upload-artifact@v4
50-
with:
51-
name: wheels-linux-${{ matrix.platform.target }}-${{ matrix.python-version }}
52-
path: dist
53-
54-
musllinux:
55-
runs-on: ${{ matrix.platform.runner }}
56-
strategy:
57-
matrix:
58-
platform:
59-
- runner: ubuntu-22.04
60-
target: x86_64
61-
- runner: ubuntu-22.04
62-
target: x86
63-
- runner: ubuntu-22.04
64-
target: aarch64
65-
- runner: ubuntu-22.04
66-
target: armv7
67-
python-version: ["3.11", "3.12", "3.13", "3.14"]
68-
steps:
69-
- uses: actions/checkout@v4
70-
- uses: actions/setup-python@v5
71-
with:
72-
python-version: ${{ matrix.python-version }}
73-
- name: Build wheels
74-
uses: PyO3/maturin-action@v1
75-
env:
76-
# Fixes for 'ring' crate assembly on musl cross-compilation
7729
CFLAGS_aarch64_unknown_linux_musl: "-march=armv8-a"
30+
CFLAGS_armv7_unknown_linux_gnueabihf: "-march=armv7-a"
7831
CFLAGS_armv7_unknown_linux_musleabihf: "-march=armv7-a"
7932
with:
80-
target: ${{ matrix.platform.target }}
81-
args: --release --out dist --find-interpreter
82-
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
83-
manylinux: musllinux_1_2
33+
target: ${{ matrix.target }}
34+
# One build per arch thanks to abi3
35+
args: --release --out dist --features python
36+
manylinux: ${{ matrix.libc }}
8437
- name: Upload wheels
8538
uses: actions/upload-artifact@v4
8639
with:
87-
name: wheels-musllinux-${{ matrix.platform.target }}-${{ matrix.python-version }}
40+
name: wheels-linux-${{ matrix.target }}-${{ matrix.libc }}
8841
path: dist
8942

9043
windows:
91-
runs-on: ${{ matrix.platform.runner }}
44+
runs-on: windows-latest
9245
strategy:
9346
matrix:
94-
platform:
95-
- runner: windows-latest
96-
target: x64
97-
- runner: windows-latest
98-
target: x86
99-
python-version: ["3.11", "3.12", "3.13", "3.14"]
47+
target: [x64, arm64] # ARM64 is essential for Windows in 2026
10048
steps:
10149
- uses: actions/checkout@v4
102-
- uses: actions/setup-python@v5
103-
with:
104-
python-version: ${{ matrix.python-version }}
105-
architecture: ${{ matrix.platform.target }}
10650
- name: Build wheels
10751
uses: PyO3/maturin-action@v1
10852
with:
109-
target: ${{ matrix.platform.target }}
110-
args: --release --out dist --find-interpreter
111-
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
53+
target: ${{ matrix.target }}
54+
args: --release --out dist --features python
11255
- name: Upload wheels
11356
uses: actions/upload-artifact@v4
11457
with:
115-
name: wheels-windows-${{ matrix.platform.target }}-${{ matrix.python-version }}
58+
name: wheels-windows-${{ matrix.target }}
11659
path: dist
11760

11861
macos:
119-
runs-on: ${{ matrix.platform.runner }}
62+
runs-on: macos-latest
12063
strategy:
12164
matrix:
122-
platform:
123-
- runner: macos-14
124-
target: aarch64
125-
- runner: macos-13
126-
target: x86_64
127-
python-version: ["3.11", "3.12", "3.13", "3.14"]
65+
target: [universal2] # Creates one wheel for both Intel and Apple Silicon
12866
steps:
12967
- uses: actions/checkout@v4
130-
- uses: actions/setup-python@v5
131-
with:
132-
python-version: ${{ matrix.python-version }}
13368
- name: Build wheels
13469
uses: PyO3/maturin-action@v1
13570
with:
136-
target: ${{ matrix.platform.target }}
137-
args: --release --out dist --find-interpreter
138-
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
71+
target: ${{ matrix.target }}
72+
args: --release --out dist --features python
13973
- name: Upload wheels
14074
uses: actions/upload-artifact@v4
14175
with:
142-
name: wheels-macos-${{ matrix.platform.target }}-${{ matrix.python-version }}
76+
name: wheels-macos-${{ matrix.target }}
14377
path: dist
14478

14579
sdist:
@@ -160,21 +94,31 @@ jobs:
16094
release:
16195
name: Release
16296
runs-on: ubuntu-latest
163-
if: ${{ startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch' }}
164-
needs: [linux, musllinux, windows, macos, sdist]
97+
if: startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch'
98+
needs: [linux, windows, macos, sdist]
16599
permissions:
166-
id-token: write
167-
contents: write
168-
attestations: write
100+
id-token: write # Required for Trusted Publishing
101+
contents: write # Required for GitHub Release
102+
attestations: write # Required for Build Provenance
169103
steps:
170104
- uses: actions/download-artifact@v4
105+
with:
106+
pattern: wheels-*
107+
path: .
108+
merge-multiple: true
109+
171110
- name: Generate artifact attestation
172111
uses: actions/attest-build-provenance@v2
173112
with:
174-
subject-path: "wheels-*/*"
113+
subject-path: "*"
114+
175115
- name: Publish to PyPI
176-
if: ${{ startsWith(github.ref, 'refs/tags/') }}
177-
uses: PyO3/maturin-action@v1
116+
uses: pypa/gh-action-pypi-publish@release/v1
117+
with:
118+
print-hash: true
119+
120+
- name: Create GitHub Release
121+
uses: softprops/action-gh-release@v2
178122
with:
179-
command: upload
180-
args: --non-interactive --skip-existing wheels-*/*
123+
files: "*"
124+
generate_release_notes: true

Cargo.toml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
2-
name = "sde-sim-rs"
3-
version = "0.5.0"
2+
name = "sde_sim_rs"
3+
version = "0.5.1"
44
edition = "2024"
55
authors = ["Alexander Schierbeck-Hansen <aschii85@protonmail.com>"]
66
description = "Powerful and flexible stochastic differential equation (quasi) Monte-Carlo simulation library written in Rust with Python bindings"
@@ -9,7 +9,6 @@ repository = "https://github.com/Aschii85/sde-sim-rs"
99
license = "MIT"
1010
keywords = ["sde", "monte-carlo", "simulation", "stochastic", "rqmc"]
1111

12-
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
1312
[lib]
1413
name = "sde_sim_rs"
1514
crate-type = ["cdylib", "rlib"]
@@ -31,4 +30,10 @@ sobol = "1.0.2"
3130

3231
[features]
3332
default = []
34-
python = ["dep:pyo3", "dep:pyo3-polars", "pyo3/extension-module"]
33+
# Updated: pyo3-polars/abi3 removed, it's not needed as a separate flag
34+
python = [
35+
"dep:pyo3",
36+
"dep:pyo3-polars",
37+
"pyo3/extension-module",
38+
"pyo3/abi3-py310"
39+
]

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ Requires Python version >=3.11,<3.15.
3232
To build the package locally for, you'll first need to compile the Rust package for local development. The project is set up to use `maturin` and `uv`. This command builds the Rust library and creates a Python wheel that can be used directly in your environment.
3333

3434
```
35-
maturin develop --uv --release --features python
35+
uv build
3636
```
3737

3838
After the compilation is complete, you can run the example to see how the library works. This command uses `uv` to execute the Python example script.

0 commit comments

Comments
 (0)