diff --git a/src/build.rs b/src/build.rs new file mode 100644 index 0000000..7f83869 --- /dev/null +++ b/src/build.rs @@ -0,0 +1,52 @@ +use anyhow::{Error, Result}; +use git2::BranchType; + +use crate::config::RepoConfig; + +pub fn pull_or_clone_and_build_and_push(repo: &RepoConfig) -> Result<(), BuildError> { + let git_repo = pull_or_clone(repo)?; + build(&git_repo)?; + push(&git_repo)?; + + Ok(()) +} + +fn pull_or_clone(repo: &RepoConfig) -> Result { + match git2::Repository::open(&repo.local_git_repo) { + Ok(git_repo) => { + pull(&git_repo).map_err(|err| BuildError::FailedToPull(err))?; + Ok(git_repo) + }, + + Err(open_err) => match git2::Repository::clone(&repo.remote_git_repo, &repo.local_git_repo) { + Ok(git_repo) => Ok(git_repo), + Err(clone_err) => Err(BuildError::FailedToOpenOrClone(open_err.into(), clone_err.into())), + } + } +} + +fn pull(git_repo: &git2::Repository) -> Result<()> { + let mut origin = git_repo.find_remote("origin")?; + let (main_branch, main_branch_name) = git_repo.find_branch("main", BranchType::Local).map(|b| (b, "main")) + .or_else(|_| git_repo.find_branch("master", BranchType::Local).map(|b| (b, "master")))?; + let upstream_main_branch = main_branch.upstream()?; + + git_repo.set_head(main_branch_name)?; + origin.fetch(&[main_branch_name], None, None)?; + let upstream_commit = git_repo.reference_to_annotated_commit(&upstream_main_branch.into_reference())?; + git_repo.merge(&[&upstream_commit], None, None)?; + Ok(()) +} + +fn build(git_repo: &git2::Repository) -> Result<(), BuildError> { + todo!() +} + +fn push(git_repo: &git2::Repository) -> Result<(), BuildError> { + todo!() +} + +pub enum BuildError { + FailedToOpenOrClone(Error, Error), + FailedToPull(Error), +} diff --git a/src/main.rs b/src/main.rs index 215f9e6..42cfaae 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,12 +4,13 @@ use dirs::config_dir; #[macro_use] extern crate rocket; +mod build; mod config; use config::read_config; use rocket::{State, http::Status}; -use crate::config::Config; +use crate::{build::{BuildError, pull_or_clone_and_build_and_push}, config::Config}; const BIN_NAME: &str = "build-joeac"; @@ -30,7 +31,20 @@ fn index(remote_git_repo: PathBuf, config: &State) -> (Status, String) { None => (Status::BadRequest, format!("Failed to convert request path to unicode: {:?}", remote_git_repo)), Some(remote_git_repo) => match config.repositories.iter().find(|repo| repo.remote_git_repo.eq(remote_git_repo)) { None => (Status::NotFound, format!("Remote git repository not configured: {remote_git_repo}")), - Some(repo) => (Status::Ok, format!("Matched! {:?}", repo)) + Some(repo) => match pull_or_clone_and_build_and_push(repo) { + Err(BuildError::FailedToOpenOrClone(open_err, clone_err)) => ( + Status::InternalServerError, + format!( + "Failed to open or clone git repository. Error opening: {:#?}\n\nError cloning: {:#?}", + open_err, + clone_err) + ), + Err(BuildError::FailedToPull(err)) => ( + Status::InternalServerError, + format!("Failed to pull git repository. Error: {:#?}", err), + ), + Ok(()) => (Status::Ok, String::from("Pulled, built and pushed image")), + } } } }