Skip to content

Commit 690daee

Browse files
authored
feat: ✨ Add CI workflow configuration for cross-platform testing and coverage (#25)
1 parent e0781b6 commit 690daee

4 files changed

Lines changed: 189 additions & 24 deletions

File tree

.github/workflows/ci.yml

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
2+
3+
name: CI
4+
5+
permissions:
6+
contents: read
7+
8+
on:
9+
push:
10+
branches: [main]
11+
pull_request:
12+
branches: [main]
13+
schedule:
14+
- cron: "0 0 * * *"
15+
16+
env:
17+
CARGO_TERM_COLOR: always
18+
19+
jobs:
20+
# Cross-platform tests (default features only - no video/ffmpeg required)
21+
test:
22+
name: test / ${{ matrix.os }}
23+
runs-on: ${{ matrix.os }}
24+
strategy:
25+
fail-fast: false
26+
matrix:
27+
os: [ubuntu-latest, macos-latest, windows-latest]
28+
29+
steps:
30+
- uses: actions/checkout@v4
31+
32+
- name: Set up Rust
33+
uses: dtolnay/rust-toolchain@stable
34+
35+
- name: Cache build artifacts
36+
uses: Swatinem/rust-cache@v2
37+
38+
- name: Format
39+
run: cargo fmt --all -- --check
40+
41+
- name: Clippy (annotate feature)
42+
run: cargo clippy --all-targets --no-default-features --features annotate -- -D warnings
43+
44+
- name: Tests (annotate feature)
45+
run: cargo test --no-default-features --features annotate
46+
47+
# Video feature tests (requires ffmpeg)
48+
test-video:
49+
name: test / linux / ffmpeg ${{ matrix.ffmpeg_version }}
50+
runs-on: ubuntu-latest
51+
container: jrottenberg/ffmpeg:${{ matrix.ffmpeg_version }}-ubuntu
52+
53+
strategy:
54+
matrix:
55+
ffmpeg_version: ["7.1"]
56+
fail-fast: false
57+
58+
steps:
59+
- name: Checkout
60+
uses: actions/checkout@v4
61+
62+
- name: Install dependencies
63+
run: |
64+
DEBIAN_FRONTEND=noninteractive apt-get update
65+
DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential ca-certificates clang curl pkg-config libssl-dev
66+
67+
- name: Setup Rust
68+
uses: dtolnay/rust-toolchain@stable
69+
with:
70+
components: rustfmt, clippy
71+
72+
- name: Cache build artifacts
73+
uses: Swatinem/rust-cache@v2
74+
75+
- name: Clippy (annotate + video)
76+
run: cargo clippy --all --features annotate,video -- -D warnings
77+
78+
- name: Tests (annotate + video)
79+
run: cargo test --all --features annotate,video
80+
81+
# macOS video build test
82+
build-macos-video:
83+
name: build / macos / ffmpeg 7
84+
runs-on: macos-latest
85+
86+
steps:
87+
- uses: actions/checkout@v4
88+
89+
- name: Install dependencies
90+
run: brew install ffmpeg@7 pkg-config
91+
92+
- name: Setup Rust
93+
uses: dtolnay/rust-toolchain@stable
94+
95+
- name: Cache build artifacts
96+
uses: Swatinem/rust-cache@v2
97+
98+
- name: Build (annotate + video features)
99+
run: cargo build --features annotate,video
100+
env:
101+
LDFLAGS: "-L/opt/homebrew/opt/ffmpeg@7/lib"
102+
CPPFLAGS: "-I/opt/homebrew/opt/ffmpeg@7/include"
103+
PKG_CONFIG_PATH: "/opt/homebrew/opt/ffmpeg@7/lib/pkgconfig"
104+
105+
# Windows video build test
106+
build-windows-video:
107+
name: build / windows / ffmpeg 7.1
108+
runs-on: windows-latest
109+
110+
env:
111+
FFMPEG_DOWNLOAD_URL: https://www.gyan.dev/ffmpeg/builds/packages/ffmpeg-7.1.1-full_build-shared.7z
112+
113+
steps:
114+
- uses: actions/checkout@v4
115+
116+
- name: Install dependencies
117+
run: |
118+
$VCINSTALLDIR = $(& "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" -latest -property installationPath)
119+
Add-Content $env:GITHUB_ENV "LIBCLANG_PATH=${VCINSTALLDIR}\VC\Tools\LLVM\x64\bin"
120+
Invoke-WebRequest "${env:FFMPEG_DOWNLOAD_URL}" -OutFile ffmpeg-7.1.1-full_build-shared.7z
121+
7z x ffmpeg-7.1.1-full_build-shared.7z
122+
mkdir ffmpeg
123+
mv ffmpeg-*/* ffmpeg/
124+
Add-Content $env:GITHUB_ENV "FFMPEG_DIR=${pwd}\ffmpeg"
125+
Add-Content $env:GITHUB_PATH "${pwd}\ffmpeg\bin"
126+
127+
- name: Setup Rust
128+
uses: dtolnay/rust-toolchain@stable
129+
130+
- name: Cache build artifacts
131+
uses: Swatinem/rust-cache@v2
132+
133+
- name: Build (annotate + video features)
134+
run: cargo build --features annotate,video
135+
136+
# Code coverage (runs on macOS with ffmpeg for full feature coverage)
137+
coverage:
138+
name: coverage
139+
runs-on: macos-latest
140+
needs: [test, test-video]
141+
142+
steps:
143+
- uses: actions/checkout@v4
144+
145+
- name: Install dependencies
146+
run: brew install ffmpeg@7 pkg-config
147+
148+
- name: Set up Rust
149+
uses: dtolnay/rust-toolchain@nightly
150+
151+
- name: Cache build artifacts
152+
uses: Swatinem/rust-cache@v2
153+
154+
- name: Install cargo-llvm-cov
155+
uses: taiki-e/install-action@v2
156+
with:
157+
tool: cargo-llvm-cov
158+
159+
- name: Coverage
160+
run: cargo llvm-cov --features annotate,video --workspace --lcov --output-path lcov.info
161+
env:
162+
LDFLAGS: "-L/opt/homebrew/opt/ffmpeg@7/lib"
163+
CPPFLAGS: "-I/opt/homebrew/opt/ffmpeg@7/include"
164+
PKG_CONFIG_PATH: "/opt/homebrew/opt/ffmpeg@7/lib/pkgconfig"
165+
166+
- name: Upload coverage to Codecov
167+
uses: codecov/codecov-action@v5
168+
with:
169+
files: ./lcov.info
170+
token: ${{ secrets.CODECOV_TOKEN }}
171+
flags: template_coverage

Cargo.toml

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -118,27 +118,7 @@ nvidia = ["cuda", "tensorrt"]
118118
amd = ["rocm", "migraphx"]
119119
intel = ["openvino", "onednn"]
120120
mobile = ["nnapi", "coreml", "qnn"]
121-
all = [
122-
"cuda",
123-
"tensorrt",
124-
"rocm",
125-
"openvino",
126-
"onednn",
127-
"directml",
128-
"nnapi",
129-
"coreml",
130-
"xnnpack",
131-
"acl",
132-
"armnn",
133-
"tvm",
134-
"migraphx",
135-
"rknpu",
136-
"vitis",
137-
"cann",
138-
"qnn",
139-
"webgpu",
140-
"azure",
141-
]
121+
all = ["annotate", "video"]
142122

143123
[dev-dependencies]
144124
# Testing dependencies

src/download.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@ mod tests {
397397
let result = try_download_model("unknown_model.onnx");
398398
assert!(result.is_err());
399399
let err = result.unwrap_err().to_string();
400-
assert!(err.contains("Auto-download is only supported"));
400+
assert!(err.contains("Auto-download is supported for"));
401401
}
402402

403403
#[test]

src/main.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ fn run_prediction(args: &[String]) {
7575
let mut imgsz: Option<usize> = None;
7676
let mut save = false;
7777
let mut half = false;
78+
#[cfg(feature = "visualize")]
7879
let mut show = false;
7980

8081
let mut i = 0;
@@ -125,7 +126,16 @@ fn run_prediction(args: &[String]) {
125126
i += 1;
126127
}
127128
"--show" => {
128-
show = true;
129+
#[cfg(feature = "visualize")]
130+
{
131+
show = true;
132+
}
133+
#[cfg(not(feature = "visualize"))]
134+
{
135+
eprintln!(
136+
"WARNING ⚠️ --show requires the 'visualize' feature. Compile with --features visualize to enable display."
137+
);
138+
}
129139
i += 1;
130140
}
131141
"--imgsz" => {
@@ -262,6 +272,7 @@ fn run_prediction(args: &[String]) {
262272
#[cfg(feature = "visualize")]
263273
let mut viewer: Option<Viewer> = None;
264274

275+
#[cfg(feature = "visualize")]
265276
let mut frame_count = 0;
266277
for item in source_iter {
267278
let (img, meta) = match item {
@@ -388,7 +399,10 @@ fn run_prediction(args: &[String]) {
388399

389400
all_results.push((image_path.clone(), result));
390401
}
391-
frame_count += 1;
402+
#[cfg(feature = "visualize")]
403+
{
404+
frame_count += 1;
405+
}
392406
}
393407

394408
// Print speed summary with inference tensor shape (after letterboxing)

0 commit comments

Comments
 (0)