Skip to content

Commit f3b37a5

Browse files
authored
Merge pull request #632 from Kobzol/command-delegate
Improve delegate command error message and add `@bors delegate` alias
2 parents ede58cb + 9cd1086 commit f3b37a5

5 files changed

Lines changed: 89 additions & 13 deletions

File tree

src/bors/command/parser.rs

Lines changed: 69 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ pub enum CommandParseError {
1414
MissingCommand,
1515
UnknownCommand(String),
1616
MissingArgValue { arg: String },
17-
UnknownArg(String),
17+
UnknownArg { arg: String, did_you_mean: String },
1818
DuplicateArg(String),
1919
ValidationError(String),
2020
}
@@ -270,7 +270,10 @@ fn parser_try(command: &CommandPart<'_>, parts: &[CommandPart<'_>]) -> ParseResu
270270
for part in parts {
271271
match part {
272272
CommandPart::Bare(key) => {
273-
return Some(Err(CommandParseError::UnknownArg(key.to_string())));
273+
return Some(Err(CommandParseError::UnknownArg {
274+
arg: key.to_string(),
275+
did_you_mean: "jobs=<jobs>|parent=<parent>".to_string(),
276+
}));
274277
}
275278
CommandPart::KeyValue { key, value } => match (*key, *value) {
276279
("parent", "last") => parent = Some(Parent::Last),
@@ -299,7 +302,10 @@ fn parser_try(command: &CommandPart<'_>, parts: &[CommandPart<'_>]) -> ParseResu
299302
jobs = raw_jobs;
300303
}
301304
_ => {
302-
return Some(Err(CommandParseError::UnknownArg(key.to_string())));
305+
return Some(Err(CommandParseError::UnknownArg {
306+
arg: key.to_string(),
307+
did_you_mean: "jobs=<jobs>|parent=<parent>".to_string(),
308+
}));
303309
}
304310
},
305311
}
@@ -318,11 +324,24 @@ fn parser_try_cancel(command: &CommandPart<'_>, parts: &[CommandPart<'_>]) -> Pa
318324
}
319325

320326
/// Parses `@bors delegate=<try|review>` or `@bors delegate+`.
321-
fn parser_delegate(command: &CommandPart<'_>, _parts: &[CommandPart<'_>]) -> ParseResult {
327+
fn parser_delegate(command: &CommandPart<'_>, parts: &[CommandPart<'_>]) -> ParseResult {
322328
match command {
323329
CommandPart::Bare("delegate+") => {
324330
Some(Ok(BorsCommand::SetDelegate(DelegatedPermission::Review)))
325331
}
332+
CommandPart::Bare("delegate") => {
333+
if !parts.is_empty() {
334+
Some(Err(CommandParseError::UnknownArg {
335+
arg: match parts[0] {
336+
CommandPart::Bare(arg) => arg.to_owned(),
337+
CommandPart::KeyValue { key, .. } => key.to_owned(),
338+
},
339+
did_you_mean: "delegate=<try|review>".to_string(),
340+
}))
341+
} else {
342+
Some(Ok(BorsCommand::SetDelegate(DelegatedPermission::Review)))
343+
}
344+
}
326345
CommandPart::KeyValue {
327346
key: "delegate",
328347
value,
@@ -1163,15 +1182,31 @@ for the crater",
11631182
#[test]
11641183
fn parse_try_unknown_arg() {
11651184
let cmds = parse_commands("@bors try a");
1166-
assert_eq!(cmds.len(), 1);
1167-
assert_eq!(cmds[0], Err(CommandParseError::UnknownArg("a".to_string())));
1185+
insta::assert_debug_snapshot!(cmds, @r#"
1186+
[
1187+
Err(
1188+
UnknownArg {
1189+
arg: "a",
1190+
did_you_mean: "jobs=<jobs>|parent=<parent>",
1191+
},
1192+
),
1193+
]
1194+
"#);
11681195
}
11691196

11701197
#[test]
11711198
fn parse_try_unknown_kv_arg() {
11721199
let cmds = parse_commands("@bors try a=b");
1173-
assert_eq!(cmds.len(), 1);
1174-
assert_eq!(cmds[0], Err(CommandParseError::UnknownArg("a".to_string())));
1200+
insta::assert_debug_snapshot!(cmds, @r#"
1201+
[
1202+
Err(
1203+
UnknownArg {
1204+
arg: "a",
1205+
did_you_mean: "jobs=<jobs>|parent=<parent>",
1206+
},
1207+
),
1208+
]
1209+
"#);
11751210
}
11761211

11771212
#[test]
@@ -1228,7 +1263,7 @@ for the crater",
12281263
}
12291264

12301265
#[test]
1231-
fn parse_delegate_author() {
1266+
fn parse_delegate_plus_author() {
12321267
let cmds = parse_commands("@bors delegate+");
12331268
assert_eq!(cmds.len(), 1);
12341269
assert!(matches!(
@@ -1237,6 +1272,31 @@ for the crater",
12371272
));
12381273
}
12391274

1275+
#[test]
1276+
fn parse_delegate_author() {
1277+
let cmds = parse_commands("@bors delegate");
1278+
assert_eq!(cmds.len(), 1);
1279+
assert!(matches!(
1280+
cmds[0],
1281+
Ok(BorsCommand::SetDelegate(DelegatedPermission::Review))
1282+
));
1283+
}
1284+
1285+
#[test]
1286+
fn parse_delegate_unknown_arg() {
1287+
let cmds = parse_commands("@bors delegate try");
1288+
insta::assert_debug_snapshot!(cmds, @r#"
1289+
[
1290+
Err(
1291+
UnknownArg {
1292+
arg: "try",
1293+
did_you_mean: "delegate=<try|review>",
1294+
},
1295+
),
1296+
]
1297+
"#);
1298+
}
1299+
12401300
#[test]
12411301
fn parse_delegate_review_author() {
12421302
let cmds = parse_commands("@bors delegate=review");

src/bors/handlers/help.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ mod tests {
4343
- `delegate=<try|review>`: Delegate permissions for running try builds or approving to the PR author
4444
- `try` allows the PR author to start try builds.
4545
- `review` allows the PR author to both start try builds and approve the PR.
46-
- `delegate+`: Delegate approval permissions to the PR author
46+
- `delegate` | `delegate+`: Delegate approval permissions to the PR author
4747
- Shortcut for `delegate=review`
4848
- `delegate-`: Remove any previously granted permission delegation
4949
- `try [parent=<parent>] [job|jobs=<jobs>]`: Start a try build.

src/bors/handlers/mod.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -549,8 +549,11 @@ async fn handle_comment(
549549
CommandParseError::MissingArgValue { arg } => {
550550
format!(r#"Unknown value for argument "{arg}"."#)
551551
}
552-
CommandParseError::UnknownArg(arg) => {
553-
format!(r#"Unknown argument "{arg}"."#)
552+
CommandParseError::UnknownArg { arg, did_you_mean } => {
553+
format!(
554+
r#"Unknown argument "{arg}". Did you mean to use `{} {did_you_mean}`?"#,
555+
ctx.parser.prefix()
556+
)
554557
}
555558
CommandParseError::DuplicateArg(arg) => {
556559
format!(r#"Argument "{arg}" found multiple times."#)

src/bors/handlers/review.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -882,6 +882,19 @@ approved = { modifications = ["+foo", "+baz"], unless = ["label1", "label2"] }
882882
.await;
883883
}
884884

885+
#[sqlx::test]
886+
async fn delegate_error_message(pool: sqlx::PgPool) {
887+
BorsBuilder::new(pool)
888+
.github(GitHub::unauthorized_pr_author())
889+
.run_test(async |ctx: &mut BorsTester| {
890+
ctx.post_comment(review_comment("@bors delegate try"))
891+
.await?;
892+
insta::assert_snapshot!(ctx.get_next_comment_text(()).await?, @r#"Unknown argument "try". Did you mean to use `@bors delegate=<try|review>`? Run `@bors help` to see available commands."#);
893+
Ok(())
894+
})
895+
.await;
896+
}
897+
885898
#[sqlx::test]
886899
async fn delegatee_can_try(pool: sqlx::PgPool) {
887900
let gh = BorsBuilder::new(pool)

src/bors/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ You can use the following commands:
9797
- `delegate=<try|review>`: Delegate permissions for running try builds or approving to the PR author
9898
- `try` allows the PR author to start try builds.
9999
- `review` allows the PR author to both start try builds and approve the PR.
100-
- `delegate+`: Delegate approval permissions to the PR author
100+
- `delegate` | `delegate+`: Delegate approval permissions to the PR author
101101
- Shortcut for `delegate=review`
102102
- `delegate-`: Remove any previously granted permission delegation
103103
- `try [parent=<parent>] [job|jobs=<jobs>]`: Start a try build.

0 commit comments

Comments
 (0)