WIP: gitea

This commit is contained in:
Kasper Juul Hermansen 2022-11-24 22:10:34 +01:00
parent 0f8db6be08
commit 1a3084e651
Signed by: kjuulh
GPG Key ID: 57B6E1465221F912
9 changed files with 155 additions and 13 deletions

View File

@ -1,6 +1,20 @@
apiVersion: action apiVersion: action
name: write-a-readme name: write-a-readme
select: 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: git:
repositories: repositories:
- git@git.front.kjuulh.io:kjuulh/octopush-test.git - git@git.front.kjuulh.io:kjuulh/octopush-test.git

View File

@ -42,8 +42,7 @@ pub async fn execute_subcommand(args: &ArgMatches) -> eyre::Result<()> {
tracing::debug!(name, "running action"); tracing::debug!(name, "running action");
tracing::info!("fetching repos"); tracing::info!("fetching repos");
let mut paths = Vec::new(); let mut git_paths = Vec::new();
if let Some(git) = select.git.clone() { if let Some(git) = select.git.clone() {
let mut repo_clones = Vec::with_capacity(git.repositories.len()); let mut repo_clones = Vec::with_capacity(git.repositories.len());
for repo in git.repositories { for repo in git.repositories {
@ -53,11 +52,27 @@ pub async fn execute_subcommand(args: &ArgMatches) -> eyre::Result<()> {
for repo_clone in repo_clones { for repo_clone in repo_clones {
let path = repo_clone.await??; 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)); let repo = Arc::new(Mutex::new(repo));
if let Some(git) = select.git.clone() { if let Some(git) = select.git.clone() {
if let Some(push) = git.push { if let Some(push) = git.push {

View File

@ -1,24 +1,24 @@
use std::{path::PathBuf, sync::Arc}; use std::{path::PathBuf, sync::Arc};
use git2::{Cred, RemoteCallbacks, Repository, Signature}; use git2::{Cred, PushOptions, RemoteCallbacks, Repository};
use tokio::sync::Mutex; use tokio::sync::Mutex;
use crate::{schema::models::GitPushBranch, storage::DynStorageEngine}; use crate::{schema::models::GitPushBranch, storage::DynStorageEngine};
use super::GitProvider; use super::GitProvider;
pub struct GitHubGitProvider { pub struct LocalGitProvider {
storage_engine: DynStorageEngine, storage_engine: DynStorageEngine,
} }
impl GitHubGitProvider { impl LocalGitProvider {
pub fn new(storage_engine: DynStorageEngine) -> Self { pub fn new(storage_engine: DynStorageEngine) -> Self {
Self { storage_engine } Self { storage_engine }
} }
} }
#[async_trait::async_trait] #[async_trait::async_trait]
impl GitProvider for GitHubGitProvider { impl GitProvider for LocalGitProvider {
async fn clone_from_url(&self, url: String) -> eyre::Result<(PathBuf, Repository)> { async fn clone_from_url(&self, url: String) -> eyre::Result<(PathBuf, Repository)> {
tracing::debug!(url, "allocating dir"); tracing::debug!(url, "allocating dir");
let dir = self.storage_engine.allocate_dir().await?; let dir = self.storage_engine.allocate_dir().await?;
@ -86,12 +86,13 @@ impl GitProvider for GitHubGitProvider {
) -> eyre::Result<()> { ) -> eyre::Result<()> {
let repo = repo.lock().await; let repo = repo.lock().await;
tracing::trace!("pulling signature from local git");
let signature = repo.signature()?; let signature = repo.signature()?;
tracing::trace!("fetching index and adding changed files to working tree");
let mut index = repo.index()?; let mut index = repo.index()?;
index.add_path(PathBuf::from(".").as_path())?; index.add_all(&["."], git2::IndexAddOption::DEFAULT, None)?;
index.write()?; index.write()?;
let tree = index.write_tree()?; let tree = index.write_tree()?;
let tree = repo.find_tree(tree)?; let tree = repo.find_tree(tree)?;
@ -101,6 +102,7 @@ impl GitProvider for GitHubGitProvider {
.map(|t| repo.find_commit(t)) .map(|t| repo.find_commit(t))
})???; })???;
tracing::trace!("writing commit object");
repo.commit( repo.commit(
None, None,
&signature, &signature,
@ -110,6 +112,24 @@ impl GitProvider for GitHubGitProvider {
&[&parents], &[&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(()) Ok(())
} }
} }

View File

@ -0,0 +1,7 @@
pub struct DefaultGiteaClient {}
impl DefaultGiteaClient {
pub fn new() -> Self {
Self {}
}
}

View File

@ -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<dyn GiteaClient + Send + Sync>;
#[async_trait]
pub trait GiteaProvider {
async fn clone_from_qualified(repo: String) -> eyre::Result<String>;
}
pub type DynGiteaProvider = Arc<dyn GiteaProvider + Send + Sync>;

View File

@ -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<String> {
todo!()
}
}

View File

@ -6,7 +6,8 @@ use tokio::sync::Mutex;
use crate::schema::models::GitPushBranch; use crate::schema::models::GitPushBranch;
pub mod github; pub mod git;
pub mod gitea;
#[async_trait] #[async_trait]
pub trait GitProvider { pub trait GitProvider {

View File

@ -7,6 +7,11 @@ pub struct GitPushBranch {
pub name: String, pub name: String,
} }
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
pub struct GitPushPullRequest {
pub name: String,
}
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
pub struct GitPush { pub struct GitPush {
pub branch: GitPushBranch, pub branch: GitPushBranch,
@ -18,9 +23,33 @@ pub struct Git {
pub repositories: Vec<Repository>, pub repositories: Vec<Repository>,
} }
#[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<GitHubPush>,
pub repositories: Vec<Repository>,
}
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
pub struct Gitea {
pub push: Option<GiteaPush>,
pub repositories: Vec<Repository>,
}
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
pub struct SelectAction { pub struct SelectAction {
pub git: Option<Git>, pub git: Option<Git>,
pub github: Option<GitHub>,
pub gitea: Option<Gitea>,
} }
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]

View File

@ -3,7 +3,11 @@ use std::sync::Arc;
use octopush_core::{ use octopush_core::{
builder::{builder_capabilities::BuilderCapabilities, DynBuilder}, builder::{builder_capabilities::BuilderCapabilities, DynBuilder},
executor::{default_executor::DefaultExecutor, executor::DynExecutor}, executor::{default_executor::DefaultExecutor, executor::DynExecutor},
git::{github::GitHubGitProvider, DynGitProvider}, git::{
git::LocalGitProvider,
gitea::{provider::DefaultGiteaProvider, DynGiteaProvider},
DynGitProvider,
},
schema::parser::{DefaultSchemaParser, DynSchemaParser}, schema::parser::{DefaultSchemaParser, DynSchemaParser},
storage::{local::LocalStorageEngine, DynStorageEngine}, storage::{local::LocalStorageEngine, DynStorageEngine},
}; };
@ -14,15 +18,17 @@ pub struct ServiceRegister {
pub schema_parser: DynSchemaParser, pub schema_parser: DynSchemaParser,
pub builder: DynBuilder, pub builder: DynBuilder,
pub executor: DynExecutor, pub executor: DynExecutor,
pub gitea_provider: DynGiteaProvider,
} }
impl ServiceRegister { impl ServiceRegister {
pub fn new() -> Self { pub fn new() -> Self {
let storage_engine = Arc::new(LocalStorageEngine::new("/tmp/octopush".into())); 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 schema_parser = Arc::new(DefaultSchemaParser::new());
let builder = Arc::new(BuilderCapabilities::new()); let builder = Arc::new(BuilderCapabilities::new());
let executor = Arc::new(DefaultExecutor::new(builder.clone())); let executor = Arc::new(DefaultExecutor::new(builder.clone()));
let gitea_provider = Arc::new(DefaultGiteaProvider::new(git_provider.clone()));
Self { Self {
storage_engine, storage_engine,
@ -30,6 +36,7 @@ impl ServiceRegister {
schema_parser, schema_parser,
builder, builder,
executor, executor,
gitea_provider,
} }
} }