Skip to content

Commit 7284769

Browse files
committed
Handle r? as assignment
This adds parsing support for handling r? to direct assignment; anyone can do so on a PR to any org member. A future commit will add support for r? with a team. This does not currently auto-assign reviewers like highfive to new PRs, though.
1 parent 2f42fdf commit 7284769

File tree

1 file changed

+108
-46
lines changed

1 file changed

+108
-46
lines changed

parser/src/command.rs

Lines changed: 108 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ pub mod relabel;
1111
pub mod second;
1212

1313
pub fn find_command_start(input: &str, bot: &str) -> Option<usize> {
14-
input.find(&format!("@{}", bot))
14+
[&format!("@{}", bot), "r?", "R?"]
15+
.iter()
16+
.map(|s| input.find(s))
17+
.min_by_key(|i| i.unwrap_or(usize::MAX))?
1518
}
1619

1720
#[derive(Debug, PartialEq)]
@@ -65,51 +68,87 @@ impl<'a> Input<'a> {
6568

6669
fn parse_command(&mut self) -> Option<Command<'a>> {
6770
let mut tok = Tokenizer::new(&self.all[self.parsed..]);
68-
assert_eq!(
69-
tok.next_token().unwrap(),
70-
Some(Token::Word(&format!("@{}", self.bot)))
71-
);
72-
log::info!("identified potential command");
73-
71+
let review = match tok.next_token() {
72+
Ok(Some(Token::Word(w))) if w == &format!("@{}", self.bot) => false,
73+
Ok(Some(Token::Word(w))) if w == "r" || w == "R" => true,
74+
other => {
75+
log::trace!("received odd review start token: {:?}", other);
76+
return None;
77+
}
78+
};
79+
7480
let mut success = vec![];
75-
76-
let original_tokenizer = tok.clone();
77-
78-
success.extend(parse_single_command(
79-
relabel::RelabelCommand::parse,
80-
Command::Relabel,
81-
&original_tokenizer,
82-
));
83-
success.extend(parse_single_command(
84-
assign::AssignCommand::parse,
85-
Command::Assign,
86-
&original_tokenizer,
87-
));
88-
success.extend(parse_single_command(
89-
ping::PingCommand::parse,
90-
Command::Ping,
91-
&original_tokenizer,
92-
));
93-
success.extend(parse_single_command(
94-
nominate::NominateCommand::parse,
95-
Command::Nominate,
96-
&original_tokenizer,
97-
));
98-
success.extend(parse_single_command(
99-
prioritize::PrioritizeCommand::parse,
100-
Command::Prioritize,
101-
&original_tokenizer,
102-
));
103-
success.extend(parse_single_command(
104-
second::SecondCommand::parse,
105-
Command::Second,
106-
&original_tokenizer,
107-
));
108-
success.extend(parse_single_command(
109-
glacier::GlacierCommand::parse,
110-
Command::Glacier,
111-
&original_tokenizer,
112-
));
81+
82+
if review {
83+
match tok.next_token() {
84+
Ok(Some(Token::Question)) => {}
85+
other => {
86+
log::trace!("received odd review start token: {:?}", other);
87+
return None;
88+
}
89+
}
90+
log::info!("identified potential review request");
91+
match tok.next_token() {
92+
Ok(Some(Token::Word(w))) => {
93+
let mentions = crate::mentions::get_mentions(w);
94+
if let [a] = &mentions[..] {
95+
success.push((
96+
tok,
97+
Command::Assign(Ok(assign::AssignCommand::User {
98+
username: (*a).to_owned(),
99+
})),
100+
));
101+
} else {
102+
log::trace!("{:?} had non-one mention: {:?}", w, mentions);
103+
return None
104+
}
105+
}
106+
other => {
107+
log::trace!("received odd review start token: {:?}", other);
108+
return None
109+
}
110+
}
111+
} else {
112+
log::info!("identified potential command");
113+
114+
let original_tokenizer = tok.clone();
115+
116+
success.extend(parse_single_command(
117+
relabel::RelabelCommand::parse,
118+
Command::Relabel,
119+
&original_tokenizer,
120+
));
121+
success.extend(parse_single_command(
122+
assign::AssignCommand::parse,
123+
Command::Assign,
124+
&original_tokenizer,
125+
));
126+
success.extend(parse_single_command(
127+
ping::PingCommand::parse,
128+
Command::Ping,
129+
&original_tokenizer,
130+
));
131+
success.extend(parse_single_command(
132+
nominate::NominateCommand::parse,
133+
Command::Nominate,
134+
&original_tokenizer,
135+
));
136+
success.extend(parse_single_command(
137+
prioritize::PrioritizeCommand::parse,
138+
Command::Prioritize,
139+
&original_tokenizer,
140+
));
141+
success.extend(parse_single_command(
142+
second::SecondCommand::parse,
143+
Command::Second,
144+
&original_tokenizer,
145+
));
146+
success.extend(parse_single_command(
147+
glacier::GlacierCommand::parse,
148+
Command::Glacier,
149+
&original_tokenizer,
150+
));
151+
}
113152

114153
if success.len() > 1 {
115154
panic!(
@@ -119,6 +158,8 @@ impl<'a> Input<'a> {
119158
);
120159
}
121160

161+
let (mut tok, c) = success.pop()?;
162+
122163
if self
123164
.code
124165
.overlaps_code((self.parsed)..(self.parsed + tok.position()))
@@ -128,7 +169,6 @@ impl<'a> Input<'a> {
128169
return None;
129170
}
130171

131-
let (mut tok, c) = success.pop()?;
132172
// if we errored out while parsing the command do not move the input forwards
133173
self.parsed += if c.is_ok() {
134174
tok.position()
@@ -230,3 +270,25 @@ fn move_input_along_1() {
230270
// don't move input along if parsing the command fails
231271
assert_eq!(&input.all[..input.parsed], "@bot");
232272
}
273+
274+
#[test]
275+
fn parse_assign_review() {
276+
let input = "R? @user";
277+
let mut input = Input::new(input, "bot");
278+
match input.next().unwrap() {
279+
Command::Assign(Ok(x)) => assert_eq!(
280+
x,
281+
assign::AssignCommand::User {
282+
username: String::from("user"),
283+
}
284+
),
285+
o => panic!("unknown: {:?}", o),
286+
};
287+
}
288+
289+
#[test]
290+
fn parse_assign_review_no_panic() {
291+
let input = "R ?";
292+
let mut input = Input::new(input, "bot");
293+
assert!(input.next().is_none());
294+
}

0 commit comments

Comments
 (0)