From b264de0ebc7cdc9b9171f27151bd7c467dbcce73 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Tue, 6 Feb 2024 01:02:46 +0100 Subject: [PATCH 1/3] Add support for labeling draft PRs --- src/config.rs | 18 ++++++++++++ src/handlers.rs | 4 +++ src/handlers/autolabel.rs | 17 ++++++------ src/handlers/converted_to_draft.rs | 44 ++++++++++++++++++++++++++++++ src/handlers/ready_for_review.rs | 44 ++++++++++++++++++++++++++++++ 5 files changed, 119 insertions(+), 8 deletions(-) create mode 100644 src/handlers/converted_to_draft.rs create mode 100644 src/handlers/ready_for_review.rs diff --git a/src/config.rs b/src/config.rs index 244c35ef..3ec99725 100644 --- a/src/config.rs +++ b/src/config.rs @@ -32,6 +32,8 @@ pub(crate) struct Config { pub(crate) github_releases: Option, pub(crate) review_submitted: Option, pub(crate) review_requested: Option, + pub(crate) converted_to_draft: Option, + pub(crate) ready_for_review: Option, pub(crate) shortcut: Option, pub(crate) note: Option, pub(crate) mentions: Option, @@ -209,6 +211,8 @@ pub(crate) struct AutolabelLabelConfig { #[serde(default)] pub(crate) new_pr: bool, #[serde(default)] + pub(crate) new_draft_pr: bool, + #[serde(default)] pub(crate) new_issue: bool, } @@ -289,6 +293,20 @@ pub(crate) struct ReviewRequestedConfig { pub(crate) add_labels: Vec, } +#[derive(PartialEq, Eq, Debug, serde::Deserialize)] +#[serde(deny_unknown_fields)] +pub(crate) struct ConvertedToDraftConfig { + pub(crate) remove_labels: Vec, + pub(crate) add_labels: Vec, +} + +#[derive(PartialEq, Eq, Debug, serde::Deserialize)] +#[serde(deny_unknown_fields)] +pub(crate) struct ReadyForReviewConfig { + pub(crate) remove_labels: Vec, + pub(crate) add_labels: Vec, +} + pub(crate) async fn get( gh: &GithubClient, repo: &Repository, diff --git a/src/handlers.rs b/src/handlers.rs index 814113b3..cdce3af7 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -26,6 +26,7 @@ impl fmt::Display for HandlerError { mod assign; mod autolabel; mod close; +mod converted_to_draft; pub mod docs_update; mod github_releases; mod glacier; @@ -39,6 +40,7 @@ mod notification; mod notify_zulip; mod ping; mod prioritize; +mod ready_for_review; mod relabel; mod review_requested; mod review_submitted; @@ -167,6 +169,8 @@ issue_handlers! { no_merges, notify_zulip, review_requested, + converted_to_draft, + ready_for_review, validate_config, } diff --git a/src/handlers/autolabel.rs b/src/handlers/autolabel.rs index 2a107849..dae3fb16 100644 --- a/src/handlers/autolabel.rs +++ b/src/handlers/autolabel.rs @@ -69,21 +69,22 @@ pub(super) async fn parse_input( name: label.to_owned(), }); } - if cfg.new_pr && event.action == IssuesAction::Opened { - autolabels.push(Label { - name: label.to_owned(), - }); - } } - if event.issue.pull_request.is_none() - && cfg.new_issue - && event.action == IssuesAction::Opened + if event.issue.is_pr() + && matches!(event.action, IssuesAction::Opened) + && ((cfg.new_pr && !event.issue.draft) || (cfg.new_draft_pr && event.issue.draft)) { autolabels.push(Label { name: label.to_owned(), }); } + + if !event.issue.is_pr() && cfg.new_issue && event.action == IssuesAction::Opened { + autolabels.push(Label { + name: label.to_owned(), + }); + } } if !autolabels.is_empty() { diff --git a/src/handlers/converted_to_draft.rs b/src/handlers/converted_to_draft.rs new file mode 100644 index 00000000..ef16f001 --- /dev/null +++ b/src/handlers/converted_to_draft.rs @@ -0,0 +1,44 @@ +use crate::config::ConvertedToDraftConfig; +use crate::github::{IssuesAction, IssuesEvent, Label}; +use crate::handlers::Context; + +pub(crate) struct ConvertedToDraftInput {} + +pub(crate) async fn parse_input( + _ctx: &Context, + event: &IssuesEvent, + _config: Option<&ConvertedToDraftConfig>, +) -> Result, String> { + // PR author requests a review from one of the assignees + + match &event.action { + IssuesAction::ConvertedToDraft => Ok(Some(ConvertedToDraftInput {})), + _ => Ok(None), + } +} + +pub(crate) async fn handle_input( + ctx: &Context, + config: &ConvertedToDraftConfig, + event: &IssuesEvent, + ConvertedToDraftInput {}: ConvertedToDraftInput, +) -> anyhow::Result<()> { + event + .issue + .add_labels( + &ctx.github, + config + .add_labels + .iter() + .cloned() + .map(|name| Label { name }) + .collect(), + ) + .await?; + + for label in &config.remove_labels { + event.issue.remove_label(&ctx.github, label).await?; + } + + Ok(()) +} diff --git a/src/handlers/ready_for_review.rs b/src/handlers/ready_for_review.rs new file mode 100644 index 00000000..929ebd2a --- /dev/null +++ b/src/handlers/ready_for_review.rs @@ -0,0 +1,44 @@ +use crate::config::ReadyForReviewConfig; +use crate::github::{IssuesAction, IssuesEvent, Label}; +use crate::handlers::Context; + +pub(crate) struct ReadyForReviewInput {} + +pub(crate) async fn parse_input( + _ctx: &Context, + event: &IssuesEvent, + _config: Option<&ReadyForReviewConfig>, +) -> Result, String> { + // PR author requests a review from one of the assignees + + match &event.action { + IssuesAction::ReadyForReview => Ok(Some(ReadyForReviewInput {})), + _ => Ok(None), + } +} + +pub(crate) async fn handle_input( + ctx: &Context, + config: &ReadyForReviewConfig, + event: &IssuesEvent, + ReadyForReviewInput {}: ReadyForReviewInput, +) -> anyhow::Result<()> { + event + .issue + .add_labels( + &ctx.github, + config + .add_labels + .iter() + .cloned() + .map(|name| Label { name }) + .collect(), + ) + .await?; + + for label in &config.remove_labels { + event.issue.remove_label(&ctx.github, label).await?; + } + + Ok(()) +} From e2bce8b00abbe7e065db723eb648b1ad54888151 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Tue, 6 Feb 2024 01:06:50 +0100 Subject: [PATCH 2/3] Apply labels to reopened issues --- src/config.rs | 4 ++++ src/handlers/autolabel.rs | 15 ++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/config.rs b/src/config.rs index 3ec99725..cbd682e9 100644 --- a/src/config.rs +++ b/src/config.rs @@ -213,6 +213,10 @@ pub(crate) struct AutolabelLabelConfig { #[serde(default)] pub(crate) new_draft_pr: bool, #[serde(default)] + pub(crate) reopened_pr: bool, + #[serde(default)] + pub(crate) reopened_draft_pr: bool, + #[serde(default)] pub(crate) new_issue: bool, } diff --git a/src/handlers/autolabel.rs b/src/handlers/autolabel.rs index dae3fb16..26a00428 100644 --- a/src/handlers/autolabel.rs +++ b/src/handlers/autolabel.rs @@ -26,7 +26,10 @@ pub(super) async fn parse_input( // FIXME: This will re-apply labels after a push that the user had tried to // remove. Not much can be done about that currently; the before/after on // synchronize may be straddling a rebase, which will break diff generation. - if event.action == IssuesAction::Opened || event.action == IssuesAction::Synchronize { + if matches!( + &event.action, + IssuesAction::Opened | IssuesAction::Reopened | IssuesAction::Synchronize + ) { let files = event .issue .diff(&ctx.github) @@ -80,6 +83,16 @@ pub(super) async fn parse_input( }); } + if event.issue.is_pr() + && matches!(event.action, IssuesAction::Reopened) + && ((cfg.reopened_pr && !event.issue.draft) + || (cfg.reopened_draft_pr && event.issue.draft)) + { + autolabels.push(Label { + name: label.to_owned(), + }); + } + if !event.issue.is_pr() && cfg.new_issue && event.action == IssuesAction::Opened { autolabels.push(Label { name: label.to_owned(), From 672829bd5704b8159aca0af793bbee4dd2c7cd68 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Tue, 6 Feb 2024 01:50:52 +0100 Subject: [PATCH 3/3] Add an option to change labels on PR closing --- src/config.rs | 8 +++++++ src/handlers.rs | 2 ++ src/handlers/closed_pr.rs | 44 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 src/handlers/closed_pr.rs diff --git a/src/config.rs b/src/config.rs index cbd682e9..b9853552 100644 --- a/src/config.rs +++ b/src/config.rs @@ -34,6 +34,7 @@ pub(crate) struct Config { pub(crate) review_requested: Option, pub(crate) converted_to_draft: Option, pub(crate) ready_for_review: Option, + pub(crate) closed_pr: Option, pub(crate) shortcut: Option, pub(crate) note: Option, pub(crate) mentions: Option, @@ -311,6 +312,13 @@ pub(crate) struct ReadyForReviewConfig { pub(crate) add_labels: Vec, } +#[derive(PartialEq, Eq, Debug, serde::Deserialize)] +#[serde(deny_unknown_fields)] +pub(crate) struct ClosedPrConfig { + pub(crate) remove_labels: Vec, + pub(crate) add_labels: Vec, +} + pub(crate) async fn get( gh: &GithubClient, repo: &Repository, diff --git a/src/handlers.rs b/src/handlers.rs index cdce3af7..0a7d3347 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -26,6 +26,7 @@ impl fmt::Display for HandlerError { mod assign; mod autolabel; mod close; +mod closed_pr; mod converted_to_draft; pub mod docs_update; mod github_releases; @@ -171,6 +172,7 @@ issue_handlers! { review_requested, converted_to_draft, ready_for_review, + closed_pr, validate_config, } diff --git a/src/handlers/closed_pr.rs b/src/handlers/closed_pr.rs new file mode 100644 index 00000000..1ad15480 --- /dev/null +++ b/src/handlers/closed_pr.rs @@ -0,0 +1,44 @@ +use crate::config::ClosedPrConfig; +use crate::github::{IssuesAction, IssuesEvent, Label}; +use crate::handlers::Context; + +pub(crate) struct ClosedPrInput {} + +pub(crate) async fn parse_input( + _ctx: &Context, + event: &IssuesEvent, + _config: Option<&ClosedPrConfig>, +) -> Result, String> { + // PR author requests a review from one of the assignees + + match &event.action { + IssuesAction::Closed if event.issue.is_pr() => Ok(Some(ClosedPrInput {})), + _ => Ok(None), + } +} + +pub(crate) async fn handle_input( + ctx: &Context, + config: &ClosedPrConfig, + event: &IssuesEvent, + ClosedPrInput {}: ClosedPrInput, +) -> anyhow::Result<()> { + event + .issue + .add_labels( + &ctx.github, + config + .add_labels + .iter() + .cloned() + .map(|name| Label { name }) + .collect(), + ) + .await?; + + for label in &config.remove_labels { + event.issue.remove_label(&ctx.github, label).await?; + } + + Ok(()) +}