Skip to content

Commit 155434b

Browse files
Merge pull request #1733 from WaffleLapkin/review-requested
Allow switching prs to waiting on review when author has requested a review from an assignee
2 parents da21290 + 9563aff commit 155434b

File tree

7 files changed

+94
-32
lines changed

7 files changed

+94
-32
lines changed

src/config.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pub(crate) struct Config {
3030
pub(crate) notify_zulip: Option<NotifyZulipConfig>,
3131
pub(crate) github_releases: Option<GitHubReleasesConfig>,
3232
pub(crate) review_submitted: Option<ReviewSubmittedConfig>,
33+
pub(crate) review_requested: Option<ReviewRequestedConfig>,
3334
pub(crate) shortcut: Option<ShortcutConfig>,
3435
pub(crate) note: Option<NoteConfig>,
3536
pub(crate) mentions: Option<MentionsConfig>,
@@ -253,6 +254,12 @@ pub(crate) struct ReviewSubmittedConfig {
253254
pub(crate) reviewed_label: String,
254255
}
255256

257+
#[derive(PartialEq, Eq, Debug, serde::Deserialize)]
258+
pub(crate) struct ReviewRequestedConfig {
259+
pub(crate) remove_labels: Vec<String>,
260+
pub(crate) add_labels: Vec<String>,
261+
}
262+
256263
pub(crate) async fn get(
257264
gh: &GithubClient,
258265
repo: &Repository,
@@ -421,6 +428,7 @@ mod tests {
421428
notify_zulip: None,
422429
github_releases: None,
423430
review_submitted: None,
431+
review_requested: None,
424432
mentions: None,
425433
no_merges: None,
426434
}

src/github.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -923,7 +923,7 @@ pub struct IssueCommentEvent {
923923
}
924924

925925
#[derive(PartialEq, Eq, Debug, serde::Deserialize)]
926-
#[serde(rename_all = "snake_case")]
926+
#[serde(rename_all = "snake_case", tag = "action")]
927927
pub enum IssuesAction {
928928
Opened,
929929
Edited,
@@ -935,13 +935,22 @@ pub enum IssuesAction {
935935
Reopened,
936936
Assigned,
937937
Unassigned,
938-
Labeled,
939-
Unlabeled,
938+
Labeled {
939+
/// The label added from the issue
940+
label: Label,
941+
},
942+
Unlabeled {
943+
/// The label removed from the issue
944+
label: Label,
945+
},
940946
Locked,
941947
Unlocked,
942948
Milestoned,
943949
Demilestoned,
944-
ReviewRequested,
950+
ReviewRequested {
951+
/// The person requested to review the pull request
952+
requested_reviewer: User,
953+
},
945954
ReviewRequestRemoved,
946955
ReadyForReview,
947956
Synchronize,
@@ -952,13 +961,14 @@ pub enum IssuesAction {
952961

953962
#[derive(Debug, serde::Deserialize)]
954963
pub struct IssuesEvent {
964+
#[serde(flatten)]
955965
pub action: IssuesAction,
956966
#[serde(alias = "pull_request")]
957967
pub issue: Issue,
958968
pub changes: Option<Changes>,
959969
pub repository: Repository,
960-
/// Some if action is IssuesAction::Labeled, for example
961-
pub label: Option<Label>,
970+
/// The GitHub user that triggered the event.
971+
pub sender: User,
962972
}
963973

964974
#[derive(Debug, serde::Deserialize)]

src/handlers.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ mod notify_zulip;
4141
mod ping;
4242
mod prioritize;
4343
mod relabel;
44+
mod review_requested;
4445
mod review_submitted;
4546
mod rfc_helper;
4647
pub mod rustc_commits;
@@ -164,6 +165,7 @@ issue_handlers! {
164165
mentions,
165166
no_merges,
166167
notify_zulip,
168+
review_requested,
167169
}
168170

169171
macro_rules! command_handlers {

src/handlers/autolabel.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,9 @@ pub(super) async fn parse_input(
9595
}
9696
}
9797

98-
if event.action == IssuesAction::Labeled {
98+
if let IssuesAction::Labeled { label } = &event.action {
9999
let mut autolabels = Vec::new();
100-
let applied_label = &event.label.as_ref().expect("label").name;
100+
let applied_label = &label.name;
101101

102102
'outer: for (label, config) in config.get_by_trigger(applied_label) {
103103
let exclude_patterns: Vec<glob::Pattern> = config

src/handlers/major_change.rs

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,7 @@ pub(super) async fn parse_input(
5555
}
5656

5757
// If we were labeled with accepted, then issue that event
58-
if event.action == IssuesAction::Labeled
59-
&& event
60-
.label
61-
.as_ref()
62-
.map_or(false, |l| l.name == config.accept_label)
58+
if matches!(&event.action, IssuesAction::Labeled { label } if label.name == config.accept_label)
6359
{
6460
return Ok(Some(Invocation::AcceptedProposal));
6561
}
@@ -70,17 +66,8 @@ pub(super) async fn parse_input(
7066
// We want to treat reopened issues as new proposals but if the
7167
// issue is freshly opened, we only want to trigger once;
7268
// currently we do so on the label event.
73-
if (event.action == IssuesAction::Reopened
74-
&& event
75-
.issue
76-
.labels()
77-
.iter()
78-
.any(|l| l.name == enabling_label))
79-
|| (event.action == IssuesAction::Labeled
80-
&& event
81-
.label
82-
.as_ref()
83-
.map_or(false, |l| l.name == enabling_label))
69+
if matches!(event.action, IssuesAction::Reopened if event.issue.labels().iter().any(|l| l.name == enabling_label))
70+
|| matches!(&event.action, IssuesAction::Labeled { label } if label.name == enabling_label)
8471
{
8572
return Ok(Some(Invocation::NewProposal));
8673
}

src/handlers/notify_zulip.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ pub(super) async fn parse_input(
3131
None => return Ok(None),
3232
};
3333

34-
match event.action {
35-
IssuesAction::Labeled | IssuesAction::Unlabeled => {
36-
let applied_label = event.label.as_ref().expect("label").clone();
34+
match &event.action {
35+
IssuesAction::Labeled { label } | IssuesAction::Unlabeled { label } => {
36+
let applied_label = label.clone();
3737
Ok(config
3838
.labels
3939
.get(&applied_label.name)
@@ -60,14 +60,16 @@ fn parse_label_change_input(
6060
}
6161

6262
match event.action {
63-
IssuesAction::Labeled if config.message_on_add.is_some() => Some(NotifyZulipInput {
63+
IssuesAction::Labeled { .. } if config.message_on_add.is_some() => Some(NotifyZulipInput {
6464
notification_type: NotificationType::Labeled,
6565
label,
6666
}),
67-
IssuesAction::Unlabeled if config.message_on_remove.is_some() => Some(NotifyZulipInput {
68-
notification_type: NotificationType::Unlabeled,
69-
label,
70-
}),
67+
IssuesAction::Unlabeled { .. } if config.message_on_remove.is_some() => {
68+
Some(NotifyZulipInput {
69+
notification_type: NotificationType::Unlabeled,
70+
label,
71+
})
72+
}
7173
_ => None,
7274
}
7375
}

src/handlers/review_requested.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
use crate::config::ReviewRequestedConfig;
2+
use crate::github::{IssuesAction, IssuesEvent, Label};
3+
use crate::handlers::Context;
4+
5+
pub(crate) struct ReviewRequestedInput {}
6+
7+
pub(crate) async fn parse_input(
8+
_ctx: &Context,
9+
event: &IssuesEvent,
10+
_config: Option<&ReviewRequestedConfig>,
11+
) -> Result<Option<ReviewRequestedInput>, String> {
12+
// PR author requests a review from one of the assignees
13+
14+
let IssuesAction::ReviewRequested { requested_reviewer } = &event.action else {
15+
return Ok(None);
16+
};
17+
18+
if event.sender != event.issue.user {
19+
return Ok(None);
20+
}
21+
22+
if !event.issue.assignees.contains(requested_reviewer) {
23+
return Ok(None);
24+
}
25+
26+
Ok(Some(ReviewRequestedInput {}))
27+
}
28+
29+
pub(crate) async fn handle_input(
30+
ctx: &Context,
31+
config: &ReviewRequestedConfig,
32+
event: &IssuesEvent,
33+
ReviewRequestedInput {}: ReviewRequestedInput,
34+
) -> anyhow::Result<()> {
35+
event
36+
.issue
37+
.add_labels(
38+
&ctx.github,
39+
config
40+
.add_labels
41+
.iter()
42+
.cloned()
43+
.map(|name| Label { name })
44+
.collect(),
45+
)
46+
.await?;
47+
48+
for label in &config.remove_labels {
49+
event.issue.remove_label(&ctx.github, label).await?;
50+
}
51+
52+
Ok(())
53+
}

0 commit comments

Comments
 (0)