diff --git a/src/commands/diff.rs b/src/commands/diff.rs index df0eb1f..250be60 100644 --- a/src/commands/diff.rs +++ b/src/commands/diff.rs @@ -18,7 +18,7 @@ use crate::{ PullRequestUpdate, }, message::{MessageSection, validate_commit_message}, - output::{output, write_commit_title}, + output::{output, write_commit_info, write_commit_title}, utils::{parse_name_list, remove_all_parens, slugify}, }; use git2::Oid; @@ -435,6 +435,49 @@ async fn diff_impl( } } + if let Some(ref pull_request) = pull_request + && config.check_for_commits_from_others + { + let last_pr_commit = git.repo().find_commit(pull_request.head_oid)?; + let last_pr_committer = last_pr_commit.committer(); + let local_commit = git.repo().find_commit(local_commit.oid)?; + let local_committer = local_commit.committer(); + if local_committer.name() != last_pr_committer.name() { + let commit_id = last_pr_commit.id().to_string(); + let summary = last_pr_commit.summary().unwrap_or(""); + let pr_committer = last_pr_committer.name().unwrap_or("unknown"); + output("⚠️", "The last PR commit is not from you:")?; + write_commit_info(&commit_id[0..7], &summary, &pr_committer)?; + let pr_branch_name = pull_request.head.branch_name().to_string(); + let input = tokio::task::spawn_blocking(move || { + dialoguer::Input::<String>::new() + .with_prompt(formatdoc!( + " + + Please select what you want do: + 1) Type 'yes' to continue (risks losing changes from others) + 2) Hit Enter to stop + + Then manually merge in the changes from the PR: + + git fetch origin {pr_branch_name} + git merge --squash origin/{pr_branch_name} + git commit --amend + + Then run `spr diff` again. + + ", + )) + .allow_empty(true) + .interact_text() + }) + .await??; + if input.is_empty() || input != "yes" { + bail!("Aborted as per user request"); + } + } + } + // Check if there is a base branch on GitHub already. That's the case when // there is an existing Pull Request, and its base is not the master branch. let base_branch = if let Some(ref pr) = pull_request { diff --git a/src/config.rs b/src/config.rs index f054c61..cee1033 100644 --- a/src/config.rs +++ b/src/config.rs @@ -18,6 +18,7 @@ pub struct Config { pub auth_token: String, pub require_approval: bool, pub require_test_plan: bool, + pub check_for_commits_from_others: bool, } impl Config { @@ -30,6 +31,7 @@ impl Config { auth_token: String, require_approval: bool, require_test_plan: bool, + check_for_commits_from_others: bool, ) -> Self { let master_ref = GitHubBranch::new_from_branch_name(&master_branch, &master_branch); @@ -41,6 +43,7 @@ impl Config { auth_token, require_approval, require_test_plan, + check_for_commits_from_others, } } @@ -106,6 +109,7 @@ mod tests { "xyz".into(), false, true, + false, ) } diff --git a/src/main.rs b/src/main.rs index 2d77961..6e7f1a3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -138,6 +138,10 @@ pub async fn spr() -> Result<()> { .get_bool("spr.requireTestPlan") .ok() .unwrap_or(true); + let check_for_commits_from_others = git_config + .get_bool("spr.checkForCommitsFromOthers") + .ok() + .unwrap_or(false); let github_auth_token = match cli.github_auth_token { Some(v) => Ok(v), @@ -152,6 +156,7 @@ pub async fn spr() -> Result<()> { github_auth_token.clone(), require_approval, require_test_plan, + check_for_commits_from_others, ); debug!("config: {:?}", config); diff --git a/src/output.rs b/src/output.rs index e8e54c8..28dffa2 100644 --- a/src/output.rs +++ b/src/output.rs @@ -42,3 +42,18 @@ pub fn write_commit_title(prepared_commit: &PreparedCommit) -> Result<()> { ))?; Ok(()) } + +pub fn write_commit_info( + short_id: &str, + title: &str, + committer: &str, +) -> Result<()> { + let term = console::Term::stdout(); + term.write_line(&format!( + "{} {} (from {})", + console::style(short_id).italic(), + console::style(title).yellow(), + console::style(committer) + ))?; + Ok(()) +}