Merge pull request #1524 from dorssel/nbgv

Refactor to use Nerdbank.GitVersioning
This commit is contained in:
Frans van Dorsselaer authored and GitHub committed 2026-11-09 02:34:29 +01:00
commit 79ca1d3817
30 files changed
+244 -141

No files matched your search

+54
View File
@@ -0,0 +1,54 @@
<!--
SPDX-FileCopyrightText: 2026 Frans van Dorsselaer
SPDX-License-Identifier: GPL-3.0-only
-->
# GitHub Copilot Review Instructions
## 1. Maintainer-Driven Release Pipeline Intent
* **Accepted Human-in-the-Loop Assumption:**
Accept that builds executed on the `master` branch within the CI environment are intended to be "promotion-ready" stable releases.
The final validation, gating, and publishing of these artifacts are strictly the responsibility of the human maintainer, not the automation alone.
* **No Master Branch Restrictive Flags:**
Do not flag configurations or workflows that allow stable (non-prerelease) outputs on the `master` branch as a security or architectural risk.
This behavior is deliberate to support artifact promotion.
## 2. Validation of version.json and MSBuild Overrides
* **Intent of Overrides:**
Conditional properties in `.csproj` files designed to force prerelease tags (e.g., overriding `PublicRelease` or appending suffixes)
are intentional safety nets for local development, non-CI execution, or dirty Git statuses.
* **Approved Patterns:**
Approve MSBuild logic evaluating environment triggers like `$(CI)` or `$(GITHUB_ACTIONS)`.
Forcing non-CI or dirty builds into a prerelease state is desired, safe behavior and must not be flagged as unpredictable code.
## 3. Nerdbank.GitVersioning (NBGV) Context Awareness
* **Dual-Layer Versioning:**
Recognize that `version.json` dictates the base versioning hierarchy, while the `.csproj` file modifies the final
prerelease classification based on environmental state.
* **Empty Suffix Handling:**
If an MSBuild condition evaluates or clears a version property to achieve a stable NuGet package output on `master`,
do not flag this as a missing argument or logical omission.
This is the correct structural mechanism for NuGet compilation.
## 4. Static Analysis Scoping and Runtime Omissions
* **Accept Compilation-Simulation Limits:**
Acknowledge that deep verification of MSBuild target ordering (`BeforeTargets`/`AfterTargets`) and actual artifact
outputs cannot be evaluated via static text analysis. Do not block or flag PRs with "needs a closer look" due to the
absence of a live CI restore or build execution environment.
* **Permit High-Impact Metadata Modifications:**
Explicitly allow modifications affecting version computation, assembly metadata, CI environment variables
(e.g., `$(CI)`, `$(GITHUB_ACTIONS)`), and NuGet package naming schemes. If the declarative syntax is logically sound
and aligns with Section 2 and 3 patterns, approve the configuration change.
* **Defer to Live CI Validation:**
Treat the actual validation of build outputs and target executions as the responsibility of the real CI runtime
pipeline. If the structural XML is valid, approve the pull request.
+10 -4
View File
@@ -52,6 +52,12 @@ jobs:
dotnet restore
dotnet restore Installer
- name: GitVersioning
run: |
dotnet build --configuration Release --no-restore `
--property:NBGV_SetCloudBuildVersionVars=true `
--target:Win32ResourceGenerator:GetBuildVersion,Win32ResourceGenerator:SetCloudBuildVersionVars
- name: Build x64
run: |
dotnet build --configuration Release --no-restore --property:Platform=x64 `
@@ -85,27 +91,27 @@ jobs:
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
archive: false
path: Installer/bin/x64/Release/usbipd-win_${{ env.GitVersion_MajorMinorPatch }}_x64.msi
path: Installer/bin/x64/Release/usbipd-win_${{ env.NBGV_NuGetPackageVersion }}_x64.msi
- name: Upload arm64 Installer
id: upload-arm64
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
archive: false
path: Installer/bin/arm64/Release/usbipd-win_${{ env.GitVersion_MajorMinorPatch }}_arm64.msi
path: Installer/bin/arm64/Release/usbipd-win_${{ env.NBGV_NuGetPackageVersion }}_arm64.msi
- name: Build x64 Attestation
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4.2.2
with:
subject-name: usbipd-win_${{ env.GitVersion_MajorMinorPatch }}_x64.msi
subject-name: usbipd-win_${{ env.NBGV_NuGetPackageVersion }}_x64.msi
subject-digest: sha256:${{ steps.upload-x64.outputs.artifact-digest }}
- name: Build arm64 Attestation
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4.2.2
with:
subject-name: usbipd-win_${{ env.GitVersion_MajorMinorPatch }}_arm64.msi
subject-name: usbipd-win_${{ env.NBGV_NuGetPackageVersion }}_arm64.msi
subject-digest: sha256:${{ steps.upload-arm64.outputs.artifact-digest }}
- name: Upload test results to Codecov
+27 -8
View File
@@ -42,8 +42,12 @@ SPDX-License-Identifier: GPL-3.0-only
<GenerateDocumentationFile>false</GenerateDocumentationFile>
<PublishDocumentationFiles>false</PublishDocumentationFiles>
<!-- GitVersion will handle this -->
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<!-- Nerdbank.GitVersioning -->
<GitVersionBaseDirectory>$(MSBuildThisFileDirectory)</GitVersionBaseDirectory>
<PublicRelease Condition="!$(ContinuousIntegrationBuild)">false</PublicRelease>
<PublicRelease Condition="'$(GITHUB_REF_NAME)' != 'master'">false</PublicRelease>
<PublicRelease Condition="'$(Configuration)' != 'Release'">false</PublicRelease>
<NBGV_SetCloudBuildVersionVars Condition="'$(NBGV_SetCloudBuildVersionVars)' != 'true'">false</NBGV_SetCloudBuildVersionVars>
<!-- Bump MSTest.Sdk "transitive" dependencies (they are actually direct dependencies) -->
<!-- none at this time -->
@@ -60,20 +64,35 @@ SPDX-License-Identifier: GPL-3.0-only
<!-- Required for Dependabot -->
<PropertyGroup Label="Dependabot" Condition="'$(DEPENDABOT)' == 'true'">
<RestoreLockedMode>false</RestoreLockedMode>
<GitVersion_AllowShallowEnabled>true</GitVersion_AllowShallowEnabled>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="GitVersion.MsBuild" PrivateAssets="all" />
<PackageReference Include="Nerdbank.GitVersioning" PrivateAssets="all" />
</ItemGroup>
<Target Name="SetCopyright" AfterTargets="GetVersion">
<ItemGroup>
<PrereleaseIdentifier Condition="!$(ContinuousIntegrationBuild)" Include="private" />
<PrereleaseIdentifier Condition="'$(GITHUB_REF_NAME)' != 'master'" Include="dev" />
<PrereleaseIdentifier Condition="'$(Configuration)' != 'Release'" Include="debug" />
</ItemGroup>
<Target Name="VersioningFixups" AfterTargets="GetBuildVersion">
<PropertyGroup>
<!-- For deterministic builds, use the commit year as the copyright year. -->
<CopyrightYear Condition="$(ContinuousIntegrationBuild)">$([System.DateTime]::Parse($(GitVersion_CommitDate)).ToString("yyyy"))</CopyrightYear>
<CopyrightYear Condition="!$(ContinuousIntegrationBuild)">$([System.DateTime]::UtcNow.ToString("yyyy"))</CopyrightYear>
<Copyright>Copyright (C) $(CopyrightYear) $(Company)</Copyright>
<Copyright>Copyright © $([System.DateTime]::new($(GitCommitDateTicks)).Year) $(Company)</Copyright>
<!-- We want the full commit hash in the InformationalVersion (but not in the NuGet package version, which has a limit of 64 characters). -->
<AssemblyInformationalVersion>$(AssemblyInformationalVersion.Split('+')[0])+$(GitCommitId)</AssemblyInformationalVersion>
<!-- We inject the GitHub run-number as the fourth component of the file version. 0 means "no CI build number" (i.e. a non-CI build). -->
<AssemblyFileVersion Condition="'$(GITHUB_RUN_NUMBER)' != ''">$(BuildVersion3Components).$(GITHUB_RUN_NUMBER)</AssemblyFileVersion>
<AssemblyFileVersion Condition="'$(GITHUB_RUN_NUMBER)' == ''">$(BuildVersion3Components).0</AssemblyFileVersion>
</PropertyGroup>
<ItemGroup>
<AdditionalThisAssemblyFields Include="Company" String="$(Company)" />
<AdditionalThisAssemblyFields Include="Copyright" String="$(Copyright)" />
<AdditionalThisAssemblyFields Include="GitVersionHeight" String="$(GitVersionHeight)" />
<AdditionalThisAssemblyFields Include="NuGetPackageVersion" String="$(NuGetPackageVersion)" />
<AdditionalThisAssemblyFields Include="Product" String="$(Product)" />
</ItemGroup>
</Target>
</Project>
+1 -2
View File
@@ -7,7 +7,7 @@ SPDX-License-Identifier: GPL-3.0-only
<Project>
<ItemGroup>
<!-- all -->
<PackageVersion Include="GitVersion.MsBuild" Version="6.8.2" />
<PackageVersion Include="Nerdbank.GitVersioning" Version="3.10.94" />
<!-- Usbipd -->
<PackageVersion Include="Microsoft.Extensions.Hosting.WindowsServices" Version="10.0.14" />
<PackageVersion Include="Microsoft.Windows.CsWin32" Version="0.3.367" />
@@ -15,7 +15,6 @@ SPDX-License-Identifier: GPL-3.0-only
<!-- Usbipd.PowerShell -->
<PackageVersion Include="PowerShellStandard.Library" Version="5.1.1" />
<!-- Installer -->
<PackageVersion Include="Dorssel.GitVersion.MsBuild" Version="2.1.0" />
<PackageVersion Include="WixToolset.Firewall.wixext" Version="7.0.1" />
<PackageVersion Include="WixToolset.UI.wixext" Version="7.0.1" />
<PackageVersion Include="WixToolset.Util.wixext" Version="7.0.1" />
-8
View File
@@ -1,8 +0,0 @@
# SPDX-FileCopyrightText: 2020 Frans van Dorsselaer
#
# SPDX-License-Identifier: GPL-3.0-only
---
# yaml-language-server: $schema=https://raw.githubusercontent.com/GitTools/GitVersion/main/schemas/6.3/GitVersion.configuration.json
assembly-file-versioning-format: '{Major}.{Minor}.{Patch}.{env:GITHUB_RUN_NUMBER ?? 0}'
-1
View File
@@ -9,7 +9,6 @@ SPDX-License-Identifier: GPL-3.0-only
<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)..\'))" />
<ItemGroup>
<PackageReference Include="Dorssel.GitVersion.MsBuild" PrivateAssets="all" />
<PackageReference Include="WixToolset.Firewall.wixext" />
<PackageReference Include="WixToolset.UI.wixext" />
<PackageReference Include="WixToolset.Util.wixext" />
+29 -30
View File
@@ -9,8 +9,7 @@ SPDX-License-Identifier: GPL-3.0-only
<AcceptEula>wix7</AcceptEula>
<Platforms>x64;ARM64</Platforms>
<RuntimeIdentifiers>win-x64;win-arm64</RuntimeIdentifiers>
<OutputName>usbipd-win</OutputName>
<DefineConstants>Copyright=$(Copyright)</DefineConstants>
<OutputName>$(Product)</OutputName>
<Pedantic>true</Pedantic>
<BuildProjectReferences>false</BuildProjectReferences>
</PropertyGroup>
@@ -22,34 +21,34 @@ SPDX-License-Identifier: GPL-3.0-only
<BindPath Include="..\Usbipd\bin\publish\$(Platform)" />
<BindPath Include="..\Usbipd.PowerShell\bin\publish" />
</ItemGroup>
<Target Name="SetTarget" AfterTargets="GetVersion">
<!--
Now that we have determined the version, augment the OutputName to include the version number.
-->
<Message Importance="high" Text="Version detected as $(GitVersion_FullSemVer)" />
<CreateProperty Value="$(OutputName)_$(GitVersion_MajorMinorPatch)_$(Platform.ToLowerInvariant())">
<Output TaskParameter="Value" PropertyName="TargetName" />
</CreateProperty>
<CreateProperty Value="$(TargetName)$(TargetExt)">
<Output TaskParameter="Value" PropertyName="TargetFileName" />
</CreateProperty>
<CreateProperty Value="$(TargetDir)$(TargetFileName)">
<Output TaskParameter="Value" PropertyName="TargetPath" />
</CreateProperty>
<CreateProperty Value="$(TargetName).wixpdb">
<Output TaskParameter="Value" PropertyName="TargetPdbFileName" />
</CreateProperty>
<CreateProperty Value="$(TargetPdbDir)$(TargetPdbFileName)">
<Output TaskParameter="Value" PropertyName="TargetPdbPath" />
</CreateProperty>
<!--
This ensures that each x.y.z version has a different ProductCode, so every update is a MajorUpgrade.
It also ensures that 2 builds of the same x.y.z version will never be installed simultaneously.
The alternative (WiX AllowSameVersionUpgrades) causes ICE61.
-->
<CreateProperty Value="$(DefineConstants);ProductCode=EA1D5623-E6A7-4E4A-9259-E39722$([System.Byte]::Parse($(GitVersion_Major)).ToString(X2))$([System.Byte]::Parse($(GitVersion_Minor)).ToString(X2))$([System.Byte]::Parse($(GitVersion_Patch)).ToString(X2))">
<Output TaskParameter="Value" PropertyName="DefineConstants" />
</CreateProperty>
<Target Name="SetTarget" DependsOnTargets="GetBuildVersion" AfterTargets="VersioningFixups" BeforeTargets="BeforeBuild">
<Message Importance="high" Text="Version detected as $(NuGetPackageVersion)" />
<PropertyGroup>
<!--
Now that we have determined the version, augment the OutputName to include the version number.
-->
<TargetName>$(OutputName)_$(NuGetPackageVersion)_$(Platform.ToLowerInvariant())</TargetName>
<TargetFileName>$(TargetName)$(TargetExt)</TargetFileName>
<TargetPath>$(TargetDir)$(TargetFileName)</TargetPath>
<TargetPdbFileName>$(TargetName).wixpdb</TargetPdbFileName>
<TargetPdbPath>$(TargetPdbDir)$(TargetPdbFileName)</TargetPdbPath>
<BuildVersionMajor>$([System.Version]::Parse('$(BuildVersion)').Major)</BuildVersionMajor>
<BuildVersionMinor>$([System.Version]::Parse('$(BuildVersion)').Minor)</BuildVersionMinor>
<BuildVersionBuild>$([System.Version]::Parse('$(BuildVersion)').Build)</BuildVersionBuild>
<DefineConstants>$(DefineConstants);Product=$(Product)</DefineConstants>
<DefineConstants>$(DefineConstants);Company=$(Company)</DefineConstants>
<DefineConstants>$(DefineConstants);Copyright=$(Copyright)</DefineConstants>
<DefineConstants>$(DefineConstants);NuGetPackageVersion=$(NuGetPackageVersion)</DefineConstants>
<DefineConstants>$(DefineConstants);BuildVersion3Components=$(BuildVersion3Components)</DefineConstants>
<!--
This ensures that each x.y.z version has a different ProductCode, so every update is a MajorUpgrade.
It also ensures that 2 builds of the same x.y.z version will never be installed simultaneously.
The alternative (WiX AllowSameVersionUpgrades) causes ICE61.
-->
<DefineConstants>$(DefineConstants);ProductCode=EA1D5623-E6A7-4E4A-9259-E39722$([System.Byte]::Parse($(BuildVersionMajor)).ToString(X2))$([System.Byte]::Parse($(BuildVersionMinor)).ToString(X2))$([System.Byte]::Parse($(BuildVersionBuild)).ToString(X2))</DefineConstants>
</PropertyGroup>
</Target>
<Target Name="AssumePublishedDependencies" BeforeTargets="BeforeBuild">
<Message Importance="high" Text="Making installer for (assumed) pre-published Usbipd and Usbipd.PowerShell" />
+3 -4
View File
@@ -10,11 +10,10 @@ SPDX-License-Identifier: GPL-3.0-only
>
<Package
ProductCode="$(var.ProductCode)"
Name="usbipd-win"
Name="$(var.Product)"
Language="1033"
Codepage="0"
Version="$(var.GitVersion_MajorMinorPatch)"
Manufacturer="Frans van Dorsselaer"
Version="$(var.BuildVersion3Components)"
Manufacturer="$(var.Company)"
UpgradeCode="{EA1D5623-E6A7-4E4A-9259-E3972226646F}"
UpgradeStrategy="majorUpgrade"
InstallerVersion="500"
+1 -1
View File
@@ -69,7 +69,7 @@ SPDX-License-Identifier: GPL-3.0-only
-->
<RegistryKey Root="HKLM" Key="SOFTWARE\usbipd-win" ForceDeleteOnUninstall="yes">
<RegistryValue Name="APPLICATIONFOLDER" Type="string" Value="[APPLICATIONFOLDER]" />
<RegistryValue Name="Version" Type="string" Value="$(var.GitVersion_MajorMinorPatch)" />
<RegistryValue Name="Version" Type="string" Value="$(var.NuGetPackageVersion)" />
<RegistryKey
Key="Devices"
ForceCreateOnInstall="yes"
+4 -10
View File
@@ -2,17 +2,11 @@
"version": 2,
"dependencies": {
"native,Version=v0.0": {
"Dorssel.GitVersion.MsBuild": {
"Nerdbank.GitVersioning": {
"type": "Direct",
"requested": "[2.1.0, )",
"resolved": "2.1.0",
"contentHash": "Dkiov8KyUy9JQHkFmcnkWfxC1MGCqBwLBSdCBaU3q7KLgcWS2qU6qriVbDURk21zZQseEub5LgwqEOwv3KFoxw=="
},
"GitVersion.MsBuild": {
"type": "Direct",
"requested": "[6.8.2, )",
"resolved": "6.8.2",
"contentHash": "eTd8jUiogUXpVssFyDWWdMrPr5Cdc57tWaQ3Cv/eMIhnumOHZhDkc/wcy8hYU8aH7NS4VT2w/pHjVITDSTXMGw=="
"requested": "[3.10.94, )",
"resolved": "3.10.94",
"contentHash": "sn6gFIx6bwFj3Me0XGmek3gLZi/MZC8C4tRLwslXGeBcXcVxvFpZyDrQA93G8TiYgxTS7J7triKB7hj5wXzSxA=="
},
"WixToolset.Firewall.wixext": {
"type": "Direct",
+1 -1
View File
@@ -8,7 +8,7 @@ SPDX-License-Identifier: GPL-3.0-only
[![REUSE status](https://api.reuse.software/badge/github.com/dorssel/usbipd-win)](https://api.reuse.software/info/github.com/dorssel/usbipd-win)
[![Codecov](https://codecov.io/gh/dorssel/usbipd-win/branch/master/graph/badge.svg?token=L0QI0AZRJI)](https://codecov.io/gh/dorssel/usbipd-win)
[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/dorssel/usbipd-win/badge)](https://scorecard.dev/viewer/?uri=github.com/dorssel/usbipd-win)
[![OpenSSF Scorecard](https://img.shields.io/ossf-scorecard/github.com/dorssel/usbipd-win?label=openssf%20scorecard)](https://scorecard.dev/viewer/?uri=github.com/dorssel/usbipd-win)
[![GitHub all releases](https://img.shields.io/github/downloads/dorssel/usbipd-win/total?logo=github)](https://github.com/dorssel/usbipd-win/releases)
Windows software for sharing locally connected USB devices to other machines, including Hyper-V guests and WSL 2.
+1 -1
View File
@@ -41,7 +41,7 @@ sealed class CommandHandlersCli_Tests
using var usbipdKey = TestRegistry.CreateSubKey(@"SOFTWARE\usbipd-win");
usbipdKey.SetValue("APPLICATIONFOLDER", AppDomain.CurrentDomain.BaseDirectory);
#pragma warning disable CS0436 // Type conflicts with imported type
usbipdKey.SetValue("Version", GitVersionInformation.MajorMinorPatch);
usbipdKey.SetValue("Version", ThisAssembly.NuGetPackageVersion);
#pragma warning restore CS0436 // Type conflicts with imported type
using var devicesKey = usbipdKey.CreateSubKey("Devices");
using var policyKey = usbipdKey.CreateSubKey("Policy");
+1
View File
@@ -17,3 +17,4 @@ using System.Diagnostics.CodeAnalysis;
Justification = "Some unit tests require reflection")]
[assembly: SuppressMessage("Style", "IDE0053:Use expression body for lambda expression", Justification = "Better readability for Assert.ThrowsExactly")]
[assembly: SuppressMessage("Style", "IDE0058:Expression value is never used", Justification = "Not useful for tests")]
[assembly: SuppressMessage("Usage", "MSTEST0084:Platform compatibility attributes should be consistent with '[OSCondition]'", Justification = "Everything is Windows only")]
+1 -1
View File
@@ -41,7 +41,7 @@ sealed class UsbipdRegistry_Tests
using var usbipdKey = TestRegistry.CreateSubKey(@"SOFTWARE\usbipd-win");
usbipdKey.SetValue("APPLICATIONFOLDER", AppDomain.CurrentDomain.BaseDirectory);
#pragma warning disable CS0436 // Type conflicts with imported type
usbipdKey.SetValue("Version", GitVersionInformation.MajorMinorPatch);
usbipdKey.SetValue("Version", ThisAssembly.NuGetPackageVersion);
#pragma warning restore CS0436 // Type conflicts with imported type
using var devicesKey = usbipdKey.CreateSubKey("Devices");
using var policyKey = usbipdKey.CreateSubKey("Policy");
+6 -6
View File
@@ -2,12 +2,6 @@
"version": 2,
"dependencies": {
"net10.0-windows10.0.17763": {
"GitVersion.MsBuild": {
"type": "Direct",
"requested": "[6.8.2, )",
"resolved": "6.8.2",
"contentHash": "eTd8jUiogUXpVssFyDWWdMrPr5Cdc57tWaQ3Cv/eMIhnumOHZhDkc/wcy8hYU8aH7NS4VT2w/pHjVITDSTXMGw=="
},
"JunitXml.TestLogger": {
"type": "Direct",
"requested": "[8.1.0, )",
@@ -84,6 +78,12 @@
"MSTest.Analyzers": "4.5.2"
}
},
"Nerdbank.GitVersioning": {
"type": "Direct",
"requested": "[3.10.94, )",
"resolved": "3.10.94",
"contentHash": "sn6gFIx6bwFj3Me0XGmek3gLZi/MZC8C4tRLwslXGeBcXcVxvFpZyDrQA93G8TiYgxTS7J7triKB7hj5wXzSxA=="
},
"Castle.Core": {
"type": "Transitive",
"resolved": "5.2.1",
+4 -3
View File
@@ -68,14 +68,15 @@ static class Installation
var applicationFolder = GetRegistryStringValue(stdout, "APPLICATIONFOLDER");
var exeFile = Path.Combine(Path.GetFullPath(applicationFolder), "usbipd.exe");
if (!Version.TryParse(GetRegistryStringValue(stdout, "Version"), out var version) || !File.Exists(exeFile))
if (!File.Exists(exeFile))
{
throw new ApplicationFailedException("usbipd-win is not installed.");
}
if (version != Version.Parse(GitVersionInformation.MajorMinorPatch))
var installedVersion = GetRegistryStringValue(stdout, "Version");
if (installedVersion != ThisAssembly.NuGetPackageVersion)
{
throw new ApplicationFailedException(
$"PowerShell module version {GitVersionInformation.MajorMinorPatch} does not match installed usbipd-win version {version}.");
$"PowerShell module version {ThisAssembly.NuGetPackageVersion} does not match installed usbipd-win version {installedVersion}.");
}
#if DEBUG
return Path.GetFullPath(Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetCallingAssembly().Location),
+4 -4
View File
@@ -2,11 +2,11 @@
"version": 2,
"dependencies": {
".NETStandard,Version=v2.0": {
"GitVersion.MsBuild": {
"Nerdbank.GitVersioning": {
"type": "Direct",
"requested": "[6.8.2, )",
"resolved": "6.8.2",
"contentHash": "eTd8jUiogUXpVssFyDWWdMrPr5Cdc57tWaQ3Cv/eMIhnumOHZhDkc/wcy8hYU8aH7NS4VT2w/pHjVITDSTXMGw=="
"requested": "[3.10.94, )",
"resolved": "3.10.94",
"contentHash": "sn6gFIx6bwFj3Me0XGmek3gLZi/MZC8C4tRLwslXGeBcXcVxvFpZyDrQA93G8TiYgxTS7J7triKB7hj5wXzSxA=="
},
"NETStandard.Library": {
"type": "Direct",
+2 -2
View File
@@ -74,8 +74,8 @@ sealed partial class CommandHandlers : ICommandHandlers
// 70 leads (approximately) to the GPL default.
var width = console.IsOutputRedirected ? 70 : console.WindowWidth;
foreach (var line in Wrap($"""
{Program.Product} {GitVersionInformation.MajorMinorPatch}
{Program.Copyright}
{ThisAssembly.Product} {ThisAssembly.NuGetPackageVersion}
{ThisAssembly.Copyright}
This program is free software: you can redistribute it and/or modify \
it under the terms of the GNU General Public License as published by \
+1 -1
View File
@@ -447,7 +447,7 @@ sealed partial class PcapNg
block.Write((ushort)0); // minor PcapNg version
block.Write(0xffffffffffffffff); // unspecified section size
AddOption(block, 3, $"{Environment.OSVersion.VersionString}"); // shb_os
AddOption(block, 4, $"{Program.Product} {GitVersionInformation.InformationalVersion}"); // shb_userappl
AddOption(block, 4, $"{ThisAssembly.Product} {ThisAssembly.NuGetPackageVersion}"); // shb_userappl
return FinishBlock(block);
}
+1 -5
View File
@@ -12,16 +12,12 @@ using System.Diagnostics;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Reflection;
using Usbipd.Automation;
namespace Usbipd;
static class Program
{
public static readonly string Product = Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyProductAttribute>()!.Product;
public static readonly string Copyright = Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyCopyrightAttribute>()!.Copyright;
static void AddParseError<T>(ArgumentResult argumentResult)
{
var value = argumentResult.Tokens[0].Value;
@@ -182,7 +178,7 @@ static class Program
public override int Invoke(ParseResult parseResult)
{
// Always prepend the product and version.
parseResult.InvocationConfiguration.Output.WriteLine($"{Product} {GitVersionInformation.MajorMinorPatch}");
parseResult.InvocationConfiguration.Output.WriteLine($"{ThisAssembly.Product} {ThisAssembly.NuGetPackageVersion}");
parseResult.InvocationConfiguration.Output.WriteLine();
var command = parseResult.CommandResult.Command;
+1 -1
View File
@@ -82,7 +82,7 @@ sealed partial class Server : BackgroundService
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
Logger.Debug(GitVersionInformation.InformationalVersion);
Logger.Debug(ThisAssembly.AssemblyInformationalVersion);
// Cleanup any left-overs in case the previous instance crashed.
_ = UsbipdRegistry.Instance.SetAllDevicesAsDetached();
+1
View File
@@ -20,6 +20,7 @@ SPDX-License-Identifier: GPL-3.0-only
<OptimizationPreference>Speed</OptimizationPreference>
<AssemblyName>usbipd</AssemblyName>
<AssemblyTitle>USB/IP Server</AssemblyTitle>
</PropertyGroup>
<ItemGroup>
+6 -6
View File
@@ -2,12 +2,6 @@
"version": 2,
"dependencies": {
"net10.0-windows10.0.17763": {
"GitVersion.MsBuild": {
"type": "Direct",
"requested": "[6.8.2, )",
"resolved": "6.8.2",
"contentHash": "eTd8jUiogUXpVssFyDWWdMrPr5Cdc57tWaQ3Cv/eMIhnumOHZhDkc/wcy8hYU8aH7NS4VT2w/pHjVITDSTXMGw=="
},
"Microsoft.DotNet.ILCompiler": {
"type": "Direct",
"requested": "[10.0.14, )",
@@ -42,6 +36,12 @@
"Microsoft.Windows.WDK.Win32Metadata": "0.13.25-experimental"
}
},
"Nerdbank.GitVersioning": {
"type": "Direct",
"requested": "[3.10.94, )",
"resolved": "3.10.94",
"contentHash": "sn6gFIx6bwFj3Me0XGmek3gLZi/MZC8C4tRLwslXGeBcXcVxvFpZyDrQA93G8TiYgxTS7J7triKB7hj5wXzSxA=="
},
"System.CommandLine": {
"type": "Direct",
"requested": "[2.0.14, )",
@@ -10,7 +10,7 @@
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
VS_VERSION_INFO VERSIONINFO
FILEVERSION VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, CI_BUILD_NUMBER
FILEVERSION VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, GITHUB_RUN_NUMBER
PRODUCTVERSION VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, COMMITS_SINCE_VERSION_SOURCE
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
FILEFLAGS FILE_FLAGS
@@ -23,9 +23,9 @@ BEGIN
BLOCK "{{BlockCulture}}"
BEGIN
VALUE "CompanyName", "{{CompanyName}}"
VALUE "FileDescription", "Utility for sharing locally connected USB devices to other machines"
VALUE "FileDescription", "{{FileDescription}}"
VALUE "FileVersion", "{{FileVersion}}"
VALUE "InternalName", "usbipd"
VALUE "InternalName", "{{InternalName}}"
VALUE "LegalCopyright", "{{LegalCopyright}}"
VALUE "OriginalFilename", "usbipd.exe"
VALUE "ProductName", "{{ProductName}}"
+56 -30
View File
@@ -8,6 +8,7 @@ using System.Globalization;
using System.Reflection;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Windows.Win32;
using Windows.Win32.Storage.FileSystem;
@@ -20,8 +21,6 @@ public class Generator : IIncrementalGenerator
readonly byte[] Resources;
readonly FileVersionInfo FileVersionInfo;
readonly string EventManifestTemplate;
readonly string VersionInfoTemplate;
@@ -69,11 +68,22 @@ public class Generator : IIncrementalGenerator
VersionInfoTemplate = reader.ReadToEnd();
}
}
// Our own FileVersionInfo is used to generate the VersionInfo.rc file.
FileVersionInfo = FileVersionInfo.GetVersionInfo(assembly.Location);
}
}
static BuildOptions CreateTargetBuildOptions(AnalyzerConfigOptionsProvider provider)
{
// NOTE: We need to box the struct in order to set its properties through reflection.
object buildOptions = new BuildOptions();
foreach (var p in typeof(BuildOptions).GetProperties())
{
_ = provider.GlobalOptions.TryGetValue($"build_property.{p.Name}", out var value);
p.SetValue(buildOptions, value ?? string.Empty);
}
// Unbox the struct and return it.
return (BuildOptions)buildOptions;
}
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// We need to filter out generated sources, which either have no file path or end with .g.cs.
@@ -84,20 +94,23 @@ public class Generator : IIncrementalGenerator
&& !syntaxNode.SyntaxTree.FilePath.EndsWith(".g.cs", StringComparison.OrdinalIgnoreCase),
(context, _) => LoggerMessage.Create(context));
var buildOptions = context.AnalyzerConfigOptionsProvider.Select((provider, ct) =>
{
_ = provider.GlobalOptions.TryGetValue("build_property.ProjectDir", out var projectDir);
_ = provider.GlobalOptions.TryGetValue("build_property.intermediateOutputPath", out var intermediateOutputPath);
_ = provider.GlobalOptions.TryGetValue("build_property.Configuration", out var configuration);
return new BuildOptions(projectDir ?? string.Empty, intermediateOutputPath ?? string.Empty, configuration ?? string.Empty);
});
var buildOptions = context.AnalyzerConfigOptionsProvider.Select((provider, cancellationToken) => CreateTargetBuildOptions(provider));
var loggerMessagesWithOptions = loggerMessages.Collect().Combine(buildOptions);
// We need to access ThisAssembly *from the target project* (because the generator always uses Release build itself).
var messagesAndOptionsAndCompiler = loggerMessages.Collect().Combine(buildOptions).Combine(context.CompilationProvider);
context.RegisterSourceOutput(loggerMessagesWithOptions, (context, loggerMessagesWithOptions) =>
context.RegisterSourceOutput(messagesAndOptionsAndCompiler, (context, messagesAndOptionsAndCompiler) =>
{
var loggerMessages = loggerMessagesWithOptions.Left;
var buildOptions = loggerMessagesWithOptions.Right;
var loggerMessages = messagesAndOptionsAndCompiler.Left.Left;
var buildOptions = messagesAndOptionsAndCompiler.Left.Right;
var compilation = messagesAndOptionsAndCompiler.Right;
var targetAssembly = compilation.GetTypeByMetadataName("ThisAssembly");
if (targetAssembly is null)
{
// ThisAssembly is not available in the target project (yet), so we cannot generate the Win32 resources.
return;
}
var seenIds = new Dictionary<int, LoggerMessage>();
var hasErrors = false;
@@ -185,7 +198,7 @@ public class Generator : IIncrementalGenerator
var applicationManifest = File.ReadAllBytes(Path.Combine(buildOptions.ProjectDir, "app.manifest"));
_ = UpdateIfContentChanged(Path.Combine(generatorOutputDir, "app.manifest"), applicationManifest);
_ = GenerateVersionInfo(generatorOutputDir, buildOptions.Configuration == "Release");
_ = GenerateVersionInfo(targetAssembly, generatorOutputDir, buildOptions);
if (IsUpdateRequired(generatorOutputDir,
["Resources.rc", "app.manifest", "VersionInfo.rc", "EventManifest.rc", "EventManifestTEMP.BIN", "MSG00001.bin"],
@@ -245,23 +258,32 @@ public class Generator : IIncrementalGenerator
return true;
}
bool GenerateVersionInfo(string generatorOutputDir, bool release)
static string GetConstantStringValue(INamedTypeSymbol typeSymbol, string fieldName)
{
var field = typeSymbol.GetMembers(fieldName).OfType<IFieldSymbol>().FirstOrDefault();
return field is not null && field.IsConst && field.HasConstantValue ? field.ConstantValue?.ToString() ?? string.Empty : string.Empty;
}
bool GenerateVersionInfo(INamedTypeSymbol targetAssembly, string generatorOutputDir, BuildOptions buildOptions)
{
var culture = new CultureInfo("en-US", false);
var versionInfoPath = Path.Combine(generatorOutputDir, "VersionInfo.rc");
var version = new Version(GitVersionInformation.AssemblySemFileVer);
var assemblyFileVersion = new Version(GetConstantStringValue(targetAssembly, "AssemblyFileVersion"));
VS_FIXEDFILEINFO_FILE_FLAGS fileFlags = 0;
string? privateBuild = null;
if (!release)
if (buildOptions.Configuration != "Release")
{
fileFlags |= VS_FIXEDFILEINFO_FILE_FLAGS.VS_FF_DEBUG | VS_FIXEDFILEINFO_FILE_FLAGS.VS_FF_PRIVATEBUILD;
privateBuild = "This is an unofficial (debug) build.";
}
else if (version.Revision == 0)
else if (assemblyFileVersion.Revision == 0)
{
// On official CI builds, the Revision field of the AssemblyFileVersion is set to the GITHUB_RUN_NUMBER.
// If it is 0, then this is a local build (not from CI).
fileFlags |= VS_FIXEDFILEINFO_FILE_FLAGS.VS_FF_PRIVATEBUILD;
privateBuild = "This is an unofficial (non-CI) build.";
}
@@ -274,22 +296,26 @@ public class Generator : IIncrementalGenerator
var versionInfoContent = VersionInfoTemplate
.Replace("VS_VERSION_INFO", $"{PInvoke.VS_VERSION_INFO}")
.Replace("VERSION_MAJOR", $"{version.Major}")
.Replace("VERSION_MINOR", $"{version.Minor}")
.Replace("VERSION_PATCH", $"{version.Build}")
.Replace("CI_BUILD_NUMBER", $"{version.Revision}")
.Replace("COMMITS_SINCE_VERSION_SOURCE", $"{GitVersionInformation.CommitsSinceVersionSource}")
.Replace("VERSION_MAJOR", $"{assemblyFileVersion.Major}")
.Replace("VERSION_MINOR", $"{assemblyFileVersion.Minor}")
.Replace("VERSION_PATCH", $"{assemblyFileVersion.Build}")
// GITHUB_RUN_NUMBER is stored in the Revision field of the numeric FILEVERSION (already available as the Revision of the AssemblyFileVersion).
.Replace("GITHUB_RUN_NUMBER", $"{assemblyFileVersion.Revision}")
// The commit height is stored in the Revision field of the numeric PRODUCTVERSION.
.Replace("COMMITS_SINCE_VERSION_SOURCE", GetConstantStringValue(targetAssembly, "GitVersionHeight"))
.Replace("VOS_NT_WINDOWS32", $"0x{(uint)VS_FIXEDFILEINFO_FILE_OS.VOS_NT_WINDOWS32:x8}L")
.Replace("VFT_APP", $"0x{(uint)VS_FIXEDFILEINFO_FILE_TYPE.VFT_APP:x8}L")
.Replace("VS_FFI_FILEFLAGSMASK", $"0x{PInvoke.VS_FFI_FILEFLAGSMASK:x8}L")
.Replace("FILE_FLAGS", $"0x{(uint)fileFlags:x8}L")
.Replace("{{OptionalPrivateBuild}}", privateBuild)
.Replace("{{BlockCulture}}", $"{culture.LCID:x4}{Encoding.Unicode.CodePage:x4}")
.Replace("{{CompanyName}}", $"{FileVersionInfo.CompanyName}")
.Replace("{{FileVersion}}", $"{FileVersionInfo.FileVersion}")
.Replace("{{LegalCopyright}}", $"{FileVersionInfo.LegalCopyright}")
.Replace("{{ProductName}}", $"{FileVersionInfo.ProductName}")
.Replace("{{ProductVersion}}", $"{FileVersionInfo.ProductVersion}")
.Replace("{{CompanyName}}", GetConstantStringValue(targetAssembly, "Company"))
.Replace("{{FileDescription}}", GetConstantStringValue(targetAssembly, "AssemblyTitle"))
.Replace("{{FileVersion}}", GetConstantStringValue(targetAssembly, "AssemblyInformationalVersion"))
.Replace("{{InternalName}}", GetConstantStringValue(targetAssembly, "AssemblyName"))
.Replace("{{LegalCopyright}}", GetConstantStringValue(targetAssembly, "Copyright"))
.Replace("{{ProductName}}", GetConstantStringValue(targetAssembly, "Product"))
.Replace("{{ProductVersion}}", GetConstantStringValue(targetAssembly, "NuGetPackageVersion"))
.Replace("{{LCID}}", $"{culture.LCID}")
.Replace("{{CodePage}}", $"{Encoding.Unicode.CodePage}")
;
@@ -12,7 +12,9 @@ SPDX-License-Identifier: GPL-3.0-only
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
<Configurations>Release</Configurations>
<Configuration>Release</Configuration>
<!-- We cannot use the version info injected into the generator itself, as the generator always uses Release build. -->
<NBGV_EmitThisAssemblyClass>false</NBGV_EmitThisAssemblyClass>
</PropertyGroup>
<ItemGroup>
+6 -6
View File
@@ -2,12 +2,6 @@
"version": 2,
"dependencies": {
".NETStandard,Version=v2.0": {
"GitVersion.MsBuild": {
"type": "Direct",
"requested": "[6.8.2, )",
"resolved": "6.8.2",
"contentHash": "eTd8jUiogUXpVssFyDWWdMrPr5Cdc57tWaQ3Cv/eMIhnumOHZhDkc/wcy8hYU8aH7NS4VT2w/pHjVITDSTXMGw=="
},
"Microsoft.CodeAnalysis.CSharp": {
"type": "Direct",
"requested": "[5.9.0, )",
@@ -43,6 +37,12 @@
"resolved": "10.0.28000.2957",
"contentHash": "nTsRheC9AO+if3BykWkRJ4QXkIMfkqufnBFPIcSEOj7rnX60fqiGrORnxzVFnIXJvsMIjlDOvs/K5EzMLA2RKQ=="
},
"Nerdbank.GitVersioning": {
"type": "Direct",
"requested": "[3.10.94, )",
"resolved": "3.10.94",
"contentHash": "sn6gFIx6bwFj3Me0XGmek3gLZi/MZC8C4tRLwslXGeBcXcVxvFpZyDrQA93G8TiYgxTS7J7triKB7hj5wXzSxA=="
},
"NETStandard.Library": {
"type": "Direct",
"requested": "[2.0.3, )",
+2 -2
View File
@@ -16,14 +16,14 @@ SPDX-License-Identifier: GPL-3.0-only
<File Path="Directory.Build.props" />
<File Path="Directory.Build.targets" />
<File Path="Directory.Packages.props" />
<File Path="GitVersion.yml" />
<File Path="global.json" />
<File Path="nuget.config" />
<File Path="Platform.Build.props" />
<File Path="README.md" />
<File Path="version.json" />
</Folder>
<Project Path="Win32ResourceGenerator/Win32ResourceGenerator.csproj">
<BuildType Solution="Debug|*" Project="Release" />
<BuildType Project="Release" />
</Project>
<Project Path="Installer/Installer.wixproj" Type="b7dd6f7e-def8-4e67-b5b7-07ef123db6f0">
<Build Project="false" />
+12
View File
@@ -0,0 +1,12 @@
{
"$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/NerdBank.GitVersioning/version.schema.json",
"version": "5.3.1",
"publicReleaseRefSpec": ["^refs/heads/master$"],
"gitCommitIdIncludeDirty": true,
"nugetPackageVersion": {
"semVer": 2
},
"cloudBuild": {
"setAllVariables": true
}
}
+3
View File
@@ -0,0 +1,3 @@
SPDX-FileCopyrightText: 2026 Frans van Dorsselaer
SPDX-License-Identifier: GPL-3.0-only