Sub-issue of #267. Depends on Phase 1 (#268, config foundation). Lands before Phases 5–7; no live code is wired to it yet.
Scope
- New
src/Buildvana.Core.Versioning/ (replacing the empty leftover directory), targeting $(StandardTfm). Dependencies: Buildvana.Core.Abstractions, Buildvana.Core.Configuration, NuGet.Versioning, LibGit2Sharp. NuGet.Versioning and LibGit2Sharp stay internal — never surfaced in a public signature.
- Definitions →
Buildvana.Core.Abstractions (namespace Buildvana.Core.Versioning): VersionSpec(int Major, int Minor, bool Prerelease); the VersionSpecChange enum; any other simple enums. BCL-only. No Buildvana.Core.Versioning.Abstractions project — a single height impl plus a string-typed service surface means nothing trips a promotion trigger.
- Machinery →
Buildvana.Core.Versioning:
VersionSpec.Parse(string) as a static extension member (C# 14 extension block). Format MAJOR.MINOR[-[tag]] — no v prefix, tag optional, a bare - allowed without a tag; the presence of - after the minor sets Prerelease = true. Proposed regex (semver grammar minus patch/metadata, single loosened tag): ^(?<Major>0|[1-9][0-9]*)\.(?<Minor>0|[1-9][0-9]*)((?<Prerelease>\-)[0-9a-zA-Z]*)?(\s|$). ToString() emits M.m or M.m-prerelease, used only to round-trip the VERSION file.
- Single LibGit2Sharp git-height calculator; version-file name is a constructor parameter. Height = commits from
HEAD back to (and excluding) the last commit that modified the version file. Detached HEAD / empty branch handled per the non-public-release convention.
- Main part →
Buildvana.Core.Versioning (may depend on Buildvana.Core.Configuration):
VersioningSettings, mirroring DotNetSettings; surfaces release.branches, release.prereleaseTag, versioning.assemblyVersionPrecision.
VersioningService: constructor-injected dependencies (no DI container), uses IReporter, throws BuildFailedException. Reads the VERSION file (fail loudly if absent), computes the current version, and exposes it in the needed string forms (full semver, simple M.m.p, assembly version honoring precision, informational). IsPublicRelease = short branch name matches any release.branches regex (explicit ^…$ anchors, compiled, match timeout); IsPrerelease. Enforce: version is prerelease but release.prereleaseTag absent ⇒ fail.
- The version value lives in a
VERSION file (no extension) holding MAJOR.MINOR[-[tag]]; the file's tag text is informational (only the presence of - is read) — the effective prerelease tag comes from release.prereleaseTag.
- Config keys:
release.branches and release.prereleaseTag already exist; consider relocating them from ReleaseConfig to a VersioningConfig section if that better fits the new structure (config is unreleased, so no migration concern). Ensure versioning.assemblyVersionPrecision exists, adding it (model + generated schema) if not yet present.
- Nothing else is touched:
Buildvana.Tool keeps its own versioning types and nbgv; no wiring; no behavior change.
Acceptance criteria
Buildvana.Core.Versioning and the new Buildvana.Core.Abstractions types build cleanly; no Buildvana.Core.Versioning.Abstractions project exists; NuGet.Versioning/LibGit2Sharp appear in no public signature.
- Unit tests (TUnit) pass in CI:
VERSION parsing (1.0, 1.0-preview, 1.0-, malformed); branch-regex matching (match, no match, empty list, detached-HEAD/empty branch); assembly-version precision (major|minor|build|revision); height monotonicity and reset across a VERSION change on a temporary LibGit2Sharp repo; the version string formats.
bv behavior is unchanged (NBGV still in use; the tool is not yet wired to the library).
- CHANGELOG: internal-only; no public entry (the library is not packaged standalone and not yet consumed).
Sub-issue of #267. Depends on Phase 1 (#268, config foundation). Lands before Phases 5–7; no live code is wired to it yet.
Scope
src/Buildvana.Core.Versioning/(replacing the empty leftover directory), targeting$(StandardTfm). Dependencies:Buildvana.Core.Abstractions,Buildvana.Core.Configuration,NuGet.Versioning,LibGit2Sharp.NuGet.VersioningandLibGit2Sharpstay internal — never surfaced in a public signature.Buildvana.Core.Abstractions(namespaceBuildvana.Core.Versioning):VersionSpec(int Major, int Minor, bool Prerelease); theVersionSpecChangeenum; any other simple enums. BCL-only. NoBuildvana.Core.Versioning.Abstractionsproject — a single height impl plus a string-typed service surface means nothing trips a promotion trigger.Buildvana.Core.Versioning:VersionSpec.Parse(string)as a static extension member (C# 14 extension block). FormatMAJOR.MINOR[-[tag]]— novprefix, tag optional, a bare-allowed without a tag; the presence of-after the minor setsPrerelease = true. Proposed regex (semver grammar minus patch/metadata, single loosened tag):^(?<Major>0|[1-9][0-9]*)\.(?<Minor>0|[1-9][0-9]*)((?<Prerelease>\-)[0-9a-zA-Z]*)?(\s|$).ToString()emitsM.morM.m-prerelease, used only to round-trip theVERSIONfile.HEADback to (and excluding) the last commit that modified the version file. Detached HEAD / empty branch handled per the non-public-release convention.Buildvana.Core.Versioning(may depend onBuildvana.Core.Configuration):VersioningSettings, mirroringDotNetSettings; surfacesrelease.branches,release.prereleaseTag,versioning.assemblyVersionPrecision.VersioningService: constructor-injected dependencies (no DI container), usesIReporter, throwsBuildFailedException. Reads theVERSIONfile (fail loudly if absent), computes the current version, and exposes it in the needed string forms (full semver, simpleM.m.p, assembly version honoring precision, informational).IsPublicRelease= short branch name matches anyrelease.branchesregex (explicit^…$anchors, compiled, match timeout);IsPrerelease. Enforce: version is prerelease butrelease.prereleaseTagabsent ⇒ fail.VERSIONfile (no extension) holdingMAJOR.MINOR[-[tag]]; the file's tag text is informational (only the presence of-is read) — the effective prerelease tag comes fromrelease.prereleaseTag.release.branchesandrelease.prereleaseTagalready exist; consider relocating them fromReleaseConfigto aVersioningConfigsection if that better fits the new structure (config is unreleased, so no migration concern). Ensureversioning.assemblyVersionPrecisionexists, adding it (model + generated schema) if not yet present.Buildvana.Toolkeeps its own versioning types andnbgv; no wiring; no behavior change.Acceptance criteria
Buildvana.Core.Versioningand the newBuildvana.Core.Abstractionstypes build cleanly; noBuildvana.Core.Versioning.Abstractionsproject exists;NuGet.Versioning/LibGit2Sharpappear in no public signature.VERSIONparsing (1.0,1.0-preview,1.0-, malformed); branch-regex matching (match, no match, empty list, detached-HEAD/empty branch); assembly-version precision (major|minor|build|revision); height monotonicity and reset across aVERSIONchange on a temporary LibGit2Sharp repo; the version string formats.bvbehavior is unchanged (NBGV still in use; the tool is not yet wired to the library).