1use crate::receipt::ToolInfo;
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct BuildfixApply {
6 pub schema: String,
7 pub tool: ToolInfo,
8 pub repo: ApplyRepoInfo,
9 pub plan_ref: PlanRef,
10 pub preconditions: ApplyPreconditions,
11 #[serde(default)]
12 pub results: Vec<ApplyResult>,
13 pub summary: ApplySummary,
14
15 #[serde(default, skip_serializing_if = "Option::is_none")]
16 pub auto_commit: Option<AutoCommitInfo>,
17
18 #[serde(default, skip_serializing_if = "Vec::is_empty")]
19 pub errors: Vec<String>,
20}
21
22impl BuildfixApply {
23 pub fn new(tool: ToolInfo, repo: ApplyRepoInfo, plan_ref: PlanRef) -> Self {
24 Self {
25 schema: crate::schema::BUILDFIX_APPLY_V1.to_string(),
26 tool,
27 repo,
28 plan_ref,
29 preconditions: ApplyPreconditions::default(),
30 results: vec![],
31 summary: ApplySummary::default(),
32 auto_commit: None,
33 errors: vec![],
34 }
35 }
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct AutoCommitInfo {
40 pub enabled: bool,
41 pub attempted: bool,
42 pub committed: bool,
43
44 #[serde(default, skip_serializing_if = "Option::is_none")]
45 pub commit_sha: Option<String>,
46
47 #[serde(default, skip_serializing_if = "Option::is_none")]
48 pub message: Option<String>,
49
50 #[serde(default, skip_serializing_if = "Option::is_none")]
51 pub skip_reason: Option<String>,
52}
53
54#[derive(Debug, Clone, Serialize, Deserialize)]
55pub struct ApplyRepoInfo {
56 pub root: String,
57
58 #[serde(default, skip_serializing_if = "Option::is_none")]
59 pub head_sha_before: Option<String>,
60
61 #[serde(default, skip_serializing_if = "Option::is_none")]
62 pub head_sha_after: Option<String>,
63
64 #[serde(default, skip_serializing_if = "Option::is_none")]
65 pub dirty_before: Option<bool>,
66
67 #[serde(default, skip_serializing_if = "Option::is_none")]
68 pub dirty_after: Option<bool>,
69}
70
71#[derive(Debug, Clone, Serialize, Deserialize)]
72pub struct PlanRef {
73 pub path: String,
74
75 #[serde(default, skip_serializing_if = "Option::is_none")]
76 pub sha256: Option<String>,
77}
78
79#[derive(Debug, Clone, Default, Serialize, Deserialize)]
80pub struct ApplyPreconditions {
81 pub verified: bool,
82
83 #[serde(default)]
84 pub mismatches: Vec<PreconditionMismatch>,
85}
86
87#[derive(Debug, Clone, Serialize, Deserialize)]
88pub struct PreconditionMismatch {
89 pub path: String,
90 pub expected: String,
91 pub actual: String,
92}
93
94#[derive(Debug, Clone, Serialize, Deserialize)]
95pub struct ApplyResult {
96 pub op_id: String,
97 pub status: ApplyStatus,
98
99 #[serde(default, skip_serializing_if = "Option::is_none")]
100 pub message: Option<String>,
101
102 #[serde(default, skip_serializing_if = "Option::is_none")]
103 pub blocked_reason: Option<String>,
104
105 #[serde(default, skip_serializing_if = "Option::is_none")]
106 pub blocked_reason_token: Option<String>,
107
108 #[serde(default, skip_serializing_if = "Vec::is_empty")]
109 pub files: Vec<ApplyFile>,
110}
111
112#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
113#[serde(rename_all = "snake_case")]
114pub enum ApplyStatus {
115 Applied,
116 Blocked,
117 Failed,
118 Skipped,
119}
120
121#[derive(Debug, Clone, Serialize, Deserialize)]
122pub struct ApplyFile {
123 pub path: String,
124
125 #[serde(default, skip_serializing_if = "Option::is_none")]
126 pub sha256_before: Option<String>,
127
128 #[serde(default, skip_serializing_if = "Option::is_none")]
129 pub sha256_after: Option<String>,
130
131 #[serde(default, skip_serializing_if = "Option::is_none")]
132 pub backup_path: Option<String>,
133}
134
135#[derive(Debug, Clone, Default, Serialize, Deserialize)]
136pub struct ApplySummary {
137 pub attempted: u64,
138 pub applied: u64,
139 pub blocked: u64,
140 pub failed: u64,
141 pub files_modified: u64,
142}