pipedash_core/domain/
provider.rs1use std::collections::HashMap;
2
3use async_trait::async_trait;
4use serde::{
5 Deserialize,
6 Serialize,
7};
8
9use super::error::{
10 DomainResult,
11 FailureKind,
12};
13use super::health::ProviderHealth;
14use super::pipeline::{
15 Pipeline,
16 PipelineRun,
17 TriggerParams,
18};
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct ProviderConfig {
22 pub id: Option<i64>,
23 pub name: String,
24 pub provider_type: String,
25 pub token: String,
26 pub config: HashMap<String, String>,
27 #[serde(default = "default_refresh_interval")]
28 pub refresh_interval: i64,
29 #[serde(default)]
30 pub version: Option<i64>,
31}
32
33fn default_refresh_interval() -> i64 {
34 30
35}
36
37impl ProviderConfig {
38 pub fn display_name(&self) -> &str {
39 self.config
40 .get("display_name")
41 .map(|s| s.as_str())
42 .unwrap_or(&self.name)
43 }
44}
45
46#[derive(Debug, Clone, Serialize, Deserialize)]
47#[serde(rename_all = "lowercase")]
48pub enum FetchStatus {
49 Success,
50 Error,
51 Never,
52}
53
54#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
55pub struct ProviderImportResult {
56 pub added: Vec<String>,
57 pub skipped: Vec<String>,
58}
59
60#[derive(Debug, Clone, Serialize, Deserialize)]
61pub struct ProviderSummary {
62 pub id: i64,
63 pub name: String,
64 pub provider_type: String,
65 pub icon: Option<String>,
66 pub pipeline_count: usize,
67 pub last_updated: Option<chrono::DateTime<chrono::Utc>>,
68 pub refresh_interval: i64,
69 pub configured_repositories: Vec<String>,
70 pub last_fetch_status: FetchStatus,
71 pub last_fetch_error: Option<String>,
72 pub last_fetch_at: Option<chrono::DateTime<chrono::Utc>>,
73 #[serde(default)]
74 pub paused_until: Option<chrono::DateTime<chrono::Utc>>,
75 #[serde(default)]
76 pub last_fetch_error_kind: Option<FailureKind>,
77 #[serde(default)]
78 pub health: ProviderHealth,
79 pub version: i64,
80}
81
82#[async_trait]
83pub trait Provider: Send + Sync {
84 async fn fetch_pipelines(&self) -> DomainResult<Vec<Pipeline>>;
85
86 async fn fetch_pipelines_paginated(
87 &self, page: usize, page_size: usize,
88 ) -> DomainResult<pipedash_plugin_api::PaginatedResponse<Pipeline>> {
89 use pipedash_plugin_api::PaginatedResponse;
90
91 let all_pipelines = self.fetch_pipelines().await?;
92 let total_count = all_pipelines.len();
93 let start = (page - 1) * page_size;
94 let end = start + page_size;
95
96 let pipelines = if start < total_count {
97 all_pipelines[start..end.min(total_count)].to_vec()
98 } else {
99 Vec::new()
100 };
101
102 Ok(PaginatedResponse::new(
103 pipelines,
104 page,
105 page_size,
106 total_count,
107 ))
108 }
109
110 async fn fetch_run_history(
111 &self, pipeline_id: &str, limit: usize,
112 ) -> DomainResult<Vec<PipelineRun>>;
113
114 async fn fetch_run_details(
115 &self, pipeline_id: &str, run_number: i64,
116 ) -> DomainResult<PipelineRun>;
117
118 async fn trigger_pipeline(&self, params: TriggerParams) -> DomainResult<String>;
119
120 async fn cancel_run(&self, pipeline_id: &str, run_number: i64) -> DomainResult<()>;
121
122 async fn review_run(
123 &self, pipeline_id: &str, run_number: i64, decision: pipedash_plugin_api::ReviewDecision,
124 ) -> DomainResult<()>;
125
126 async fn get_workflow_parameters(
127 &self, workflow_id: &str,
128 ) -> DomainResult<Vec<pipedash_plugin_api::WorkflowParameter>>;
129
130 async fn fetch_rate_limit(&self) -> DomainResult<Option<pipedash_plugin_api::RateLimit>>;
131
132 #[allow(dead_code)]
133 async fn validate_credentials(&self) -> DomainResult<bool>;
134
135 #[allow(dead_code)]
136 fn provider_type(&self) -> &str;
137
138 fn capabilities(&self) -> &pipedash_plugin_api::PluginCapabilities;
139
140 fn status_source(&self) -> Option<&pipedash_plugin_api::StatusSource>;
141
142 async fn check_health(&self) -> DomainResult<Vec<pipedash_plugin_api::ComponentHealth>>;
143}