Skip to content

Make unrolling independent of the merge event #1382

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 67 additions & 6 deletions site/src/github.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,58 @@ type BoxedError = Box<dyn std::error::Error + Send + Sync>;

pub use comparison_summary::post_finished;

/// Enqueues try build artifacts and posts a message about them on the original rollup PR
pub async fn unroll_rollup(
ci_client: client::Client,
main_repo_client: client::Client,
rollup_merges: impl Iterator<Item = &Commit>,
previous_master: &str,
rollup_pr_number: u32,
) -> Result<(), String> {
let mapping = enqueue_unrolled_try_builds(ci_client, rollup_merges, previous_master)
.await?
.into_iter()
.fold(String::new(), |mut string, c| {
use std::fmt::Write;
write!(
&mut string,
"|#{pr}|[{commit}](https://github.com/rust-lang-ci/rust/commit/{commit})|\n",
pr = c.original_pr_number,
commit = c.sha
)
.unwrap();
string
});
let msg =
format!("📌 Perf builds for each rolled up PR:\n\n\
|PR# | Perf Build Sha|\n|----|-----|\n\
{mapping}\nIn the case of a perf regression, \
run the following command for each PR you suspect might be the cause: `@rust-timer build $SHA`");
main_repo_client.post_comment(rollup_pr_number, msg).await;
Ok(())
}

/// Enqueues try builds on the try-perf branch for every rollup merge in `rollup_merges`.
/// Returns a mapping between the rollup merge commit and the try build sha.
///
/// `rollup_merges` must only include actual rollup merge commits.
pub async fn enqueue_unrolled_try_builds<'a>(
async fn enqueue_unrolled_try_builds<'a>(
client: client::Client,
rollup_merges: impl Iterator<Item = &'a Commit>,
previous_master: &str,
) -> Result<Vec<(&'a Commit, String)>, String> {
) -> Result<Vec<UnrolledCommit<'a>>, String> {
let mut mapping = Vec::new();
for rollup_merge in rollup_merges {
// Grab the number of the rolled up PR from its commit message
let original_pr_number = ROLLEDUP_PR_NUMBER
.captures(&rollup_merge.message)
.and_then(|c| c.get(1))
.map(|m| m.as_str())
.ok_or_else(|| {
format!(
"Could not get PR number from message: '{}'",
rollup_merge.message
)
})?;

// Fetch the rollup merge commit which should have two parents.
// The first parent is in the chain of rollup merge commits all the way back to `previous_master`.
// The second parent is the head of the PR that was rolled up. We want the second parent.
Expand All @@ -45,7 +86,11 @@ pub async fn enqueue_unrolled_try_builds<'a>(

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

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

mapping.push((rollup_merge, sha));
mapping.push(UnrolledCommit {
original_pr_number,
rollup_merge,
sha,
});
// Wait to ensure there's enough time for GitHub to checkout these changes before they are overwritten
tokio::time::sleep(std::time::Duration::from_secs(15)).await
}

Ok(mapping)
}

/// A commit representing a rolled up PR as if it had been merged into master directly
pub struct UnrolledCommit<'a> {
/// The PR number that was rolled up
pub original_pr_number: &'a str,
/// The original rollup merge commit
pub rollup_merge: &'a Commit,
/// The sha of the new unrolled merge commit
pub sha: String,
}

lazy_static::lazy_static! {
static ref ROLLUP_PR_NUMBER: regex::Regex =
regex::Regex::new(r#"^Auto merge of #(\d+)"#).unwrap();
static ref ROLLEDUP_PR_NUMBER: regex::Regex =
regex::Regex::new(r#"^Rollup merge of #(\d+)"#).unwrap();
}

// Gets the pr number for the associated rollup PR message. Returns None if this is not a rollup PR
Expand Down
65 changes: 8 additions & 57 deletions site/src/request_handlers/github.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
use crate::api::{github, ServerResult};
use crate::github::{
client, enqueue_sha, enqueue_unrolled_try_builds, parse_homu_comment, rollup_pr_number,
};
use crate::github::{client, enqueue_sha, parse_homu_comment, rollup_pr_number, unroll_rollup};
use crate::load::SiteCtxt;

use std::sync::Arc;

use regex::Regex;

lazy_static::lazy_static! {
static ref ROLLUP_PR_NUMBER: Regex =
Regex::new(r#"^Auto merge of #(\d+)"#).unwrap();
static ref ROLLEDUP_PR_NUMBER: Regex =
Regex::new(r#"^Rollup merge of #(\d+)"#).unwrap();
static ref BODY_TRY_COMMIT: Regex =
Regex::new(r#"(?:\W|^)@rust-timer\s+build\s+(\w+)(?:\W|$)(?:include=(\S+))?\s*(?:exclude=(\S+))?\s*(?:runs=(\d+))?"#).unwrap();
static ref BODY_QUEUE: Regex =
Expand Down Expand Up @@ -54,10 +48,15 @@ async fn handle_push(ctxt: Arc<SiteCtxt>, push: github::Push) -> ServerResult<gi
// GitHub webhooks have a timeout of 10 seconds, so we process this
// in the background.
tokio::spawn(async move {
let result = handle_rollup_merge(
let rollup_merges = commits
.iter()
.rev()
.skip(1) // skip the head commit
.take_while(|c| c.message.starts_with("Rollup merge of "));
let result = unroll_rollup(
ci_client,
main_repo_client,
commits,
rollup_merges,
&previous_master,
rollup_pr_number,
)
Expand All @@ -67,54 +66,6 @@ async fn handle_push(ctxt: Arc<SiteCtxt>, push: github::Push) -> ServerResult<gi
Ok(github::Response)
}

/// Handler for when a rollup has been merged
async fn handle_rollup_merge(
ci_client: client::Client,
main_repo_client: client::Client,
commits: Vec<github::Commit>,
previous_master: &str,
rollup_pr_number: u32,
) -> Result<(), String> {
let rollup_merges = commits
.iter()
.rev()
.skip(1) // skip the head commit
.take_while(|c| c.message.starts_with("Rollup merge of "));
let mapping = enqueue_unrolled_try_builds(ci_client, rollup_merges, previous_master).await?;
let mapping = mapping
.into_iter()
.map(|(rollup_merge, sha)| {
ROLLEDUP_PR_NUMBER
.captures(&rollup_merge.message)
.and_then(|c| c.get(1))
.map(|m| (m.as_str(), sha))
.ok_or_else(|| {
format!(
"Could not get PR number from message: '{}'",
rollup_merge.message
)
})
})
.fold(ServerResult::Ok(String::new()), |string, n| {
use std::fmt::Write;
let (pr, commit) = n?;
let mut string = string?;
write!(
&mut string,
"|#{pr}|[{commit}](https://github.com/rust-lang-ci/rust/commit/{commit})|\n"
)
.unwrap();
Ok(string)
})?;
let msg =
format!("📌 Perf builds for each rolled up PR:\n\n\
|PR# | Perf Build Sha|\n|----|-----|\n\
{mapping}\nIn the case of a perf regression, \
run the following command for each PR you suspect might be the cause: `@rust-timer build $SHA`");
main_repo_client.post_comment(rollup_pr_number, msg).await;
Ok(())
}

async fn handle_issue(
ctxt: Arc<SiteCtxt>,
issue: github::Issue,
Expand Down