astro_run/plugins/
plugin.rs

1use crate::{
2  HookBeforeRunStepResult, HookNoopResult, HookResolveActionResult, JobRunResult, Plugin,
3  RunJobEvent, RunStepEvent, RunWorkflowEvent, Step, StepRunResult, UserActionStep, WorkflowLog,
4  WorkflowRunResult, WorkflowStateEvent,
5};
6
7type OnStateChange = dyn Fn(WorkflowStateEvent) -> HookNoopResult + Send + Sync;
8type OnLog = dyn Fn(WorkflowLog) -> HookNoopResult + Send + Sync;
9type OnRunWorkflow = dyn Fn(RunWorkflowEvent) -> HookNoopResult + Send + Sync;
10type OnRunJob = dyn Fn(RunJobEvent) -> HookNoopResult + Send + Sync;
11type OnRunStep = dyn Fn(RunStepEvent) -> HookNoopResult + Send + Sync;
12type OnWorkflowComplete = dyn Fn(WorkflowRunResult) -> HookNoopResult + Send + Sync;
13type OnJobComplete = dyn Fn(JobRunResult) -> HookNoopResult + Send + Sync;
14type OnStepComplete = dyn Fn(StepRunResult) -> HookNoopResult + Send + Sync;
15type OnResolveDynamicAction = dyn Fn(UserActionStep) -> HookResolveActionResult + Send + Sync;
16type OnBeforeRunStep = dyn Fn(Step) -> HookBeforeRunStepResult + Send + Sync;
17
18pub struct PluginBuilder {
19  name: &'static str,
20  on_resolve_dynamic_action: Option<Box<OnResolveDynamicAction>>,
21  on_run_workflow: Option<Box<OnRunWorkflow>>,
22  on_run_job: Option<Box<OnRunJob>>,
23  on_before_run_step: Option<Box<OnBeforeRunStep>>,
24  on_run_step: Option<Box<OnRunStep>>,
25  on_state_change: Option<Box<OnStateChange>>,
26  on_log: Option<Box<OnLog>>,
27  on_step_completed: Option<Box<OnStepComplete>>,
28  on_job_completed: Option<Box<OnJobComplete>>,
29  on_workflow_completed: Option<Box<OnWorkflowComplete>>,
30}
31
32impl PluginBuilder {
33  fn new(name: &'static str) -> Self {
34    PluginBuilder {
35      name,
36      on_resolve_dynamic_action: None,
37      on_state_change: None,
38      on_log: None,
39      on_run_workflow: None,
40      on_run_job: None,
41      on_before_run_step: None,
42      on_run_step: None,
43      on_step_completed: None,
44      on_job_completed: None,
45      on_workflow_completed: None,
46    }
47  }
48
49  pub fn on_state_change<T>(mut self, on_state_change: T) -> Self
50  where
51    T: Fn(WorkflowStateEvent) -> HookNoopResult + 'static + Send + Sync,
52  {
53    self.on_state_change = Some(Box::new(on_state_change));
54    self
55  }
56
57  pub fn on_log<T>(mut self, on_log: T) -> Self
58  where
59    T: Fn(WorkflowLog) -> HookNoopResult + 'static + Send + Sync,
60  {
61    self.on_log = Some(Box::new(on_log));
62    self
63  }
64
65  pub fn on_run_workflow<T>(mut self, on_run_workflow: T) -> Self
66  where
67    T: Fn(RunWorkflowEvent) -> HookNoopResult + 'static + Send + Sync,
68  {
69    self.on_run_workflow = Some(Box::new(on_run_workflow));
70    self
71  }
72
73  pub fn on_run_job<T>(mut self, on_run_job: T) -> Self
74  where
75    T: Fn(RunJobEvent) -> HookNoopResult + 'static + Send + Sync,
76  {
77    self.on_run_job = Some(Box::new(on_run_job));
78    self
79  }
80
81  pub fn on_run_step<T>(mut self, on_run_step: T) -> Self
82  where
83    T: Fn(RunStepEvent) -> HookNoopResult + 'static + Send + Sync,
84  {
85    self.on_run_step = Some(Box::new(on_run_step));
86    self
87  }
88
89  pub fn on_workflow_completed<T>(mut self, on_workflow_completed: T) -> Self
90  where
91    T: Fn(WorkflowRunResult) -> HookNoopResult + Send + Sync + 'static,
92  {
93    self.on_workflow_completed = Some(Box::new(on_workflow_completed));
94
95    self
96  }
97
98  pub fn on_job_completed<T>(mut self, on_job_completed: T) -> Self
99  where
100    T: Fn(JobRunResult) -> HookNoopResult + Send + Sync + 'static,
101  {
102    self.on_job_completed = Some(Box::new(on_job_completed));
103
104    self
105  }
106
107  pub fn on_step_completed<T>(mut self, on_step_completed: T) -> Self
108  where
109    T: Fn(StepRunResult) -> HookNoopResult + Send + Sync + 'static,
110  {
111    self.on_step_completed = Some(Box::new(on_step_completed));
112
113    self
114  }
115
116  pub fn on_resolve_dynamic_action<T>(mut self, on_resolve_dynamic_action: T) -> Self
117  where
118    T: Fn(UserActionStep) -> HookResolveActionResult + Send + Sync + 'static,
119  {
120    self.on_resolve_dynamic_action = Some(Box::new(on_resolve_dynamic_action));
121
122    self
123  }
124
125  pub fn on_before_run_step<T>(mut self, on_before_run_step: T) -> Self
126  where
127    T: Fn(Step) -> HookBeforeRunStepResult + Send + Sync + 'static,
128  {
129    self.on_before_run_step = Some(Box::new(on_before_run_step));
130
131    self
132  }
133
134  pub fn build(self) -> AstroRunPlugin {
135    AstroRunPlugin {
136      name: self.name,
137      on_state_change: self.on_state_change,
138      on_log: self.on_log,
139      on_run_workflow: self.on_run_workflow,
140      on_run_job: self.on_run_job,
141      on_run_step: self.on_run_step,
142      on_workflow_completed: self.on_workflow_completed,
143      on_job_completed: self.on_job_completed,
144      on_step_completed: self.on_step_completed,
145      on_resolve_dynamic_action: self.on_resolve_dynamic_action,
146      on_before_run_step: self.on_before_run_step,
147    }
148  }
149}
150
151/// `AstroRunPlugin` enables rapid definition of a synchronous astro-run plugin
152/// without the need to declare a new struct to implement the `Plugin` trait.
153pub struct AstroRunPlugin {
154  name: &'static str,
155  on_resolve_dynamic_action: Option<Box<OnResolveDynamicAction>>,
156  on_run_workflow: Option<Box<OnRunWorkflow>>,
157  on_run_job: Option<Box<OnRunJob>>,
158  on_before_run_step: Option<Box<OnBeforeRunStep>>,
159  on_run_step: Option<Box<OnRunStep>>,
160  on_state_change: Option<Box<OnStateChange>>,
161  on_log: Option<Box<OnLog>>,
162  on_step_completed: Option<Box<OnStepComplete>>,
163  on_job_completed: Option<Box<OnJobComplete>>,
164  on_workflow_completed: Option<Box<OnWorkflowComplete>>,
165}
166
167impl AstroRunPlugin {
168  pub fn builder(name: &'static str) -> PluginBuilder {
169    PluginBuilder::new(name)
170  }
171}
172
173#[async_trait::async_trait]
174impl Plugin for AstroRunPlugin {
175  fn name(&self) -> &'static str {
176    self.name
177  }
178
179  async fn on_state_change(&self, event: WorkflowStateEvent) -> HookNoopResult {
180    if let Some(on_state_change) = &self.on_state_change {
181      on_state_change(event)?;
182    }
183
184    Ok(())
185  }
186
187  async fn on_log(&self, log: WorkflowLog) -> HookNoopResult {
188    if let Some(on_log) = &self.on_log {
189      on_log(log)?;
190    }
191
192    Ok(())
193  }
194
195  async fn on_run_workflow(&self, event: RunWorkflowEvent) -> HookNoopResult {
196    if let Some(on_run_workflow) = &self.on_run_workflow {
197      on_run_workflow(event)?;
198    }
199
200    Ok(())
201  }
202
203  async fn on_run_job(&self, event: RunJobEvent) -> HookNoopResult {
204    if let Some(on_run_job) = &self.on_run_job {
205      on_run_job(event)?;
206    }
207
208    Ok(())
209  }
210
211  async fn on_run_step(&self, event: RunStepEvent) -> HookNoopResult {
212    if let Some(on_run_step) = &self.on_run_step {
213      on_run_step(event)?;
214    }
215
216    Ok(())
217  }
218
219  async fn on_workflow_completed(&self, result: WorkflowRunResult) -> HookNoopResult {
220    if let Some(on_workflow_completed) = &self.on_workflow_completed {
221      on_workflow_completed(result)?;
222    }
223
224    Ok(())
225  }
226
227  async fn on_job_completed(&self, result: JobRunResult) -> HookNoopResult {
228    if let Some(on_job_completed) = &self.on_job_completed {
229      on_job_completed(result)?;
230    }
231
232    Ok(())
233  }
234
235  async fn on_step_completed(&self, result: StepRunResult) -> HookNoopResult {
236    if let Some(on_step_completed) = &self.on_step_completed {
237      on_step_completed(result)?;
238    }
239
240    Ok(())
241  }
242
243  async fn on_before_run_step(&self, step: Step) -> HookBeforeRunStepResult {
244    let mut step = step;
245
246    if let Some(on_before_run_step) = &self.on_before_run_step {
247      match on_before_run_step(step.clone()) {
248        Ok(new_step) => {
249          step = new_step;
250        }
251        Err(err) => return Err(err),
252      }
253    }
254
255    Ok(step)
256  }
257
258  async fn on_resolve_dynamic_action(&self, step: UserActionStep) -> HookResolveActionResult {
259    if let Some(on_resolve_dynamic_action) = &self.on_resolve_dynamic_action {
260      return on_resolve_dynamic_action(step);
261    }
262
263    Ok(None)
264  }
265}