From 80109349990a76569ce6e0e5e7913c93ad4d6dcb Mon Sep 17 00:00:00 2001 From: Matt Kotsenas Date: Mon, 26 Aug 2024 12:41:50 -0700 Subject: [PATCH 1/4] Add MSBuildProjectCreator test harness --- Directory.Build.props | 3 ++ DotNet.ReproducibleBuilds.sln | 6 +++ azure-pipelines.yml | 3 ++ .../BooleanExtensions.cs | 9 ++++ .../DotNet.ReproducibleBuilds.Tests.csproj | 35 +++++++++++++++ .../MSBuildModuleInitializer.cs | 13 ++++++ .../ProjectTemplates.cs | 20 +++++++++ .../SourceLinkTests.cs | 23 ++++++++++ .../TestBase.cs | 43 +++++++++++++++++++ 9 files changed, 155 insertions(+) create mode 100644 tests/DotNet.ReproducibleBuilds.Tests/BooleanExtensions.cs create mode 100644 tests/DotNet.ReproducibleBuilds.Tests/DotNet.ReproducibleBuilds.Tests.csproj create mode 100644 tests/DotNet.ReproducibleBuilds.Tests/MSBuildModuleInitializer.cs create mode 100644 tests/DotNet.ReproducibleBuilds.Tests/ProjectTemplates.cs create mode 100644 tests/DotNet.ReproducibleBuilds.Tests/SourceLinkTests.cs create mode 100644 tests/DotNet.ReproducibleBuilds.Tests/TestBase.cs diff --git a/Directory.Build.props b/Directory.Build.props index 598b4c6..0746ad4 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,5 +1,7 @@ + $(MSBuildThisFileDirectory) + false @@ -36,6 +38,7 @@ diff --git a/DotNet.ReproducibleBuilds.sln b/DotNet.ReproducibleBuilds.sln index c7c9d0d..a5409f9 100644 --- a/DotNet.ReproducibleBuilds.sln +++ b/DotNet.ReproducibleBuilds.sln @@ -17,6 +17,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNet.ReproducibleBuilds.Isolated", "src\DotNet.ReproducibleBuilds.Isolated\DotNet.ReproducibleBuilds.Isolated.csproj", "{BD88D2CB-4342-47A3-B0D1-07321E9A92C1}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNet.ReproducibleBuilds.Tests", "tests\DotNet.ReproducibleBuilds.Tests\DotNet.ReproducibleBuilds.Tests.csproj", "{72BE4FA4-D190-44AF-B056-23AA79D1553A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -31,6 +33,10 @@ Global {BD88D2CB-4342-47A3-B0D1-07321E9A92C1}.Debug|Any CPU.Build.0 = Debug|Any CPU {BD88D2CB-4342-47A3-B0D1-07321E9A92C1}.Release|Any CPU.ActiveCfg = Release|Any CPU {BD88D2CB-4342-47A3-B0D1-07321E9A92C1}.Release|Any CPU.Build.0 = Release|Any CPU + {72BE4FA4-D190-44AF-B056-23AA79D1553A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {72BE4FA4-D190-44AF-B056-23AA79D1553A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {72BE4FA4-D190-44AF-B056-23AA79D1553A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {72BE4FA4-D190-44AF-B056-23AA79D1553A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 123f459..18466f3 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -30,6 +30,9 @@ stages: - script: dotnet nbgv cloud displayName: Set Version + - script: dotnet test dirs.proj + displayName: Test + - script: dotnet pack dirs.proj displayName: Create package(s) diff --git a/tests/DotNet.ReproducibleBuilds.Tests/BooleanExtensions.cs b/tests/DotNet.ReproducibleBuilds.Tests/BooleanExtensions.cs new file mode 100644 index 0000000..05a2bf6 --- /dev/null +++ b/tests/DotNet.ReproducibleBuilds.Tests/BooleanExtensions.cs @@ -0,0 +1,9 @@ +using System.Diagnostics.CodeAnalysis; + +namespace DotNet.ReproducibleBuilds.Tests; + +internal static class BooleanExtensions +{ + public static string ToLowerInvariant(this bool value) => value.ToString().ToLowerInvariant(); + public static string? ToLowerInvariant([NotNullIfNotNull(nameof(value))] this bool? value) => value?.ToString().ToLowerInvariant(); +} diff --git a/tests/DotNet.ReproducibleBuilds.Tests/DotNet.ReproducibleBuilds.Tests.csproj b/tests/DotNet.ReproducibleBuilds.Tests/DotNet.ReproducibleBuilds.Tests.csproj new file mode 100644 index 0000000..c0e5b89 --- /dev/null +++ b/tests/DotNet.ReproducibleBuilds.Tests/DotNet.ReproducibleBuilds.Tests.csproj @@ -0,0 +1,35 @@ + + + + net8.0 + enable + enable + + true + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + diff --git a/tests/DotNet.ReproducibleBuilds.Tests/MSBuildModuleInitializer.cs b/tests/DotNet.ReproducibleBuilds.Tests/MSBuildModuleInitializer.cs new file mode 100644 index 0000000..a892955 --- /dev/null +++ b/tests/DotNet.ReproducibleBuilds.Tests/MSBuildModuleInitializer.cs @@ -0,0 +1,13 @@ +using Microsoft.Build.Utilities.ProjectCreation; +using System.Runtime.CompilerServices; + +namespace DotNet.ReproducibleBuilds.Tests; + +internal static class MSBuildModuleInitializer +{ + [ModuleInitializer] + internal static void InitializeMSBuild() + { + MSBuildAssemblyResolver.Register(); + } +} diff --git a/tests/DotNet.ReproducibleBuilds.Tests/ProjectTemplates.cs b/tests/DotNet.ReproducibleBuilds.Tests/ProjectTemplates.cs new file mode 100644 index 0000000..ad9e15a --- /dev/null +++ b/tests/DotNet.ReproducibleBuilds.Tests/ProjectTemplates.cs @@ -0,0 +1,20 @@ +using Microsoft.Build.Utilities.ProjectCreation; + +namespace DotNet.ReproducibleBuilds.Tests; + +internal static class ProjectTemplates +{ + private static readonly string ThisAssemblyDirectory = Path.GetDirectoryName(typeof(ProjectTemplates).Assembly.Location)!; + + public static ProjectCreator ReproducibleBuildProject(this ProjectCreatorTemplates templates, string directory, Action configure) + { + ProjectCreator template = ProjectCreator.Templates + .SdkCsproj(path: Path.Combine(directory, "test.csproj"), targetFramework: "net8.0") + .Import(Path.Combine(ThisAssemblyDirectory, "DotNet.ReproducibleBuilds.props")); + + configure(template); + + return template + .Import(Path.Combine(ThisAssemblyDirectory, "DotNet.ReproducibleBuilds.targets")); + } +} diff --git a/tests/DotNet.ReproducibleBuilds.Tests/SourceLinkTests.cs b/tests/DotNet.ReproducibleBuilds.Tests/SourceLinkTests.cs new file mode 100644 index 0000000..44c9747 --- /dev/null +++ b/tests/DotNet.ReproducibleBuilds.Tests/SourceLinkTests.cs @@ -0,0 +1,23 @@ +using FluentAssertions; +using Microsoft.Build.Utilities.ProjectCreation; + +namespace DotNet.ReproducibleBuilds.Tests; + +public class SourceLinkTests : TestBase +{ + [Theory] + [InlineData(null, true)] + [InlineData(false, false)] + [InlineData(true, true)] + public void PublishRepositoryUrlIsSet(bool? publishRepositoryUrl, bool expected) + { + ProjectCreator.Templates.ReproducibleBuildProject(TestRootPath, project => + { + project + .PropertyGroup() + .Property("PublishRepositoryUrl", publishRepositoryUrl.ToLowerInvariant()); + }).Project + .GetPropertyValue("PublishRepositoryUrl") + .Should().Be(expected.ToLowerInvariant()); + } +} diff --git a/tests/DotNet.ReproducibleBuilds.Tests/TestBase.cs b/tests/DotNet.ReproducibleBuilds.Tests/TestBase.cs new file mode 100644 index 0000000..2c0003b --- /dev/null +++ b/tests/DotNet.ReproducibleBuilds.Tests/TestBase.cs @@ -0,0 +1,43 @@ +namespace DotNet.ReproducibleBuilds.Tests; + +public abstract class TestBase : IDisposable +{ + protected TestBase() + { + TestRootPath = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), Path.GetRandomFileName())).FullName; + } + + public string TestRootPath { get; } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool isDisposing) + { + if (Directory.Exists(TestRootPath)) + { + try + { + Directory.Delete(TestRootPath, recursive: true); + } + catch (Exception) + { + // Ignored + } + } + } + + protected string GetTempFileName(string? extension = null) + { + return Path.Combine(TestRootPath, $"{Path.GetRandomFileName()}{extension ?? string.Empty}"); + } + + protected string GetTempProjectPath(string? extension = null) + { + DirectoryInfo tempDirectoryInfo = Directory.CreateDirectory(Path.Combine(TestRootPath, Path.GetRandomFileName())); + + return Path.Combine(tempDirectoryInfo.FullName, $"{Path.GetRandomFileName()}{extension ?? string.Empty}"); + } +} From b195e985e4e1a0770750184350446450021ac186 Mon Sep 17 00:00:00 2001 From: Matt Kotsenas Date: Mon, 26 Aug 2024 15:39:39 -0700 Subject: [PATCH 2/4] More closely emulate NuGet package import and add DebugType tests --- .../FileSystemInfoExtensions.cs | 9 +++++++ .../ProjectTemplates.cs | 20 +++++++++----- .../SourceLinkTests.cs | 26 ++++++++++++++----- .../TestBase.cs | 22 +++++----------- 4 files changed, 48 insertions(+), 29 deletions(-) create mode 100644 tests/DotNet.ReproducibleBuilds.Tests/FileSystemInfoExtensions.cs diff --git a/tests/DotNet.ReproducibleBuilds.Tests/FileSystemInfoExtensions.cs b/tests/DotNet.ReproducibleBuilds.Tests/FileSystemInfoExtensions.cs new file mode 100644 index 0000000..7abcbb7 --- /dev/null +++ b/tests/DotNet.ReproducibleBuilds.Tests/FileSystemInfoExtensions.cs @@ -0,0 +1,9 @@ +namespace DotNet.ReproducibleBuilds.Tests; + +internal static class FileSystemInfoExtensions +{ + public static string Combine(this FileSystemInfo info, params string[] paths) + { + return Path.Combine([info.FullName, ..paths]); + } +} diff --git a/tests/DotNet.ReproducibleBuilds.Tests/ProjectTemplates.cs b/tests/DotNet.ReproducibleBuilds.Tests/ProjectTemplates.cs index ad9e15a..d2f7ff2 100644 --- a/tests/DotNet.ReproducibleBuilds.Tests/ProjectTemplates.cs +++ b/tests/DotNet.ReproducibleBuilds.Tests/ProjectTemplates.cs @@ -6,15 +6,21 @@ internal static class ProjectTemplates { private static readonly string ThisAssemblyDirectory = Path.GetDirectoryName(typeof(ProjectTemplates).Assembly.Location)!; - public static ProjectCreator ReproducibleBuildProject(this ProjectCreatorTemplates templates, string directory, Action configure) + public static ProjectCreator ReproducibleBuildProject(this ProjectCreatorTemplates templates, DirectoryInfo path) { - ProjectCreator template = ProjectCreator.Templates - .SdkCsproj(path: Path.Combine(directory, "test.csproj"), targetFramework: "net8.0") - .Import(Path.Combine(ThisAssemblyDirectory, "DotNet.ReproducibleBuilds.props")); + FileInfo project = new(path.Combine("test.csproj")); - configure(template); + _ = ProjectCreator + .Create(path: path.Combine("obj", $"{project.Name}.tests.g.props")) + .Import(Path.Combine(ThisAssemblyDirectory, "DotNet.ReproducibleBuilds.props")) + .Save(); - return template - .Import(Path.Combine(ThisAssemblyDirectory, "DotNet.ReproducibleBuilds.targets")); + _ = ProjectCreator + .Create(path: path.Combine("obj", $"{project.Name}.tests.g.targets")) + .Import(Path.Combine(ThisAssemblyDirectory, "DotNet.ReproducibleBuilds.targets")) + .Save(); + + return templates + .SdkCsproj(path: project.FullName, targetFramework: "net8.0"); } } diff --git a/tests/DotNet.ReproducibleBuilds.Tests/SourceLinkTests.cs b/tests/DotNet.ReproducibleBuilds.Tests/SourceLinkTests.cs index 44c9747..8084dab 100644 --- a/tests/DotNet.ReproducibleBuilds.Tests/SourceLinkTests.cs +++ b/tests/DotNet.ReproducibleBuilds.Tests/SourceLinkTests.cs @@ -11,13 +11,27 @@ public class SourceLinkTests : TestBase [InlineData(true, true)] public void PublishRepositoryUrlIsSet(bool? publishRepositoryUrl, bool expected) { - ProjectCreator.Templates.ReproducibleBuildProject(TestRootPath, project => - { - project - .PropertyGroup() - .Property("PublishRepositoryUrl", publishRepositoryUrl.ToLowerInvariant()); - }).Project + ProjectCreator.Templates + .ReproducibleBuildProject(TestRootPath) + .PropertyGroup() + .Property("PublishRepositoryUrl", publishRepositoryUrl.ToLowerInvariant()) + .Project .GetPropertyValue("PublishRepositoryUrl") .Should().Be(expected.ToLowerInvariant()); } + + [Theory] + [InlineData(null, "embedded")] + [InlineData("embedded", "embedded")] + [InlineData("portable", "portable")] + public void DebugTypeIsSet(string? debugType, string expected) + { + ProjectCreator.Templates + .ReproducibleBuildProject(TestRootPath) + .PropertyGroup() + .Property("DebugType", debugType) + .Project + .GetPropertyValue("DebugType") + .Should().Be(expected); + } } diff --git a/tests/DotNet.ReproducibleBuilds.Tests/TestBase.cs b/tests/DotNet.ReproducibleBuilds.Tests/TestBase.cs index 2c0003b..acf8df4 100644 --- a/tests/DotNet.ReproducibleBuilds.Tests/TestBase.cs +++ b/tests/DotNet.ReproducibleBuilds.Tests/TestBase.cs @@ -4,23 +4,25 @@ public abstract class TestBase : IDisposable { protected TestBase() { - TestRootPath = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), Path.GetRandomFileName())).FullName; + TestRootPath = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), Path.GetRandomFileName())); } - public string TestRootPath { get; } + public DirectoryInfo TestRootPath { get; } public void Dispose() { Dispose(true); + GC.SuppressFinalize(this); } protected virtual void Dispose(bool isDisposing) { - if (Directory.Exists(TestRootPath)) + TestRootPath.Refresh(); + if (TestRootPath.Exists) { try { - Directory.Delete(TestRootPath, recursive: true); + TestRootPath.Delete(recursive: true); } catch (Exception) { @@ -28,16 +30,4 @@ protected virtual void Dispose(bool isDisposing) } } } - - protected string GetTempFileName(string? extension = null) - { - return Path.Combine(TestRootPath, $"{Path.GetRandomFileName()}{extension ?? string.Empty}"); - } - - protected string GetTempProjectPath(string? extension = null) - { - DirectoryInfo tempDirectoryInfo = Directory.CreateDirectory(Path.Combine(TestRootPath, Path.GetRandomFileName())); - - return Path.Combine(tempDirectoryInfo.FullName, $"{Path.GetRandomFileName()}{extension ?? string.Empty}"); - } } From 509ec14f6cb793e76a53164878510fdc7d96cbb0 Mon Sep 17 00:00:00 2001 From: Matt Kotsenas Date: Mon, 26 Aug 2024 15:46:54 -0700 Subject: [PATCH 3/4] Add tests for EmbedUntrackedSources --- .../SourceLinkTests.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/DotNet.ReproducibleBuilds.Tests/SourceLinkTests.cs b/tests/DotNet.ReproducibleBuilds.Tests/SourceLinkTests.cs index 8084dab..337fdbb 100644 --- a/tests/DotNet.ReproducibleBuilds.Tests/SourceLinkTests.cs +++ b/tests/DotNet.ReproducibleBuilds.Tests/SourceLinkTests.cs @@ -34,4 +34,19 @@ public void DebugTypeIsSet(string? debugType, string expected) .GetPropertyValue("DebugType") .Should().Be(expected); } + + [Theory] + [InlineData(null, true)] + [InlineData(false, false)] + [InlineData(true, true)] + public void EmbedUntrackedSourcesIsSet(bool? embedUntrackedSources, bool expected) + { + ProjectCreator.Templates + .ReproducibleBuildProject(TestRootPath) + .PropertyGroup() + .Property("PublishRepositoryUrl", embedUntrackedSources.ToLowerInvariant()) + .Project + .GetPropertyValue("PublishRepositoryUrl") + .Should().Be(expected.ToLowerInvariant()); + } } From b18402c5a1ce0392d20a9324c55cec12402c3531 Mon Sep 17 00:00:00 2001 From: Matt Kotsenas Date: Mon, 26 Aug 2024 16:34:08 -0700 Subject: [PATCH 4/4] Add tests for CI providers to RepositoryBranch --- .../EnvironmentVariableSuppressor.cs | 19 ++++++ .../ProjectTemplates.cs | 8 +-- .../SourceLinkTests.cs | 59 ++++++++++++++++++- .../TestBase.cs | 5 ++ 4 files changed, 84 insertions(+), 7 deletions(-) create mode 100644 tests/DotNet.ReproducibleBuilds.Tests/EnvironmentVariableSuppressor.cs diff --git a/tests/DotNet.ReproducibleBuilds.Tests/EnvironmentVariableSuppressor.cs b/tests/DotNet.ReproducibleBuilds.Tests/EnvironmentVariableSuppressor.cs new file mode 100644 index 0000000..0f62f24 --- /dev/null +++ b/tests/DotNet.ReproducibleBuilds.Tests/EnvironmentVariableSuppressor.cs @@ -0,0 +1,19 @@ +namespace DotNet.ReproducibleBuilds.Tests; + +internal sealed class EnvironmentVariableSuppressor : IDisposable +{ + private readonly string? _value; + private readonly string _name; + + public EnvironmentVariableSuppressor(string name) + { + _name = name; + _value = Environment.GetEnvironmentVariable(name); + Environment.SetEnvironmentVariable(name, null); + } + + public void Dispose() + { + Environment.SetEnvironmentVariable(_name, _value); + } +} diff --git a/tests/DotNet.ReproducibleBuilds.Tests/ProjectTemplates.cs b/tests/DotNet.ReproducibleBuilds.Tests/ProjectTemplates.cs index d2f7ff2..d2ebecb 100644 --- a/tests/DotNet.ReproducibleBuilds.Tests/ProjectTemplates.cs +++ b/tests/DotNet.ReproducibleBuilds.Tests/ProjectTemplates.cs @@ -6,17 +6,17 @@ internal static class ProjectTemplates { private static readonly string ThisAssemblyDirectory = Path.GetDirectoryName(typeof(ProjectTemplates).Assembly.Location)!; - public static ProjectCreator ReproducibleBuildProject(this ProjectCreatorTemplates templates, DirectoryInfo path) + public static ProjectCreator ReproducibleBuildProject(this ProjectCreatorTemplates templates, FileInfo project) { - FileInfo project = new(path.Combine("test.csproj")); + DirectoryInfo directory = project.Directory ?? throw new ArgumentException("Project's path does not appear to have a parent.", nameof(project)); _ = ProjectCreator - .Create(path: path.Combine("obj", $"{project.Name}.tests.g.props")) + .Create(path: directory.Combine("obj", $"{project.Name}.tests.g.props")) .Import(Path.Combine(ThisAssemblyDirectory, "DotNet.ReproducibleBuilds.props")) .Save(); _ = ProjectCreator - .Create(path: path.Combine("obj", $"{project.Name}.tests.g.targets")) + .Create(path: directory.Combine("obj", $"{project.Name}.tests.g.targets")) .Import(Path.Combine(ThisAssemblyDirectory, "DotNet.ReproducibleBuilds.targets")) .Save(); diff --git a/tests/DotNet.ReproducibleBuilds.Tests/SourceLinkTests.cs b/tests/DotNet.ReproducibleBuilds.Tests/SourceLinkTests.cs index 337fdbb..d46c7f9 100644 --- a/tests/DotNet.ReproducibleBuilds.Tests/SourceLinkTests.cs +++ b/tests/DotNet.ReproducibleBuilds.Tests/SourceLinkTests.cs @@ -12,7 +12,7 @@ public class SourceLinkTests : TestBase public void PublishRepositoryUrlIsSet(bool? publishRepositoryUrl, bool expected) { ProjectCreator.Templates - .ReproducibleBuildProject(TestRootPath) + .ReproducibleBuildProject(GetRandomFile(".csproj")) .PropertyGroup() .Property("PublishRepositoryUrl", publishRepositoryUrl.ToLowerInvariant()) .Project @@ -27,7 +27,7 @@ public void PublishRepositoryUrlIsSet(bool? publishRepositoryUrl, bool expected) public void DebugTypeIsSet(string? debugType, string expected) { ProjectCreator.Templates - .ReproducibleBuildProject(TestRootPath) + .ReproducibleBuildProject(GetRandomFile(".csproj")) .PropertyGroup() .Property("DebugType", debugType) .Project @@ -42,11 +42,64 @@ public void DebugTypeIsSet(string? debugType, string expected) public void EmbedUntrackedSourcesIsSet(bool? embedUntrackedSources, bool expected) { ProjectCreator.Templates - .ReproducibleBuildProject(TestRootPath) + .ReproducibleBuildProject(GetRandomFile(".csproj")) .PropertyGroup() .Property("PublishRepositoryUrl", embedUntrackedSources.ToLowerInvariant()) .Project .GetPropertyValue("PublishRepositoryUrl") .Should().Be(expected.ToLowerInvariant()); } + + [Theory] + [InlineData("GITHUB_REF", "refs/pull/1234/merge", "pr1234")] + [InlineData("GITHUB_REF", "refs/heads/my-branch", "my-branch")] + [InlineData("GITHUB_REF", "refs/tags/v1.2.3", "v1.2.3")] + + [InlineData("BUILD_SOURCEBRANCH", "refs/heads/my-branch", "my-branch")] + [InlineData("BUILD_SOURCEBRANCH", "refs/tags/v1.2.3", "v1.2.3")] + + [InlineData("APPVEYOR_PULL_REQUEST_NUMBER", "1234", "pr1234")] + [InlineData("APPVEYOR_REPO_TAG_NAME", "refs/tags/v1.2.3", "refs/tags/v1.2.3")] + [InlineData("APPVEYOR_REPO_BRANCH", "refs/heads/my-branch", "refs/heads/my-branch")] + + [InlineData("TEAMCITY_BUILD_BRANCH", "refs/heads/my-branch", "refs/heads/my-branch")] + + [InlineData("TRAVIS_PULL_REQUEST", "1234", "pr1234")] + [InlineData("TRAVIS_BRANCH", "refs/heads/my-branch", "refs/heads/my-branch")] + + [InlineData("CIRCLE_PR_NUMBER", "1234", "pr1234")] + [InlineData("CIRCLE_TAG", "refs/heads/v1.2.3", "refs/heads/v1.2.3")] + [InlineData("CIRCLE_BRANCH", "refs/heads/my-branch", "refs/heads/my-branch")] + + [InlineData("CI_COMMIT_TAG", "refs/tags/v1.2.3", "refs/tags/v1.2.3")] + [InlineData("CI_MERGE_REQUEST_IID", "1234", "pr1234")] + [InlineData("CI_COMMIT_BRANCH", "refs/heads/my-branch", "refs/heads/my-branch")] + + [InlineData("BUDDY_EXECUTION_PULL_REQUEST_NO", "1234", "pr1234")] + [InlineData("BUDDY_EXECUTION_TAG", "refs/tags/v1.2.3", "refs/tags/v1.2.3")] + [InlineData("BUDDY_EXECUTION_BRANCH", "refs/heads/my-branch", "refs/heads/my-branch")] + public void RepositoryBranchIsSet(string ci, string original, string expected) + { + using EnvironmentVariableSuppressor hostSuppressor = new("BUILD_SOURCEBRANCH"); // Suppress our own CI provider variables (i.e. Azure DevOps) + using EnvironmentVariableSuppressor ciSuppressor = new(ci); // Suppress the mock CI provider (just in case). + + // If RepositoryBranch is set, it should take precedence over the CI provider variables + ProjectCreator.Templates + .ReproducibleBuildProject(GetRandomFile(".csproj")) + .PropertyGroup() + .Property("RepositoryBranch", "explicitly-set") + .Property(ci, original) + .Project + .GetPropertyValue("RepositoryBranch") + .Should().Be("explicitly-set", "because explicitly setting `RepositoryBranch` should always win."); + + // If RepositoryBranch is not set, it should be set from the CI provider property + ProjectCreator.Templates + .ReproducibleBuildProject(GetRandomFile(".csproj")) + .PropertyGroup() + .Property(ci, original) + .Project + .GetPropertyValue("RepositoryBranch") + .Should().Be(expected); + } } diff --git a/tests/DotNet.ReproducibleBuilds.Tests/TestBase.cs b/tests/DotNet.ReproducibleBuilds.Tests/TestBase.cs index acf8df4..b1599f4 100644 --- a/tests/DotNet.ReproducibleBuilds.Tests/TestBase.cs +++ b/tests/DotNet.ReproducibleBuilds.Tests/TestBase.cs @@ -30,4 +30,9 @@ protected virtual void Dispose(bool isDisposing) } } } + + protected FileInfo GetRandomFile(string? extension = null) + { + return new(TestRootPath.Combine($"{Path.GetRandomFileName()}{extension ?? string.Empty}")); + } }