diff --git a/_examples/actions/write_a_readme/octopush.yml b/_examples/actions/write_a_readme/octopush.yml index b112816..b45a24f 100644 --- a/_examples/actions/write_a_readme/octopush.yml +++ b/_examples/actions/write_a_readme/octopush.yml @@ -1,6 +1,20 @@ apiVersion: action name: write-a-readme select: + github: + repositories: + - kjuulh/octopush-test + push: + pull-request: + name: "write a readme" + + gitea: + repositories: + - kjuulh/octopush-test + push: + pull-request: + name: "write a readme" + git: repositories: - git@git.front.kjuulh.io:kjuulh/octopush-test.git diff --git a/crates/octopush_cli/src/commands/execute.rs b/crates/octopush_cli/src/commands/execute.rs index 804fd30..99a343d 100644 --- a/crates/octopush_cli/src/commands/execute.rs +++ b/crates/octopush_cli/src/commands/execute.rs @@ -42,8 +42,7 @@ pub async fn execute_subcommand(args: &ArgMatches) -> eyre::Result<()> { tracing::debug!(name, "running action"); tracing::info!("fetching repos"); - let mut paths = Vec::new(); - + let mut git_paths = Vec::new(); if let Some(git) = select.git.clone() { let mut repo_clones = Vec::with_capacity(git.repositories.len()); for repo in git.repositories { @@ -53,11 +52,27 @@ pub async fn execute_subcommand(args: &ArgMatches) -> eyre::Result<()> { for repo_clone in repo_clones { let path = repo_clone.await??; - paths.push(path); + git_paths.push(path); } } - for (path, repo) in paths { + let mut gitea_paths = Vec::new(); + if let Some(gitea) = &select.gitea { + let mut repo_clones = Vec::with_capacity(gitea.repositories.len()); + for repo in gitea.repositories { + let gp = service_register.gitea_provider.clone(); + repo_clones.push(tokio::spawn( + async move { gp.clone_from_qualified(repo).await }, + )) + } + + for repo_clone in repo_clones { + let path = repo_clone.await??; + gitea_paths.push(path); + } + } + + for (path, repo) in git_paths { let repo = Arc::new(Mutex::new(repo)); if let Some(git) = select.git.clone() { if let Some(push) = git.push { diff --git a/crates/octopush_core/src/git/github.rs b/crates/octopush_core/src/git/git.rs similarity index 72% rename from crates/octopush_core/src/git/github.rs rename to crates/octopush_core/src/git/git.rs index 12ecf1b..773d593 100644 --- a/crates/octopush_core/src/git/github.rs +++ b/crates/octopush_core/src/git/git.rs @@ -1,24 +1,24 @@ use std::{path::PathBuf, sync::Arc}; -use git2::{Cred, RemoteCallbacks, Repository, Signature}; +use git2::{Cred, PushOptions, RemoteCallbacks, Repository}; use tokio::sync::Mutex; use crate::{schema::models::GitPushBranch, storage::DynStorageEngine}; use super::GitProvider; -pub struct GitHubGitProvider { +pub struct LocalGitProvider { storage_engine: DynStorageEngine, } -impl GitHubGitProvider { +impl LocalGitProvider { pub fn new(storage_engine: DynStorageEngine) -> Self { Self { storage_engine } } } #[async_trait::async_trait] -impl GitProvider for GitHubGitProvider { +impl GitProvider for LocalGitProvider { 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?; @@ -86,12 +86,13 @@ impl GitProvider for GitHubGitProvider { ) -> eyre::Result<()> { let repo = repo.lock().await; + tracing::trace!("pulling signature from local git"); let signature = repo.signature()?; + tracing::trace!("fetching index and adding changed files to working tree"); let mut index = repo.index()?; - index.add_path(PathBuf::from(".").as_path())?; + index.add_all(&["."], git2::IndexAddOption::DEFAULT, None)?; index.write()?; - let tree = index.write_tree()?; let tree = repo.find_tree(tree)?; @@ -101,6 +102,7 @@ impl GitProvider for GitHubGitProvider { .map(|t| repo.find_commit(t)) })???; + tracing::trace!("writing commit object"); repo.commit( None, &signature, @@ -110,6 +112,24 @@ impl GitProvider for GitHubGitProvider { &[&parents], )?; + let mut remote = repo.find_remote("origin")?; + let head = repo.head()?; + let refspec = &[head + .name() + .ok_or(eyre::anyhow!("could not find head.name"))?]; + + let mut remote_callbacks = RemoteCallbacks::new(); + remote_callbacks.credentials(|url, username_from_url, _allowed_types| { + tracing::debug!(username_from_url, url, "pulling key from ssh-agent"); + Cred::ssh_key_from_agent(username_from_url.unwrap()) + }); + + let mut push_options = PushOptions::new(); + push_options.remote_callbacks(remote_callbacks); + + tracing::trace!("pushing to remote"); + remote.push(refspec, Some(&mut push_options))?; + Ok(()) } } diff --git a/crates/octopush_core/src/git/gitea/client.rs b/crates/octopush_core/src/git/gitea/client.rs new file mode 100644 index 0000000..9ba09e9 --- /dev/null +++ b/crates/octopush_core/src/git/gitea/client.rs @@ -0,0 +1,7 @@ +pub struct DefaultGiteaClient {} + +impl DefaultGiteaClient { + pub fn new() -> Self { + Self {} + } +} diff --git a/crates/octopush_core/src/git/gitea/mod.rs b/crates/octopush_core/src/git/gitea/mod.rs new file mode 100644 index 0000000..c745ac5 --- /dev/null +++ b/crates/octopush_core/src/git/gitea/mod.rs @@ -0,0 +1,17 @@ +pub mod client; +pub mod provider; + +use std::sync::Arc; + +use async_trait::async_trait; + +pub trait GiteaClient {} + +pub type DynGiteaClient = Arc; + +#[async_trait] +pub trait GiteaProvider { + async fn clone_from_qualified(repo: String) -> eyre::Result; +} + +pub type DynGiteaProvider = Arc; diff --git a/crates/octopush_core/src/git/gitea/provider.rs b/crates/octopush_core/src/git/gitea/provider.rs new file mode 100644 index 0000000..eda97dc --- /dev/null +++ b/crates/octopush_core/src/git/gitea/provider.rs @@ -0,0 +1,32 @@ +use async_trait::async_trait; + +use crate::{git::DynGitProvider, storage::DynStorageEngine}; + +use super::{DynGiteaClient, GiteaProvider}; + +pub struct DefaultGiteaProvider { + git_provider: DynGitProvider, + storage_engine: DynStorageEngine, + gitea_client: DynGiteaClient, +} + +impl DefaultGiteaProvider { + pub fn new( + git_provider: DynGitProvider, + storage_engine: DynStorageEngine, + gitea_client: DynGiteaClient, + ) -> Self { + Self { + git_provider, + storage_engine, + gitea_client, + } + } +} + +#[async_trait] +impl GiteaProvider for DefaultGiteaProvider { + async fn clone_from_qualified(repo: String) -> eyre::Result { + todo!() + } +} diff --git a/crates/octopush_core/src/git/mod.rs b/crates/octopush_core/src/git/mod.rs index 8448174..91d3132 100644 --- a/crates/octopush_core/src/git/mod.rs +++ b/crates/octopush_core/src/git/mod.rs @@ -6,7 +6,8 @@ use tokio::sync::Mutex; use crate::schema::models::GitPushBranch; -pub mod github; +pub mod git; +pub mod gitea; #[async_trait] pub trait GitProvider { diff --git a/crates/octopush_core/src/schema/models.rs b/crates/octopush_core/src/schema/models.rs index 36150d8..85eb35d 100644 --- a/crates/octopush_core/src/schema/models.rs +++ b/crates/octopush_core/src/schema/models.rs @@ -7,6 +7,11 @@ pub struct GitPushBranch { pub name: String, } +#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] +pub struct GitPushPullRequest { + pub name: String, +} + #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] pub struct GitPush { pub branch: GitPushBranch, @@ -18,9 +23,33 @@ pub struct Git { pub repositories: Vec, } +#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] +pub struct GitHubPush { + pub branch: GitPushPullRequest, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] +pub struct GiteaPush { + pub branch: GitPushPullRequest, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] +pub struct GitHub { + pub push: Option, + pub repositories: Vec, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] +pub struct Gitea { + pub push: Option, + pub repositories: Vec, +} + #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] pub struct SelectAction { pub git: Option, + pub github: Option, + pub gitea: Option, } #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] diff --git a/crates/octopush_infra/src/service_register.rs b/crates/octopush_infra/src/service_register.rs index 7037e73..334a8be 100644 --- a/crates/octopush_infra/src/service_register.rs +++ b/crates/octopush_infra/src/service_register.rs @@ -3,7 +3,11 @@ use std::sync::Arc; use octopush_core::{ builder::{builder_capabilities::BuilderCapabilities, DynBuilder}, executor::{default_executor::DefaultExecutor, executor::DynExecutor}, - git::{github::GitHubGitProvider, DynGitProvider}, + git::{ + git::LocalGitProvider, + gitea::{provider::DefaultGiteaProvider, DynGiteaProvider}, + DynGitProvider, + }, schema::parser::{DefaultSchemaParser, DynSchemaParser}, storage::{local::LocalStorageEngine, DynStorageEngine}, }; @@ -14,15 +18,17 @@ pub struct ServiceRegister { pub schema_parser: DynSchemaParser, pub builder: DynBuilder, pub executor: DynExecutor, + pub gitea_provider: DynGiteaProvider, } impl ServiceRegister { pub fn new() -> Self { let storage_engine = Arc::new(LocalStorageEngine::new("/tmp/octopush".into())); - let git_provider = Arc::new(GitHubGitProvider::new(storage_engine.clone())); + let git_provider = Arc::new(LocalGitProvider::new(storage_engine.clone())); let schema_parser = Arc::new(DefaultSchemaParser::new()); let builder = Arc::new(BuilderCapabilities::new()); let executor = Arc::new(DefaultExecutor::new(builder.clone())); + let gitea_provider = Arc::new(DefaultGiteaProvider::new(git_provider.clone())); Self { storage_engine, @@ -30,6 +36,7 @@ impl ServiceRegister { schema_parser, builder, executor, + gitea_provider, } }