-
Notifications
You must be signed in to change notification settings - Fork 97
Fix backport label handler #2245
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,14 @@ | ||
| //! Handle backport labels for PRs fixing P-high/critical regressions | ||
| //! | ||
| //! Configuration is done with the `[backport]` table. | ||
| //! | ||
| use std::collections::HashMap; | ||
| use std::sync::LazyLock; | ||
|
|
||
| use crate::config::BackportConfig; | ||
| use crate::github::{IssuesAction, IssuesEvent, Label}; | ||
| use crate::handlers::Context; | ||
| use crate::utils::contains_any; | ||
| use anyhow::Context as AnyhowContext; | ||
| use futures::future::join_all; | ||
| use regex::Regex; | ||
|
|
@@ -15,12 +20,9 @@ static CLOSES_ISSUE_REGEXP: LazyLock<Regex> = LazyLock::new(|| { | |
| Regex::new("(?i)(?P<action>close[sd]*|fix([e]*[sd]*)?|resolve[sd]*)(?P<spaces>:? +)(?P<org_repo>[a-zA-Z0-9_-]*/[a-zA-Z0-9_-]*)?#(?P<issue_num>[0-9]+)").unwrap() | ||
| }); | ||
|
|
||
| const BACKPORT_LABELS: [&str; 4] = [ | ||
| "beta-nominated", | ||
| "beta-accepted", | ||
| "stable-nominated", | ||
| "stable-accepted", | ||
| ]; | ||
| const BACKPORT_ACCEPTED_LABELS: [&str; 2] = ["beta-accepted", "stable-accepted"]; | ||
|
|
||
| const BACKPORT_NOMINATED_LABELS: [&str; 2] = ["beta-nominated", "stable-nominated"]; | ||
|
|
||
| const REGRESSION_LABELS: [&str; 3] = [ | ||
| "regression-from-stable-to-nightly", | ||
|
|
@@ -41,7 +43,7 @@ pub(crate) struct BackportInput { | |
| } | ||
|
|
||
| pub(super) async fn parse_input( | ||
| _ctx: &Context, | ||
| ctx: &Context, | ||
| event: &IssuesEvent, | ||
| config: Option<&BackportConfig>, | ||
| ) -> Result<Option<BackportInput>, String> { | ||
|
|
@@ -53,13 +55,17 @@ pub(super) async fn parse_input( | |
| // - is opened (and not a draft) | ||
| // - is converted from draft to ready for review | ||
| // - when the first comment is edited | ||
| // - when a label is added (later we check which one) | ||
| let skip_check = !matches!( | ||
| event.action, | ||
| IssuesAction::Opened | IssuesAction::Edited | IssuesAction::ReadyForReview | ||
| IssuesAction::Opened | ||
| | IssuesAction::Edited | ||
| | IssuesAction::ReadyForReview | ||
| | IssuesAction::Labeled { label: _ } | ||
| ); | ||
| if skip_check || !event.issue.is_pr() || event.issue.draft { | ||
| log::debug!( | ||
| "Skipping backport event because: IssuesAction = {:?}, issue.is_pr() {}, draft = {}", | ||
| "Skipping backport event because: IssuesAction = {:?}, issue.is_pr() = {}, draft = {}", | ||
| event.action, | ||
| event.issue.is_pr(), | ||
| event.issue.draft | ||
|
|
@@ -69,9 +75,28 @@ pub(super) async fn parse_input( | |
| let pr = &event.issue; | ||
|
|
||
| let pr_labels: Vec<&str> = pr.labels.iter().map(|l| l.name.as_str()).collect(); | ||
| if contains_any(&pr_labels, &BACKPORT_LABELS) { | ||
| log::debug!("PR #{} already has a backport label", pr.number); | ||
| return Ok(None); | ||
|
|
||
| // If a "-nominated" label is added to an already "-accepted" PR, remove the label added by github | ||
| if let IssuesAction::Labeled { label } = &event.action | ||
| && BACKPORT_NOMINATED_LABELS.contains(&label.name.as_str()) | ||
| { | ||
| if contains_any(&pr_labels, &BACKPORT_ACCEPTED_LABELS) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will have the same bug as before, right? If the PR is already You'll need to separate the labels on the axis of beta/stable, rather than nominated/accepted.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm ... you're right but the solution is more complex that separating on another axis. I'm afraid I'll need to map all possible cases (4 labels = 16 cases) and then see if I can reduce to a couple of ifs. In any case, I want to keep it simple: if this does not work, I have another patch to add "negated labels" when sending zulip notification, that would solve the issue from another point of view. I'll be back on this.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can't just remove this: if contains_any(&pr_labels, &BACKPORT_LABELS) {
log::debug!("PR #{} already has a backport label", pr.number);
return Ok(None);
}? Seems like the bug is just caused by this. Btw, I tested that once you receive the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sorry, I am confused by your comment: isn't that chunk of code removed in this patch? Or did you mean to just remove that code without adding anything else? In the latter case, I think that not checking labels would open up to confusion when adding regression labels (which was the point of this patch).
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I meant remove without adding anything else. Say that we remove the original check - what will be the problematic situations that could be caused in that case? Adding |
||
| log::debug!( | ||
| "Refusing to backport nominate, PR #{} is already backport accepted (found labels: {:?})", | ||
| pr.number, | ||
| pr_labels | ||
| ); | ||
| let label_to_remove = vec![Label { | ||
| name: label.name.clone(), | ||
| }]; | ||
| let _ = &event | ||
| .issue | ||
| .remove_labels(&ctx.github, label_to_remove) | ||
| .await | ||
| .context("failed to remove labels from the issue") | ||
| .unwrap(); | ||
| return Ok(None); | ||
| } | ||
| } | ||
|
|
||
| // Retrieve backport config for this PR, based on its team label(s) | ||
|
|
@@ -187,7 +212,8 @@ pub(super) async fn handle_input( | |
| continue; | ||
| } | ||
|
|
||
| // Add backport nomination label(s) to PR | ||
| // When backport nominating/accepting a PR, if a `[notify-zulip]` table is configured in triagebot.toml | ||
| // that will trigger the notify_zulip handler | ||
| let mut new_labels = pr.labels().to_owned(); | ||
| new_labels.extend( | ||
| add_labels | ||
|
|
@@ -210,16 +236,12 @@ pub(super) async fn handle_input( | |
| Ok(()) | ||
| } | ||
|
|
||
| fn contains_any(haystack: &[&str], needles: &[&str]) -> bool { | ||
| needles.iter().any(|needle| haystack.contains(needle)) | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use crate::handlers::backport::CLOSES_ISSUE_REGEXP; | ||
|
|
||
| #[tokio::test] | ||
| async fn backport_match_comment() { | ||
| #[test] | ||
| fn backport_match_comment() { | ||
| let test_strings = vec![ | ||
| ("close #10", vec![10]), | ||
| ("closes #10", vec![10]), | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.