Skip to content

Commit 7149430

Browse files
committed
Remove our custom diff parsing and prefer Github compare json API
1 parent c335263 commit 7149430

File tree

9 files changed

+62
-178
lines changed

9 files changed

+62
-178
lines changed

src/github.rs

Lines changed: 26 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -308,16 +308,7 @@ pub struct PullRequestDetails {
308308
/// handlers want to see PR changes, and getting the diff can be
309309
/// expensive.
310310
#[serde(skip)]
311-
files_changed: tokio::sync::OnceCell<Vec<FileDiff>>,
312-
}
313-
314-
/// Representation of a diff to a single file.
315-
#[derive(Debug)]
316-
pub struct FileDiff {
317-
/// The full path of the file.
318-
pub path: String,
319-
/// The diff for the file.
320-
pub diff: String,
311+
compare: tokio::sync::OnceCell<GithubCompare>,
321312
}
322313

323314
/// The return from GitHub compare API
@@ -329,13 +320,23 @@ pub struct GithubCompare {
329320
///
330321
/// See <https://git-scm.com/docs/git-merge-base> for more details
331322
pub merge_base_commit: GithubCommit,
332-
// FIXME: Also retrieve and use the files list (see our diff function)
323+
/// List of file differences
324+
pub files: Vec<FileDiff>,
325+
}
326+
327+
/// Representation of a diff to a single file.
328+
#[derive(Debug, serde::Deserialize)]
329+
pub struct FileDiff {
330+
/// The fullname path of the file.
331+
pub filename: String,
332+
/// The patch/diff for the file.
333+
pub patch: String,
333334
}
334335

335336
impl PullRequestDetails {
336337
pub fn new() -> PullRequestDetails {
337338
PullRequestDetails {
338-
files_changed: tokio::sync::OnceCell::new(),
339+
compare: tokio::sync::OnceCell::new(),
339340
}
340341
}
341342
}
@@ -977,6 +978,13 @@ impl Issue {
977978
///
978979
/// Returns `None` if the issue is not a PR.
979980
pub async fn diff(&self, client: &GithubClient) -> anyhow::Result<Option<&[FileDiff]>> {
981+
Ok(self.compare(client).await?.map(|c| c.files.as_ref()))
982+
}
983+
984+
/// Returns the comparison of this event.
985+
///
986+
/// Returns `None` if the issue is not a PR.
987+
pub async fn compare(&self, client: &GithubClient) -> anyhow::Result<Option<&GithubCompare>> {
980988
let Some(pr) = &self.pull_request else {
981989
return Ok(None);
982990
};
@@ -986,41 +994,17 @@ impl Issue {
986994
return Ok(None);
987995
};
988996

989-
let diff = pr
990-
.files_changed
997+
let compare = pr
998+
.compare
991999
.get_or_try_init::<anyhow::Error, _, _>(|| async move {
992-
let url = format!(
1000+
let req = client.get(&format!(
9931001
"{}/compare/{before}...{after}",
9941002
self.repository().url(client)
995-
);
996-
let mut req = client.get(&url);
997-
req = req.header("Accept", "application/vnd.github.v3.diff");
998-
let (diff, _) = client
999-
.send_req(req)
1000-
.await
1001-
.with_context(|| format!("failed to fetch diff comparison for {url}"))?;
1002-
let body = String::from_utf8_lossy(&diff);
1003-
Ok(parse_diff(&body))
1003+
));
1004+
Ok(client.json(req).await?)
10041005
})
10051006
.await?;
1006-
Ok(Some(diff))
1007-
}
1008-
1009-
/// Returns the comparison of this event.
1010-
///
1011-
/// Returns `None` if the issue is not a PR.
1012-
pub async fn compare(&self, client: &GithubClient) -> anyhow::Result<Option<GithubCompare>> {
1013-
let (before, after) = if let (Some(base), Some(head)) = (&self.base, &self.head) {
1014-
(&base.sha, &head.sha)
1015-
} else {
1016-
return Ok(None);
1017-
};
1018-
1019-
let req = client.get(&format!(
1020-
"{}/compare/{before}...{after}",
1021-
self.repository().url(client)
1022-
));
1023-
Ok(Some(client.json(req).await?))
1007+
Ok(Some(compare))
10241008
}
10251009

10261010
/// Returns the commits from this pull request (no commits are returned if this `Issue` is not
@@ -1264,31 +1248,6 @@ pub struct CommitBase {
12641248
pub repo: Option<Repository>,
12651249
}
12661250

1267-
pub fn parse_diff(diff: &str) -> Vec<FileDiff> {
1268-
// This does not properly handle filenames with spaces.
1269-
let re = regex::Regex::new("(?m)^diff --git .* b/(.*)").unwrap();
1270-
let mut files: Vec<_> = re
1271-
.captures_iter(diff)
1272-
.map(|cap| {
1273-
let start = cap.get(0).unwrap().start();
1274-
let path = cap.get(1).unwrap().as_str().to_string();
1275-
(start, path)
1276-
})
1277-
.collect();
1278-
// Break the list up into (start, end) pairs starting from the "diff --git" line.
1279-
files.push((diff.len(), String::new()));
1280-
files
1281-
.windows(2)
1282-
.map(|w| {
1283-
let (start, end) = (&w[0], &w[1]);
1284-
FileDiff {
1285-
path: start.1.clone(),
1286-
diff: diff[start.0..end.0].to_string(),
1287-
}
1288-
})
1289-
.collect()
1290-
}
1291-
12921251
#[derive(Debug, serde::Deserialize)]
12931252
pub struct IssueSearchResult {
12941253
pub total_count: u64,
@@ -3221,71 +3180,4 @@ mod tests {
32213180
};
32223181
assert_eq!(x.to_string(), "Unknown labels: A-bootstrap, xxx");
32233182
}
3224-
3225-
#[test]
3226-
fn extract_one_file() {
3227-
let input = r##"\
3228-
diff --git a/triagebot.toml b/triagebot.toml
3229-
index fb9cee43b2d..b484c25ea51 100644
3230-
--- a/triagebot.toml
3231-
+++ b/triagebot.toml
3232-
@@ -114,6 +114,15 @@ trigger_files = [
3233-
"src/tools/rustdoc-themes",
3234-
]
3235-
+[autolabel."T-compiler"]
3236-
+trigger_files = [
3237-
+ # Source code
3238-
+ "compiler",
3239-
+
3240-
+ # Tests
3241-
+ "src/test/ui",
3242-
+]
3243-
+
3244-
[notify-zulip."I-prioritize"]
3245-
zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
3246-
topic = "#{number} {title}"
3247-
"##;
3248-
let files: Vec<_> = parse_diff(input).into_iter().map(|d| d.path).collect();
3249-
assert_eq!(files, vec!["triagebot.toml".to_string()]);
3250-
}
3251-
3252-
#[test]
3253-
fn extract_several_files() {
3254-
let input = r##"\
3255-
diff --git a/library/stdarch b/library/stdarch
3256-
index b70ae88ef2a..cfba59fccd9 160000
3257-
--- a/library/stdarch
3258-
+++ b/library/stdarch
3259-
@@ -1 +1 @@
3260-
-Subproject commit b70ae88ef2a6c83acad0a1e83d5bd78f9655fd05
3261-
+Subproject commit cfba59fccd90b3b52a614120834320f764ab08d1
3262-
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
3263-
index 1fe4aa9023e..f0330f1e424 100644
3264-
--- a/src/librustdoc/clean/types.rs
3265-
+++ b/src/librustdoc/clean/types.rs
3266-
@@ -2322,3 +2322,4 @@ impl SubstParam {
3267-
if let Self::Lifetime(lt) = self { Some(lt) } else { None }
3268-
}
3269-
}
3270-
+
3271-
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
3272-
index c58310947d2..3b0854d4a9b 100644
3273-
--- a/src/librustdoc/core.rs
3274-
+++ b/src/librustdoc/core.rs
3275-
@@ -591,3 +591,4 @@ fn from(idx: u32) -> Self {
3276-
ImplTraitParam::ParamIndex(idx)
3277-
}
3278-
}
3279-
+
3280-
"##;
3281-
let files: Vec<_> = parse_diff(input).into_iter().map(|d| d.path).collect();
3282-
assert_eq!(
3283-
files,
3284-
vec![
3285-
"library/stdarch".to_string(),
3286-
"src/librustdoc/clean/types.rs".to_string(),
3287-
"src/librustdoc/core.rs".to_string(),
3288-
]
3289-
)
3290-
}
32913183
}

src/handlers/assign.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@ fn find_reviewers_from_diff(
421421
.with_context(|| format!("owner file pattern `{owner_pattern}` is not valid"))?
422422
.build()?;
423423
if ignore
424-
.matched_path_or_any_parents(&file_diff.path, false)
424+
.matched_path_or_any_parents(&file_diff.filename, false)
425425
.is_ignore()
426426
{
427427
let owner_len = owner_pattern.split('/').count();
@@ -442,7 +442,7 @@ fn find_reviewers_from_diff(
442442
}
443443

444444
// Count the modified lines.
445-
for line in file_diff.diff.lines() {
445+
for line in file_diff.patch.lines() {
446446
if (!line.starts_with("+++") && line.starts_with('+'))
447447
|| (!line.starts_with("---") && line.starts_with('-'))
448448
{

src/handlers/assign/tests/tests_from_diff.rs

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
//! Tests for `find_reviewers_from_diff`
22
33
use super::super::*;
4-
use crate::github::parse_diff;
54
use std::fmt::Write;
65

7-
fn test_from_diff(diff: &str, config: toml::Table, expected: &[&str]) {
8-
let files = parse_diff(diff);
6+
fn test_from_diff(diff: &Vec<FileDiff>, config: toml::Table, expected: &[&str]) {
97
let aconfig: AssignConfig = config.try_into().unwrap();
108
assert_eq!(
11-
find_reviewers_from_diff(&aconfig, &files).unwrap(),
9+
find_reviewers_from_diff(&aconfig, &*diff).unwrap(),
1210
expected.iter().map(|x| x.to_string()).collect::<Vec<_>>()
1311
);
1412
}
@@ -18,27 +16,24 @@ fn test_from_diff(diff: &str, config: toml::Table, expected: &[&str]) {
1816
/// `paths` should be a slice of `(path, added, removed)` tuples where `added`
1917
/// is the number of lines added, and `removed` is the number of lines
2018
/// removed.
21-
fn make_fake_diff(paths: &[(&str, u32, u32)]) -> String {
19+
fn make_fake_diff(paths: &[(&str, u32, u32)]) -> Vec<FileDiff> {
2220
// This isn't a properly structured diff, but it has approximately enough
2321
// information for what is needed for testing.
2422
paths
2523
.iter()
2624
.map(|(path, added, removed)| {
27-
let mut diff = format!(
28-
"diff --git a/{path} b/{path}\n\
29-
index 1677422122e..1108c1f4d4c 100644\n\
30-
--- a/{path}\n\
31-
+++ b/{path}\n\
32-
@@ -0,0 +1 @@\n"
33-
);
25+
let mut diff = "@@ -0,0 +1 @@ ".to_string();
3426
for n in 0..*added {
3527
writeln!(diff, "+Added line {n}").unwrap();
3628
}
3729
for n in 0..*removed {
3830
writeln!(diff, "-Removed line {n}").unwrap();
3931
}
4032
diff.push('\n');
41-
diff
33+
FileDiff {
34+
filename: path.to_string(),
35+
patch: diff,
36+
}
4237
})
4338
.collect()
4439
}
@@ -61,16 +56,15 @@ fn from_diff_submodule() {
6156
[owners]
6257
"/src" = ["user1", "user2"]
6358
);
64-
let diff = "\
65-
diff --git a/src/jemalloc b/src/jemalloc\n\
66-
index 2dba541..b001609 160000\n\
67-
--- a/src/jemalloc\n\
68-
+++ b/src/jemalloc\n\
69-
@@ -1 +1 @@\n\
70-
-Subproject commit 2dba541881fb8e35246d653bbe2e7c7088777a4a\n\
71-
+Subproject commit b001609960ca33047e5cbc5a231c1e24b6041d4b\n\
72-
";
73-
test_from_diff(diff, config, &["user1", "user2"]);
59+
let diff = vec![FileDiff {
60+
filename: "src/jemalloc".to_string(),
61+
patch: "@@ -1 +1 @@\n\
62+
-Subproject commit 2dba541881fb8e35246d653bbe2e7c7088777a4a\n\
63+
+Subproject commit b001609960ca33047e5cbc5a231c1e24b6041d4b\n\
64+
"
65+
.to_string(),
66+
}];
67+
test_from_diff(&diff, config, &["user1", "user2"]);
7468
}
7569

7670
#[test]
@@ -131,9 +125,12 @@ fn empty_file_still_counts() {
131125
"/compiler" = ["compiler"]
132126
"/compiler/rustc_parse" = ["parser"]
133127
);
134-
let diff = "diff --git a/compiler/rustc_parse/src/foo.rs b/compiler/rustc_parse/src/foo.rs\n\
135-
new file mode 100644\n\
136-
index 0000000..e69de29\n";
128+
let diff = vec![FileDiff {
129+
filename: "compiler/rustc_parse/src/foo.rs".to_string(),
130+
patch: "new file mode 100644\n\
131+
index 0000000..e69de29\n"
132+
.to_string(),
133+
}];
137134
test_from_diff(&diff, config, &["parser"]);
138135
}
139136

src/handlers/autolabel.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,11 @@ pub(super) async fn parse_input(
8484
// This a PR with modified files.
8585

8686
// Add the matching labels for the modified files paths
87-
if cfg
88-
.trigger_files
89-
.iter()
90-
.any(|f| files.iter().any(|file_diff| file_diff.path.starts_with(f)))
91-
{
87+
if cfg.trigger_files.iter().any(|f| {
88+
files
89+
.iter()
90+
.any(|file_diff| file_diff.filename.starts_with(f))
91+
}) {
9292
autolabels.push(Label {
9393
name: label.to_owned(),
9494
});

src/handlers/check_commits.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,19 +52,14 @@ pub(super) async fn handle(ctx: &Context, event: &Event, config: &Config) -> any
5252
return Ok(());
5353
}
5454

55-
let Some(diff) = event.issue.diff(&ctx.github).await? else {
56-
bail!(
57-
"expected issue {} to be a PR, but the diff could not be determined",
58-
event.issue.number
59-
)
60-
};
6155
let Some(compare) = event.issue.compare(&ctx.github).await? else {
6256
bail!(
6357
"expected issue {} to be a PR, but the compare could not be determined",
6458
event.issue.number
6559
)
6660
};
6761
let commits = event.issue.commits(&ctx.github).await?;
62+
let diff = &compare.files;
6863

6964
let mut warnings = Vec::new();
7065
let mut labels = Vec::new();

src/handlers/check_commits/modified_submodule.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const SUBMODULE_WARNING_MSG: &str = "Some commits in this PR modify **submodules
55
/// Returns a message if the PR modifies a git submodule.
66
pub(super) fn modifies_submodule(diff: &[FileDiff]) -> Option<String> {
77
let re = regex::Regex::new(r"\+Subproject\scommit\s").unwrap();
8-
if diff.iter().any(|fd| re.is_match(&fd.diff)) {
8+
if diff.iter().any(|fd| re.is_match(&fd.patch)) {
99
Some(SUBMODULE_WARNING_MSG.to_string())
1010
} else {
1111
None

src/handlers/mentions.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ pub(super) async fn parse_input(
5959
})
6060
.unwrap_or_default()
6161
{
62-
let file_paths: Vec<_> = files.iter().map(|fd| Path::new(&fd.path)).collect();
62+
let file_paths: Vec<_> = files.iter().map(|fd| Path::new(&fd.filename)).collect();
6363
let to_mention: Vec<_> = config
6464
.paths
6565
.iter()

src/handlers/milestone_prs.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,10 @@ pub(super) async fn handle(ctx: &Context, event: &Event) -> anyhow::Result<()> {
6565

6666
let files = e.issue.diff(&ctx.github).await?;
6767
if let Some(files) = files {
68-
if let Some(cargo) = files.iter().find(|fd| fd.path == "src/tools/cargo") {
68+
if let Some(cargo) = files.iter().find(|fd| fd.filename == "src/tools/cargo") {
6969
// The webhook timeout of 10 seconds can be too short, so process in
7070
// the background.
71-
let diff = cargo.diff.clone();
71+
let diff = cargo.patch.clone();
7272
tokio::task::spawn(async move {
7373
let gh = GithubClient::new_from_env();
7474
if let Err(e) = milestone_cargo(&gh, &version, &diff).await {

src/handlers/validate_config.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub(super) async fn parse_input(
3434
return Ok(None);
3535
}
3636
};
37-
if !diff.iter().any(|diff| diff.path == CONFIG_FILE_NAME) {
37+
if !diff.iter().any(|diff| diff.filename == CONFIG_FILE_NAME) {
3838
return Ok(None);
3939
}
4040

0 commit comments

Comments
 (0)