From 95c850264d78125fd55e20f196baf8d4e0faf6f9 Mon Sep 17 00:00:00 2001 From: Bittrance Date: Mon, 2 Oct 2023 20:51:05 +0200 Subject: [PATCH] Inject current and last successful git sha into action envs. --- README.md | 2 +- src/actions.rs | 4 ++++ src/task/gixworkload.rs | 10 +++++++-- src/task/mod.rs | 2 +- src/testutils.rs | 2 +- tests/workload.rs | 48 +++++++++++++++++++++++++++++++++++------ 6 files changed, 57 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 730c313..920c237 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ The plan forward, roughly in falling priority: - [x] allow configuring notification actions - [x] proper options validation (e.g. config-file xor url/action) - [x] specialized notification action to update github status -- [ ] new git sha and branch name in action env vars +- [x] new git sha and branch name in action env vars - [ ] changed task config should override state loaded from disk - [ ] docker packaging - [ ] readme with design and deployment options diff --git a/src/actions.rs b/src/actions.rs index 4c48813..5beb952 100644 --- a/src/actions.rs +++ b/src/actions.rs @@ -39,6 +39,10 @@ impl Action { pub fn id(&self) -> String { self.name.clone() } + + pub fn set_env(&mut self, key: String, val: String) { + self.environment.insert(key, val); + } } impl TryFrom<&CliOptions> for Action { diff --git a/src/task/gixworkload.rs b/src/task/gixworkload.rs index e8b798a..ff63944 100644 --- a/src/task/gixworkload.rs +++ b/src/task/gixworkload.rs @@ -72,7 +72,7 @@ impl Workload for GitWorkload { self.config.interval } - fn perform(&self, workdir: PathBuf, current_sha: ObjectId) -> Result { + fn perform(mut self, workdir: PathBuf, current_sha: ObjectId) -> Result { let deadline = Instant::now() + self.config.timeout; let watchers = self.watchers.clone(); let sink = Arc::new(Mutex::new(move |event: WorkloadEvent| { @@ -81,9 +81,15 @@ impl Workload for GitWorkload { } Ok::<_, GitOpsError>(()) })); - let new_sha = ensure_worktree(&self.config.git, deadline, &self.repo_dir, &workdir)?; if current_sha != new_sha { + self.config.actions.iter_mut().for_each(|action| { + action.set_env( + "KITOPS_LAST_SUCCESSFUL_SHA".to_string(), + current_sha.to_string(), + ); + action.set_env("KITOPS_SHA".to_string(), new_sha.to_string()); + }); sink.lock().unwrap()(WorkloadEvent::Changes( self.config.name.clone(), current_sha, diff --git a/src/task/mod.rs b/src/task/mod.rs index babe6f0..7ea1b19 100644 --- a/src/task/mod.rs +++ b/src/task/mod.rs @@ -15,7 +15,7 @@ pub mod scheduled; pub trait Workload { fn id(&self) -> String; fn interval(&self) -> Duration; - fn perform(&self, workdir: PathBuf, current_sha: ObjectId) -> Result; + fn perform(self, workdir: PathBuf, current_sha: ObjectId) -> Result; } #[derive(Clone, Debug, Serialize, Deserialize)] diff --git a/src/testutils.rs b/src/testutils.rs index 9dad2c7..a62bc0f 100644 --- a/src/testutils.rs +++ b/src/testutils.rs @@ -40,7 +40,7 @@ impl Workload for TestWorkload { Duration::from_secs(1) } - fn perform(&self, _workdir: PathBuf, _current_sha: ObjectId) -> Result { + fn perform(self, _workdir: PathBuf, _current_sha: ObjectId) -> Result { self.status .store(true, std::sync::atomic::Ordering::Relaxed); sleep(Duration::from_millis(10)); diff --git a/tests/workload.rs b/tests/workload.rs index 7d33e6c..315b18e 100644 --- a/tests/workload.rs +++ b/tests/workload.rs @@ -5,7 +5,7 @@ use gix::{hash::Kind, ObjectId}; use kitops::{ errors::GitOpsError, opts::CliOptions, - receiver::WorkloadEvent, + receiver::{SourceType, WorkloadEvent}, task::{gixworkload::GitWorkload, GitTaskConfig, Workload}, }; use utils::*; @@ -16,7 +16,7 @@ fn cli_options(repodir: &tempfile::TempDir) -> CliOptions { CliOptions::parse_from(&["kitops", "--repo-dir", &repodir.path().to_str().unwrap()]) } -fn config(upstream: &tempfile::TempDir, entrypoint: &str) -> GitTaskConfig { +fn config(upstream: &tempfile::TempDir, entrypoint: &str, args: &[&str]) -> GitTaskConfig { serde_yaml::from_str(&format!( r#" name: ze-task @@ -25,9 +25,11 @@ git: actions: - name: ze-action entrypoint: {} + args: {} "#, upstream.path().to_str().unwrap(), - entrypoint + entrypoint, + serde_json::to_string(args).unwrap() )) .unwrap() } @@ -57,7 +59,7 @@ fn watch_successful_workload() { let next_sha = ObjectId::from_hex(next_sha.as_bytes()).unwrap(); let workdir = tempfile::tempdir().unwrap(); let opts = cli_options(&repodir); - let config = config(&upstream, "/bin/ls"); + let config = config(&upstream, "/bin/ls", &[]); let mut workload = GitWorkload::from_config(config, &opts); let events = Arc::new(Mutex::new(Vec::new())); let events2 = events.clone(); @@ -85,7 +87,7 @@ fn watch_failing_workload() { let repodir = tempfile::tempdir().unwrap(); let workdir = tempfile::tempdir().unwrap(); let opts = cli_options(&repodir); - let config = config(&upstream, "/usr/bin/false"); + let config = config(&upstream, "/usr/bin/false", &[]); let mut workload = GitWorkload::from_config(config, &opts); let events = Arc::new(Mutex::new(Vec::new())); let events2 = events.clone(); @@ -110,7 +112,7 @@ fn watch_erroring_workload() { let repodir = tempfile::tempdir().unwrap(); let workdir = tempfile::tempdir().unwrap(); let opts = cli_options(&repodir); - let config = config(&upstream, "/no/such/file"); + let config = config(&upstream, "/no/such/file", &[]); let mut workload = GitWorkload::from_config(config, &opts); let events = Arc::new(Mutex::new(Vec::new())); let events2 = events.clone(); @@ -126,3 +128,37 @@ fn watch_erroring_workload() { assert!(matches!(events[0], WorkloadEvent::Changes(..))); assert!(matches!(events[1], WorkloadEvent::Error(..))); } + +#[cfg(unix)] +#[test] +fn woarkload_gets_sha_env() { + let sh = shell(); + let upstream = empty_repo(&sh); + let next_sha = commit_file(&upstream, "revision 1"); + let repodir = tempfile::tempdir().unwrap(); + let next_sha = ObjectId::from_hex(next_sha.as_bytes()).unwrap(); + let workdir = tempfile::tempdir().unwrap(); + let opts = cli_options(&repodir); + let config = config(&upstream, "/bin/sh", &["-c", "echo $KITOPS_SHA"]); + let mut workload = GitWorkload::from_config(config, &opts); + let events = Arc::new(Mutex::new(Vec::new())); + let events2 = events.clone(); + workload.watch(move |event| { + events2.lock().unwrap().push(event); + Ok(()) + }); + let prev_sha = ObjectId::empty_tree(Kind::Sha1); + workload.perform(workdir.into_path(), prev_sha).unwrap(); + assert_eq!( + events + .lock() + .unwrap() + .iter() + .find(|e| matches!(e, WorkloadEvent::ActionOutput(..))), + Some(&WorkloadEvent::ActionOutput( + "ze-task|ze-action".to_string(), + SourceType::StdOut, + format!("{}\n", next_sha).into_bytes(), + )) + ); +}