Skip to content

Commit ffcf40d

Browse files
authored
Merge pull request #1935 from Kobzol/assign-refactoring
Refactor assignment logic slightly
2 parents d697f2a + 64fcac7 commit ffcf40d

File tree

4 files changed

+50
-62
lines changed

4 files changed

+50
-62
lines changed

parser/src/command.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ fn review_commands() {
322322
let mut input = Input::new(input, vec!["bot"]);
323323
assert_eq!(
324324
input.next(),
325-
Some(Command::Assign(Ok(assign::AssignCommand::ReviewName {
325+
Some(Command::Assign(Ok(assign::AssignCommand::RequestReview {
326326
name: name.to_string()
327327
})))
328328
);

parser/src/command/assign.rs

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,14 @@ use std::fmt;
1414

1515
#[derive(PartialEq, Eq, Debug)]
1616
pub enum AssignCommand {
17-
Own,
18-
Release,
19-
User { username: String },
20-
ReviewName { name: String },
17+
/// Corresponds to `@bot claim`.
18+
Claim,
19+
/// Corresponds to `@bot release-assignment`.
20+
ReleaseAssignment,
21+
/// Corresponds to `@bot assign @user`.
22+
AssignUser { username: String },
23+
/// Corresponds to `r? [@]user`.
24+
RequestReview { name: String },
2125
}
2226

2327
#[derive(PartialEq, Eq, Debug)]
@@ -47,15 +51,15 @@ impl AssignCommand {
4751
if let Some(Token::Dot) | Some(Token::EndOfLine) = toks.peek_token()? {
4852
toks.next_token()?;
4953
*input = toks;
50-
return Ok(Some(AssignCommand::Own));
54+
return Ok(Some(AssignCommand::Claim));
5155
} else {
5256
return Err(toks.error(ParseError::ExpectedEnd));
5357
}
5458
} else if let Some(Token::Word("assign")) = toks.peek_token()? {
5559
toks.next_token()?;
5660
if let Some(Token::Word(user)) = toks.next_token()? {
5761
if user.starts_with('@') && user.len() != 1 {
58-
Ok(Some(AssignCommand::User {
62+
Ok(Some(AssignCommand::AssignUser {
5963
username: user[1..].to_owned(),
6064
}))
6165
} else {
@@ -69,7 +73,7 @@ impl AssignCommand {
6973
if let Some(Token::Dot) | Some(Token::EndOfLine) = toks.peek_token()? {
7074
toks.next_token()?;
7175
*input = toks;
72-
return Ok(Some(AssignCommand::Release));
76+
return Ok(Some(AssignCommand::ReleaseAssignment));
7377
} else {
7478
return Err(toks.error(ParseError::ExpectedEnd));
7579
}
@@ -86,7 +90,7 @@ impl AssignCommand {
8690
if name.is_empty() {
8791
return Err(input.error(ParseError::NoUser));
8892
}
89-
Ok(Some(AssignCommand::ReviewName { name }))
93+
Ok(Some(AssignCommand::RequestReview { name }))
9094
}
9195
_ => Err(input.error(ParseError::NoUser)),
9296
}
@@ -104,19 +108,19 @@ mod tests {
104108

105109
#[test]
106110
fn test_1() {
107-
assert_eq!(parse("claim."), Ok(Some(AssignCommand::Own)),);
111+
assert_eq!(parse("claim."), Ok(Some(AssignCommand::Claim)),);
108112
}
109113

110114
#[test]
111115
fn test_2() {
112-
assert_eq!(parse("claim"), Ok(Some(AssignCommand::Own)),);
116+
assert_eq!(parse("claim"), Ok(Some(AssignCommand::Claim)),);
113117
}
114118

115119
#[test]
116120
fn test_3() {
117121
assert_eq!(
118122
parse("assign @user"),
119-
Ok(Some(AssignCommand::User {
123+
Ok(Some(AssignCommand::AssignUser {
120124
username: "user".to_owned()
121125
})),
122126
);
@@ -154,7 +158,7 @@ mod tests {
154158
] {
155159
assert_eq!(
156160
parse_review(input),
157-
Ok(Some(AssignCommand::ReviewName {
161+
Ok(Some(AssignCommand::RequestReview {
158162
name: name.to_string()
159163
})),
160164
"failed on {input}"

src/handlers.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ macro_rules! command_handlers {
308308
// case, just ignore it.
309309
if commands
310310
.iter()
311-
.all(|cmd| matches!(cmd, Command::Assign(Ok(AssignCommand::ReviewName { .. }))))
311+
.all(|cmd| matches!(cmd, Command::Assign(Ok(AssignCommand::RequestReview { .. }))))
312312
{
313313
return;
314314
}

src/handlers/assign.rs

Lines changed: 32 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,13 @@ Use `r?` to explicitly pick a reviewer";
7070
const RETURNING_USER_WELCOME_MESSAGE_NO_REVIEWER: &str =
7171
"@{author}: no appropriate reviewer found, use `r?` to override";
7272

73-
const ON_VACATION_WARNING: &str = "{username} is on vacation.
73+
fn on_vacation_warning(username: &str) -> String {
74+
format!(
75+
r"{username} is on vacation.
7476
75-
Please choose another assignee.";
77+
Please choose another assignee."
78+
)
79+
}
7680

7781
pub const SELF_ASSIGN_HAS_NO_CAPACITY: &str = "
7882
You have insufficient capacity to be assigned the pull request at this time. PR assignment has been reverted.
@@ -215,7 +219,7 @@ pub(super) async fn handle_input(
215219
fn find_assign_command(ctx: &Context, event: &IssuesEvent) -> Option<String> {
216220
let mut input = Input::new(&event.issue.body, vec![&ctx.username]);
217221
input.find_map(|command| match command {
218-
Command::Assign(Ok(AssignCommand::ReviewName { name })) => Some(name),
222+
Command::Assign(Ok(AssignCommand::RequestReview { name })) => Some(name),
219223
_ => None,
220224
})
221225
}
@@ -458,68 +462,49 @@ pub(super) async fn handle_command(
458462
.await?;
459463
return Ok(());
460464
}
461-
let username = match cmd {
462-
AssignCommand::Own => event.user().login.clone(),
463-
AssignCommand::User { username } => {
465+
if matches!(
466+
event,
467+
Event::Issue(IssuesEvent {
468+
action: IssuesAction::Opened,
469+
..
470+
})
471+
) {
472+
// Don't handle review request comments on new PRs. Those will be
473+
// handled by the new PR trigger (which also handles the
474+
// welcome message).
475+
return Ok(());
476+
}
477+
478+
let requested_name = match cmd {
479+
AssignCommand::Claim => event.user().login.clone(),
480+
AssignCommand::AssignUser { username } => {
464481
// Allow users on vacation to assign themselves to a PR, but not anyone else.
465482
if config.is_on_vacation(&username)
466483
&& event.user().login.to_lowercase() != username.to_lowercase()
467484
{
468485
// This is a comment, so there must already be a reviewer assigned. No need to assign anyone else.
469486
issue
470-
.post_comment(
471-
&ctx.github,
472-
&ON_VACATION_WARNING.replace("{username}", &username),
473-
)
487+
.post_comment(&ctx.github, &on_vacation_warning(&username))
474488
.await?;
475489
return Ok(());
476490
}
477491
username
478492
}
479-
AssignCommand::Release => {
493+
AssignCommand::ReleaseAssignment => {
480494
log::trace!(
481495
"ignoring release on PR {:?}, must always have assignee",
482496
issue.global_id()
483497
);
484498
return Ok(());
485499
}
486-
AssignCommand::ReviewName { name } => {
500+
AssignCommand::RequestReview { name } => {
487501
if config.owners.is_empty() {
488502
// To avoid conflicts with the highfive bot while transitioning,
489503
// r? is ignored if `owners` is not configured in triagebot.toml.
490504
return Ok(());
491505
}
492-
if matches!(
493-
event,
494-
Event::Issue(IssuesEvent {
495-
action: IssuesAction::Opened,
496-
..
497-
})
498-
) {
499-
// Don't handle r? comments on new PRs. Those will be
500-
// handled by the new PR trigger (which also handles the
501-
// welcome message).
502-
return Ok(());
503-
}
504506
let db_client = ctx.db.get().await;
505507
if is_self_assign(&name, &event.user().login) {
506-
// let work_queue = has_user_capacity(&db_client, &name).await;
507-
// if work_queue.is_err() {
508-
// // NOTE: disabled for now, just log
509-
// log::warn!(
510-
// "[#{}] PR self-assign failed, DB reported that user {} has no review capacity. Ignoring.",
511-
// issue.number,
512-
// name
513-
// );
514-
// // issue
515-
// // .post_comment(
516-
// // &ctx.github,
517-
// // &REVIEWER_HAS_NO_CAPACITY.replace("{username}", &name),
518-
// // )
519-
// // .await?;
520-
// // return Ok(());
521-
// }
522-
523508
name.to_string()
524509
} else {
525510
let teams = crate::team_data::teams(&ctx.github).await?;
@@ -560,7 +545,7 @@ pub(super) async fn handle_command(
560545
};
561546

562547
// This user is validated and can accept the PR
563-
set_assignee(issue, &ctx.github, &username).await;
548+
set_assignee(issue, &ctx.github, &requested_name).await;
564549
// This PR will now be registered in the reviewer's work queue
565550
// by the `pr_tracking` handler
566551
return Ok(());
@@ -569,14 +554,14 @@ pub(super) async fn handle_command(
569554
let e = EditIssueBody::new(&issue, "ASSIGN");
570555

571556
let to_assign = match cmd {
572-
AssignCommand::Own => event.user().login.clone(),
573-
AssignCommand::User { username } => {
557+
AssignCommand::Claim => event.user().login.clone(),
558+
AssignCommand::AssignUser { username } => {
574559
if !is_team_member && username != event.user().login {
575560
bail!("Only Rust team members can assign other users");
576561
}
577562
username.clone()
578563
}
579-
AssignCommand::Release => {
564+
AssignCommand::ReleaseAssignment => {
580565
if let Some(AssignData {
581566
user: Some(current),
582567
}) = e.current_data()
@@ -603,7 +588,7 @@ pub(super) async fn handle_command(
603588
}
604589
};
605590
}
606-
AssignCommand::ReviewName { .. } => bail!("r? is only allowed on PRs."),
591+
AssignCommand::RequestReview { .. } => bail!("r? is only allowed on PRs."),
607592
};
608593
// Don't re-assign if aleady assigned, e.g. on comment edit
609594
if issue.contain_assignee(&to_assign) {
@@ -620,7 +605,6 @@ pub(super) async fn handle_command(
620605

621606
e.apply(&ctx.github, String::new(), &data).await?;
622607

623-
// Assign the PR: user's work queue has been checked and can accept this PR
624608
match issue.set_assignee(&ctx.github, &to_assign).await {
625609
Ok(()) => return Ok(()), // we are done
626610
Err(github::AssignmentError::InvalidAssignee) => {
@@ -718,7 +702,7 @@ impl fmt::Display for FindReviewerError {
718702
write!(f, "{}", NO_REVIEWER_HAS_CAPACITY)
719703
}
720704
FindReviewerError::ReviewerOnVacation { username } => {
721-
write!(f, "{}", ON_VACATION_WARNING.replace("{username}", username))
705+
write!(f, "{}", on_vacation_warning(username))
722706
}
723707
FindReviewerError::ReviewerIsPrAuthor { username } => {
724708
write!(

0 commit comments

Comments
 (0)