|
|
@ -12,7 +12,6 @@ pub struct Positions {
|
|
|
|
pub dev_commit_history: Vec<git::Commit>,
|
|
|
|
pub dev_commit_history: Vec<git::Commit>,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[allow(clippy::cognitive_complexity)] // TODO: (#83) reduce complexity
|
|
|
|
|
|
|
|
pub fn validate_positions(
|
|
|
|
pub fn validate_positions(
|
|
|
|
open_repository: &dyn git::repository::OpenRepositoryLike,
|
|
|
|
open_repository: &dyn git::repository::OpenRepositoryLike,
|
|
|
|
repo_details: &git::RepoDetails,
|
|
|
|
repo_details: &git::RepoDetails,
|
|
|
@ -21,39 +20,31 @@ pub fn validate_positions(
|
|
|
|
let main_branch = repo_config.branches().main();
|
|
|
|
let main_branch = repo_config.branches().main();
|
|
|
|
let next_branch = repo_config.branches().next();
|
|
|
|
let next_branch = repo_config.branches().next();
|
|
|
|
let dev_branch = repo_config.branches().dev();
|
|
|
|
let dev_branch = repo_config.branches().dev();
|
|
|
|
tracing::debug!(%main_branch, %next_branch, %dev_branch, "branches");
|
|
|
|
|
|
|
|
// Collect Commit Histories for `main`, `next` and `dev` branches
|
|
|
|
// Collect Commit Histories for `main`, `next` and `dev` branches
|
|
|
|
open_repository.fetch()?;
|
|
|
|
open_repository.fetch()?;
|
|
|
|
tracing::debug!("fetch okay");
|
|
|
|
|
|
|
|
let commit_histories = get_commit_histories(open_repository, &repo_config)?;
|
|
|
|
let commit_histories = get_commit_histories(open_repository, &repo_config)?;
|
|
|
|
tracing::debug!(?commit_histories, "get commit histories okay");
|
|
|
|
|
|
|
|
// branch tips
|
|
|
|
// branch tips
|
|
|
|
let main =
|
|
|
|
let main =
|
|
|
|
commit_histories.main.first().cloned().ok_or_else(|| {
|
|
|
|
commit_histories.main.first().cloned().ok_or_else(|| {
|
|
|
|
Error::NonRetryable(format!("Branch has no commits: {}", main_branch))
|
|
|
|
Error::NonRetryable(format!("Branch has no commits: {}", main_branch))
|
|
|
|
})?;
|
|
|
|
})?;
|
|
|
|
tracing::debug!("main branch okay");
|
|
|
|
|
|
|
|
let next =
|
|
|
|
let next =
|
|
|
|
commit_histories.next.first().cloned().ok_or_else(|| {
|
|
|
|
commit_histories.next.first().cloned().ok_or_else(|| {
|
|
|
|
Error::NonRetryable(format!("Branch has no commits: {}", next_branch))
|
|
|
|
Error::NonRetryable(format!("Branch has no commits: {}", next_branch))
|
|
|
|
})?;
|
|
|
|
})?;
|
|
|
|
tracing::debug!("next branch okay");
|
|
|
|
|
|
|
|
let dev = commit_histories
|
|
|
|
let dev = commit_histories
|
|
|
|
.dev
|
|
|
|
.dev
|
|
|
|
.first()
|
|
|
|
.first()
|
|
|
|
.cloned()
|
|
|
|
.cloned()
|
|
|
|
.ok_or_else(|| Error::NonRetryable(format!("Branch has no commits: {}", dev_branch)))?;
|
|
|
|
.ok_or_else(|| Error::NonRetryable(format!("Branch has no commits: {}", dev_branch)))?;
|
|
|
|
tracing::debug!("dev branch okay");
|
|
|
|
|
|
|
|
// Validations:
|
|
|
|
// Validations:
|
|
|
|
// Dev must be on main branch, else the USER must rebase it
|
|
|
|
// Dev must be on main branch, else the USER must rebase it
|
|
|
|
if is_not_based_on(&commit_histories.dev, &main) {
|
|
|
|
if is_not_based_on(&commit_histories.dev, &main) {
|
|
|
|
tracing::warn!("Dev '{dev_branch}' not based on main '{main_branch}' - user must rebase",);
|
|
|
|
return Err(Error::UserIntervention(format!(
|
|
|
|
return Err(Error::NonRetryable(format!(
|
|
|
|
|
|
|
|
"Branch '{}' not based on '{}'",
|
|
|
|
"Branch '{}' not based on '{}'",
|
|
|
|
dev_branch, main_branch
|
|
|
|
dev_branch, main_branch
|
|
|
|
)));
|
|
|
|
)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tracing::debug!("dev based on main okay");
|
|
|
|
|
|
|
|
// verify that next is on main or at most one commit on top of main, else reset it back to main
|
|
|
|
// verify that next is on main or at most one commit on top of main, else reset it back to main
|
|
|
|
if is_not_based_on(
|
|
|
|
if is_not_based_on(
|
|
|
|
commit_histories
|
|
|
|
commit_histories
|
|
|
@ -68,14 +59,11 @@ pub fn validate_positions(
|
|
|
|
tracing::info!("Main not on same commit as next, or it's parent - resetting next to main",);
|
|
|
|
tracing::info!("Main not on same commit as next, or it's parent - resetting next to main",);
|
|
|
|
return reset_next_to_main(open_repository, repo_details, &main, &next, &next_branch);
|
|
|
|
return reset_next_to_main(open_repository, repo_details, &main, &next, &next_branch);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tracing::debug!("next on or near main okay");
|
|
|
|
|
|
|
|
// verify that next is an ancestor of dev, else reset it back to main
|
|
|
|
// verify that next is an ancestor of dev, else reset it back to main
|
|
|
|
if is_not_based_on(&commit_histories.dev, &next) {
|
|
|
|
if is_not_based_on(&commit_histories.dev, &next) {
|
|
|
|
tracing::info!("Next is not an ancestor of dev - resetting next to main");
|
|
|
|
tracing::info!("Next is not an ancestor of dev - resetting next to main");
|
|
|
|
return reset_next_to_main(open_repository, repo_details, &main, &next, &next_branch);
|
|
|
|
return reset_next_to_main(open_repository, repo_details, &main, &next, &next_branch);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tracing::debug!("dev based on next okay");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ok(git::validation::positions::Positions {
|
|
|
|
Ok(git::validation::positions::Positions {
|
|
|
|
main,
|
|
|
|
main,
|
|
|
|
next,
|
|
|
|
next,
|
|
|
@ -131,6 +119,9 @@ pub enum Error {
|
|
|
|
|
|
|
|
|
|
|
|
#[error("{0} - not retrying")]
|
|
|
|
#[error("{0} - not retrying")]
|
|
|
|
NonRetryable(String),
|
|
|
|
NonRetryable(String),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[error("{0} - user intervention required")]
|
|
|
|
|
|
|
|
UserIntervention(String),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl From<git::fetch::Error> for Error {
|
|
|
|
impl From<git::fetch::Error> for Error {
|
|
|
|
fn from(value: git::fetch::Error) -> Self {
|
|
|
|
fn from(value: git::fetch::Error) -> Self {
|
|
|
|