syncable_cli/analyzer/helmlint/formatter/
mod.rs

1//! Output formatters for helmlint results.
2//!
3//! Provides multiple output formats:
4//! - JSON: Machine-readable format
5//! - Stylish: Human-readable with colors
6//! - GitHub: GitHub Actions annotation format
7
8pub mod github;
9pub mod json;
10pub mod stylish;
11
12use crate::analyzer::helmlint::lint::LintResult;
13
14/// Output format options.
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
16pub enum OutputFormat {
17    /// JSON format for machine parsing
18    Json,
19    /// Human-readable format with colors
20    #[default]
21    Stylish,
22    /// GitHub Actions annotation format
23    Github,
24    /// Compact single-line format
25    Compact,
26}
27
28impl OutputFormat {
29    /// Parse from string.
30    pub fn parse(s: &str) -> Option<Self> {
31        match s.to_lowercase().as_str() {
32            "json" => Some(Self::Json),
33            "stylish" | "default" => Some(Self::Stylish),
34            "github" | "github-actions" => Some(Self::Github),
35            "compact" => Some(Self::Compact),
36            _ => None,
37        }
38    }
39}
40
41/// Format a lint result to stdout.
42pub fn format_result(result: &LintResult, format: OutputFormat) {
43    let output = format_result_to_string(result, format);
44    println!("{}", output);
45}
46
47/// Format a lint result to a string.
48pub fn format_result_to_string(result: &LintResult, format: OutputFormat) -> String {
49    match format {
50        OutputFormat::Json => json::format(result),
51        OutputFormat::Stylish => stylish::format(result),
52        OutputFormat::Github => github::format(result),
53        OutputFormat::Compact => compact_format(result),
54    }
55}
56
57/// Format multiple results.
58pub fn format_results(results: &[LintResult], format: OutputFormat) -> String {
59    match format {
60        OutputFormat::Json => {
61            // Combine into a single JSON array
62            let jsons: Vec<String> = results.iter().map(json::format).collect();
63            format!("[{}]", jsons.join(","))
64        }
65        _ => results
66            .iter()
67            .map(|r| format_result_to_string(r, format))
68            .collect::<Vec<_>>()
69            .join("\n"),
70    }
71}
72
73/// Compact format: one line per failure.
74fn compact_format(result: &LintResult) -> String {
75    let mut lines = Vec::new();
76
77    for failure in &result.failures {
78        lines.push(format!(
79            "{}:{}:{}: {} {}",
80            failure.file.display(),
81            failure.line,
82            failure.column.unwrap_or(1),
83            failure.code,
84            failure.message
85        ));
86    }
87
88    if lines.is_empty() {
89        format!("{}: No issues found", result.chart_path)
90    } else {
91        lines.join("\n")
92    }
93}
94
95#[cfg(test)]
96mod tests {
97    use super::*;
98
99    #[test]
100    fn test_output_format_parse() {
101        assert_eq!(OutputFormat::parse("json"), Some(OutputFormat::Json));
102        assert_eq!(OutputFormat::parse("stylish"), Some(OutputFormat::Stylish));
103        assert_eq!(OutputFormat::parse("github"), Some(OutputFormat::Github));
104        assert_eq!(OutputFormat::parse("compact"), Some(OutputFormat::Compact));
105        assert_eq!(OutputFormat::parse("invalid"), None);
106    }
107}