use super::types::{GateResult, QualityGate, Severity, Violation, ViolationType};
use crate::tdg::TdgBaseline;
use anyhow::Result;
pub struct CriticalDefectGate {
max_files: usize,
}
impl CriticalDefectGate {
#[must_use]
pub fn new(max_files: usize) -> Self {
Self { max_files }
}
#[must_use]
pub fn with_defaults() -> Self {
Self::new(0)
}
}
impl Default for CriticalDefectGate {
fn default() -> Self {
Self::with_defaults()
}
}
impl QualityGate for CriticalDefectGate {
fn name(&self) -> &str {
"CriticalDefectGate"
}
fn check(&self, _baseline: &TdgBaseline, current: &TdgBaseline) -> Result<GateResult> {
let mut violations = Vec::new();
let mut waived = 0usize;
for (path, entry) in ¤t.files {
if !entry.score.has_critical_defects {
continue;
}
if entry.score.critical_defects_suppressed.is_some() {
waived += 1;
continue;
}
violations.push(Violation {
path: path.clone(),
violation_type: ViolationType::BelowMinimum,
severity: Severity::Critical,
message: format!(
"{} critical defect(s) - requires immediate attention",
entry.score.critical_defects_count
),
old_score: None,
new_score: entry.score.total,
old_grade: None,
new_grade: entry.score.grade,
});
}
let offending = violations.len();
let passed = offending <= self.max_files;
let message = match (offending, waived) {
(0, 0) => "No critical defects".to_string(),
(0, w) => format!("No unsuppressed critical defects ({w} file(s) waived under #279)"),
(n, 0) => format!("{n} file(s) with critical defects"),
(n, w) => format!("{n} file(s) with critical defects ({w} waived under #279)"),
};
Ok(GateResult {
gate_name: self.name().to_string(),
passed,
violations,
message,
})
}
}
#[cfg(test)]
#[path = "critical_defect_tests.rs"]
mod critical_defect_tests;