History

Add Danger check for changes to eval fixtures (#33852)

Also, revert unintentional changes to fixtures. Changes to test fixtures are intentional and necessary. Release Notes: - N/A

Oleksiy Syvokon committed 1 year ago

Commit cc0d8a41 parent 12ab53b2 files · +41 −188Browse files

Unified · Split

2 files
  1. crates/assistant_tools/src/edit_agent/evals/fixtures/disable_cursor_blinking/before.rs +20 −188
  2. script/danger/dangerfile.ts +21 −0
crates/assistant_tools/src/edit_agent/evals/fixtures/disable_cursor_blinking/before.rs+20−188
@@ -9132,7 +9132,7 @@ impl Editor { · 9131 unmodified lines
9132 window: &mut Window,9132 window: &mut Window,
9133 cx: &mut Context<Self>,9133 cx: &mut Context<Self>,
9134 ) {9134 ) {
9135 self.manipulate_immutable_lines(window, cx, |lines| lines.sort())9135 self.manipulate_lines(window, cx, |lines| lines.sort())
9136 }9136 }
9137 9137
9138 pub fn sort_lines_case_insensitive(9138 pub fn sort_lines_case_insensitive(
@@ -9141,7 +9141,7 @@ impl Editor { · 2 unmodified lines
9141 window: &mut Window,9141 window: &mut Window,
9142 cx: &mut Context<Self>,9142 cx: &mut Context<Self>,
9143 ) {9143 ) {
9144 self.manipulate_immutable_lines(window, cx, |lines| {9144 self.manipulate_lines(window, cx, |lines| {
9145 lines.sort_by_key(|line| line.to_lowercase())9145 lines.sort_by_key(|line| line.to_lowercase())
9146 })9146 })
9147 }9147 }
@@ -9152,7 +9152,7 @@ impl Editor { · 4 unmodified lines
9152 window: &mut Window,9152 window: &mut Window,
9153 cx: &mut Context<Self>,9153 cx: &mut Context<Self>,
9154 ) {9154 ) {
9155 self.manipulate_immutable_lines(window, cx, |lines| {9155 self.manipulate_lines(window, cx, |lines| {
9156 let mut seen = HashSet::default();9156 let mut seen = HashSet::default();
9157 lines.retain(|line| seen.insert(line.to_lowercase()));9157 lines.retain(|line| seen.insert(line.to_lowercase()));
9158 })9158 })
@@ -9164,7 +9164,7 @@ impl Editor { · 5 unmodified lines
9164 window: &mut Window,9164 window: &mut Window,
9165 cx: &mut Context<Self>,9165 cx: &mut Context<Self>,
9166 ) {9166 ) {
9167 self.manipulate_immutable_lines(window, cx, |lines| {9167 self.manipulate_lines(window, cx, |lines| {
9168 let mut seen = HashSet::default();9168 let mut seen = HashSet::default();
9169 lines.retain(|line| seen.insert(*line));9169 lines.retain(|line| seen.insert(*line));
9170 })9170 })
@@ -9606,20 +9606,20 @@ impl Editor { · 435 unmodified lines
9606 }9606 }
9607 9607
9608 pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {9608 pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
9609 self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())9609 self.manipulate_lines(window, cx, |lines| lines.reverse())
9610 }9610 }
9611 9611
9612 pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {9612 pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
9613 self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))9613 self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
9614 }9614 }
9615 9615
9616 fn manipulate_lines<M>(9616 fn manipulate_lines<Fn>(
9617 &mut self,9617 &mut self,
9618 window: &mut Window,9618 window: &mut Window,
9619 cx: &mut Context<Self>,9619 cx: &mut Context<Self>,
9620 mut manipulate: M,9620 mut callback: Fn,
9621 ) where9621 ) where
9622 M: FnMut(&str) -> LineManipulationResult,9622 Fn: FnMut(&mut Vec<&str>),
9623 {9623 {
9624 self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);9624 self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
9625 9625
@@ -9652,14 +9652,18 @@ impl Editor { · 26 unmodified lines
9652 .text_for_range(start_point..end_point)9652 .text_for_range(start_point..end_point)
9653 .collect::<String>();9653 .collect::<String>();
9654 9654
9655 let LineManipulationResult { new_text, line_count_before, line_count_after} = manipulate(&text);9655 let mut lines = text.split('\n').collect_vec();
9656 9656
9657 edits.push((start_point..end_point, new_text));9657 let lines_before = lines.len();
9658 callback(&mut lines);
9659 let lines_after = lines.len();
9660
9661 edits.push((start_point..end_point, lines.join("\n")));
9658 9662
9659 // Selections must change based on added and removed line count9663 // Selections must change based on added and removed line count
9660 let start_row =9664 let start_row =
9661 MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);9665 MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
9662 let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);9666 let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
9663 new_selections.push(Selection {9667 new_selections.push(Selection {
9664 id: selection.id,9668 id: selection.id,
9665 start: start_row,9669 start: start_row,
@@ -9668,10 +9672,10 @@ impl Editor { · 2 unmodified lines
9668 reversed: selection.reversed,9672 reversed: selection.reversed,
9669 });9673 });
9670 9674
9671 if line_count_after > line_count_before {9675 if lines_after > lines_before {
9672 added_lines += line_count_after - line_count_before;9676 added_lines += lines_after - lines_before;
9673 } else if line_count_before > line_count_after {9677 } else if lines_before > lines_after {
9674 removed_lines += line_count_before - line_count_after;9678 removed_lines += lines_before - lines_after;
9675 }9679 }
9676 }9680 }
9677 9681
@@ -9716,171 +9720,6 @@ impl Editor { · 38 unmodified lines
9716 })9720 })
9717 }9721 }
9718 9722
9719 fn manipulate_immutable_lines<Fn>(
9720 &mut self,
9721 window: &mut Window,
9722 cx: &mut Context<Self>,
9723 mut callback: Fn,
9724 ) where
9725 Fn: FnMut(&mut Vec<&str>),
9726 {
9727 self.manipulate_lines(window, cx, |text| {
9728 let mut lines: Vec<&str> = text.split('\n').collect();
9729 let line_count_before = lines.len();
9730
9731 callback(&mut lines);
9732
9733 LineManipulationResult {
9734 new_text: lines.join("\n"),
9735 line_count_before,
9736 line_count_after: lines.len(),
9737 }
9738 });
9739 }
9740
9741 fn manipulate_mutable_lines<Fn>(
9742 &mut self,
9743 window: &mut Window,
9744 cx: &mut Context<Self>,
9745 mut callback: Fn,
9746 ) where
9747 Fn: FnMut(&mut Vec<Cow<'_, str>>),
9748 {
9749 self.manipulate_lines(window, cx, |text| {
9750 let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
9751 let line_count_before = lines.len();
9752
9753 callback(&mut lines);
9754
9755 LineManipulationResult {
9756 new_text: lines.join("\n"),
9757 line_count_before,
9758 line_count_after: lines.len(),
9759 }
9760 });
9761 }
9762
9763 pub fn convert_indentation_to_spaces(
9764 &mut self,
9765 _: &ConvertIndentationToSpaces,
9766 window: &mut Window,
9767 cx: &mut Context<Self>,
9768 ) {
9769 let settings = self.buffer.read(cx).language_settings(cx);
9770 let tab_size = settings.tab_size.get() as usize;
9771
9772 self.manipulate_mutable_lines(window, cx, |lines| {
9773 // Allocates a reasonably sized scratch buffer once for the whole loop
9774 let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
9775 // Avoids recomputing spaces that could be inserted many times
9776 let space_cache: Vec<Vec<char>> = (1..=tab_size)
9777 .map(|n| IndentSize::spaces(n as u32).chars().collect())
9778 .collect();
9779
9780 for line in lines.iter_mut().filter(|line| !line.is_empty()) {
9781 let mut chars = line.as_ref().chars();
9782 let mut col = 0;
9783 let mut changed = false;
9784
9785 while let Some(ch) = chars.next() {
9786 match ch {
9787 ' ' => {
9788 reindented_line.push(' ');
9789 col += 1;
9790 }
9791 '\t' => {
9792 // \t are converted to spaces depending on the current column
9793 let spaces_len = tab_size - (col % tab_size);
9794 reindented_line.extend(&space_cache[spaces_len - 1]);
9795 col += spaces_len;
9796 changed = true;
9797 }
9798 _ => {
9799 // If we dont append before break, the character is consumed
9800 reindented_line.push(ch);
9801 break;
9802 }
9803 }
9804 }
9805
9806 if !changed {
9807 reindented_line.clear();
9808 continue;
9809 }
9810 // Append the rest of the line and replace old reference with new one
9811 reindented_line.extend(chars);
9812 *line = Cow::Owned(reindented_line.clone());
9813 reindented_line.clear();
9814 }
9815 });
9816 }
9817
9818 pub fn convert_indentation_to_tabs(
9819 &mut self,
9820 _: &ConvertIndentationToTabs,
9821 window: &mut Window,
9822 cx: &mut Context<Self>,
9823 ) {
9824 let settings = self.buffer.read(cx).language_settings(cx);
9825 let tab_size = settings.tab_size.get() as usize;
9826
9827 self.manipulate_mutable_lines(window, cx, |lines| {
9828 // Allocates a reasonably sized buffer once for the whole loop
9829 let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
9830 // Avoids recomputing spaces that could be inserted many times
9831 let space_cache: Vec<Vec<char>> = (1..=tab_size)
9832 .map(|n| IndentSize::spaces(n as u32).chars().collect())
9833 .collect();
9834
9835 for line in lines.iter_mut().filter(|line| !line.is_empty()) {
9836 let mut chars = line.chars();
9837 let mut spaces_count = 0;
9838 let mut first_non_indent_char = None;
9839 let mut changed = false;
9840
9841 while let Some(ch) = chars.next() {
9842 match ch {
9843 ' ' => {
9844 // Keep track of spaces. Append \t when we reach tab_size
9845 spaces_count += 1;
9846 changed = true;
9847 if spaces_count == tab_size {
9848 reindented_line.push('\t');
9849 spaces_count = 0;
9850 }
9851 }
9852 '\t' => {
9853 reindented_line.push('\t');
9854 spaces_count = 0;
9855 }
9856 _ => {
9857 // Dont append it yet, we might have remaining spaces
9858 first_non_indent_char = Some(ch);
9859 break;
9860 }
9861 }
9862 }
9863
9864 if !changed {
9865 reindented_line.clear();
9866 continue;
9867 }
9868 // Remaining spaces that didn't make a full tab stop
9869 if spaces_count > 0 {
9870 reindented_line.extend(&space_cache[spaces_count - 1]);
9871 }
9872 // If we consume an extra character that was not indentation, add it back
9873 if let Some(extra_char) = first_non_indent_char {
9874 reindented_line.push(extra_char);
9875 }
9876 // Append the rest of the line and replace old reference with new one
9877 reindented_line.extend(chars);
9878 *line = Cow::Owned(reindented_line.clone());
9879 reindented_line.clear();
9880 }
9881 });
9882 }
9883
9884 pub fn convert_to_upper_case(9723 pub fn convert_to_upper_case(
9885 &mut self,9724 &mut self,
9886 _: &ConvertToUpperCase,9725 _: &ConvertToUpperCase,
@@ -21318,13 +21157,6 @@ pub struct LineHighlight { · 11431 unmodified lines
21318 pub type_id: Option<TypeId>,21157 pub type_id: Option<TypeId>,
21319}21158}
21320 21159
21321struct LineManipulationResult {
21322 pub new_text: String,
21323 pub line_count_before: usize,
21324 pub line_count_after: usize,
21325}
21326
21327
21328fn render_diff_hunk_controls(21160fn render_diff_hunk_controls(
21329 row: u32,21161 row: u32,
21330 status: &DiffHunkStatus,21162 status: &DiffHunkStatus,
script/danger/dangerfile.ts+21−0
@@ -94,3 +94,24 @@ for (const promptPath of modifiedPrompts) { · 93 unmodified lines
94 );94 );
95 }95 }
96}96}
97
98const FIXTURE_CHANGE_ATTESTATION = "Changes to test fixtures are intentional and necessary.";
99
100const FIXTURES_PATHS = ["crates/assistant_tools/src/edit_agent/evals/fixtures"];
101
102const modifiedFixtures = danger.git.modified_files.filter((file) =>
103 FIXTURES_PATHS.some((fixturePath) => file.includes(fixturePath)),
104);
105
106if (modifiedFixtures.length > 0) {
107 if (!body.includes(FIXTURE_CHANGE_ATTESTATION)) {
108 const modifiedFixturesStr = modifiedFixtures.map((path) => "`" + path + "`").join(", ");
109 fail(
110 [
111 `This PR modifies eval or test fixtures (${modifiedFixturesStr}), which are typically expected to remain unchanged.`,
112 "If these changes are intentional and required, please add the following attestation to your PR description: ",
113 `"${FIXTURE_CHANGE_ATTESTATION}"`,
114 ].join("\n\n"),
115 );
116 }
117}