swarm-controller: track agent config-PR status independently of hives
This commit is contained in:
parent
3c390f8132
commit
66c494697f
3 changed files with 217 additions and 2 deletions
|
|
@ -20,14 +20,26 @@ use forgejo_api::structs::{
|
|||
AddCollaboratorOption, AddCollaboratorOptionPermission, ChangeFileOperation,
|
||||
ChangeFileOperationOperation, ChangeFilesOptions, CreateBranchProtectionOption,
|
||||
CreateHookOption, CreateHookOptionConfig, CreateHookOptionType, CreateRepoOption,
|
||||
RepoGetContentsQuery,
|
||||
RepoGetContentsQuery, RepoListPullRequestsQuery, RepoListPullRequestsQueryState,
|
||||
};
|
||||
use forgejo_api::{ApiErrorKind, Auth, Forgejo, ForgejoError};
|
||||
use reqwest::StatusCode;
|
||||
use serde::Serialize;
|
||||
use std::collections::BTreeMap;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
use crate::webhook::DeliveryKind;
|
||||
|
||||
/// An agent's open config-PR, as [`Client::list_open_config_prs`] reports it
|
||||
/// and [`crate::get_agent_config_pr`] serves it.
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, ToSchema)]
|
||||
pub struct ConfigPrStatus {
|
||||
pub pr_number: u64,
|
||||
/// Absent only if Forgejo itself omitted the field — every real PR has
|
||||
/// one; not worth failing the whole scan over.
|
||||
pub html_url: Option<String>,
|
||||
}
|
||||
|
||||
/// The `operators` team, whitelisted for the merge gate on every repo
|
||||
/// this client protects — provisioned by `hive-c0re::forge::repos`
|
||||
/// already (`ensure_operators_team`), not re-provisioned here. If that
|
||||
|
|
@ -351,6 +363,71 @@ impl Client {
|
|||
}
|
||||
}
|
||||
|
||||
/// Every agent in [`CONFIG_ORG`] with an open config PR, keyed by agent
|
||||
/// name. Mirrors `hive-c0re::forge::config_pr_poll::poll_open_config_prs`'s
|
||||
/// scan shape (list repos in the org, list open PRs per repo) but returns
|
||||
/// data instead of side-effecting an approval queue — this daemon has no
|
||||
/// approval system of its own; it exists so [`crate::get_agent_config_pr`]
|
||||
/// has something to answer from, independent of any one hive being up.
|
||||
///
|
||||
/// A single repo's list failing does not fail the whole scan — logged and
|
||||
/// skipped, so one flaky repo can't blank out every other agent's status.
|
||||
pub async fn list_open_config_prs(
|
||||
&self,
|
||||
) -> Result<std::collections::HashMap<String, ConfigPrStatus>> {
|
||||
let repos = self
|
||||
.api
|
||||
.org_list_repos(CONFIG_ORG)
|
||||
.all()
|
||||
.await
|
||||
.with_context(|| format!("list repos in {CONFIG_ORG}"))?;
|
||||
|
||||
let mut out = std::collections::HashMap::new();
|
||||
for repo in repos {
|
||||
let Some(agent) = repo.name.as_deref() else {
|
||||
continue;
|
||||
};
|
||||
let query = RepoListPullRequestsQuery {
|
||||
state: Some(RepoListPullRequestsQueryState::Open),
|
||||
sort: None,
|
||||
milestone: None,
|
||||
labels: None,
|
||||
poster: None,
|
||||
base: None,
|
||||
head: None,
|
||||
};
|
||||
let prs = match self
|
||||
.api
|
||||
.repo_list_pull_requests(CONFIG_ORG, agent, query)
|
||||
.all()
|
||||
.await
|
||||
{
|
||||
Ok(prs) => prs,
|
||||
Err(e) => {
|
||||
tracing::debug!(%agent, error = %e, "swarm forge: listing config PRs failed, skipping repo");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
// Only the first open PR matters for the panel — a config repo
|
||||
// is meant to carry at most one live proposal at a time (the
|
||||
// same assumption `hive-c0re`'s poller and the `MergeConfigPr`
|
||||
// approval flow both make).
|
||||
if let Some(pr) = prs.into_iter().next() {
|
||||
let Some(pr_number) = pr.number.and_then(|n| u64::try_from(n).ok()) else {
|
||||
continue;
|
||||
};
|
||||
out.insert(
|
||||
agent.to_owned(),
|
||||
ConfigPrStatus {
|
||||
pr_number,
|
||||
html_url: pr.html_url.map(|u| u.to_string()),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
/// Register the swarm-wide hooks against this controller, so a real
|
||||
/// forge event reaches [`crate::webhook`] instead of the endpoint only
|
||||
/// being reachable by hand.
|
||||
|
|
|
|||
Loading…
Reference in a new issue