git-next/crates/forge-github/src/webhook/register.rs
Paul Campbell db90280641 fix: github: restarting server creates duplicate webhook for repo
The Github routine for registering a new webhook, wasn't removing any
existing matching webhooks. There is a test for this, but it doesn't
assert that the delete requests are made. (This is a limitation of
kxio).

Closes kemitix/git-next#102
2024-06-30 12:23:42 +01:00

68 lines
2.4 KiB
Rust

//
use crate::{self as github, webhook};
use git_next_config as config;
use git_next_git as git;
use kxio::network;
// https://docs.github.com/en/rest/repos/webhooks?apiVersion=2022-11-28#create-a-repository-webhook
pub async fn register(
github: &github::Github,
webhook_url: &config::server::WebhookUrl,
) -> git::forge::webhook::Result<config::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, webhook_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 = config::WebhookAuth::generate();
let request = network::NetRequest::new(
network::RequestMethod::Post,
network::NetUrl::new(format!(
"https://api.{hostname}/repos/{}/hooks",
repo_details.repo_path
)),
github::webhook::headers(repo_details.forge.token()),
network::RequestBody::Json(network::json!({
"name": "web",
"active": true,
"events": ["push"],
"config": {
"url": webhook_url.as_ref(),
"content_type": "json",
"secret": authorisation.to_string(),
"insecure_ssl": "0",
}
})),
network::ResponseType::Json,
None,
network::NetRequestLogging::None,
);
let result = net.post_json::<github::GithubHook>(request).await;
match result {
Ok(response) => {
let Some(hook) = response.response_body() else {
#[cfg(not(tarpaulin_include))]
// request response is Json so response_body never returns None
return Err(git::forge::webhook::Error::NetworkResponseEmpty);
};
tracing::info!(webhook_id = %hook.id, "Webhook registered");
Ok(config::RegisteredWebhook::new(
config::WebhookId::new(format!("{}", hook.id)),
authorisation,
))
}
Err(e) => {
tracing::warn!("Failed to register webhook");
Err(git::forge::webhook::Error::FailedToRegister(e.to_string()))
}
}
}