Skip to main content

opal/gitlab/
graph.rs

1use petgraph::graph::{DiGraph, NodeIndex};
2use std::collections::HashMap;
3use std::path::PathBuf;
4use std::time::Duration;
5
6use super::rules::JobRule;
7
8#[derive(Debug, Clone)]
9pub struct PipelineGraph {
10    pub graph: DiGraph<Job, ()>,
11    pub stages: Vec<StageGroup>,
12    pub defaults: PipelineDefaults,
13    pub workflow: Option<WorkflowConfig>,
14    pub filters: PipelineFilters,
15}
16#[derive(Debug, Clone)]
17pub struct StageGroup {
18    pub name: String,
19    pub jobs: Vec<NodeIndex>,
20}
21#[derive(Debug, Clone)]
22pub struct Job {
23    pub name: String,
24    pub stage: String,
25    pub commands: Vec<String>,
26    pub needs: Vec<JobDependency>,
27    pub explicit_needs: bool,
28    pub dependencies: Vec<String>,
29    pub before_script: Option<Vec<String>>,
30    pub after_script: Option<Vec<String>>,
31    pub inherit_default_image: bool,
32    pub inherit_default_before_script: bool,
33    pub inherit_default_after_script: bool,
34    pub inherit_default_cache: bool,
35    pub inherit_default_services: bool,
36    pub inherit_default_timeout: bool,
37    pub inherit_default_retry: bool,
38    pub inherit_default_interruptible: bool,
39    pub when: Option<String>,
40    pub rules: Vec<JobRule>,
41    pub only: Vec<String>,
42    pub except: Vec<String>,
43    pub artifacts: ArtifactConfig,
44    pub cache: Vec<CacheConfig>,
45    pub image: Option<ImageConfig>,
46    pub variables: HashMap<String, String>,
47    pub services: Vec<ServiceConfig>,
48    pub timeout: Option<Duration>,
49    pub retry: RetryPolicy,
50    pub interruptible: bool,
51    pub resource_group: Option<String>,
52    pub parallel: Option<ParallelConfig>,
53    pub tags: Vec<String>,
54    pub environment: Option<EnvironmentConfig>,
55}
56
57#[derive(Debug, Clone, Default)]
58pub struct ArtifactConfig {
59    pub name: Option<String>,
60    pub paths: Vec<PathBuf>,
61    pub exclude: Vec<String>,
62    pub untracked: bool,
63    pub when: ArtifactWhen,
64    pub expire_in: Option<Duration>,
65    pub report_dotenv: Option<PathBuf>,
66}
67
68#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
69pub enum ArtifactWhen {
70    #[default]
71    OnSuccess,
72    OnFailure,
73    Always,
74}
75#[derive(Debug, Clone, Default)]
76pub struct PipelineDefaults {
77    pub image: Option<ImageConfig>,
78    pub before_script: Vec<String>,
79    pub after_script: Vec<String>,
80    pub variables: HashMap<String, String>,
81    pub cache: Vec<CacheConfig>,
82    pub services: Vec<ServiceConfig>,
83    pub timeout: Option<Duration>,
84    pub retry: RetryPolicy,
85    pub interruptible: bool,
86}
87#[derive(Debug, Clone)]
88pub struct JobDependency {
89    pub job: String,
90    pub needs_artifacts: bool,
91    pub optional: bool,
92    pub source: DependencySource,
93    pub parallel: Option<Vec<HashMap<String, String>>>,
94    pub inline_variant: Option<Vec<String>>,
95}
96
97#[derive(Debug, Clone)]
98pub enum DependencySource {
99    Local,
100    External(ExternalDependency),
101}
102
103#[derive(Debug, Clone)]
104pub struct ExternalDependency {
105    pub project: String,
106    pub reference: String,
107}
108
109#[derive(Debug, Clone)]
110pub struct ServiceConfig {
111    pub image: String,
112    pub aliases: Vec<String>,
113    pub docker_platform: Option<String>,
114    pub docker_user: Option<String>,
115    pub entrypoint: Vec<String>,
116    pub command: Vec<String>,
117    pub variables: HashMap<String, String>,
118}
119
120#[derive(Debug, Clone)]
121pub struct ImageConfig {
122    pub name: String,
123    pub docker_platform: Option<String>,
124    pub docker_user: Option<String>,
125    pub entrypoint: Vec<String>,
126}
127
128#[derive(Debug, Clone, Default)]
129pub struct RetryPolicy {
130    pub max: u32,
131    pub when: Vec<String>,
132    pub exit_codes: Vec<i32>,
133}
134
135#[derive(Debug, Clone)]
136pub enum ParallelConfig {
137    Count(u32),
138    Matrix(Vec<ParallelMatrixEntry>),
139}
140
141#[derive(Debug, Clone)]
142pub struct ParallelMatrixEntry {
143    pub variables: Vec<ParallelVariable>,
144}
145
146#[derive(Debug, Clone)]
147pub struct ParallelVariable {
148    pub name: String,
149    pub values: Vec<String>,
150}
151
152#[derive(Debug, Clone)]
153pub struct EnvironmentConfig {
154    pub name: String,
155    pub url: Option<String>,
156    pub on_stop: Option<String>,
157    pub auto_stop_in: Option<Duration>,
158    pub action: EnvironmentAction,
159}
160
161#[derive(Debug, Clone, Copy, PartialEq, Eq)]
162pub enum EnvironmentAction {
163    Start,
164    Prepare,
165    Stop,
166    Verify,
167    Access,
168}
169
170#[derive(Debug, Clone)]
171pub struct CacheConfig {
172    pub key: CacheKey,
173    pub fallback_keys: Vec<String>,
174    pub paths: Vec<PathBuf>,
175    pub policy: CachePolicy,
176}
177
178#[derive(Debug, Clone, PartialEq, Eq)]
179pub enum CacheKey {
180    Literal(String),
181    Files {
182        files: Vec<PathBuf>,
183        prefix: Option<String>,
184    },
185}
186
187impl Default for CacheKey {
188    fn default() -> Self {
189        Self::Literal("default".to_string())
190    }
191}
192
193impl CacheKey {
194    pub fn describe(&self) -> String {
195        match self {
196            CacheKey::Literal(value) => value.clone(),
197            CacheKey::Files { files, prefix } => {
198                let files_text = files
199                    .iter()
200                    .map(|path| path.display().to_string())
201                    .collect::<Vec<_>>()
202                    .join(", ");
203                if let Some(prefix) = prefix {
204                    format!("{{ files: [{files_text}], prefix: {prefix} }}")
205                } else {
206                    format!("{{ files: [{files_text}] }}")
207                }
208            }
209        }
210    }
211}
212
213#[derive(Debug, Clone, Default)]
214pub struct WorkflowConfig {
215    pub rules: Vec<JobRule>,
216}
217
218#[derive(Debug, Clone, Default)]
219pub struct PipelineFilters {
220    pub only: Vec<String>,
221    pub except: Vec<String>,
222}
223
224#[derive(Debug, Clone, Copy, PartialEq, Eq)]
225pub enum CachePolicy {
226    Pull,
227    Push,
228    PullPush,
229}
230impl CachePolicy {
231    pub(crate) fn from_str(value: &str) -> Self {
232        match value.to_ascii_lowercase().as_str() {
233            "pull" => CachePolicy::Pull,
234            "push" => CachePolicy::Push,
235            _ => CachePolicy::PullPush,
236        }
237    }
238
239    pub fn allows_pull(self) -> bool {
240        matches!(self, CachePolicy::Pull | CachePolicy::PullPush)
241    }
242
243    pub fn allows_push(self) -> bool {
244        matches!(self, CachePolicy::Push | CachePolicy::PullPush)
245    }
246}