extern crate git_workarea;
use self::git_workarea::CommitId;
use super::super::*;
use std::process::Command;
#[derive(Debug, Default, Clone, Copy)]
pub struct ValidName;
fn check_name(name: &str) -> bool {
name.find(' ').is_some()
}
fn check_email(email: &str) -> bool {
let domain_part = email.splitn(2, '@')
.skip(1)
.next();
if let Some(domain) = domain_part {
let dig = Command::new("host")
.arg("-t").arg("MX")
.arg(format!("{}.", domain)) .output();
let dig_output = match dig {
Ok(dig_output) => dig_output,
Err(err) => {
error!(target: "git-checks",
"failed to construct host command: {:?}",
err);
return false;
},
};
if !dig_output.status.success() {
warn!(target: "git-checks",
"failed to look up MX record for domain {}: {}",
domain,
String::from_utf8_lossy(&dig_output.stdout));
false
} else {
true
}
} else {
false
}
}
fn check_identity(what: &str, who: &str, identity: &Identity) -> CheckResult {
let mut result = CheckResult::new();
if !check_name(&identity.name) {
result.add_error(format!("The {} name (`{}`) for {} has no space in it. \
A full name is required for contribution. Please set the \
`user.name` Git configuration value.",
who,
identity.name,
what));
}
if !check_email(&identity.email) {
result.add_error(format!("The {} email (`{}`) for {} has an unknown domain. Please set \
the `user.email` Git configuration value.",
who,
identity.email,
what));
}
result
}
impl ValidName {
pub fn new() -> Self {
ValidName {}
}
}
impl Check for ValidName {
fn name(&self) -> &str {
"valid-name"
}
fn check(&self, _: &CheckGitContext, commit: &Commit) -> Result<CheckResult> {
let what = format!("commit {}", commit.sha1_short);
let author_res = check_identity(&what, "author", &commit.author);
let commiter_res = check_identity(&what, "committer", &commit.committer);
Ok(author_res.combine(commiter_res))
}
}
impl BranchCheck for ValidName {
fn name(&self) -> &str {
"valid-name"
}
fn check(&self, ctx: &CheckGitContext, _: &CommitId) -> Result<CheckResult> {
Ok(check_identity("the topic", "owner", ctx.topic_owner()))
}
}
#[cfg(test)]
mod tests {
use super::ValidName;
use super::super::test::*;
static BAD_TOPIC: &'static str = "dcd8895d299031d607481b4936478f8de4cc28ae";
#[test]
fn test_valid_name() {
let check = ValidName::new();
let mut conf = GitCheckConfiguration::new();
conf.add_check(&check);
let result = test_check("test_valid_name", BAD_TOPIC, &conf);
assert_eq!(result.warnings().len(), 0);
assert_eq!(result.alerts().len(), 0);
assert_eq!(result.errors().len(), 6);
assert_eq!(result.errors()[0],
"The committer email (`bademail@baddomain.invalid`) for commit dcd8895 has an \
unknown domain. Please set the `user.email` Git configuration value.");
assert_eq!(result.errors()[1],
"The author email (`bademail@baddomain.invalid`) for commit 9002239 has an \
unknown domain. Please set the `user.email` Git configuration value.");
assert_eq!(result.errors()[2],
"The committer email (`bademail`) for commit da71ae0 has an unknown domain. \
Please set the `user.email` Git configuration value.");
assert_eq!(result.errors()[3],
"The committer name (`Mononym`) for commit 1debf17 has no space in it. A full \
name is required for contribution. Please set the `user.name` Git \
configuration value.");
assert_eq!(result.errors()[4],
"The author email (`bademail`) for commit 9de4928 has an unknown domain. \
Please set the `user.email` Git configuration value.");
assert_eq!(result.errors()[5],
"The author name (`Mononym`) for commit edac4e5 has no space in it. A full \
name is required for contribution. Please set the `user.name` Git \
configuration value.");
assert_eq!(result.allowed(), false);
assert_eq!(result.pass(), false);
}
}