pub fn changelog_sections(
project_root: &Path,
range_start: &str,
) -> Result<Vec<(ChangelogHeading, Vec<String>)>, VersionError>Expand description
Group --no-merges commits in range_start..HEAD by ChangelogHeading
(D-12). Walks the identical range and git log --no-merges <range> --format=%H%x1f%B%x1e argv as classify_range_bump (same record
separators, same git_conventional::Commit::parse call) — but, unlike
classify_range_bump (which folds every commit down to a single
aggregate Bump value; see RESEARCH.md Pitfall 1), collects each
commit’s subject into its group instead of discarding it.
classify_range_bump’s returned Bump is never used as changelog
content; this is sibling code, not a wrapper around it.
Complete per-type mapping (D-12, Task 2), evaluated in this order:
git_conventional::Commit::parsefails →ChangelogHeading::Changed, bullet = the message’s first line.commit.breaking()is true →ChangelogHeading::Breaking— checked before the type match, mirroringclassify_commit_message’s own precedence.- type is
feat→ChangelogHeading::Added. - type is
fix/perf→ChangelogHeading::Fixed. - every other type (
docs,test,chore,"ci",refactor,style, or any other recognized-but-unlisted type) →ChangelogHeading::Changed.
Deliberate divergence from classify_commit_message: an unparseable
message is Bump::Patch for versioning (D-10’s floor — an unrecognized
commit still bumps something) but Changed here — a message with no
conventional type has no claim to Fixed. Do not “fix” this into
agreement; it is intentional.
Bullets preserve git-log order (newest first) within each group; groups
are emitted in ChangelogHeading declaration order, omitting any group
with no bullets. A range with no commits returns Ok(Vec::new()).