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
91329132 window: &mut Window,
91339133 cx: &mut Context<Self>,
91349134 ) {
9135− self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
9135+ self.manipulate_lines(window, cx, |lines| lines.sort())
91369136 }
91379137
91389138 pub fn sort_lines_case_insensitive(
@@ -9141,7 +9141,7 @@ impl Editor { · 2 unmodified lines
91419141 window: &mut Window,
91429142 cx: &mut Context<Self>,
91439143 ) {
9144− self.manipulate_immutable_lines(window, cx, |lines| {
9144+ self.manipulate_lines(window, cx, |lines| {
91459145 lines.sort_by_key(|line| line.to_lowercase())
91469146 })
91479147 }
@@ -9152,7 +9152,7 @@ impl Editor { · 4 unmodified lines
91529152 window: &mut Window,
91539153 cx: &mut Context<Self>,
91549154 ) {
9155− self.manipulate_immutable_lines(window, cx, |lines| {
9155+ self.manipulate_lines(window, cx, |lines| {
91569156 let mut seen = HashSet::default();
91579157 lines.retain(|line| seen.insert(line.to_lowercase()));
91589158 })
@@ -9164,7 +9164,7 @@ impl Editor { · 5 unmodified lines
91649164 window: &mut Window,
91659165 cx: &mut Context<Self>,
91669166 ) {
9167− self.manipulate_immutable_lines(window, cx, |lines| {
9167+ self.manipulate_lines(window, cx, |lines| {
91689168 let mut seen = HashSet::default();
91699169 lines.retain(|line| seen.insert(*line));
91709170 })
@@ -9606,20 +9606,20 @@ impl Editor { · 435 unmodified lines
96069606 }
96079607
96089608 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())
96109610 }
96119611
96129612 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()))
96149614 }
96159615
9616− fn manipulate_lines<M>(
9616+ fn manipulate_lines<Fn>(
96179617 &mut self,
96189618 window: &mut Window,
96199619 cx: &mut Context<Self>,
9620− mut manipulate: M,
9620+ mut callback: Fn,
96219621 ) where
9622− M: FnMut(&str) -> LineManipulationResult,
9622+ Fn: FnMut(&mut Vec<&str>),
96239623 {
96249624 self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
96259625
@@ -9652,14 +9652,18 @@ impl Editor { · 26 unmodified lines
96529652 .text_for_range(start_point..end_point)
96539653 .collect::<String>();
96549654
9655− let LineManipulationResult { new_text, line_count_before, line_count_after} = manipulate(&text);
9655+ let mut lines = text.split('\n').collect_vec();
96569656
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")));
96589662
96599663 // Selections must change based on added and removed line count
96609664 let start_row =
96619665 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);
96639667 new_selections.push(Selection {
96649668 id: selection.id,
96659669 start: start_row,
@@ -9668,10 +9672,10 @@ impl Editor { · 2 unmodified lines
96689672 reversed: selection.reversed,
96699673 });
96709674
9671− if line_count_after > line_count_before {
9672− added_lines += line_count_after - line_count_before;
9673− } else if line_count_before > line_count_after {
9674− removed_lines += line_count_before - line_count_after;
9675+ if lines_after > lines_before {
9676+ added_lines += lines_after - lines_before;
9677+ } else if lines_before > lines_after {
9678+ removed_lines += lines_before - lines_after;
96759679 }
96769680 }
96779681
@@ -9716,171 +9720,6 @@ impl Editor { · 38 unmodified lines
97169720 })
97179721 }
97189722
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−
98849723 pub fn convert_to_upper_case(
98859724 &mut self,
98869725 _: &ConvertToUpperCase,
@@ -21318,13 +21157,6 @@ pub struct LineHighlight { · 11431 unmodified lines
2131821157 pub type_id: Option<TypeId>,
2131921158 }
2132021159
21321−struct LineManipulationResult {
21322− pub new_text: String,
21323− pub line_count_before: usize,
21324− pub line_count_after: usize,
21325−}
21326−
21327−
2132821160 fn render_diff_hunk_controls(
2132921161 row: u32,
2133021162 status: &DiffHunkStatus,
script/danger/dangerfile.ts+21−0
@@ -94,3 +94,24 @@ for (const promptPath of modifiedPrompts) { · 93 unmodified lines
9494 );
9595 }
9696 }
97+
98+const FIXTURE_CHANGE_ATTESTATION = "Changes to test fixtures are intentional and necessary.";
99+
100+const FIXTURES_PATHS = ["crates/assistant_tools/src/edit_agent/evals/fixtures"];
101+
102+const modifiedFixtures = danger.git.modified_files.filter((file) =>
103+ FIXTURES_PATHS.some((fixturePath) => file.includes(fixturePath)),
104+);
105+
106+if (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+}