Skip to main content

fallow_output/
pr_decision.rs

1use serde::{Deserialize, Serialize};
2
3pub const PR_DECISION_SCHEMA: &str = "fallow-pr-decision/v1";
4
5#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
6pub struct PrDecisionSurface {
7    pub schema: String,
8    pub title: String,
9    pub conclusion: PrDecisionConclusion,
10    pub gates: Vec<PrDecisionGate>,
11    pub annotations: Vec<PrDecisionAnnotation>,
12    pub details: PrDecisionDetails,
13}
14
15#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
16#[serde(rename_all = "snake_case")]
17pub enum PrDecisionConclusion {
18    Success,
19    Failure,
20    Neutral,
21    Skipped,
22}
23
24#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
25pub struct PrDecisionGate {
26    pub id: String,
27    pub label: String,
28    pub status: PrDecisionConclusion,
29    pub observed: String,
30    pub threshold: Option<String>,
31    pub scope: String,
32}
33
34#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
35pub struct PrDecisionAnnotation {
36    pub path: String,
37    pub line: u32,
38    pub level: PrDecisionAnnotationLevel,
39    pub title: String,
40    pub message: String,
41    pub raw_details: Option<String>,
42}
43
44#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
45#[serde(rename_all = "snake_case")]
46pub enum PrDecisionAnnotationLevel {
47    Notice,
48    Warning,
49    Failure,
50}
51
52#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
53pub struct PrDecisionDetails {
54    pub summary_markdown: String,
55    pub full_report_path: Option<String>,
56    pub details_url: Option<String>,
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62
63    #[test]
64    fn decision_surface_serializes_stable_schema() {
65        let surface = PrDecisionSurface {
66            schema: PR_DECISION_SCHEMA.to_owned(),
67            title: "Fallow".to_owned(),
68            conclusion: PrDecisionConclusion::Failure,
69            gates: vec![PrDecisionGate {
70                id: "duplication".to_owned(),
71                label: "Duplication".to_owned(),
72                status: PrDecisionConclusion::Failure,
73                observed: "9.1% on changed code".to_owned(),
74                threshold: Some("<= 3%".to_owned()),
75                scope: "new code".to_owned(),
76            }],
77            annotations: vec![PrDecisionAnnotation {
78                path: "src/app.ts".to_owned(),
79                line: 42,
80                level: PrDecisionAnnotationLevel::Warning,
81                title: "Duplication".to_owned(),
82                message: "Clone group found".to_owned(),
83                raw_details: Some("fallow/code-duplication".to_owned()),
84            }],
85            details: PrDecisionDetails {
86                summary_markdown: "Quality gate failed".to_owned(),
87                full_report_path: None,
88                details_url: None,
89            },
90        };
91
92        let json = serde_json::to_value(surface).expect("serializes");
93        assert_eq!(json["schema"], PR_DECISION_SCHEMA);
94        assert_eq!(json["conclusion"], "failure");
95        assert_eq!(json["annotations"][0]["level"], "warning");
96    }
97}