Skip to content
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

Fetch untriaged perf-regression PRs #907

Merged
merged 1 commit into from
Jul 19, 2021
Merged
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
64 changes: 26 additions & 38 deletions site/src/comparison.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use crate::api;
use crate::db::{ArtifactId, Cache, Crate, Profile};
use crate::github;
use crate::load::SiteCtxt;
use crate::selector::{self, Tag};

Expand Down Expand Up @@ -80,7 +81,7 @@ pub async fn handle_triage(
}
let end = end.unwrap_or(after);

let report = generate_report(&start, &end, report);
let report = generate_report(&start, &end, report).await;
Ok(api::triage::Response(report))
}

Expand Down Expand Up @@ -191,7 +192,7 @@ impl ComparisonSummary<'_> {
use std::fmt::Write;

let mut result = if let Some(pr) = comparison.b.pr {
let title = gh_pr_title(pr).await;
let title = github::pr_title(pr).await;
format!(
"{} [#{}](https://github.com/rust-lang/rust/issues/{})\n",
title, pr, pr
Expand Down Expand Up @@ -437,7 +438,7 @@ impl Comparison {

/// Gets the sha of the next commit after `b`
pub fn next(&self, master_commits: &[collector::MasterCommit]) -> Option<String> {
next_commit(&self.a.artifact, master_commits).map(|c| c.parent_sha.clone())
next_commit(&self.b.artifact, master_commits).map(|c| c.sha.clone())
}

fn get_benchmarks<'a>(&'a self) -> Vec<BenchmarkComparison<'a>> {
Expand Down Expand Up @@ -725,7 +726,7 @@ impl std::fmt::Display for Direction {
}
}

fn generate_report(
async fn generate_report(
start: &Bound,
end: &Bound,
mut report: HashMap<Direction, Vec<String>>,
Expand All @@ -742,6 +743,22 @@ fn generate_report(
let regressions = report.remove(&Direction::Regression).unwrap_or_default();
let improvements = report.remove(&Direction::Improvement).unwrap_or_default();
let mixed = report.remove(&Direction::Mixed).unwrap_or_default();
let untriaged = match github::untriaged_perf_regressions().await {
Ok(u) => u
.iter()
.map(|github::PullRequest { title, number }| {
format!(
"- [#{} {}](https://github.com/rust-lang/rust/pull/{})",
number, title, number
)
})
.collect::<Vec<_>>()
.join("\n"),
Err(e) => format!(
"An **error** occurred when finding the untriaged PRs: {}",
e
),
};
format!(
r#####"# {date} Triage Log

Expand All @@ -764,6 +781,10 @@ Revision range: [{first_commit}..{last_commit}](https://perf.rust-lang.org/?star

{mixed}

#### Untriaged Pull Requests

{untriaged}

#### Nags requiring follow up

TODO: Nags
Expand All @@ -778,6 +799,7 @@ TODO: Nags
regressions = regressions.join("\n\n"),
improvements = improvements.join("\n\n"),
mixed = mixed.join("\n\n"),
untriaged = untriaged
)
}

Expand All @@ -795,37 +817,3 @@ fn compare_link(start: &ArtifactId, end: &ArtifactId) -> String {
start, end
)
}

async fn gh_pr_title(pr: u32) -> String {
let url = format!("https://api.github.com/repos/rust-lang/rust/pulls/{}", pr);
let client = reqwest::Client::new();
let mut request = client
.get(&url)
.header("Content-Type", "application/json")
.header("User-Agent", "rustc-perf");

if let Some(token) = std::env::var("GITHUB_TOKEN").ok() {
request = request.header("Authorization", format!("token {}", token));
}

async fn send(request: reqwest::RequestBuilder) -> Result<String, BoxedError> {
Ok(request
.send()
.await?
.error_for_status()?
.json::<serde_json::Value>()
.await?
.get("title")
.ok_or_else(|| "JSON was malformed".to_owned())?
.as_str()
.ok_or_else(|| "JSON was malformed".to_owned())?
.to_owned())
}
match send(request).await {
Ok(t) => t,
Err(e) => {
eprintln!("Error fetching url: {}", e);
String::from("<UNKNOWN>")
}
}
}
90 changes: 87 additions & 3 deletions site/src/github.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
use crate::api::{github, ServerResult};
use crate::comparison::{ComparisonSummary, Direction};
use crate::load::{Config, SiteCtxt, TryCommit};
use anyhow::Context as _;
use hashbrown::HashSet;
use serde::Deserialize;

use anyhow::Context as _;
use database::ArtifactId;
use hashbrown::HashSet;
use regex::Regex;
use reqwest::header::USER_AGENT;
use serde::Deserialize;

use std::{fmt::Write, sync::Arc, time::Duration};

type BoxedError = Box<dyn std::error::Error + Send + Sync>;

lazy_static::lazy_static! {
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();
Expand Down Expand Up @@ -732,3 +735,84 @@ async fn categorize_benchmark(
write!(result, "\n{}", DISAGREEMENT).unwrap();
(result, Some(direction))
}

pub(crate) struct PullRequest {
pub number: u64,
pub title: String,
}

/// Fetch all merged PRs that are labeled with `perf-regression` and not `perf-regression-triaged`
pub(crate) async fn untriaged_perf_regressions() -> Result<Vec<PullRequest>, BoxedError> {
let url = "https://api.github.com/search/issues?q=repo:rust-lang/rust+label:perf-regression+-label:perf-regression-triaged+is:merged".to_owned();
let request = github_request(&url);
let body = send_request(request).await?;
Ok(body
.get("items")
.ok_or_else(malformed_json_error)?
.as_array()
.ok_or_else(malformed_json_error)?
.iter()
.map(|v| {
let title = v
.get("title")
.ok_or_else(malformed_json_error)?
.as_str()
.ok_or_else(malformed_json_error)?
.to_owned();
let number = v
.get("number")
.ok_or_else(malformed_json_error)?
.as_u64()
.ok_or_else(malformed_json_error)?;
Ok(PullRequest { title, number })
})
.collect::<Result<_, BoxedError>>()?)
}

/// Get the title of a PR with the given number
pub(crate) async fn pr_title(pr: u32) -> String {
let url = format!("https://api.github.com/repos/rust-lang/rust/pulls/{}", pr);
let request = github_request(&url);

async fn send(request: reqwest::RequestBuilder) -> Result<String, BoxedError> {
let body = send_request(request).await?;
Ok(body
.get("title")
.ok_or_else(malformed_json_error)?
.as_str()
.ok_or_else(malformed_json_error)?
.to_owned())
}
match send(request).await {
Ok(t) => t,
Err(e) => {
eprintln!("Error fetching url: {}", e);
String::from("<UNKNOWN>")
}
}
}

fn github_request(url: &str) -> reqwest::RequestBuilder {
let client = reqwest::Client::new();
let mut request = client
.get(url)
.header("Content-Type", "application/json")
.header("User-Agent", "rustc-perf");
if let Some(token) = std::env::var("GITHUB_TOKEN").ok() {
request = request.header("Authorization", format!("token {}", token));
}
request
}

async fn send_request(request: reqwest::RequestBuilder) -> Result<serde_json::Value, BoxedError> {
Ok(request
.send()
.await?
.error_for_status()?
.json::<serde_json::Value>()
.await?)
}

fn malformed_json_error() -> String {
"JSON was malformed".to_owned()
}