1use std::collections::HashMap;
2
3use chrono::{
4 DateTime,
5 Utc,
6};
7use serde::{
8 Deserialize,
9 Serialize,
10};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
13#[serde(rename_all = "lowercase")]
14pub enum PipelineStatus {
15 Success,
16 Failed,
17 Running,
18 Pending,
19 Cancelled,
20 Skipped,
21}
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
24#[serde(rename_all = "lowercase")]
25pub enum ReviewDecision {
26 Approve,
27 Reject,
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize)]
31pub struct AvailablePipeline {
32 pub id: String,
33 pub name: String,
34 pub description: Option<String>,
35 pub organization: Option<String>,
36 pub repository: Option<String>,
37}
38
39#[derive(Debug, Clone, Serialize, Deserialize)]
40pub struct Pipeline {
41 pub id: String,
42 pub provider_id: i64,
43 pub provider_type: String,
44 pub name: String,
45 pub status: PipelineStatus,
46 pub last_run: Option<DateTime<Utc>>,
47 pub last_updated: DateTime<Utc>,
48 pub repository: String,
49 pub branch: Option<String>,
50 pub workflow_file: Option<String>,
51 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
52 pub metadata: HashMap<String, serde_json::Value>,
53}
54
55#[derive(Debug, Clone, Serialize, Deserialize)]
56pub struct PipelineRun {
57 pub id: String,
58 pub pipeline_id: String,
59 pub run_number: i64,
60 pub status: PipelineStatus,
61 pub started_at: DateTime<Utc>,
62 pub concluded_at: Option<DateTime<Utc>>,
63 pub duration_seconds: Option<i64>,
64 pub logs_url: String,
65 pub commit_sha: Option<String>,
66 pub commit_message: Option<String>,
67 pub branch: Option<String>,
68 pub actor: Option<String>,
69 #[serde(skip_serializing_if = "Option::is_none")]
70 pub inputs: Option<serde_json::Value>,
71 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
72 pub metadata: HashMap<String, serde_json::Value>,
73}
74
75#[derive(Debug, Clone, Serialize, Deserialize)]
76pub struct TriggerParams {
77 pub workflow_id: String,
78 pub inputs: Option<serde_json::Value>,
79}
80
81#[derive(Debug, Clone, Serialize, Deserialize)]
82pub struct BuildAgent {
83 pub id: String,
84 pub name: String,
85 pub hostname: String,
86 pub status: String,
87 pub job_id: Option<String>,
88 pub last_seen: DateTime<Utc>,
89 pub metadata: HashMap<String, String>,
90}
91
92#[derive(Debug, Clone, Serialize, Deserialize)]
93pub struct BuildQueue {
94 pub id: String,
95 pub waiting: usize,
96 pub running: usize,
97 pub avg_wait_time: Option<i64>,
98}
99
100#[derive(Debug, Clone, Serialize, Deserialize)]
101pub struct BuildArtifact {
102 pub id: String,
103 pub run_id: String,
104 pub filename: String,
105 pub size_bytes: i64,
106 pub download_url: String,
107 pub content_type: Option<String>,
108 pub created_at: DateTime<Utc>,
109}
110
111#[derive(Debug, Clone, Serialize, Deserialize)]
112pub struct Organization {
113 pub id: String,
114 pub name: String,
115 pub description: Option<String>,
116}
117
118#[derive(Debug, Clone, Serialize, Deserialize)]
119#[serde(tag = "type", rename_all = "lowercase")]
120pub enum WorkflowParameterType {
121 String {
122 #[serde(default)]
123 default: Option<String>,
124 },
125 Boolean {
126 #[serde(default)]
127 default: bool,
128 },
129 Choice {
130 options: Vec<String>,
131 #[serde(default)]
132 default: Option<String>,
133 },
134 Number {
135 #[serde(default)]
136 default: Option<f64>,
137 },
138}
139
140#[derive(Debug, Clone, Serialize, Deserialize)]
141pub struct WorkflowParameter {
142 pub name: String,
143 pub label: Option<String>,
144 pub description: Option<String>,
145 #[serde(flatten)]
146 pub param_type: WorkflowParameterType,
147 #[serde(default)]
148 pub required: bool,
149}
150
151#[derive(Debug, Clone, Serialize, Deserialize)]
152pub struct PaginationParams {
153 pub page: usize,
154 pub page_size: usize,
155}
156
157impl PaginationParams {
158 pub fn validate(&self) -> Result<(), String> {
159 if self.page == 0 {
160 return Err("Page must be >= 1".to_string());
161 }
162 if self.page_size == 0 {
163 return Err("Page size must be >= 1".to_string());
164 }
165 if self.page_size > 200 {
166 return Err("Page size must be <= 200".to_string());
167 }
168 Ok(())
169 }
170
171 pub fn calculate_offset(&self) -> Result<usize, String> {
172 self.page
173 .checked_sub(1)
174 .and_then(|p| p.checked_mul(self.page_size))
175 .ok_or_else(|| "Pagination offset overflow".to_string())
176 }
177}
178
179impl Default for PaginationParams {
180 fn default() -> Self {
181 Self {
182 page: 1,
183 page_size: 100,
184 }
185 }
186}
187
188#[derive(Debug, Clone, Serialize, Deserialize)]
189pub struct PaginatedResponse<T> {
190 pub items: Vec<T>,
191 pub page: usize,
192 pub page_size: usize,
193 pub total_count: usize,
194 pub total_pages: usize,
195 pub has_more: bool,
196}
197
198impl<T> PaginatedResponse<T> {
199 pub fn new(items: Vec<T>, page: usize, page_size: usize, total_count: usize) -> Self {
200 let items_count = items.len();
201 let total_pages = if page_size > 0 {
202 total_count.div_ceil(page_size)
203 } else {
204 1
205 };
206 let has_more = items_count == page_size;
207
208 Self {
209 items,
210 page,
211 page_size,
212 total_count,
213 total_pages,
214 has_more,
215 }
216 }
217
218 pub fn empty() -> Self {
219 Self {
220 items: Vec::new(),
221 page: 1,
222 page_size: 100,
223 total_count: 0,
224 total_pages: 0,
225 has_more: false,
226 }
227 }
228}
229
230pub type PaginatedAvailablePipelines = PaginatedResponse<AvailablePipeline>;
231
232#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
233pub struct Permission {
234 pub name: String,
235 pub description: String,
236 pub required: bool,
237}
238
239#[derive(Debug, Clone, Serialize, Deserialize)]
240pub struct PermissionCheck {
241 pub permission: Permission,
242 pub granted: bool,
243}
244
245#[derive(Debug, Clone, Serialize, Deserialize)]
246pub struct PermissionStatus {
247 pub permissions: Vec<PermissionCheck>,
248 pub all_granted: bool,
249 pub checked_at: DateTime<Utc>,
250 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
251 pub metadata: HashMap<String, String>,
252}
253
254#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
255pub struct RateLimit {
256 pub limit: u64,
257 pub remaining: u64,
258 pub reset_at: DateTime<Utc>,
259}
260
261#[derive(Debug, Clone, Serialize, Deserialize)]
262pub struct Feature {
263 pub id: String,
264 pub name: String,
265 pub description: String,
266 pub required_permissions: Vec<String>,
267}
268
269#[derive(Debug, Clone, Serialize, Deserialize)]
270pub struct FeatureAvailability {
271 pub feature: Feature,
272 pub available: bool,
273 pub missing_permissions: Vec<String>,
274}