Bennewitz.Ninja.AutoVersioning
2026.3.916
Prefix Reserved
dotnet add package Bennewitz.Ninja.AutoVersioning --version 2026.3.916
NuGet\Install-Package Bennewitz.Ninja.AutoVersioning -Version 2026.3.916
<PackageReference Include="Bennewitz.Ninja.AutoVersioning" Version="2026.3.916"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
<PackageVersion Include="Bennewitz.Ninja.AutoVersioning" Version="2026.3.916" />
<PackageReference Include="Bennewitz.Ninja.AutoVersioning"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
paket add Bennewitz.Ninja.AutoVersioning --version 2026.3.916
#r "nuget: Bennewitz.Ninja.AutoVersioning, 2026.3.916"
#:package Bennewitz.Ninja.AutoVersioning@2026.3.916
#addin nuget:?package=Bennewitz.Ninja.AutoVersioning&version=2026.3.916
#tool nuget:?package=Bennewitz.Ninja.AutoVersioning&version=2026.3.916
Bennewitz.Ninja.AutoVersioning
A Roslyn incremental source generator that injects assembly metadata attributes and build-time constants into .NET projects at compile time — no AssemblyInfo.cs, no disk writes, full IDE caching.
Requirements
.NET SDK 6.0 or later (requires Roslyn 4.0+ for IIncrementalGenerator support). The consuming project may target any framework — .NET Framework 4.x, .NET Standard, .NET 6+, etc.
Quick Start
1. Add the package:
<PackageReference Include="Bennewitz.Ninja.AutoVersioning" Version="x.x.x" />
2. Enable the generator in your root Directory.Build.props (or any .props / .csproj imported by your build):
<PropertyGroup>
<GenerateAutoVersionedAssemblyInfo>true</GenerateAutoVersionedAssemblyInfo>
<AssemblyCompany>YourCompany</AssemblyCompany>
<AssemblyProduct>YourProduct</AssemblyProduct>
<CommitSha Condition="'$(CommitSha)' == ''">$(GITHUB_SHA)</CommitSha>
<PublicVersion Condition="'$(PublicVersion)' == ''">$(MY_VERSION_VAR)</PublicVersion>
</PropertyGroup>
Note: The package's auto-imported
Build.targetssuppresses the 8 SDK-generated attributes that this generator also emits (e.g.AssemblyVersion,AssemblyCopyright), so you do not need to disable anything yourself. Do not add<GenerateAssemblyInfo>false</GenerateAssemblyInfo>: it is redundant, and broader than intended — that switch disables every SDK-generated attribute, includingInternalsVisibleTodeclared via MSBuild<InternalsVisibleTo>items. (A hand-writtenInternalsVisibleToin a compiled.csfile is unaffected either way.)
A ready-to-use template is available at Directory.Build.props.template.
3. Build. The generator runs automatically — no further setup needed.
Tip: View the generated files in your IDE under
Dependencies → Analyzers → *SourceGenerators.
Generated Output
Given a build on 2026-04-29 at 14:35 UTC for company Acme Corp, product Acme App, commit abc1234def, and public version 3.1.0:
AutoVersionedAssemblyInfo.g.cs
using System.Reflection;
using System.Runtime.CompilerServices;
[assembly: AssemblyDescription("Assembly Version: 2026.2.429.1435")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCompany("Acme Corp")]
[assembly: AssemblyProduct("Acme App v2026.2.429.1435")]
[assembly: AssemblyCopyright("Copyright 2026 [Release]")]
[assembly: AssemblyVersion("2026.2.429.1435")]
[assembly: AssemblyFileVersion("2026.2.429.1435")]
[assembly: AssemblyInformationalVersion("Commit♥: abc1234def")]
[assembly: AssemblyMetadata("CommitSha", "abc1234def")]
[assembly: AssemblyMetadata("GITHUB_SHA", "abc1234def")]
[assembly: AssemblyMetadata("PublicVersion", "3.1.0")]
DirectoryBuildInfo.g.cs
// <auto-generated/>
namespace Bennewitz.Ninja.AutoVersioning
{
/// <summary>Build-time constants generated by the source generator.</summary>
public static class DirectoryBuildInfo
{
public const string BuildRelease = "Version 2026.2.429.1435 [built 4/29/2026 2:35:00 PM (UTC)]";
}
}
Use DirectoryBuildInfo.BuildRelease wherever you need the build version at runtime — error trackers, log enrichment, health endpoints — without reading environment variables.
Configuration Reference
| MSBuild Property | Description | Required |
|---|---|---|
GenerateAutoVersionedAssemblyInfo |
Set to true to enable the generator |
Yes |
AssemblyCompany |
Value for [assembly: AssemblyCompany(...)] |
Yes |
AssemblyProduct |
Value for [assembly: AssemblyProduct(...)] |
Yes |
CopyrightHolder |
Name shown in the copyright attribute — defaults to AssemblyCompany if omitted |
No |
CommitSha |
Git commit SHA | No |
PublicVersion |
Your app's public-facing version string | No |
Configuration |
Debug / Release — set automatically by MSBuild |
Auto |
BuildTimestamp |
Build start time in yyyyMMddHHmmss format — captured automatically at MSBuild evaluation time (before any project compiles), ensuring a consistent version across all projects in a multi-project solution build. Override on CI for an exact guarantee: dotnet build -p:BuildTimestamp=$(date +%Y%m%d%H%M%S) |
Auto |
AutoVersion |
Output. The four-part version YEAR.QUARTER.MMdd.HHmm the generator stamps, derived from BuildTimestamp during property evaluation so MSBuild can read it too. Overridable |
Auto |
AutoPackageVersion |
Output. The same version without the time component: YEAR.QUARTER.MMdd. Overridable |
Auto |
Using the version from MSBuild
The generator calculates the version inside the Roslyn pipeline, which is too late for anything
MSBuild decides. PackageVersion is the common casualty: it is evaluated long before compilation,
so a library packs as NuGet's default 1.0.0 while the assembly inside that package is stamped
2026.3.913.1613. The package and its own contents disagree, and nothing reports it.
AutoVersion and AutoPackageVersion are derived during property evaluation from the same
BuildTimestamp the generator is handed, so they are available early enough to assign:
<PropertyGroup>
<PackageVersion>$(AutoPackageVersion)</PackageVersion>
</PropertyGroup>
Neither property is assigned to anything automatically — opting in is explicit, because this
package should not quietly take over PackageVersion for every project that references it.
Three-part for packages on purpose: four-part versions are not SemVer, which matters for anything published publicly, and
Pack.ps1already defaults to that form.
GenerateAutoVersionedAssemblyInfo may be set anywhere the build sees it — Directory.Build.props,
another .props file, or the .csproj itself. The SDK attribute suppressions live in the package's
auto-imported Build.targets, which NuGet imports after the project body, so the flag is honoured
regardless of where it is declared.
CI Provider Mappings
Map CommitSha from whichever variable your provider sets. The CI-flag column is listed for
convenience only — this package does not read it; it is what you would condition your own MSBuild
targets on (e.g. Condition="'$(GITHUB_ACTIONS)' == 'true'").
| Provider | Commit SHA | CI flag |
|---|---|---|
| GitHub Actions | $(GITHUB_SHA) |
$(GITHUB_ACTIONS) |
| GitLab CI | $(CI_COMMIT_SHA) |
$(GITLAB_CI) |
| Bitbucket Pipelines | $(BITBUCKET_COMMIT) |
$(CI) |
Version Format
The generator uses CalVer: YEAR.QUARTER.MMDD.HHmm
| Part | Example | Meaning |
|---|---|---|
| Major | 2026 |
Calendar year |
| Minor | 2 |
Quarter (1–4) |
| Build | 429 |
Month + day (MMdd as integer) |
| Revision | 1435 |
Hour + minute (HHmm as integer) |
How It Works
This is a modern C# IIncrementalGenerator. Compared to legacy ISourceGenerator approaches it:
- Runs entirely in-memory — zero files written to disk
- Uses the Roslyn caching pipeline — the IDE (Rider, Visual Studio) only re-runs the generator when its inputs change, eliminating background compilation loops
- Reads MSBuild properties via
AnalyzerConfigOptionsProvider— safe, no direct environment variable reads
The package auto-imports two files via NuGet: Build.props, which declares the CompilerVisibleProperty items and derives AutoVersion / AutoPackageVersion, and Build.targets, which suppresses the SDK's conflicting AssemblyInfo attributes (preventing CS0579 duplicate attribute errors when the generator is enabled). The suppressions live in the .targets because NuGet imports it after the consuming project's body, so GenerateAutoVersionedAssemblyInfo is honoured wherever it is set.
Timestamp Consistency in Multi-Project Builds
BuildTimestamp keeps the version consistent across every project in a solution build. See docs/MultiProjectBuildTimestamps.md for how it works and what alternative approaches were considered.
TL;DR: For CI, or any local build where an exact guarantee matters more than convenience, use
-p:BuildTimestamp=...to fix the value explicitly instead of relying on evaluation-time capture. Ready-to-use wrappers are available atBuild.ps1.template(Windows/PowerShell 7+) andBuild.sh.template(Linux/macOS/bash).
Diagnostics
| ID | Severity | Description |
|---|---|---|
BAUTOVERSIONING00 |
Warning | Generator is installed but GenerateAutoVersionedAssemblyInfo is not set to true (single-line signal) |
BAUTOVERSIONING01 |
Warning | Generator threw an unexpected exception |
BAUTOVERSIONING02 |
Error | AssemblyCompany is not configured |
BAUTOVERSIONING03 |
Error | AssemblyProduct is not configured |
BAUTOVERSIONING04 |
Warning | Multi-line setup snippet emitted alongside BAUTOVERSIONING00 — shows the required Directory.Build.props configuration |
Building Locally
Requires PowerShell 7+ and the .NET SDK.
./Pack.ps1
The script prompts for a version (defaults to CalVer YYYY.Q.MMDD) and produces .nupkg files in packages/Debug/ and packages/Release/.
License
MIT © 2026 Brian Bennewitz
Learn more about Target Frameworks and .NET Standard.
This package has no dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2026.3.916 | 2,169 | 9/16/2026 |
| 2026.3.914 | 1,412 | 9/14/2026 |
| 2026.3.819 | 933 | 8/19/2026 |
| 2026.3.701 | 15,260 | 7/1/2026 |
| 2026.2.522 | 780 | 5/21/2026 |
| 2026.2.521 | 114 | 5/21/2026 |
| 2026.2.515 | 117 | 5/15/2026 |
| 2026.2.501 | 165 | 5/1/2026 |
| 2026.2.429 | 160 | 4/29/2026 |