Skip to content

Introduce buildvana.json configuration and native versioning (replacing Nerdbank.GitVersioning) #267

@rdeago

Description

@rdeago

Reference version

2.0.134-preview

Background and motivation

Two needs have converged into one effort:

  • bv has no configuration file. Repo-constant options (main branch, most release options) must be passed on every invocation or rely on hardcoded defaults; recurring dotnet parameters can't be shared across pipeline commands; and secrets/endpoints live in environment variables read by the seedling ToolConfiguration/NuGetPushConfiguration types, which already document themselves as awaiting a file layer.
  • Nerdbank.GitVersioning (NBGV) is heavyweight and owns branch policy. Branch→public-release policy (publicReleaseRefSpec) and the prerelease tag (firstUnstableTag) live in NBGV's version.json, separate from bv, and bv shells out to the nbgv CLI at runtime.

These are coupled: native versioning needs publicReleaseRefSpecrelease.branches and firstUnstableTagrelease.prereleaseTag to live in a bv-owned file, the version value needs its own home, and the SDK's build-time version task must read that policy. So configuration and native versioning are one body of work, and both are prerequisites for shipping a stable release.

This supersedes #229 and its sub-issues #230#233, which assumed version.json stays NBGV-shaped and unchanged — an assumption this design overturns.

Proposed enhancement

End state:

  • A committed buildvana.json at the repo root (.json xor .jsonc; bail if both) holds repo-stable policy and endpoints. Secrets are referenced by *Env fields naming an environment variable, never inlined. Precedence is CLI flag → buildvana.json → hardcoded default; it is the single source of truth for everything it covers.
  • A shared, host-agnostic configuration library (Core-tier; System.Text.Json + BCL only) reads and validates it, consumed by both Buildvana.Tool and Buildvana.Sdk.Tasks.
  • NBGV is removed end-to-end. Version computation becomes native via a Buildvana.Core.Versioning library, with git height from a single LibGit2Sharp-based calculator shared by both the tool and the SDK build-time task (no git CLI dependency).
  • The version value moves to a machine-rewritten VERSION file (no extension) holding MAJOR.MINOR[-[tag]] (the tag text is informational — only the presence of - marks a prerelease line); policy (public-release branches, prerelease tag, assembly-version precision) lives in buildvana.json.
  • mainBranch discovery is replaced by release.generateDocsFrom (regex); the --main-branch global flag and GitService branch discovery are removed.
  • A new bv version command exposes version inspection and advancement.

Branch matching uses ordinary .NET regex (matched against the short branch name, explicit ^…$ anchoring, compiled with a match timeout) — not a bespoke glob syntax — for portability and familiarity.

Implementation proposals

Eight sequenced, individually shippable phases. Critical path 1 → 4 → 7 → 8, with 5 and 6 also feeding 7; 2 and 3 are parallel tracks after 1, and 5/6 are independent of 4. Each phase must leave dotnet bv build self-hosting.

  1. Shared config foundation — config library + loader + DI + generated schema; SDK home-marker change.
  2. Today's optionsdotnet/release configuration, checkPublicApi, changelogUpdates+emptyChangelog, dogfood, dotnet.args, generateDocsFrom.
  3. Secrets/endpointsnuget.feeds, github.tokenEnv, git.identity shape.
  4. Buildvana.Core.Versioning library — version logic + VERSION reader + the single LibGit2Sharp height calculator + settings/service. (Versioning Phase 4 — create the Buildvana.Core.Versioning library #293)
  5. IReporter-over-MSBuild adapter — instrument BuildvanaSdkTask so Core services run in-process inside tasks. (Versioning Phase 5 — IReporter-over-MSBuild adapter and BuildvanaSdkTask instrumentation #294)
  6. Restore the dormant ThisAssemblyClass module + generator — off by default; no version coupling yet. (Versioning Phase 6 — restore the dormant ThisAssemblyClass SDK module and source generator #295)
  7. Swap NBGV → native — SDK Versioning module + build-time task, tool rewire, ThisAssembly version constants, remove NBGV end-to-end. (Versioning Phase 7 — swap NBGV for native versioning (SDK task + module, tool rewire, ThisAssembly) #296)
  8. bv version commandshow / advance. (Versioning Phase 8 — bv version command #274)

Each phase is filed as a sub-issue with its own scope and acceptance criteria.

Usage examples

// buildvana.json (repo root)
{
  "release": {
    "branches": ["^main$", "^v\\d+\\.\\d+$"],     // regex vs short branch name; single source of public-release branches
    "generateDocsFrom": ["^main$"],                // regex; replaces the old mainBranch docs gate
    "configuration": "Release",                    // optional; defaults to dotnet.configuration
    "checkPublicApi": true,
    "changelogUpdates": "stable",                  // none | stable | all
    "emptyChangelog": "No public-facing changes in this release.", // optional; substitute text, else fail
    "dogfood": true,
    "prereleaseTag": "preview"                      // optional; absent ⇒ no prerelease versions allowed
  },
  "versioning": { "assemblyVersionPrecision": "major" }, // major | minor | build | revision
  "dotnet": {
    "configuration": "Release",
    "args": { "all": ["-p:ContinuousIntegrationBuild=true"], "pack": ["-p:Foo=1"] }
  },
  "nuget": {
    "feeds": {
      "prerelease": { "source": "...", "apiKeyEnv": "PRERELEASE_NUGET_KEY" }, // defaults onto release if absent
      "release":    { "source": "https://api.nuget.org/v3/index.json", "apiKeyEnv": "RELEASE_NUGET_KEY" }
    }
  },
  "github": { "tokenEnv": "GITHUB_TOKEN" },
  "git": { "identity": { "name": "Buildvana Bot", "email": "buildvana-bot@example.com" } }
}

The repo-root version file (MAJOR.MINOR[-[tag]] — the - marks a prerelease line; the tag text is informational, the effective tag comes from release.prereleaseTag):

// VERSION (repo root)
2.0-preview
dotnet bv version show
dotnet bv version advance minor

Risks

  • Breaking change for consumers. version.json (NBGV) → VERSION + buildvana.json keys. Mitigation: a migration note and a **BREAKING CHANGE** changelog entry; the repo's own migration is sequenced after the new SDK is published so self-hosting (which builds with the last published SDK) never breaks.
  • Hard-fail on unknown keys may surprise. Mitigation: clear error messages and an editor schema for authoring-time validation.
  • Detached HEAD ⇒ non-public-release (mirrors GitService's empty-string convention). Height uses a single LibGit2Sharp calculator in both hosts, so there is no system-git dependency; the new risk is packaging LibGit2Sharp's native assets into Buildvana.Sdk so the build-time task loads them under both dotnet build and msbuild.exe (de-risked by an early spike in Phase 7).
  • Height is no longer parity-checked against NBGV — by design. The only invariant is within-line monotonicity (height resets at each VERSION change; the overall semver never regresses).
  • Dependency changes. Remove Nerdbank.GitVersioning injection and the nbgv tool; add the shared config library and Buildvana.Core.Versioning. NuGet.Versioning and LibGit2Sharp stay. Net consumer footprint shrinks.

Additional information

  • Drop Cake.Frosting from Buildvana.Tool #228 (drop Cake.Frosting) has shipped, so the bv version CLI is plain Spectre subcommands — no flat-task fallback.
  • assemblyVersion.precision becomes configurable (versioning.assemblyVersionPrecision); semVer 2.0 stays fixed; pathFilters is dropped (warning on non-empty).
  • Where the native height/branch-matching logic reproduces NBGV (MIT) details, source comments cite NBGV and preserve its copyright.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancement[issue/PR] requests / implements new or improved functionality.refactor[issue/PR] requests / implements a refactor of existing code without affecting functionality.
    No fields configured for Feature.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions