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