pin internal/meta's hyperhive on the controller's rev and rebuild agents when it moves
The swarm controller offers its own running rev (services.hyperhive.c0re. hyperhiveRev) as the hyperhive pin of internal/meta and takes it only when the forge compare API shows it descends from the committed pin; merges to hyperhive main no longer move the pin, and the first commit pins main's head. When a commit moves the pin, every placed agent gets a TriggerDeploy. A deploy after a meta update no longer waits on it succeeding (after_any), so a down builder does not hold back hives that render locally.
This commit is contained in:
parent
5950363a10
commit
22e2d30581
1 changed files with 1027 additions and 148 deletions
|
|
@ -9,7 +9,7 @@ use forgejo_api::structs::{
|
|||
};
|
||||
|
||||
use super::objects::SHARED_ORG;
|
||||
use super::{Client, DefaultBranchFiles};
|
||||
use super::{Client, DefaultBranchFiles, is_repo_not_found};
|
||||
use crate::meta_flake::{META_REPO, MetaFile, MetaForge};
|
||||
|
||||
impl MetaForge for Client {
|
||||
|
|
@ -36,6 +36,27 @@ impl MetaForge for Client {
|
|||
.await
|
||||
}
|
||||
|
||||
async fn commits_ahead(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
base: &str,
|
||||
head: &str,
|
||||
) -> Result<Option<u64>> {
|
||||
let basehead = format!("{base}...{head}");
|
||||
match self
|
||||
.api
|
||||
.call(|api| api.repo_compare_diff(owner, repo, &basehead).into_future())
|
||||
.await
|
||||
{
|
||||
Ok(compare) => Ok(Some(
|
||||
u64::try_from(compare.total_commits.unwrap_or(0)).unwrap_or(0),
|
||||
)),
|
||||
Err(e) if is_repo_not_found(&e) => Ok(None),
|
||||
Err(e) => Err(e).with_context(|| format!("compare {basehead} in {owner}/{repo}")),
|
||||
}
|
||||
}
|
||||
|
||||
async fn commit_meta(&self, message: &str, files: Vec<MetaFile>) -> Result<()> {
|
||||
let ops: Vec<ChangeFileOperation> = files
|
||||
.into_iter()
|
||||
|
|
@ -75,3 +96,70 @@ impl MetaForge for Client {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use super::*;
|
||||
|
||||
/// A stand-in forge answering Forgejo's compare endpoint: `total_commits`
|
||||
/// of 3 for `aaa...bbb`, 0 for `bbb...aaa`, 404 for anything else.
|
||||
/// Records every request's path.
|
||||
async fn compare_forge() -> (Client, Arc<Mutex<Vec<String>>>) {
|
||||
use axum::http::{StatusCode, Uri};
|
||||
|
||||
let seen = Arc::new(Mutex::new(Vec::new()));
|
||||
let recorded = Arc::clone(&seen);
|
||||
let app = axum::Router::new().fallback(move |uri: Uri| {
|
||||
let recorded = Arc::clone(&recorded);
|
||||
async move {
|
||||
recorded.lock().unwrap().push(uri.path().to_owned());
|
||||
match uri.path() {
|
||||
"/api/v1/repos/o/r/compare/aaa...bbb" => (
|
||||
StatusCode::OK,
|
||||
r#"{"total_commits":3,"commits":[],"files":[]}"#,
|
||||
),
|
||||
"/api/v1/repos/o/r/compare/bbb...aaa" => {
|
||||
(StatusCode::OK, r#"{"total_commits":0,"commits":[]}"#)
|
||||
}
|
||||
_ => (StatusCode::NOT_FOUND, r#"{"message":"not found"}"#),
|
||||
}
|
||||
}
|
||||
});
|
||||
let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
|
||||
let url = url::Url::parse(&format!("http://{}/", listener.local_addr().unwrap())).unwrap();
|
||||
tokio::spawn(async move { axum::serve(listener, app).await });
|
||||
let api = crate::forge::api::tests::fixed(url.clone(), "stub-token");
|
||||
(Client { api, url }, seen)
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn commits_ahead_reads_the_compare_endpoint_as_base_dots_head() {
|
||||
let (client, seen) = compare_forge().await;
|
||||
assert_eq!(
|
||||
client.commits_ahead("o", "r", "aaa", "bbb").await.unwrap(),
|
||||
Some(3)
|
||||
);
|
||||
assert_eq!(
|
||||
client.commits_ahead("o", "r", "bbb", "aaa").await.unwrap(),
|
||||
Some(0)
|
||||
);
|
||||
assert_eq!(
|
||||
*seen.lock().unwrap(),
|
||||
[
|
||||
"/api/v1/repos/o/r/compare/aaa...bbb",
|
||||
"/api/v1/repos/o/r/compare/bbb...aaa"
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn a_commit_the_forge_lacks_is_no_count_not_an_error() {
|
||||
let (client, _) = compare_forge().await;
|
||||
assert_eq!(
|
||||
client.commits_ahead("o", "r", "aaa", "zzz").await.unwrap(),
|
||||
None
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue