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 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),