diff --git a/_examples/actions/write_a_readme/dist/bin b/_examples/actions/write_a_readme/dist/bin index 0f3982a..1e966c1 100755 Binary files a/_examples/actions/write_a_readme/dist/bin and b/_examples/actions/write_a_readme/dist/bin differ diff --git a/_examples/actions/write_a_readme/main.go b/_examples/actions/write_a_readme/main.go index a652402..a344b29 100644 --- a/_examples/actions/write_a_readme/main.go +++ b/_examples/actions/write_a_readme/main.go @@ -7,7 +7,6 @@ func main() { Echo("# Readme"). WriteFile("README.md") - println("i did something!") if err != nil { panic(err) } diff --git a/_examples/actions/write_a_readme/octopush.yml b/_examples/actions/write_a_readme/octopush.yml index a68bf9d..b112816 100644 --- a/_examples/actions/write_a_readme/octopush.yml +++ b/_examples/actions/write_a_readme/octopush.yml @@ -1,11 +1,12 @@ apiVersion: action name: write-a-readme select: - repositories: - - git@git.front.kjuulh.io:kjuulh/octopush-test.git - # providers: - # - gitea: https://git.front.kjuulh.io - # organisation: "cibus" -actions: - - type: go - entry: "main.go" + git: + repositories: + - git@git.front.kjuulh.io:kjuulh/octopush-test.git + push: + branch: + name: "write a readme" +action: + type: go + entry: "main.go" diff --git a/crates/octopush_cli/src/commands/execute.rs b/crates/octopush_cli/src/commands/execute.rs index 926b760..804fd30 100644 --- a/crates/octopush_cli/src/commands/execute.rs +++ b/crates/octopush_cli/src/commands/execute.rs @@ -1,8 +1,9 @@ -use std::path::PathBuf; +use std::{path::PathBuf, sync::Arc}; use clap::{Arg, ArgAction, ArgMatches, Command}; use octopush_core::schema; use octopush_infra::service_register::ServiceRegister; +use tokio::sync::Mutex; pub fn execute_cmd() -> Command { Command::new("execute") @@ -36,29 +37,49 @@ pub async fn execute_subcommand(args: &ArgMatches) -> eyre::Result<()> { schema::models::Schema::Action { name, select, - actions, + action, } => { tracing::debug!(name, "running action"); tracing::info!("fetching repos"); - let mut repo_clones = Vec::with_capacity(select.repositories.len()); - for repo in select.repositories { - let gp = service_register.git_provider.clone(); - repo_clones.push(tokio::spawn(async move { gp.clone_from_url(repo).await })); - } - let mut paths = Vec::new(); - for repo_clone in repo_clones { - let path = repo_clone.await??; - paths.push(path); + + if let Some(git) = select.git.clone() { + let mut repo_clones = Vec::with_capacity(git.repositories.len()); + for repo in git.repositories { + let gp = service_register.git_provider.clone(); + repo_clones.push(tokio::spawn(async move { gp.clone_from_url(repo).await })); + } + + for repo_clone in repo_clones { + let path = repo_clone.await??; + paths.push(path); + } } - for path in paths { - for action in actions.clone() { - service_register - .executor - .execute(path.clone(), action_path.clone(), action) - .await?; + for (path, repo) in paths { + let repo = Arc::new(Mutex::new(repo)); + if let Some(git) = select.git.clone() { + if let Some(push) = git.push { + service_register + .git_provider + .create_branch(repo.clone(), &push.branch) + .await?; + } + } + + service_register + .executor + .execute(path.clone(), action_path.clone(), action.clone()) + .await?; + + if let Some(git) = select.git.clone() { + if let Some(push) = git.push { + service_register + .git_provider + .push_branch(repo, &push.branch) + .await?; + } } } } diff --git a/crates/octopush_core/src/git/github.rs b/crates/octopush_core/src/git/github.rs index 50e6464..310314e 100644 --- a/crates/octopush_core/src/git/github.rs +++ b/crates/octopush_core/src/git/github.rs @@ -1,8 +1,9 @@ -use std::path::PathBuf; +use std::{path::PathBuf, sync::Arc}; -use git2::{Cred, RemoteCallbacks}; +use git2::{Cred, RemoteCallbacks, Repository}; +use tokio::sync::Mutex; -use crate::storage::DynStorageEngine; +use crate::{schema::models::GitPushBranch, storage::DynStorageEngine}; use super::GitProvider; @@ -18,12 +19,12 @@ impl GitHubGitProvider { #[async_trait::async_trait] impl GitProvider for GitHubGitProvider { - async fn clone_from_url(&self, url: String) -> eyre::Result { + async fn clone_from_url(&self, url: String) -> eyre::Result<(PathBuf, Repository)> { tracing::debug!(url, "allocating dir"); let dir = self.storage_engine.allocate_dir().await?; let dirpath = dir.clone().path(); - let _ = tokio::task::spawn_blocking(move || { + let repo = tokio::task::spawn_blocking(move || { let mut callbacks = RemoteCallbacks::new(); callbacks.credentials(|url, username_from_url, _allowed_types| { tracing::debug!(username_from_url, url, "pulling key from ssh-agent"); @@ -47,6 +48,43 @@ impl GitProvider for GitHubGitProvider { tracing::debug!("done pulling repo"); - Ok(dir.path()) + Ok((dir.path(), repo)) + } + + async fn create_branch( + &self, + repo: Arc>, + branch: &GitPushBranch, + ) -> eyre::Result<()> { + let repo = repo.lock().await; + + let head_commit_oid = repo + .head()? + .target() + .ok_or(eyre::anyhow!("could not get access to target commit"))?; + let head_commit = repo.find_commit(head_commit_oid)?; + let newbranch = repo.branch( + &branch.name.to_lowercase().replace(" ", "-"), + &head_commit, + true, + )?; + + repo.set_head( + newbranch + .into_reference() + .name() + .ok_or(eyre::anyhow!("could not get name of reference"))?, + )?; + + Ok(()) + } + + async fn push_branch( + &self, + repo: Arc>, + branch: &GitPushBranch, + ) -> eyre::Result<()> { + let repo = repo.lock().await; + Ok(()) } } diff --git a/crates/octopush_core/src/git/mod.rs b/crates/octopush_core/src/git/mod.rs index b6b2cb7..8448174 100644 --- a/crates/octopush_core/src/git/mod.rs +++ b/crates/octopush_core/src/git/mod.rs @@ -1,12 +1,26 @@ use std::{path::PathBuf, sync::Arc}; use async_trait::async_trait; +use git2::Repository; +use tokio::sync::Mutex; + +use crate::schema::models::GitPushBranch; pub mod github; #[async_trait] pub trait GitProvider { - async fn clone_from_url(&self, url: String) -> eyre::Result; + async fn clone_from_url(&self, url: String) -> eyre::Result<(PathBuf, Repository)>; + async fn create_branch( + &self, + repo: Arc>, + branch: &GitPushBranch, + ) -> eyre::Result<()>; + async fn push_branch( + &self, + repo: Arc>, + branch: &GitPushBranch, + ) -> eyre::Result<()>; } pub type DynGitProvider = Arc; diff --git a/crates/octopush_core/src/schema/models.rs b/crates/octopush_core/src/schema/models.rs index 015168c..36150d8 100644 --- a/crates/octopush_core/src/schema/models.rs +++ b/crates/octopush_core/src/schema/models.rs @@ -3,10 +3,26 @@ use serde::{Deserialize, Serialize}; pub type Repository = String; #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub struct SelectAction { +pub struct GitPushBranch { + pub name: String, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] +pub struct GitPush { + pub branch: GitPushBranch, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] +pub struct Git { + pub push: Option, pub repositories: Vec, } +#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] +pub struct SelectAction { + pub git: Option, +} + #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] #[serde(tag = "type")] pub enum Action { @@ -21,6 +37,6 @@ pub enum Schema { Action { name: String, select: SelectAction, - actions: Vec, + action: Action, }, } diff --git a/crates/octopush_core/src/schema/parser.rs b/crates/octopush_core/src/schema/parser.rs index c87b23b..7bc714c 100644 --- a/crates/octopush_core/src/schema/parser.rs +++ b/crates/octopush_core/src/schema/parser.rs @@ -60,7 +60,7 @@ actions: select: SelectAction { repositories: vec!["git@git.front.kjuulh.io:kjuulh/octopush-test.git".into()] }, - actions: vec![Action::Go { + action: vec![Action::Go { entry: "main.go".into() }] } diff --git a/crates/octopush_core/src/shell/mod.rs b/crates/octopush_core/src/shell/mod.rs index ea5d588..77fd0f0 100644 --- a/crates/octopush_core/src/shell/mod.rs +++ b/crates/octopush_core/src/shell/mod.rs @@ -43,7 +43,7 @@ pub async fn execute_shell(cmd: String, path: Option) -> eyre::Result<( }); while let Some(line) = reader.next_line().await? { - tracing::trace!("{}", line) + tracing::trace!("something: {}", line) } Ok(())