swarm-controller: emit vcs commit/push otel counters from an instance-wide forge webhook

This commit is contained in:
damocles 2026-08-24 19:59:41 +02:00 committed by mara
commit 6bb64d8bc2
6 changed files with 290 additions and 3 deletions

View file

@ -557,6 +557,15 @@ impl Client {
},
),
DeliveryKind::ConfigPr => ("pull_request", HookScope::Org { org: CONFIG_ORG }),
// Instance-wide: commit/push activity is not scoped to one
// org (unlike the two above) — it needs observing across
// every repo the forge hosts, per the "no metric exists for
// commits or pushes" tracker issue. Forgejo's
// "global (system) webhook" (`admin_create_hook`) is exactly
// this — the only scope in this API that fires for a repo
// in an org created after this hook was registered, with no
// per-org registration to keep in sync as orgs come and go.
DeliveryKind::VcsActivity => ("push", HookScope::Instance),
};
self.ensure_hook(&scope, &target_url, event, secret)
.await
@ -624,8 +633,18 @@ impl Client {
/// theirs — a hook on the wrong scope would never fire, and forgejo would
/// report that as a perfectly healthy hook with no deliveries.
enum HookScope<'a> {
Repo { org: &'a str, repo: &'a str },
Org { org: &'a str },
Repo {
org: &'a str,
repo: &'a str,
},
Org {
org: &'a str,
},
/// Forgejo's "global (system) webhook" — fires for every repo in the
/// instance, in every org, present or future. The `admin_*` API
/// namespace; needs the same `write:admin` scope
/// `Client::ensure_agent_user` already requires on this token.
Instance,
}
impl HookScope<'_> {
@ -634,6 +653,7 @@ impl HookScope<'_> {
let hooks = match self {
Self::Repo { org, repo } => api.repo_list_hooks(org, repo).all().await?,
Self::Org { org } => api.org_list_hooks(org).send().await?,
Self::Instance => api.admin_list_hooks().await?,
};
Ok(hooks
.iter()
@ -645,6 +665,7 @@ impl HookScope<'_> {
match self {
Self::Repo { org, repo } => api.repo_create_hook(org, repo, hook).await.map(drop),
Self::Org { org } => api.org_create_hook(org, hook).await.map(drop),
Self::Instance => api.admin_create_hook(hook).await.map(drop),
}
}
}