Skip to content

Commit 66ce675

Browse files
committed
Rearrange handlers macro impl and usage
1 parent adc93ef commit 66ce675

File tree

2 files changed

+247
-244
lines changed

2 files changed

+247
-244
lines changed

src/handlers.rs

Lines changed: 37 additions & 244 deletions
Original file line numberDiff line numberDiff line change
@@ -15,37 +15,9 @@ macro_rules! inform {
1515
anyhow::bail!(crate::handlers::UserError($err.into()))
1616
};
1717
}
18-
macro_rules! custom_handlers {
19-
($errors:ident -> $($name:ident: $hd:expr,)*) => {{
20-
// Process the handlers concurrently
21-
let results = futures::join!(
22-
$(
23-
async {
24-
async {
25-
$hd
26-
}
27-
.await
28-
.map_err(|e: anyhow::Error| {
29-
HandlerError::Other(e.context(format!(
30-
"error when processing {} handler",
31-
stringify!($name)
32-
)))
33-
})
34-
}
35-
),*
36-
);
3718

38-
// Destructure the results into named variables
39-
let ($($name,)*) = results;
40-
41-
// Push errors for each handler
42-
$(
43-
if let Err(e) = $name {
44-
$errors.push(e);
45-
}
46-
)*
47-
}}
48-
}
19+
#[macro_use]
20+
mod macros;
4921

5022
mod assign;
5123
mod autolabel;
@@ -94,6 +66,41 @@ pub struct Context {
9466
pub gha_logs: Arc<tokio::sync::RwLock<GitHubActionLogsCache>>,
9567
}
9668

69+
// Handle events that happened on issues
70+
//
71+
// This is for events that happen only on issues or pull requests (e.g. label changes or assignments).
72+
// Each module in the list must contain the functions `parse_input` and `handle_input`.
73+
issue_handlers! {
74+
assign,
75+
autolabel,
76+
backport,
77+
issue_links,
78+
major_change,
79+
mentions,
80+
notify_zulip,
81+
review_requested,
82+
pr_tracking,
83+
}
84+
85+
// Handle commands in comments/issues body
86+
//
87+
// This is for handlers for commands parsed by the `parser` crate.
88+
// Each variant of `parser::command::Command` must be in this list,
89+
// preceded by the module containing the corresponding `handle_command` function
90+
command_handlers! {
91+
assign: Assign,
92+
nominate: Nominate,
93+
ping: Ping,
94+
prioritize: Prioritize,
95+
relabel: Relabel,
96+
major_change: Second,
97+
shortcut: Shortcut,
98+
close: Close,
99+
note: Note,
100+
concern: Concern,
101+
transfer: Transfer,
102+
}
103+
97104
pub async fn handle(ctx: &Context, host: &str, event: &Event) -> Vec<HandlerError> {
98105
let config = config::get(&ctx.github, event.repo()).await;
99106
if let Err(e) = &config {
@@ -164,220 +171,6 @@ pub async fn handle(ctx: &Context, host: &str, event: &Event) -> Vec<HandlerErro
164171
errors
165172
}
166173

167-
macro_rules! issue_handlers {
168-
($($name:ident,)*) => {
169-
async fn handle_issue(
170-
ctx: &Context,
171-
event: &IssuesEvent,
172-
config: &Arc<Config>,
173-
errors: &mut Vec<HandlerError>,
174-
) {
175-
// Process the issue handlers concurrently
176-
let results = futures::join!(
177-
$(
178-
async {
179-
match $name::parse_input(ctx, event, config.$name.as_ref()).await {
180-
Err(err) => Err(HandlerError::Message(err)),
181-
Ok(Some(input)) => {
182-
if let Some(config) = &config.$name {
183-
$name::handle_input(ctx, config, event, input)
184-
.await
185-
.map_err(|e| {
186-
HandlerError::Other(e.context(format!(
187-
"error when processing {} handler",
188-
stringify!($name)
189-
)))
190-
})
191-
} else {
192-
Err(HandlerError::Message(format!(
193-
"The feature `{}` is not enabled in this repository.\n\
194-
To enable it add its section in the `triagebot.toml` \
195-
in the root of the repository.",
196-
stringify!($name)
197-
)))
198-
}
199-
}
200-
Ok(None) => Ok(())
201-
}
202-
}
203-
),*
204-
);
205-
206-
// Destructure the results into named variables
207-
let ($($name,)*) = results;
208-
209-
// Push errors for each handler
210-
$(
211-
if let Err(e) = $name {
212-
errors.push(e);
213-
}
214-
)*
215-
}
216-
}
217-
}
218-
219-
// Handle events that happened on issues
220-
//
221-
// This is for events that happen only on issues or pull requests (e.g. label changes or assignments).
222-
// Each module in the list must contain the functions `parse_input` and `handle_input`.
223-
issue_handlers! {
224-
assign,
225-
autolabel,
226-
backport,
227-
issue_links,
228-
major_change,
229-
mentions,
230-
notify_zulip,
231-
review_requested,
232-
pr_tracking,
233-
}
234-
235-
macro_rules! command_handlers {
236-
($($name:ident: $enum:ident,)*) => {
237-
async fn handle_command(
238-
ctx: &Context,
239-
event: &Event,
240-
config: &Result<Arc<Config>, ConfigurationError>,
241-
body: &str,
242-
errors: &mut Vec<HandlerError>,
243-
) {
244-
match event {
245-
// always handle new PRs / issues
246-
Event::Issue(IssuesEvent { action: IssuesAction::Opened, .. }) => {},
247-
Event::Issue(IssuesEvent { action: IssuesAction::Edited, .. }) => {
248-
// if the issue was edited, but we don't get a `changes[body]` diff, it means only the title was edited, not the body.
249-
// don't process the same commands twice.
250-
if event.comment_from().is_none() {
251-
log::debug!("skipping title-only edit event");
252-
return;
253-
}
254-
},
255-
Event::Issue(e) => {
256-
// no change in issue's body for these events, so skip
257-
log::debug!("skipping event, issue was {:?}", e.action);
258-
return;
259-
}
260-
Event::IssueComment(e) => {
261-
match e.action {
262-
IssueCommentAction::Created => {}
263-
IssueCommentAction::Edited => {
264-
if event.comment_from().is_none() {
265-
// We are not entirely sure why this happens.
266-
// Sometimes when someone posts a PR review,
267-
// GitHub sends an "edited" event with no
268-
// changes just before the "created" event.
269-
log::debug!("skipping issue comment edit without changes");
270-
return;
271-
}
272-
}
273-
IssueCommentAction::Deleted => {
274-
// don't execute commands again when comment is deleted
275-
log::debug!("skipping event, comment was {:?}", e.action);
276-
return;
277-
}
278-
}
279-
}
280-
Event::Push(_) | Event::Create(_) => {
281-
log::debug!("skipping unsupported event");
282-
return;
283-
}
284-
}
285-
286-
let input = Input::new(&body, vec![&ctx.username, "triagebot"]);
287-
let commands = if let Some(previous) = event.comment_from() {
288-
let prev_commands = Input::new(&previous, vec![&ctx.username, "triagebot"]).collect::<Vec<_>>();
289-
input.filter(|cmd| !prev_commands.contains(cmd)).collect::<Vec<_>>()
290-
} else {
291-
input.collect()
292-
};
293-
294-
log::info!("Comment parsed to {:?}", commands);
295-
296-
if commands.is_empty() {
297-
return;
298-
}
299-
300-
let config = match config {
301-
Ok(config) => config,
302-
Err(e @ ConfigurationError::Missing) => {
303-
// r? is conventionally used to mean "hey, can you review"
304-
// even if the repo doesn't have a triagebot.toml. In that
305-
// case, just ignore it.
306-
if commands
307-
.iter()
308-
.all(|cmd| matches!(cmd, Command::Assign(Ok(AssignCommand::RequestReview { .. }))))
309-
{
310-
return;
311-
}
312-
return errors.push(HandlerError::Message(e.to_string()));
313-
}
314-
Err(e @ ConfigurationError::Toml(_)) => {
315-
return errors.push(HandlerError::Message(e.to_string()));
316-
}
317-
Err(e @ ConfigurationError::Http(_)) => {
318-
return errors.push(HandlerError::Other(e.clone().into()));
319-
}
320-
};
321-
322-
for command in commands {
323-
match command {
324-
$(
325-
Command::$enum(Ok(command)) => {
326-
if let Some(config) = &config.$name {
327-
$name::handle_command(ctx, config, event, command)
328-
.await
329-
.unwrap_or_else(|mut err| {
330-
if let Some(err) = err.downcast_mut::<UserError>() {
331-
errors.push(HandlerError::Message(std::mem::take(&mut err.0)));
332-
} else {
333-
errors.push(HandlerError::Other(err.context(format!(
334-
"error when processing {} command handler",
335-
stringify!($name)
336-
))));
337-
}
338-
});
339-
} else {
340-
errors.push(HandlerError::Message(format!(
341-
"The feature `{}` is not enabled in this repository.\n\
342-
To enable it add its section in the `triagebot.toml` \
343-
in the root of the repository.",
344-
stringify!($name)
345-
)));
346-
}
347-
}
348-
Command::$enum(Err(err)) => {
349-
errors.push(HandlerError::Message(format!(
350-
"Parsing {} command in [comment]({}) failed: {}",
351-
stringify!($name),
352-
event.html_url().expect("has html url"),
353-
err
354-
)));
355-
})*
356-
}
357-
}
358-
}
359-
}
360-
}
361-
362-
// Handle commands in comments/issues body
363-
//
364-
// This is for handlers for commands parsed by the `parser` crate.
365-
// Each variant of `parser::command::Command` must be in this list,
366-
// preceded by the module containing the corresponding `handle_command` function
367-
command_handlers! {
368-
assign: Assign,
369-
nominate: Nominate,
370-
ping: Ping,
371-
prioritize: Prioritize,
372-
relabel: Relabel,
373-
major_change: Second,
374-
shortcut: Shortcut,
375-
close: Close,
376-
note: Note,
377-
concern: Concern,
378-
transfer: Transfer,
379-
}
380-
381174
#[derive(Debug)]
382175
pub enum HandlerError {
383176
Message(String),

0 commit comments

Comments
 (0)