Skip to content
55 changes: 55 additions & 0 deletions .github/workflows/rust-clippy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: Rust Clippy

on:
push:
branches:
- main
pull_request:

permissions:
contents: read

concurrency:
group: rust-clippy-${{ github.ref }}
cancel-in-progress: true

jobs:
clippy:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4

# Pinned toolchain (NOT @stable): keeps green-local <=> green-CI deterministic.
# Current stable (1.97.x) already adds default-warn lints this branch was not
# validated against. Bump this pin deliberately: update the version, re-run the
# gate locally on that toolchain, fix new lints in the same PR.
- uses: dtolnay/rust-toolchain@master
with:
toolchain: 1.96.0
components: clippy, rustfmt

- uses: Swatinem/rust-cache@v2

# freshell-tauri (Tauri v2 / WRY) needs GTK+WebKit system libs to compile
# on ubuntu-latest; installing them keeps the gate truly --workspace.
- name: Install Tauri system dependencies
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
libwebkit2gtk-4.1-dev libgtk-3-dev libsoup-3.0-dev \
libjavascriptcoregtk-4.1-dev librsvg2-dev \
libayatana-appindicator3-dev pkg-config build-essential

- name: cargo fmt
run: cargo fmt --all --check

- name: cargo clippy (workspace)
run: cargo clippy --workspace --all-targets -- -D warnings

# --all-targets does not imply --all-features: the real-transport
# backends are default-off and would otherwise go unlinted.
- name: cargo clippy (feature-gated backends)
run: |
cargo clippy -p freshell-codex --features real-transport --all-targets -- -D warnings
cargo clippy -p freshell-opencode --features real-transport --all-targets -- -D warnings
14 changes: 7 additions & 7 deletions crates/freshell-freshagent/src/claude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -973,7 +973,7 @@ mod tests {
fn sidecar_entry_resolves_to_the_vendored_package() {
// Guard against the dedup tests' concurrent FRESHELL_CLAUDE_SIDECAR mutation
// (see CLAUDE_ENV_LOCK below) -- this test reads the SAME process-global env var.
let _guard = CLAUDE_ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner());
let _guard = CLAUDE_ENV_LOCK.blocking_lock();
std::env::remove_var("FRESHELL_CLAUDE_SIDECAR");
// The compile-time path points at the vendored Node package beside this crate.
let entry = sidecar_entry_path();
Expand All @@ -994,7 +994,7 @@ mod tests {
/// Serializes every test in this file that mutates process-global env vars
/// (`FRESHELL_CLAUDE_SIDECAR` / `FRESHELL_CLAUDE_NODE`), mirroring codex's
/// `ENV_LOCK` (`codex.rs`).
static CLAUDE_ENV_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
static CLAUDE_ENV_LOCK: tokio::sync::Mutex<()> = tokio::sync::Mutex::const_new(());

/// A minimal scripted fake claude sidecar (no real `@anthropic-ai/claude-agent-sdk`,
/// no network, no cost): on `{"type":"create",...}` it appends a marker line to
Expand Down Expand Up @@ -1139,7 +1139,7 @@ rl.on('line', (line) => {
/// SAME session id on the second response.
#[tokio::test]
async fn handle_create_duplicate_request_id_reuses_the_session_and_spawns_once() {
let _guard = CLAUDE_ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner());
let _guard = CLAUDE_ENV_LOCK.lock().await;
let env = FakeClaudeSidecarEnv::install();
let (tx, mut rx) = tokio::sync::broadcast::channel::<String>(64);
let st = FreshClaudeState::new(Arc::new(tx));
Expand Down Expand Up @@ -1170,7 +1170,7 @@ rl.on('line', (line) => {
/// must still spawn at most one sidecar and both resolve to the SAME session.
#[tokio::test]
async fn handle_create_concurrent_duplicate_request_id_spawns_at_most_once() {
let _guard = CLAUDE_ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner());
let _guard = CLAUDE_ENV_LOCK.lock().await;
let env = FakeClaudeSidecarEnv::install();
let (tx, mut rx) = tokio::sync::broadcast::channel::<String>(64);
let st = FreshClaudeState::new(Arc::new(tx));
Expand Down Expand Up @@ -1200,7 +1200,7 @@ rl.on('line', (line) => {
/// Control: DISTINCT requestIds must never dedup against each other.
#[tokio::test]
async fn handle_create_distinct_request_ids_create_distinct_sessions() {
let _guard = CLAUDE_ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner());
let _guard = CLAUDE_ENV_LOCK.lock().await;
let env = FakeClaudeSidecarEnv::install();
let (tx, mut rx) = tokio::sync::broadcast::channel::<String>(64);
let st = FreshClaudeState::new(Arc::new(tx));
Expand Down Expand Up @@ -1237,7 +1237,7 @@ rl.on('line', (line) => {
/// it is dropped rather than mirrored redundantly -- 4 tests, not 5.
#[tokio::test]
async fn handle_create_duplicate_after_explicit_kill_creates_a_fresh_session() {
let _guard = CLAUDE_ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner());
let _guard = CLAUDE_ENV_LOCK.lock().await;
let env = FakeClaudeSidecarEnv::install();
let (tx, mut rx) = tokio::sync::broadcast::channel::<String>(64);
let st = FreshClaudeState::new(Arc::new(tx));
Expand Down Expand Up @@ -1330,7 +1330,7 @@ rl.on('line', (line) => {
/// assert on instead).
#[tokio::test]
async fn handle_interrupt_forwards_the_request_to_the_sidecar_for_a_known_session() {
let _guard = CLAUDE_ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner());
let _guard = CLAUDE_ENV_LOCK.lock().await;
let env = FakeClaudeSidecarEnv::install();
let (tx, mut rx) = tokio::sync::broadcast::channel::<String>(64);
let st = FreshClaudeState::new(Arc::new(tx));
Expand Down
Loading
Loading