[F] Fix webhook uninstall missing url

This commit is contained in:
2026-05-09 22:47:02 +00:00
parent de88150445
commit 44b1865b15
3 changed files with 104 additions and 19 deletions
+34 -13
View File
@@ -726,32 +726,53 @@ fn remove_webhook_state_keys(state: &mut WebhookState, keys: Vec<String>, url: &
fn uninstall_webhook_task(task: WebhookUninstallTask) -> Result<Option<String>> { fn uninstall_webhook_task(task: WebhookUninstallTask) -> Result<Option<String>> {
let key = webhook_installation_key(&task.group, &task.endpoint, &task.repo.name); let key = webhook_installation_key(&task.group, &task.endpoint, &task.repo.name);
if task.dry_run {
crate::logln!( crate::logln!(
" {} {} {}", " {} {} {}",
style(if task.dry_run { style("would uninstall").red().bold(),
"would uninstall"
} else {
"uninstall"
})
.red()
.bold(),
style(&task.repo.name).cyan(), style(&task.repo.name).cyan(),
style(format!("from {}", task.endpoint.label())).dim() style(format!("from {}", task.endpoint.label())).dim()
); );
if task.dry_run {
return Ok(None); return Ok(None);
} }
let client = ProviderClient::new(&task.site)?; let client = ProviderClient::new(&task.site)?;
client match client.uninstall_webhook(&task.endpoint, &task.repo.name, &task.url) {
.uninstall_webhook(&task.endpoint, &task.repo.name, &task.url) Ok(true) => {
.with_context(|| { crate::logln!(
" {} {} {}",
style("uninstall").red().bold(),
style(&task.repo.name).cyan(),
style(format!("from {}", task.endpoint.label())).dim()
);
Ok(Some(key))
}
Ok(false) => {
crate::logln!(
" {} {} {}",
style("missing").yellow().bold(),
style(&task.repo.name).cyan(),
style(format!("webhook from {}", task.endpoint.label())).dim()
);
Ok(None)
}
Err(error) if non_actionable_webhook_failure_reason(&error).is_some() => {
let reason = non_actionable_webhook_failure_reason(&error).unwrap();
crate::logln!(
" {} {} {}",
style("skip").yellow().bold(),
style(&task.repo.name).cyan(),
style(format!("from {}: {reason}", task.endpoint.label())).dim()
);
Ok(None)
}
Err(error) => Err(error).with_context(|| {
format!( format!(
"failed to uninstall webhook for {} from {}", "failed to uninstall webhook for {} from {}",
task.repo.name, task.repo.name,
task.endpoint.label() task.endpoint.label()
) )
})?; }),
Ok(Some(key)) }
} }
fn non_actionable_webhook_failure_reason(error: &anyhow::Error) -> Option<String> { fn non_actionable_webhook_failure_reason(error: &anyhow::Error) -> Option<String> {
+34
View File
@@ -255,6 +255,40 @@ fn uninstall_webhook_deletes_matching_github_hook() {
handle.join().unwrap(); handle.join().unwrap();
} }
#[test]
fn uninstall_webhook_reports_missing_github_hook() {
let (api_url, handle) = one_request_server(
"200 OK",
r#"[{"id":42,"config":{"url":"https://old.example.test/webhook"}}]"#,
|request| {
assert!(
request.starts_with("GET /repos/alice/repo/hooks "),
"request was {request}"
)
},
);
let site = SiteConfig {
api_url: Some(api_url),
..site(ProviderKind::Github, None)
};
let client = ProviderClient::new(&site).unwrap();
let removed = client
.uninstall_webhook(
&EndpointConfig {
site: "github".to_string(),
kind: NamespaceKind::User,
namespace: "alice".to_string(),
},
"repo",
"https://mirror.example.test/webhook",
)
.unwrap();
assert!(!removed);
handle.join().unwrap();
}
#[test] #[test]
fn delete_repo_deletes_github_repo() { fn delete_repo_deletes_github_repo() {
let (api_url, handle) = one_request_server("204 No Content", "", |request| { let (api_url, handle) = one_request_server("204 No Content", "", |request| {
+32 -2
View File
@@ -450,7 +450,7 @@ fn install_task_state_cache_is_only_used_for_sync() {
} }
#[test] #[test]
fn uninstall_task_removes_state_even_when_hook_is_missing() { fn uninstall_task_keeps_state_when_hook_is_missing() {
let (api_url, handle) = one_request_server("200 OK", "[]", |request| { let (api_url, handle) = one_request_server("200 OK", "[]", |request| {
assert!(request.starts_with("GET /repos/alice/repo/hooks ")) assert!(request.starts_with("GET /repos/alice/repo/hooks "))
}); });
@@ -473,7 +473,37 @@ fn uninstall_task_removes_state_even_when_hook_is_missing() {
}) })
.unwrap(); .unwrap();
assert_eq!(key.as_deref(), Some("sync-1\tgithub\tUser\talice\trepo")); assert_eq!(key, None);
handle.join().unwrap();
}
#[test]
fn blocked_webhook_uninstall_is_skipped() {
let (api_url, handle) = one_request_server(
"403 Forbidden",
r#"{"message":"Repository access blocked","block":{"reason":"sensitive_data","created_at":"2021-05-18T16:29:54Z","html_url":"https://github.com/tos"}}"#,
|request| assert!(request.starts_with("GET /repos/alice/repo/hooks ")),
);
let key = uninstall_webhook_task(WebhookUninstallTask {
group: "sync-1".to_string(),
site: SiteConfig {
api_url: Some(api_url),
..site("github", ProviderKind::Github)
},
endpoint: endpoint("github", NamespaceKind::User, "alice"),
repo: RemoteRepo {
name: "repo".to_string(),
clone_url: "https://github.com/alice/repo.git".to_string(),
private: true,
description: None,
},
url: "https://mirror.example.test/webhook".to_string(),
dry_run: false,
})
.unwrap();
assert_eq!(key, None);
handle.join().unwrap(); handle.join().unwrap();
} }