Single-commit clean baseline after security scrub of niche-tells, project codenames, internal jargon, and contributor-email leaks. Contents: - 100 Rust crates (_primitives/_rust/) - 37 agent manifests (_manifests/) + generated specs (_generated/) - 67 user-invocable skills (skills/) - 33 hooks (hooks/) - Composition blocks (_blocks/) - Documentation (docs/, README.md) - TS adapter packages (_ts_packages/) - Assembler (_assembler/) - Roles (_roles/) - Templates (_templates/) - Forgejo CI (.forgejo/) Author: Denis Parfionovich <info@greendragon.info> License: see LICENSE.
39 lines
1.1 KiB
Rust
39 lines
1.1 KiB
Rust
//! Group commits by kind, preserving insertion order within each bucket.
|
|
|
|
use crate::commit::{Commit, CommitKind};
|
|
use std::collections::BTreeMap;
|
|
|
|
/// Commits grouped by `CommitKind`, sorted by `CommitKind::sort_key`.
|
|
#[derive(Debug, Default)]
|
|
pub struct Grouped {
|
|
pub by_kind: BTreeMap<u8, (CommitKind, Vec<Commit>)>,
|
|
pub breaking: Vec<Commit>,
|
|
}
|
|
|
|
impl Grouped {
|
|
/// Build a `Grouped` from an ordered slice of commits.
|
|
///
|
|
/// Breaking commits are additionally copied into `breaking` so renderers
|
|
/// can surface them in a "BREAKING CHANGES" section.
|
|
#[must_use]
|
|
pub fn from_commits(commits: &[Commit]) -> Self {
|
|
let mut g = Self::default();
|
|
for c in commits {
|
|
if c.breaking {
|
|
g.breaking.push(c.clone());
|
|
}
|
|
let key = c.kind.sort_key();
|
|
g.by_kind
|
|
.entry(key)
|
|
.or_insert_with(|| (c.kind.clone(), Vec::new()))
|
|
.1
|
|
.push(c.clone());
|
|
}
|
|
g
|
|
}
|
|
|
|
#[must_use]
|
|
pub fn is_empty(&self) -> bool {
|
|
self.by_kind.is_empty() && self.breaking.is_empty()
|
|
}
|
|
}
|