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>(
24        &self,
25        result: &LintResult,
26        filename: &str,
27        writer: &mut W,
28    ) -> std::io::Result<()> {
29        for failure in &result.failures {
30            let severity_str = match failure.severity {
31                Severity::Error => "error",
32                Severity::Warning => "warning",
33                Severity::Info => "info",
34                Severity::Style => "style",
35                Severity::Ignore => "note",
36            };
37
38            // GNU format: file:line:column: severity: message [code]
39            if let Some(col) = failure.column {
40                writeln!(
41                    writer,
42                    "{}:{}:{}: {}: {} [{}]",
43                    filename, failure.line, col, severity_str, failure.message, failure.code
44                )?;
45            } else {
46                writeln!(
47                    writer,
48                    "{}:{}: {}: {} [{}]",
49                    filename, failure.line, severity_str, failure.message, failure.code
50                )?;
51            }
52        }
53        Ok(())
54    }
55}
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60    use crate::analyzer::hadolint::types::CheckFailure;
61
62    #[test]
63    fn test_gnu_output() {
64        let mut result = LintResult::new();
65        result.failures.push(CheckFailure::new(
66            "DL3008",
67            Severity::Warning,
68            "Pin versions in apt get install",
69            5,
70        ));
71
72        let formatter = GnuFormatter::new();
73        let output = formatter.format_to_string(&result, "Dockerfile");
74
75        assert_eq!(
76            output.trim(),
77            "Dockerfile:5: warning: Pin versions in apt get install [DL3008]"
78        );
79    }
80
81    #[test]
82    fn test_gnu_output_with_column() {
83        let mut result = LintResult::new();
84        result.failures.push(CheckFailure::with_column(
85            "DL3008",
86            Severity::Warning,
87            "Pin versions",
88            5,
89            10,
90        ));
91
92        let formatter = GnuFormatter::new();
93        let output = formatter.format_to_string(&result, "Dockerfile");
94
95        assert!(output.contains("Dockerfile:5:10:"));
96    }
97}