Skip to content

Commit 890dd72

Browse files
committed
test(git-fetcher): drop skip_if_no_{git,npm} guards
Replace runtime probe-and-skip helpers with the existing `.unwrap()` calls — if `git`, `node`, or `npm` is missing the test will fail loudly rather than silently return. Tolerance defeats the purpose of testing: an under-provisioned environment is a bug in the environment, not something the suite should paper over. Git is ubiquitous and Node.js is a documented prerequisite for building pnpm. Codify the rule in pacquet/AGENTS.md so future ports don't reintroduce the pattern. Platform-locked tools are still allowed to gate via `#[cfg(...)]` or `#[cfg_attr(..., ignore = "...")]`, which surface in the test report instead of disappearing. --- Written by an agent (Claude Code, claude-opus-4-7).
1 parent 4195766 commit 890dd72

2 files changed

Lines changed: 42 additions & 54 deletions

File tree

pacquet/AGENTS.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,48 @@ Warnings are errors (`--deny warnings` in lint). Do not silence them with
204204
regression. Consult it before adding ported tests, and update its
205205
checkboxes as items land.
206206

207+
### No "tolerant" tests for missing tools
208+
209+
Tests must not be tolerant of a missing build / runtime environment by
210+
silently `return`-ing early when a tool isn't found. Patterns like:
211+
212+
```rust
213+
fn skip_if_no_git() -> bool {
214+
if std::process::Command::new("git").arg("--version").output().is_err() {
215+
eprintln!("skipping: `git` not on PATH");
216+
return true;
217+
}
218+
false
219+
}
220+
221+
#[test]
222+
fn my_test() {
223+
if skip_if_no_git() {
224+
return;
225+
}
226+
// ...
227+
}
228+
```
229+
230+
are forbidden. If the test needs a tool, just call into it and let the
231+
existing `.unwrap()` / `.expect(...)` panic when the tool is absent — a
232+
failing test in an under-provisioned environment is the correct signal.
233+
Tolerance defeats the purpose of testing: if the environment really
234+
doesn't have the required tools, that's the *environment's* fault and it
235+
needs to be fixed.
236+
237+
This applies in particular to `git`, `node`, and `npm` — git is ubiquitous
238+
on developer machines, and Node.js is a documented prerequisite for
239+
building pnpm. There is no realistic environment in which pacquet's tests
240+
should run *and* these tools should be absent.
241+
242+
The only marginally acceptable exception is platform-locked tools — APIs
243+
or binaries that exist on one OS but not another. Even then, prefer
244+
`#[cfg_attr(target_os = "windows", ignore = "...")]` (or the matching
245+
`#[cfg(unix)]` gate already used in this crate for `/bin/sh` shims) over a
246+
runtime probe-and-skip helper. The gate is visible to `cargo test` and
247+
shows up in the test report; a silent `return` does not.
248+
207249
### Running tests narrowly
208250

209251
Running the full suite is slow. While iterating, target what you're working

pacquet/crates/git-fetcher/src/fetcher/tests.rs

Lines changed: 0 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -8,33 +8,6 @@ use pacquet_testing_utils::env_guard::EnvGuard;
88
use std::{fs, path::Path, path::PathBuf};
99
use tempfile::tempdir;
1010

11-
fn skip_if_no_git() -> bool {
12-
let probe = std::process::Command::new("git").arg("--version").output();
13-
if probe.is_err() {
14-
eprintln!("skipping: `git` not on PATH");
15-
return true;
16-
}
17-
false
18-
}
19-
20-
/// Skip the test if `npm` (and `node`) aren't on `PATH`. Used by the
21-
/// real-prepare tests below, which spawn an actual lifecycle script:
22-
/// `prepare_package` synthesizes `npm install` for any non-pnpm
23-
/// preferred-pm, and that needs an npm binary to invoke. Hosts
24-
/// without node tooling (a Rust-only sandbox, an embedded CI image)
25-
/// silently skip rather than fail so the suite stays portable.
26-
fn skip_if_no_npm() -> bool {
27-
if std::process::Command::new("npm").arg("--version").output().is_err() {
28-
eprintln!("skipping: `npm` not on PATH");
29-
return true;
30-
}
31-
if std::process::Command::new("node").arg("--version").output().is_err() {
32-
eprintln!("skipping: `node` not on PATH");
33-
return true;
34-
}
35-
false
36-
}
37-
3811
/// Build a bare repo whose manifest declares a `prepare` script. The
3912
/// script is whatever the caller passes — typically a `node -e '…'`
4013
/// one-liner that writes a marker file or exits non-zero. Returns
@@ -122,9 +95,6 @@ fn extract_host_handles_user_authority_and_port() {
12295

12396
#[tokio::test(flavor = "multi_thread")]
12497
async fn fetcher_imports_package_into_cas() {
125-
if skip_if_no_git() {
126-
return;
127-
}
12898
let tmp = tempdir().unwrap();
12999
let (bare, commit) = make_bare_repo(tmp.path());
130100
let store_root = tempdir().unwrap();
@@ -164,9 +134,6 @@ async fn fetcher_imports_package_into_cas() {
164134

165135
#[tokio::test(flavor = "multi_thread")]
166136
async fn fetcher_rejects_commit_mismatch() {
167-
if skip_if_no_git() {
168-
return;
169-
}
170137
let tmp = tempdir().unwrap();
171138
let (bare, _commit) = make_bare_repo(tmp.path());
172139
let store_root = tempdir().unwrap();
@@ -211,9 +178,6 @@ async fn fetcher_rejects_commit_mismatch() {
211178

212179
#[tokio::test(flavor = "multi_thread")]
213180
async fn fetcher_blocks_build_when_not_allowed() {
214-
if skip_if_no_git() {
215-
return;
216-
}
217181
let tmp = tempdir().unwrap();
218182
// A repo whose manifest declares a `prepare` script — exercises
219183
// the `allow_build` gate without actually spawning the script
@@ -337,9 +301,6 @@ fn make_bare_repo_without_manifest(tmp: &Path) -> (PathBuf, String) {
337301
/// the monorepo root or sibling packages.
338302
#[tokio::test(flavor = "multi_thread")]
339303
async fn fetcher_packs_subfolder_when_path_set() {
340-
if skip_if_no_git() {
341-
return;
342-
}
343304
let tmp = tempdir().unwrap();
344305
let (bare, commit) = make_monorepo_bare_repo(tmp.path());
345306
let store_root = tempdir().unwrap();
@@ -387,9 +348,6 @@ async fn fetcher_packs_subfolder_when_path_set() {
387348
/// downstream, but the fetcher itself must not crash.
388349
#[tokio::test(flavor = "multi_thread")]
389350
async fn fetcher_handles_repo_without_package_json() {
390-
if skip_if_no_git() {
391-
return;
392-
}
393351
let tmp = tempdir().unwrap();
394352
let (bare, commit) = make_bare_repo_without_manifest(tmp.path());
395353
let store_root = tempdir().unwrap();
@@ -433,9 +391,6 @@ async fn fetcher_handles_repo_without_package_json() {
433391
/// build (matches upstream's `shouldBeBuilt = true` short-circuit).
434392
#[tokio::test(flavor = "multi_thread")]
435393
async fn fetcher_skips_build_when_ignore_scripts() {
436-
if skip_if_no_git() {
437-
return;
438-
}
439394
let tmp = tempdir().unwrap();
440395
// A repo whose `prepare` script would fail if it ran — observing
441396
// success proves the lifecycle runner never spawned anything.
@@ -510,9 +465,6 @@ async fn fetcher_skips_build_when_ignore_scripts() {
510465
/// actually executed (the file didn't exist in the source tree).
511466
#[tokio::test(flavor = "multi_thread")]
512467
async fn fetcher_runs_prepare_script_when_allowed() {
513-
if skip_if_no_git() || skip_if_no_npm() {
514-
return;
515-
}
516468
let tmp = tempdir().unwrap();
517469
// The prepare script writes a marker. Single-quoted inner
518470
// string so the JSON doesn't need to escape it; node reads the
@@ -569,9 +521,6 @@ async fn fetcher_runs_prepare_script_when_allowed() {
569521
/// fetcher refuses to add a broken-build snapshot to the CAS.
570522
#[tokio::test(flavor = "multi_thread")]
571523
async fn fetcher_surfaces_prepare_failure() {
572-
if skip_if_no_git() || skip_if_no_npm() {
573-
return;
574-
}
575524
let tmp = tempdir().unwrap();
576525
let (bare, commit) = make_bare_repo_with_prepare_script(
577526
tmp.path(),
@@ -641,9 +590,6 @@ async fn fetcher_surfaces_prepare_failure() {
641590
/// keep the block-test green.
642591
#[tokio::test(flavor = "multi_thread")]
643592
async fn fetcher_runs_prepare_when_allow_build_returns_true() {
644-
if skip_if_no_git() || skip_if_no_npm() {
645-
return;
646-
}
647593
let tmp = tempdir().unwrap();
648594
let (bare, commit) = make_bare_repo_with_prepare_script(
649595
tmp.path(),

0 commit comments

Comments
 (0)