Skip to content

Commit 5de0a71

Browse files
committed
feat: add delegation commands
1 parent 3b95f4d commit 5de0a71

15 files changed

+564
-22
lines changed

.sqlx/query-491dd6278535e1015a8071f416a56112a153713a71af8d62917e2ff9873ecec1.json renamed to .sqlx/query-1afc103866242e2b1944b340e1db0206788b37a5cd9df052ce6d4cc636548254.json

Lines changed: 9 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.sqlx/query-67511f5f15c07537d3d4f2d011abedd2173ab301e8a06c740b587738b140795a.json renamed to .sqlx/query-24cf4ecf74e363fbd4e3f9d4b5baaa664ec0a267d2a0258417b340979e3e3200.json

Lines changed: 9 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.sqlx/query-255692270d8542f08c1741401256f7e326f055bc3598b444a9300d61df45fde0.json

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.sqlx/query-51b05195690ba3b4af66c8bf33d335b1d0edead1a3da21617f8def3d42a010a8.json

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/commands.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,7 @@ which is by default set to `@bors`.
88
| `try` | `try` | Start a try build based on the most recent commit from the main branch. |
99
| `try parent=<sha>` | `try` | Start a try build based on the specified parent commit `sha`. |
1010
| `try cancel` | `try` | Cancel a running try build. |
11-
| `p=<priority>` | `try` | Set the priority of a PR. |
11+
| `p=<priority>` | `review` | Set the priority of a PR. |
12+
| `delegate=<user>` | `review` | Delegate approval authority to a specific user. |
13+
| `delegate+` | `review` | Delegate approval authority to the PR author. |
14+
| `delegate-` | `review` | Remove any previously granted delegation. |
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- Add down migration script here
2+
ALTER TABLE pull_request DROP COLUMN delegated_to;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- Add up migration script here
2+
ALTER TABLE pull_request ADD COLUMN delegated_to TEXT NULL;

src/bors/command/mod.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,17 @@ pub enum Parent {
1616

1717
#[derive(Clone, Debug, PartialEq)]
1818
pub enum Approver {
19-
/// The approver is the same as the comment author.
19+
/// The approver is the same as the comment author: delegate+.
2020
Myself,
21-
/// The approver is specified by the user.
21+
/// The approver is specified by the user: delegate=<username>.
22+
Specified(String),
23+
}
24+
25+
#[derive(Clone, Debug, PartialEq)]
26+
pub enum Delegatee {
27+
/// The assignee is the same as the PR author.
28+
Author,
29+
/// The assignee is specified by the user.
2230
Specified(String),
2331
}
2432

@@ -49,4 +57,8 @@ pub enum BorsCommand {
4957
TryCancel,
5058
/// Set the priority of a commit.
5159
SetPriority(Priority),
60+
/// Delegate approval authority.
61+
Delegate(Delegatee),
62+
/// Revoke any previously granted delegation.
63+
Undelegate,
5264
}

src/bors/command/parser.rs

Lines changed: 105 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::collections::HashSet;
55
use crate::bors::command::{Approver, BorsCommand, Parent};
66
use crate::github::CommitSha;
77

8-
use super::Priority;
8+
use super::{Delegatee, Priority};
99

1010
const PRIORITY_NAMES: [&str; 2] = ["p", "priority"];
1111

@@ -51,6 +51,8 @@ impl CommandParser {
5151
parser_ping,
5252
parser_try_cancel,
5353
parser_try,
54+
parse_delegate_author,
55+
parse_undelegate,
5456
];
5557

5658
text.lines()
@@ -86,6 +88,12 @@ impl CommandParser {
8688
}
8789
}
8890

91+
if key == "delegate" {
92+
if let Some(result) = parse_delegate_to(&parts) {
93+
return Some(result);
94+
}
95+
}
96+
8997
Some(Err(CommandParseError::MissingCommand))
9098
}
9199
}
@@ -152,6 +160,7 @@ fn parse_approve_on_behalf<'a>(parts: &[CommandPart<'a>]) -> ParseResult<'a> {
152160
if value.is_empty() {
153161
return Some(Err(CommandParseError::MissingArgValue { arg: "r" }));
154162
}
163+
155164
match parse_priority_arg(&parts[1..]) {
156165
Ok(priority) => Some(Ok(BorsCommand::Approve {
157166
approver: Approver::Specified(value.to_string()),
@@ -270,6 +279,39 @@ fn parser_try_cancel<'a>(command: &'a str, parts: &[CommandPart<'a>]) -> ParseRe
270279
}
271280
}
272281

282+
/// Parses "@bors delegate+"
283+
fn parse_delegate_author<'a>(command: &'a str, _parts: &[CommandPart<'a>]) -> ParseResult<'a> {
284+
if command == "delegate+" {
285+
Some(Ok(BorsCommand::Delegate(Delegatee::Author)))
286+
} else {
287+
None
288+
}
289+
}
290+
291+
/// Parses "@bors delegate=<username>"
292+
fn parse_delegate_to<'a>(parts: &[CommandPart<'a>]) -> ParseResult<'a> {
293+
if let Some(CommandPart::KeyValue { value, .. }) = parts.first() {
294+
if value.is_empty() {
295+
return Some(Err(CommandParseError::MissingArgValue { arg: "delegate" }));
296+
}
297+
298+
Some(Ok(BorsCommand::Delegate(Delegatee::Specified(
299+
value.to_string(),
300+
))))
301+
} else {
302+
Some(Err(CommandParseError::MissingArgValue { arg: "delegate" }))
303+
}
304+
}
305+
306+
/// Parses "@bors delegate-"
307+
fn parse_undelegate<'a>(command: &'a str, _parts: &[CommandPart<'a>]) -> ParseResult<'a> {
308+
if command == "delegate-" {
309+
Some(Ok(BorsCommand::Undelegate))
310+
} else {
311+
None
312+
}
313+
}
314+
273315
/// Parses "@bors p=<priority>"
274316
fn parse_priority<'a>(parts: &[CommandPart<'a>]) -> ParseResult<'a> {
275317
// If we have more than one part, check for duplicate priority arguments
@@ -324,7 +366,7 @@ fn parse_priority_arg<'a>(parts: &[CommandPart<'a>]) -> Result<Option<u32>, Comm
324366
#[cfg(test)]
325367
mod tests {
326368
use crate::bors::command::parser::{CommandParseError, CommandParser};
327-
use crate::bors::command::{Approver, BorsCommand, Parent};
369+
use crate::bors::command::{Approver, BorsCommand, Delegatee, Parent};
328370
use crate::github::CommitSha;
329371

330372
#[test]
@@ -821,6 +863,67 @@ line two
821863
assert!(matches!(cmds[0], Ok(BorsCommand::TryCancel)));
822864
}
823865

866+
#[test]
867+
fn parse_delegate_author() {
868+
let cmds = parse_commands("@bors delegate+");
869+
assert_eq!(cmds.len(), 1);
870+
assert!(matches!(
871+
cmds[0],
872+
Ok(BorsCommand::Delegate(Delegatee::Author))
873+
));
874+
}
875+
876+
#[test]
877+
fn parse_delegate_to_user() {
878+
let cmds = parse_commands("@bors delegate=user1");
879+
assert_eq!(cmds.len(), 1);
880+
assert_eq!(
881+
cmds[0],
882+
Ok(BorsCommand::Delegate(Delegatee::Specified(
883+
"user1".to_string()
884+
)))
885+
);
886+
}
887+
888+
#[test]
889+
fn parse_delegate_empty() {
890+
let cmds = parse_commands("@bors delegate=");
891+
assert_eq!(cmds.len(), 1);
892+
insta::assert_debug_snapshot!(cmds[0], @r###"
893+
Err(
894+
MissingArgValue {
895+
arg: "delegate",
896+
},
897+
)
898+
"###);
899+
}
900+
901+
#[test]
902+
fn parse_undelegate() {
903+
let cmds = parse_commands("@bors delegate-");
904+
assert_eq!(cmds.len(), 1);
905+
assert_eq!(cmds[0], Ok(BorsCommand::Undelegate));
906+
}
907+
908+
#[test]
909+
fn parse_delegate_author_unknown_arg() {
910+
let cmds = parse_commands("@bors delegate+ a");
911+
assert_eq!(cmds.len(), 1);
912+
assert_eq!(cmds[0], Ok(BorsCommand::Delegate(Delegatee::Author)));
913+
}
914+
915+
#[test]
916+
fn parse_delegate_user_unknown_arg() {
917+
let cmds = parse_commands("@bors delegate=user1 a");
918+
assert_eq!(cmds.len(), 1);
919+
assert_eq!(
920+
cmds[0],
921+
Ok(BorsCommand::Delegate(Delegatee::Specified(
922+
"user1".to_string()
923+
)))
924+
);
925+
}
926+
824927
fn parse_commands(text: &str) -> Vec<Result<BorsCommand, CommandParseError>> {
825928
CommandParser::new("@bors".to_string()).parse_commands(text)
826929
}

src/bors/handlers/help.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::bors::command::{Approver, BorsCommand};
1+
use crate::bors::command::{Approver, BorsCommand, Delegatee};
22
use crate::bors::Comment;
33
use crate::bors::RepositoryState;
44
use crate::github::PullRequest;
@@ -19,6 +19,9 @@ pub(super) async fn command_help(
1919
},
2020
BorsCommand::Unapprove,
2121
BorsCommand::SetPriority(0),
22+
BorsCommand::Delegate(Delegatee::Specified("".to_string())),
23+
BorsCommand::Delegate(Delegatee::Author),
24+
BorsCommand::Undelegate,
2225
BorsCommand::Try {
2326
parent: None,
2427
jobs: vec![],
@@ -53,6 +56,15 @@ fn get_command_help(command: BorsCommand) -> String {
5356
BorsCommand::SetPriority(_) => {
5457
"`p=<priority>`: Set the priority of this PR"
5558
}
59+
BorsCommand::Delegate(Delegatee::Specified(_)) => {
60+
"`delegate=<username>`: Delegate approval authority to a specific user"
61+
}
62+
BorsCommand::Delegate(Delegatee::Author) => {
63+
"`delegate+`: Delegate approval authority to the PR author"
64+
}
65+
BorsCommand::Undelegate => {
66+
"`delegate-`: Remove any previously granted delegation"
67+
}
5668
BorsCommand::Help => {
5769
"`help`: Print this help message"
5870
}
@@ -82,6 +94,9 @@ mod tests {
8294
- `r=<user> [p=<priority>]`: Approve this PR on behalf of `<user>`. Optionally, you can specify a `<priority>`.
8395
- `r-`: Unapprove this PR
8496
- `p=<priority>`: Set the priority of this PR
97+
- `delegate=<username>`: Delegate approval authority to a specific user
98+
- `delegate+`: Delegate approval authority to the PR author
99+
- `delegate-`: Remove any previously granted delegation
85100
- `try [parent=<parent>] [jobs=<jobs>]`: Start a try build. Optionally, you can specify a `<parent>` SHA or a list of `<jobs>` to run
86101
- `try cancel`: Cancel a running try build
87102
- `ping`: Check if the bot is alive

0 commit comments

Comments
 (0)