Skip to main content

buildfix_types/
report.rs

1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Serialize, Deserialize)]
4pub struct BuildfixReport {
5    pub schema: String,
6    pub tool: ReportToolInfo,
7    pub run: ReportRunInfo,
8    pub verdict: ReportVerdict,
9
10    #[serde(default)]
11    pub findings: Vec<ReportFinding>,
12
13    /// Capabilities block for "No Green By Omission" pattern.
14    #[serde(default, skip_serializing_if = "Option::is_none")]
15    pub capabilities: Option<ReportCapabilities>,
16
17    /// Pointers to related artifact files.
18    #[serde(default, skip_serializing_if = "Option::is_none")]
19    pub artifacts: Option<ReportArtifacts>,
20
21    #[serde(default, skip_serializing_if = "Option::is_none")]
22    pub data: Option<serde_json::Value>,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
26pub struct ReportToolInfo {
27    pub name: String,
28    pub version: String,
29
30    #[serde(default, skip_serializing_if = "Option::is_none")]
31    pub commit: Option<String>,
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct ReportRunInfo {
36    pub started_at: String,
37
38    #[serde(default, skip_serializing_if = "Option::is_none")]
39    pub ended_at: Option<String>,
40
41    #[serde(default, skip_serializing_if = "Option::is_none")]
42    pub duration_ms: Option<u64>,
43
44    #[serde(default, skip_serializing_if = "Option::is_none")]
45    pub git_head_sha: Option<String>,
46}
47
48#[derive(Debug, Clone, Serialize, Deserialize)]
49pub struct ReportVerdict {
50    pub status: ReportStatus,
51    pub counts: ReportCounts,
52
53    #[serde(default, skip_serializing_if = "Vec::is_empty")]
54    pub reasons: Vec<String>,
55}
56
57#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
58#[serde(rename_all = "snake_case")]
59pub enum ReportStatus {
60    Pass,
61    Warn,
62    Fail,
63    Skip,
64}
65
66#[derive(Debug, Clone, Default, Serialize, Deserialize)]
67pub struct ReportCounts {
68    pub info: u64,
69    pub warn: u64,
70    pub error: u64,
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize)]
74pub struct ReportFinding {
75    pub severity: ReportSeverity,
76
77    #[serde(default, skip_serializing_if = "Option::is_none")]
78    pub check_id: Option<String>,
79
80    pub code: String,
81    pub message: String,
82
83    #[serde(default, skip_serializing_if = "Option::is_none")]
84    pub location: Option<ReportLocation>,
85
86    #[serde(default, skip_serializing_if = "Option::is_none")]
87    pub fingerprint: Option<String>,
88
89    #[serde(default, skip_serializing_if = "Option::is_none")]
90    pub data: Option<serde_json::Value>,
91}
92
93#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
94#[serde(rename_all = "snake_case")]
95pub enum ReportSeverity {
96    Info,
97    Warn,
98    Error,
99}
100
101#[derive(Debug, Clone, Serialize, Deserialize)]
102pub struct ReportLocation {
103    pub path: String,
104
105    #[serde(default, skip_serializing_if = "Option::is_none")]
106    pub line: Option<u64>,
107
108    #[serde(default, skip_serializing_if = "Option::is_none")]
109    pub col: Option<u64>,
110}
111
112/// Capabilities block for "No Green By Omission" pattern.
113#[derive(Debug, Clone, Default, Serialize, Deserialize)]
114pub struct ReportCapabilities {
115    /// List of check_ids this sensor can emit.
116    #[serde(default, skip_serializing_if = "Vec::is_empty")]
117    pub check_ids: Vec<String>,
118
119    /// Scopes this sensor covers, e.g. ['workspace', 'crate'].
120    #[serde(default, skip_serializing_if = "Vec::is_empty")]
121    pub scopes: Vec<String>,
122
123    /// True if some inputs could not be processed.
124    #[serde(default)]
125    pub partial: bool,
126
127    /// Reason for partial results, if applicable.
128    #[serde(default, skip_serializing_if = "Option::is_none")]
129    pub reason: Option<String>,
130
131    /// Successfully loaded input paths/receipts.
132    #[serde(default, skip_serializing_if = "Vec::is_empty")]
133    pub inputs_available: Vec<String>,
134
135    /// Input paths that failed to load.
136    #[serde(default, skip_serializing_if = "Vec::is_empty")]
137    pub inputs_failed: Vec<InputFailure>,
138}
139
140/// Record of an input that failed to load.
141#[derive(Debug, Clone, Serialize, Deserialize)]
142pub struct InputFailure {
143    pub path: String,
144    pub reason: String,
145}
146
147/// Pointers to related artifact files.
148#[derive(Debug, Clone, Default, Serialize, Deserialize)]
149pub struct ReportArtifacts {
150    #[serde(default, skip_serializing_if = "Option::is_none")]
151    pub plan: Option<String>,
152
153    #[serde(default, skip_serializing_if = "Option::is_none")]
154    pub apply: Option<String>,
155
156    #[serde(default, skip_serializing_if = "Option::is_none")]
157    pub patch: Option<String>,
158
159    #[serde(default, skip_serializing_if = "Option::is_none")]
160    pub comment: Option<String>,
161}