git_internal/internal/object/
evidence.rs1use std::fmt;
13
14use serde::{Deserialize, Serialize};
15use uuid::Uuid;
16
17use crate::{
18 errors::GitError,
19 hash::ObjectHash,
20 internal::object::{
21 ObjectTrait,
22 types::{ActorRef, ArtifactRef, Header, ObjectType},
23 },
24};
25
26#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
28#[serde(rename_all = "snake_case")]
29pub enum EvidenceKind {
30 Test,
32 Lint,
34 Build,
36 #[serde(untagged)]
37 Other(String),
38}
39
40impl fmt::Display for EvidenceKind {
41 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42 match self {
43 EvidenceKind::Test => write!(f, "test"),
44 EvidenceKind::Lint => write!(f, "lint"),
45 EvidenceKind::Build => write!(f, "build"),
46 EvidenceKind::Other(s) => write!(f, "{}", s),
47 }
48 }
49}
50
51impl From<String> for EvidenceKind {
52 fn from(s: String) -> Self {
53 match s.as_str() {
54 "test" => EvidenceKind::Test,
55 "lint" => EvidenceKind::Lint,
56 "build" => EvidenceKind::Build,
57 _ => EvidenceKind::Other(s),
58 }
59 }
60}
61
62impl From<&str> for EvidenceKind {
63 fn from(s: &str) -> Self {
64 match s {
65 "test" => EvidenceKind::Test,
66 "lint" => EvidenceKind::Lint,
67 "build" => EvidenceKind::Build,
68 _ => EvidenceKind::Other(s.to_string()),
69 }
70 }
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize)]
76pub struct Evidence {
77 #[serde(flatten)]
78 header: Header,
79 run_id: Uuid,
80 patchset_id: Option<Uuid>,
81 kind: EvidenceKind,
82 tool: String,
83 command: Option<String>,
84 exit_code: Option<i32>,
85 summary: Option<String>, #[serde(default)]
87 report_artifacts: Vec<ArtifactRef>,
88}
89
90impl Evidence {
91 pub fn new(
92 repo_id: Uuid,
93 created_by: ActorRef,
94 run_id: Uuid,
95 kind: impl Into<EvidenceKind>,
96 tool: impl Into<String>,
97 ) -> Result<Self, String> {
98 Ok(Self {
99 header: Header::new(ObjectType::Evidence, repo_id, created_by)?,
100 run_id,
101 patchset_id: None,
102 kind: kind.into(),
103 tool: tool.into(),
104 command: None,
105 exit_code: None,
106 summary: None,
107 report_artifacts: Vec::new(),
108 })
109 }
110
111 pub fn header(&self) -> &Header {
112 &self.header
113 }
114
115 pub fn run_id(&self) -> Uuid {
116 self.run_id
117 }
118
119 pub fn patchset_id(&self) -> Option<Uuid> {
120 self.patchset_id
121 }
122
123 pub fn kind(&self) -> &EvidenceKind {
124 &self.kind
125 }
126
127 pub fn tool(&self) -> &str {
128 &self.tool
129 }
130
131 pub fn command(&self) -> Option<&str> {
132 self.command.as_deref()
133 }
134
135 pub fn exit_code(&self) -> Option<i32> {
136 self.exit_code
137 }
138
139 pub fn summary(&self) -> Option<&str> {
140 self.summary.as_deref()
141 }
142
143 pub fn report_artifacts(&self) -> &[ArtifactRef] {
144 &self.report_artifacts
145 }
146
147 pub fn set_patchset_id(&mut self, patchset_id: Option<Uuid>) {
148 self.patchset_id = patchset_id;
149 }
150
151 pub fn set_command(&mut self, command: Option<String>) {
152 self.command = command;
153 }
154
155 pub fn set_exit_code(&mut self, exit_code: Option<i32>) {
156 self.exit_code = exit_code;
157 }
158
159 pub fn set_summary(&mut self, summary: Option<String>) {
160 self.summary = summary;
161 }
162
163 pub fn add_report_artifact(&mut self, artifact: ArtifactRef) {
164 self.report_artifacts.push(artifact);
165 }
166}
167
168impl fmt::Display for Evidence {
169 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
170 write!(f, "Evidence: {}", self.header.object_id())
171 }
172}
173
174impl ObjectTrait for Evidence {
175 fn from_bytes(data: &[u8], _hash: ObjectHash) -> Result<Self, GitError>
176 where
177 Self: Sized,
178 {
179 serde_json::from_slice(data).map_err(|e| GitError::InvalidObjectInfo(e.to_string()))
180 }
181
182 fn get_type(&self) -> ObjectType {
183 ObjectType::Evidence
184 }
185
186 fn get_size(&self) -> usize {
187 serde_json::to_vec(self).map(|v| v.len()).unwrap_or(0)
188 }
189
190 fn to_data(&self) -> Result<Vec<u8>, GitError> {
191 serde_json::to_vec(self).map_err(|e| GitError::InvalidObjectInfo(e.to_string()))
192 }
193}
194
195#[cfg(test)]
196mod tests {
197 use super::*;
198
199 #[test]
200 fn test_evidence_fields() {
201 let repo_id = Uuid::from_u128(0x0123456789abcdef0123456789abcdef);
202 let actor = ActorRef::agent("test-agent").expect("actor");
203 let run_id = Uuid::from_u128(0x1);
204 let patchset_id = Uuid::from_u128(0x2);
205
206 let mut evidence =
207 Evidence::new(repo_id, actor, run_id, "test", "cargo").expect("evidence");
208 evidence.set_patchset_id(Some(patchset_id));
209 evidence.set_exit_code(Some(1));
210 evidence.add_report_artifact(ArtifactRef::new("local", "log.txt").expect("artifact"));
211
212 assert_eq!(evidence.patchset_id(), Some(patchset_id));
213 assert_eq!(evidence.exit_code(), Some(1));
214 assert_eq!(evidence.report_artifacts().len(), 1);
215 assert_eq!(evidence.kind(), &EvidenceKind::Test);
216 }
217}