Skip to content

Commit b7b11a6

Browse files
Merge pull request #1381 from rylev/better-commit-message
Make unrolled commit message more descriptive
2 parents 727b532 + d0c5ded commit b7b11a6

File tree

2 files changed

+154
-116
lines changed

2 files changed

+154
-116
lines changed

site/src/github.rs

Lines changed: 103 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,58 @@ type BoxedError = Box<dyn std::error::Error + Send + Sync>;
1010

1111
pub use comparison_summary::post_finished;
1212

13+
/// Enqueues try build artifacts and posts a message about them on the original rollup PR
14+
pub async fn unroll_rollup(
15+
ci_client: client::Client,
16+
main_repo_client: client::Client,
17+
rollup_merges: impl Iterator<Item = &Commit>,
18+
previous_master: &str,
19+
rollup_pr_number: u32,
20+
) -> Result<(), String> {
21+
let mapping = enqueue_unrolled_try_builds(ci_client, rollup_merges, previous_master)
22+
.await?
23+
.into_iter()
24+
.fold(String::new(), |mut string, c| {
25+
use std::fmt::Write;
26+
write!(
27+
&mut string,
28+
"|#{pr}|[{commit}](https://github.com/rust-lang-ci/rust/commit/{commit})|\n",
29+
pr = c.original_pr_number,
30+
commit = c.sha
31+
)
32+
.unwrap();
33+
string
34+
});
35+
let msg =
36+
format!("📌 Perf builds for each rolled up PR:\n\n\
37+
|PR# | Perf Build Sha|\n|----|-----|\n\
38+
{mapping}\nIn the case of a perf regression, \
39+
run the following command for each PR you suspect might be the cause: `@rust-timer build $SHA`");
40+
main_repo_client.post_comment(rollup_pr_number, msg).await;
41+
Ok(())
42+
}
43+
1344
/// Enqueues try builds on the try-perf branch for every rollup merge in `rollup_merges`.
1445
/// Returns a mapping between the rollup merge commit and the try build sha.
15-
///
16-
/// `rollup_merges` must only include actual rollup merge commits.
17-
pub async fn enqueue_unrolled_try_builds<'a>(
46+
async fn enqueue_unrolled_try_builds<'a>(
1847
client: client::Client,
1948
rollup_merges: impl Iterator<Item = &'a Commit>,
2049
previous_master: &str,
21-
) -> Result<Vec<(&'a Commit, String)>, String> {
50+
) -> Result<Vec<UnrolledCommit<'a>>, String> {
2251
let mut mapping = Vec::new();
2352
for rollup_merge in rollup_merges {
53+
// Grab the number of the rolled up PR from its commit message
54+
let original_pr_number = ROLLEDUP_PR_NUMBER
55+
.captures(&rollup_merge.message)
56+
.and_then(|c| c.get(1))
57+
.map(|m| m.as_str())
58+
.ok_or_else(|| {
59+
format!(
60+
"Could not get PR number from message: '{}'",
61+
rollup_merge.message
62+
)
63+
})?;
64+
2465
// Fetch the rollup merge commit which should have two parents.
2566
// The first parent is in the chain of rollup merge commits all the way back to `previous_master`.
2667
// The second parent is the head of the PR that was rolled up. We want the second parent.
@@ -45,7 +86,11 @@ pub async fn enqueue_unrolled_try_builds<'a>(
4586

4687
// Merge in the rolled up PR's head commit into the previous master
4788
let sha = client
48-
.merge_branch("perf-tmp", rolled_up_head, "merge")
89+
.merge_branch(
90+
"perf-tmp",
91+
rolled_up_head,
92+
&format!("Unrolled build for #{}", original_pr_number),
93+
)
4994
.await
5095
.map_err(|e| format!("Error merging commit into perf-tmp: {e:?}"))?;
5196

@@ -55,17 +100,33 @@ pub async fn enqueue_unrolled_try_builds<'a>(
55100
.await
56101
.map_err(|e| format!("Error updating the try-perf branch: {e:?}"))?;
57102

58-
mapping.push((rollup_merge, sha));
103+
mapping.push(UnrolledCommit {
104+
original_pr_number,
105+
rollup_merge,
106+
sha,
107+
});
59108
// Wait to ensure there's enough time for GitHub to checkout these changes before they are overwritten
60109
tokio::time::sleep(std::time::Duration::from_secs(15)).await
61110
}
62111

63112
Ok(mapping)
64113
}
65114

115+
/// A commit representing a rolled up PR as if it had been merged into master directly
116+
pub struct UnrolledCommit<'a> {
117+
/// The PR number that was rolled up
118+
pub original_pr_number: &'a str,
119+
/// The original rollup merge commit
120+
pub rollup_merge: &'a Commit,
121+
/// The sha of the new unrolled merge commit
122+
pub sha: String,
123+
}
124+
66125
lazy_static::lazy_static! {
67126
static ref ROLLUP_PR_NUMBER: regex::Regex =
68127
regex::Regex::new(r#"^Auto merge of #(\d+)"#).unwrap();
128+
static ref ROLLEDUP_PR_NUMBER: regex::Regex =
129+
regex::Regex::new(r#"^Rollup merge of #(\d+)"#).unwrap();
69130
}
70131

71132
// Gets the pr number for the associated rollup PR message. Returns None if this is not a rollup PR
@@ -101,43 +162,49 @@ pub async fn rollup_pr_number(
101162
.then(|| issue.number))
102163
}
103164

104-
pub async fn enqueue_sha(
165+
pub async fn enqueue_shas(
105166
ctxt: &SiteCtxt,
106167
main_client: &client::Client,
107168
ci_client: &client::Client,
108169
pr_number: u32,
109-
commit: String,
170+
commits: impl Iterator<Item = &str>,
110171
) -> Result<(), String> {
111-
let commit_response = ci_client
112-
.get_commit(&commit)
113-
.await
114-
.map_err(|e| e.to_string())?;
115-
if commit_response.parents.len() != 2 {
116-
log::error!(
117-
"Bors try commit {} unexpectedly has {} parents.",
118-
commit_response.sha,
119-
commit_response.parents.len()
120-
);
121-
return Ok(());
122-
}
123-
let try_commit = TryCommit {
124-
sha: commit_response.sha.clone(),
125-
parent_sha: commit_response.parents[0].sha.clone(),
126-
};
127-
let queued = {
128-
let conn = ctxt.conn().await;
129-
conn.pr_attach_commit(pr_number, &try_commit.sha, &try_commit.parent_sha)
172+
let mut msg = String::new();
173+
for commit in commits {
174+
let mut commit_response = ci_client
175+
.get_commit(&commit)
130176
.await
131-
};
132-
if queued {
133-
let msg = format!(
134-
"Queued {} with parent {}, future [comparison URL]({}).",
135-
try_commit.sha,
136-
try_commit.parent_sha,
137-
try_commit.comparison_url(),
138-
);
139-
main_client.post_comment(pr_number, msg).await;
177+
.map_err(|e| e.to_string())?;
178+
if commit_response.parents.len() != 2 {
179+
log::error!(
180+
"Bors try commit {} unexpectedly has {} parents.",
181+
commit_response.sha,
182+
commit_response.parents.len()
183+
);
184+
return Ok(());
185+
}
186+
let try_commit = TryCommit {
187+
sha: commit_response.sha,
188+
parent_sha: commit_response.parents.remove(0).sha,
189+
};
190+
let queued = {
191+
let conn = ctxt.conn().await;
192+
conn.pr_attach_commit(pr_number, &try_commit.sha, &try_commit.parent_sha)
193+
.await
194+
};
195+
if queued {
196+
if !msg.is_empty() {
197+
msg.push('\n');
198+
}
199+
msg.push_str(&format!(
200+
"Queued {} with parent {}, future [comparison URL]({}).",
201+
try_commit.sha,
202+
try_commit.parent_sha,
203+
try_commit.comparison_url(),
204+
));
205+
}
140206
}
207+
main_client.post_comment(pr_number, msg).await;
141208
Ok(())
142209
}
143210

site/src/request_handlers/github.rs

Lines changed: 51 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,15 @@
11
use crate::api::{github, ServerResult};
2-
use crate::github::{
3-
client, enqueue_sha, enqueue_unrolled_try_builds, parse_homu_comment, rollup_pr_number,
4-
};
2+
use crate::github::{client, enqueue_shas, parse_homu_comment, rollup_pr_number, unroll_rollup};
53
use crate::load::SiteCtxt;
64

75
use std::sync::Arc;
86

97
use regex::Regex;
108

119
lazy_static::lazy_static! {
12-
static ref ROLLUP_PR_NUMBER: Regex =
13-
Regex::new(r#"^Auto merge of #(\d+)"#).unwrap();
14-
static ref ROLLEDUP_PR_NUMBER: Regex =
15-
Regex::new(r#"^Rollup merge of #(\d+)"#).unwrap();
16-
static ref BODY_TRY_COMMIT: Regex =
10+
static ref BODY_TIMER_BUILD: Regex =
1711
Regex::new(r#"(?:\W|^)@rust-timer\s+build\s+(\w+)(?:\W|$)(?:include=(\S+))?\s*(?:exclude=(\S+))?\s*(?:runs=(\d+))?"#).unwrap();
18-
static ref BODY_QUEUE: Regex =
12+
static ref BODY_TIMER_QUEUE: Regex =
1913
Regex::new(r#"(?:\W|^)@rust-timer\s+queue(?:\W|$)(?:include=(\S+))?\s*(?:exclude=(\S+))?\s*(?:runs=(\d+))?"#).unwrap();
2014
}
2115

@@ -54,10 +48,15 @@ async fn handle_push(ctxt: Arc<SiteCtxt>, push: github::Push) -> ServerResult<gi
5448
// GitHub webhooks have a timeout of 10 seconds, so we process this
5549
// in the background.
5650
tokio::spawn(async move {
57-
let result = handle_rollup_merge(
51+
let rollup_merges = commits
52+
.iter()
53+
.rev()
54+
.skip(1) // skip the head commit
55+
.take_while(|c| c.message.starts_with("Rollup merge of "));
56+
let result = unroll_rollup(
5857
ci_client,
5958
main_repo_client,
60-
commits,
59+
rollup_merges,
6160
&previous_master,
6261
rollup_pr_number,
6362
)
@@ -67,54 +66,6 @@ async fn handle_push(ctxt: Arc<SiteCtxt>, push: github::Push) -> ServerResult<gi
6766
Ok(github::Response)
6867
}
6968

70-
/// Handler for when a rollup has been merged
71-
async fn handle_rollup_merge(
72-
ci_client: client::Client,
73-
main_repo_client: client::Client,
74-
commits: Vec<github::Commit>,
75-
previous_master: &str,
76-
rollup_pr_number: u32,
77-
) -> Result<(), String> {
78-
let rollup_merges = commits
79-
.iter()
80-
.rev()
81-
.skip(1) // skip the head commit
82-
.take_while(|c| c.message.starts_with("Rollup merge of "));
83-
let mapping = enqueue_unrolled_try_builds(ci_client, rollup_merges, previous_master).await?;
84-
let mapping = mapping
85-
.into_iter()
86-
.map(|(rollup_merge, sha)| {
87-
ROLLEDUP_PR_NUMBER
88-
.captures(&rollup_merge.message)
89-
.and_then(|c| c.get(1))
90-
.map(|m| (m.as_str(), sha))
91-
.ok_or_else(|| {
92-
format!(
93-
"Could not get PR number from message: '{}'",
94-
rollup_merge.message
95-
)
96-
})
97-
})
98-
.fold(ServerResult::Ok(String::new()), |string, n| {
99-
use std::fmt::Write;
100-
let (pr, commit) = n?;
101-
let mut string = string?;
102-
write!(
103-
&mut string,
104-
"|#{pr}|[{commit}](https://github.com/rust-lang-ci/rust/commit/{commit})|\n"
105-
)
106-
.unwrap();
107-
Ok(string)
108-
})?;
109-
let msg =
110-
format!("📌 Perf builds for each rolled up PR:\n\n\
111-
|PR# | Perf Build Sha|\n|----|-----|\n\
112-
{mapping}\nIn the case of a perf regression, \
113-
run the following command for each PR you suspect might be the cause: `@rust-timer build $SHA`");
114-
main_repo_client.post_comment(rollup_pr_number, msg).await;
115-
Ok(())
116-
}
117-
11869
async fn handle_issue(
11970
ctxt: Arc<SiteCtxt>,
12071
issue: github::Issue,
@@ -130,7 +81,14 @@ async fn handle_issue(
13081
);
13182
if comment.body.contains(" homu: ") {
13283
if let Some(sha) = parse_homu_comment(&comment.body).await {
133-
enqueue_sha(&ctxt, &main_client, &ci_client, issue.number, sha).await?;
84+
enqueue_shas(
85+
&ctxt,
86+
&main_client,
87+
&ci_client,
88+
issue.number,
89+
std::iter::once(sha.as_str()),
90+
)
91+
.await?;
13492
return Ok(github::Response);
13593
}
13694
}
@@ -161,7 +119,7 @@ async fn handle_rust_timer(
161119
return Ok(github::Response);
162120
}
163121

164-
if let Some(captures) = BODY_QUEUE.captures(&comment.body) {
122+
if let Some(captures) = BODY_TIMER_QUEUE.captures(&comment.body) {
165123
let include = captures.get(1).map(|v| v.as_str());
166124
let exclude = captures.get(2).map(|v| v.as_str());
167125
let runs = captures.get(3).and_then(|v| v.as_str().parse::<i32>().ok());
@@ -179,30 +137,43 @@ async fn handle_rust_timer(
179137
.await;
180138
return Ok(github::Response);
181139
}
182-
if let Some(captures) = BODY_TRY_COMMIT.captures(&comment.body) {
183-
if let Some(commit) = captures.get(1).map(|c| c.as_str().to_owned()) {
184-
let include = captures.get(2).map(|v| v.as_str());
185-
let exclude = captures.get(3).map(|v| v.as_str());
186-
let runs = captures.get(4).and_then(|v| v.as_str().parse::<i32>().ok());
187-
let commit = commit.trim_start_matches("https://github.com/rust-lang/rust/commit/");
188-
{
189-
let conn = ctxt.conn().await;
190-
conn.queue_pr(issue.number, include, exclude, runs).await;
191-
}
192-
enqueue_sha(
193-
&ctxt,
194-
&main_client,
195-
&ci_client,
196-
issue.number,
197-
commit.to_owned(),
198-
)
199-
.await?;
200-
return Ok(github::Response);
140+
141+
for captures in build_captures(&comment).map(|(_, captures)| captures) {
142+
let include = captures.get(2).map(|v| v.as_str());
143+
let exclude = captures.get(3).map(|v| v.as_str());
144+
let runs = captures.get(4).and_then(|v| v.as_str().parse::<i32>().ok());
145+
{
146+
let conn = ctxt.conn().await;
147+
conn.queue_pr(issue.number, include, exclude, runs).await;
201148
}
202149
}
150+
151+
enqueue_shas(
152+
&ctxt,
153+
&main_client,
154+
&ci_client,
155+
issue.number,
156+
build_captures(&comment).map(|(commit, _)| commit),
157+
)
158+
.await?;
159+
203160
Ok(github::Response)
204161
}
205162

163+
/// Run the `@rust-timer build` regex over the comment message extracting the commit and the other captures
164+
fn build_captures(comment: &github::Comment) -> impl Iterator<Item = (&str, regex::Captures)> {
165+
BODY_TIMER_BUILD
166+
.captures_iter(&comment.body)
167+
.filter_map(|captures| {
168+
captures.get(1).map(|m| {
169+
let commit = m
170+
.as_str()
171+
.trim_start_matches("https://github.com/rust-lang/rust/commit/");
172+
(commit, captures)
173+
})
174+
})
175+
}
176+
206177
pub async fn get_authorized_users() -> Result<Vec<usize>, String> {
207178
let url = format!("{}/permissions/perf.json", ::rust_team_data::v1::BASE_URL);
208179
let client = reqwest::Client::new();

0 commit comments

Comments
 (0)