Эх сурвалжийг харах

refactor handlers to register them using a macro

Pietro Albini 6 жил өмнө
parent
commit
568737977d
5 өөрчлөгдсөн 86 нэмэгдсэн , 80 устгасан
  1. 8 0
      src/github.rs
  2. 43 13
      src/handlers.rs
  3. 32 16
      src/handlers/label.rs
  4. 3 8
      src/main.rs
  5. 0 43
      src/registry.rs

+ 8 - 0
src/github.rs

@@ -176,6 +176,14 @@ pub enum Event {
     IssueComment(IssueCommentEvent),
 }
 
+impl Event {
+    pub fn repo_name(&self) -> &str {
+        match self {
+            Event::IssueComment(event) => &event.repository.full_name,
+        }
+    }
+}
+
 trait RequestSend: Sized {
     fn configure(self, g: &GithubClient) -> Self;
     fn send_req(self) -> Result<Response, HttpError>;

+ 43 - 13
src/handlers.rs

@@ -1,21 +1,51 @@
-use crate::github::GithubClient;
-use crate::registry::HandleRegistry;
+use crate::github::{Event, GithubClient};
+use failure::Error;
 
-//mod assign;
-mod label;
-//mod tracking_issue;
+macro_rules! handlers {
+    ($($name:ident = $handler:expr,)*) => {
+        $(mod $name;)*
+
+        pub fn handle(ctx: &Context, event: &Event) -> Result<(), Error> {
+            $(if let Some(input) = Handler::parse_input(&$handler, ctx, event)? {
+                let config = crate::config::get(&ctx.github, event.repo_name())?;
+                if let Some(config) = &config.$name {
+                    Handler::handle_input(&$handler, ctx, config, event, input)?;
+                } else {
+                    failure::bail!(
+                        "The feature `{}` is not enabled in this repository.\n\
+                         To enable it add its section in the `triagebot.toml` \
+                         in the root of the repository.",
+                        stringify!($name)
+                    );
+                }
+            })*
+            Ok(())
+        }
+    }
+}
+
+handlers! {
+    //assign = assign::AssignmentHandler,
+    label = label::LabelHandler,
+    //tracking_issue = tracking_issue::TrackingIssueHandler,
+}
 
 pub struct Context {
     pub github: GithubClient,
     pub username: String,
 }
 
-pub fn register_all(registry: &mut HandleRegistry) {
-    registry.register(label::LabelHandler);
-    //registry.register(assign::AssignmentHandler {
-    //    client: client.clone(),
-    //});
-    //registry.register(tracking_issue::TrackingIssueHandler {
-    //    client: client.clone(),
-    //});
+pub trait Handler: Sync + Send {
+    type Input;
+    type Config;
+
+    fn parse_input(&self, ctx: &Context, event: &Event) -> Result<Option<Self::Input>, Error>;
+
+    fn handle_input(
+        &self,
+        ctx: &Context,
+        config: &Self::Config,
+        event: &Event,
+        input: Self::Input,
+    ) -> Result<(), Error>;
 }

+ 32 - 16
src/handlers/label.rs

@@ -9,33 +9,33 @@
 //! notification noise.
 
 use crate::{
+    config::LabelConfig,
     github::{self, Event, GithubClient},
-    handlers::Context,
+    handlers::{Context, Handler},
     interactions::ErrorComment,
-    registry::Handler,
 };
 use failure::Error;
 use parser::command::label::{LabelCommand, LabelDelta};
 use parser::command::{Command, Input};
 
-pub struct LabelHandler;
+pub(super) struct LabelHandler;
 
 impl Handler for LabelHandler {
-    fn handle_event(&self, ctx: &Context, event: &Event) -> Result<(), Error> {
+    type Input = LabelCommand;
+    type Config = LabelConfig;
+
+    fn parse_input(&self, ctx: &Context, event: &Event) -> Result<Option<Self::Input>, Error> {
         #[allow(irrefutable_let_patterns)]
         let event = if let Event::IssueComment(e) = event {
             e
         } else {
             // not interested in other events
-            return Ok(());
+            return Ok(None);
         };
 
-        let repo = &event.repository.full_name;
-        let mut issue_labels = event.issue.labels().to_owned();
-
         let mut input = Input::new(&event.comment.body, &ctx.username);
-        let deltas = match input.parse_command() {
-            Command::Label(Ok(LabelCommand(deltas))) => deltas,
+        match input.parse_command() {
+            Command::Label(Ok(command)) => Ok(Some(command)),
             Command::Label(Err(err)) => {
                 ErrorComment::new(
                     &event.issue,
@@ -51,13 +51,30 @@ impl Handler for LabelHandler {
                     err
                 );
             }
-            _ => return Ok(()),
+            _ => Ok(None),
+        }
+    }
+
+    fn handle_input(
+        &self,
+        ctx: &Context,
+        config: &LabelConfig,
+        event: &Event,
+        input: LabelCommand,
+    ) -> Result<(), Error> {
+        #[allow(irrefutable_let_patterns)]
+        let event = if let Event::IssueComment(e) = event {
+            e
+        } else {
+            // not interested in other events
+            return Ok(());
         };
 
+        let mut issue_labels = event.issue.labels().to_owned();
         let mut changed = false;
-        for delta in &deltas {
+        for delta in &input.0 {
             let name = delta.label().as_str();
-            if let Err(msg) = check_filter(name, repo, &event.comment.user, &ctx.github) {
+            if let Err(msg) = check_filter(name, config, &event.comment.user, &ctx.github) {
                 ErrorComment::new(&event.issue, msg.to_string()).post(&ctx.github)?;
                 return Ok(());
             }
@@ -89,7 +106,7 @@ impl Handler for LabelHandler {
 
 fn check_filter(
     label: &str,
-    repo: &str,
+    config: &LabelConfig,
     user: &github::User,
     client: &GithubClient,
 ) -> Result<(), Error> {
@@ -105,8 +122,7 @@ fn check_filter(
             // continue on; if we failed to check their membership assume that they are not members.
         }
     }
-    let config = crate::config::get(client, repo)?;
-    for pattern in &config.label.as_ref().unwrap().allow_unauthenticated {
+    for pattern in &config.allow_unauthenticated {
         let pattern = glob::Pattern::new(pattern)?;
         if pattern.matches(label) {
             return Ok(());

+ 3 - 8
src/main.rs

@@ -12,8 +12,6 @@ use rocket::{http::Status, Outcome, Request};
 use std::env;
 
 mod handlers;
-mod registry;
-
 mod config;
 mod github;
 mod interactions;
@@ -21,7 +19,6 @@ mod payload;
 mod team;
 
 use payload::SignedPayload;
-use registry::HandleRegistry;
 
 enum EventName {
     IssueComment,
@@ -68,7 +65,7 @@ impl From<Error> for WebhookError {
 fn webhook(
     event: EventName,
     payload: SignedPayload,
-    reg: State<HandleRegistry>,
+    ctx: State<handlers::Context>,
 ) -> Result<(), WebhookError> {
     match event {
         EventName::IssueComment => {
@@ -78,7 +75,7 @@ fn webhook(
                 .map_err(Error::from)?;
 
             let event = github::Event::IssueComment(payload);
-            reg.handle(&event).map_err(Error::from)?;
+            handlers::handle(&ctx, &event)?;
         }
         // Other events need not be handled
         EventName::Other => {}
@@ -102,8 +99,6 @@ fn main() {
         github: gh.clone(),
         username: github::User::current(&gh).unwrap().login,
     };
-    let mut registry = HandleRegistry::new(ctx);
-    handlers::register_all(&mut registry);
 
     let mut config = rocket::Config::active().unwrap();
     config.set_port(
@@ -113,7 +108,7 @@ fn main() {
     );
     rocket::custom(config)
         .manage(gh)
-        .manage(registry)
+        .manage(ctx)
         .mount("/", routes![webhook])
         .register(catchers![not_found])
         .launch();

+ 0 - 43
src/registry.rs

@@ -1,43 +0,0 @@
-use crate::github::Event;
-use crate::handlers::Context;
-use failure::Error;
-
-pub struct HandleRegistry {
-    handlers: Vec<Box<dyn Handler>>,
-    ctx: Context,
-}
-
-impl HandleRegistry {
-    pub fn new(ctx: Context) -> HandleRegistry {
-        HandleRegistry {
-            handlers: Vec::new(),
-            ctx,
-        }
-    }
-
-    pub fn register<H: Handler + 'static>(&mut self, h: H) {
-        self.handlers.push(Box::new(h));
-    }
-
-    pub fn handle(&self, event: &Event) -> Result<(), Error> {
-        let mut last_error = None;
-        for h in &self.handlers {
-            match h.handle_event(&self.ctx, event) {
-                Ok(()) => {}
-                Err(e) => {
-                    eprintln!("event handling failed: {:?}", e);
-                    last_error = Some(e);
-                }
-            }
-        }
-        if let Some(err) = last_error {
-            Err(err)
-        } else {
-            Ok(())
-        }
-    }
-}
-
-pub trait Handler: Sync + Send {
-    fn handle_event(&self, ctx: &Context, event: &Event) -> Result<(), Error>;
-}