forge
ExploreLog in

Tahinli/forge

public
0 watching
★ 0
5.1 KiB
1//! CI models: run and job states, runners, runs, jobs and artifacts. The stored shape is in
2//! migrations/0024_ci.sql; the store functions live in store/ci.rs.
3//!
4//! Job specs are kept as JSON text (`CiJob::spec_json`). The store reads only the `needs` and
5//! `runs_on` arrays out of it, so this crate does not depend on forge-ci.
6
7use std::str::FromStr;
8
9use crate::error::{Error, Result};
10
11/// State of a run. Stored as the `as_str` name.
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum RunState {
14 WaitingApproval,
15 Queued,
16 Running,
17 Success,
18 Failure,
19 Cancelled,
20 Error,
21}
22
23impl RunState {
24 pub fn as_str(self) -> &'static str {
25 match self {
26 RunState::WaitingApproval => "waiting_approval",
27 RunState::Queued => "queued",
28 RunState::Running => "running",
29 RunState::Success => "success",
30 RunState::Failure => "failure",
31 RunState::Cancelled => "cancelled",
32 RunState::Error => "error",
33 }
34 }
35
36 /// True for states a run cannot leave.
37 pub fn is_terminal(self) -> bool {
38 matches!(
39 self,
40 RunState::Success | RunState::Failure | RunState::Cancelled | RunState::Error
41 )
42 }
43}
44
45impl FromStr for RunState {
46 type Err = Error;
47
48 fn from_str(s: &str) -> Result<Self> {
49 Ok(match s {
50 "waiting_approval" => RunState::WaitingApproval,
51 "queued" => RunState::Queued,
52 "running" => RunState::Running,
53 "success" => RunState::Success,
54 "failure" => RunState::Failure,
55 "cancelled" => RunState::Cancelled,
56 "error" => RunState::Error,
57 other => return Err(Error::Database(format!("unknown CI run state {other:?}"))),
58 })
59 }
60}
61
62/// State of a job. Stored as the `as_str` name.
63#[derive(Debug, Clone, Copy, PartialEq, Eq)]
64pub enum JobState {
65 Blocked,
66 Queued,
67 Running,
68 Success,
69 Failure,
70 Cancelled,
71 Error,
72 Skipped,
73}
74
75impl JobState {
76 pub fn as_str(self) -> &'static str {
77 match self {
78 JobState::Blocked => "blocked",
79 JobState::Queued => "queued",
80 JobState::Running => "running",
81 JobState::Success => "success",
82 JobState::Failure => "failure",
83 JobState::Cancelled => "cancelled",
84 JobState::Error => "error",
85 JobState::Skipped => "skipped",
86 }
87 }
88
89 /// True for states a job cannot leave.
90 pub fn is_terminal(self) -> bool {
91 matches!(
92 self,
93 JobState::Success
94 | JobState::Failure
95 | JobState::Cancelled
96 | JobState::Error
97 | JobState::Skipped
98 )
99 }
100}
101
102impl FromStr for JobState {
103 type Err = Error;
104
105 fn from_str(s: &str) -> Result<Self> {
106 Ok(match s {
107 "blocked" => JobState::Blocked,
108 "queued" => JobState::Queued,
109 "running" => JobState::Running,
110 "success" => JobState::Success,
111 "failure" => JobState::Failure,
112 "cancelled" => JobState::Cancelled,
113 "error" => JobState::Error,
114 "skipped" => JobState::Skipped,
115 other => return Err(Error::Database(format!("unknown CI job state {other:?}"))),
116 })
117 }
118}
119
120/// A registered runner. The secret and its hash are never part of this type.
121#[derive(Debug, Clone, PartialEq, Eq)]
122pub struct CiRunner {
123 pub id: String,
124 pub name: String,
125 pub labels: Vec<String>,
126 pub created_at: String,
127 pub last_seen_at: Option<String>,
128 pub disabled: bool,
129}
130
131/// One run of the workflow for a commit.
132#[derive(Debug, Clone, PartialEq, Eq)]
133pub struct CiRun {
134 pub id: String,
135 pub repo_id: String,
136 pub number: i64,
137 /// `push`, `tag`, `pull_request` or `manual`.
138 pub trigger: String,
139 pub git_ref: String,
140 pub commit_oid: String,
141 pub pull_number: Option<i64>,
142 pub actor_id: String,
143 pub state: RunState,
144 pub config_error: Option<String>,
145 pub created_at: String,
146 pub finished_at: Option<String>,
147}
148
149/// One job of a run. `spec_json` is the JobSpec as JSON text.
150#[derive(Debug, Clone, PartialEq, Eq)]
151pub struct CiJob {
152 pub id: String,
153 pub run_id: String,
154 pub name: String,
155 pub spec_json: String,
156 pub state: JobState,
157 pub runner_id: Option<String>,
158 pub exit_code: Option<i64>,
159 pub message: Option<String>,
160 pub queued_at: Option<String>,
161 pub started_at: Option<String>,
162 pub finished_at: Option<String>,
163 pub heartbeat_at: Option<String>,
164 pub cancel_requested: bool,
165 pub log_bytes: i64,
166}
167
168/// An artifact uploaded by a job. The file itself is stored outside the database.
169#[derive(Debug, Clone, PartialEq, Eq)]
170pub struct CiArtifact {
171 pub id: String,
172 pub job_id: String,
173 pub name: String,
174 pub size: i64,
175 pub sha256: String,
176 pub created_at: String,
177}
178
179/// A job to create with a run. `needs` must match the `needs` in `spec_json`.
180#[derive(Debug, Clone, Copy)]
181pub struct NewJob<'a> {
182 pub name: &'a str,
183 pub spec_json: &'a str,
184 pub needs: &'a [String],
185}