syncable_cli/analyzer/hadolint/formatter/
gnu.rs

1//! GNU formatter for hadolint-rs.
2//!
3//! Outputs lint results in GNU compiler-style format for editor integration.
4//! Format: filename:line:column: severity: message [code]
5
6use crate::analyzer::hadolint::formatter::Formatter;
7use crate::analyzer::hadolint::lint::LintResult;
8use crate::analyzer::hadolint::types::Severity;
9use std::io::Write;
10
11/// GNU compiler-style output formatter.
12#[derive(Debug, Clone, Default)]
13pub struct GnuFormatter;
14
15impl GnuFormatter {
16    /// Create a new GNU formatter.
17    pub fn new() -> Self {
18        Self
19    }
20}
21
22impl Formatter for GnuFormatter {
23    fn format<W: Write>(&self, result: &LintResult, filename: &str, writer: &mut W) -> std::io::Result<()> {
24        for failure in &result.failures {
25            let severity_str = match failure.severity {
26                Severity::Error => "error",
27                Severity::Warning => "warning",
28                Severity::Info => "info",
29                Severity::Style => "style",
30                Severity::Ignore => "note",
31            };
32
33            // GNU format: file:line:column: severity: message [code]
34            if let Some(col) = failure.column {
35                writeln!(
36                    writer,
37                    "{}:{}:{}: {}: {} [{}]",
38                    filename,
39                    failure.line,
40                    col,
41                    severity_str,
42                    failure.message,
43                    failure.code
44                )?;
45            } else {
46                writeln!(
47                    writer,
48                    "{}:{}: {}: {} [{}]",
49                    filename,
50                    failure.line,
51                    severity_str,
52                    failure.message,
53                    failure.code
54                )?;
55            }
56        }
57        Ok(())
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64    use crate::analyzer::hadolint::types::CheckFailure;
65
66    #[test]
67    fn test_gnu_output() {
68        let mut result = LintResult::new();
69        result.failures.push(CheckFailure::new(
70            "DL3008",
71            Severity::Warning,
72            "Pin versions in apt get install",
73            5,
74        ));
75
76        let formatter = GnuFormatter::new();
77        let output = formatter.format_to_string(&result, "Dockerfile");
78
79        assert_eq!(
80            output.trim(),
81            "Dockerfile:5: warning: Pin versions in apt get install [DL3008]"
82        );
83    }
84
85    #[test]
86    fn test_gnu_output_with_column() {
87        let mut result = LintResult::new();
88        result.failures.push(CheckFailure::with_column(
89            "DL3008",
90            Severity::Warning,
91            "Pin versions",
92            5,
93            10,
94        ));
95
96        let formatter = GnuFormatter::new();
97        let output = formatter.format_to_string(&result, "Dockerfile");
98
99        assert!(output.contains("Dockerfile:5:10:"));
100    }
101}