ok/jj
1
0
Fork 0
forked from mirrors/jj

cli: don't crash if $EDITOR fails

This commit is contained in:
Martin von Zweigbergk 2022-04-09 15:53:32 -07:00 committed by Martin von Zweigbergk
parent f8724ee5a9
commit 2958f5791c
3 changed files with 37 additions and 12 deletions

View file

@ -26,6 +26,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* `jj untrack` now requires at least one path (allowing no arguments was a UX * `jj untrack` now requires at least one path (allowing no arguments was a UX
bug). bug).
* You now get a proper error message instead of a crash when `$EDITOR` doesn't
exist or exits with an error.
## [0.4.0] - 2022-04-02 ## [0.4.0] - 2022-04-02
### Breaking changes ### Breaking changes

View file

@ -2951,7 +2951,7 @@ fn cmd_obslog(ui: &mut Ui, command: &CommandHelper, args: &ObslogArgs) -> Result
Ok(()) Ok(())
} }
fn edit_description(repo: &ReadonlyRepo, description: &str) -> String { fn edit_description(repo: &ReadonlyRepo, description: &str) -> Result<String, CommandError> {
let random: u32 = rand::random(); let random: u32 = rand::random();
let description_file_path = repo.repo_path().join(format!("description-{}", random)); let description_file_path = repo.repo_path().join(format!("description-{}", random));
{ {
@ -2975,8 +2975,12 @@ fn edit_description(repo: &ReadonlyRepo, description: &str) -> String {
.args(editor_args) .args(editor_args)
.arg(&description_file_path) .arg(&description_file_path)
.status() .status()
.expect("failed to run editor"); .map_err(|_| CommandError::UserError(format!("Failed to run editor '{editor}'")))?;
assert!(exit_status.success(), "failed to run editor"); if !exit_status.success() {
return Err(CommandError::UserError(format!(
"Editor '{editor}' exited with an error"
)));
}
let mut description_file = OpenOptions::new() let mut description_file = OpenOptions::new()
.read(true) .read(true)
@ -2996,7 +3000,7 @@ fn edit_description(repo: &ReadonlyRepo, description: &str) -> String {
while matches!(lines.last(), Some(&"\n") | Some(&"\r\n")) { while matches!(lines.last(), Some(&"\n") | Some(&"\r\n")) {
lines.pop().unwrap(); lines.pop().unwrap();
} }
lines.join("") Ok(lines.join(""))
} }
fn cmd_describe( fn cmd_describe(
@ -3016,7 +3020,7 @@ fn cmd_describe(
} else if let Some(message) = &args.message { } else if let Some(message) = &args.message {
description = message.to_owned() description = message.to_owned()
} else { } else {
description = edit_description(repo, commit.description()); description = edit_description(repo, commit.description())?;
} }
if description == *commit.description() { if description == *commit.description() {
ui.write("Nothing changed.\n")?; ui.write("Nothing changed.\n")?;
@ -3054,9 +3058,9 @@ fn cmd_close(ui: &mut Ui, command: &CommandHelper, args: &CloseArgs) -> Result<(
let description = if let Some(message) = &args.message { let description = if let Some(message) = &args.message {
message.to_string() message.to_string()
} else if commit.description().is_empty() { } else if commit.description().is_empty() {
edit_description(repo, "\n\nJJ: Enter commit description.\n") edit_description(repo, "\n\nJJ: Enter commit description.\n")?
} else if args.edit { } else if args.edit {
edit_description(repo, commit.description()) edit_description(repo, commit.description())?
} else { } else {
commit.description().to_string() commit.description().to_string()
}; };
@ -3496,7 +3500,7 @@ any changes, then the operation will be aborted.
repo, repo,
&("JJ: Enter commit description for the first part.\n".to_string() &("JJ: Enter commit description for the first part.\n".to_string()
+ commit.description()), + commit.description()),
); )?;
let first_commit = CommitBuilder::for_rewrite_from(ui.settings(), repo.store(), &commit) let first_commit = CommitBuilder::for_rewrite_from(ui.settings(), repo.store(), &commit)
.set_tree(tree_id) .set_tree(tree_id)
.set_description(first_description) .set_description(first_description)
@ -3505,7 +3509,7 @@ any changes, then the operation will be aborted.
repo, repo,
&("JJ: Enter commit description for the second part.\n".to_string() &("JJ: Enter commit description for the second part.\n".to_string()
+ commit.description()), + commit.description()),
); )?;
let second_commit = CommitBuilder::for_rewrite_from(ui.settings(), repo.store(), &commit) let second_commit = CommitBuilder::for_rewrite_from(ui.settings(), repo.store(), &commit)
.set_parents(vec![first_commit.id().clone()]) .set_parents(vec![first_commit.id().clone()])
.set_tree(commit.tree().id().clone()) .set_tree(commit.tree().id().clone())
@ -3566,7 +3570,7 @@ fn cmd_merge(ui: &mut Ui, command: &CommandHelper, args: &MergeArgs) -> Result<(
edit_description( edit_description(
repo, repo,
"\n\nJJ: Enter commit description for the merge commit.\n", "\n\nJJ: Enter commit description for the merge commit.\n",
) )?
}; };
let merged_tree = merge_commit_trees(repo.as_repo_ref(), &commits); let merged_tree = merge_commit_trees(repo.as_repo_ref(), &commits);
let mut tx = workspace_command.start_transaction("merge commits"); let mut tx = workspace_command.start_transaction("merge commits");

View file

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use crate::common::TestEnvironment; use crate::common::{get_stderr_string, TestEnvironment};
pub mod common; pub mod common;
@ -42,8 +42,26 @@ fn test_describe() {
"); ");
// Lines in editor starting with "JJ: " are ignored // Lines in editor starting with "JJ: " are ignored
std::fs::write(&edit_script, "write\nJJ: ignored\ndescription among comment\nJJ: ignored").unwrap(); std::fs::write(
&edit_script,
"write\nJJ: ignored\ndescription among comment\nJJ: ignored",
)
.unwrap();
let stdout = test_env.jj_cmd_success(&repo_path, &["describe"]); let stdout = test_env.jj_cmd_success(&repo_path, &["describe"]);
insta::assert_snapshot!(stdout, @"Working copy now at: 95664f6316ae description among comment insta::assert_snapshot!(stdout, @"Working copy now at: 95664f6316ae description among comment
"); ");
// Fails if the editor fails
std::fs::write(&edit_script, "fail").unwrap();
let stderr = test_env.jj_cmd_failure(&repo_path, &["describe"]);
assert!(stderr.contains("exited with an error"));
// Fails if the editor doesn't exist
std::fs::write(&edit_script, "").unwrap();
let assert = test_env
.jj_cmd(&repo_path, &["describe"])
.env("EDITOR", "this-editor-does-not-exist")
.assert()
.failure();
assert!(get_stderr_string(&assert).contains("Failed to run"));
} }