diff --git a/src/Management/src/GitProperties.Build/PackageReadme.md b/src/Management/src/GitProperties.Build/PackageReadme.md index 4e3115adeb..1c8cb70ef1 100644 --- a/src/Management/src/GitProperties.Build/PackageReadme.md +++ b/src/Management/src/GitProperties.Build/PackageReadme.md @@ -102,6 +102,31 @@ This command writes an extra copy of `git.properties` directly next to your proj > > If you deploy by pushing your source code directly, rather than a pre-built or published output (for example with Cloud Foundry's `cf push`), be careful not to *also* exclude `git.properties` from whatever gets pushed or deployed. For Cloud Foundry, that means leaving it out of `.cfignore`. `git.properties` must stay out of Git through `.gitignore`, but it still needs to be present on disk and travel along with your source code. +### Refreshing many projects at once + +The command above works for one project at a time. If your solution has several projects, and only some of them use this package, running the same command on a project that doesn't use it fails with an error like this: + +``` +error MSB4057: The target "WriteGitPropertiesFallbackFile" does not exist in the project. +``` + +To safely refresh every project at once, add a `Directory.Build.targets` file that applies to all of them (your solution's root folder works well). It defines a new target that only calls the real one on projects that use this package. This makes it safe to run on every project, even ones that don't use this package: + +```xml + + + + + + +``` + +Then, instead of the command shown above, run this new target for your whole solution: + +```shell +dotnet build YourSolution.slnx -t:RefreshGitPropertiesFallbackFile +``` + ## Using this package in a shared project Installing this package as shown under [Getting started](#getting-started), whether with the `dotnet` CLI or Visual Studio's Add Package dialog, writes `PrivateAssets="all"` into the `` line automatically. This stops the reference from becoming transitive, so `git.properties` generation stays local to the project you installed it in. That's the right choice for most solutions: usually only a few host apps need `git.properties`, so keeping the reference non-transitive avoids running Git commands anywhere else. diff --git a/src/Management/src/GitProperties.Build/buildTransitive/Steeltoe.Management.GitProperties.Build.targets b/src/Management/src/GitProperties.Build/buildTransitive/Steeltoe.Management.GitProperties.Build.targets index a4c9ff0afa..7da08792ec 100644 --- a/src/Management/src/GitProperties.Build/buildTransitive/Steeltoe.Management.GitProperties.Build.targets +++ b/src/Management/src/GitProperties.Build/buildTransitive/Steeltoe.Management.GitProperties.Build.targets @@ -58,6 +58,10 @@ $(IntermediateOutputPath)git.properties + + true + + <_GitPropertiesShouldGenerate>$(GenerateGitProperties) @@ -72,7 +76,7 @@ <_GitPropertiesSuppressGitRepositoryNotFound>false - <_GitPropertiesSuppressGitRepositoryNotFound Condition="Exists('$(GitPropertiesFallbackFile)')">true + <_GitPropertiesSuppressGitRepositoryNotFound Condition="Exists('$(GitPropertiesFallbackFile)') and '$(_ForceWriteGitPropertiesFallbackFile)' != 'true'">true - <_GitPropertiesFallbackFileTarget Condition="'$(GitPropertiesWriteToProjectDirectory)' == 'true'">$(GitPropertiesFallbackFile) + <_GitPropertiesFallbackFileTarget Condition="'$(GitPropertiesWriteToProjectDirectory)' == 'true' or '$(_ForceWriteGitPropertiesFallbackFile)' == 'true'">$(GitPropertiesFallbackFile) + Properties="Configuration=$(Configuration);_ForceWriteGitPropertiesFallbackFile=true" /> + + + + + + + %(ProjectReference.GlobalPropertiesToRemove);_ForceWriteGitPropertiesFallbackFile + + diff --git a/src/Management/test/GitProperties.Build.Test/FallbackFile/WriteGitPropertiesFallbackFileDoesNotForceServiceDefaultsToWriteFallbackCopyTest.cs b/src/Management/test/GitProperties.Build.Test/FallbackFile/WriteGitPropertiesFallbackFileDoesNotForceServiceDefaultsToWriteFallbackCopyTest.cs new file mode 100644 index 0000000000..5f951e47f5 --- /dev/null +++ b/src/Management/test/GitProperties.Build.Test/FallbackFile/WriteGitPropertiesFallbackFileDoesNotForceServiceDefaultsToWriteFallbackCopyTest.cs @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information. + +namespace Steeltoe.Management.GitProperties.Build.Test.FallbackFile; + +public sealed class WriteGitPropertiesFallbackFileDoesNotForceServiceDefaultsToWriteFallbackCopyTest : GitPropertiesTestBase +{ + [Fact] + public async Task Test() + { + GitRepository repository = await Workspace.CreateGitRepositoryAsync("repo", 1); + + TestProject serviceDefaults = await repository.AddTestLibraryAsync("ServiceDefaults", true, [ + Workspace.FakeEndpointPackageReference, + Workspace.GetGitPropertiesPackageReferenceWithPrivateAssets("none") + ]); + + TestProject apiService = await repository.AddTestAppAsync("ApiService", projectReferences: [serviceDefaults]); + await apiService.BuildAsync("-t:WriteGitPropertiesFallbackFile"); + + apiService.FallbackGitPropertiesGenerated.Should().BeTrue(); + serviceDefaults.GitPropertiesGenerated.Should().BeTrue(); + serviceDefaults.FallbackGitPropertiesGenerated.Should().BeFalse(); + } +} diff --git a/src/Management/test/GitProperties.Build.Test/FallbackFile/WriteGitPropertiesFallbackFileOverridesGlobalOptOutTest.cs b/src/Management/test/GitProperties.Build.Test/FallbackFile/WriteGitPropertiesFallbackFileOverridesGlobalOptOutTest.cs new file mode 100644 index 0000000000..a282a9cbe3 --- /dev/null +++ b/src/Management/test/GitProperties.Build.Test/FallbackFile/WriteGitPropertiesFallbackFileOverridesGlobalOptOutTest.cs @@ -0,0 +1,28 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information. + +namespace Steeltoe.Management.GitProperties.Build.Test.FallbackFile; + +public sealed class WriteGitPropertiesFallbackFileOverridesGlobalOptOutTest : GitPropertiesTestBase +{ + [Fact] + public async Task Test() + { + GitRepository repository = await Workspace.CreateGitRepositoryAsync("repo", 1); + + await Workspace.WriteFileAsync(Path.Combine(Workspace.GetPath("repo"), "Directory.Build.props"), """ + + + false + + + """); + + TestProject testApp = repository.TestApp; + + await testApp.BuildAsync("-t:WriteGitPropertiesFallbackFile"); + + testApp.FallbackGitPropertiesGenerated.Should().BeTrue(); + } +} diff --git a/src/Management/test/GitProperties.Build.Test/FallbackFile/WriteGitPropertiesFallbackFileWrapperSupportsServiceDefaultsAndAppHostTest.cs b/src/Management/test/GitProperties.Build.Test/FallbackFile/WriteGitPropertiesFallbackFileWrapperSupportsServiceDefaultsAndAppHostTest.cs new file mode 100644 index 0000000000..acc3bfae0d --- /dev/null +++ b/src/Management/test/GitProperties.Build.Test/FallbackFile/WriteGitPropertiesFallbackFileWrapperSupportsServiceDefaultsAndAppHostTest.cs @@ -0,0 +1,37 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information. + +namespace Steeltoe.Management.GitProperties.Build.Test.FallbackFile; + +public sealed class WriteGitPropertiesFallbackFileWrapperSupportsServiceDefaultsAndAppHostTest : GitPropertiesTestBase +{ + [Fact] + public async Task Test() + { + GitRepository repository = await Workspace.CreateGitRepositoryAsync("repo", 1); + + await Workspace.WriteFileAsync(Path.Combine(Workspace.GetPath("repo"), "Directory.Build.targets"), """ + + + + + + """); + + TestProject serviceDefaults = await repository.AddTestLibraryAsync("ServiceDefaults", false, [ + Workspace.FakeEndpointPackageReference, + Workspace.GetGitPropertiesPackageReferenceWithPrivateAssets("none") + ]); + + TestProject apiService = await repository.AddTestAppAsync("ApiService", projectReferences: [serviceDefaults]); + await apiService.BuildAsync("-t:RefreshGitPropertiesFallbackFile"); + + TestProject appHost = await repository.AddTestAppAsync("AppHost"); + await appHost.BuildAsync("-t:RefreshGitPropertiesFallbackFile"); + + serviceDefaults.FallbackGitPropertiesGenerated.Should().BeFalse(); + apiService.FallbackGitPropertiesGenerated.Should().BeTrue(); + appHost.FallbackGitPropertiesGenerated.Should().BeFalse(); + } +} diff --git a/src/Management/test/GitProperties.Build.Test/GitRepositoryBuilder.cs b/src/Management/test/GitProperties.Build.Test/GitRepositoryBuilder.cs index c9b796df8a..273b43d292 100644 --- a/src/Management/test/GitProperties.Build.Test/GitRepositoryBuilder.cs +++ b/src/Management/test/GitProperties.Build.Test/GitRepositoryBuilder.cs @@ -6,6 +6,14 @@ namespace Steeltoe.Management.GitProperties.Build.Test; internal static class GitRepositoryBuilder { + private const string GitConfigAppendix = """ + [user] + name = Test User + email = test@example.com + [commit] + gpgsign = false # Avoid an interactive prompt on a machine that has commit signing configured globally. + """; + private static readonly HashSet DirectoryNamesExcludedInPush = new(StringComparer.OrdinalIgnoreCase) { ".git", @@ -17,13 +25,12 @@ public static async Task InitializeEmptyAsync(string destination) { Directory.CreateDirectory(destination); await ProcessRunner.RunGitAsync(destination, "init", "--quiet", "--initial-branch=main", "."); + await File.AppendAllTextAsync(Path.Combine(destination, ".git", "config"), GitConfigAppendix, TestContext.Current.CancellationToken); } public static async Task InitializeAsync(string destination, int commitCount, bool includeFallbackFileInGitignore) { await InitializeEmptyAsync(destination); - await ProcessRunner.RunGitAsync(destination, "config", "user.name", "Test User"); - await ProcessRunner.RunGitAsync(destination, "config", "user.email", "test@example.com"); string gitignoreContent = includeFallbackFileInGitignore ? """