Add github (#41)
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
Co-authored-by: kjuulh <contact@kjuulh.io> Reviewed-on: #41
This commit is contained in:
@@ -21,3 +21,4 @@ git2 = { version = "0.15.0", features = [
|
||||
] }
|
||||
serde = { version = "1.0.147", features = ["derive"] }
|
||||
serde_yaml = "0.9.14"
|
||||
octocrab = { version = "0.17.0", features = ["futures-core", "futures-util"] }
|
||||
|
@@ -239,9 +239,15 @@ impl GitProvider for LocalGitProvider {
|
||||
|
||||
remote.fetch(refspec, Some(&mut fo), None)?;
|
||||
|
||||
let fetch_head = repo.find_reference("FETCH_HEAD")?;
|
||||
let commit = repo.reference_to_annotated_commit(&fetch_head)?;
|
||||
Self::do_merge(&repo, &branch_name, commit)?;
|
||||
match repo.find_reference("FETCH_HEAD") {
|
||||
Ok(fetch_head) => {
|
||||
let commit = repo.reference_to_annotated_commit(&fetch_head)?;
|
||||
Self::do_merge(&repo, &branch_name, commit)?;
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::info!(error = e.to_string(), "upstream branch not found");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
61
crates/octopush_core/src/git/github/github_client.rs
Normal file
61
crates/octopush_core/src/git/github/github_client.rs
Normal file
@@ -0,0 +1,61 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use octocrab::{Octocrab, OctocrabBuilder};
|
||||
|
||||
use super::GitHubClient;
|
||||
|
||||
pub struct DefaultGitHubClientOptions {
|
||||
pub basicauth: Option<String>,
|
||||
}
|
||||
|
||||
pub struct DefaultGitHubClient {
|
||||
github: Arc<Octocrab>,
|
||||
}
|
||||
|
||||
impl DefaultGitHubClient {
|
||||
pub fn new(options: &DefaultGitHubClientOptions) -> eyre::Result<Self> {
|
||||
let mut github = OctocrabBuilder::new();
|
||||
|
||||
if let Some(basicauth) = options.basicauth.clone() {
|
||||
if let Some((username, password)) = basicauth.split_once(":") {
|
||||
github = github.basic_auth(username.into(), password.into());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
github: Arc::new(github.build()?),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl GitHubClient for DefaultGitHubClient {
|
||||
async fn get_clone_url(&self, owner: String, repo_name: String) -> eyre::Result<String> {
|
||||
let repo = self.github.repos(&owner, &repo_name).get().await?;
|
||||
let clone_url = repo
|
||||
.ssh_url
|
||||
.ok_or(eyre::anyhow!("clone_url is not set for repository"))?;
|
||||
|
||||
Ok(clone_url)
|
||||
}
|
||||
|
||||
async fn create_pull_request(
|
||||
&self,
|
||||
owner: &String,
|
||||
repo_name: &String,
|
||||
pull_request_name: &String,
|
||||
) -> eyre::Result<()> {
|
||||
self.github
|
||||
.pulls(owner, repo_name)
|
||||
.create(
|
||||
pull_request_name.clone(),
|
||||
pull_request_name.to_lowercase().replace(" ", "-"),
|
||||
"main",
|
||||
)
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
79
crates/octopush_core/src/git/github/github_provider.rs
Normal file
79
crates/octopush_core/src/git/github/github_provider.rs
Normal file
@@ -0,0 +1,79 @@
|
||||
use std::{path::PathBuf, sync::Arc};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use git2::Repository;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::{git::DynGitProvider, schema::models::GitPushPullRequest, storage::DynStorageEngine};
|
||||
|
||||
use super::{DynGitHubClient, GitHubProvider};
|
||||
|
||||
pub struct DefaultGitHubProvider {
|
||||
git_provider: DynGitProvider,
|
||||
_storage_engine: DynStorageEngine,
|
||||
github_client: DynGitHubClient,
|
||||
}
|
||||
|
||||
impl DefaultGitHubProvider {
|
||||
pub fn new(
|
||||
git_provider: DynGitProvider,
|
||||
storage_engine: DynStorageEngine,
|
||||
github_client: DynGitHubClient,
|
||||
) -> Self {
|
||||
Self {
|
||||
git_provider,
|
||||
_storage_engine: storage_engine,
|
||||
github_client,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl GitHubProvider for DefaultGitHubProvider {
|
||||
async fn clone_from_qualified(&self, repo: &String) -> eyre::Result<(PathBuf, Repository)> {
|
||||
let (owner, repo_name) = repo
|
||||
.split_once("/")
|
||||
.ok_or(eyre::anyhow!("repo is not a valid format"))?;
|
||||
|
||||
let clone_url = self
|
||||
.github_client
|
||||
.get_clone_url(owner.into(), repo_name.into())
|
||||
.await?;
|
||||
|
||||
let (path, repo) = self.git_provider.clone_from_url(&clone_url).await?;
|
||||
|
||||
Ok((path, repo))
|
||||
}
|
||||
|
||||
async fn create_branch(
|
||||
&self,
|
||||
repo: Arc<Mutex<Repository>>,
|
||||
pull_request: &GitPushPullRequest,
|
||||
) -> eyre::Result<()> {
|
||||
tracing::trace!("creating branch");
|
||||
self.git_provider
|
||||
.create_branch(repo, &pull_request.name)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn create_pull_request(
|
||||
&self,
|
||||
repo: Arc<Mutex<Repository>>,
|
||||
repo_name: &String,
|
||||
pull_request: &GitPushPullRequest,
|
||||
) -> eyre::Result<()> {
|
||||
let (owner, repo_name) = repo_name
|
||||
.split_once("/")
|
||||
.ok_or(eyre::anyhow!("repo is not a valid format"))?;
|
||||
|
||||
tracing::trace!("push_branch");
|
||||
self.git_provider
|
||||
.push_branch(repo, &pull_request.name)
|
||||
.await?;
|
||||
|
||||
tracing::trace!("create_pull_request");
|
||||
self.github_client
|
||||
.create_pull_request(&owner.into(), &repo_name.into(), &pull_request.name)
|
||||
.await
|
||||
}
|
||||
}
|
42
crates/octopush_core/src/git/github/mod.rs
Normal file
42
crates/octopush_core/src/git/github/mod.rs
Normal file
@@ -0,0 +1,42 @@
|
||||
pub mod github_client;
|
||||
pub mod github_provider;
|
||||
|
||||
use std::{path::PathBuf, sync::Arc};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use git2::Repository;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::schema::models::GitPushPullRequest;
|
||||
|
||||
#[async_trait]
|
||||
pub trait GitHubClient {
|
||||
async fn get_clone_url(&self, owner: String, repo_name: String) -> eyre::Result<String>;
|
||||
async fn create_pull_request(
|
||||
&self,
|
||||
owner: &String,
|
||||
repo_name: &String,
|
||||
pull_request_name: &String,
|
||||
) -> eyre::Result<()>;
|
||||
}
|
||||
|
||||
pub type DynGitHubClient = Arc<dyn GitHubClient + Send + Sync>;
|
||||
|
||||
#[async_trait]
|
||||
pub trait GitHubProvider {
|
||||
async fn clone_from_qualified(&self, repo: &String) -> eyre::Result<(PathBuf, Repository)>;
|
||||
async fn create_branch(
|
||||
&self,
|
||||
repo: Arc<Mutex<Repository>>,
|
||||
branch: &GitPushPullRequest,
|
||||
) -> eyre::Result<()>;
|
||||
|
||||
async fn create_pull_request(
|
||||
&self,
|
||||
repo: Arc<Mutex<Repository>>,
|
||||
repo_name: &String,
|
||||
pull_request: &GitPushPullRequest,
|
||||
) -> eyre::Result<()>;
|
||||
}
|
||||
|
||||
pub type DynGitHubProvider = Arc<dyn GitHubProvider + Send + Sync>;
|
@@ -6,6 +6,7 @@ use tokio::sync::Mutex;
|
||||
|
||||
pub mod git;
|
||||
pub mod gitea;
|
||||
pub mod github;
|
||||
|
||||
#[async_trait]
|
||||
pub trait GitProvider {
|
||||
|
59
crates/octopush_core/src/selectors/github_selector.rs
Normal file
59
crates/octopush_core/src/selectors/github_selector.rs
Normal file
@@ -0,0 +1,59 @@
|
||||
use std::{path::PathBuf, sync::Arc};
|
||||
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::{
|
||||
executor::executor::DynExecutor,
|
||||
git::{github::DynGitHubProvider, DynGitProvider},
|
||||
schema::models::{Action, GitHub},
|
||||
};
|
||||
|
||||
pub struct GitHubSelector {
|
||||
github_provider: DynGitHubProvider,
|
||||
git_provider: DynGitProvider,
|
||||
executor: DynExecutor,
|
||||
}
|
||||
|
||||
impl GitHubSelector {
|
||||
pub fn new(
|
||||
github_provider: DynGitHubProvider,
|
||||
git_provider: DynGitProvider,
|
||||
executor: DynExecutor,
|
||||
) -> Self {
|
||||
Self {
|
||||
github_provider,
|
||||
git_provider,
|
||||
executor,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn run(
|
||||
&self,
|
||||
git: &GitHub,
|
||||
action_path: &PathBuf,
|
||||
action: &Action,
|
||||
) -> eyre::Result<()> {
|
||||
tracing::info!("fetching repos");
|
||||
for repo in &git.repositories {
|
||||
let gp = self.github_provider.clone();
|
||||
let (path, repo) = gp.clone_from_qualified(repo).await?;
|
||||
let repo = Arc::new(Mutex::new(repo));
|
||||
|
||||
if let Some(push) = &git.push {
|
||||
self.git_provider
|
||||
.create_branch(repo.clone(), &push.pull_request.name)
|
||||
.await?;
|
||||
}
|
||||
|
||||
self.executor.execute(&path, action_path, action).await?;
|
||||
|
||||
if let Some(push) = &git.push {
|
||||
self.git_provider
|
||||
.push_branch(repo, &push.pull_request.name)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
@@ -1,3 +1,4 @@
|
||||
pub mod git_selector;
|
||||
pub mod gitea_selector;
|
||||
pub mod github_selector;
|
||||
|
||||
|
Reference in New Issue
Block a user