use crate::parser::Commit;
use super::{Condition, EnumOpts, Rule, Severity};
use miette::{miette, LabeledSpan, Report};
pub struct ScopeEnumRule {
pub opts: EnumOpts,
}
impl Rule for ScopeEnumRule {
fn run(&self, commit: &Commit) -> Option<Report> {
let severity = &self.opts.0;
let condition = &self.opts.1;
let scopes = &self.opts.2;
if severity == &Severity::Off || scopes.is_empty() {
return None;
}
if let Some(scope) = &commit.scope {
let is_in_scopes = scopes.contains(&scope.to_string());
let is_valid = match condition {
Condition::Never => !is_in_scopes,
Condition::Always => is_in_scopes,
};
if !is_valid {
return Some(
miette!(
severity = match severity {
Severity::Warning => miette::Severity::Warning,
Severity::Error => miette::Severity::Error,
Severity::Off => miette::Severity::Advice,
},
labels = vec![LabeledSpan::at(
scope.start()..scope.end(),
"not allowed scope"
),],
help = String::from("scope must")
+ match condition {
Condition::Never => " not",
Condition::Always => "",
}
+ " be one of "
+ &scopes.join(", "),
code = "rule/scope-enum",
url = "https://example.com",
"Scope not allowed",
)
.with_source_code(commit.raw.clone()),
);
}
}
None
}
}
#[cfg(test)]
mod tests {
use crate::parser::CommitSpan;
use super::*;
#[test]
fn test_empty_scope() {
let mut commit: Commit<'_> = Default::default();
commit.scope = None;
let rule = ScopeEnumRule {
opts: EnumOpts(
Severity::Error,
Condition::Never,
vec!["feat".to_string(), "fix".to_string()],
),
};
assert!(rule.run(&commit).is_none());
let rule = ScopeEnumRule {
opts: EnumOpts(
Severity::Error,
Condition::Always,
vec!["feat".to_string(), "fix".to_string()],
),
};
assert!(rule.run(&commit).is_none());
}
#[test]
fn test_never_condition() {
let mut commit: Commit<'_> = Default::default();
let rule = ScopeEnumRule {
opts: EnumOpts(
Severity::Error,
Condition::Never,
vec!["feat".to_string(), "fix".to_string()],
),
};
commit.scope = Some(Default::default());
assert!(rule.run(&commit).is_none());
commit.scope = Some(CommitSpan::new("nice", 0, 4));
assert!(rule.run(&commit).is_none());
commit.scope = Some(CommitSpan::new("feat", 0, 4));
assert!(rule.run(&commit).is_some());
}
#[test]
fn test_always_condition() {
let mut commit: Commit<'_> = Default::default();
let rule = ScopeEnumRule {
opts: EnumOpts(
Severity::Error,
Condition::Always,
vec!["feat".to_string(), "fix".to_string()],
),
};
commit.scope = Some(Default::default());
assert!(rule.run(&commit).is_some());
commit.scope = Some(CommitSpan::new("nice", 0, 4));
assert!(rule.run(&commit).is_some());
commit.scope = Some(CommitSpan::new("feat", 0, 4));
assert!(rule.run(&commit).is_none());
}
#[test]
fn test_severity_off() {
let mut commit: Commit<'_> = Default::default();
let rule = ScopeEnumRule {
opts: EnumOpts(
Severity::Off,
Condition::Always,
vec!["feat".to_string(), "fix".to_string()],
),
};
commit.scope = Some(Default::default());
assert!(rule.run(&commit).is_none());
commit.scope = Some(CommitSpan::new("nice", 0, 4));
assert!(rule.run(&commit).is_none());
commit.scope = Some(CommitSpan::new("feat", 0, 4));
assert!(rule.run(&commit).is_none());
}
#[test]
fn test_empty_list() {
let mut commit: Commit<'_> = Default::default();
let rule = ScopeEnumRule {
opts: EnumOpts(Severity::Error, Condition::Always, vec![]),
};
commit.scope = Some(Default::default());
assert!(rule.run(&commit).is_none());
commit.scope = Some(CommitSpan::new("nice", 0, 4));
assert!(rule.run(&commit).is_none());
commit.scope = Some(CommitSpan::new("feat", 0, 4));
assert!(rule.run(&commit).is_none());
}
}