Skip to main content

rust_bucket/
verify.rs

1// Verification and validation logic
2
3use std::path::Path;
4use std::process::Command;
5use thiserror::Error;
6
7/// Verification step types
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum VerifyStep {
10    Format,
11    Clippy,
12    Test,
13}
14
15/// Result of running a verification step
16#[derive(Debug, Clone, PartialEq, Eq)]
17pub enum StepResult {
18    Pass,
19    Fail(String),
20    Skip(String),
21}
22
23/// Report containing results of all verification steps
24#[derive(Debug, Clone, PartialEq, Eq)]
25pub struct VerifyReport {
26    pub format: StepResult,
27    pub clippy: StepResult,
28    pub test: StepResult,
29}
30
31/// Errors that can occur during verification
32#[derive(Error, Debug)]
33pub enum VerifyError {
34    #[error("Failed to execute cargo command: {0}")]
35    CommandExecution(String),
36
37    #[error("I/O error during verification: {0}")]
38    Io(#[from] std::io::Error),
39}
40
41impl VerifyReport {
42    /// Check if all verification steps passed or were skipped
43    pub fn is_success(&self) -> bool {
44        matches!(self.format, StepResult::Pass | StepResult::Skip(_))
45            && matches!(self.clippy, StepResult::Pass | StepResult::Skip(_))
46            && matches!(self.test, StepResult::Pass | StepResult::Skip(_))
47    }
48}
49
50/// Run all verification steps on the target directory
51pub fn run_all(target_dir: &Path) -> Result<VerifyReport, VerifyError> {
52    let format = run_format_check(target_dir)?;
53    let clippy = run_clippy(target_dir)?;
54    let test = run_tests(target_dir)?;
55
56    Ok(VerifyReport {
57        format,
58        clippy,
59        test,
60    })
61}
62
63/// Run cargo fmt --check
64fn run_format_check(target_dir: &Path) -> Result<StepResult, VerifyError> {
65    let output = Command::new("cargo")
66        .arg("fmt")
67        .arg("--check")
68        .current_dir(target_dir)
69        .output()?;
70
71    if output.status.success() {
72        Ok(StepResult::Pass)
73    } else {
74        let stderr = String::from_utf8_lossy(&output.stderr);
75        let stdout = String::from_utf8_lossy(&output.stdout);
76        let message = format!("{}\n{}", stdout, stderr).trim().to_string();
77        Ok(StepResult::Fail(message))
78    }
79}
80
81/// Run cargo clippy --all-targets --all-features
82fn run_clippy(target_dir: &Path) -> Result<StepResult, VerifyError> {
83    let output = Command::new("cargo")
84        .arg("clippy")
85        .arg("--all-targets")
86        .arg("--all-features")
87        .current_dir(target_dir)
88        .output()?;
89
90    if output.status.success() {
91        Ok(StepResult::Pass)
92    } else {
93        let stderr = String::from_utf8_lossy(&output.stderr);
94        let stdout = String::from_utf8_lossy(&output.stdout);
95        let message = format!("{}\n{}", stdout, stderr).trim().to_string();
96        Ok(StepResult::Fail(message))
97    }
98}
99
100/// Run cargo nextest run
101fn run_tests(target_dir: &Path) -> Result<StepResult, VerifyError> {
102    // First check if cargo-nextest is available
103    let nextest_check = Command::new("cargo")
104        .arg("nextest")
105        .arg("--version")
106        .output();
107
108    match nextest_check {
109        Ok(output) if output.status.success() => {
110            // cargo-nextest is available, run tests
111            let test_output = Command::new("cargo")
112                .arg("nextest")
113                .arg("run")
114                .current_dir(target_dir)
115                .output()?;
116
117            if test_output.status.success() {
118                Ok(StepResult::Pass)
119            } else {
120                let stderr = String::from_utf8_lossy(&test_output.stderr);
121                let stdout = String::from_utf8_lossy(&test_output.stdout);
122                let message = format!("{}\n{}", stdout, stderr).trim().to_string();
123                Ok(StepResult::Fail(message))
124            }
125        }
126        Ok(_) | Err(_) => {
127            // cargo-nextest not installed
128            Ok(StepResult::Skip("cargo-nextest not installed".to_string()))
129        }
130    }
131}