use crate::config::{GateDefinition, GateEnforcement};
use crate::db::Database;
use anyhow::Result;
use serde::{Deserialize, Serialize};
use std::collections::HashSet;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GateResult {
pub gate_type: String,
pub enforcement: GateEnforcement,
pub description: String,
pub satisfied: bool,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct GateCheckResult {
pub status: String,
pub unsatisfied_gates: Vec<GateResult>,
}
pub fn evaluate_gates(
db: &Database,
task_id: &str,
gates: &[GateDefinition],
) -> Result<GateCheckResult> {
let attachments = db.get_attachments(task_id)?;
let attachment_types: HashSet<String> = attachments
.iter()
.map(|a| a.attachment_type.clone())
.collect();
let mut unsatisfied_gates = Vec::new();
let mut has_reject = false;
let mut has_warn = false;
for gate in gates {
let satisfied = attachment_types.contains(&gate.gate_type);
if !satisfied {
match gate.enforcement {
GateEnforcement::Reject => has_reject = true,
GateEnforcement::Warn => has_warn = true,
GateEnforcement::Allow => {} }
unsatisfied_gates.push(GateResult {
gate_type: gate.gate_type.clone(),
enforcement: gate.enforcement,
description: gate.description.clone(),
satisfied: false,
});
}
}
let status = if has_reject {
"fail".to_string()
} else if has_warn {
"warn".to_string()
} else {
"pass".to_string()
};
Ok(GateCheckResult {
status,
unsatisfied_gates,
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_gate_check_result_status_pass() {
let result = GateCheckResult {
status: "pass".to_string(),
unsatisfied_gates: vec![],
};
assert_eq!(result.status, "pass");
}
#[test]
fn test_gate_result_serialization() {
let gate = GateResult {
gate_type: "gate/tests".to_string(),
enforcement: GateEnforcement::Warn,
description: "Tests must pass".to_string(),
satisfied: false,
};
let json = serde_json::to_string(&gate).unwrap();
assert!(json.contains("gate/tests"));
assert!(json.contains("warn"));
}
}