DotnetVersionReader 1.2.0
See the version list below for details.
dotnet tool install --global DotnetVersionReader --version 1.2.0
dotnet new tool-manifest
dotnet tool install --local DotnetVersionReader --version 1.2.0
#tool dotnet:?package=DotnetVersionReader&version=1.2.0
nuke :add-package DotnetVersionReader --version 1.2.0
DotnetVersionReader
A .NET global tool for reading version information from .csproj, .sln, and .slnx files,
for enforcing version bumps in pull requests, and for showing which projects had their version changed.
Installation
dotnet tool install --global DotnetVersionReader
Or from a local build:
dotnet pack src/DotnetVersionReader -c Release
dotnet tool install --global DotnetVersionReader --version <version> --add-source ./src/DotnetVersionReader/bin/Release
Commands
dotnet-version [command] [options]
Commands:
read Reads and displays version information from .csproj files. (default)
check Checks that every project whose source files have changed has had its version bumped.
diff Shows projects whose version has changed (or that are new) relative to a base branch.
dotnet-version read — read versions (default)
Reads and displays version information. This is the default command: running
dotnet-version with no subcommand is equivalent to dotnet-version read.
# Both forms are equivalent:
dotnet-version [--input <path>] [options]
dotnet-version read [--input <path>] [options]
Options
| Option | Short | Description |
|---|---|---|
--input |
-i |
Path to a .csproj, .sln, .slnx file or a folder. Defaults to the current directory. |
--output |
-o |
Output format: json (default), table, list, or version (single project only). |
--filter |
-f |
Filter in the form XmlNode=Value. Value can be a regex. Repeatable. |
--schema |
Print the JSON schema for --output json and exit. Defaults to false. |
Version resolution
The tool follows MSBuild semantics:
- If
<Version>is set, it is used as-is. - Otherwise the version is
<VersionPrefix>(default1.0.0) optionally followed by-<VersionSuffix>.
Examples
# Current directory – JSON output (default, both forms are equivalent)
dotnet-version
dotnet-version read
# Specific solution file – table output
dotnet-version read --input MySolution.slnx --output table
dotnet-version read -i MySolution.slnx -o table
# Only projects that generate a NuGet package
dotnet-version read --filter "GeneratePackageOnBuild=true"
# Combine multiple filters (all must match)
dotnet-version read -i MySolution.slnx -f "TargetFramework=^net10\.0$" -f "GeneratePackageOnBuild=true"
Sample JSON output
[
{
"Name": "MyLibrary",
"Version": "2.1.0-rc.1",
"Major": 2,
"Minor": 1,
"Patch": 0,
"Suffix": "rc.1"
},
{
"Name": "MyApp",
"Version": "1.0.0",
"Major": 1,
"Minor": 0,
"Patch": 0,
"Suffix": null
}
]
Sample table output
| Name | Version | Major | Minor | Patch | Suffix |
| --------- | ---------- | ----- | ----- | ----- | ------ |
| MyLibrary | 2.1.0-rc.1 | 2 | 1 | 0 | rc.1 |
| MyApp | 1.0.0 | 1 | 0 | 0 | |
Sample list output
MyLibrary 2.1.0-rc.1
MyApp 1.0.0
Sample version output
2.1.0-rc.1
dotnet-version check — enforce version bumps in PRs
Checks that every project whose source files have changed (compared to a base branch) has had its version bumped. Designed to run as a CI gate on pull requests.
dotnet-version check [--base <ref>] [--input <path>] [--head <ref>] [--output <format>] [--filter <XmlNode=Value>]...
# Short aliases (--base defaults to origin/main):
dotnet-version check [-b <ref>] [-i <path>] [--head <ref>] [-o <format>] [-f <XmlNode=Value>]...
Options
| Option | Short | Required | Description |
|---|---|---|---|
--input |
-i |
Path to a .csproj, .sln, .slnx file or a folder. Defaults to the current directory. |
|
--base |
-b |
The git ref to compare against. Defaults to origin/main. |
|
--head |
The git ref for the current state. Defaults to HEAD. |
||
--output |
-o |
Output format: json (default), table, or version (single project only). |
|
--filter |
-f |
Filter in the form XmlNode=Value. Only matching projects are checked. Value can be a regex. Repeatable. |
Exit codes
| Code | Meaning |
|---|---|
0 |
All affected projects have been version-bumped (or no relevant files changed). |
1 |
At least one affected project has not been bumped — the check failed. |
2 |
Usage or argument error (bad input path, git not found, etc.). |
How it works
- Locates all
.csprojfiles from<input>. - Builds a dependency graph: for each project, which files it owns and which other projects it references via
<ProjectReference>. - Collects changed files by unioning: committed diff (
<base>...<head>), staged changes, unstaged tracked changes, and untracked new files — so it works both in a PR context and with local uncommitted modifications. - Determines affected projects transitively: if a library changes, every project that depends on it (directly or indirectly) is also considered affected.
- For each affected project, reads the version on
<base>(viagit show) and compares it to the version in the working tree. - Reports the result and exits with code
1if any version was not bumped.
Examples
# Check current directory against origin/main (default, both are equivalent)
dotnet-version check
dotnet-version check --base origin/main
# Scope to a specific solution file
dotnet-version check --input MySolution.slnx --base origin/main
dotnet-version check -i MySolution.slnx -b origin/main
# Table output
dotnet-version check --input MySolution.slnx --base origin/main --output table
# Single project, bare version output (useful for scripts)
dotnet-version check --input src/MyLib/MyLib.csproj --base origin/main --output version
# Only check projects that produce a NuGet package
dotnet-version check --input MySolution.slnx --base origin/main --filter "GeneratePackageOnBuild=true"
Sample JSON output
[
{
"Name": "MyLib",
"FilePath": "src/MyLib/MyLib.csproj",
"HeadVersion": "2.0.0",
"BaseVersion": "1.0.0",
"Status": "Ok"
},
{
"Name": "MyApp",
"FilePath": "src/MyApp/MyApp.csproj",
"HeadVersion": "3.1.0",
"BaseVersion": "3.1.0",
"Status": "BumpRequired"
}
]
Possible Status values:
| Value | Meaning |
|---|---|
Ok |
No relevant files changed, or the version was bumped. |
BumpRequired |
Files changed but the version is the same as on the base branch. |
NewProject |
The project did not exist on the base branch — no bump required. |
Sample table output
| Name | HeadVersion | BaseVersion | Status |
|-------|-------------|-------------|--------------|
| MyLib | 2.0.0 | 1.0.0 | Ok |
| MyApp | 3.1.0 | 3.1.0 | BumpRequired |
GitHub Actions integration
name: Check version bumps
on:
pull_request:
branches: [main]
jobs:
check-versions:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # full history is required for git diff
- uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x
- name: Install dotnet-version
run: dotnet tool install --global DotnetVersionReader
- name: Check version bumps
run: dotnet-version check --input MySolution.slnx --base origin/main
Important:
fetch-depth: 0(or at least enough history to reach the base branch) is required; a shallow clone will causegit diffto fail.
dotnet-version diff — show version changes relative to a base branch
Shows all projects whose version has changed (or that are brand-new) compared to a base branch.
Unlike check, this command never exits with a non-zero code based on results — it is a
pure informational diff, useful for release notes, changelogs, or scripting.
dotnet-version diff [--base <ref>] [--input <path>] [--head <ref>] [--output <format>] [--filter <XmlNode=Value>]...
# Short aliases (--base defaults to origin/main):
dotnet-version diff [-b <ref>] [-i <path>] [--head <ref>] [-o <format>] [-f <XmlNode=Value>]...
Options
| Option | Short | Description |
|---|---|---|
--input |
-i |
Path to a .csproj, .sln, .slnx file or a folder. Defaults to the current directory. |
--base |
-b |
The git ref to compare against. Defaults to origin/main. |
--head |
The git ref for the current state. Defaults to HEAD. |
|
--output |
-o |
Output format: json (default), table, list, or version (single project only). |
--filter |
-f |
Filter in the form XmlNode=Value. Only matching projects are considered. Value can be a regex. Repeatable. |
Exit codes
| Code | Meaning |
|---|---|
0 |
Command completed successfully (regardless of how many projects changed). |
2 |
Usage or argument error (bad input path, git not found, etc.). |
How it works
Uses the same git/dependency-graph pipeline as check (steps 1–4 are identical), but at step 5
only keeps projects whose version on <head> differs from the version on <base> (or projects
that are brand-new). Projects whose version is unchanged are silently omitted.
Examples
# Show changed versions against origin/main (default)
dotnet-version diff
dotnet-version diff --base origin/main
# Scope to a specific solution file
dotnet-version diff --input MySolution.slnx --base origin/main
dotnet-version diff -i MySolution.slnx -b origin/main
# Table output
dotnet-version diff --input MySolution.slnx --base origin/main --output table
# Simple list output – handy for release notes
dotnet-version diff --input MySolution.slnx --base origin/main --output list
# Only projects that produce a NuGet package
dotnet-version diff --input MySolution.slnx --base origin/main --filter "GeneratePackageOnBuild=true"
Sample JSON output
[
{
"Name": "MyLib",
"FilePath": "src/MyLib/MyLib.csproj",
"HeadVersion": "2.0.0",
"BaseVersion": "1.0.0",
"Status": "Bumped"
},
{
"Name": "MyNewLib",
"FilePath": "src/MyNewLib/MyNewLib.csproj",
"HeadVersion": "1.0.0",
"BaseVersion": null,
"Status": "NewProject"
}
]
Possible Status values:
| Value | Meaning |
|---|---|
Bumped |
The version was bumped relative to the base branch. |
NewProject |
The project did not exist on the base branch. |
Sample table output
| Name | HeadVersion | BaseVersion | Status |
|-----------|-------------|-------------|------------|
| MyLib | 2.0.0 | 1.0.0 | Bumped |
| MyNewLib | 1.0.0 | | NewProject |
Sample list output
MyLib 2.0.0
MyNewLib 1.0.0
Development
# Restore & build
dotnet build DotnetVersionReader.slnx
# Run tests
dotnet test DotnetVersionReader.slnx
# Pack
dotnet pack DotnetVersionReader.slnx -c Release
CI / CD
The repository uses two GitHub Actions workflows.
check-version-bump.yml — PR gate
Runs on every pull request targeting main. Builds the tool from source and
runs dotnet-version check to ensure every NuGet-publishable project that
changed has had its version bumped.
dotnet-version check --input DotnetVersionReader.slnx --filter "GeneratePackageOnBuild=true"
The PR must pass this check before merging.
build-test-pack-publish.yml — publish on push to main
Runs automatically on every push to main and can also be triggered manually.
What the publish workflow does
| Step | Details |
|---|---|
| Restore | dotnet restore against the .slnx solution file |
| Build | dotnet build -c Release (no restore) |
| Test | dotnet test -c Release --no-build |
| Check version bumps | Runs dotnet-version check against the previous release tag — blocks publish if any package version was not bumped |
| Collect metadata | Runs the freshly built dotnet-version with the solution file and -f GeneratePackageOnBuild=true to enumerate all package names + versions |
| Tag commits | Pushes an annotated git tag per package (<Name>-v<Version>) plus one combined release tag |
| Publish to NuGet | Pushes every .nupkg to nuget.org with --skip-duplicate |
| GitHub Release | Creates a GitHub release on the combined tag and uploads all .nupkg files as assets |
Required repository secret
| Secret | Description |
|---|---|
NUGET_API_KEY |
API key from nuget.org with push permission for the package(s) |
Add it under Settings → Secrets and variables → Actions → New repository secret.
Manual dispatch
The workflow can be triggered manually from the Actions tab.
An optional slnx_file input lets you override the solution path
(default: DotnetVersionReader.slnx).
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
This package has no dependencies.