Skip to content

Commit 93d9985

Browse files
authored
Merge pull request #2022 from Urgau/concerns
Add `concern`/`resolve` commands in an rfcbot-like manner
2 parents c84ab75 + 7e3f5d3 commit 93d9985

File tree

6 files changed

+322
-0
lines changed

6 files changed

+322
-0
lines changed

parser/src/command.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use regex::Regex;
55

66
pub mod assign;
77
pub mod close;
8+
pub mod concern;
89
pub mod nominate;
910
pub mod note;
1011
pub mod ping;
@@ -25,6 +26,7 @@ pub enum Command<'a> {
2526
Shortcut(Result<shortcut::ShortcutCommand, Error<'a>>),
2627
Close(Result<close::CloseCommand, Error<'a>>),
2728
Note(Result<note::NoteCommand, Error<'a>>),
29+
Concern(Result<concern::ConcernCommand, Error<'a>>),
2830
Transfer(Result<transfer::TransferCommand, Error<'a>>),
2931
}
3032

@@ -97,6 +99,11 @@ impl<'a> Input<'a> {
9799
Command::Note,
98100
&original_tokenizer,
99101
));
102+
success.extend(parse_single_command(
103+
concern::ConcernCommand::parse,
104+
Command::Concern,
105+
&original_tokenizer,
106+
));
100107
success.extend(parse_single_command(
101108
ping::PingCommand::parse,
102109
Command::Ping,
@@ -206,6 +213,7 @@ impl<'a> Command<'a> {
206213
Command::Shortcut(r) => r.is_ok(),
207214
Command::Close(r) => r.is_ok(),
208215
Command::Note(r) => r.is_ok(),
216+
Command::Concern(r) => r.is_ok(),
209217
Command::Transfer(r) => r.is_ok(),
210218
}
211219
}
@@ -353,3 +361,27 @@ fn review_ignored() {
353361
assert_eq!(input.next(), None);
354362
}
355363
}
364+
365+
#[test]
366+
fn concern() {
367+
let input = "@bot concern this is my concern";
368+
let mut input = Input::new(input, vec!["bot"]);
369+
assert_eq!(
370+
input.next(),
371+
Some(Command::Concern(Ok(concern::ConcernCommand::Concern {
372+
title: "this is my concern".to_string()
373+
})))
374+
);
375+
}
376+
377+
#[test]
378+
fn resolve() {
379+
let input = "@bot resolve this is my concern";
380+
let mut input = Input::new(input, vec!["bot"]);
381+
assert_eq!(
382+
input.next(),
383+
Some(Command::Concern(Ok(concern::ConcernCommand::Resolve {
384+
title: "this is my concern".to_string()
385+
})))
386+
);
387+
}

parser/src/command/concern.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
use crate::error::Error;
2+
use crate::token::{Token, Tokenizer};
3+
use std::fmt;
4+
5+
#[derive(PartialEq, Eq, Debug)]
6+
pub enum ConcernCommand {
7+
Concern { title: String },
8+
Resolve { title: String },
9+
}
10+
11+
#[derive(PartialEq, Eq, Debug)]
12+
pub enum ParseError {
13+
MissingTitle,
14+
}
15+
16+
impl std::error::Error for ParseError {}
17+
impl fmt::Display for ParseError {
18+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
19+
match self {
20+
ParseError::MissingTitle => write!(f, "missing required title"),
21+
}
22+
}
23+
}
24+
25+
impl ConcernCommand {
26+
pub fn parse<'a>(input: &mut Tokenizer<'a>) -> Result<Option<Self>, Error<'a>> {
27+
let mut toks = input.clone();
28+
if let Some(Token::Word(action @ ("concern" | "resolve"))) = toks.peek_token()? {
29+
toks.next_token()?;
30+
31+
let title = toks.take_line()?.trim().to_string();
32+
33+
if title.is_empty() {
34+
return Err(toks.error(ParseError::MissingTitle));
35+
}
36+
37+
let command = if action == "resolve" {
38+
ConcernCommand::Resolve { title }
39+
} else {
40+
ConcernCommand::Concern { title }
41+
};
42+
43+
Ok(Some(command))
44+
} else {
45+
Ok(None)
46+
}
47+
}
48+
}

src/config.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ pub(crate) struct Config {
3535
pub(crate) review_requested: Option<ReviewRequestedConfig>,
3636
pub(crate) shortcut: Option<ShortcutConfig>,
3737
pub(crate) note: Option<NoteConfig>,
38+
pub(crate) concern: Option<ConcernConfig>,
3839
pub(crate) mentions: Option<MentionsConfig>,
3940
pub(crate) no_merges: Option<NoMergesConfig>,
4041
// We want this validation to run even without the entry in the config file
@@ -191,6 +192,14 @@ pub(crate) struct NoteConfig {
191192
_empty: (),
192193
}
193194

195+
#[derive(PartialEq, Eq, Debug, serde::Deserialize)]
196+
#[serde(deny_unknown_fields)]
197+
pub(crate) struct ConcernConfig {
198+
/// Set the labels on the PR when concerns are active.
199+
#[serde(default)]
200+
pub(crate) labels: Vec<String>,
201+
}
202+
194203
#[derive(PartialEq, Eq, Debug, serde::Deserialize)]
195204
pub(crate) struct MentionsConfig {
196205
#[serde(flatten)]
@@ -594,6 +603,9 @@ mod tests {
594603
595604
[note]
596605
606+
[concern]
607+
labels = ["has-concerns"]
608+
597609
[ping.compiler]
598610
message = """\
599611
So many people!\
@@ -691,6 +703,9 @@ mod tests {
691703
behind_upstream: Some(BehindUpstreamConfig {
692704
days_threshold: Some(14),
693705
}),
706+
concern: Some(ConcernConfig {
707+
labels: vec!["has-concerns".to_string()],
708+
}),
694709
}
695710
);
696711
}
@@ -742,6 +757,7 @@ mod tests {
742757
}),
743758
note: None,
744759
ping: None,
760+
concern: None,
745761
nominate: None,
746762
shortcut: None,
747763
prioritize: None,

src/github.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,7 @@ pub struct Comment {
482482
pub updated_at: chrono::DateTime<Utc>,
483483
#[serde(default, rename = "state")]
484484
pub pr_review_state: Option<PullRequestReviewState>,
485+
pub author_association: AuthorAssociation,
485486
}
486487

487488
#[derive(Debug, serde::Deserialize, serde::Serialize, Eq, PartialEq)]

src/handlers.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ mod autolabel;
2929
mod bot_pull_requests;
3030
mod check_commits;
3131
mod close;
32+
mod concern;
3233
pub mod docs_update;
3334
mod github_releases;
3435
mod issue_links;
@@ -365,6 +366,7 @@ command_handlers! {
365366
shortcut: Shortcut,
366367
close: Close,
367368
note: Note,
369+
concern: Concern,
368370
transfer: Transfer,
369371
}
370372

0 commit comments

Comments
 (0)