Skip to content

Commit

Permalink
Align RepositoryBranch logic with .NET 9 (#50)
Browse files Browse the repository at this point in the history
Fixes #46 

Addresses the difference in behavior between the .NET 9 SDK's version of
SourceLink and our own branch logic. Doing so has two implications:

1. We no longer attempt to shorten git refs like `refs/heads/` or
`refs/tags/`
2. We prefer the tag over the branch over the PR ID (old logic was PR
ID, tag, branch)

For code reviewers I suggest reviewing each commit separately, as the
first moves the test data and covers all the combinations of values, and
the second is the logic and test result change
  • Loading branch information
MattKotsenas authored Sep 6, 2024
1 parent 94faeb1 commit f2c641c
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 38 deletions.
13 changes: 6 additions & 7 deletions src/DotNet.ReproducibleBuilds/DotNet.ReproducibleBuilds.targets
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,31 @@

<PropertyGroup Condition="'$(RepositoryBranch)' == '' and '$(PublishRepositoryUrl)' == 'true'">
<!-- GitHub Actions: https://docs.github.com/en/actions/reference/environment-variables#default-environment-variables -->
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(GITHUB_REF)' != '' and $(GITHUB_REF.Contains('refs/pull/'))">pr$(GITHUB_REF.Replace('refs/pull/', '').Replace('/merge', ''))</RepositoryBranch>
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(GITHUB_REF)' != ''">$(GITHUB_REF.Replace('refs/heads/', '').Replace('refs/tags/', ''))</RepositoryBranch>
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(GITHUB_REF)' != ''">$(GITHUB_REF)</RepositoryBranch>
<!-- Azure DevOps: https://docs.microsoft.com/en-us/azure/devops/pipelines/build/variables -->
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(BUILD_SOURCEBRANCH)' != ''">$(BUILD_SOURCEBRANCH.Replace('refs/heads/', '').Replace('refs/tags/', ''))</RepositoryBranch>
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(BUILD_SOURCEBRANCH)' != ''">$(BUILD_SOURCEBRANCH)</RepositoryBranch>
<!-- AppVeyor: https://www.appveyor.com/docs/environment-variables/ -->
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(APPVEYOR_PULL_REQUEST_NUMBER)' != ''">pr$(APPVEYOR_PULL_REQUEST_NUMBER)</RepositoryBranch>
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(APPVEYOR_REPO_TAG_NAME)' != ''">$(APPVEYOR_REPO_TAG_NAME)</RepositoryBranch>
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(APPVEYOR_REPO_BRANCH)' != ''">$(APPVEYOR_REPO_BRANCH)</RepositoryBranch>
<!-- TeamCity: https://www.jetbrains.com/help/teamcity/predefined-build-parameters.html#Branch-Related+Parameters -->
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(TEAMCITY_BUILD_BRANCH)' != ''">$(TEAMCITY_BUILD_BRANCH)</RepositoryBranch>
<!--TravisCI: https://docs.travis-ci.com/user/environment-variables/ -->
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(TRAVIS_PULL_REQUEST)' != '' and '$(TRAVIS_PULL_REQUEST)' != 'false'">pr$(TRAVIS_PULL_REQUEST)</RepositoryBranch>
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(TRAVIS_BRANCH)' != ''">$(TRAVIS_BRANCH)</RepositoryBranch>
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(TRAVIS_PULL_REQUEST)' != '' and '$(TRAVIS_PULL_REQUEST)' != 'false'">pr$(TRAVIS_PULL_REQUEST)</RepositoryBranch>
<!-- CircleCI: https://circleci.com/docs/2.0/env-vars/ -->
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(CIRCLE_PR_NUMBER)' != ''">pr$(CIRCLE_PR_NUMBER)</RepositoryBranch>
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(CIRCLE_TAG)' != ''">$(CIRCLE_TAG)</RepositoryBranch>
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(CIRCLE_BRANCH)' != ''">$(CIRCLE_BRANCH)</RepositoryBranch>
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(CIRCLE_PR_NUMBER)' != ''">pr$(CIRCLE_PR_NUMBER)</RepositoryBranch>
<!-- GitLab: https://docs.gitlab.com/ee/ci/variables/predefined_variables.html -->
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(CI_COMMIT_TAG)' != ''">$(CI_COMMIT_TAG)</RepositoryBranch>
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(CI_COMMIT_BRANCH)' != ''">$(CI_COMMIT_BRANCH)</RepositoryBranch>
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(CI_MERGE_REQUEST_IID)' != ''">pr$(CI_MERGE_REQUEST_IID)</RepositoryBranch>
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(CI_EXTERNAL_PULL_REQUEST_IID)' != ''">pr$(CI_EXTERNAL_PULL_REQUEST_IID)</RepositoryBranch>
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(CI_COMMIT_BRANCH)' != ''">$(CI_COMMIT_BRANCH)</RepositoryBranch>
<!-- Buddy: https://buddy.works/docs/pipelines/environment-variables#default-environment-variables -->
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(BUDDY_EXECUTION_PULL_REQUEST_NO)' != ''">pr$(BUDDY_EXECUTION_PULL_REQUEST_NO)</RepositoryBranch>
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(BUDDY_EXECUTION_TAG)' != ''">$(BUDDY_EXECUTION_TAG)</RepositoryBranch>
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(BUDDY_EXECUTION_BRANCH)' != ''">$(BUDDY_EXECUTION_BRANCH)</RepositoryBranch>
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(BUDDY_EXECUTION_PULL_REQUEST_NO)' != ''">pr$(BUDDY_EXECUTION_PULL_REQUEST_NO)</RepositoryBranch>
</PropertyGroup>

<PropertyGroup>
Expand Down
6 changes: 6 additions & 0 deletions tests/DotNet.ReproducibleBuilds.Tests/CollectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace DotNet.ReproducibleBuilds.Tests;

internal static class CollectionExtensions
{
public static IDisposable ToDisposable(this IEnumerable<IDisposable> disposables) => new DisposableCollection(disposables);
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public void RespectsSetValue(bool? value, string expected)

[Theory]
[MemberData(nameof(MemberData))]
public void RespectsGlobalProperites(Dictionary<string, string> envVars)
public void RespectsGlobalProperties(Dictionary<string, string> envVars)
{
using EnvironmentVariableSuppressor hostSuppressor = new("TF_BUILD"); // Suppress our own CI provider variables (i.e. Azure DevOps)

Expand Down
18 changes: 18 additions & 0 deletions tests/DotNet.ReproducibleBuilds.Tests/DisposableCollection.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace DotNet.ReproducibleBuilds.Tests;

internal sealed class DisposableCollection : IDisposable
{
private readonly List<IDisposable> _disposables = [];

public DisposableCollection(IEnumerable<IDisposable> disposables) => _disposables.AddRange(disposables);

public void Add(IDisposable disposable) => _disposables.Add(disposable);

public void Dispose()
{
foreach (IDisposable disposable in _disposables)
{
disposable.Dispose();
}
}
}
10 changes: 10 additions & 0 deletions tests/DotNet.ReproducibleBuilds.Tests/ProjectCreatorExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,14 @@ public static Project ProjectWithGlobalProperties(this ProjectCreator creator, I

return project;
}

public static ProjectCreator Properties(this ProjectCreator creator, IEnumerable<KeyValuePair<string, string?>> properties)
{
foreach (KeyValuePair<string, string?> property in properties)
{
creator.Property(property.Key, property.Value);
}

return creator;
}
}
95 changes: 65 additions & 30 deletions tests/DotNet.ReproducibleBuilds.Tests/SourceLinkTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,42 +51,16 @@ public void EmbedUntrackedSourcesIsSet(bool? embedUntrackedSources, bool expecte
}

[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)
[MemberData(nameof(RepositoryBranchData))]
public void RepositoryBranchIsSet(Dictionary<string, string?> env, 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)
using IDisposable ciSuppressors = env.Select(kvp => new EnvironmentVariableSuppressor(kvp.Key)).ToDisposable(); // Suppress the mock CI provider (just in case)

ProjectCreator project = ProjectCreator.Templates
.ReproducibleBuildProject(GetRandomFile(".csproj"))
.PropertyGroup()
.Property(ci, original);
.Properties(env);

// If RepositoryBranch is not set, it should be set from the CI provider property
project.Project
Expand All @@ -99,4 +73,65 @@ public void RepositoryBranchIsSet(string ci, string original, string expected)
.GetPropertyValue("RepositoryBranch")
.Should().Be("explicitly-set", "because explicitly setting `RepositoryBranch` should always win.");
}

public static TheoryData<Dictionary<string, string?>, string> RepositoryBranchData()
{
TheoryData<Dictionary<string, string?>, string> data = new()
{
{ new() { ["GITHUB_REF"] = "refs/pull/1234/merge" }, "refs/pull/1234/merge" },
{ new() { ["GITHUB_REF"] = "refs/heads/my-branch" }, "refs/heads/my-branch" },
{ new() { ["GITHUB_REF"] = "refs/tags/v1.2.3" }, "refs/tags/v1.2.3" },

{ new() { ["BUILD_SOURCEBRANCH"] = "refs/heads/my-branch" }, "refs/heads/my-branch" },
{ new() { ["BUILD_SOURCEBRANCH"] = "refs/tags/v1.2.3" }, "refs/tags/v1.2.3" },

{ new() { ["APPVEYOR_PULL_REQUEST_NUMBER"] = "1234" }, "pr1234" },
{ new() { ["APPVEYOR_REPO_TAG_NAME"] = "refs/tags/v1.2.3" }, "refs/tags/v1.2.3" },
{ new() { ["APPVEYOR_REPO_BRANCH"] = "refs/heads/my-branch" }, "refs/heads/my-branch" },
{ new() { ["APPVEYOR_PULL_REQUEST_NUMBER"] = "1234" , ["APPVEYOR_REPO_BRANCH"] = "refs/heads/my-branch" }, "pr1234" },
{ new() { ["APPVEYOR_REPO_TAG_NAME"] = "refs/tags/v1.2.3" , ["APPVEYOR_REPO_BRANCH"] = "refs/heads/my-branch" }, "refs/tags/v1.2.3" },
{ new() { ["APPVEYOR_PULL_REQUEST_NUMBER"] = "1234", ["APPVEYOR_REPO_TAG_NAME"] = "refs/tags/v1.2.3", ["APPVEYOR_REPO_BRANCH"] = "refs/heads/my-branch" }, "pr1234" },

{ new() { ["TEAMCITY_BUILD_BRANCH"] = "refs/heads/my-branch" }, "refs/heads/my-branch" },

{ new() { ["TRAVIS_PULL_REQUEST"] = "1234" }, "pr1234" },
{ new() { ["TRAVIS_BRANCH"] = "refs/heads/my-branch" }, "refs/heads/my-branch" },
{ new() { ["TRAVIS_PULL_REQUEST"] = "1234", ["TRAVIS_BRANCH"] = "refs/heads/my-branch" }, "refs/heads/my-branch" },
{ new() { ["TRAVIS_PULL_REQUEST"] = "false", ["TRAVIS_BRANCH"] = "refs/heads/my-branch" }, "refs/heads/my-branch" },

{ new() { ["CIRCLE_PR_NUMBER"] = "1234" }, "pr1234" },
{ new() { ["CIRCLE_TAG"] = "refs/tags/v1.2.3" }, "refs/tags/v1.2.3" },
{ new() { ["CIRCLE_BRANCH"] = "refs/heads/my-branch" }, "refs/heads/my-branch" },
{ new() { ["CIRCLE_PR_NUMBER"] = "1234", ["CIRCLE_TAG"] = "refs/tags/v1.2.3" }, "refs/tags/v1.2.3" },
{ new() { ["CIRCLE_PR_NUMBER"] = "1234", ["CIRCLE_BRANCH"] = "refs/heads/my-branch" }, "refs/heads/my-branch" },
{ new() { ["CIRCLE_TAG"] = "refs/tags/v1.2.3", ["CIRCLE_BRANCH"] = "refs/heads/my-branch" }, "refs/tags/v1.2.3" },
{ new() { ["CIRCLE_PR_NUMBER"] = "1234", ["CIRCLE_TAG"] = "refs/tags/v1.2.3", ["CIRCLE_BRANCH"] = "refs/heads/my-branch" }, "refs/tags/v1.2.3" },

{ new() { ["CI_COMMIT_TAG"] = "refs/tags/v1.2.3" }, "refs/tags/v1.2.3" },
{ new() { ["CI_MERGE_REQUEST_IID"] = "1234" }, "pr1234" },
{ new() { ["CI_EXTERNAL_PULL_REQUEST_IID"] = "5678" }, "pr5678" },
{ new() { ["CI_COMMIT_BRANCH"] = "refs/heads/my-branch" }, "refs/heads/my-branch" },
{ new() { ["CI_COMMIT_TAG"] = "refs/tags/v1.2.3", ["CI_MERGE_REQUEST_IID"] = "1234" }, "refs/tags/v1.2.3" },
{ new() { ["CI_COMMIT_TAG"] = "refs/tags/v1.2.3", ["CI_EXTERNAL_PULL_REQUEST_IID"] = "5678" }, "refs/tags/v1.2.3" },
{ new() { ["CI_COMMIT_TAG"] = "refs/tags/v1.2.3", ["CI_COMMIT_BRANCH"] = "refs/heads/my-branch" }, "refs/tags/v1.2.3" },
{ new() { ["CI_MERGE_REQUEST_IID"] = "1234", ["CI_EXTERNAL_PULL_REQUEST_IID"] = "5678" }, "pr1234" },
{ new() { ["CI_MERGE_REQUEST_IID"] = "1234", ["CI_COMMIT_BRANCH"] = "refs/heads/my-branch" }, "refs/heads/my-branch" },
{ new() { ["CI_EXTERNAL_PULL_REQUEST_IID"] = "5678", ["CI_COMMIT_BRANCH"] = "refs/heads/my-branch" }, "refs/heads/my-branch" },
{ new() { ["CI_COMMIT_TAG"] = "refs/tags/v1.2.3", ["CI_MERGE_REQUEST_IID"] = "1234", ["CI_EXTERNAL_PULL_REQUEST_IID"] = "5678" }, "refs/tags/v1.2.3" },
{ new() { ["CI_COMMIT_TAG"] = "refs/tags/v1.2.3", ["CI_MERGE_REQUEST_IID"] = "1234", ["CI_COMMIT_BRANCH"] = "refs/heads/my-branch" }, "refs/tags/v1.2.3" },
{ new() { ["CI_COMMIT_TAG"] = "refs/tags/v1.2.3", ["CI_EXTERNAL_PULL_REQUEST_IID"] = "5678", ["CI_COMMIT_BRANCH"] = "refs/heads/my-branch" }, "refs/tags/v1.2.3" },
{ new() { ["CI_MERGE_REQUEST_IID"] = "1234", ["CI_EXTERNAL_PULL_REQUEST_IID"] = "5678", ["CI_COMMIT_BRANCH"] = "refs/heads/my-branch" }, "refs/heads/my-branch" },
{ new() { ["CI_COMMIT_TAG"] = "refs/tags/v1.2.3", ["CI_MERGE_REQUEST_IID"] = "1234", ["CI_EXTERNAL_PULL_REQUEST_IID"] = "5678", ["CI_COMMIT_BRANCH"] = "refs/heads/my-branch" }, "refs/tags/v1.2.3" },

{ new() { ["BUDDY_EXECUTION_PULL_REQUEST_NO"] = "1234" }, "pr1234" },
{ new() { ["BUDDY_EXECUTION_TAG"] = "refs/tags/v1.2.3" }, "refs/tags/v1.2.3" },
{ new() { ["BUDDY_EXECUTION_BRANCH"] = "refs/heads/my-branch" }, "refs/heads/my-branch" },
{ new() { ["BUDDY_EXECUTION_PULL_REQUEST_NO"] = "1234", ["BUDDY_EXECUTION_TAG"] = "refs/tags/v1.2.3" }, "refs/tags/v1.2.3" },
{ new() { ["BUDDY_EXECUTION_PULL_REQUEST_NO"] = "1234", ["BUDDY_EXECUTION_BRANCH"] = "refs/heads/my-branch" }, "refs/heads/my-branch" },
{ new() { ["BUDDY_EXECUTION_TAG"] = "refs/tags/v1.2.3", ["BUDDY_EXECUTION_BRANCH"] = "refs/heads/my-branch" }, "refs/tags/v1.2.3" },
{ new() { ["BUDDY_EXECUTION_PULL_REQUEST_NO"] = "1234", ["BUDDY_EXECUTION_BRANCH"] = "refs/heads/my-branch", ["BUDDY_EXECUTION_TAG"] = "refs/tags/v1.2.3" }, "refs/tags/v1.2.3" },
};

return data;
}
}

0 comments on commit f2c641c

Please sign in to comment.