Skip to content

Commit

Permalink
Merge pull request #667 from dotnet/quickbuild2
Browse files Browse the repository at this point in the history
Add property that can disable the private MSBuild task invocation
  • Loading branch information
AArnott committed Oct 9, 2021
2 parents cb72788 + f0e05d1 commit a1d636e
Show file tree
Hide file tree
Showing 12 changed files with 218 additions and 67 deletions.
55 changes: 55 additions & 0 deletions doc/quickbuild.md
@@ -0,0 +1,55 @@
# Microsoft's (internal) quickbuild

Nerdbank.GitVersioning supports the Microsoft-internal quickbuild/cloudbuild tool.

It works out of the box, but each project will recompute the version, which may accumulate to a significant increase in overall build time.

🚧 A future version of Nerdbank.GitVersioning will cache version information as a file so that the following instructions will be effective. 🚧

To calculate the version just once for an entire build, a few manual steps are required.

1. Create this project in your repo. The suggested location is `VersionGeneration/VersionGeneration.msbuildproj`.

```xml
<Project Sdk="Microsoft.Build.NoTargets">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<IsPackable>false</IsPackable>
<SkipCopyBuildProduct>true</SkipCopyBuildProduct>
<NBGV_CacheMode>VersionGenerationTarget</NBGV_CacheMode>
</PropertyGroup>
</Project>
```

The `TargetFramework` property value is not important as no assemblies are built by this project,
but a value is nonetheless required for NuGet to be willing to consume the Nerdbank.GitVersioning package reference
(which is referenced in Directory.Build.props as described later).

1. Add the SDK version to your repo-root level `global.json` file, if it is not already present.
The [latest available version from nuget.org](https://www.nuget.org/packages/microsoft.build.notargets) is recommended.

```json
{
"msbuild-sdks": {
"Microsoft.Build.NoTargets": "3.1.0"
}
}
```

1. Modify your repo-root level `Directory.Build.props` file to contain these elements:

```xml
<PropertyGroup>
<!-- This entire repo has just one version.json file, so compute the version once and share with all projects in a large build. -->
<GitVersionBaseDirectory>$(MSBuildThisFileDirectory)</GitVersionBaseDirectory>
</PropertyGroup>

<PropertyGroup Condition=" '$(QBuild)' == '1' ">
<NBGV_CacheMode>MSBuildTargetCaching</NBGV_CacheMode>
<NBGV_CachingProjectReference>$(MSBuildThisFileDirectory)VersionGeneration\VersionGeneration.msbuildproj</NBGV_CachingProjectReference>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Nerdbank.GitVersioning" Version="3.5.*" PrivateAssets="all" />
</ItemGroup>
```
22 changes: 22 additions & 0 deletions src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs
Expand Up @@ -39,6 +39,25 @@ protected override void ApplyGlobalProperties(IDictionary<string, string> global
=> globalProperties["NBGV_GitEngine"] = "Managed";
}

[Trait("Engine", "Managed")]
[Collection("Build")] // msbuild sets current directory in the process, so we can't have it be concurrent with other build tests.
public class BuildIntegrationInProjectManagedTests : BuildIntegrationTests
{
public BuildIntegrationInProjectManagedTests(ITestOutputHelper logger)
: base(logger)
{
}

protected override GitContext CreateGitContext(string path, string committish = null)
=> GitContext.Create(path, committish, writable: false);

protected override void ApplyGlobalProperties(IDictionary<string, string> globalProperties)
{
globalProperties["NBGV_GitEngine"] = "Managed";
globalProperties["NBGV_CacheMode"] = "None";
}
}

[Trait("Engine", "LibGit2")]
[Collection("Build")] // msbuild sets current directory in the process, so we can't have it be concurrent with other build tests.
public class BuildIntegrationLibGit2Tests : BuildIntegrationTests
Expand All @@ -57,6 +76,7 @@ protected override void ApplyGlobalProperties(IDictionary<string, string> global

public abstract class BuildIntegrationTests : RepoTestBase, IClassFixture<MSBuildFixture>
{
private const string GitVersioningPropsFileName = "NerdBank.GitVersioning.props";
private const string GitVersioningTargetsFileName = "NerdBank.GitVersioning.targets";
private const string UnitTestCloudBuildPrefix = "UnitTest: ";
private static readonly string[] ToxicEnvironmentVariablePrefixes = new string[]
Expand Down Expand Up @@ -1175,6 +1195,7 @@ private ProjectRootElement CreateNativeProjectRootElement(string projectDirector
{
var pre = ProjectRootElement.Create(reader, this.projectCollection);
pre.FullPath = Path.Combine(projectDirectory, projectName);
pre.InsertAfterChild(pre.CreateImportElement(Path.Combine(this.RepoPath, GitVersioningPropsFileName)), null);
pre.AddImport(Path.Combine(this.RepoPath, GitVersioningTargetsFileName));
return pre;
}
Expand All @@ -1186,6 +1207,7 @@ private ProjectRootElement CreateProjectRootElement(string projectDirectory, str
{
var pre = ProjectRootElement.Create(reader, this.projectCollection);
pre.FullPath = Path.Combine(projectDirectory, projectName);
pre.InsertAfterChild(pre.CreateImportElement(Path.Combine(this.RepoPath, GitVersioningPropsFileName)), null);
pre.AddImport(Path.Combine(this.RepoPath, GitVersioningTargetsFileName));
return pre;
}
Expand Down
Expand Up @@ -12,7 +12,7 @@
<Compile Include="..\Shared\**\*.cs" LinkBase="Shared" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="..\Nerdbank.GitVersioning.Tasks\build\*.targets">
<EmbeddedResource Include="..\Nerdbank.GitVersioning.Tasks\build\*.targets;..\Nerdbank.GitVersioning.Tasks\build\*.props;..\Nerdbank.GitVersioning.Tasks\build\*.proj">
<Visible>false</Visible>
<Link>Targets\%(FileName)%(Extension)</Link>
</EmbeddedResource>
Expand Down
Expand Up @@ -48,9 +48,13 @@ IMPORTANT: The 3.x release may produce a different version height than prior maj
<file src="$BaseOutputPath$netcoreapp3.1\System.Text.Json.dll" target="build\MSBuildCore\System.Text.Json.dll" />
<file src="$BaseOutputPath$netcoreapp3.1\Validation.dll" target="build\MSBuildCore\Validation.dll" />

<file src="build\Nerdbank.GitVersioning.targets" target="build\Nerdbank.GitVersioning$LKGSuffix$.targets" />
<file src="build\InProjectVersionComputation.targets" target="build\InProjectVersionComputation.targets" />
<file src="build\MSBuildTargetCaching.targets" target="build\MSBuildTargetCaching.targets" />
<file src="build\Nerdbank.GitVersioning.Common.targets" target="build\Nerdbank.GitVersioning.Common.targets" />
<file src="build\Nerdbank.GitVersioning.Inner.targets" target="build\Nerdbank.GitVersioning.Inner.targets" />
<file src="build\Nerdbank.GitVersioning.props" target="build\Nerdbank.GitVersioning$LKGSuffix$.props" />
<file src="build\Nerdbank.GitVersioning.targets" target="build\Nerdbank.GitVersioning$LKGSuffix$.targets" />
<file src="build\PrivateP2PCaching.proj" target="build\PrivateP2PCaching.proj" />
<file src="buildCrossTargeting\Nerdbank.GitVersioning.targets" target="buildCrossTargeting\Nerdbank.GitVersioning$LKGSuffix$.targets" />
<file src="readme.txt" target="readme.txt" />
</files>
Expand Down
@@ -0,0 +1,20 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="Nerdbank.GitVersioning.Inner.targets"/>

<Target Name="SetPropertiesForInvokeGetBuildVersionTask">
<!-- Set properties required for InvokeGetBuildVersionTask here, because
CallTarget invoked targets do not see properties set by the calling target. -->
<PropertyGroup>
<BuildMetadata>@(BuildMetadata, ',')</BuildMetadata>
</PropertyGroup>
</Target>

<Target Name="InvokeGetBuildVersionTask" DependsOnTargets="SetPropertiesForInvokeGetBuildVersionTask">
<CallTarget Targets="GetBuildVersion_Properties">
<Output TaskParameter="TargetOutputs" ItemName="NBGV_PropertyItems" />
</CallTarget>
<CallTarget Targets="GetBuildVersion_CloudBuildVersionVars">
<Output TaskParameter="TargetOutputs" ItemName="CloudBuildVersionVars" />
</CallTarget>
</Target>
</Project>
@@ -0,0 +1,69 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<NBGV_InnerGlobalProperties Condition=" '$(GitRepoRoot)' != '' ">$(NBGV_InnerGlobalProperties)GitRepoRoot=$(GitRepoRoot);</NBGV_InnerGlobalProperties>
<NBGV_InnerGlobalProperties Condition=" '$(PublicRelease)' != '' ">$(NBGV_InnerGlobalProperties)PublicRelease=$(PublicRelease);</NBGV_InnerGlobalProperties>
<NBGV_InnerGlobalProperties Condition=" '$(_NBGV_BuildingRef)' != '' ">$(NBGV_InnerGlobalProperties)_NBGV_BuildingRef=$(_NBGV_BuildingRef);</NBGV_InnerGlobalProperties>
<NBGV_InnerGlobalProperties Condition=" '$(ProjectPathRelativeToGitRepoRoot)' != '' ">$(NBGV_InnerGlobalProperties)ProjectPathRelativeToGitRepoRoot=$(ProjectPathRelativeToGitRepoRoot);</NBGV_InnerGlobalProperties>
<NBGV_InnerGlobalProperties Condition=" '$(GitVersionBaseDirectory)' != '' ">$(NBGV_InnerGlobalProperties)GitVersionBaseDirectory=$(GitVersionBaseDirectory);</NBGV_InnerGlobalProperties>
<NBGV_InnerGlobalProperties Condition=" '$(OverrideBuildNumberOffset)' != '' ">$(NBGV_InnerGlobalProperties)OverrideBuildNumberOffset=$(OverrideBuildNumberOffset);</NBGV_InnerGlobalProperties>
</PropertyGroup>

<!-- Compile a list of global properties that may vary when a project builds but that would never influence the result of the GetBuildVersion task. -->
<ItemGroup>
<NBGV_GlobalPropertiesToRemove Include="TargetFramework" />
<NBGV_GlobalPropertiesToRemove Include="RuntimeIdentifier" />

<_BuildMetadataSnapped Include="@(BuildMetadata)" />
</ItemGroup>

<!-- We generally prefer to clear config|platform properties because they do not impact the version.
But quickbuild doesn't like a p2p that removes these, so set them to defensible constant values in that situation. -->
<PropertyGroup Condition=" '$(QBuild)' == '1' ">
<NBGV_InnerGlobalProperties>$(NBGV_InnerGlobalProperties)Configuration=Release;</NBGV_InnerGlobalProperties>
<NBGV_InnerGlobalProperties>$(NBGV_InnerGlobalProperties)Platform=AnyCPU;</NBGV_InnerGlobalProperties>
</PropertyGroup>
<ItemGroup Condition=" '$(QBuild)' != '1' ">
<NBGV_GlobalPropertiesToRemove Include="Configuration" />
<NBGV_GlobalPropertiesToRemove Include="Platform" />
</ItemGroup>

<ItemGroup>
<!-- Declare a P2P so that "msbuild -graph -isolate" doesn't complain when we use the MSBuild task to invoke our inner shared project. -->
<ProjectReference Include="$(NBGV_CachingProjectReference)">
<Targets>GetBuildVersion_Properties;GetBuildVersion_CloudBuildVersionVars</Targets>
<Properties>$(NBGV_InnerGlobalProperties)BuildMetadata=@(BuildMetadata, ',');</Properties>
<GlobalPropertiesToRemove>@(NBGV_GlobalPropertiesToRemove)</GlobalPropertiesToRemove>

<!-- Do our very best to prevent Microsoft.Common.CurrentVersion.targets or IDEs from processing this P2P. It's only here for MSBuild's static graph. -->
<BuildReference>false</BuildReference>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
<SkipGetTargetFrameworkProperties>true</SkipGetTargetFrameworkProperties>
<Visible>false</Visible>
<NBGV_InnerProject>true</NBGV_InnerProject>
<PrivateAssets>all</PrivateAssets>
</ProjectReference>
</ItemGroup>

<Target Name="InvokeGetBuildVersionTask">
<Error Text="BuildMetadata items changed after a copy was made. Add all BuildMetadata items before importing this file." Condition=" '@(BuildMetadata)' != '@(_BuildMetadataSnapped)' " />

<!-- Calculate version by invoking another "project" with global properties that will serve as a key
into an msbuild cache to ensure we only invoke the GetBuildVersion task as many times as will produce a unique value. -->
<MSBuild Projects="@(ProjectReference)"
Condition=" '%(ProjectReference.NBGV_InnerProject)' == 'true' "
Properties="%(ProjectReference.Properties)"
RemoveProperties="%(ProjectReference.GlobalPropertiesToRemove)"
Targets="GetBuildVersion_Properties">
<Output TaskParameter="TargetOutputs" ItemName="NBGV_PropertyItems" />
</MSBuild>

<!-- Also get other items. -->
<MSBuild Projects="@(ProjectReference)"
Condition=" '%(ProjectReference.NBGV_InnerProject)' == 'true' "
Properties="%(ProjectReference.Properties)"
RemoveProperties="%(ProjectReference.GlobalPropertiesToRemove)"
Targets="GetBuildVersion_CloudBuildVersionVars">
<Output TaskParameter="TargetOutputs" ItemName="CloudBuildVersionVars" />
</MSBuild>
</Target>
</Project>
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<_NBGV_Common_Targets_Imported>true</_NBGV_Common_Targets_Imported>
<_NBGV_PlatformSuffix Condition=" '$(_NBGV_PlatformSuffix)' == '' and '$(MSBuildRuntimeType)' == 'Core' ">MSBuildCore/</_NBGV_PlatformSuffix>
<_NBGV_PlatformSuffix Condition=" '$(_NBGV_PlatformSuffix)' == '' ">MSBuildFull/</_NBGV_PlatformSuffix>
<NerdbankGitVersioningTasksPath Condition=" '$(NerdbankGitVersioningTasksPath)' == '' ">$(MSBuildThisFileDirectory)$(_NBGV_PlatformSuffix)</NerdbankGitVersioningTasksPath>
Expand Down
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

<Import Project="Nerdbank.GitVersioning.Common.targets"/>
<Import Project="Nerdbank.GitVersioning.Common.targets" Condition=" '$(_NBGV_Common_Targets_Imported)' != 'true' "/>

<UsingTask AssemblyFile="$(NerdbankGitVersioningTasksPath)Nerdbank.GitVersioning.Tasks.dll" TaskName="Nerdbank.GitVersioning.Tasks.GetBuildVersion"/>

Expand All @@ -18,7 +18,7 @@
BuildingRef="$(_NBGV_BuildingRef)"
BuildMetadata="$(BuildMetadata.Replace(',',';'))"
DefaultPublicRelease="$(PublicRelease)"
ProjectDirectory="$(ProjectDirectory)"
ProjectDirectory="$(GitVersionBaseDirectory)"
GitRepoRoot="$(GitRepoRoot)"
ProjectPathRelativeToGitRepoRoot="$(ProjectPathRelativeToGitRepoRoot)"
OverrideBuildNumberOffset="$(OverrideBuildNumberOffset)"
Expand All @@ -42,11 +42,5 @@
<Message Importance="low" Text="AssemblyInformationalVersion: $(AssemblyInformationalVersion)" />
<Message Importance="low" Text="NuGetPackageVersion: $(NuGetPackageVersion)" />
</Target>

<!-- These targets are called by MSBuild static graph because we declare a ProjectReference item to this file. -->
<Target Name="GetTargetFrameworks" />
<Target Name="GetNativeManifest" />
<Target Name="GetCopyToOutputDirectoryItems" />
<Target Name="GetTargetFrameworksWithPlatformForSingleTargetFramework" />

</Project>
@@ -0,0 +1,20 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<!-- Cache modes include:
MSBuildTargetCaching
This is the default.
Versions will be computed by an MSBuild target which can be shared across an entire build session via MSBuild target output caching.
None
Every project will compute its own version.
Note that the choice in caching should have no bearing on the result of the versions computed - only on build perf and which systems it can work with.
-->
<NBGV_CacheMode Condition=" '$(NBGV_CacheMode)' == '' and '$(QBuild)' == '1' ">None</NBGV_CacheMode>
<NBGV_CacheMode Condition=" '$(NBGV_CacheMode)' == '' ">MSBuildTargetCaching</NBGV_CacheMode>

<!-- This property may be overridden in environments where all P2P references must be a project actually defined within the git repo directory.
Learn more at :/doc/quickbuild.md.
-->
<NBGV_CachingProjectReference Condition=" '$(NBGV_CachingProjectReference)' == '' ">$(MSBuildThisFileDirectory)PrivateP2PCaching.proj</NBGV_CachingProjectReference>
</PropertyGroup>
</Project>

0 comments on commit a1d636e

Please sign in to comment.