Skip to main content

fallow_types/
output_format.rs

1/// Output format for fallow results.
2///
3/// This is command-line and integration metadata, not stored in config files.
4/// Keeping it in `fallow-types` lets config, output, CLI, MCP, and API layers
5/// agree on the same contract without creating a config-to-output dependency.
6#[derive(Debug, Default, Clone, Copy)]
7pub enum OutputFormat {
8    /// Human-readable terminal output with source context.
9    #[default]
10    Human,
11    /// Machine-readable JSON.
12    Json,
13    /// SARIF format for GitHub Code Scanning.
14    Sarif,
15    /// One issue per line (grep-friendly).
16    Compact,
17    /// Markdown for PR comments.
18    Markdown,
19    /// `CodeClimate` JSON for GitLab Code Quality.
20    ///
21    /// CLI aliases: `codeclimate`, `gitlab-codequality`, `gitlab-code-quality`.
22    CodeClimate,
23    /// GitHub-flavored sticky PR comment markdown.
24    PrCommentGithub,
25    /// GitLab-flavored sticky MR comment markdown.
26    PrCommentGitlab,
27    /// GitHub PR review JSON envelope.
28    ReviewGithub,
29    /// GitLab MR review JSON envelope.
30    ReviewGitlab,
31    /// Shields.io-compatible SVG badge (health command only).
32    Badge,
33    /// GitHub Actions workflow-command annotations (`::error` / `::warning` /
34    /// `::notice` lines). Provider-prefixed name because workflow-command
35    /// annotations are a GitHub-only concept with no GitLab twin.
36    GithubAnnotations,
37    /// GitHub Actions job-summary markdown (for `>> $GITHUB_STEP_SUMMARY`).
38    /// Provider-prefixed for the same reason as `GithubAnnotations`.
39    GithubSummary,
40}
41
42#[cfg(test)]
43mod tests {
44    use super::*;
45
46    const VARIANTS: [OutputFormat; 13] = [
47        OutputFormat::Human,
48        OutputFormat::Json,
49        OutputFormat::Sarif,
50        OutputFormat::Compact,
51        OutputFormat::Markdown,
52        OutputFormat::CodeClimate,
53        OutputFormat::PrCommentGithub,
54        OutputFormat::PrCommentGitlab,
55        OutputFormat::ReviewGithub,
56        OutputFormat::ReviewGitlab,
57        OutputFormat::Badge,
58        OutputFormat::GithubAnnotations,
59        OutputFormat::GithubSummary,
60    ];
61
62    #[test]
63    fn default_is_human() {
64        assert!(matches!(OutputFormat::default(), OutputFormat::Human));
65    }
66
67    #[test]
68    fn debug_names_remain_stable() {
69        let names: Vec<String> = VARIANTS
70            .iter()
71            .map(|variant| format!("{variant:?}"))
72            .collect();
73        assert_eq!(
74            names,
75            vec![
76                "Human",
77                "Json",
78                "Sarif",
79                "Compact",
80                "Markdown",
81                "CodeClimate",
82                "PrCommentGithub",
83                "PrCommentGitlab",
84                "ReviewGithub",
85                "ReviewGitlab",
86                "Badge",
87                "GithubAnnotations",
88                "GithubSummary",
89            ]
90        );
91    }
92
93    #[test]
94    fn variants_are_distinct() {
95        let names: Vec<String> = VARIANTS
96            .iter()
97            .map(|variant| format!("{variant:?}"))
98            .collect();
99
100        for (i, a) in names.iter().enumerate() {
101            for (j, b) in names.iter().enumerate() {
102                if i != j {
103                    assert_ne!(a, b);
104                }
105            }
106        }
107    }
108}