syncable_cli/analyzer/hadolint/formatter/
mod.rs

1//! Output formatters for hadolint-rs lint results.
2//!
3//! Provides multiple output formats for compatibility with various CI/CD systems:
4//! - **TTY**: Colored terminal output for human readability
5//! - **JSON**: Machine-readable format for CI/CD pipelines
6//! - **SARIF**: Static Analysis Results Interchange Format for GitHub Actions
7//! - **Checkstyle**: XML format for Jenkins and other tools
8//! - **CodeClimate**: JSON format for GitLab CI
9//! - **GNU**: Standard compiler-style output for editors
10
11mod checkstyle;
12mod codeclimate;
13mod gnu;
14mod json;
15mod sarif;
16mod tty;
17
18pub use checkstyle::CheckstyleFormatter;
19pub use codeclimate::CodeClimateFormatter;
20pub use gnu::GnuFormatter;
21pub use json::JsonFormatter;
22pub use sarif::SarifFormatter;
23pub use tty::TtyFormatter;
24
25use crate::analyzer::hadolint::lint::LintResult;
26use std::io::Write;
27
28/// Output format for lint results.
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
30pub enum OutputFormat {
31    /// Colored terminal output (default)
32    #[default]
33    Tty,
34    /// JSON format for CI/CD
35    Json,
36    /// SARIF format for GitHub Actions
37    Sarif,
38    /// Checkstyle XML for Jenkins
39    Checkstyle,
40    /// CodeClimate JSON for GitLab
41    CodeClimate,
42    /// GNU compiler-style output
43    Gnu,
44}
45
46impl OutputFormat {
47    /// Parse format from string (case-insensitive).
48    pub fn from_str(s: &str) -> Option<Self> {
49        match s.to_lowercase().as_str() {
50            "tty" | "terminal" | "color" => Some(Self::Tty),
51            "json" => Some(Self::Json),
52            "sarif" => Some(Self::Sarif),
53            "checkstyle" => Some(Self::Checkstyle),
54            "codeclimate" | "gitlab" => Some(Self::CodeClimate),
55            "gnu" => Some(Self::Gnu),
56            _ => None,
57        }
58    }
59
60    /// Get all available format names.
61    pub fn all_names() -> &'static [&'static str] {
62        &["tty", "json", "sarif", "checkstyle", "codeclimate", "gnu"]
63    }
64}
65
66/// Trait for formatting lint results.
67pub trait Formatter {
68    /// Format the lint result and write to the given writer.
69    fn format<W: Write>(&self, result: &LintResult, filename: &str, writer: &mut W) -> std::io::Result<()>;
70
71    /// Format the lint result to a string.
72    fn format_to_string(&self, result: &LintResult, filename: &str) -> String {
73        let mut buf = Vec::new();
74        self.format(result, filename, &mut buf).unwrap_or_default();
75        String::from_utf8(buf).unwrap_or_default()
76    }
77}
78
79/// Format a lint result using the specified output format.
80pub fn format_result<W: Write>(
81    result: &LintResult,
82    filename: &str,
83    format: OutputFormat,
84    writer: &mut W,
85) -> std::io::Result<()> {
86    match format {
87        OutputFormat::Tty => TtyFormatter::new().format(result, filename, writer),
88        OutputFormat::Json => JsonFormatter::new().format(result, filename, writer),
89        OutputFormat::Sarif => SarifFormatter::new().format(result, filename, writer),
90        OutputFormat::Checkstyle => CheckstyleFormatter::new().format(result, filename, writer),
91        OutputFormat::CodeClimate => CodeClimateFormatter::new().format(result, filename, writer),
92        OutputFormat::Gnu => GnuFormatter::new().format(result, filename, writer),
93    }
94}
95
96/// Format a lint result to a string using the specified output format.
97pub fn format_result_to_string(result: &LintResult, filename: &str, format: OutputFormat) -> String {
98    let mut buf = Vec::new();
99    format_result(result, filename, format, &mut buf).unwrap_or_default();
100    String::from_utf8(buf).unwrap_or_default()
101}