From 9d36c66e9cb6725a16f566a4d89f26ae111f21a7 Mon Sep 17 00:00:00 2001 From: Chris Raethke Date: Mon, 6 Apr 2026 18:24:14 +1000 Subject: [PATCH 1/2] ci: add CI workflow for PRs and pushes to main Runs cargo fmt --check, clippy, build, and test on every PR and push to main so issues are caught before merge rather than at release time. Closes #31 --- .github/workflows/ci.yml | 42 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..3e48c68 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,42 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + rust: + name: Rust checks + runs-on: ubuntu-latest + env: + CARGO_TERM_COLOR: always + CARGO_INCREMENTAL: "0" + RUSTFLAGS: "-D warnings" + RUST_BACKTRACE: 1 + steps: + - uses: actions/checkout@v4 + + - uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt, clippy + + - uses: Swatinem/rust-cache@v2 + with: + cache-on-failure: true + + - name: Check formatting + run: cargo fmt --check + + - name: Clippy + run: cargo clippy --all-targets -- -D warnings + + - name: Build + run: cargo build --all-targets + + - name: Test + run: cargo test From 87fc253e825c39975f6cbb9d74b723ab6ec301b5 Mon Sep 17 00:00:00 2001 From: Chris Raethke Date: Mon, 6 Apr 2026 19:07:36 +1000 Subject: [PATCH 2/2] fix: resolve clippy warnings for CI (zombie_processes, useless_format) Properly wait on spawned child processes in tests and replace useless format!() with .to_string() in report test helper. --- src/claude_code.rs | 15 +++++++++------ src/report.rs | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/claude_code.rs b/src/claude_code.rs index aedd149..20fa7df 100644 --- a/src/claude_code.rs +++ b/src/claude_code.rs @@ -635,7 +635,7 @@ mod tests { #[test] fn stream_turn_iterator_with_mock_process() { // Simulate stdout with assistant + result events - let child = Command::new("sh") + let mut child = Command::new("sh") .arg("-c") .arg(r#"echo '{"type":"system","subtype":"init"}'; echo '{"type":"assistant","message":{"content":[{"type":"text","text":"Hello"}]}}'; echo '{"type":"result","result":"Hello","subtype":"success"}';"#) .stdout(Stdio::piped()) @@ -643,7 +643,7 @@ mod tests { .spawn() .unwrap(); - let stdout = child.stdout.unwrap(); + let stdout = child.stdout.take().unwrap(); let mut reader = BufReader::new(stdout); // Skip system init @@ -666,11 +666,12 @@ mod tests { } assert_eq!(collected, vec!["Hello"]); + let _ = child.wait(); } #[test] fn stream_turn_iterator_reports_error_events() { - let child = Command::new("sh") + let mut child = Command::new("sh") .arg("-c") .arg(r#"echo '{"type":"error","error":"something went wrong"}'"#) .stdout(Stdio::piped()) @@ -678,7 +679,7 @@ mod tests { .spawn() .unwrap(); - let stdout = child.stdout.unwrap(); + let stdout = child.stdout.take().unwrap(); let mut reader = BufReader::new(stdout); let mut iter = StreamTurnIterator { @@ -694,11 +695,12 @@ mod tests { matches!(item, Err(ProviderError::StreamError(ref msg)) if msg == "something went wrong"), "expected StreamError, got: {item:?}" ); + let _ = child.wait(); } #[test] fn stream_turn_iterator_skips_non_json_lines() { - let child = Command::new("sh") + let mut child = Command::new("sh") .arg("-c") .arg(r#"echo 'not json'; echo '{"type":"assistant","message":{"content":[{"type":"text","text":"text"}]}}'; echo '{"type":"result","result":"text","subtype":"success"}';"#) .stdout(Stdio::piped()) @@ -706,7 +708,7 @@ mod tests { .spawn() .unwrap(); - let stdout = child.stdout.unwrap(); + let stdout = child.stdout.take().unwrap(); let mut reader = BufReader::new(stdout); let mut iter = StreamTurnIterator { @@ -725,6 +727,7 @@ mod tests { } assert_eq!(texts, vec!["text"]); + let _ = child.wait(); } #[test] diff --git a/src/report.rs b/src/report.rs index c44c0bd..754611e 100644 --- a/src/report.rs +++ b/src/report.rs @@ -338,7 +338,7 @@ mod tests { instruction: instruction.to_string(), source_file: PathBuf::from("tests/login.test.toml"), result: StepResult::Verdict(StepVerdict::Ok), - transcript: format!("Checked.\nRESULT OK"), + transcript: "Checked.\nRESULT OK".to_string(), log_events: vec![], evidence_refs: vec![], duration: Duration::from_millis(1500),