1use chrono::{DateTime, Utc};
6use schemars::JsonSchema as DeriveJsonSchema;
7use serde::{Deserialize, Serialize};
8use uuid::Uuid;
9
10use crate::executor::SnapshotRef;
11
12#[derive(
13 Debug,
14 Clone,
15 Copy,
16 PartialEq,
17 Eq,
18 Serialize,
19 Deserialize,
20 DeriveJsonSchema,
21 derive_more::IsVariant,
22)]
23#[serde(rename_all = "snake_case")]
24pub enum StdStream {
25 Stdout,
26 Stderr,
27}
28
29#[derive(
30 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, DeriveJsonSchema, derive_more::IsVariant,
31)]
32#[serde(tag = "kind", rename_all = "snake_case")]
33#[non_exhaustive]
34pub enum BuildEvent {
35 BuildStart {
36 run_id: Uuid,
37 plan: PlanSummary,
38 started_at: DateTime<Utc>,
39 },
40 BuildAccepted {
43 build: BuildRef,
44 watch_url: Option<String>,
45 },
46 StepQueued {
47 step_id: Uuid,
48 key: String,
49 chain_idx: usize,
50 parent_key: Option<String>,
53 display_name: String,
56 },
57 StepStart {
58 step_id: Uuid,
59 runner: String,
60 image: Option<String>,
61 },
62 StepLog {
63 step_id: Uuid,
64 stream: StdStream,
65 line: String,
66 ts: DateTime<Utc>,
67 },
68 StepCacheHit {
69 step_id: Uuid,
70 key: String,
71 tag: String,
72 },
73 StepEnd {
74 step_id: Uuid,
75 exit_code: i32,
76 duration_ms: u64,
77 snapshot: Option<SnapshotRef>,
78 },
79 ChainFailed {
84 chain_idx: usize,
85 failed_step_id: Uuid,
86 failed_step_key: String,
87 exit_code: i32,
88 message: String,
89 ts: DateTime<Utc>,
90 },
91 BuildEnd {
92 exit_code: i32,
93 duration_ms: u64,
94 },
95}
96
97#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, DeriveJsonSchema)]
100pub struct BuildRef {
101 pub run_id: Uuid,
102 pub number: Option<i64>,
103 pub org: Option<String>,
104 pub pipeline: String,
105}
106
107#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, DeriveJsonSchema)]
110pub struct PlanSummary {
111 pub step_count: usize,
112 pub chain_count: usize,
113 pub default_runner: String,
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119
120 #[allow(clippy::unwrap_used)]
121 #[test]
122 fn build_accepted_round_trips() {
123 let ev = BuildEvent::BuildAccepted {
124 build: BuildRef {
125 run_id: uuid::Uuid::nil(),
126 number: Some(42),
127 org: Some("acme".into()),
128 pipeline: "ci".into(),
129 },
130 watch_url: Some("https://app.harmont.dev/acme/ci/builds/42".into()),
131 };
132 let s = serde_json::to_string(&ev).unwrap();
133 let back: BuildEvent = serde_json::from_str(&s).unwrap();
134 assert!(matches!(back, BuildEvent::BuildAccepted { .. }));
135 }
136}