Skip to main content

bb_cli/api/
models.rs

1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Deserialize)]
4pub struct User {
5    pub uuid: Option<String>,
6    pub display_name: Option<String>,
7    pub nickname: Option<String>,
8}
9
10#[derive(Debug, Deserialize)]
11pub struct BranchName {
12    pub name: Option<String>,
13}
14
15#[derive(Debug, Deserialize)]
16pub struct Endpoint {
17    pub branch: Option<BranchName>,
18}
19
20#[derive(Debug, Deserialize)]
21pub struct Link {
22    pub href: Option<String>,
23}
24
25#[derive(Debug, Deserialize)]
26pub struct Links {
27    pub html: Option<Link>,
28}
29
30#[derive(Debug, Deserialize)]
31pub struct Participant {
32    pub user: Option<User>,
33    pub state: Option<String>,
34}
35
36#[derive(Debug, Deserialize)]
37pub struct PullRequest {
38    pub id: u64,
39    pub title: Option<String>,
40    pub state: Option<String>,
41    pub author: Option<User>,
42    pub source: Option<Endpoint>,
43    pub destination: Option<Endpoint>,
44    pub links: Option<Links>,
45    #[serde(default)]
46    pub reviewers: Vec<User>,
47    #[serde(default)]
48    pub participants: Vec<Participant>,
49}
50
51impl PullRequest {
52    pub fn source_branch(&self) -> &str {
53        self.source
54            .as_ref()
55            .and_then(|e| e.branch.as_ref())
56            .and_then(|b| b.name.as_deref())
57            .unwrap_or("-")
58    }
59
60    pub fn destination_branch(&self) -> &str {
61        self.destination
62            .as_ref()
63            .and_then(|e| e.branch.as_ref())
64            .and_then(|b| b.name.as_deref())
65            .unwrap_or("-")
66    }
67
68    pub fn html_url(&self) -> &str {
69        self.links
70            .as_ref()
71            .and_then(|l| l.html.as_ref())
72            .and_then(|l| l.href.as_deref())
73            .unwrap_or("-")
74    }
75
76    pub fn author_name(&self) -> &str {
77        self.author
78            .as_ref()
79            .and_then(|a| a.nickname.as_deref().or(a.display_name.as_deref()))
80            .unwrap_or("-")
81    }
82}
83
84#[derive(Debug, Deserialize)]
85pub struct CommentContent {
86    pub raw: Option<String>,
87}
88
89#[derive(Debug, Deserialize)]
90pub struct Inline {
91    pub path: Option<String>,
92    pub from: Option<u64>,
93    pub to: Option<u64>,
94}
95
96#[derive(Debug, Deserialize)]
97pub struct Comment {
98    pub id: u64,
99    pub content: Option<CommentContent>,
100    pub user: Option<User>,
101    pub created_on: Option<String>,
102    pub inline: Option<Inline>,
103    #[serde(default)]
104    pub deleted: bool,
105    /// Present (even as `{}`) when the inline thread has been resolved.
106    pub resolution: Option<serde_json::Value>,
107}
108
109impl Comment {
110    pub fn is_inline(&self) -> bool {
111        self.inline
112            .as_ref()
113            .and_then(|i| i.path.as_deref())
114            .is_some_and(|p| !p.is_empty())
115    }
116
117    pub fn is_resolved(&self) -> bool {
118        self.resolution.is_some()
119    }
120
121    pub fn body(&self) -> String {
122        if self.deleted {
123            return "[deleted]".to_string();
124        }
125        self.content
126            .as_ref()
127            .and_then(|c| c.raw.clone())
128            .unwrap_or_default()
129    }
130
131    pub fn author(&self) -> &str {
132        self.user
133            .as_ref()
134            .and_then(|u| u.display_name.as_deref())
135            .unwrap_or("Unknown")
136    }
137}
138
139#[derive(Debug, Deserialize)]
140pub struct CommitAuthor {
141    pub user: Option<User>,
142    pub raw: Option<String>,
143}
144
145#[derive(Debug, Deserialize)]
146pub struct CommitTarget {
147    pub author: Option<CommitAuthor>,
148    pub date: Option<String>,
149}
150
151#[derive(Debug, Deserialize)]
152pub struct BranchRef {
153    pub name: String,
154    pub target: Option<CommitTarget>,
155}
156
157impl BranchRef {
158    pub fn owner(&self) -> String {
159        self.target
160            .as_ref()
161            .and_then(|t| t.author.as_ref())
162            .and_then(|a| {
163                a.user
164                    .as_ref()
165                    .and_then(|u| u.display_name.clone())
166                    .or_else(|| a.raw.clone())
167            })
168            .unwrap_or_else(|| "-".to_string())
169    }
170}
171
172#[derive(Debug, Deserialize)]
173pub struct CommitSummary {
174    pub raw: Option<String>,
175}
176
177#[derive(Debug, Deserialize)]
178pub struct Commit {
179    pub hash: Option<String>,
180    pub summary: Option<CommitSummary>,
181}
182
183#[derive(Debug, Deserialize)]
184pub struct DiffStatEntry {
185    pub status: Option<String>,
186    #[serde(rename = "new")]
187    pub new_file: Option<PathEntry>,
188    #[serde(rename = "old")]
189    pub old_file: Option<PathEntry>,
190}
191
192#[derive(Debug, Deserialize)]
193pub struct PathEntry {
194    pub path: Option<String>,
195}
196
197impl DiffStatEntry {
198    pub fn path(&self) -> &str {
199        self.new_file
200            .as_ref()
201            .and_then(|p| p.path.as_deref())
202            .or_else(|| self.old_file.as_ref().and_then(|p| p.path.as_deref()))
203            .unwrap_or("-")
204    }
205}
206
207#[derive(Debug, Serialize)]
208pub struct ReviewerRef {
209    pub uuid: String,
210}