diff --git a/git-branchless-submit/src/branch_forge.rs b/git-branchless-submit/src/branch_forge.rs index 99caa36aa..2c870bf9b 100644 --- a/git-branchless-submit/src/branch_forge.rs +++ b/git-branchless-submit/src/branch_forge.rs @@ -325,11 +325,14 @@ These remotes are available: {}", progress.notify_progress_inc(branch_names.len()); // FIXME: report push errors - result.extend( - branch_names - .iter() - .map(|(_branch, commit_oid)| (*commit_oid, UpdateStatus::Updated)), - ); + result.extend(branch_names.iter().map(|(branch, commit_oid)| { + ( + *commit_oid, + UpdateStatus::Updated { + local_commit_name: branch.to_owned(), + }, + ) + })); } Ok(Ok(result)) diff --git a/git-branchless-submit/src/github.rs b/git-branchless-submit/src/github.rs index a9fffdbb3..9f3dea2e1 100644 --- a/git-branchless-submit/src/github.rs +++ b/git-branchless-submit/src/github.rs @@ -491,7 +491,15 @@ impl Forge for GithubForge<'_> { progress.notify_progress_inc(1); // FIXME: report push/update errors - result.insert(commit_oid, UpdateStatus::Updated); + result.insert( + commit_oid, + UpdateStatus::Updated { + local_commit_name: commit_status + .local_commit_name + .clone() + .unwrap_or_else(|| commit_oid.to_string()), + }, + ); } } diff --git a/git-branchless-submit/src/lib.rs b/git-branchless-submit/src/lib.rs index 40d93fab9..5ec7b154c 100644 --- a/git-branchless-submit/src/lib.rs +++ b/git-branchless-submit/src/lib.rs @@ -13,12 +13,13 @@ mod branch_forge; pub mod github; pub mod phabricator; -use std::collections::{BTreeSet, HashMap}; +use std::collections::HashMap; use std::fmt::{Debug, Write}; use std::time::SystemTime; use branch_forge::BranchForge; use cursive_core::theme::{BaseColor, Effect, Style}; +use cursive_core::utils::markup::StyledString; use git_branchless_invoke::CommandContext; use git_branchless_test::{RawTestOptions, ResolvedTestOptions, Verbosity}; use github::GithubForge; @@ -27,7 +28,6 @@ use lazy_static::lazy_static; use lib::core::dag::{union_all, CommitSet, Dag}; use lib::core::effects::Effects; use lib::core::eventlog::{EventLogDb, EventReplayer}; -use lib::core::formatting::{Pluralize, StyledStringBuilder}; use lib::core::repo_ext::{RepoExt, RepoReferencesSnapshot}; use lib::git::{GitRunInfo, NonZeroOid, Repo}; use lib::try_exit_code; @@ -43,13 +43,20 @@ use tracing::{debug, info, instrument, warn}; use crate::github::github_push_remote; lazy_static! { - /// The style for branches which were successfully submitted. - pub static ref STYLE_PUSHED: Style = + /// The style for commits which were successfully submitted. + pub static ref STYLE_SUCCESS: Style = Style::merge(&[BaseColor::Green.light().into(), Effect::Bold.into()]); - /// The style for branches which were not submitted. + /// The style for commits which were not submitted. pub static ref STYLE_SKIPPED: Style = Style::merge(&[BaseColor::Yellow.light().into(), Effect::Bold.into()]); + + /// The style for commits which failed to be submitted. + pub static ref STYLE_FAILED: Style = + Style::merge(&[BaseColor::Red.light().into(), Effect::Bold.into()]); + + /// The style for informational text. + pub static ref STYLE_INFO: Style = Effect::Dim.into(); } /// The status of a commit, indicating whether it needs to be updated remotely. @@ -157,17 +164,14 @@ pub enum CreateStatus { local_commit_name: String, }, - /// The commit was skipped. This could happen if a previous commit could not - /// be created due to an error. - Skipped { - /// The commit which was skipped. - commit_oid: NonZeroOid, - }, + /// The commit was skipped because it didn't already exist on the remote and + /// `--create` was not passed. + Skipped, /// The commit could not be created due to an error. Err { - /// The commit which produced an error. - commit_oid: NonZeroOid, + /// The error message to display to the user. + message: String, }, } @@ -177,7 +181,14 @@ pub enum CreateStatus { #[derive(Clone, Debug)] pub enum UpdateStatus { /// The commit was successfully updated. - Updated, + Updated { + /// An identifier corresponding to the commit, for display purposes only. + /// This may be a branch name, a change ID, the commit summary, etc. + /// + /// This does not necessarily correspond to the commit's name/identifier in + /// the forge (e.g. not a code review link). + local_commit_name: String, + }, } /// "Forge" refers to a Git hosting provider, such as GitHub, GitLab, etc. @@ -316,6 +327,7 @@ fn submit( }; let unioned_revset = Revset(revsets.iter().map(|Revset(inner)| inner).join(" + ")); + let commit_oids = dag.sort(&commit_set)?; let mut forge = select_forge( effects, git_run_info, @@ -326,254 +338,219 @@ fn submit( &unioned_revset, forge_kind, )?; - let statuses = try_exit_code!(forge.query_status(commit_set)?); - debug!(?statuses, "Commit statuses"); - - #[allow(clippy::type_complexity)] - let (_local_commits, unsubmitted_commits, commits_to_update, commits_to_skip): ( - HashMap, - HashMap, - HashMap, - HashMap, - ) = statuses.into_iter().fold(Default::default(), |acc, elem| { - let (mut local, mut unsubmitted, mut to_update, mut to_skip) = acc; - let (commit_oid, commit_status) = elem; - match commit_status { - CommitStatus { - submit_status: SubmitStatus::Local, - remote_name: _, - local_commit_name: _, - remote_commit_name: _, - } => { - local.insert(commit_oid, commit_status); - } + let current_statuses = try_exit_code!(forge.query_status(commit_set)?); + debug!(?current_statuses, "Commit statuses"); - CommitStatus { - submit_status: SubmitStatus::Unsubmitted, - remote_name: _, - local_commit_name: _, - remote_commit_name: _, - } => { - unsubmitted.insert(commit_oid, commit_status); - } - - CommitStatus { - submit_status: SubmitStatus::NeedsUpdate, - remote_name: _, - local_commit_name: _, - remote_commit_name: _, - } => { - to_update.insert(commit_oid, commit_status); - } - - CommitStatus { - submit_status: SubmitStatus::UpToDate, - remote_name: _, - local_commit_name: Some(_), - remote_commit_name: _, - } => { - to_skip.insert(commit_oid, commit_status); - } - - // Don't know what to do in these cases 🙃. - CommitStatus { - submit_status: SubmitStatus::Unknown, - remote_name: _, - local_commit_name: _, - remote_commit_name: _, - } - | CommitStatus { - submit_status: SubmitStatus::UpToDate, - remote_name: _, - local_commit_name: None, - remote_commit_name: _, - } => {} - } - (local, unsubmitted, to_update, to_skip) - }); - - let (submitted_commit_names, unsubmitted_commit_names, create_error_commits): ( - BTreeSet, - BTreeSet, - BTreeSet, - ) = { - let unsubmitted_commit_names: BTreeSet = unsubmitted_commits - .values() - .flat_map(|commit_status| commit_status.local_commit_name.clone()) + let create_statuses: HashMap = { + let unsubmitted_commits: HashMap = current_statuses + .iter() + .filter(|(_commit_oid, commit_status)| match commit_status { + CommitStatus { + submit_status: SubmitStatus::Unsubmitted, + .. + } => true, + CommitStatus { + submit_status: + SubmitStatus::Local + | SubmitStatus::NeedsUpdate + | SubmitStatus::Unknown + | SubmitStatus::UpToDate, + .. + } => false, + }) + .map(|(commit_oid, create_status)| (*commit_oid, create_status.clone())) .collect(); - if create { - let (created_commit_names, error_commits) = if dry_run { - (unsubmitted_commit_names.clone(), Default::default()) - } else { - let create_statuses = - try_exit_code!(forge.create(unsubmitted_commits, &submit_options)?); - let mut created_commit_names = BTreeSet::new(); - let mut error_commits = BTreeSet::new(); - for (_commit_oid, create_status) in create_statuses { - match create_status { + match (create, dry_run) { + (false, _) => unsubmitted_commits + .into_keys() + .map(|commit_oid| (commit_oid, CreateStatus::Skipped)) + .collect(), + + (true, true) => unsubmitted_commits + .into_iter() + .map(|(commit_oid, commit_status)| { + ( + commit_oid, CreateStatus::Created { - final_commit_oid: _, - local_commit_name, - } => { - created_commit_names.insert(local_commit_name); - } - // For now, treat `Skipped` the same as `Err` as it would be - // a lot of work to render it differently in the output, and - // we may want to rethink the data structures before doing - // that. - CreateStatus::Skipped { commit_oid } | CreateStatus::Err { commit_oid } => { - error_commits.insert(commit_oid); - } - } - } - (created_commit_names, error_commits) - }; - (created_commit_names, Default::default(), error_commits) - } else { - ( - Default::default(), - unsubmitted_commit_names, - Default::default(), - ) + final_commit_oid: commit_oid, + local_commit_name: commit_status + .local_commit_name + .unwrap_or_else(|| "".to_string()), + }, + ) + }) + .collect(), + + (true, false) => try_exit_code!(forge.create(unsubmitted_commits, &submit_options)?), } }; - let (updated_commit_names, skipped_commit_names): (BTreeSet, BTreeSet) = { - let updated_commit_names = commits_to_update - .iter() - .flat_map(|(_commit_oid, commit_status)| commit_status.local_commit_name.clone()) - .collect(); - let skipped_commit_names = commits_to_skip + let update_statuses: HashMap = { + let commits_to_update: HashMap = current_statuses .iter() - .flat_map(|(_commit_oid, commit_status)| commit_status.local_commit_name.clone()) + .filter(|(_commit_oid, commit_status)| match commit_status { + CommitStatus { + submit_status: SubmitStatus::NeedsUpdate, + .. + } => true, + CommitStatus { + submit_status: + SubmitStatus::Local + | SubmitStatus::Unsubmitted + | SubmitStatus::Unknown + | SubmitStatus::UpToDate, + .. + } => false, + }) + .map(|(commit_oid, commit_status)| (*commit_oid, commit_status.clone())) .collect(); - - if !dry_run { - try_exit_code!(forge.update(commits_to_update, &submit_options)?); + if dry_run { + commits_to_update + .into_iter() + .map(|(commit_oid, commit_status)| { + ( + commit_oid, + UpdateStatus::Updated { + local_commit_name: commit_status + .local_commit_name + .unwrap_or_else(|| "".to_string()), + }, + ) + }) + .collect() + } else { + try_exit_code!(forge.update(commits_to_update, &submit_options)?) } - (updated_commit_names, skipped_commit_names) }; - if !submitted_commit_names.is_empty() { - writeln!( - effects.get_output_stream(), - "{} {}: {}", - if dry_run { "Would submit" } else { "Submitted" }, - Pluralize { - determiner: None, - amount: submitted_commit_names.len(), - unit: ("commit", "commits"), - }, - submitted_commit_names - .into_iter() - .map(|commit_name| effects - .get_glyphs() - .render( - StyledStringBuilder::new() - .append_styled(commit_name, *STYLE_PUSHED) - .build(), - ) - .expect("Rendering commit name")) - .join(", ") - )?; - } - if !updated_commit_names.is_empty() { - writeln!( - effects.get_output_stream(), - "{} {}: {}", - if dry_run { "Would update" } else { "Updated" }, - Pluralize { - determiner: None, - amount: updated_commit_names.len(), - unit: ("commit", "commits"), - }, - updated_commit_names - .into_iter() - .map(|branch_name| effects - .get_glyphs() - .render( - StyledStringBuilder::new() - .append_styled(branch_name, *STYLE_PUSHED) - .build(), - ) - .expect("Rendering commit name")) - .join(", ") - )?; - } - if !skipped_commit_names.is_empty() { - writeln!( - effects.get_output_stream(), - "{} {} (already up-to-date): {}", - if dry_run { "Would skip" } else { "Skipped" }, - Pluralize { - determiner: None, - amount: skipped_commit_names.len(), - unit: ("commit", "commits"), + let styled = |style: Style, text: &str| { + effects + .get_glyphs() + .render(StyledString::styled(text, style)) + }; + let mut had_errors = false; + for commit_oid in commit_oids { + let current_status = match current_statuses.get(&commit_oid) { + Some(status) => status, + None => { + warn!(?commit_oid, "Could not find commit status"); + continue; + } + }; + + let commit = repo.find_commit_or_fail(commit_oid)?; + let commit = effects + .get_glyphs() + .render(commit.friendly_describe(effects.get_glyphs())?)?; + + match current_status.submit_status { + SubmitStatus::Local => continue, + SubmitStatus::Unknown => { + warn!( + ?commit_oid, + "Commit status is unknown; reporting info not implemented." + ); + continue; + } + SubmitStatus::UpToDate => { + writeln!( + effects.get_output_stream(), + "{action} {commit} {info}", + action = styled( + *STYLE_SKIPPED, + if dry_run { "Would skip" } else { "Skipped" } + )?, + info = styled(*STYLE_INFO, "(already up-to-date)")?, + )?; + } + + SubmitStatus::Unsubmitted => match create_statuses.get(&commit_oid) { + Some(CreateStatus::Created { + final_commit_oid: _, + local_commit_name, + }) => { + writeln!( + effects.get_output_stream(), + "{action} {commit} {info}", + action = styled( + *STYLE_SUCCESS, + if dry_run { "Would submit" } else { "Submitted" }, + )?, + info = styled(*STYLE_INFO, &format!("(as {local_commit_name})"))?, + )?; + } + + Some(CreateStatus::Skipped) => { + writeln!( + effects.get_output_stream(), + "{action} {commit} {info}", + action = styled( + *STYLE_SKIPPED, + if dry_run { "Would skip" } else { "Skipped" }, + )?, + info = styled(*STYLE_INFO, "(pass --create to submit)")?, + )?; + } + + Some(CreateStatus::Err { message }) => { + had_errors = true; + writeln!( + effects.get_output_stream(), + "{action} {commit} {info}", + action = styled( + *STYLE_FAILED, + if dry_run { + "Would fail to create" + } else { + "Failed to create" + }, + )?, + info = styled(*STYLE_INFO, &format!("({message})"))?, + )?; + } + + None => { + writeln!( + effects.get_output_stream(), + "{action} {commit} {info}", + action = styled( + *STYLE_SKIPPED, + if dry_run { "Would skip" } else { "Skipped" }, + )?, + info = styled(*STYLE_INFO, "(unknown reason, bug?)")?, + )?; + } }, - skipped_commit_names - .into_iter() - .map(|commit_name| effects - .get_glyphs() - .render( - StyledStringBuilder::new() - .append_styled(commit_name, *STYLE_SKIPPED) - .build(), - ) - .expect("Rendering commit name")) - .join(", ") - )?; - } - if !unsubmitted_commit_names.is_empty() { - writeln!( - effects.get_output_stream(), - "{} {} (not yet on remote): {}", - if dry_run { "Would skip" } else { "Skipped" }, - Pluralize { - determiner: None, - amount: unsubmitted_commit_names.len(), - unit: ("commit", "commits") + + SubmitStatus::NeedsUpdate => match update_statuses.get(&commit_oid) { + Some(UpdateStatus::Updated { local_commit_name }) => { + writeln!( + effects.get_output_stream(), + "{action} {commit} {info}", + action = styled( + *STYLE_SUCCESS, + if dry_run { "Would update" } else { "Updated" }, + )?, + info = styled(*STYLE_INFO, &format!("(as {local_commit_name})"))?, + )?; + } + + None => { + writeln!( + effects.get_output_stream(), + "{action} {commit} {info}", + action = styled( + *STYLE_SKIPPED, + if dry_run { "Would skip" } else { "Skipped" }, + )?, + info = styled(*STYLE_INFO, "(unknown reason, bug?)")?, + )?; + } }, - unsubmitted_commit_names - .into_iter() - .map(|commit_name| effects - .get_glyphs() - .render( - StyledStringBuilder::new() - .append_styled(commit_name, *STYLE_SKIPPED) - .build(), - ) - .expect("Rendering commit name")) - .join(", ") - )?; - writeln!( - effects.get_output_stream(), - "\ -These commits {} skipped because they {} not already associated with a remote -repository. To submit them, retry this operation with the --create option.", - if dry_run { "would be" } else { "were" }, - if dry_run { "are" } else { "were" }, - )?; + }; } - if !create_error_commits.is_empty() { - writeln!( - effects.get_output_stream(), - "Failed to create {}:", - Pluralize { - determiner: None, - amount: create_error_commits.len(), - unit: ("commit", "commits") - }, - )?; - for error_commit_oid in &create_error_commits { - let error_commit = repo.find_commit_or_fail(*error_commit_oid)?; - writeln!( - effects.get_output_stream(), - "{}", - effects - .get_glyphs() - .render(error_commit.friendly_describe(effects.get_glyphs())?)? - )?; - } + + if had_errors { Ok(Err(ExitCode(1))) } else { Ok(Ok(())) diff --git a/git-branchless-submit/src/phabricator.rs b/git-branchless-submit/src/phabricator.rs index 9939ffb17..4759f7053 100644 --- a/git-branchless-submit/src/phabricator.rs +++ b/git-branchless-submit/src/phabricator.rs @@ -36,7 +36,7 @@ use thiserror::Error; use tracing::{instrument, warn}; use crate::{ - CommitStatus, CreateStatus, Forge, SubmitOptions, SubmitStatus, UpdateStatus, STYLE_PUSHED, + CommitStatus, CreateStatus, Forge, SubmitOptions, SubmitStatus, UpdateStatus, STYLE_SUCCESS, }; /// Wrapper around the Phabricator "ID" type. (This is *not* a PHID, just a @@ -540,9 +540,12 @@ fi if let Some(error_reason) = error_commits.get(&commit_oid) { create_statuses.insert( commit_oid, - match error_reason { - ErrorReason::NotTested => CreateStatus::Skipped { commit_oid }, - ErrorReason::TestFailed => CreateStatus::Err { commit_oid }, + CreateStatus::Err { + message: match error_reason { + ErrorReason::TestFailed => "arc diff failed", + ErrorReason::NotTested => "dependency could not be submitted", + } + .to_string(), }, ); continue; @@ -555,7 +558,12 @@ fi commit_oid } None => { - create_statuses.insert(commit_oid, CreateStatus::Skipped { commit_oid }); + create_statuses.insert( + commit_oid, + CreateStatus::Err { + message: "could not find rewritten commit".to_string(), + }, + ); continue; } }; @@ -563,17 +571,14 @@ fi match self.get_revision_id(final_commit_oid)? { Some(Id(id)) => format!("D{id}"), None => { - writeln!( - self.effects.get_output_stream(), - "Failed to upload (link to newly-created revision not found in commit message): {}", - self.effects.get_glyphs().render( - self.repo.friendly_describe_commit_from_oid( - self.effects.get_glyphs(), - final_commit_oid - )? - )?, - )?; - create_statuses.insert(commit_oid, CreateStatus::Err { commit_oid }); + create_statuses.insert( + commit_oid, + CreateStatus::Err { + message: + "could not find link to newly-created revision in updated commit message" + .to_string(), + }, + ); continue; } } @@ -748,18 +753,21 @@ fi .collect(), &CommitSet::empty() )?); - Ok(Ok(success_commits - .into_iter() - .map(|(commit_oid, _test_output)| (commit_oid, UpdateStatus::Updated)) - .chain( - failure_commits - .into_iter() - .map(|(commit_oid, _test_output)| { - // FIXME: report error - (commit_oid, UpdateStatus::Updated) - }), - ) - .collect())) + + let mut update_statuses = HashMap::new(); + for (commit_oid, _test_output) in success_commits.into_iter() { + let revision_id = self.get_revision_id(commit_oid)?; + let local_commit_name = match revision_id { + Some(Id(id)) => format!("D{id}"), + None => "".to_string(), + }; + update_statuses.insert(commit_oid, UpdateStatus::Updated { local_commit_name }); + } + for (commit_oid, _test_output) in failure_commits.into_iter() { + let local_commit_name = commit_oid.to_string(); + update_statuses.insert(commit_oid, UpdateStatus::Updated { local_commit_name }); + } + Ok(Ok(update_statuses)) } } @@ -993,7 +1001,7 @@ impl PhabricatorForge<'_> { fn render_id(id: &Id) -> StyledString { StyledStringBuilder::new() - .append_styled(id.to_string(), *STYLE_PUSHED) + .append_styled(id.to_string(), *STYLE_SUCCESS) .build() } diff --git a/git-branchless-submit/tests/test_github_forge.rs b/git-branchless-submit/tests/test_github_forge.rs index 2187c2b19..3c8af84a3 100644 --- a/git-branchless-submit/tests/test_github_forge.rs +++ b/git-branchless-submit/tests/test_github_forge.rs @@ -104,7 +104,8 @@ fn test_github_forge_reorder_commits() -> eyre::Result<()> { branchless: running command: push --force-with-lease origin mock-github-username/create-test1-txt Updating pull request (base branch, title, body) for commit 96d1c37 create test2.txt branchless: running command: push --force-with-lease origin mock-github-username/create-test2-txt - Submitted 2 commits: mock-github-username/create-test1-txt, mock-github-username/create-test2-txt + Submitted 62fc20d create test1.txt (as mock-github-username/create-test1-txt) + Submitted 96d1c37 create test2.txt (as mock-github-username/create-test2-txt) "###); } { @@ -175,7 +176,8 @@ fn test_github_forge_reorder_commits() -> eyre::Result<()> { branchless: running command: push --force-with-lease origin mock-github-username/create-test2-txt Updating pull request (commit, base branch, title, body) for commit 0770943 create test1.txt branchless: running command: push --force-with-lease origin mock-github-username/create-test1-txt - Updated 2 commits: mock-github-username/create-test1-txt, mock-github-username/create-test2-txt + Updated fe65c1f create test2.txt (as mock-github-username/create-test2-txt) + Updated 0770943 create test1.txt (as mock-github-username/create-test1-txt) "###); } { @@ -267,7 +269,8 @@ fn test_github_forge_mock_client_closes_pull_requests() -> eyre::Result<()> { branchless: running command: push --force-with-lease origin mock-github-username/create-test1-txt Updating pull request (base branch, title, body) for commit 96d1c37 create test2.txt branchless: running command: push --force-with-lease origin mock-github-username/create-test2-txt - Submitted 2 commits: mock-github-username/create-test1-txt, mock-github-username/create-test2-txt + Submitted 62fc20d create test1.txt (as mock-github-username/create-test1-txt) + Submitted 96d1c37 create test2.txt (as mock-github-username/create-test2-txt) "###); } { @@ -359,7 +362,7 @@ fn test_github_forge_mock_client_closes_pull_requests() -> eyre::Result<()> { insta::assert_snapshot!(stdout, @r###" Updating pull request (commit, base branch, title, body) for commit fa46633 create test2.txt branchless: running command: push --force-with-lease origin mock-github-username/create-test2-txt - Updated 1 commit: mock-github-username/create-test2-txt + Updated fa46633 create test2.txt (as mock-github-username/create-test2-txt) "###); } { @@ -458,7 +461,7 @@ fn test_github_forge_no_include_unsubmitted_commits_in_stack() -> eyre::Result<( branch 'mock-github-username/create-test1-txt' set up to track 'origin/mock-github-username/create-test1-txt'. Updating pull request (title, body) for commit 62fc20d create test1.txt branchless: running command: push --force-with-lease origin mock-github-username/create-test1-txt - Submitted 1 commit: mock-github-username/create-test1-txt + Submitted 62fc20d create test1.txt (as mock-github-username/create-test1-txt) "###); } { @@ -548,7 +551,7 @@ fn test_github_forge_multiple_commits_in_pull_request() -> eyre::Result<()> { branch 'mock-github-username/create-test3-txt' set up to track 'origin/mock-github-username/create-test3-txt'. Updating pull request (title, body) for commit 70deb1e create test3.txt branchless: running command: push --force-with-lease origin mock-github-username/create-test3-txt - Submitted 1 commit: mock-github-username/create-test3-txt + Submitted 70deb1e create test3.txt (as mock-github-username/create-test3-txt) "###); } { diff --git a/git-branchless-submit/tests/test_phabricator_forge.rs b/git-branchless-submit/tests/test_phabricator_forge.rs index 62ff7a46e..48da6e3b4 100644 --- a/git-branchless-submit/tests/test_phabricator_forge.rs +++ b/git-branchless-submit/tests/test_phabricator_forge.rs @@ -76,7 +76,8 @@ fn test_submit_phabricator_strategy_working_copy() -> eyre::Result<()> { branchless: running command: rebase --continue Using command execution strategy: working-copy branchless: running command: rebase --abort - Submitted 2 commits: D0002, D0003 + Submitted 62fc20d create test1.txt (as D0002) + Submitted 96d1c37 create test2.txt (as D0003) "###); } @@ -151,7 +152,8 @@ fn test_submit_phabricator_strategy_worktree() -> eyre::Result<()> { Setting D0002 as stack root (no dependencies) Stacking D0003 on top of D0002 Using command execution strategy: worktree - Submitted 2 commits: D0002, D0003 + Submitted 62fc20d create test1.txt (as D0002) + Submitted 96d1c37 create test2.txt (as D0003) "###); } @@ -207,7 +209,8 @@ fn test_submit_phabricator_update() -> eyre::Result<()> { branchless: running command: rebase --continue Using command execution strategy: working-copy branchless: running command: rebase --abort - Submitted 2 commits: D0002, D0003 + Submitted 62fc20d create test1.txt (as D0002) + Submitted 96d1c37 create test2.txt (as D0003) "###); } @@ -228,6 +231,8 @@ fn test_submit_phabricator_update() -> eyre::Result<()> { branchless: running command: rebase --abort Setting D0002 as stack root (no dependencies) Stacking D0003 on top of D0002 + Updated 55af3db create test1.txt (as D0002) + Updated ccb7fd5 create test2.txt (as D0003) "###); } @@ -290,10 +295,9 @@ fn test_submit_phabricator_failure_commit() -> eyre::Result<()> { branchless: running command: rebase --continue Using command execution strategy: working-copy branchless: running command: rebase --abort - Submitted 1 commit: D0002 - Failed to create 2 commits: - 5b9de4b BROKEN: test2.txt - e9d3664 create test3.txt + Submitted 62fc20d create test1.txt (as D0002) + Failed to create 5b9de4b BROKEN: test2.txt (arc diff failed) + Failed to create e9d3664 create test3.txt (dependency could not be submitted) "###); } diff --git a/git-branchless-submit/tests/test_submit.rs b/git-branchless-submit/tests/test_submit.rs index ebf3f0f82..3fdbc6542 100644 --- a/git-branchless-submit/tests/test_submit.rs +++ b/git-branchless-submit/tests/test_submit.rs @@ -58,9 +58,8 @@ fn test_submit() -> eyre::Result<()> { let (stdout, stderr) = cloned_repo.run(&["submit"])?; insta::assert_snapshot!(stderr, @""); insta::assert_snapshot!(stdout, @r###" - Skipped 2 commits (not yet on remote): bar, qux - These commits were skipped because they were not already associated with a remote - repository. To submit them, retry this operation with the --create option. + Skipped f57e36f create test4.txt (pass --create to submit) + Skipped 20230db create test5.txt (pass --create to submit) "###); } @@ -69,9 +68,8 @@ fn test_submit() -> eyre::Result<()> { let (stdout, stderr) = cloned_repo.run(&["submit", "bar+qux"])?; insta::assert_snapshot!(stderr, @""); insta::assert_snapshot!(stdout, @r###" - Skipped 2 commits (not yet on remote): bar, qux - These commits were skipped because they were not already associated with a remote - repository. To submit them, retry this operation with the --create option. + Skipped f57e36f create test4.txt (pass --create to submit) + Skipped 20230db create test5.txt (pass --create to submit) "###); } @@ -80,9 +78,8 @@ fn test_submit() -> eyre::Result<()> { let (stdout, stderr) = cloned_repo.run(&["submit", "bar", "qux"])?; insta::assert_snapshot!(stderr, @""); insta::assert_snapshot!(stdout, @r###" - Skipped 2 commits (not yet on remote): bar, qux - These commits were skipped because they were not already associated with a remote - repository. To submit them, retry this operation with the --create option. + Skipped f57e36f create test4.txt (pass --create to submit) + Skipped 20230db create test5.txt (pass --create to submit) "###); } @@ -90,9 +87,8 @@ fn test_submit() -> eyre::Result<()> { let (stdout, stderr) = cloned_repo.run(&["submit", "--dry-run"])?; insta::assert_snapshot!(stderr, @""); insta::assert_snapshot!(stdout, @r###" - Would skip 2 commits (not yet on remote): bar, qux - These commits would be skipped because they are not already associated with a remote - repository. To submit them, retry this operation with the --create option. + Would skip f57e36f create test4.txt (pass --create to submit) + Would skip 20230db create test5.txt (pass --create to submit) "###); } @@ -100,7 +96,8 @@ fn test_submit() -> eyre::Result<()> { let (stdout, stderr) = cloned_repo.run(&["submit", "--create", "--dry-run"])?; insta::assert_snapshot!(stderr, @""); insta::assert_snapshot!(stdout, @r###" - Would submit 2 commits: bar, qux + Would submit f57e36f create test4.txt (as bar) + Would submit 20230db create test5.txt (as qux) "###); } @@ -120,7 +117,8 @@ fn test_submit() -> eyre::Result<()> { branchless: running command: push --set-upstream origin bar qux branch 'bar' set up to track 'origin/bar'. branch 'qux' set up to track 'origin/qux'. - Submitted 2 commits: bar, qux + Submitted f57e36f create test4.txt (as bar) + Submitted 20230db create test5.txt (as qux) "###); } @@ -150,8 +148,8 @@ fn test_submit() -> eyre::Result<()> { insta::assert_snapshot!(stdout, @r###" branchless: running command: fetch origin refs/heads/bar refs/heads/qux branchless: running command: push --force-with-lease origin qux - Updated 1 commit: qux - Skipped 1 commit (already up-to-date): bar + Skipped f57e36f create test4.txt (already up-to-date) + Updated bae8307 updated message (as qux) "###); } @@ -166,7 +164,8 @@ fn test_submit() -> eyre::Result<()> { "###); insta::assert_snapshot!(stdout, @r###" branchless: running command: fetch origin refs/heads/bar refs/heads/qux - Skipped 2 commits (already up-to-date): bar, qux + Skipped f57e36f create test4.txt (already up-to-date) + Skipped bae8307 updated message (already up-to-date) "###); } @@ -323,7 +322,7 @@ fn test_submit_up_to_date_branch() -> eyre::Result<()> { insta::assert_snapshot!(stdout, @r###" branchless: running command: push --set-upstream origin feature branch 'feature' set up to track 'origin/feature'. - Submitted 1 commit: feature + Submitted 70deb1e create test3.txt (as feature) "###); } @@ -337,7 +336,7 @@ fn test_submit_up_to_date_branch() -> eyre::Result<()> { "###); insta::assert_snapshot!(stdout, @r###" branchless: running command: fetch origin refs/heads/feature - Skipped 1 commit (already up-to-date): feature + Skipped 70deb1e create test3.txt (already up-to-date) "###); }