Watch
0
0
Fork
You've already forked hyperhive
0

swarm-controller: count default-branch merges and lines per repo

This commit is contained in:
atlas 2026-11-08 12:08:46 +01:00 • committed by mara
commit 2e23f3debf

View file

@ -132,6 +132,28 @@ fn merge_base_of(commits: &[forgejo_api::structs::Commit]) -> Option<String> {
}
}
/// Lines added and deleted, as [`Client::compare_line_stats`] sums them.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct LineStats {
pub added: u64,
pub deleted: u64,
}
/// `commits`' per-commit stats summed; a negative or missing figure is zero.
fn line_stats(commits: &[forgejo_api::structs::Commit]) -> LineStats {
let sum = |pick: fn(&forgejo_api::structs::CommitStats) -> Option<i64>| -> u64 {
commits
.iter()
.filter_map(|c| c.stats.as_ref().and_then(pick))
.map(|n| u64::try_from(n).unwrap_or(0))
.sum()
};
LineStats {
added: sum(|s| s.additions),
deleted: sum(|s| s.deletions),
}
}
/// `pulls` as the dropdown's rows, newest (highest number) first. A PR
/// without a usable number cannot be named, so it is left out.
fn open_pulls(pulls: Vec<forgejo_api::structs::PullRequest>) -> Vec<OpenPull> {
@ -1179,6 +1201,28 @@ impl Client {
Ok(open_pulls(pulls))
}
/// Lines added and deleted by the commits `before..after` of
/// `owner/repo`, summed over the per-commit stats the forge's compare
/// returns. A commit the forge sent no stats for counts as zero.
///
/// The sum is over commits, not a net diff of the two endpoints: a line
/// one commit adds and a later one removes counts once in each total.
pub async fn compare_line_stats(
&self,
owner: &str,
repo: &str,
before: &str,
after: &str,
) -> Result<LineStats> {
let basehead = format!("{before}...{after}");
let compare = self
.api
.call(|api| api.repo_compare_diff(owner, repo, &basehead).into_future())
.await
.with_context(|| format!("compare {basehead} in {owner}/{repo}"))?;
Ok(line_stats(compare.commits.as_deref().unwrap_or_default()))
}
/// Every open issue in `owner/repo`, each with its dependency-derived
/// `blocked` / `depended_on_by_count` pre-resolved server-side — the
/// whole job behind `GET /api/repos/{org}/{repo}/issue-report`. Doing
@ -2228,6 +2272,25 @@ impl Client {
#[cfg(test)]
mod tests {
use super::*;
/// Commit stats sum per side; a commit with none, or a negative figure,
/// adds zero.
#[test]
fn compare_stats_sum_across_commits() {
let commit = |stats: Option<(i64, i64)>| {
serde_json::from_value::<forgejo_api::structs::Commit>(serde_json::json!({
"stats": stats.map(|(a, d)| serde_json::json!({"additions": a, "deletions": d})),
}))
.expect("commit parses")
};
let got = line_stats(&[commit(Some((5, 2))), commit(None), commit(Some((-1, 4)))]);
assert_eq!(
got,
LineStats {
added: 5,
deleted: 6
}
);
}
/// The event list each swarm hook is registered with, as Forgejo names
/// the event types (`modules/webhook/type.go`).