Skip to main content

pipedash_plugin_api/
types.rs

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