// #[cfg(test)] mod tests; mod webhook; use std::borrow::ToOwned; use git_next_core::{ self as core, git::{self, forge::commit::Status}, server::RepoListenUrl, ForgeNotification, RegisteredWebhook, WebhookAuth, WebhookId, }; use kxio::net::Net; #[derive(Clone, Debug)] pub struct ForgeJo { repo_details: git::RepoDetails, net: Net, } impl ForgeJo { #[must_use] pub const fn new(repo_details: git::RepoDetails, net: Net) -> Self { Self { repo_details, net } } } #[async_trait::async_trait] impl git::ForgeLike for ForgeJo { fn duplicate(&self) -> Box { Box::new(self.clone()) } fn name(&self) -> String { "forgejo".to_string() } fn is_message_authorised(&self, msg: &ForgeNotification, expected: &WebhookAuth) -> bool { let authorization = msg.header("authorization"); tracing::info!(?authorization, %expected, "is message authorised?"); authorization .and_then(|header| header.strip_prefix("Basic ").map(ToOwned::to_owned)) .and_then(|value| WebhookAuth::try_new(value.as_str()).ok()) .is_some_and(|auth| &auth == expected) } fn parse_webhook_body( &self, body: &core::webhook::forge_notification::Body, ) -> git::forge::webhook::Result { webhook::parse_body(body) } async fn commit_status(&self, commit: &git::Commit) -> git::forge::webhook::Result { let repo_details = &self.repo_details; let hostname = &repo_details.forge.hostname(); let repo_path = &repo_details.repo_path; let api_token = &repo_details.forge.token(); use secrecy::ExposeSecret; let token = api_token.expose_secret(); let url = format!( "https://{hostname}/api/v1/repos/{repo_path}/commits/{commit}/status?token={token}" ); let Ok(response) = self.net.get(url).send().await else { return Ok(Status::Pending); }; let combined_status = response.json::().await.unwrap_or_default(); eprintln!("combined_status: {:?}", combined_status); let status = match combined_status.state { ForgejoState::Success => Status::Pass, ForgejoState::Pending | ForgejoState::Blank => Status::Pending, ForgejoState::Failure | ForgejoState::Error => Status::Fail, }; Ok(status) } async fn list_webhooks( &self, repo_listen_url: &RepoListenUrl, ) -> git::forge::webhook::Result> { webhook::list(&self.repo_details, repo_listen_url, &self.net).await } async fn unregister_webhook(&self, webhook_id: &WebhookId) -> git::forge::webhook::Result<()> { webhook::unregister(webhook_id, &self.repo_details, &self.net).await } async fn register_webhook( &self, repo_listen_url: &RepoListenUrl, ) -> git::forge::webhook::Result { webhook::register(&self.repo_details, repo_listen_url, &self.net).await } } #[derive(Debug, Default, serde::Deserialize)] struct CombinedStatus { pub state: ForgejoState, } #[derive(Debug, Default, serde::Deserialize)] enum ForgejoState { #[serde(rename = "success")] Success, #[serde(rename = "pending")] #[default] Pending, #[serde(rename = "failure")] Failure, #[serde(rename = "error")] Error, #[serde(rename = "")] Blank, }