Skip to content

Commit 4336d59

Browse files
authored
Add test cases for detecting CI environments and setting ContinuousIntegrationBuild (#49)
This adds test coverage so that we can merge #11 / #12.
2 parents 710a248 + d8255e2 commit 4336d59

File tree

6 files changed

+119
-21
lines changed

6 files changed

+119
-21
lines changed

src/DotNet.ReproducibleBuilds/DotNet.ReproducibleBuilds.props

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,23 @@
1212

1313
<!-- Enable ContinuousIntegrationBuild when running on CI -->
1414

15-
<!-- Azure Pipelines / DevOpsServer -->
15+
<!-- Azure Pipelines / DevOpsServer
16+
https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml#system-variables-devops-services
17+
-->
1618
<PropertyGroup Condition="'$(TF_BUILD)' == 'true'">
1719
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
1820
</PropertyGroup>
1921

20-
<!-- GitHub Actions -->
22+
<!-- GitHub Actions
23+
https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables#default-environment-variables
24+
-->
2125
<PropertyGroup Condition="'$(GITHUB_ACTIONS)' == 'true'">
2226
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
2327
</PropertyGroup>
2428

25-
<!-- AppVeyor -->
29+
<!-- AppVeyor
30+
https://www.appveyor.com/docs/environment-variables/
31+
-->
2632
<PropertyGroup Condition="'$(APPVEYOR)' == 'true'">
2733
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
2834
</PropertyGroup>
@@ -32,17 +38,23 @@
3238
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
3339
</PropertyGroup>
3440

35-
<!-- Travis CI -->
41+
<!-- Travis CI
42+
https://docs.travis-ci.com/user/environment-variables/#default-environment-variables
43+
-->
3644
<PropertyGroup Condition="'$(TRAVIS)' == 'true'">
3745
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
3846
</PropertyGroup>
3947

40-
<!-- Circle CI -->
48+
<!-- Circle CI
49+
https://circleci.com/docs/variables/#built-in-environment-variables
50+
-->
4151
<PropertyGroup Condition="'$(CIRCLECI)' == 'true'">
4252
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
4353
</PropertyGroup>
4454

45-
<!-- AWS CodeBuild -->
55+
<!-- AWS CodeBuild
56+
https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-env-vars.html
57+
-->
4658
<PropertyGroup Condition="'$(CODEBUILD_BUILD_ID)' != '' and '$(AWS_REGION)' != '' ">
4759
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
4860
</PropertyGroup>
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
using FluentAssertions;
2+
using Microsoft.Build.Utilities.ProjectCreation;
3+
4+
namespace DotNet.ReproducibleBuilds.Tests;
5+
6+
public class ContinuousIntegrationTests : TestBase
7+
{
8+
private const string ContinuousIntegrationBuild = "ContinuousIntegrationBuild";
9+
10+
[Theory]
11+
[InlineData(null, "")]
12+
[InlineData(true, "true")]
13+
[InlineData(false, "false")]
14+
public void RespectsSetValue(bool? value, string expected)
15+
{
16+
using EnvironmentVariableSuppressor hostSuppressor = new("TF_BUILD"); // Suppress our own CI provider variables (i.e. Azure DevOps)
17+
18+
ProjectCreator.Templates
19+
.ReproducibleBuildProject(GetRandomFile(".csproj"))
20+
.PropertyGroup()
21+
.Property(ContinuousIntegrationBuild, value?.ToLowerInvariant())
22+
.Project
23+
.GetPropertyValue(ContinuousIntegrationBuild)
24+
.Should().Be(expected);
25+
}
26+
27+
[Theory]
28+
[MemberData(nameof(MemberData))]
29+
public void RespectsGlobalProperites(Dictionary<string, string> envVars)
30+
{
31+
using EnvironmentVariableSuppressor hostSuppressor = new("TF_BUILD"); // Suppress our own CI provider variables (i.e. Azure DevOps)
32+
33+
// If ContinuousIntegrationBuild is not set, it should be set from the CI provider property
34+
ProjectCreator.Templates
35+
.ReproducibleBuildProject(GetRandomFile(".csproj"))
36+
.ProjectWithGlobalProperties(envVars)
37+
.GetPropertyValue(ContinuousIntegrationBuild)
38+
.Should().Be(true.ToLowerInvariant());
39+
40+
// If ContinuousIntegrationBuild is set, it should take precedence over the CI provider variables
41+
ProjectCreator.Templates
42+
.ReproducibleBuildProject(GetRandomFile(".csproj"))
43+
.ProjectWithGlobalProperties(envVars.With(ContinuousIntegrationBuild, false.ToLowerInvariant()))
44+
.GetPropertyValue(ContinuousIntegrationBuild)
45+
.Should().Be(false.ToLowerInvariant(), "because explicitly setting `ContinuousIntegrationBuild` should always win.");
46+
}
47+
48+
public static TheoryData<Dictionary<string, string>> MemberData()
49+
{
50+
return new TheoryData<Dictionary<string, string>>
51+
{
52+
{ new() { ["TF_BUILD"] = "True" } },
53+
{ new() { ["GITHUB_ACTIONS"] = "true" } },
54+
{ new() { ["APPVEYOR"] = "True" } },
55+
{ new() { ["CI"] = "true" } },
56+
{ new() { ["TRAVIS"] = "true" } },
57+
{ new() { ["CIRCLECI"] = "true" } },
58+
{ new() { ["CODEBUILD_BUILD_ID"] = "abc:123", ["AWS_REGION"] = "us-east-1" } },
59+
{ new() { ["BUILD_ID"] = "123", ["BUILD_URL"] = "https://buildserver.invalid/jenkins/job/MyJobName/123/" } },
60+
{ new() { ["BUILD_ID"] = "123", ["PROJECT_ID"] = "234" } },
61+
{ new() { ["TEAMCITY_VERSION"] = "10" } },
62+
{ new() { ["JB_SPACE_API_URL"] = "https://api.invalid/url" } },
63+
};
64+
}
65+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace DotNet.ReproducibleBuilds.Tests;
2+
3+
internal static class DictionaryExtensions
4+
{
5+
public static IDictionary<TKey, TValue> With<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, TValue value) where TKey : notnull
6+
=> new Dictionary<TKey, TValue>(dictionary) { [key] = value };
7+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using Microsoft.Build.Evaluation;
2+
using Microsoft.Build.Utilities.ProjectCreation;
3+
4+
namespace DotNet.ReproducibleBuilds.Tests;
5+
6+
internal static class ProjectCreatorExtensions
7+
{
8+
public static Project ProjectWithGlobalProperties(this ProjectCreator creator, IDictionary<string, string> properties)
9+
{
10+
creator.TryGetProject(out Project project, properties);
11+
12+
return project;
13+
}
14+
}

tests/DotNet.ReproducibleBuilds.Tests/ProjectTemplates.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Microsoft.Build.Utilities.ProjectCreation;
1+
using Microsoft.Build.Evaluation;
2+
using Microsoft.Build.Utilities.ProjectCreation;
23

34
namespace DotNet.ReproducibleBuilds.Tests;
45

@@ -20,7 +21,9 @@ public static ProjectCreator ReproducibleBuildProject(this ProjectCreatorTemplat
2021
.Import(Path.Combine(ThisAssemblyDirectory, "DotNet.ReproducibleBuilds.targets"))
2122
.Save();
2223

24+
ProjectCollection projectCollection = new(); // Create a new collection for each project to ensure environment variables aren't shared between tests
25+
2326
return templates
24-
.SdkCsproj(path: project.FullName, targetFramework: "net8.0");
27+
.SdkCsproj(path: project.FullName, targetFramework: "net8.0", projectCollection: projectCollection);
2528
}
2629
}

tests/DotNet.ReproducibleBuilds.Tests/SourceLinkTests.cs

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -81,25 +81,22 @@ public void EmbedUntrackedSourcesIsSet(bool? embedUntrackedSources, bool expecte
8181
public void RepositoryBranchIsSet(string ci, string original, string expected)
8282
{
8383
using EnvironmentVariableSuppressor hostSuppressor = new("BUILD_SOURCEBRANCH"); // Suppress our own CI provider variables (i.e. Azure DevOps)
84-
using EnvironmentVariableSuppressor ciSuppressor = new(ci); // Suppress the mock CI provider (just in case).
84+
using EnvironmentVariableSuppressor ciSuppressor = new(ci); // Suppress the mock CI provider (just in case)
8585

86-
// If RepositoryBranch is set, it should take precedence over the CI provider variables
87-
ProjectCreator.Templates
86+
ProjectCreator project = ProjectCreator.Templates
8887
.ReproducibleBuildProject(GetRandomFile(".csproj"))
8988
.PropertyGroup()
90-
.Property("RepositoryBranch", "explicitly-set")
91-
.Property(ci, original)
92-
.Project
93-
.GetPropertyValue("RepositoryBranch")
94-
.Should().Be("explicitly-set", "because explicitly setting `RepositoryBranch` should always win.");
89+
.Property(ci, original);
9590

9691
// If RepositoryBranch is not set, it should be set from the CI provider property
97-
ProjectCreator.Templates
98-
.ReproducibleBuildProject(GetRandomFile(".csproj"))
99-
.PropertyGroup()
100-
.Property(ci, original)
101-
.Project
92+
project.Project
10293
.GetPropertyValue("RepositoryBranch")
10394
.Should().Be(expected);
95+
96+
// If RepositoryBranch is set, it should take precedence over the CI provider variables
97+
project.Property("RepositoryBranch", "explicitly-set")
98+
.Project
99+
.GetPropertyValue("RepositoryBranch")
100+
.Should().Be("explicitly-set", "because explicitly setting `RepositoryBranch` should always win.");
104101
}
105102
}

0 commit comments

Comments
 (0)