crev_data/proof/review/
code.rs1use crate::{
2 ParseError, Result, proof, proof::content::ValidationResult, serde_content_serialize,
3 serde_draft_serialize,
4};
5use crev_common::{
6 self,
7 serde::{as_base64, from_base64},
8};
9use derive_builder::Builder;
10use proof::{CommonOps, Content};
11use serde::{Deserialize, Serialize};
12use std::{self, default::Default, fmt, path::PathBuf};
13
14const CURRENT_CODE_REVIEW_PROOF_SERIALIZATION_VERSION: i64 = -1;
15
16fn cur_version() -> i64 {
17 CURRENT_CODE_REVIEW_PROOF_SERIALIZATION_VERSION
18}
19
20#[derive(Clone, Debug, Serialize, Deserialize)]
21pub struct File {
22 pub path: PathBuf,
23 #[serde(serialize_with = "as_base64", deserialize_with = "from_base64")]
24 pub digest: Vec<u8>,
25 #[serde(rename = "digest-type")]
26 #[serde(
27 skip_serializing_if = "proof::equals_default_digest_type",
28 default = "proof::default_digest_type"
29 )]
30 pub digest_type: String,
31}
32
33#[derive(Clone, Builder, Debug, Serialize, Deserialize)]
35pub struct Code {
38 #[serde(flatten)]
39 pub common: proof::Common,
40 #[serde(rename = "package")]
41 pub package: proof::PackageInfo,
42 #[serde(flatten)]
43 #[builder(default = "Default::default()")]
44 pub review: super::Review,
45 #[serde(skip_serializing_if = "String::is_empty", default = "Default::default")]
46 #[builder(default = "Default::default()")]
47 pub comment: String,
48 #[serde(
49 skip_serializing_if = "std::vec::Vec::is_empty",
50 default = "std::vec::Vec::new"
51 )]
52 #[builder(default = "Default::default()")]
53 pub files: Vec<File>,
54 #[serde(skip_serializing_if = "Option::is_none", default, rename = "llm-agent")]
56 #[builder(default)]
57 pub llm_agent: Option<super::LlmAgentInfo>,
58}
59
60impl Code {
61 pub const KIND: &'static str = "code review";
62}
63
64impl CodeBuilder {
65 pub fn from<VALUE: Into<crate::PublicId>>(&mut self, value: VALUE) -> &mut Self {
66 if let Some(ref mut common) = self.common {
67 common.from = value.into();
68 } else {
69 self.common = Some(proof::Common {
70 kind: Some(Code::KIND.into()),
71 version: cur_version(),
72 date: crev_common::now(),
73 from: value.into(),
74 original: None,
75 });
76 }
77 self
78 }
79}
80
81impl proof::CommonOps for Code {
82 fn common(&self) -> &proof::Common {
83 &self.common
84 }
85
86 fn kind(&self) -> &str {
87 self.common.kind.as_deref().unwrap_or(Self::KIND)
89 }
90}
91
92impl fmt::Display for Code {
93 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94 self.serialize_to(f).map_err(|_| fmt::Error)
95 }
96}
97
98#[derive(Clone, Debug, Serialize, Deserialize)]
100pub struct Draft {
101 review: super::Review,
102 #[serde(default = "Default::default")]
103 comment: String,
104}
105
106impl Draft {
107 pub fn parse(s: &str) -> Result<Self> {
108 Ok(serde_yaml::from_str(s).map_err(ParseError::Draft)?)
109 }
110}
111
112impl From<Code> for Draft {
113 fn from(code: Code) -> Self {
114 Draft {
115 review: code.review,
116 comment: code.comment,
117 }
118 }
119}
120
121impl proof::WithReview for Code {
122 fn review(&self) -> &super::Review {
123 &self.review
124 }
125}
126
127impl proof::content::Content for Code {
128 fn validate_data(&self) -> ValidationResult<()> {
129 self.ensure_kind_is(Code::KIND)?;
130 Ok(())
131 }
132
133 fn serialize_to(&self, fmt: &mut dyn std::fmt::Write) -> fmt::Result {
134 serde_content_serialize!(self, fmt);
135 Ok(())
136 }
137}
138
139impl proof::ContentWithDraft for Code {
140 fn to_draft(&self) -> proof::Draft {
141 proof::Draft {
142 title: format!(
143 "Code Review of {} files of {} {}",
144 self.files.len(),
145 self.package.id.id.name,
146 self.package.id.version
147 ),
148 body: Draft::from(self.clone()).to_string(),
149 }
150 }
151
152 fn apply_draft(&self, s: &str) -> Result<Self> {
153 let draft = Draft::parse(s)?;
154
155 let mut copy = self.clone();
156 copy.review = draft.review;
157 copy.comment = draft.comment;
158
159 copy.validate_data()?;
160 Ok(copy)
161 }
162}
163
164impl fmt::Display for Draft {
165 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
166 serde_draft_serialize!(self, fmt);
167 Ok(())
168 }
169}