use std::error::Error;
use std::fmt::Debug;
use git_workarea::CommitId;
use crate::commit::{Commit, Content, Topic};
use crate::context::CheckGitContext;
#[derive(Debug, Default)]
pub struct CheckResult {
warnings: Vec<String>,
alerts: Vec<String>,
errors: Vec<String>,
temporary: bool,
allow: bool,
pass: bool,
}
pub enum Severity {
Warning,
Error,
Alert {
blocking: bool,
},
}
impl CheckResult {
pub fn new() -> Self {
Self {
warnings: Vec::new(),
alerts: Vec::new(),
errors: Vec::new(),
temporary: false,
allow: false,
pass: true,
}
}
pub fn add_message<S>(&mut self, severity: Severity, message: S) -> &mut Self
where
S: Into<String>,
{
match severity {
Severity::Warning => &mut self.warnings,
Severity::Error => {
self.pass = false;
&mut self.errors
},
Severity::Alert {
blocking,
} => {
if blocking {
self.pass = false;
}
&mut self.alerts
},
}
.push(message.into());
self
}
pub fn add_warning<S: Into<String>>(&mut self, warning: S) -> &mut Self {
self.add_message(Severity::Warning, warning.into())
}
pub fn add_alert<S: Into<String>>(&mut self, alert: S, should_block: bool) -> &mut Self {
self.add_message(
Severity::Alert {
blocking: should_block,
},
alert.into(),
)
}
pub fn add_error<S: Into<String>>(&mut self, error: S) -> &mut Self {
self.add_message(Severity::Error, error.into())
}
pub fn make_temporary(&mut self) -> &mut Self {
self.temporary = true;
self
}
pub fn whitelist(&mut self) -> &mut Self {
self.allow = true;
self
}
pub fn warnings(&self) -> &Vec<String> {
&self.warnings
}
pub fn alerts(&self) -> &Vec<String> {
&self.alerts
}
pub fn errors(&self) -> &Vec<String> {
&self.errors
}
pub fn temporary(&self) -> bool {
self.temporary
}
pub fn allowed(&self) -> bool {
self.allow
}
pub fn pass(&self) -> bool {
self.pass
}
pub fn combine(self, other: Self) -> Self {
Self {
warnings: self
.warnings
.into_iter()
.chain(other.warnings.into_iter())
.collect(),
alerts: self
.alerts
.into_iter()
.chain(other.alerts.into_iter())
.collect(),
errors: self
.errors
.into_iter()
.chain(other.errors.into_iter())
.collect(),
temporary: self.temporary || other.temporary,
allow: self.allow || other.allow,
pass: self.pass && other.pass,
}
}
}
pub trait Check: Debug + Send + Sync {
fn name(&self) -> &str;
fn check(&self, ctx: &CheckGitContext, commit: &Commit) -> Result<CheckResult, Box<dyn Error>>;
}
pub trait BranchCheck: Debug + Send + Sync {
fn name(&self) -> &str;
fn check(
&self,
ctx: &CheckGitContext,
commit: &CommitId,
) -> Result<CheckResult, Box<dyn Error>>;
}
pub trait TopicCheck: Debug + Send + Sync {
fn name(&self) -> &str;
fn check(&self, ctx: &CheckGitContext, topic: &Topic) -> Result<CheckResult, Box<dyn Error>>;
}
pub trait ContentCheck: Debug + Send + Sync {
fn name(&self) -> &str;
fn check(
&self,
ctx: &CheckGitContext,
content: &dyn Content,
) -> Result<CheckResult, Box<dyn Error>>;
}
impl<T> Check for T
where
T: ContentCheck,
{
fn name(&self) -> &str {
self.name()
}
fn check(&self, ctx: &CheckGitContext, commit: &Commit) -> Result<CheckResult, Box<dyn Error>> {
self.check(ctx, commit)
}
}
impl<T> TopicCheck for T
where
T: ContentCheck,
{
fn name(&self) -> &str {
self.name()
}
fn check(&self, ctx: &CheckGitContext, topic: &Topic) -> Result<CheckResult, Box<dyn Error>> {
self.check(ctx, topic)
}
}