feat: scope local reviews to comparisons
This commit is contained in:
+323
-2
@@ -3017,6 +3017,15 @@ fn diff_preserves_parked_buffers_visual_carets_and_insert_history() {
|
||||
}
|
||||
|
||||
fn working_diff(editor: &mut Editor, root: &Path, paths: &[&str]) -> Box<[(PathBuf, String)]> {
|
||||
working_diff_with_revisions(editor, root, paths, ["base", "working-snapshot"])
|
||||
}
|
||||
|
||||
fn working_diff_with_revisions(
|
||||
editor: &mut Editor,
|
||||
root: &Path,
|
||||
paths: &[&str],
|
||||
revisions: [&str; 2],
|
||||
) -> Box<[(PathBuf, String)]> {
|
||||
use crate::diff::{Catalog, Category, ChangedFile, Comparison, FileStatus, RepoKind, Revision};
|
||||
editor.execute("diff");
|
||||
let (id, _) = editor.take_diff_request().unwrap();
|
||||
@@ -3070,7 +3079,7 @@ fn working_diff(editor: &mut Editor, root: &Path, paths: &[&str]) -> Box<[(PathB
|
||||
Ok(Outcome::Comparison(Comparison {
|
||||
blame: Default::default(),
|
||||
root: root.canonicalize().unwrap(),
|
||||
revisions: ["base".into(), "working-snapshot".into()],
|
||||
revisions: revisions.map(str::to_owned),
|
||||
before: "base".into(),
|
||||
after: "Working".into(),
|
||||
editable_paths: paths.iter().map(|path| PathBuf::from(*path)).collect(),
|
||||
@@ -3081,6 +3090,16 @@ fn working_diff(editor: &mut Editor, root: &Path, paths: &[&str]) -> Box<[(PathB
|
||||
}
|
||||
|
||||
fn historical_diff(editor: &mut Editor, root: &Path, before: Vec<String>, after: Vec<String>) {
|
||||
historical_diff_with_revisions(editor, root, before, after, ["base", "head"]);
|
||||
}
|
||||
|
||||
fn historical_diff_with_revisions(
|
||||
editor: &mut Editor,
|
||||
root: &Path,
|
||||
before: Vec<String>,
|
||||
after: Vec<String>,
|
||||
revisions: [&str; 2],
|
||||
) {
|
||||
use crate::diff::{Catalog, Category, ChangedFile, Comparison, FileStatus, RepoKind, Revision};
|
||||
editor.execute("diff");
|
||||
let (id, _) = editor.take_diff_request().unwrap();
|
||||
@@ -3108,7 +3127,7 @@ fn historical_diff(editor: &mut Editor, root: &Path, before: Vec<String>, after:
|
||||
Ok(Outcome::Comparison(Comparison {
|
||||
blame: Default::default(),
|
||||
root: root.to_owned(),
|
||||
revisions: ["base".into(), "head".into()],
|
||||
revisions: revisions.map(str::to_owned),
|
||||
before: "base".into(),
|
||||
after: "head".into(),
|
||||
editable_paths: Default::default(),
|
||||
@@ -3154,6 +3173,305 @@ fn source_review_editor(directory: &Directory, text: &str) -> (Editor, PathBuf,
|
||||
(editor, root, path)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn comparison_reviews_use_ordered_resolved_identities_and_resume_only_the_same_pair() {
|
||||
use crate::review::{Store, Verdict};
|
||||
let directory = Directory::new();
|
||||
let (mut editor, root, _) = source_review_editor(&directory, "source\n");
|
||||
historical_diff(&mut editor, &root, vec!["old".into()], vec!["new".into()]);
|
||||
editor.execute("comment");
|
||||
type_text(&mut editor, "iPair feedback");
|
||||
editor.handle(Input::Escape);
|
||||
editor.execute("w");
|
||||
editor.handle(Input::Escape);
|
||||
editor.execute("diff.review.toggle");
|
||||
editor.execute("review.verdict looks_good");
|
||||
let original = editor.local_review.document.clone();
|
||||
editor.handle(Input::Escape);
|
||||
for pair in [["other", "head"], ["base", "other"], ["head", "base"]] {
|
||||
historical_diff_with_revisions(
|
||||
&mut editor,
|
||||
&root,
|
||||
vec!["old".into()],
|
||||
vec!["new".into()],
|
||||
pair,
|
||||
);
|
||||
assert_eq!(
|
||||
editor.local_review.document.comparison,
|
||||
Some(pair.map(str::to_owned))
|
||||
);
|
||||
assert!(editor.local_review.document.comments.is_empty());
|
||||
assert!(editor.local_review.document.verdict.is_none());
|
||||
assert!(editor.local_review.document.reviewed_files.is_empty());
|
||||
assert!(editor.workspace_diff().unwrap().reviewed_files.is_empty());
|
||||
editor.execute("review.verdict changes_requested");
|
||||
assert_ne!(editor.local_review.document.storage_id, original.storage_id);
|
||||
editor.handle(Input::Escape);
|
||||
}
|
||||
historical_diff(&mut editor, &root, vec!["old".into()], vec!["new".into()]);
|
||||
assert_eq!(editor.local_review.document.storage_id, original.storage_id);
|
||||
assert_eq!(
|
||||
editor.local_review.document.comments[0].body,
|
||||
"Pair feedback"
|
||||
);
|
||||
assert_eq!(
|
||||
editor.local_review.document.verdict,
|
||||
Some(Verdict::LooksGood)
|
||||
);
|
||||
assert_eq!(
|
||||
editor.workspace_diff().unwrap().reviewed_files,
|
||||
BTreeSet::from([0])
|
||||
);
|
||||
assert_eq!(
|
||||
Store::open(&root.join("reviews"))
|
||||
.unwrap()
|
||||
.list(&root)
|
||||
.unwrap()
|
||||
.len(),
|
||||
4
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn source_and_comparison_reviews_remain_separate_in_shared_panes_and_tabs() {
|
||||
let directory = Directory::new();
|
||||
let (mut editor, root, _) = source_review_editor(&directory, "source\n");
|
||||
let source = editor.pane_id;
|
||||
editor.execute("comment");
|
||||
type_text(&mut editor, "iSource feedback");
|
||||
editor.handle(Input::Escape);
|
||||
editor.execute("w");
|
||||
let source_id = editor.local_review.document.storage_id;
|
||||
editor.handle(Input::Escape);
|
||||
editor.split_pane(SplitAxis::Vertical);
|
||||
let comparison_pane = editor.pane_id;
|
||||
historical_diff(&mut editor, &root, vec!["old".into()], vec!["new".into()]);
|
||||
editor.execute("comment");
|
||||
type_text(&mut editor, "iComparison feedback");
|
||||
editor.handle(Input::Escape);
|
||||
editor.execute("w");
|
||||
let comparison_id = editor.local_review.document.storage_id;
|
||||
assert_ne!(comparison_id, source_id);
|
||||
editor.handle(Input::Escape);
|
||||
editor.select_pane(source);
|
||||
editor.execute("review.edit 1");
|
||||
assert_eq!(editor.local_review.document.storage_id, source_id);
|
||||
assert!(editor.local_review.document.comparison.is_none());
|
||||
assert_eq!(editor.context().text, "Source feedback");
|
||||
editor.handle(Input::Escape);
|
||||
editor.select_pane(comparison_pane);
|
||||
editor.execute("review.edit 1");
|
||||
assert_eq!(editor.local_review.document.storage_id, comparison_id);
|
||||
assert_eq!(editor.context().text, "Comparison feedback");
|
||||
editor.handle(Input::Escape);
|
||||
editor.select_pane(source);
|
||||
editor.execute("tab.new");
|
||||
editor.execute("review.edit 1");
|
||||
assert_eq!(editor.local_review.document.storage_id, source_id);
|
||||
assert_eq!(editor.context().text, "Source feedback");
|
||||
editor.handle(Input::Escape);
|
||||
historical_diff(&mut editor, &root, vec!["old".into()], vec!["new".into()]);
|
||||
assert_eq!(editor.local_review.document.storage_id, comparison_id);
|
||||
editor.execute("tab.previous");
|
||||
editor.select_pane(comparison_pane);
|
||||
editor.execute("review.edit 1");
|
||||
assert_eq!(editor.context().text, "Comparison feedback");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn review_selectors_and_explicit_opens_reject_other_comparison_and_source_scopes() {
|
||||
use crate::review::{Review, Store};
|
||||
let directory = Directory::new();
|
||||
let (mut editor, root, _) = source_review_editor(&directory, "source\n");
|
||||
let mut store = Store::open(&root.join("reviews")).unwrap();
|
||||
let mut source = Review::new(root.clone());
|
||||
source.summary = "source-only".into();
|
||||
store.save(&mut source).unwrap();
|
||||
let mut other = Review::new(root.clone());
|
||||
other.comparison = Some(["different".into(), "head".into()]);
|
||||
other.summary = "other-pair-only".into();
|
||||
store.save(&mut other).unwrap();
|
||||
let other_json = root.join("other.json");
|
||||
other.save(&other_json).unwrap();
|
||||
let source_json = root.join("source.json");
|
||||
source.save(&source_json).unwrap();
|
||||
historical_diff(&mut editor, &root, vec!["old".into()], vec!["new".into()]);
|
||||
editor.execute("review.verdict looks_good");
|
||||
let current = editor.local_review.document.clone();
|
||||
for command in [
|
||||
format!("review.open {}", source.storage_id.unwrap()),
|
||||
format!("review.open {}", other.storage_id.unwrap()),
|
||||
format!("review.open {}", source_json.display()),
|
||||
format!("review.open {}", other_json.display()),
|
||||
] {
|
||||
editor.execute(&command);
|
||||
assert!(
|
||||
editor
|
||||
.message()
|
||||
.contains("different comparison or source scope")
|
||||
);
|
||||
assert_eq!(editor.local_review.document.storage_id, current.storage_id);
|
||||
assert_eq!(editor.local_review.document.comparison, current.comparison);
|
||||
assert_eq!(editor.local_review.document.verdict, current.verdict);
|
||||
}
|
||||
editor.execute("review.new");
|
||||
let second_id = editor.local_review.document.storage_id;
|
||||
editor.execute("review.open");
|
||||
assert!(!editor.context().text.contains("source-only"));
|
||||
assert!(!editor.context().text.contains("other-pair-only"));
|
||||
editor.handle(Input::Enter);
|
||||
assert_eq!(editor.local_review.document.storage_id, second_id);
|
||||
editor.execute(&format!("review.open {}", current.storage_id.unwrap()));
|
||||
assert_eq!(editor.local_review.document.storage_id, current.storage_id);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dirty_review_drafts_guard_scope_replacement_new_reviews_and_mode_changes() {
|
||||
let directory = Directory::new();
|
||||
let (mut editor, root, _) = source_review_editor(&directory, "source\n");
|
||||
let source = editor.pane_id;
|
||||
editor.split_pane(SplitAxis::Vertical);
|
||||
let comparison_pane = editor.pane_id;
|
||||
historical_diff(&mut editor, &root, vec!["old".into()], vec!["new".into()]);
|
||||
editor.execute("comment");
|
||||
type_text(&mut editor, "iUnsaved feedback");
|
||||
editor.handle(Input::Escape);
|
||||
let draft = editor.buffer_id();
|
||||
let panel = editor.review_pane.unwrap();
|
||||
let scope = editor.local_review.document.comparison.clone();
|
||||
editor.execute("review.new");
|
||||
assert!(editor.message().contains("Save the current local review"));
|
||||
assert_eq!(editor.context().text, "Unsaved feedback");
|
||||
editor.select_pane(source);
|
||||
editor.execute("review.overview");
|
||||
assert!(editor.message().contains("changing review scopes"));
|
||||
assert_eq!(editor.local_review.document.comparison, scope);
|
||||
editor.select_pane(comparison_pane);
|
||||
let comparison = editor.workspace_diff().unwrap().comparison_id;
|
||||
editor.act(Action::DiffModeToggle);
|
||||
assert_eq!(editor.workspace_diff().unwrap().comparison_id, comparison);
|
||||
assert!(editor.workspace_diff().unwrap().comparison.is_some());
|
||||
editor.execute("diff");
|
||||
assert_eq!(editor.workspace_diff().unwrap().comparison_id, comparison);
|
||||
editor.select_pane(panel);
|
||||
assert_eq!(editor.buffer_id(), draft);
|
||||
assert_eq!(editor.context().text, "Unsaved feedback");
|
||||
editor.execute("w");
|
||||
editor.handle(Input::Escape);
|
||||
editor.select_pane(source);
|
||||
editor.execute("review.overview");
|
||||
assert!(editor.local_review.document.comparison.is_none());
|
||||
assert!(editor.local_review.document.comments.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn working_refresh_keeps_review_scope_and_drafts_but_explicit_reopen_uses_new_identities() {
|
||||
let directory = Directory::new();
|
||||
let (mut editor, root, _) = source_review_editor(&directory, "source\n");
|
||||
fs::write(root.join("file.txt"), "original\n").unwrap();
|
||||
working_diff(&mut editor, &root, &["file.txt"]);
|
||||
editor.handle(Input::Enter);
|
||||
editor.execute("comment");
|
||||
type_text(&mut editor, "iWorking feedback");
|
||||
editor.handle(Input::Escape);
|
||||
editor.execute("w");
|
||||
editor.handle(Input::Escape);
|
||||
let original_id = editor.local_review.document.storage_id;
|
||||
let scope = editor.local_review.document.comparison.clone();
|
||||
editor.execute("review.summary");
|
||||
type_text(&mut editor, "iUnsaved working summary");
|
||||
editor.handle(Input::Escape);
|
||||
let panel = editor.review_pane.unwrap();
|
||||
let owner = editor.diff_owner.unwrap();
|
||||
editor.queue_checkout_refreshes(true);
|
||||
let (_, request, _) = editor.take_next_diff_request().unwrap();
|
||||
let mut replacement = editor.with_pane(owner, |editor| {
|
||||
editor.diff.as_mut().unwrap().comparison.take().unwrap()
|
||||
});
|
||||
replacement.revisions[1] = "working:changed".into();
|
||||
replacement.files[0].after = vec!["refreshed".into()];
|
||||
assert!(editor.apply_diff_result(request, Ok(Outcome::CheckoutRefresh(Some(replacement)))));
|
||||
assert_eq!(editor.local_review.document.comparison, scope);
|
||||
assert_eq!(editor.local_review.document.storage_id, original_id);
|
||||
assert_eq!(
|
||||
editor.local_review.document.comments[0].body,
|
||||
"Working feedback"
|
||||
);
|
||||
assert!(editor.current_review_dirty());
|
||||
editor.select_pane(panel);
|
||||
assert_eq!(editor.context().text, "Unsaved working summary");
|
||||
editor.execute("w");
|
||||
editor.handle(Input::Escape);
|
||||
working_diff_with_revisions(
|
||||
&mut editor,
|
||||
&root,
|
||||
&["file.txt"],
|
||||
["base", "working:changed"],
|
||||
);
|
||||
assert!(editor.local_review.document.comments.is_empty());
|
||||
assert!(editor.local_review.document.summary.is_empty());
|
||||
editor.execute("review.verdict looks_good");
|
||||
assert_ne!(editor.local_review.document.storage_id, original_id);
|
||||
editor.handle(Input::Escape);
|
||||
working_diff(&mut editor, &root, &["file.txt"]);
|
||||
assert_eq!(editor.local_review.document.storage_id, original_id);
|
||||
assert_eq!(
|
||||
editor.local_review.document.summary,
|
||||
"Unsaved working summary"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn moved_bookmark_selects_new_review_and_dirty_draft_blocks_endpoint_replacement() {
|
||||
use crate::diff::Comparison;
|
||||
let directory = Directory::new();
|
||||
let (mut editor, root, _) = source_review_editor(&directory, "source\n");
|
||||
historical_diff(&mut editor, &root, vec!["old".into()], vec!["new".into()]);
|
||||
editor.execute("review.verdict looks_good");
|
||||
let original_id = editor.local_review.document.storage_id;
|
||||
editor.handle(Input::Escape);
|
||||
editor.execute("review.summary");
|
||||
type_text(&mut editor, "iBookmark draft");
|
||||
editor.handle(Input::Escape);
|
||||
let panel = editor.review_pane.unwrap();
|
||||
let moved = || Comparison {
|
||||
revisions: ["base".into(), "moved-head".into()],
|
||||
root: root.clone(),
|
||||
before: "base".into(),
|
||||
after: "head".into(),
|
||||
blame: Default::default(),
|
||||
editable_paths: Default::default(),
|
||||
files: Vec::new(),
|
||||
};
|
||||
editor.queue_checkout_refreshes(false);
|
||||
let (_, request, _) = editor.take_next_diff_request().unwrap();
|
||||
assert!(editor.apply_diff_result(request, Ok(Outcome::BookmarkRefresh(moved()))));
|
||||
assert_eq!(editor.local_review.document.storage_id, original_id);
|
||||
assert_eq!(
|
||||
editor
|
||||
.workspace_diff()
|
||||
.unwrap()
|
||||
.comparison
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.revisions[1],
|
||||
"head"
|
||||
);
|
||||
editor.select_pane(panel);
|
||||
assert_eq!(editor.context().text, "Bookmark draft");
|
||||
editor.execute("w");
|
||||
editor.handle(Input::Escape);
|
||||
editor.queue_checkout_refreshes(false);
|
||||
let (_, request, _) = editor.take_next_diff_request().unwrap();
|
||||
assert!(editor.apply_diff_result(request, Ok(Outcome::BookmarkRefresh(moved()))));
|
||||
assert_eq!(
|
||||
editor.local_review.document.comparison,
|
||||
Some(["base".into(), "moved-head".into()])
|
||||
);
|
||||
assert!(editor.local_review.document.verdict.is_none());
|
||||
assert!(editor.local_review.document.summary.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn source_review_drafts_guard_source_pane_close_and_saved_panels_retarget() {
|
||||
let directory = Directory::new();
|
||||
@@ -3443,6 +3761,8 @@ fn review_navigation_maps_working_ranges_and_preserves_stale_snapshots() {
|
||||
.unwrap()
|
||||
.revisions[1] = "working:old".into();
|
||||
editor.local_review.document = crate::review::Review::new(root);
|
||||
editor.local_review.document.comparison =
|
||||
editor.workspace_diff().unwrap().review_comparison.clone();
|
||||
let anchor = Anchor {
|
||||
revision: "working:old".into(),
|
||||
path: "file.txt".into(),
|
||||
@@ -7595,6 +7915,7 @@ mod system_clipboard {
|
||||
let root = fixture.0.0.canonicalize().unwrap();
|
||||
let storage = root.join("reviews");
|
||||
let mut review = Review::new(root.clone());
|
||||
review.comparison = Some(["base".into(), "head".into()]);
|
||||
review.summary = "Review summary".into();
|
||||
review.verdict = Some(Verdict::ChangesRequested);
|
||||
review.comments = vec![
|
||||
|
||||
Reference in New Issue
Block a user