lib.rs 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. #![feature(async_await)]
  2. #![allow(clippy::new_without_default)]
  3. use failure::{Error, ResultExt};
  4. use interactions::ErrorComment;
  5. use std::fmt;
  6. pub mod config;
  7. pub mod github;
  8. pub mod handlers;
  9. pub mod interactions;
  10. pub mod payload;
  11. pub mod team;
  12. pub enum EventName {
  13. IssueComment,
  14. Issue,
  15. Other,
  16. }
  17. impl std::str::FromStr for EventName {
  18. type Err = std::convert::Infallible;
  19. fn from_str(s: &str) -> Result<EventName, Self::Err> {
  20. Ok(match s {
  21. "issue_comment" => EventName::IssueComment,
  22. "issues" => EventName::Issue,
  23. _ => EventName::Other,
  24. })
  25. }
  26. }
  27. impl fmt::Display for EventName {
  28. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  29. write!(
  30. f,
  31. "{}",
  32. match self {
  33. EventName::IssueComment => "issue_comment",
  34. EventName::Issue => "issues",
  35. EventName::Other => "other",
  36. }
  37. )
  38. }
  39. }
  40. #[derive(Debug)]
  41. pub struct WebhookError(Error);
  42. impl From<Error> for WebhookError {
  43. fn from(e: Error) -> WebhookError {
  44. WebhookError(e)
  45. }
  46. }
  47. pub fn deserialize_payload<T: serde::de::DeserializeOwned>(v: &str) -> Result<T, Error> {
  48. Ok(serde_json::from_str(&v).with_context(|_| format!("input: {:?}", v))?)
  49. }
  50. pub async fn webhook(
  51. event: EventName,
  52. payload: String,
  53. ctx: &handlers::Context,
  54. ) -> Result<(), WebhookError> {
  55. match event {
  56. EventName::IssueComment => {
  57. let payload = deserialize_payload::<github::IssueCommentEvent>(&payload)
  58. .context("IssueCommentEvent failed to deserialize")
  59. .map_err(Error::from)?;
  60. log::info!("handling issue comment {:?}", payload);
  61. let event = github::Event::IssueComment(payload);
  62. if let Err(err) = handlers::handle(&ctx, &event).await {
  63. if let Some(issue) = event.issue() {
  64. let cmnt = ErrorComment::new(issue, err.to_string());
  65. cmnt.post(&ctx.github).await?;
  66. }
  67. return Err(err.into());
  68. }
  69. }
  70. EventName::Issue => {
  71. let payload = deserialize_payload::<github::IssuesEvent>(&payload)
  72. .context("IssuesEvent failed to deserialize")
  73. .map_err(Error::from)?;
  74. log::info!("handling issue event {:?}", payload);
  75. let event = github::Event::Issue(payload);
  76. if let Err(err) = handlers::handle(&ctx, &event).await {
  77. if let Some(issue) = event.issue() {
  78. let cmnt = ErrorComment::new(issue, err.to_string());
  79. cmnt.post(&ctx.github).await?;
  80. }
  81. return Err(err.into());
  82. }
  83. }
  84. // Other events need not be handled
  85. EventName::Other => {}
  86. }
  87. Ok(())
  88. }