Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/Skidbladnir

tests/clippy_gate.rs

//! **`cargo clippy --all-targets -- -D warnings` is green for this repo.**
//!
//! Run the gate with:
//!
//! ```text
//! cargo test --test clippy_gate -- --ignored
//! ```
//!
//! It runs three clippy passes and fails on the first that warns:
//!
//! 1. the workspace with default features,
//! 2. the workspace with every member feature that does not pull `draupnir`,
//! 3. the detached `probe/` crate (it is not a workspace member).
//!
//! **Why not `--all-features`.** `msi-oci`, `pack-oci`, `oci`, `service-drive`, `kvm`
//! and `matrix` link the sibling `../draupnir`, which is its own repo with its own
//! gate. When that sibling does not build (it did not on 2026-10-10: draupnir
//! against tunnr), `--all-features` reports draupnir's red, not ours. The feature
//! set is computed from `cargo metadata`, not written down, so a new feature is
//! linted as soon as it exists, unless it reaches draupnir.
//!
//! The non-ignored tests are cheap and run on a plain `cargo test`: the feature
//! set is non-empty and holds back exactly the draupnir features, and no source
//! file silences clippy for a whole crate (`#![allow(clippy::…)]`). A lint gets a
//! real fix, or a scoped `#[allow]` on the one item with a reason next to it.

use std::collections::BTreeMap;
use std::path::{Path, PathBuf};
use std::process::Command;

/// The sibling repo whose features are held back from the feature pass.
const HELD_BACK: &str = "draupnir";

fn repo_root() -> PathBuf {
    PathBuf::from(env!("CARGO_MANIFEST_DIR"))
}

fn cargo() -> String {
    std::env::var("CARGO").unwrap_or_else(|_| "cargo".into())
}

/// `true` if `feature` of a package with `features` turns on `dep` (directly, or
/// through another feature of the same package).
fn pulls(
    features: &BTreeMap<String, Vec<String>>,
    feature: &str,
    dep: &str,
    seen: &mut Vec<String>,
) -> bool {
    if seen.iter().any(|s| s == feature) {
        return false;
    }
    seen.push(feature.to_string());
    let Some(values) = features.get(feature) else {
        return feature == dep;
    };
    values.iter().any(|v| {
        let v = v.as_str();
        v == format!("dep:{dep}")
            || v.starts_with(&format!("{dep}/"))
            || v.starts_with(&format!("{dep}?/"))
            || pulls(features, v, dep, seen)
    })
}

/// `pkg/feature` for every workspace member feature that does not pull `dep`.
fn features_without(members: &[(String, BTreeMap<String, Vec<String>>)], dep: &str) -> Vec<String> {
    let mut out = Vec::new();
    for (pkg, features) in members {
        for f in features.keys() {
            if f != "default" && !pulls(features, f, dep, &mut Vec::new()) {
                out.push(format!("{pkg}/{f}"));
            }
        }
    }
    out
}

fn workspace_members() -> Vec<(String, BTreeMap<String, Vec<String>>)> {
    let out = Command::new(cargo())
        .args([
            "metadata",
            "--format-version",
            "1",
            "--no-deps",
            "--offline",
        ])
        .current_dir(repo_root())
        .output()
        .expect("cargo metadata did not start");
    assert!(
        out.status.success(),
        "cargo metadata failed: {}",
        String::from_utf8_lossy(&out.stderr)
    );
    let meta: serde_json::Value = serde_json::from_slice(&out.stdout).expect("cargo metadata json");
    meta["packages"]
        .as_array()
        .expect("packages")
        .iter()
        .map(|p| {
            let name = p["name"].as_str().expect("package name").to_string();
            let features = serde_json::from_value(p["features"].clone()).expect("features map");
            (name, features)
        })
        .collect()
}

fn rust_files(dir: &Path, out: &mut Vec<PathBuf>) {
    let Ok(rd) = std::fs::read_dir(dir) else {
        return;
    };
    for e in rd.flatten() {
        let p = e.path();
        let name = e.file_name();
        if p.is_dir() {
            if name != "target" && name != ".git" {
                rust_files(&p, out);
            }
        } else if p.extension().is_some_and(|x| x == "rs") {
            out.push(p);
        }
    }
}

/// The lines of `src` that silence a clippy lint for the whole crate, in the
/// single-line and the multi-line `#![allow(\n clippy::…` spelling.
fn crate_wide_clippy_allows(src: &str) -> Vec<String> {
    let mut hits = Vec::new();
    let lines: Vec<&str> = src.lines().collect();
    for (i, l) in lines.iter().enumerate() {
        let t = l.trim_start();
        if !t.starts_with("#![allow(") {
            continue;
        }
        let mut attr = t.to_string();
        let mut j = i;
        while !attr.contains(")]") && j + 1 < lines.len() {
            j += 1;
            attr.push_str(lines[j].trim());
        }
        if attr.contains("clippy::") {
            hits.push(format!("{}: {attr}", i + 1));
        }
    }
    hits
}

fn clippy(args: &[&str]) -> Result<(), String> {
    let out = Command::new(cargo())
        .arg("clippy")
        .args(args)
        .args(["--all-targets", "--", "-D", "warnings"])
        .current_dir(repo_root())
        .output()
        .map_err(|e| format!("cargo clippy did not start: {e}"))?;
    if out.status.success() {
        return Ok(());
    }
    let err = String::from_utf8_lossy(&out.stderr);
    let tail: Vec<&str> = err.lines().rev().take(60).collect();
    Err(format!(
        "cargo clippy {} --all-targets -- -D warnings is RED:\n{}",
        args.join(" "),
        tail.into_iter().rev().collect::<Vec<_>>().join("\n")
    ))
}

#[test]
fn pulls_follows_features_and_dep_spellings() {
    let f: BTreeMap<String, Vec<String>> = [
        ("a", vec!["dep:x"]),
        ("b", vec!["x/seed"]),
        ("c", vec!["x?/seed"]),
        ("d", vec!["b"]),
        ("e", vec!["dep:y", "f"]),
        ("f", vec!["e"]),
    ]
    .into_iter()
    .map(|(k, v)| (k.to_string(), v.into_iter().map(String::from).collect()))
    .collect();
    for yes in ["a", "b", "c", "d", "x"] {
        assert!(pulls(&f, yes, "x", &mut Vec::new()), "{yes} pulls x");
    }
    for no in ["e", "f", "y"] {
        assert!(!pulls(&f, no, "x", &mut Vec::new()), "{no} does not pull x");
    }
}

#[test]
fn crate_wide_clippy_allow_is_seen_in_both_spellings() {
    assert_eq!(
        crate_wide_clippy_allows("#![allow(clippy::type_complexity)]\n").len(),
        1
    );
    assert_eq!(
        crate_wide_clippy_allows("#![allow(\n    dead_code,\n    clippy::too_many_arguments\n)]\n")
            .len(),
        1
    );
    assert!(
        crate_wide_clippy_allows("#![allow(dead_code)]\n#[allow(clippy::x)]\nfn f() {}\n")
            .is_empty()
    );
}

#[test]
fn the_feature_pass_holds_back_exactly_the_draupnir_features() {
    let members = workspace_members();
    let lint = features_without(&members, HELD_BACK);
    assert!(
        lint.iter().any(|f| f == "skidbladnir/pki"),
        "feature pass is missing pki: {lint:?}"
    );
    let root = members
        .iter()
        .find(|(n, _)| n == "skidbladnir")
        .expect("root package");
    for held in ["msi-oci", "pack-oci", "service-drive", "kvm"] {
        assert!(
            root.1.contains_key(held),
            "{held} is no longer a feature; update the doc"
        );
        assert!(
            !lint.iter().any(|f| f == &format!("skidbladnir/{held}")),
            "{held} pulls {HELD_BACK}"
        );
    }
    let total: usize = members
        .iter()
        .map(|(_, f)| f.keys().filter(|k| *k != "default").count())
        .sum();
    assert!(
        lint.len() * 2 > total,
        "most features must be linted: {} of {total}",
        lint.len()
    );
}

#[test]
fn no_source_file_silences_clippy_crate_wide() {
    let root = repo_root();
    let mut files = Vec::new();
    for d in [
        "src", "tests", "crates", "probe", "benches", "examples", "build.rs",
    ] {
        let p = root.join(d);
        if p.is_file() {
            files.push(p);
        } else {
            rust_files(&p, &mut files);
        }
    }
    assert!(
        files.len() > 50,
        "scanned only {} files; the walk is broken",
        files.len()
    );
    let mut bad = Vec::new();
    for f in &files {
        let src = std::fs::read_to_string(f).unwrap();
        for hit in crate_wide_clippy_allows(&src) {
            bad.push(format!(
                "{}:{hit}",
                f.strip_prefix(&root).unwrap().display()
            ));
        }
    }
    assert!(
        bad.is_empty(),
        "crate-wide clippy allow — fix the lints instead:\n{}",
        bad.join("\n")
    );
}

#[test]
#[ignore = "runs cargo clippy three times; run with --ignored"]
fn clippy_is_clean() {
    let features = features_without(&workspace_members(), HELD_BACK).join(" ");
    let probe = repo_root().join("probe/Cargo.toml");
    let probe = probe.to_str().unwrap();
    let runs: [&[&str]; 3] = [
        &["--workspace"],
        &["--workspace", "--features", &features],
        &["--manifest-path", probe],
    ];
    let red: Vec<String> = runs.iter().filter_map(|a| clippy(a).err()).collect();
    assert!(red.is_empty(), "{}", red.join("\n\n"));
}