From f07a5dbbf632c61673153356d30f6c5d40edda1f Mon Sep 17 00:00:00 2001 From: mibac138 <5672750+mibac138@users.noreply.github.com> Date: Sun, 6 Jun 2021 19:03:30 +0200 Subject: [PATCH 1/2] Automatically add beta nominated to issues fixing regressions ... from stable to beta --- src/github.rs | 14 ++++++++++ src/handlers.rs | 1 + src/handlers/beta_backport.rs | 52 +++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+) create mode 100644 src/handlers/beta_backport.rs diff --git a/src/github.rs b/src/github.rs index 22e8fecf..a75e07da 100644 --- a/src/github.rs +++ b/src/github.rs @@ -762,6 +762,20 @@ pub struct Repository { impl Repository { const GITHUB_API_URL: &'static str = "https://api.github.com"; + pub async fn get_issue(&self, client: &GithubClient, id: u64) -> anyhow::Result { + let url = format!( + "{}/repos/{}/issues/{}", + Repository::GITHUB_API_URL, + self.full_name, + id + ); + let result = client.get(&url); + client + .json(result) + .await + .with_context(|| format!("failed to get issue from {}", url)) + } + pub async fn get_issues<'a>( &self, client: &GithubClient, diff --git a/src/handlers.rs b/src/handlers.rs index e1100fcd..cfe4a624 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -25,6 +25,7 @@ impl fmt::Display for HandlerError { mod assign; mod autolabel; +mod beta_backport; mod close; mod github_releases; mod glacier; diff --git a/src/handlers/beta_backport.rs b/src/handlers/beta_backport.rs new file mode 100644 index 00000000..07ae7e6b --- /dev/null +++ b/src/handlers/beta_backport.rs @@ -0,0 +1,52 @@ +use crate::github::{Event, IssuesAction, Label}; +use crate::handlers::Context; +use regex::Regex; + +lazy_static! { + // See https://docs.github.com/en/issues/tracking-your-work-with-issues/creating-issues/linking-a-pull-request-to-an-issue + // Max 19 digits long to prevent u64 overflow + static ref CLOSES_ISSUE: Regex = Regex::new("(close[sd]|fix(e[sd])?|resolve[sd]) #(\\d{1,19})").unwrap(); +} + +pub(crate) async fn handle( + ctx: &Context, + event: &Event, +) -> anyhow::Result<()> { + let issue_event = if let Event::Issue(event) = event { + event + } else { + return Ok(()); + }; + + if issue_event.action != IssuesAction::Opened { + return Ok(()); + } + + if issue_event.issue.pull_request.is_none() { + return Ok(()); + } + + for caps in CLOSES_ISSUE.captures_iter(&issue_event.issue.body) { + // Should never fail due to the regex + let issue_id = caps.get(1).unwrap().as_str().parse::().unwrap(); + let issue = issue_event + .repository + .get_issue(&ctx.github, issue_id) + .await?; + if issue.labels.contains(&Label { + name: "regression-from-stable-to-beta".to_string(), + }) { + let mut labels = issue_event.issue.labels().to_owned(); + labels.push(Label { + name: "beta-nominated".to_string(), + }); + issue_event + .issue + .set_labels(&ctx.github, labels) + .await?; + break; + } + } + + Ok(()) +} From 3e4588ae72b5faaa5beee1c47110095c27624f3d Mon Sep 17 00:00:00 2001 From: mibac138 <5672750+mibac138@users.noreply.github.com> Date: Sun, 11 Jul 2021 19:54:03 +0200 Subject: [PATCH 2/2] Rework beta_backport handler --- src/config.rs | 9 +++ src/handlers.rs | 1 + src/handlers/beta_backport.rs | 105 ++++++++++++++++++++++------------ 3 files changed, 79 insertions(+), 36 deletions(-) diff --git a/src/config.rs b/src/config.rs index 248ac546..acb2f14f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -29,6 +29,7 @@ pub(crate) struct Config { pub(crate) notify_zulip: Option, pub(crate) github_releases: Option, pub(crate) review_submitted: Option, + pub(crate) beta_backport: Option, } #[derive(PartialEq, Eq, Debug, serde::Deserialize)] @@ -112,6 +113,13 @@ pub(crate) struct AutolabelLabelConfig { pub(crate) exclude_labels: Vec, } +#[derive(PartialEq, Eq, Debug, serde::Deserialize)] +pub(crate) struct BetaBackportConfig { + pub(crate) trigger_labels: Vec, + #[serde(default)] + pub(crate) labels_to_add: Vec, +} + #[derive(PartialEq, Eq, Debug, serde::Deserialize)] pub(crate) struct NotifyZulipConfig { #[serde(flatten)] @@ -298,6 +306,7 @@ mod tests { notify_zulip: None, github_releases: None, review_submitted: None, + beta_backport: None, } ); } diff --git a/src/handlers.rs b/src/handlers.rs index cfe4a624..637d7787 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -142,6 +142,7 @@ macro_rules! issue_handlers { // Each module in the list must contain the functions `parse_input` and `handle_input`. issue_handlers! { autolabel, + beta_backport, major_change, notify_zulip, } diff --git a/src/handlers/beta_backport.rs b/src/handlers/beta_backport.rs index 07ae7e6b..1576c08c 100644 --- a/src/handlers/beta_backport.rs +++ b/src/handlers/beta_backport.rs @@ -1,50 +1,83 @@ -use crate::github::{Event, IssuesAction, Label}; +use crate::config::BetaBackportConfig; +use crate::github::{IssuesAction, IssuesEvent, Label}; use crate::handlers::Context; use regex::Regex; lazy_static! { // See https://docs.github.com/en/issues/tracking-your-work-with-issues/creating-issues/linking-a-pull-request-to-an-issue - // Max 19 digits long to prevent u64 overflow - static ref CLOSES_ISSUE: Regex = Regex::new("(close[sd]|fix(e[sd])?|resolve[sd]) #(\\d{1,19})").unwrap(); + static ref CLOSES_ISSUE: Regex = Regex::new("(close[sd]|fix(e[sd])?|resolve[sd]) #(\\d+)").unwrap(); } -pub(crate) async fn handle( - ctx: &Context, - event: &Event, -) -> anyhow::Result<()> { - let issue_event = if let Event::Issue(event) = event { - event - } else { - return Ok(()); - }; - - if issue_event.action != IssuesAction::Opened { - return Ok(()); +pub(crate) struct BetaBackportInput { + ids: Vec, +} + +pub(crate) fn parse_input( + _ctx: &Context, + event: &IssuesEvent, + config: Option<&BetaBackportConfig>, +) -> Result, String> { + if config.is_none() { + return Ok(None); } - if issue_event.issue.pull_request.is_none() { - return Ok(()); + if event.action != IssuesAction::Opened { + return Ok(None); } - for caps in CLOSES_ISSUE.captures_iter(&issue_event.issue.body) { - // Should never fail due to the regex - let issue_id = caps.get(1).unwrap().as_str().parse::().unwrap(); - let issue = issue_event - .repository - .get_issue(&ctx.github, issue_id) - .await?; - if issue.labels.contains(&Label { - name: "regression-from-stable-to-beta".to_string(), - }) { - let mut labels = issue_event.issue.labels().to_owned(); - labels.push(Label { - name: "beta-nominated".to_string(), - }); - issue_event - .issue - .set_labels(&ctx.github, labels) - .await?; - break; + if event.issue.pull_request.is_none() { + return Ok(None); + } + + let mut ids = vec![]; + for caps in CLOSES_ISSUE.captures_iter(&event.issue.body) { + let id = caps.get(1).unwrap().as_str(); + let id = match id.parse::() { + Ok(id) => id, + Err(err) => { + return Err(format!("Failed to parse issue id `{}`, error: {}", id, err)); + } + }; + ids.push(id); + } + + return Ok(Some(BetaBackportInput { ids })); +} + +pub(super) async fn handle_input( + ctx: &Context, + config: &BetaBackportConfig, + event: &IssuesEvent, + input: BetaBackportInput, +) -> anyhow::Result<()> { + let mut issues = input + .ids + .iter() + .copied() + .map(|id| async move { event.repository.get_issue(&ctx.github, id).await }); + + let trigger_labels: Vec<_> = config + .trigger_labels + .iter() + .cloned() + .map(|name| Label { name }) + .collect(); + while let Some(issue) = issues.next() { + let issue = issue.await.unwrap(); + if issue + .labels + .iter() + .any(|issue_label| trigger_labels.contains(issue_label)) + { + let mut new_labels = event.issue.labels().to_owned(); + new_labels.extend( + config + .labels_to_add + .iter() + .cloned() + .map(|name| Label { name }), + ); + return event.issue.set_labels(&ctx.github, new_labels).await; } }