diff --git a/Cargo.lock b/Cargo.lock index f9378be..409a6a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -342,6 +342,11 @@ dependencies = [ [[package]] name = "dagger-cuddle-please" version = "0.1.0" +dependencies = [ + "async-trait", + "dagger-sdk", + "eyre", +] [[package]] name = "dagger-sdk" @@ -667,6 +672,16 @@ version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +[[package]] +name = "gitea-cuddle-please" +version = "0.1.0" +dependencies = [ + "dagger-cuddle-please", + "dagger-sdk", + "eyre", + "tokio", +] + [[package]] name = "graphql-introspection-query" version = "0.2.0" diff --git a/Cargo.toml b/Cargo.toml index db9d8d3..8d0363c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,16 +1,15 @@ [workspace] members = [ - "crates/cuddle-components", - "crates/dagger-components", - "crates/dagger-cuddle-please", + "crates/*", + "examples/*", "ci" ] resolver = "2" [workspace.dependencies] -cuddle_components = {path = "crates/cuddle-components"} -dagger_components = {path = "crates/dagger-components"} -dagger_cuddle_please = {path = "crates/dagger-cuddle-please"} +cuddle-components = {path = "crates/cuddle-components"} +dagger-components = {path = "crates/dagger-components"} +dagger-cuddle-please = {path = "crates/dagger-cuddle-please"} ci = {path = "ci"} dagger-sdk = "0.2.22" diff --git a/ci/src/main.rs b/ci/src/main.rs index 7c2e93e..0e12142 100644 --- a/ci/src/main.rs +++ b/ci/src/main.rs @@ -119,7 +119,7 @@ async fn main() -> eyre::Result<()> { mod please_release { use std::sync::Arc; - use crate::{base_rust_image, GlobalArgs}; + use crate::GlobalArgs; pub async fn run_release_please( client: Arc, diff --git a/crates/dagger-cuddle-please/Cargo.toml b/crates/dagger-cuddle-please/Cargo.toml index e45546e..319f19d 100644 --- a/crates/dagger-cuddle-please/Cargo.toml +++ b/crates/dagger-cuddle-please/Cargo.toml @@ -6,3 +6,6 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +dagger-sdk.workspace = true +eyre.workspace = true +async-trait = "*" \ No newline at end of file diff --git a/crates/dagger-cuddle-please/src/lib.rs b/crates/dagger-cuddle-please/src/lib.rs index 8b13789..e2720f5 100644 --- a/crates/dagger-cuddle-please/src/lib.rs +++ b/crates/dagger-cuddle-please/src/lib.rs @@ -1 +1,195 @@ +use std::sync::Arc; +#[derive(Clone, Debug)] +pub struct CuddlePleaseArgs { + pub repository: String, + pub owner: String, + pub branch: String, + + pub cuddle_image: String, + pub server: Server, + + pub log_level: Option, + + pub use_ssh_socket: bool, +} + +#[derive(Clone, Debug)] +pub enum LogLevel { + Trace, + Debug, + Info, + Warn, + Error, +} + +#[derive(Clone, Debug)] +pub enum Server { + Gitea { + url: String, + user: String, + token: String, + insecure: Option, + }, + GitHub { + token: String, + }, +} + +#[async_trait::async_trait] +pub trait CuddlePlease { + async fn execute(&self, args: &CuddlePleaseArgs) -> eyre::Result<()>; +} + +pub struct DaggerCuddlePleaseAction(Arc); + +impl DaggerCuddlePleaseAction { + pub fn dagger(client: Arc) -> Self { + Self(Arc::new(DaggerCuddlePlease::new(client))) + } + + pub async fn execute(&self, args: &CuddlePleaseArgs) -> eyre::Result<()> { + self.0.execute(args).await + } +} + +#[derive(Clone)] +pub struct DaggerCuddlePlease { + client: Arc, +} + +#[async_trait::async_trait] +impl CuddlePlease for DaggerCuddlePlease { + async fn execute(&self, args: &CuddlePleaseArgs) -> eyre::Result<()> { + self.cuddle_please(self.client.clone(), args).await + } +} + +impl DaggerCuddlePlease { + pub fn new(client: Arc) -> Self { + Self { client } + } + + pub async fn cuddle_please( + &self, + client: Arc, + args: &CuddlePleaseArgs, + ) -> eyre::Result<()> { + let build_image = client.container().from(&args.cuddle_image); + + let repo_url = match &args.server { + Server::Gitea { + url, + user, + token, + insecure, + } => { + if args.use_ssh_socket { + format!( + "ssh://{}:{}@{}/{}/{}", + user, token, url, &args.owner, &args.repository + ) + } else { + format!( + "{}://{}:{}@{}/{}/{}", + if insecure.unwrap_or(false) { + "http" + } else { + "https" + }, + user, + token, + url, + &args.owner, + &args.repository + ) + } + } + Server::GitHub { .. } => { + format!("https://github.com/{}/{}", &args.owner, &args.repository) + } + }; + let api_url = match &args.server { + Server::Gitea { url, insecure, .. } => { + format!( + "{}://{}", + if insecure.unwrap_or(false) { + "http" + } else { + "https" + }, + url, + ) + } + Server::GitHub { .. } => "https://github.com".into(), + }; + + let src = client + .git_opts( + &repo_url, + dagger_sdk::QueryGitOpts { + experimental_service_host: None, + keep_git_dir: Some(true), + }, + ) + .branch("main") + .tree(); + + let res = build_image + .with_secret_variable( + "CUDDLE_PLEASE_TOKEN", + client + .set_secret( + "CUDDLE_PLEASE_TOKEN", + match &args.server { + Server::Gitea { token, .. } => token, + Server::GitHub { token } => token, + }, + ) + .id() + .await?, + ) + .with_workdir("/mnt/app") + .with_directory(".", src.id().await?) + .with_exec(vec!["git", "remote", "set-url", "origin", &repo_url]) + .with_exec(vec![ + "cuddle-please", + "release", + &format!( + "--engine={}", + match &args.server { + Server::Gitea { .. } => "gitea", + Server::GitHub { .. } => "github", + } + ), + "--owner", + &args.owner, + "--repo", + &args.repository, + "--branch", + &args.branch, + "--api-url", + &api_url, + "--log-level", + match args.log_level.as_ref().unwrap_or(&LogLevel::Info) { + LogLevel::Trace => "trace", + LogLevel::Debug => "debug", + LogLevel::Info => "info", + LogLevel::Warn => "warn", + LogLevel::Error => "error", + }, + ]); + + let exit_code = res.exit_code().await?; + if exit_code != 0 { + eyre::bail!("failed to run cuddle-please"); + } + + let please_out = res.stdout().await?; + println!("{please_out}"); + let please_out = res.stderr().await?; + println!("{please_out}"); + + Ok(()) + } +} diff --git a/examples/gitea-cuddle-please/Cargo.toml b/examples/gitea-cuddle-please/Cargo.toml new file mode 100644 index 0000000..135a045 --- /dev/null +++ b/examples/gitea-cuddle-please/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "gitea-cuddle-please" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +dagger-cuddle-please.workspace = true + +eyre.workspace = true +dagger-sdk.workspace = true +tokio.workspace = true diff --git a/examples/gitea-cuddle-please/src/main.rs b/examples/gitea-cuddle-please/src/main.rs new file mode 100644 index 0000000..e7bd7ee --- /dev/null +++ b/examples/gitea-cuddle-please/src/main.rs @@ -0,0 +1,26 @@ +use dagger_cuddle_please::{CuddlePleaseArgs, DaggerCuddlePleaseAction}; + +#[tokio::main] +pub async fn main() -> eyre::Result<()> { + let client = dagger_sdk::connect().await?; + + DaggerCuddlePleaseAction::dagger(client.clone()) + .execute(&CuddlePleaseArgs { + repository: "dagger-components".into(), + owner: "kjuulh".into(), + branch: "main".into(), + cuddle_image: "kasperhermansen/cuddle-please:latest".into(), + server: dagger_cuddle_please::Server::Gitea { + url: "https://git.front.kjuulh.io".into(), + user: "git".into(), + token: std::env::var("CUDDLE_PLEASE_TOKEN") + .expect("CUDDLE_PLEASE_TOKEN to be present"), + insecure: None, + }, + log_level: None, + use_ssh_socket: false, + }) + .await?; + + Ok(()) +}