Expand description
Hybrid Git-based SemVer.
DevFlow derives the version entirely from git history (D-11) — the
version file (Cargo.toml, pyproject.toml, or package.json) is no
longer an input to compute_version, only an output write_version
produces:
- Baseline — the highest semver tag reachable from
HEAD(reachable_semver_baseline, D-07). If the highest semver tag in the repository overall is NOT reachable fromHEAD,compute_versionrefuses rather than silently falling back to a smaller reachable tag (D-10). - Bump — classified from the conventional-commit intent of the
commits added since that baseline was released
(
classify_range_bump, D-08), over a range anchored byrelease_range_startto survive this repository’s squash-merge + sync-back release topology.
Structs§
- SelfPin
- One
[workspace.dependencies]self-pin discovered byread_workspace_self_pins— a local-path dependency’s name and its pinnedversionsub-value. - Version
- A semantic version, whether read from disk or computed from git history.
Enums§
- Bump
- The classified conventional-commit bump for a range of commits (D-08).
Declaration order is the precedence order (lowest to highest), so
Iterator::max()/Ord::maxover a range’s individual classifications yields the highest-precedence result directly. - Changelog
Heading - Keep-a-Changelog heading a changelog bullet is grouped under (D-12).
Declaration order is the render order
render_changelog_bodyemits sections in: breaking changes first, then what’s new, then what’s fixed, then everything else. - Version
Error - Errors produced by version operations.
Constants§
- CHANGELOG_
SUBJECT_ MAX_ CHARS - Maximum length, in characters, of a sanitized changelog bullet
(
sanitize_changelog_subject).
Functions§
- changelog_
sections - Group
--no-mergescommits inrange_start..HEADbyChangelogHeading(D-12). Walks the identical range andgit log --no-merges <range> --format=%H%x1f%B%x1eargv asclassify_range_bump(same record separators, samegit_conventional::Commit::parsecall) — but, unlikeclassify_range_bump(which folds every commit down to a single aggregateBumpvalue; see RESEARCH.md Pitfall 1), collects each commit’s subject into its group instead of discarding it.classify_range_bump’s returnedBumpis never used as changelog content; this is sibling code, not a wrapper around it. - classify_
range_ bump - Classify the highest-precedence conventional-commit bump over
--no-mergescommits inrange_start..HEAD.range_startmay be the empty string, meaning “no baseline tag exists” — the whole history reachable fromHEADis classified instead (git log --no-merges HEAD, no exclusion). - commits_
since_ last_ minor_ tag Deprecated - Count commits since the most recent tag. If there are no tags yet, counts all commits reachable from HEAD.
- compute_
version - Compute the full version: the baseline resolved from the highest
reachable semver tag (D-07), bumped by the conventional-commit
classification of the commits added since that baseline was released
(D-08). The version file is NOT read here (D-11) —
write_versionis the only writer, andread_versionis the only reader of what’s on disk. - count_
git_ tags Deprecated - Count all git tags.
- detect_
version_ file - Detect the project’s version file, checking Cargo.toml, then pyproject.toml, then package.json. Returns the first that exists.
- highest_
semver_ tag - Enumerate every tag in the repository (no reachability restriction), keep
only values that parse as
vMAJOR.MINOR.PATCHsemver (a leadingvis stripped first — thesemvercrate’s grammar is bareMAJOR.MINOR.PATCH), and return the maximum by semver ordering (D-07). A stray non-semver tag (e.g. this repository’sarchive-planning-docs-2026-07-24) is silently excluded viafilter_map(...ok())rather than erroring — a malformed tag can never crash this path (T-25-02). - reachable_
semver_ baseline - As
highest_semver_tag, but restricted to tags reachable fromHEADviagit tag --merged HEAD— one spawn instead of an O(n) per-tagmerge-base --is-ancestorloop, mirroringGitFlow::cleanup_merged’s existingbranch --mergedprecedent ingit.rs. This iscompute_version’s baseline (D-07). - read_
major_ version - Read the MAJOR version component from a version file.
- read_
version - Read the full
Version(major/minor/patch) out of whatever version filedetect_version_fileresolves, mirroringwrite_version’s format handling (including[workspace.package]). - read_
workspace_ self_ pins - Extract
[workspace.package] versionand every local-path[workspace.dependencies]self-pin (crate name + pinned version) from a workspace Cargo.toml’s contents. - release_
range_ start - Resolve the commit range start for D-08’s conventional-commit classifier,
given the baseline tag name (e.g.
"v2.0.0"). - render_
changelog_ body - Render
sections(fromchangelog_sections) as Keep-a-Changelog markdown: each section’s heading line, a blank line, then one- {subject}line per bullet, with a blank line between sections. Returns an empty string whensectionsis empty — the “nothing changed” fallback text iscrate::ship::prepend_changelog’s responsibility, not this function’s. - sanitize_
changelog_ subject - Neutralize and bound a commit-derived changelog bullet before it reaches
CHANGELOG.mdor atracingline (D-12, ASVS V7, T-26-05). Commit subjects are contributor-authored text — the same attacker-influenced classT-17-13/T-25-52already redact — so everychar::is_controlcharacter is mapped to a single space, then, if the result exceedsCHANGELOG_SUBJECT_MAX_CHARScharacters, it is truncated so the returned string is exactlyCHANGELOG_SUBJECT_MAX_CHARScharacters including the trailing… [truncated]marker. Mirrorsrender_gate_context’s properties (pipeline_outcomes.rs:323) — a sibling, not a shared function, since that one ispub(crate)insidedevflow-cliand not importable fromdevflow-core. - write_
version - Write
versioninto the project’s auto-detected version file.