extern crate git_workarea;
use self::git_workarea::CommitId;
use super::super::*;
#[derive(Debug)]
pub struct ReleaseBranch {
branch: String,
disallowed_commit: CommitId,
required: bool,
}
impl ReleaseBranch {
pub fn new<B: ToString, C: ToString>(branch: B, commit: C) -> Self {
ReleaseBranch {
branch: branch.to_string(),
disallowed_commit: CommitId::new(commit),
required: false,
}
}
pub fn set_required(&mut self, required: bool) -> &mut Self {
self.required = required;
self
}
}
impl BranchCheck for ReleaseBranch {
fn name(&self) -> &str {
"release-branch"
}
fn check(&self, ctx: &CheckGitContext, commit: &CommitId) -> Result<CheckResult> {
let merge_base = try!(ctx.git()
.arg("merge-base")
.arg(commit.as_str())
.arg(self.disallowed_commit.as_str())
.output()
.chain_err(|| "failed to construct merge-base command"));
if !merge_base.status.success() {
bail!(ErrorKind::Git(format!("failed to get the merge base for a release branch: {}",
String::from_utf8_lossy(&merge_base.stderr))));
}
let common_commit = String::from_utf8_lossy(&merge_base.stdout);
let is_eligible = common_commit.trim() != self.disallowed_commit.as_str();
let mut result = CheckResult::new();
if is_eligible && !self.required {
result.add_warning(format!("Eligible for the {} branch.", self.branch));
} else if !is_eligible && self.required {
result.add_error(format!("This branch is ineligible for the {} branch; it needs to \
be based on a commit before {}.",
self.branch,
self.disallowed_commit));
}
Ok(result)
}
}
#[cfg(test)]
mod tests {
use super::ReleaseBranch;
use super::super::test::*;
static RELEASE_BRANCH: &'static str = "3a22ca19fda09183da2faab60819ff6807568acd";
static POST_RELEASE_COMMIT: &'static str = "d02f015907371738253a22b9a7fec78607a969b2";
static POST_RELEASE_BRANCH: &'static str = "a61fd3759b61a4a1f740f3fe656bc42151cefbdd";
static POST_RELEASE_BRANCH_MERGE: &'static str = "c58dd19d9976722d82aa6bc6a52a2a01a52bd9e8";
fn make_release_branch_check() -> ReleaseBranch {
ReleaseBranch::new("release", POST_RELEASE_COMMIT)
}
#[test]
fn test_release_branch_ok() {
let check = make_release_branch_check();
let mut conf = GitCheckConfiguration::new();
conf.add_branch_check(&check);
let result = test_check("test_release_branch_ok", RELEASE_BRANCH, &conf);
assert_eq!(result.warnings().len(), 1);
assert_eq!(result.warnings()[0], "Eligible for the release branch.");
assert_eq!(result.alerts().len(), 0);
assert_eq!(result.errors().len(), 0);
assert_eq!(result.allowed(), false);
assert_eq!(result.pass(), true);
}
#[test]
fn test_release_branch_ok_required() {
let mut check = make_release_branch_check();
check.set_required(true);
let mut conf = GitCheckConfiguration::new();
conf.add_branch_check(&check);
let result = test_check("test_release_branch_ok_required", RELEASE_BRANCH, &conf);
assert_eq!(result.warnings().len(), 0);
assert_eq!(result.alerts().len(), 0);
assert_eq!(result.errors().len(), 0);
assert_eq!(result.allowed(), false);
assert_eq!(result.pass(), true);
}
#[test]
fn test_post_release_branch() {
let check = make_release_branch_check();
let mut conf = GitCheckConfiguration::new();
conf.add_branch_check(&check);
let result = test_check("test_post_release_branch", POST_RELEASE_BRANCH, &conf);
assert_eq!(result.warnings().len(), 0);
assert_eq!(result.alerts().len(), 0);
assert_eq!(result.errors().len(), 0);
assert_eq!(result.allowed(), false);
assert_eq!(result.pass(), true);
}
#[test]
fn test_post_release_branch_required() {
let mut check = make_release_branch_check();
check.set_required(true);
let mut conf = GitCheckConfiguration::new();
conf.add_branch_check(&check);
let result = test_check("test_post_release_branch_required",
POST_RELEASE_BRANCH,
&conf);
assert_eq!(result.warnings().len(), 0);
assert_eq!(result.alerts().len(), 0);
assert_eq!(result.errors().len(), 1);
assert_eq!(result.errors()[0],
"This branch is ineligible for the release branch; it needs to be based on a \
commit before d02f015907371738253a22b9a7fec78607a969b2.");
assert_eq!(result.allowed(), false);
assert_eq!(result.pass(), false);
}
#[test]
fn test_post_release_branch_merge() {
let check = make_release_branch_check();
let mut conf = GitCheckConfiguration::new();
conf.add_branch_check(&check);
let result = test_check("test_post_release_branch_merge",
POST_RELEASE_BRANCH_MERGE,
&conf);
assert_eq!(result.warnings().len(), 0);
assert_eq!(result.alerts().len(), 0);
assert_eq!(result.errors().len(), 0);
assert_eq!(result.allowed(), false);
assert_eq!(result.pass(), true);
}
#[test]
fn test_post_release_branch_merge_required() {
let mut check = make_release_branch_check();
check.set_required(true);
let mut conf = GitCheckConfiguration::new();
conf.add_branch_check(&check);
let result = test_check("test_post_release_branch_merge_required",
POST_RELEASE_BRANCH_MERGE,
&conf);
assert_eq!(result.warnings().len(), 0);
assert_eq!(result.alerts().len(), 0);
assert_eq!(result.errors().len(), 1);
assert_eq!(result.errors()[0],
"This branch is ineligible for the release branch; it needs to be based on a \
commit before d02f015907371738253a22b9a7fec78607a969b2.");
assert_eq!(result.allowed(), false);
assert_eq!(result.pass(), false);
}
}