From 8cf148726a09bc4bf12c05dd8ad3407b8e06ecfa Mon Sep 17 00:00:00 2001 From: kjuulh Date: Sat, 25 Nov 2023 21:41:17 +0100 Subject: [PATCH] feat: add cuddle ci draft Signed-off-by: kjuulh --- Cargo.lock | 11 +++ Cargo.toml | 4 + crates/cuddle-ci/Cargo.toml | 19 +++++ crates/cuddle-ci/src/lib.rs | 152 ++++++++++++++++++++++++++++++++++++ 4 files changed, 186 insertions(+) create mode 100644 crates/cuddle-ci/Cargo.toml create mode 100644 crates/cuddle-ci/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 16706f5..205bd06 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -320,6 +320,17 @@ dependencies = [ "typenum", ] +[[package]] +name = "cuddle-ci" +version = "0.2.0" +dependencies = [ + "async-trait", + "clap", + "dagger-sdk", + "eyre", + "tokio", +] + [[package]] name = "cuddle-components" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 6e7d356..2f04b7f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,3 +23,7 @@ eyre = "0.6.9" tokio = "1.34.0" dotenv = "0.15.0" async-trait = "0.1.74" +color-eyre = "*" +clap = {version = "4", features = ["derive"]} +futures = "0.3.28" +async-scoped = { version = "0.7.1", features = ["tokio", "use-tokio"] } diff --git a/crates/cuddle-ci/Cargo.toml b/crates/cuddle-ci/Cargo.toml new file mode 100644 index 0000000..5bdd3e6 --- /dev/null +++ b/crates/cuddle-ci/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "cuddle-ci" +version.workspace = true +edition.workspace = true +license.workspace = true +authors.workspace = true +readme.workspace = true +repository.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +dagger-sdk.workspace = true +eyre.workspace = true +clap.workspace = true +async-trait.workspace = true + +[dev-dependencies] +tokio.workspace = true diff --git a/crates/cuddle-ci/src/lib.rs b/crates/cuddle-ci/src/lib.rs new file mode 100644 index 0000000..58404f6 --- /dev/null +++ b/crates/cuddle-ci/src/lib.rs @@ -0,0 +1,152 @@ +use std::{env::Args, sync::Arc}; + +use async_trait::async_trait; + +pub struct CuddleCI { + pr_action: Arc, + main_action: Arc, + release_action: Arc, +} + +impl CuddleCI { + pub fn new( + pr: Arc, + main: Arc, + release: Arc, + ) -> Self { + Self { + pr_action: pr, + main_action: main, + release_action: release, + } + } + + pub fn with_pull_request(&mut self, pr: Arc) -> &mut Self { + self.pr_action = pr; + + self + } + + pub fn with_main(&mut self, main: Arc) -> &mut Self { + self.main_action = main; + + self + } + + pub fn with_release(&mut self, release: Arc) -> &mut Self { + self.release_action = release; + + self + } + + pub async fn execute(&mut self, args: impl IntoIterator) -> eyre::Result<()> { + let matches = clap::Command::new("cuddle-ci") + .about("is a wrapper around common CI actions") + .subcommand(clap::Command::new("pr")) + .subcommand(clap::Command::new("main")) + .subcommand(clap::Command::new("release")) + .subcommand_required(true) + .try_get_matches_from(args.into_iter())?; + + match matches.subcommand() { + Some((name, args)) => match (name, args) { + ("pr", args) => { + eprintln!("starting pr validate"); + self.pr_action.validate().await?; + eprintln!("finished pr validate"); + } + ("main", args) => { + eprintln!("starting main validate"); + self.main_action.validate().await?; + eprintln!("finished main validate"); + } + ("release", args) => { + eprintln!("starting release validate"); + self.release_action.validate().await?; + eprintln!("finished release validate"); + } + (command_name, _) => { + eyre::bail!("command is not recognized: {}", command_name) + } + }, + None => eyre::bail!("command required a subcommand [pr, main, release] etc."), + } + + Ok(()) + } +} + +impl Default for CuddleCI { + fn default() -> Self { + Self::new( + Arc::new(DefaultPullRequestAction {}), + Arc::new(DefaultMainAction {}), + Arc::new(DefaultReleaseAction {}), + ) + } +} + +#[async_trait] +pub trait PullRequestAction { + async fn validate(&self) -> eyre::Result<()> { + Ok(()) + } +} + +pub struct DefaultPullRequestAction {} +#[async_trait] +impl PullRequestAction for DefaultPullRequestAction {} + +#[async_trait] +pub trait MainAction { + async fn validate(&self) -> eyre::Result<()> { + Ok(()) + } +} + +pub struct DefaultMainAction {} +#[async_trait] +impl MainAction for DefaultMainAction {} + +#[async_trait] +pub trait ReleaseAction { + async fn validate(&self) -> eyre::Result<()> { + Ok(()) + } +} + +pub struct DefaultReleaseAction {} +#[async_trait] +impl ReleaseAction for DefaultReleaseAction {} + +#[cfg(test)] +mod test { + use super::*; + + #[tokio::test] + async fn test_can_call_default() -> eyre::Result<()> { + CuddleCI::default().execute(["cuddle-ci", "pr"]).await?; + + Ok(()) + } + + #[tokio::test] + async fn test_fails_on_no_command() -> eyre::Result<()> { + let res = CuddleCI::default().execute(["cuddle-ci"]).await; + + assert!(res.is_err()); + + Ok(()) + } + + #[tokio::test] + async fn test_fails_on_wrong_command() -> eyre::Result<()> { + let res = CuddleCI::default() + .execute(["cuddle-ci", "something"]) + .await; + + assert!(res.is_err()); + + Ok(()) + } +}