clippy-ci-parity
Clippy / CI Parity
CI treats clippy warnings as errors (-D warnings), so any lint the local workflow misses becomes a hard build failure on push. Plain cargo clippy only warns, which lets drift slip through.
Run Locally what CI Runs
cargo clippy --all-targets -- -D warnings
cargo fmt -- --check
cargo test
--all-targets covers lib, bins, tests, and examples — matching CI's surface area. Without it, test-only code (which is most of tests/) goes unchecked.
Lints that Have Bitten Us
collapsible_match—match X { Variant => { if cond { … } } }must be written asVariant if cond => { … }when there's a catchall arm. Hit insrc/tui/form.rscallout title edit handler (4 arms:Backspace,Left,Right,Char(c)each wrapping anifaround the body).unused_mutacross cfg boundaries — alet mut xis fine on Windows (where a#[cfg(target_os = "windows")]block mutates it) but flags as unused on Linux CI. Scope the allow to the platforms where it's genuinely unused:#[cfg_attr(not(target_os = "windows"), allow(unused_mut))]. Don't blanket-allow. Hit insrc/init.rs::detect_obsidian_vaults— local Windows build was happy, Linux CI was not.
Rule of Thumb
If rustc is happy but clippy isn't, CI will reject the push. Pre-push check should be the three-command block above, not just cargo build.
Test Flakes from Shared Mutexes
Tests that mutate process-wide state (env vars, CWD, etc.) commonly serialize via a static Mutex. Two gotchas the suite has hit:
- Every test touching the shared state must acquire the mutex, not just the ones clustered near its definition. Missing just one creates a race that Ubuntu's scheduler may hide but Windows' will expose. Hit when
load_with_pour_config_env_var_nonexistent_fileandload_from_pour_config_env_varmutatedPOUR_CONFIGwithoutSECRETS_ENV_LOCK, racing the guarded secrets tests. - Prefer
.lock().unwrap_or_else(|e| e.into_inner())over.lock().unwrap(). A plainunwrappanics on a poisoned mutex — which happens any time another test panics mid-critical-section — so one genuine failure cascades into N false PoisonError failures, burying the real signal. Usinginto_innerkeeps the real failure visible and lets the rest of the suite run.
Integration test isolation note: each file under tests/ compiles to a separate binary and runs as its own process, so env vars don't leak across files. Within a single file, though, tests share a process and run in parallel threads.