git-next-forge-github 0.14.1

GitHub support for git-next, the trunk-based development manager
Documentation
//
use crate::{self as github, webhook};
use git_next_core::{git, server::RepoListenUrl, RegisteredWebhook, WebhookAuth, WebhookId};
use serde_json::json;

// https://docs.github.com/en/rest/repos/webhooks?apiVersion=2022-11-28#create-a-repository-webhook
pub async fn register(
    github: &github::Github,
    repo_listen_url: &RepoListenUrl,
) -> git::forge::webhook::Result<RegisteredWebhook> {
    let repo_details = &github.repo_details;
    if repo_details.repo_config.is_none() {
        return Err(git::forge::webhook::Error::NoRepoConfig);
    };

    // remove any lingering webhooks for the same URL
    let existing_webhook_ids = webhook::list(github, repo_listen_url).await?;
    for webhook_id in existing_webhook_ids {
        webhook::unregister(github, &webhook_id).await?;
    }

    let net = &github.net;
    let hostname = repo_details.forge.hostname();
    let authorisation = WebhookAuth::generate();
    match net
        .post(format!(
            "https://api.{hostname}/repos/{}/hooks",
            repo_details.repo_path
        ))
        .headers(github::webhook::headers(repo_details.forge.token()))
        .body(
            json!({
                "name": "web",
                "active": true,
                "events": ["push"],
                "config": {
                    "url": repo_listen_url.to_string(),
                    "content_type": "json",
                    "secret": authorisation.to_string(),
                    "insecure_ssl": "0",
                }
            })
            .to_string(),
        )
        .send()
        .await
    {
        Err(e) => {
            tracing::warn!("Failed to register webhook");
            Err(git::forge::webhook::Error::FailedToRegister(e.to_string()))
        }
        Ok(response) => {
            match response.json::<github::GithubHook>().await {
                Err(_) => {
                    #[cfg(not(tarpaulin_include))]
                    // request response is Json so response_body never returns None
                    return Err(git::forge::webhook::Error::NetworkResponseEmpty);
                }
                Ok(hook) => {
                    tracing::info!(webhook_id = %hook.id, "Webhook registered");
                    Ok(RegisteredWebhook::new(
                        WebhookId::new(format!("{}", hook.id)),
                        authorisation,
                    ))
                }
            }
        }
    }
}