git_next_forge_github/
lib.rs

1//
2#[cfg(test)]
3mod tests;
4
5mod commit;
6mod webhook;
7
8use crate as github;
9use git_next_core::{
10    self as core, git,
11    server::{self, RepoListenUrl},
12    ForgeNotification, RegisteredWebhook, WebhookAuth, WebhookId,
13};
14
15use derive_more::Constructor;
16
17#[derive(Clone, Debug, Constructor)]
18pub struct Github {
19    repo_details: git::RepoDetails,
20    net: kxio::net::Net,
21}
22#[async_trait::async_trait]
23impl git::ForgeLike for Github {
24    fn duplicate(&self) -> Box<dyn git::ForgeLike> {
25        Box::new(self.clone())
26    }
27    fn name(&self) -> String {
28        "github".to_string()
29    }
30
31    fn is_message_authorised(&self, msg: &ForgeNotification, webhook_auth: &WebhookAuth) -> bool {
32        github::webhook::is_authorised(msg, webhook_auth)
33    }
34
35    fn should_ignore_message(&self, message: &ForgeNotification) -> bool {
36        let Some(event) = message.header("x-github-event") else {
37            return false;
38        };
39        if event == "ping" {
40            tracing::info!("successfull ping received");
41            return true;
42        }
43        tracing::info!(%event, "message");
44        false
45    }
46
47    fn parse_webhook_body(
48        &self,
49        body: &core::webhook::forge_notification::Body,
50    ) -> git::forge::webhook::Result<core::webhook::push::Push> {
51        github::webhook::parse_body(body)
52    }
53
54    async fn commit_status(
55        &self,
56        commit: &git::Commit,
57    ) -> git::forge::webhook::Result<git::forge::commit::Status> {
58        github::commit::status(self, commit).await
59    }
60
61    async fn list_webhooks(
62        &self,
63        repo_listen_url: &RepoListenUrl,
64    ) -> git::forge::webhook::Result<Vec<WebhookId>> {
65        github::webhook::list(self, repo_listen_url).await
66    }
67
68    async fn unregister_webhook(&self, webhook_id: &WebhookId) -> git::forge::webhook::Result<()> {
69        github::webhook::unregister(self, webhook_id).await
70    }
71
72    // https://docs.github.com/en/rest/repos/webhooks?apiVersion=2022-11-28#create-a-repository-webhook
73    async fn register_webhook(
74        &self,
75        repo_listen_url: &RepoListenUrl,
76    ) -> git::forge::webhook::Result<RegisteredWebhook> {
77        github::webhook::register(self, repo_listen_url).await
78    }
79}
80
81#[derive(Debug, serde::Deserialize, serde::Serialize)]
82struct GithubStatus {
83    pub state: GithubState,
84    // other fields that we ignore
85}
86#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
87enum GithubState {
88    #[serde(rename = "success")]
89    Success,
90    #[serde(rename = "pending")]
91    Pending,
92    #[serde(rename = "failure")]
93    Failure,
94    #[serde(rename = "error")]
95    Error,
96    #[serde(rename = "")]
97    Blank,
98}
99
100#[derive(Debug, serde::Deserialize)]
101struct GithubHook {
102    id: u64,
103    config: Config,
104}
105impl GithubHook {
106    pub fn id(&self) -> WebhookId {
107        WebhookId::new(format!("{}", self.id))
108    }
109    pub fn url(&self) -> server::ListenUrl {
110        server::ListenUrl::new(self.config.url.clone())
111    }
112}
113#[derive(Debug, serde::Deserialize)]
114struct Config {
115    pub url: String,
116}