Skip to main content

workflow_graph_shared/
lib.rs

1pub mod yaml;
2
3use serde::{Deserialize, Serialize};
4
5#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
6#[serde(rename_all = "snake_case")]
7pub enum JobStatus {
8    Queued,
9    Running,
10    Success,
11    Failure,
12    Skipped,
13    Cancelled,
14}
15
16#[derive(Clone, Debug, Serialize, Deserialize)]
17pub struct Job {
18    pub id: String,
19    pub name: String,
20    pub status: JobStatus,
21    pub command: String,
22    pub duration_secs: Option<u64>,
23    /// Epoch milliseconds when the job started running (for live timer).
24    #[serde(default)]
25    pub started_at: Option<f64>,
26    pub depends_on: Vec<String>,
27    pub output: Option<String>,
28    /// Worker labels required to execute this job.
29    #[serde(default)]
30    pub required_labels: Vec<String>,
31    /// Maximum number of retries on failure.
32    #[serde(default)]
33    pub max_retries: u32,
34    /// Current attempt number (0-indexed).
35    #[serde(default)]
36    pub attempt: u32,
37}
38
39#[derive(Clone, Debug, Serialize, Deserialize)]
40pub struct Workflow {
41    pub id: String,
42    pub name: String,
43    pub trigger: String,
44    pub jobs: Vec<Job>,
45}
46
47impl Workflow {
48    /// Returns a sample workflow matching the GitHub Actions screenshot.
49    pub fn sample() -> Self {
50        Workflow {
51            id: "ci-1".into(),
52            name: "ci.yml".into(),
53            trigger: "on: push".into(),
54            jobs: vec![
55                Job {
56                    id: "unit-tests".into(),
57                    name: "Unit Tests".into(),
58                    status: JobStatus::Queued,
59                    command: "echo 'Running unit tests' && sleep 2".into(),
60                    duration_secs: None,
61                    depends_on: vec![],
62                    started_at: None,
63                    output: None,
64                    required_labels: vec![],
65                    max_retries: 0,
66                    attempt: 0,
67                },
68                Job {
69                    id: "lint".into(),
70                    name: "Lint".into(),
71                    status: JobStatus::Queued,
72                    command: "echo 'Running linter' && sleep 1".into(),
73                    duration_secs: None,
74                    depends_on: vec![],
75                    started_at: None,
76                    output: None,
77                    required_labels: vec![],
78                    max_retries: 0,
79                    attempt: 0,
80                },
81                Job {
82                    id: "typecheck".into(),
83                    name: "Typecheck".into(),
84                    status: JobStatus::Queued,
85                    command: "echo 'Running typecheck' && sleep 2".into(),
86                    duration_secs: None,
87                    depends_on: vec![],
88                    started_at: None,
89                    output: None,
90                    required_labels: vec![],
91                    max_retries: 0,
92                    attempt: 0,
93                },
94                Job {
95                    id: "build".into(),
96                    name: "Build".into(),
97                    status: JobStatus::Queued,
98                    command: "echo 'Building project' && sleep 3".into(),
99                    duration_secs: None,
100                    depends_on: vec!["unit-tests".into(), "lint".into(), "typecheck".into()],
101                    started_at: None,
102                    output: None,
103                    required_labels: vec![],
104                    max_retries: 0,
105                    attempt: 0,
106                },
107                Job {
108                    id: "deploy-db".into(),
109                    name: "Deploy DB Migrations".into(),
110                    status: JobStatus::Queued,
111                    command: "echo 'Deploying DB migrations' && sleep 1".into(),
112                    duration_secs: None,
113                    depends_on: vec!["build".into()],
114                    started_at: None,
115                    output: None,
116                    required_labels: vec![],
117                    max_retries: 0,
118                    attempt: 0,
119                },
120                Job {
121                    id: "e2e-tests".into(),
122                    name: "E2E Tests".into(),
123                    status: JobStatus::Queued,
124                    command: "echo 'Running E2E tests' && sleep 5".into(),
125                    duration_secs: None,
126                    depends_on: vec!["build".into()],
127                    started_at: None,
128                    output: None,
129                    required_labels: vec![],
130                    max_retries: 0,
131                    attempt: 0,
132                },
133                Job {
134                    id: "deploy-preview".into(),
135                    name: "Deploy Preview".into(),
136                    status: JobStatus::Queued,
137                    command: "echo 'Deploying preview' && sleep 1".into(),
138                    duration_secs: None,
139                    depends_on: vec!["build".into()],
140                    started_at: None,
141                    output: None,
142                    required_labels: vec![],
143                    max_retries: 0,
144                    attempt: 0,
145                },
146                Job {
147                    id: "deploy-web".into(),
148                    name: "Deploy Web".into(),
149                    status: JobStatus::Queued,
150                    command: "echo 'Deploying to production' && sleep 3".into(),
151                    duration_secs: None,
152                    depends_on: vec!["deploy-db".into()],
153                    started_at: None,
154                    output: None,
155                    required_labels: vec![],
156                    max_retries: 0,
157                    attempt: 0,
158                },
159            ],
160        }
161    }
162}