fallow_output/
pr_decision.rs1use 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}