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}