Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: CI

on:
workflow_dispatch:
push:
branches: ["master"]
pull_request:
branches: ["master"]

env:
CARGO_TERM_COLOR: always

jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Build
run: cargo build --verbose --all-features

checks:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- uses: Swatinem/rust-cache@v2
- name: Format
run: cargo fmt -- --check --verbose
- name: Lint
run: cargo clippy --all-targets --all-features -- -D warnings
14 changes: 7 additions & 7 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Release

on:
push:
tags: ['v*']
tags: ["v*"]

env:
CARGO_TERM_COLOR: always
Expand All @@ -14,9 +14,9 @@ jobs:
permissions:
id-token: write
steps:
- uses: actions/checkout@v5
- uses: rust-lang/crates-io-auth-action@v1
id: auth
- run: cargo publish
env:
CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}
- uses: actions/checkout@v5
- uses: rust-lang/crates-io-auth-action@v1
id: auth
- run: cargo publish
env:
CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}
6 changes: 4 additions & 2 deletions coverage/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

This directory contains code coverage reports.

The coverage reports are generated using the [run.ps1](./run.ps1) script. To run the script, you need to install [cargo-llvm-cov](https://crates.io/crates/cargo-llvm-cov) and [cargo-nextest](https://crates.io/crates/cargo-nextest).
The coverage reports are generated using the [run.ps1](./run.ps1) (for Windows) and [run.sh](./run.sh) (for Linux/\*nix) scripts.

To run the script, you need to install [cargo-llvm-cov](https://crates.io/crates/cargo-llvm-cov) and [cargo-nextest](https://crates.io/crates/cargo-nextest).

> [!NOTE]
>
> Because the crate requires GPU support, the coverage report is not run in CI.
> Because the crate requires GPU support, the coverage report is not run in CI.
117 changes: 117 additions & 0 deletions coverage/coverage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
macro_rules! cargo {
($arg:literal $(, $fmt_args:expr),* $(,)?) => {{
let cmd_arg = format!($arg, $($fmt_args),*);
let args = cmd_arg.split_whitespace();

println!("cargo {}", cmd_arg);

let status = std::process::Command::new("cargo")
.args(args)
.status()
.expect("failed to execute process");

assert!(status.success(), "command 'cargo {}' failed", cmd_arg);
}};
}

fn main() {
let exe_path = std::env::current_exe().expect("current exe");

let mut manifest_path = exe_path.parent().expect("exe parent").to_path_buf();
while std::fs::read_dir(&manifest_path)
.expect("read dir")
.find(|entry| entry.as_ref().expect("entry").file_name() == "Cargo.toml")
.is_none()
{
manifest_path = manifest_path.parent().expect("parent").to_path_buf();
}

let coverage_path = manifest_path.join("coverage");
let lcov_path = coverage_path.join("lcov.info");
let lcov_path_str = lcov_path.to_str().expect("lcov path");
let badge_path = coverage_path.join("badge.json");
let model_path = coverage_path.join("model.ply");
let model_path_str = model_path.to_str().expect("model path");

println!("Running coverage...");

cargo!("llvm-cov clean --workspace");

println!("Running 'simple' example");
cargo!("llvm-cov run --example simple --all-features -- -m {model_path_str}");

println!("Running 'multi-model' example");
cargo!(
"llvm-cov run --example multi-model --all-features -- -m {model_path_str} -m {model_path_str}"
);

println!("Running 'selection' example");
cargo!("llvm-cov run --example selection --all-features -- -m {model_path_str}");

println!("Running doctests");
// `--doctests` flag is currently unstable
// cargo!("llvm-cov --no-report --doctests --all-features");
cargo!("test --doc");

println!("Running tests");
cargo!("llvm-cov --no-report nextest --all-features");

println!("Generating coverage report");
cargo!("llvm-cov report --lcov --output-path {lcov_path_str}");

println!("Generating badge");

let lcov = std::fs::read_to_string(&lcov_path).expect("read lcov.info");
let mut total: u64 = 0;
let mut covered: u64 = 0;

for line in lcov.lines() {
if !line.starts_with("DA:") {
continue;
}

let mut parts = line[3..].split(',');
let _line_number = parts.next();
let hits_str = parts.next();

let Some(hits_str) = hits_str else {
continue;
};
let Ok(hits) = hits_str.parse::<u64>() else {
continue;
};

total += 1;
if hits != 0 {
covered += 1;
}
}

let badge_percentage: u64 = if total == 0 {
100
} else {
((covered as f32 / total as f32) * 100.0).round() as u64
};

let badge_color = if badge_percentage >= 80 {
"brightgreen"
} else if badge_percentage >= 50 {
"yellow"
} else {
"red"
};

let badge_json = format!(
r#"
{{
"schemaVersion": 1,
"label": "coverage",
"message": "{badge_percentage}%",
"color": "{badge_color}"
}}
"#
);
std::fs::write(&badge_path, badge_json.trim().to_owned() + "\n").expect("write badge.json");

println!("Done");
}
Loading