use impl_prelude::*;
#[derive(Debug)]
pub struct ReleaseBranch {
branch: String,
disallowed_commit: CommitId,
required: bool,
}
impl ReleaseBranch {
pub fn new<B, C>(branch: B, commit: C) -> Self
where B: ToString,
C: ToString,
{
Self {
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 = ctx.git()
.arg("merge-base")
.arg("--all")
.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 merge_bases = String::from_utf8_lossy(&merge_base.stdout);
let is_eligible = merge_bases.lines()
.all(|merge_base| merge_base != 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 checks::ReleaseBranch;
use checks::test::*;
const RELEASE_BRANCH: &str = "3a22ca19fda09183da2faab60819ff6807568acd";
const POST_RELEASE_COMMIT: &str = "d02f015907371738253a22b9a7fec78607a969b2";
const POST_RELEASE_BRANCH: &str = "a61fd3759b61a4a1f740f3fe656bc42151cefbdd";
const POST_RELEASE_BRANCH_MERGE: &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 result = run_branch_check("test_release_branch_ok", RELEASE_BRANCH, check);
test_result_warnings(result, &[
"Eligible for the release branch.",
]);
}
#[test]
fn test_release_branch_ok_required() {
let mut check = make_release_branch_check();
check.set_required(true);
run_branch_check_ok("test_release_branch_ok_required", RELEASE_BRANCH, check);
}
#[test]
fn test_post_release_branch() {
let check = make_release_branch_check();
run_branch_check_ok("test_post_release_branch", POST_RELEASE_BRANCH, check);
}
#[test]
fn test_post_release_branch_required() {
let mut check = make_release_branch_check();
check.set_required(true);
let result = run_branch_check("test_post_release_branch_required",
POST_RELEASE_BRANCH,
check);
test_result_errors(result, &[
"This branch is ineligible for the release branch; it needs to be based on a commit \
before d02f015907371738253a22b9a7fec78607a969b2.",
]);
}
#[test]
fn test_post_release_branch_merge() {
let check = make_release_branch_check();
run_branch_check_ok("test_post_release_branch_merge",
POST_RELEASE_BRANCH_MERGE,
check);
}
#[test]
fn test_post_release_branch_merge_required() {
let mut check = make_release_branch_check();
check.set_required(true);
let result = run_branch_check("test_post_release_branch_merge_required",
POST_RELEASE_BRANCH_MERGE,
check);
test_result_errors(result, &[
"This branch is ineligible for the release branch; it needs to be based on a commit \
before d02f015907371738253a22b9a7fec78607a969b2.",
]);
}
}