astro_run/
actions.rs

1use crate::{Result, UserActionStep, UserStep};
2use serde::{Deserialize, Serialize};
3use std::{collections::HashMap, fmt::Debug, sync::Arc};
4
5#[derive(Deserialize, Serialize, Debug, Clone)]
6pub struct ActionSteps {
7  pub pre: Option<UserStep>,
8  pub run: UserStep,
9  pub post: Option<UserStep>,
10}
11
12pub trait Action: Send + Sync {
13  fn normalize(&self, step: UserActionStep) -> Result<ActionSteps>;
14}
15
16pub type SharedActionDriver = Arc<ActionDriver>;
17
18#[derive(Clone)]
19pub struct ActionDriver {
20  actions: Arc<HashMap<String, Box<dyn Action>>>,
21}
22
23impl ActionDriver {
24  pub fn new(actions: HashMap<String, Box<dyn Action>>) -> Self {
25    Self {
26      actions: Arc::new(actions),
27    }
28  }
29
30  pub fn try_normalize(&self, step: UserActionStep) -> Result<Option<ActionSteps>> {
31    if let Some(action) = &self.actions.get(&step.uses) {
32      let normalized = action.normalize(step)?;
33
34      Ok(Some(normalized))
35    } else {
36      Ok(None)
37    }
38  }
39}
40
41#[cfg(test)]
42mod tests {
43  use super::*;
44  use crate::UserCommandStep;
45
46  #[test]
47  fn test_normalize_step_actions() -> Result<()> {
48    struct CacheAction {}
49
50    impl Action for CacheAction {
51      fn normalize(&self, _step: UserActionStep) -> Result<ActionSteps> {
52        Ok(ActionSteps {
53          pre: None,
54          run: UserStep::Command(UserCommandStep {
55            name: Some("Restore cache".to_string()),
56            run: "restore cache".to_string(),
57            ..Default::default()
58          }),
59          post: Some(UserStep::Command(UserCommandStep {
60            name: Some("Save cache".to_string()),
61            run: "save cache".to_string(),
62            ..Default::default()
63          })),
64        })
65      }
66    }
67
68    let mut actions = HashMap::new();
69
70    actions.insert(
71      "caches".to_string(),
72      Box::new(CacheAction {}) as Box<dyn Action>,
73    );
74
75    let actions = ActionDriver::new(actions);
76
77    let test_step = UserActionStep {
78      uses: "caches".to_string(),
79      ..Default::default()
80    };
81
82    let steps = actions.try_normalize(test_step)?.unwrap();
83
84    assert!(steps.pre.is_none());
85
86    if let UserStep::Command(step) = steps.run {
87      assert_eq!(step.name, Some("Restore cache".to_string()));
88      assert_eq!(step.run, "restore cache".to_string());
89    } else {
90      panic!("Should be command step");
91    }
92
93    if let Some(UserStep::Command(step)) = steps.post {
94      assert_eq!(step.name, Some("Save cache".to_string()));
95      assert_eq!(step.run, "save cache".to_string());
96    } else {
97      panic!("Should be command step");
98    }
99
100    Ok(())
101  }
102
103  #[test]
104  fn test_not_exists_action() -> Result<()> {
105    let actions = HashMap::new();
106
107    let actions = ActionDriver::new(actions);
108
109    let step = UserActionStep {
110      uses: "not-exists-action".to_string(),
111      ..Default::default()
112    };
113
114    let result = actions.try_normalize(step).unwrap();
115
116    assert!(result.is_none(),);
117
118    Ok(())
119  }
120}