#![allow(
clippy::print_stderr,
reason = "the gate explains a non-zero exit on stderr, like the other CLI gates"
)]
use fallow_engine::baseline::{BaselineStaleness, stale_baseline_gate_trips};
use std::path::{Path, PathBuf};
#[derive(Clone, Debug)]
pub struct LoadedBaselineStaleness {
pub staleness: BaselineStaleness,
pub path: PathBuf,
}
pub const DEAD_CODE_NOUN: &str = "issue";
pub const DUPES_NOUN: &str = "clone group";
pub const HEALTH_NOUN: &str = "finding";
pub fn gate_failed(loaded: Option<&LoadedBaselineStaleness>, enabled: bool, noun: &str) -> bool {
if !enabled {
return false;
}
let Some(loaded) = loaded else {
return false;
};
report_gate(
loaded.staleness.entries,
loaded.staleness.matched,
loaded.staleness.change_scoped,
&loaded.path,
noun,
)
}
pub fn gate_failed_from_counts(
entries: usize,
matched: usize,
change_scoped: bool,
path: Option<&Path>,
enabled: bool,
noun: &str,
) -> bool {
if !enabled {
return false;
}
let Some(path) = path else {
return false;
};
report_gate(entries, matched, change_scoped, path, noun)
}
pub fn note_stood_down(path: Option<&Path>, enabled: bool, reason: &str) {
if !enabled {
return;
}
let Some(path) = path else {
return;
};
eprintln!(
"Note: --fail-on-stale-baseline did not run: {reason}, so the baseline {} was not judged.",
path.display(),
);
}
fn report_gate(
entries: usize,
matched: usize,
change_scoped: bool,
path: &Path,
noun: &str,
) -> bool {
if !stale_baseline_gate_trips(entries, matched, change_scoped) {
if change_scoped && entries > 0 {
eprintln!(
"Note: --fail-on-stale-baseline did not run: this analysis covered only part of \
the project, which cannot judge the whole-project baseline {}. Re-run over the \
whole project to gate on it.",
path.display(),
);
}
return false;
}
let stale = entries.saturating_sub(matched);
eprintln!(
"Baseline gate failed: {stale} of {entries} entries in {} matched no current {noun}. \
Re-save with: --save-baseline {}",
path.display(),
path.display(),
);
true
}