Skip to content

Commit d57b105

Browse files
authored
Merge pull request #3 from Eyevinn/fix/ci-trunk-build
Fix CI: Make build.rs gracefully handle missing trunk
2 parents 254ca4b + a5cff03 commit d57b105

7 files changed

Lines changed: 154 additions & 38 deletions

File tree

.dockerignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,11 @@ scripts/
5151

5252
# Test data
5353
test-data/
54+
55+
# Core dumps and debug files
56+
core-dumps/
57+
*.core
58+
gst-debug.log
59+
60+
# Test and development scripts
61+
*.sh

.github/workflows/ci.yml

Lines changed: 82 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ env:
1111
RUST_BACKTRACE: 1
1212
# Trunk version for caching
1313
TRUNK_VERSION: "0.21.5"
14+
# Disable incremental compilation to avoid deadlocks
15+
CARGO_INCREMENTAL: 0
16+
# Limit parallel cargo jobs to avoid deadlocks
17+
CARGO_BUILD_JOBS: 2
1418

1519
jobs:
1620
fmt:
@@ -36,6 +40,7 @@ jobs:
3640
clippy:
3741
name: Clippy (Backend & MCP)
3842
runs-on: ubuntu-latest
43+
timeout-minutes: 15
3944
steps:
4045
- uses: actions/checkout@v4
4146

@@ -86,6 +91,7 @@ jobs:
8691
test:
8792
name: Test Suite
8893
runs-on: ubuntu-latest
94+
timeout-minutes: 15
8995
steps:
9096
- uses: actions/checkout@v4
9197

@@ -110,8 +116,8 @@ jobs:
110116
- name: Run tests on MCP server
111117
run: cargo test --package strom-mcp-server --all-features
112118

113-
build:
114-
name: Build (Backend + Frontend + MCP)
119+
build-frontend:
120+
name: Build Frontend (WASM)
115121
runs-on: ubuntu-latest
116122
steps:
117123
- uses: actions/checkout@v4
@@ -121,12 +127,6 @@ jobs:
121127
with:
122128
targets: wasm32-unknown-unknown
123129

124-
- name: Cache apt packages
125-
uses: awalsh128/cache-apt-pkgs-action@v1
126-
with:
127-
packages: libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libgstreamer-plugins-bad1.0-dev gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-tools
128-
version: 1.1
129-
130130
- name: Cache trunk binary
131131
id: cache-trunk
132132
uses: actions/cache@v4
@@ -142,17 +142,83 @@ jobs:
142142
- name: Cache Rust dependencies
143143
uses: Swatinem/rust-cache@v2
144144
with:
145-
shared-key: build
145+
shared-key: frontend-wasm
146146
cache-on-failure: true
147-
# Cache trunk build artifacts
148-
cache-directories: |
149-
frontend/dist
150147

151148
- name: Build frontend
152149
run: |
153150
cd frontend
154151
trunk build --release
155152
153+
- name: Upload frontend dist
154+
uses: actions/upload-artifact@v4
155+
with:
156+
name: frontend-dist
157+
path: backend/dist
158+
retention-days: 1
159+
160+
build:
161+
name: Build ${{ matrix.platform }}
162+
needs: build-frontend
163+
runs-on: ${{ matrix.os }}
164+
timeout-minutes: 30
165+
strategy:
166+
fail-fast: false
167+
matrix:
168+
include:
169+
- os: ubuntu-latest
170+
platform: linux
171+
binary_ext: ""
172+
- os: windows-latest
173+
platform: windows
174+
binary_ext: ".exe"
175+
- os: macos-latest
176+
platform: macos
177+
binary_ext: ""
178+
steps:
179+
- uses: actions/checkout@v4
180+
181+
- name: Install Rust stable with WASM target
182+
uses: dtolnay/rust-toolchain@stable
183+
with:
184+
targets: wasm32-unknown-unknown
185+
186+
# Linux: Install GStreamer via apt
187+
- name: Cache apt packages (Linux)
188+
if: matrix.platform == 'linux'
189+
uses: awalsh128/cache-apt-pkgs-action@v1
190+
with:
191+
packages: libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libgstreamer-plugins-bad1.0-dev gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-tools
192+
version: 1.1
193+
194+
# Windows: Install GStreamer and pkg-config via Chocolatey
195+
- name: Install GStreamer (Windows)
196+
if: matrix.platform == 'windows'
197+
run: |
198+
choco install pkgconfiglite gstreamer gstreamer-devel --yes --no-progress
199+
echo "GSTREAMER_1_0_ROOT_MSVC_X86_64=D:\gstreamer\1.0\msvc_x86_64\" >> $env:GITHUB_ENV
200+
echo "D:\gstreamer\1.0\msvc_x86_64\bin" >> $env:GITHUB_PATH
201+
echo "PKG_CONFIG_PATH=D:\gstreamer\1.0\msvc_x86_64\lib\pkgconfig" >> $env:GITHUB_ENV
202+
203+
# macOS: Install GStreamer via Homebrew
204+
- name: Install GStreamer (macOS)
205+
if: matrix.platform == 'macos'
206+
run: |
207+
brew install gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-libav
208+
209+
# Download the pre-built frontend from the frontend build job
210+
- name: Download frontend dist
211+
uses: actions/download-artifact@v4
212+
with:
213+
name: frontend-dist
214+
path: backend/dist
215+
216+
- name: Cache Rust dependencies
217+
uses: Swatinem/rust-cache@v2
218+
with:
219+
shared-key: build-${{ matrix.platform }}
220+
cache-on-failure: true
221+
156222
- name: Build backend (with embedded frontend)
157223
run: cargo build --release --package strom-backend
158224

@@ -162,13 +228,13 @@ jobs:
162228
- name: Upload backend binary
163229
uses: actions/upload-artifact@v4
164230
with:
165-
name: strom-backend
166-
path: target/release/strom-backend
231+
name: strom-backend-${{ matrix.platform }}
232+
path: target/release/strom-backend${{ matrix.binary_ext }}
167233
retention-days: 7
168234

169235
- name: Upload MCP server binary
170236
uses: actions/upload-artifact@v4
171237
with:
172-
name: strom-mcp-server
173-
path: target/release/strom-mcp-server
238+
name: strom-mcp-server-${{ matrix.platform }}
239+
path: target/release/strom-mcp-server${{ matrix.binary_ext }}
174240
retention-days: 7

.github/workflows/docker-publish.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,7 @@ jobs:
4848
labels: ${{ steps.meta.outputs.labels }}
4949
cache-from: type=gha
5050
cache-to: type=gha,mode=max
51-
platforms: linux/amd64
51+
platforms: linux/amd64,linux/arm64
52+
# Use build-time annotations for better metadata
53+
provenance: true
54+
sbom: true

Dockerfile

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,11 @@ RUN cargo chef prepare --recipe-path recipe.json
1919
FROM chef AS builder
2020
WORKDIR /app
2121

22-
# Install GStreamer development dependencies
22+
# Install GStreamer development dependencies (including WebRTC plugin)
2323
RUN apt-get update && apt-get install -y \
2424
libgstreamer1.0-dev \
2525
libgstreamer-plugins-base1.0-dev \
26+
libgstreamer-plugins-bad1.0-dev \
2627
gstreamer1.0-plugins-base \
2728
gstreamer1.0-plugins-good \
2829
gstreamer1.0-plugins-bad \
@@ -31,8 +32,8 @@ RUN apt-get update && apt-get install -y \
3132
gstreamer1.0-tools \
3233
&& rm -rf /var/lib/apt/lists/*
3334

34-
# Install trunk for building the WASM frontend from binary release
35-
RUN curl -L https://github.com/trunk-rs/trunk/releases/download/v0.20.3/trunk-x86_64-unknown-linux-gnu.tar.gz | tar -xz -C /usr/local/bin
35+
# Install trunk for building the WASM frontend from binary release (match CI version)
36+
RUN curl -L https://github.com/trunk-rs/trunk/releases/download/v0.21.5/trunk-x86_64-unknown-linux-gnu.tar.gz | tar -xz -C /usr/local/bin
3637

3738
# Add WASM target for frontend compilation
3839
RUN rustup target add wasm32-unknown-unknown

backend/build.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,28 @@ fn is_dir_empty(dir: &Path) -> Result<bool, std::io::Error> {
109109

110110
/// Build the frontend using trunk
111111
fn build_frontend(frontend_dir: &Path) {
112+
// Check if trunk is available
113+
let trunk_check = Command::new("trunk").arg("--version").output();
114+
115+
if trunk_check.is_err() {
116+
println!("cargo:warning=trunk not found - skipping frontend build");
117+
println!("cargo:warning=Install trunk with: cargo install trunk");
118+
println!("cargo:warning=Backend will compile without embedded frontend");
119+
120+
// Create empty dist directory with placeholder so RustEmbed doesn't fail
121+
let dist_dir = PathBuf::from("dist");
122+
if !dist_dir.exists() {
123+
fs::create_dir(&dist_dir).expect("Failed to create dist directory");
124+
}
125+
fs::write(
126+
dist_dir.join(".placeholder"),
127+
"Frontend not built - trunk not available during compilation",
128+
)
129+
.expect("Failed to create placeholder file");
130+
131+
return;
132+
}
133+
112134
let status = Command::new("trunk")
113135
.arg("build")
114136
.arg("--release")

backend/src/gst/discovery.rs

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -419,8 +419,12 @@ impl ElementDiscovery {
419419
(PropertyType::Int { min, max }, default)
420420
} else if let Some(param_spec) = pspec.downcast_ref::<glib::ParamSpecLong>()
421421
{
422-
let min = param_spec.minimum();
423-
let max = param_spec.maximum();
422+
// Cast glong to i64 for cross-platform compatibility
423+
// glong is i32 on Windows but i64 on Linux
424+
#[allow(clippy::unnecessary_cast)]
425+
let min = param_spec.minimum() as i64;
426+
#[allow(clippy::unnecessary_cast)]
427+
let max = param_spec.maximum() as i64;
424428
let default =
425429
std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
426430
pad.property::<i64>(&name)
@@ -446,8 +450,12 @@ impl ElementDiscovery {
446450
} else if let Some(param_spec) =
447451
pspec.downcast_ref::<glib::ParamSpecULong>()
448452
{
449-
let min = param_spec.minimum();
450-
let max = param_spec.maximum();
453+
// Cast gulong to u64 for cross-platform compatibility
454+
// gulong is u32 on Windows but u64 on Linux
455+
#[allow(clippy::unnecessary_cast)]
456+
let min = param_spec.minimum() as u64;
457+
#[allow(clippy::unnecessary_cast)]
458+
let max = param_spec.maximum() as u64;
451459
let default =
452460
std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
453461
pad.property::<u64>(&name)
@@ -824,8 +832,12 @@ impl ElementDiscovery {
824832
(PropertyType::Int { min, max }, default)
825833
} else if let Some(param_spec) = pspec.downcast_ref::<glib::ParamSpecLong>()
826834
{
827-
let min = param_spec.minimum();
828-
let max = param_spec.maximum();
835+
// Cast glong to i64 for cross-platform compatibility
836+
// glong is i32 on Windows but i64 on Linux
837+
#[allow(clippy::unnecessary_cast)]
838+
let min = param_spec.minimum() as i64;
839+
#[allow(clippy::unnecessary_cast)]
840+
let max = param_spec.maximum() as i64;
829841
let default =
830842
std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
831843
pad.property::<i64>(&name)
@@ -851,8 +863,12 @@ impl ElementDiscovery {
851863
} else if let Some(param_spec) =
852864
pspec.downcast_ref::<glib::ParamSpecULong>()
853865
{
854-
let min = param_spec.minimum();
855-
let max = param_spec.maximum();
866+
// Cast gulong to u64 for cross-platform compatibility
867+
// gulong is u32 on Windows but u64 on Linux
868+
#[allow(clippy::unnecessary_cast)]
869+
let min = param_spec.minimum() as u64;
870+
#[allow(clippy::unnecessary_cast)]
871+
let max = param_spec.maximum() as u64;
856872
let default =
857873
std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
858874
pad.property::<u64>(&name)

backend/src/gst/pipeline.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2030,8 +2030,8 @@ mod tests {
20302030
flow
20312031
}
20322032

2033-
#[test]
2034-
fn test_create_pipeline() {
2033+
#[tokio::test(flavor = "multi_thread")]
2034+
async fn test_create_pipeline() {
20352035
gst::init().unwrap();
20362036
let flow = create_test_flow();
20372037
let events = EventBroadcaster::default();
@@ -2040,8 +2040,8 @@ mod tests {
20402040
assert!(manager.is_ok());
20412041
}
20422042

2043-
#[test]
2044-
fn test_start_stop_pipeline() {
2043+
#[tokio::test(flavor = "multi_thread")]
2044+
async fn test_start_stop_pipeline() {
20452045
gst::init().unwrap();
20462046
let flow = create_test_flow();
20472047
let events = EventBroadcaster::default();
@@ -2063,8 +2063,8 @@ mod tests {
20632063
assert_eq!(state.unwrap(), PipelineState::Null);
20642064
}
20652065

2066-
#[test]
2067-
fn test_invalid_element() {
2066+
#[tokio::test(flavor = "multi_thread")]
2067+
async fn test_invalid_element() {
20682068
gst::init().unwrap();
20692069
let mut flow = create_test_flow();
20702070
flow.elements[0].element_type = "nonexistentelement".to_string();
@@ -2075,8 +2075,8 @@ mod tests {
20752075
assert!(manager.is_err());
20762076
}
20772077

2078-
#[test]
2079-
fn test_auto_tee_insertion() {
2078+
#[tokio::test(flavor = "multi_thread")]
2079+
async fn test_auto_tee_insertion() {
20802080
gst::init().unwrap();
20812081

20822082
// Create a flow with one source and two sinks (should auto-insert a tee)
@@ -2127,8 +2127,8 @@ mod tests {
21272127
assert!(manager.elements.contains_key("auto_tee_src"));
21282128
}
21292129

2130-
#[test]
2131-
fn test_no_tee_insertion_when_not_needed() {
2130+
#[tokio::test(flavor = "multi_thread")]
2131+
async fn test_no_tee_insertion_when_not_needed() {
21322132
gst::init().unwrap();
21332133

21342134
let flow = create_test_flow(); // Simple 1-to-1 connection

0 commit comments

Comments
 (0)