diff --git a/src/bors/command/parser.rs b/src/bors/command/parser.rs index 64c88f15..5eccad9b 100644 --- a/src/bors/command/parser.rs +++ b/src/bors/command/parser.rs @@ -28,11 +28,22 @@ enum CommandPart<'a> { pub struct CommandParser { prefix: String, + parsers: Vec, } impl CommandParser { pub fn new(prefix: String) -> Self { - Self { prefix } + Self { + prefix, + parsers: DEFAULT_PARSERS.to_vec(), + } + } + + pub fn new_try_only(prefix: String) -> Self { + Self { + prefix, + parsers: ONLY_TRY_PARSERS.to_vec(), + } } /// Prefix of the bot, used to invoke commands from PR comments. @@ -52,7 +63,7 @@ impl CommandParser { .filter_map(|line| match line.find(&self.prefix) { Some(index) => { let input = &line[index + self.prefix.len()..]; - parse_command(input) + parse_command(input, &self.parsers) } None => None, }) @@ -116,9 +127,10 @@ fn extract_text_from_markdown(text: &str) -> String { } type ParseResult = Option>; +type ParserFn = fn(&CommandPart<'_>, &[CommandPart<'_>]) -> ParseResult; // The order of the parsers in the vector is important -const PARSERS: &[fn(&CommandPart<'_>, &[CommandPart<'_>]) -> ParseResult] = &[ +const DEFAULT_PARSERS: &[ParserFn] = &[ parser_approval, parser_unapprove, parser_rollup, @@ -133,12 +145,14 @@ const PARSERS: &[fn(&CommandPart<'_>, &[CommandPart<'_>]) -> ParseResult] = &[ parser_tree_ops, ]; -fn parse_command(input: &str) -> ParseResult { +const ONLY_TRY_PARSERS: &[ParserFn] = &[parser_try_cancel, parser_try]; + +fn parse_command(input: &str, parsers: &[ParserFn]) -> ParseResult { match parse_parts(input) { Ok(parts) => match parts.as_slice() { [] => Some(Err(CommandParseError::MissingCommand)), [command, arguments @ ..] => { - for parser in PARSERS { + for parser in parsers { if let Some(result) = parser(command, arguments) { return Some(result); } diff --git a/src/bors/handlers/mod.rs b/src/bors/handlers/mod.rs index 9f45a643..c0d1d16c 100644 --- a/src/bors/handlers/mod.rs +++ b/src/bors/handlers/mod.rs @@ -24,7 +24,7 @@ use crate::bors::{BorsContext, Comment, RepositoryState}; use crate::database::{DelegatedPermission, PullRequestModel}; use crate::github::{GithubUser, PullRequest, PullRequestNumber}; use crate::permissions::PermissionType; -use crate::{PgDbClient, TeamApiClient, load_repositories}; +use crate::{CommandParser, PgDbClient, TeamApiClient, load_repositories}; use anyhow::Context; use octocrab::Octocrab; use pr_events::{ @@ -360,7 +360,23 @@ async fn handle_comment( use std::fmt::Write; let pr_number = comment.pr_number; - let commands = ctx.parser.parse_commands(&comment.text); + let mut commands = ctx.parser.parse_commands(&comment.text); + + // Temporary special case for migration from homu on rust-lang/rust. + // Try to parse `@bors try` commands with a hardcoded prefix normally assigned to homu. + if repo.repository().owner() == "rust-lang" && repo.repository().name() == "rust" { + let homu_commands = CommandParser::new_try_only("@bors".to_string()) + .parse_commands(&comment.text) + .into_iter() + .filter(|res| match res { + // Let homu handle unknown and missing commands + Err(CommandParseError::UnknownCommand(_) | CommandParseError::MissingCommand) => { + false + } + _ => true, + }); + commands.extend(homu_commands); + } // Bail if no commands if commands.is_empty() {