use std::path::Path;
use ito_config::types::ItoConfig;
use crate::process::ProcessRunner;
use crate::validate::{ValidationReport, report, with_rule_id};
pub mod audit_rules;
pub mod backend_rules;
pub mod coordination_rules;
pub mod pre_commit_detect;
pub mod registry;
pub mod repository_rules;
pub mod rule;
pub mod staged;
pub mod worktrees_rules;
pub use pre_commit_detect::{PreCommitSystem, detect_pre_commit_system};
pub use registry::{ActiveRule, RuleRegistry, list_active_rules, list_active_rules_for};
pub use rule::{Rule, RuleContext, RuleId, RuleSeverity};
pub use staged::StagedFiles;
pub fn run_repo_validation(
config: &ItoConfig,
project_root: &Path,
staged: &StagedFiles,
runner: &dyn ProcessRunner,
strict: bool,
) -> ValidationReport {
let registry = RuleRegistry::built_in();
let ctx = RuleContext::new(config, project_root, staged, runner);
let mut builder = report(strict);
for rule in registry.iter() {
if !rule.is_active(config) {
continue;
}
match rule.check(&ctx) {
Ok(issues) => builder.extend(issues),
Err(err) => {
let mut issue = crate::validate::error(rule.id().as_str(), err.to_string());
issue = with_rule_id(issue, rule.id().as_str());
builder.push(issue);
}
}
}
builder.finish()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::process::SystemProcessRunner;
use ito_config::types::{CoordinationStorage, ItoConfig};
use std::path::Path;
fn embedded_config() -> ItoConfig {
let mut cfg = ItoConfig::default();
cfg.changes.coordination_branch.storage = CoordinationStorage::Embedded;
cfg.worktrees.enabled = false;
cfg
}
#[test]
fn run_repo_validation_skips_inactive_rules() {
let config = embedded_config();
let runner = SystemProcessRunner;
let staged = StagedFiles::empty();
let report = run_repo_validation(&config, Path::new("/"), &staged, &runner, false);
assert!(
report.valid,
"expected valid report; issues: {:?}",
report.issues
);
assert!(report.issues.is_empty());
}
#[test]
fn run_repo_validation_strict_promotes_warnings_to_errors() {
let mut config = embedded_config();
config.changes.coordination_branch.name = "coordination/foo".to_string();
let runner = SystemProcessRunner;
let staged = StagedFiles::empty();
let lenient = run_repo_validation(&config, Path::new("/"), &staged, &runner, false);
assert!(!lenient.issues.is_empty(), "warning expected");
assert!(
lenient.valid,
"lenient mode: warning should not invalidate the report"
);
let strict = run_repo_validation(&config, Path::new("/"), &staged, &runner, true);
assert!(
!strict.valid,
"strict mode: warning should invalidate the report"
);
}
}