From 8f9f6f7b19e4be323d5cef4d80c9567dddd11a69 Mon Sep 17 00:00:00 2001 From: Paul Delafosse Date: Fri, 11 Oct 2024 15:32:33 +0200 Subject: [PATCH] feat: support pull request opened event --- src/gh/event.rs | 17 ++++++++++++++- src/gh/mod.rs | 35 +++++++++++++++++++++++++++++- src/main.rs | 57 ++++++++++++++++++++++++++++++++----------------- 3 files changed, 88 insertions(+), 21 deletions(-) diff --git a/src/gh/event.rs b/src/gh/event.rs index c45bc60..35940a0 100644 --- a/src/gh/event.rs +++ b/src/gh/event.rs @@ -1,5 +1,13 @@ +use octocrab::models::webhook_events::payload::PullRequestWebhookEventPayload; use serde::Deserialize; +#[derive(Debug, Deserialize)] +#[serde(untagged)] +pub enum Payload { + CheckSuite(CheckSuiteEvent), + PullRequest(PullRequestEvent), +} + #[derive(Debug, Deserialize)] pub struct CheckSuiteEvent { pub action: CheckSuiteAction, @@ -18,7 +26,6 @@ pub enum CheckSuiteAction { #[derive(Debug, Deserialize)] pub struct CheckSuitePayload { - pub id: u64, pub pull_requests: Vec, pub head_sha: String, } @@ -44,3 +51,11 @@ pub struct RepositoryOwner { pub struct Installation { pub id: u64, } + +#[derive(Debug, Deserialize)] +pub struct PullRequestEvent { + pub installation: Installation, + #[serde(flatten)] + pub inner: PullRequestWebhookEventPayload, + pub repository: octocrab::models::Repository, +} diff --git a/src/gh/mod.rs b/src/gh/mod.rs index 3a7adea..b72c970 100644 --- a/src/gh/mod.rs +++ b/src/gh/mod.rs @@ -1,3 +1,4 @@ +use anyhow::anyhow; use cocogitto::settings::Settings as CogSettings; use octocrab::models::checks::CheckRun; use octocrab::models::issues::Comment; @@ -12,6 +13,7 @@ use event::CheckSuiteEvent; use crate::cog::report::CogBotReportBuilder; use crate::gh::authenticate::authenticate; use crate::gh::commits::GetCommits; +use crate::gh::event::PullRequestEvent; pub mod authenticate; pub mod check_run; @@ -30,7 +32,7 @@ pub struct CocogittoBot { const COCOGITTO_BOT_LOGIN: &str = "cocogitto-bot[bot]"; impl CocogittoBot { - pub async fn from_check_suite(event: CheckSuiteEvent, gh_key: &str) -> octocrab::Result { + pub async fn from_check_suite(event: CheckSuiteEvent, gh_key: &str) -> anyhow::Result { let check_suite = event.check_suite; let installation = event.installation; let repository = event.repository; @@ -62,6 +64,37 @@ impl CocogittoBot { }) } + pub async fn from_pull_request(event: PullRequestEvent, gh_key: &str) -> anyhow::Result { + let installation = event.installation; + let repository = event.repository; + + info!("Authenticating to github api"); + let auth = authenticate(installation.id, &repository.name, gh_key).await; + if let Err(auth_error) = &auth { + return Err(anyhow!("Failed to authenticate: {auth_error}")); + } + + let inner = auth?; + let pull_request_number = Some(event.inner.pull_request.number); + + let Some(default_branch) = repository.default_branch else { + return Err(anyhow!("default_branch missing from pull_request event")); + }; + + let Some(owner) = repository.owner.map(|owner| owner.login) else { + return Err(anyhow!("owner missing from pull_request event")); + }; + + Ok(Self { + inner, + owner, + repo: repository.name, + head_sha: event.inner.pull_request.head.sha, + pull_request_number, + default_branch, + }) + } + pub async fn run(&mut self) -> anyhow::Result<()> { let check_run = self.create_check_runs().await?; diff --git a/src/main.rs b/src/main.rs index 99c6007..797162c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,14 +5,15 @@ use axum::http::HeaderMap; use axum::routing::{get, post}; use axum::{Json, Router}; use axum_macros::debug_handler; +use gh::event::CheckSuiteAction; +use octocrab::models::webhook_events::payload::PullRequestWebhookEventAction; use tower_http::trace::TraceLayer; use tracing::{info, warn}; use tracing_subscriber::layer::SubscriberExt; use tracing_subscriber::util::SubscriberInitExt; -use gh::event::{CheckSuiteAction, CheckSuiteEvent}; - use crate::error::AppResult; +use crate::gh::event::Payload; use crate::gh::CocogittoBot; use crate::settings::Settings; @@ -64,33 +65,51 @@ async fn main() -> anyhow::Result<()> { async fn pull_request_handler( State(state): State, headers: HeaderMap, - Json(event): Json, + Json(event): Json, ) -> AppResult<()> { let Some(event_header) = headers.get("X-Github-Event") else { warn!("'X-Github-Event' header missing, ignoring request"); return Ok(()); }; - let Ok("check_suite") = event_header.to_str() else { - info!("Ignoring non check_suite event"); - return Ok(()); - }; - - if event.action == CheckSuiteAction::Completed { - info!("Ignoring completed check_suite"); - return Ok(()); + match event_header.to_str() { + Ok("check_suite") | Ok("pull_request") => {} + _ => { + info!("Ignoring non check_suite event"); + return Ok(()); + } } - if event.check_suite.pull_requests.is_empty() { - info!("Ignoring non pull request check_suite event"); - return Ok(()); + match event { + Payload::CheckSuite(event) => { + if event.action == CheckSuiteAction::Completed { + info!("Ignoring completed check_suite"); + return Ok(()); + } + + if event.check_suite.pull_requests.is_empty() { + info!("Ignoring non pull request check_suite event"); + return Ok(()); + } + + CocogittoBot::from_check_suite(event, &state.github_key) + .await? + .run() + .await?; + } + Payload::PullRequest(event) => { + if event.inner.action != PullRequestWebhookEventAction::Opened { + info!("Ignoring pull_request event"); + return Ok(()); + } + + CocogittoBot::from_pull_request(event, &state.github_key) + .await? + .run() + .await?; + } } - CocogittoBot::from_check_suite(event, &state.github_key) - .await? - .run() - .await?; - Ok(()) }