feat: handle Git errors

This commit is contained in:
Aravinth Manivannan 2022-04-26 20:12:17 +05:30
parent eb87453bd1
commit b758042836
Signed by: realaravinth
GPG key ID: AD9F0F08E855ED88
3 changed files with 61 additions and 32 deletions

View file

@ -25,6 +25,7 @@ use actix_web::{
};
use config::ConfigError as ConfigErrorInner;
use derive_more::{Display, Error};
use git2::Error as GitError;
use serde::{Deserialize, Serialize};
use url::ParseError;
@ -118,6 +119,9 @@ pub enum ServiceError {
#[display(fmt = "Configuration Error {}", _0)]
ConfigError(ConfigError),
#[display(fmt = "Git Error {}", _0)]
GitError(GitError),
}
impl From<ParseError> for ServiceError {
@ -127,6 +131,13 @@ impl From<ParseError> for ServiceError {
}
}
impl From<GitError> for ServiceError {
#[cfg(not(tarpaulin_include))]
fn from(e: GitError) -> ServiceError {
ServiceError::GitError(e)
}
}
/// Generic result data structure
#[cfg(not(tarpaulin_include))]
pub type ServiceResult<V> = std::result::Result<V, ServiceError>;
@ -167,6 +178,7 @@ impl ResponseError for ServiceError {
ServiceError::UnauthorizedOperation(_) => StatusCode::UNAUTHORIZED,
ServiceError::BadRequest(_) => StatusCode::BAD_REQUEST,
ServiceError::GitError(_) => StatusCode::BAD_REQUEST,
}
}
}

View file

@ -18,6 +18,8 @@ use git2::{build::CheckoutBuilder, BranchType, Direction, ObjectType, Repository
use log::info;
use serde::Deserialize;
use crate::errors::*;
#[derive(Debug, Clone, PartialEq, Deserialize)]
pub struct Page {
pub secret: String,
@ -27,50 +29,50 @@ pub struct Page {
}
impl Page {
fn create_repo(&self) -> Repository {
fn create_repo(&self) -> ServiceResult<Repository> {
let repo = Repository::open(&self.path);
if let Ok(repo) = repo {
return repo;
return Ok(repo);
} else {
info!("Cloning repository {} at {}", self.repo, self.path);
Repository::clone(&self.repo, &self.path).unwrap()
Repository::clone(&self.repo, &self.path)?;
};
let repo = Repository::open(&self.path).unwrap();
self._fetch_upstream(&repo, &self.branch);
self.deploy_branch(&repo);
repo
let repo = Repository::open(&self.path)?;
self._fetch_upstream(&repo, &self.branch)?;
self.deploy_branch(&repo)?;
Ok(repo)
}
pub fn deploy_branch(&self, repo: &Repository) {
let branch = repo
.find_branch(&format!("origin/{}", &self.branch), BranchType::Remote)
.unwrap();
pub fn deploy_branch(&self, repo: &Repository) -> ServiceResult<()> {
let branch = repo.find_branch(&format!("origin/{}", &self.branch), BranchType::Remote)?;
let mut checkout_options = CheckoutBuilder::new();
checkout_options.force();
let tree = branch.get().peel(ObjectType::Tree).unwrap();
let tree = branch.get().peel(ObjectType::Tree)?;
repo.checkout_tree(&tree, Some(&mut checkout_options))
.unwrap();
repo.set_head(branch.get().name().unwrap()).unwrap();
repo.checkout_tree(&tree, Some(&mut checkout_options))?;
repo.set_head(branch.get().name().unwrap())?;
info!("Deploying branch {}", self.branch);
Ok(())
}
fn _fetch_upstream(&self, repo: &Repository, branch: &str) {
fn _fetch_upstream(&self, repo: &Repository, branch: &str) -> ServiceResult<()> {
let mut remote = repo.find_remote("origin").unwrap();
remote.connect(Direction::Fetch).unwrap();
remote.connect(Direction::Fetch)?;
info!("Updating repository {}", self.repo);
remote.fetch(&[branch], None, None).unwrap();
remote.disconnect().unwrap();
remote.fetch(&[branch], None, None)?;
remote.disconnect()?;
Ok(())
}
pub fn update(&self) {
let repo = self.create_repo();
self._fetch_upstream(&repo, &self.branch);
self.deploy_branch(&repo);
pub fn update(&self) -> ServiceResult<()> {
let repo = self.create_repo()?;
self._fetch_upstream(&repo, &self.branch)?;
self.deploy_branch(&repo)?;
Ok(())
}
}
@ -105,9 +107,9 @@ mod tests {
"repository doesn't exist yet"
);
let repo = page.create_repo();
let repo = page.create_repo().unwrap();
assert!(!repo.is_bare(), "repository isn't bare");
page.create_repo();
page.create_repo().unwrap();
assert!(
Repository::open(tmp_dir.as_path()).is_ok(),
"repository exists yet"
@ -119,7 +121,7 @@ mod tests {
&"origin/gh-pages"
);
page.branch = "master".to_string();
page.update();
page.update().unwrap();
let master = page.get_tree(&repo);
assert_eq!(master.name().unwrap().as_ref().unwrap(), &"origin/master");
}

View file

@ -17,11 +17,12 @@
use std::env;
use std::path::Path;
use config::{Config, ConfigError, Environment, File};
use config::{Config, Environment, File};
use log::warn;
use serde::Deserialize;
use url::Url;
use crate::errors::*;
use crate::page::Page;
#[derive(Debug, Clone, Deserialize)]
@ -47,7 +48,7 @@ pub struct Settings {
#[cfg(not(tarpaulin_include))]
impl Settings {
pub fn new() -> Result<Self, ConfigError> {
pub fn new() -> ServiceResult<Self> {
let mut s = Config::builder();
const CURRENT_DIR: &str = "./config/default.toml";
@ -99,12 +100,26 @@ impl Settings {
if index2 == index {
continue;
}
if page.secret == page2.secret || page.repo == page2.repo || page.path == page2.path
{
panic!("duplicate page onfiguration {:?} and {:?}", page, page2);
if page.secret == page2.secret {
log::error!(
"{}",
ServiceError::SecretTaken(page.to_owned(), page2.to_owned())
);
} else if page.repo == page2.repo {
log::error!(
"{}",
ServiceError::DuplicateRepositoryURL(page.to_owned(), page2.to_owned(),)
);
} else if page.path == page2.path {
log::error!(
"{}",
ServiceError::PathTaken(page.to_owned(), page2.to_owned())
);
}
}
page.update();
if let Err(e) = page.update() {
log::error!("{e}");
}
}
Ok(settings)