Skip to content

Commit ed64993

Browse files
authored
Merge pull request #66 from graspologic-org/ci-build-adjustments
chore: modernize build toolchain and expand platform support
2 parents f5d88fc + 5d87e39 commit ed64993

20 files changed

Lines changed: 179 additions & 168 deletions

.github/workflows/build.yml

Lines changed: 91 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,21 @@ jobs:
44
codestyle-check:
55
runs-on: "ubuntu-latest"
66
steps:
7-
- uses: actions/checkout@v4
7+
- uses: actions/checkout@v6
88
- name: Check format
99
run: |
1010
cargo fmt -- --check
11+
- name: Clippy
12+
run: |
13+
cargo clippy --all-targets -- -D warnings
1114
version:
1215
runs-on: "ubuntu-latest"
1316
steps:
14-
- uses: actions/checkout@v4
15-
- name: Set up Python 3.12
16-
uses: actions/setup-python@v5
17+
- uses: actions/checkout@v6
18+
- name: Set up Python
19+
uses: actions/setup-python@v6
1720
with:
18-
python-version: 3.12
21+
python-version: "3.14"
1922
- name: Materialize build number
2023
run: |
2124
pip install -U pip
@@ -31,17 +34,49 @@ jobs:
3134
path: version.txt
3235
build:
3336
needs: ['codestyle-check', 'version']
34-
runs-on: ${{ matrix.os }}
37+
runs-on: ${{ matrix.runner }}
3538
strategy:
3639
fail-fast: false
3740
matrix:
38-
os: ["ubuntu-latest", "windows-latest", "macos-latest", "ubuntu-24.04-arm"]
41+
include:
42+
- runner: ubuntu-latest
43+
target: x64
44+
manylinux: "2014"
45+
args: -m packages/pyo3/Cargo.toml --release --sdist
46+
artifact_name: dist-linux-x64
47+
- runner: ubuntu-24.04-arm
48+
target: aarch64
49+
manylinux: "2014"
50+
args: -m packages/pyo3/Cargo.toml --release
51+
artifact_name: dist-linux-aarch64
52+
- runner: ubuntu-latest
53+
target: x64
54+
manylinux: musllinux_1_2
55+
args: -m packages/pyo3/Cargo.toml --release
56+
artifact_name: dist-musllinux-x64
57+
- runner: ubuntu-24.04-arm
58+
target: aarch64
59+
manylinux: musllinux_1_2
60+
args: -m packages/pyo3/Cargo.toml --release
61+
artifact_name: dist-musllinux-aarch64
62+
- runner: windows-latest
63+
target: x64
64+
args: -m packages/pyo3/Cargo.toml --release
65+
artifact_name: dist-windows-x64
66+
- runner: windows-11-arm
67+
target: aarch64-pc-windows-msvc
68+
args: -m packages/pyo3/Cargo.toml --release
69+
artifact_name: dist-windows-aarch64
70+
- runner: macos-latest
71+
target: universal2-apple-darwin
72+
args: -m packages/pyo3/Cargo.toml --release
73+
artifact_name: dist-macos-universal2
3974
steps:
40-
- uses: actions/checkout@v4
41-
- name: Set up Python 3.12
42-
uses: actions/setup-python@v5
75+
- uses: actions/checkout@v6
76+
- name: Set up Python
77+
uses: actions/setup-python@v6
4378
with:
44-
python-version: 3.12
79+
python-version: "3.14"
4580
- uses: actions/download-artifact@v4
4681
with:
4782
name: cargo-toml
@@ -54,50 +89,25 @@ jobs:
5489
run: |
5590
cargo test --manifest-path packages/network_partitions/Cargo.toml
5691
57-
# the following are the actual maturin build actions. each one is different per OS, so rather than copy/paste
58-
# the same steps except for the build, we conditionally do one of the builds depending on the os in question
59-
# note that windows and mac don't do sdists, but ubuntu does; this is just because we don't need to repeat
60-
# ourselves or overwrite the .tar.gz sdist.
61-
62-
- uses: PyO3/maturin-action@v1
63-
if: ${{ matrix.os == 'windows-latest' }}
64-
name: Maturin Build for Windows
65-
with:
66-
maturin-version: 1.4.0
67-
command: build
68-
target: x64
69-
args: -m packages/pyo3/Cargo.toml --release -i ${{env.pythonLocation}}\python.exe
70-
7192
- uses: PyO3/maturin-action@v1
72-
if: ${{ matrix.os == 'macos-latest' }}
73-
name: Maturin Build for MacOS
93+
if: ${{ !startsWith(matrix.runner, 'windows') }}
94+
name: Maturin Build
7495
with:
75-
maturin-version: 1.4.0
7696
command: build
77-
target: universal2-apple-darwin
78-
args: -m packages/pyo3/Cargo.toml --release
97+
target: ${{ matrix.target }}
98+
args: ${{ matrix.args }}
99+
manylinux: ${{ matrix.manylinux || 'auto' }}
79100

80101
- uses: PyO3/maturin-action@v1
81-
if: ${{ matrix.os == 'ubuntu-latest' }}
82-
name: Maturin Build for Linux
102+
if: ${{ startsWith(matrix.runner, 'windows') }}
103+
name: Maturin Build (Windows)
83104
with:
84-
maturin-version: 1.4.0
85105
command: build
86-
target: x64
87-
args: -m packages/pyo3/Cargo.toml --release --sdist
88-
manylinux: 2014
89-
90-
- uses: PyO3/maturin-action@v1
91-
if: ${{ matrix.os == 'ubuntu-24.04-arm' }}
92-
name: Maturin Build for Linux
93-
with:
94-
maturin-version: 1.4.0
95-
command: build
96-
target: aarch64
97-
args: -m packages/pyo3/Cargo.toml --release --sdist
98-
manylinux: 2014
106+
target: ${{ matrix.target }}
107+
args: ${{ matrix.args }} -i ${{env.pythonLocation}}\python.exe
99108

100109
- name: Python Unittests
110+
if: ${{ !matrix.manylinux || matrix.manylinux != 'musllinux_1_2' }}
101111
run: |
102112
cd packages/pyo3
103113
pip install ../../target/wheels/*.whl
@@ -106,35 +116,49 @@ jobs:
106116

107117
- uses: actions/upload-artifact@v4
108118
with:
109-
name: dist-${{ matrix.os }}
119+
name: ${{ matrix.artifact_name }}
110120
path: |
111121
target/wheels/*.whl
112122
target/wheels/*.tar.gz
113123
publish:
114124
runs-on: ubuntu-latest
115125
needs: 'build'
116126
if: github.ref=='refs/heads/main' || github.ref=='refs/heads/dev'
127+
permissions:
128+
contents: write
117129
steps:
118-
- uses: actions/checkout@v4
119-
- name: Set up Python 3.12
120-
uses: actions/setup-python@v2
130+
- uses: actions/checkout@v6
131+
- name: Set up Python
132+
uses: actions/setup-python@v6
121133
with:
122-
python-version: 3.12
134+
python-version: "3.14"
123135
- uses: actions/download-artifact@v4
124136
with:
125-
name: dist-ubuntu-latest
137+
name: dist-linux-x64
126138
path: dist/
127139
- uses: actions/download-artifact@v4
128140
with:
129-
name: dist-windows-latest
141+
name: dist-linux-aarch64
130142
path: dist/
131143
- uses: actions/download-artifact@v4
132144
with:
133-
name: dist-macos-latest
145+
name: dist-musllinux-x64
134146
path: dist/
135147
- uses: actions/download-artifact@v4
136148
with:
137-
name: dist-ubuntu-24.04-arm
149+
name: dist-musllinux-aarch64
150+
path: dist/
151+
- uses: actions/download-artifact@v4
152+
with:
153+
name: dist-windows-x64
154+
path: dist/
155+
- uses: actions/download-artifact@v4
156+
with:
157+
name: dist-windows-aarch64
158+
path: dist/
159+
- uses: actions/download-artifact@v4
160+
with:
161+
name: dist-macos-universal2
138162
path: dist/
139163
- name: Generate SHA256 files for each wheel
140164
run: |
@@ -160,12 +184,17 @@ jobs:
160184
run: |
161185
twine upload dist/*
162186
- name: Create Github Release
163-
uses: actions/create-release@v1
164187
env:
165-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
166-
with:
167-
tag_name: ${{ env.GRASPOLOGIC_VERSION }}
168-
release_name: graspologic-native-${{ env.GRASPOLOGIC_VERSION }}
169-
body_path: "checksums.txt"
170-
prerelease: github.ref=='refs/heads/dev'
188+
GH_TOKEN: ${{ github.token }}
189+
run: |
190+
PRERELEASE_FLAG=""
191+
if [ "${{ github.ref }}" = "refs/heads/dev" ]; then
192+
PRERELEASE_FLAG="--prerelease"
193+
fi
194+
gh release create "$GRASPOLOGIC_VERSION" \
195+
--title "graspologic-native-${GRASPOLOGIC_VERSION}" \
196+
--notes-file checksums.txt \
197+
$PRERELEASE_FLAG \
198+
dist/*.whl \
199+
dist/*.tar.gz
171200

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
[workspace]
22
members = ["packages/network_partitions", "packages/cli", "packages/pyo3"]
3+
resolver = "3"
34

45
[profile.release]
56
opt-level = 3

packages/cli/Cargo.toml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
[package]
22
name = "cli"
3-
version = "0.1.1"
3+
version = "0.2.0"
44
authors = ["Dax Pryce <daxpryce@microsoft.com>"]
5-
edition = "2018"
5+
edition = "2024"
66
license = "MIT"
77
description = "CLI Runner for the topologic associated crates (network_partitions and eventually network_automatic_layouts)"
88

99
[dependencies]
10-
clap = "4.5"
11-
rand = "0.8"
12-
rand_xorshift = "0.3"
10+
clap = "4"
11+
rand = "0.10"
1312
network_partitions={path = "../network_partitions"}

packages/cli/src/leiden.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use network_partitions::network::prelude::*;
88
use network_partitions::quality;
99

1010
use rand::SeedableRng;
11-
use rand_xorshift::XorShiftRng;
11+
use rand::rngs::SmallRng;
1212

1313
use std::fs::File;
1414
use std::io::prelude::*;
@@ -44,12 +44,12 @@ pub fn leiden(
4444

4545
let loaded_file_instant: Instant = Instant::now();
4646

47-
let mut rng: XorShiftRng = match seed {
47+
let mut rng: SmallRng = match seed {
4848
Some(seed) => {
4949
println!("Using {} for PRNG seed", seed as u64);
50-
XorShiftRng::seed_from_u64(seed as u64)
50+
SmallRng::seed_from_u64(seed as u64)
5151
}
52-
None => XorShiftRng::from_entropy(),
52+
None => SmallRng::from_rng(&mut rand::rng()),
5353
};
5454

5555
let result: Result<(bool, Clustering), CoreError> = leiden_internal(
Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
[package]
22
name = "network_partitions"
3-
version = "0.1.0"
3+
version = "0.2.0"
44
authors = ["Dax Pryce <daxpryce@microsoft.com>"]
5-
edition = "2018"
5+
edition = "2024"
66
license = "MIT"
77
description = "Leiden community detection as per https://arxiv.org/abs/1810.08473"
88

99
[dependencies]
10-
rand = "0.8"
11-
12-
[dev-dependencies]
13-
rand_xorshift = "0.3"
14-
10+
rand = "0.10"

packages/network_partitions/src/leiden/full_network_clustering.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,11 +257,11 @@ mod tests {
257257
use crate::network::{Edge, LabeledNetwork};
258258
use crate::resolution;
259259
use rand::SeedableRng;
260-
use rand_xorshift::XorShiftRng;
260+
use rand::rngs::SmallRng;
261261

262262
#[test]
263263
fn test_improve_initial_clustering() {
264-
let mut rng: XorShiftRng = XorShiftRng::seed_from_u64(1234);
264+
let mut rng: SmallRng = SmallRng::seed_from_u64(1234);
265265

266266
// generate same graph as in java, done via Network object not InternalNetwork, then
267267
// generate a InternalNetwork from it

packages/network_partitions/src/leiden/full_network_work_queue.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
use crate::errors::CoreError;
55
use std::collections::VecDeque;
66

7-
use rand::Rng;
7+
use rand::{Rng, RngExt};
88

99
/// The FullNetworkWorkQueue is a composite class of a circular work queue and a vec of bools indicating
1010
/// when a node should be treated as stable
@@ -62,7 +62,7 @@ impl FullNetworkWorkQueue {
6262
let mut stable: Vec<bool> = Vec::with_capacity(len);
6363
for i in 0..len {
6464
stable.push(false);
65-
let random_index: usize = rng.gen_range(0..len);
65+
let random_index: usize = rng.random_range(0..len);
6666
permutation.swap(i, random_index);
6767
}
6868
let work_queue: VecDeque<usize> = VecDeque::from(permutation);
@@ -110,12 +110,12 @@ impl FullNetworkWorkQueue {
110110
mod tests {
111111
use super::*;
112112
use rand::SeedableRng;
113-
use rand_xorshift::XorShiftRng;
113+
use rand::rngs::SmallRng;
114114

115115
#[test]
116116
fn test_determinism() {
117-
let mut rng1: XorShiftRng = XorShiftRng::seed_from_u64(1234);
118-
let mut rng2: XorShiftRng = XorShiftRng::seed_from_u64(1234);
117+
let mut rng1: SmallRng = SmallRng::seed_from_u64(1234);
118+
let mut rng2: SmallRng = SmallRng::seed_from_u64(1234);
119119
let order_1: FullNetworkWorkQueue =
120120
FullNetworkWorkQueue::items_in_random_order(100000, &mut rng1);
121121
let order_2: FullNetworkWorkQueue =

packages/network_partitions/src/leiden/leiden_clustering.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// Licensed under the MIT license.
33

44
use std::collections::{HashMap, HashSet};
5-
use std::iter;
65

76
use rand::Rng;
87

@@ -198,8 +197,10 @@ fn initial_clustering_for_induced(
198197
num_nodes_per_cluster_induced_network.iter().enumerate()
199198
{
200199
// fill num_nodes_per_induced_cluster_index into positions from clusters_induced_network_index to clusters_induced_network_index + num_nodes_per_cluster_reduced_network[num_nodes_per_induced_cluster_index]
201-
clusters_induced_network
202-
.extend(iter::repeat(num_nodes_per_induced_cluster_index).take(*repetitions));
200+
clusters_induced_network.extend(std::iter::repeat_n(
201+
num_nodes_per_induced_cluster_index,
202+
*repetitions,
203+
));
203204
}
204205
let next_cluster_id: usize = match clusters_induced_network.last() {
205206
Some(largest_cluster) => *largest_cluster + 1,
@@ -274,7 +275,7 @@ mod tests {
274275
("g".into(), "c".into(), 3.0),
275276
("h".into(), "d".into(), 11.0),
276277
];
277-
return edges;
278+
edges
278279
}
279280

280281
#[test]
@@ -308,7 +309,7 @@ mod tests {
308309
.expect("Updating this known cluster for h should work");
309310
clustering.remove_empty_clusters();
310311
assert_eq!(clustering[a_compact], clustering[h_compact]);
311-
guarantee_clustering_sanity(&compact_network, &mut clustering)
312+
guarantee_clustering_sanity(compact_network, &mut clustering)
312313
.expect("guarantee clustering sanity should not throw an error");
313314
assert_ne!(clustering[a_compact], clustering[h_compact]);
314315
let isolate_clusters: Vec<ClusterId> = vec![clustering[a_compact], clustering[h_compact]];

packages/network_partitions/src/leiden/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT license.
33

4-
pub use self::hierarchical::{hierarchical_leiden, HierarchicalCluster};
4+
pub use self::hierarchical::{HierarchicalCluster, hierarchical_leiden};
55
pub use self::leiden_clustering::leiden;
66

77
mod full_network_clustering;

0 commit comments

Comments
 (0)