config PRs: document the operator merge, deploy only merges into main
docs: the config-repo `main` merge gate (merge = `core` + team `operators`, approvals = `operators`), the operator merge in the forge UI and what it deploys, the hand-added `operators` membership, and that with no eval-verify a failed rebuild leaves `applied/main` at the merged commit. The swarm README lists the converged gate and the merge deploy. `merged()` also requires `pull_request.base.ref == "main"`: the hive deploys its config repo's `main`, so a merge into another branch would only cost a forge fetch and a refusal comment (argus, #4894). Refs #4850
This commit is contained in:
parent
f1c695c212
commit
a5ea015bc6
4 changed files with 90 additions and 16 deletions
|
|
@ -62,6 +62,16 @@ struct WebhookPullRequest {
|
|||
/// The commit the merge left on the base branch.
|
||||
#[serde(default)]
|
||||
merge_commit_sha: Option<String>,
|
||||
/// The branch the PR targets. Only a merge into `main` is deployed: the
|
||||
/// hive builds its config repo's `main`.
|
||||
#[serde(default)]
|
||||
base: Option<WebhookBranch>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct WebhookBranch {
|
||||
#[serde(rename = "ref")]
|
||||
name: String,
|
||||
}
|
||||
|
||||
/// A config PR that was just merged: whose config, and the commit to deploy.
|
||||
|
|
@ -75,11 +85,17 @@ pub struct MergedConfigPr {
|
|||
///
|
||||
/// Only the `closed` action counts: Forgejo also sends `merged: true` on
|
||||
/// later events about an already-merged PR (a label or an edit), and those
|
||||
/// must not deploy it again. A body that does not parse is `None`;
|
||||
/// [`ConfigPrCache::apply_webhook_delivery`] already logs it.
|
||||
/// must not deploy it again. So does only a merge into `main`. A body that
|
||||
/// does not parse is `None`; [`ConfigPrCache::apply_webhook_delivery`]
|
||||
/// already logs it.
|
||||
pub fn merged(body: &[u8]) -> Option<MergedConfigPr> {
|
||||
let payload: ConfigPrWebhookPayload = serde_json::from_slice(body).ok()?;
|
||||
if payload.action != "closed" || !payload.pull_request.merged {
|
||||
let into_main = payload
|
||||
.pull_request
|
||||
.base
|
||||
.as_ref()
|
||||
.is_some_and(|base| base.name == "main");
|
||||
if payload.action != "closed" || !payload.pull_request.merged || !into_main {
|
||||
return None;
|
||||
}
|
||||
let Some(rev) = payload.pull_request.merge_commit_sha else {
|
||||
|
|
@ -301,6 +317,7 @@ mod tests {
|
|||
"html_url": "https://forge.example/pr",
|
||||
"merged": merged,
|
||||
"merge_commit_sha": merged.then_some("abc123"),
|
||||
"base": { "ref": "main" },
|
||||
},
|
||||
"repository": { "name": "damocles" },
|
||||
})
|
||||
|
|
@ -332,6 +349,14 @@ mod tests {
|
|||
assert_eq!(super::merged(body.to_string().as_bytes()), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_merge_into_another_branch_is_not_deployed() {
|
||||
let mut body: serde_json::Value =
|
||||
serde_json::from_slice(&closed(true)).expect("fixture is json");
|
||||
body["pull_request"]["base"]["ref"] = "staging".into();
|
||||
assert_eq!(super::merged(body.to_string().as_bytes()), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn an_open_delivery_is_not_a_merge() {
|
||||
assert_eq!(super::merged(&payload("damocles", 5, "open")), None);
|
||||
|
|
|
|||
Loading…
Reference in a new issue