diff --git a/README.md b/README.md
index 88b726ed..e1d1bc14 100644
--- a/README.md
+++ b/README.md
@@ -92,7 +92,7 @@ For projects hosted by [GitLab](https://gitlab.com) reference [Microsoft.SourceL
### Bitbucket.org
-For projects hosted on [Bitbucket.org](https://bitbucket.org) in git repositories reference [Microsoft.SourceLink.Bitbucket.Git](https://www.nuget.org/packages/Microsoft.SourceLink.Bitbucket.Git) package:
+For projects hosted on [Bitbucket.org](https://bitbucket.org) in git repositories reference [Microsoft.SourceLink.Bitbucket.Git](https://www.nuget.org/packages/Microsoft.SourceLink.Bitbucket.Git) package:
```xml
@@ -100,6 +100,19 @@ For projects hosted on [Bitbucket.org](https://bitbucket.org) in git repositorie
```
+For self-hosted Bitbucket projects reference [Microsoft.SourceLink.Bitbucket.Git](https://www.nuget.org/packages/Microsoft.SourceLink.Bitbucket.Git) package and add Bitbucket host configuration.
+Additional configuration is available when SourceLinkBitbucketGitHost is added to csproj:
+
+- EnterpriseEdition - flag whether it is Enterprise Edition or Cloud Edition, by default it is true.
+- Version="4.7" - for Enterprise Edition provides its version. URL format for accessing files is different for Bitbucket in version < 4.7, please add Bitbucket version if it is the case
+
+```xml
+
+
+
+
+```
+
### Multiple providers, repositories with submodules
If your repository contains submodules hosted by other git providers reference packages of all these providers. For example, projects in a repository hosted by Azure DevOps that links a GitHub repository via a submodule should reference both [Microsoft.SourceLink.Vsts.Git](https://www.nuget.org/packages/Microsoft.SourceLink.Vsts.Git) and [Microsoft.SourceLink.GitHub](https://www.nuget.org/packages/Microsoft.SourceLink.GitHub) packages. [Additional configuration](https://github.com/dotnet/sourcelink/blob/master/docs/README.md#configuring-projects-with-multiple-sourcelink-providers) might be needed if multiple Source Link packages are used in the project.
diff --git a/src/SourceLink.Bitbucket.Git.UnitTests/GetSourceLinkUrlTests.cs b/src/SourceLink.Bitbucket.Git.UnitTests/GetSourceLinkUrlTests.cs
index b0bc0eff..b0c6e170 100644
--- a/src/SourceLink.Bitbucket.Git.UnitTests/GetSourceLinkUrlTests.cs
+++ b/src/SourceLink.Bitbucket.Git.UnitTests/GetSourceLinkUrlTests.cs
@@ -8,6 +8,11 @@ namespace Microsoft.SourceLink.Bitbucket.Git.UnitTests
{
public class GetSourceLinkUrlTests
{
+ private const string ExpectedUrlForCloudEdition =
+ "https://domain.com/x/y/a/b/raw/0123456789abcdefABCDEF000000000000000000/*";
+ private const string ExpectedUrlForEnterpriseEditionOldVersion = "https://bitbucket.domain.com/projects/a/repos/b/browse/*?at=0123456789abcdefABCDEF000000000000000000&raw";
+ private const string ExpectedUrlForEnterpriseEditionNewVersion = "https://bitbucket.domain.com/projects/a/repos/b/raw/*?at=0123456789abcdefABCDEF000000000000000000";
+
[Fact]
public void EmptyHosts()
{
@@ -32,24 +37,190 @@ public void EmptyHosts()
[InlineData("", "/")]
[InlineData("/", "")]
[InlineData("/", "/")]
- public void BuildSourceLinkUrl(string s1, string s2)
+ public void BuildSourceLinkUrl_BitbucketCloud(string s1, string s2)
{
+ var isEnterpriseEditionSetting = KVP("EnterpriseEdition", "false");
var engine = new MockEngine();
-
var task = new GetSourceLinkUrl()
{
BuildEngine = engine,
SourceRoot = new MockItem("/src/", KVP("RepositoryUrl", "http://subdomain.mybitbucket.org:100/a/b" + s1), KVP("SourceControl", "git"), KVP("RevisionId", "0123456789abcdefABCDEF000000000000000000")),
Hosts = new[]
{
- new MockItem("mybitbucket.org", KVP("ContentUrl", "https://domain.com/x/y" + s2)),
+ new MockItem("mybitbucket.org", KVP("ContentUrl", "https://domain.com/x/y" + s2), isEnterpriseEditionSetting),
+ }
+ };
+
+ bool result = task.Execute();
+ AssertEx.AssertEqualToleratingWhitespaceDifferences("", engine.Log);
+ AssertEx.AreEqual(ExpectedUrlForCloudEdition, task.SourceLinkUrl);
+ Assert.True(result);
+ }
+
+ [Fact]
+ public void BuildSourceLinkUrl_MetadataWithEnterpriseEditionButWithoutVersion_UseNewVersionAsDefauld()
+ {
+ var isEnterpriseEditionSetting = KVP("EnterpriseEdition", "true");
+ var engine = new MockEngine();
+ var task = new GetSourceLinkUrl()
+ {
+ BuildEngine = engine,
+ SourceRoot = new MockItem("/src/", KVP("RepositoryUrl", "http://bitbucket.domain.com:100/a/b"), KVP("SourceControl", "git"), KVP("RevisionId", "0123456789abcdefABCDEF000000000000000000")),
+ Hosts = new[]
+ {
+ new MockItem("domain.com", KVP("ContentUrl", "https://bitbucket.domain.com"), isEnterpriseEditionSetting),
+ }
+ };
+
+ bool result = task.Execute();
+ AssertEx.AssertEqualToleratingWhitespaceDifferences("", engine.Log);
+ AssertEx.AreEqual(ExpectedUrlForEnterpriseEditionNewVersion, task.SourceLinkUrl);
+ Assert.True(result);
+ }
+
+ [Theory]
+ [InlineData("", "", "4.4")]
+ [InlineData("", "/", "4.4")]
+ [InlineData("/", "", "4.4")]
+ [InlineData("/", "/", "4.4")]
+ [InlineData("", "", "4.6")]
+ [InlineData("", "/", "4.6")]
+ [InlineData("/", "", "4.6")]
+ [InlineData("/", "/", "4.6")]
+ public void BuildSourceLinkUrl_BitbucketEnterpriseOldVersionSsh(string s1, string s2, string bitbucketVersion)
+ {
+ var isEnterpriseEditionSetting = KVP("EnterpriseEdition", "true");
+ var version = KVP("Version", bitbucketVersion);
+ var engine = new MockEngine();
+ var task = new GetSourceLinkUrl()
+ {
+ BuildEngine = engine,
+ SourceRoot = new MockItem("/src/", KVP("RepositoryUrl", "http://bitbucket.domain.com:100/a/b" + s1), KVP("SourceControl", "git"), KVP("RevisionId", "0123456789abcdefABCDEF000000000000000000")),
+ Hosts = new[]
+ {
+ new MockItem("domain.com", KVP("ContentUrl", "https://bitbucket.domain.com" + s2), isEnterpriseEditionSetting, version),
+ }
+ };
+
+ bool result = task.Execute();
+ AssertEx.AssertEqualToleratingWhitespaceDifferences("", engine.Log);
+ AssertEx.AreEqual(ExpectedUrlForEnterpriseEditionOldVersion, task.SourceLinkUrl);
+ Assert.True(result);
+ }
+
+ [Theory]
+ [InlineData("", "", "4.4")]
+ [InlineData("", "/", "4.4")]
+ [InlineData("/", "", "4.4")]
+ [InlineData("/", "/", "4.4")]
+ [InlineData("", "", "4.6")]
+ [InlineData("", "/", "4.6")]
+ [InlineData("/", "", "4.6")]
+ [InlineData("/", "/", "4.6")]
+ public void BuildSourceLinkUrl_BitbucketEnterpriseOldVersionHttps(string s1, string s2, string bitbucketVersion)
+ {
+ var isEnterpriseEditionSetting = KVP("EnterpriseEdition", "true");
+ var version = KVP("Version", bitbucketVersion);
+ var engine = new MockEngine();
+ var task = new GetSourceLinkUrl()
+ {
+ BuildEngine = engine,
+ SourceRoot = new MockItem("/src/", KVP("RepositoryUrl", "http://bitbucket.domain.com:100/scm/a/b" + s1), KVP("SourceControl", "git"), KVP("RevisionId", "0123456789abcdefABCDEF000000000000000000")),
+ Hosts = new[]
+ {
+ new MockItem("domain.com", KVP("ContentUrl", "https://bitbucket.domain.com" + s2), isEnterpriseEditionSetting, version),
}
};
bool result = task.Execute();
AssertEx.AssertEqualToleratingWhitespaceDifferences("", engine.Log);
- AssertEx.AreEqual("https://domain.com/x/y/a/b/raw/0123456789abcdefABCDEF000000000000000000/*", task.SourceLinkUrl);
+ AssertEx.AreEqual(ExpectedUrlForEnterpriseEditionOldVersion, task.SourceLinkUrl);
Assert.True(result);
}
+
+ [Theory]
+ [InlineData("", "", "")]
+ [InlineData("", "", "4.7")]
+ [InlineData("", "/", "4.7")]
+ [InlineData("/", "", "4.7")]
+ [InlineData("/", "/", "4.7")]
+ [InlineData("", "", "5.6")]
+ [InlineData("", "/", "5.6")]
+ [InlineData("/", "", "5.6")]
+ [InlineData("/", "/", "5.6")]
+ public void BuildSourceLinkUrl_BitbucketEnterpriseNewVersionSsh(string s1, string s2, string bitbucketVersion)
+ {
+ var isEnterpriseEditionSetting = KVP("EnterpriseEdition", "true");
+ var version = KVP("Version", bitbucketVersion);
+ var engine = new MockEngine();
+ var task = new GetSourceLinkUrl()
+ {
+ BuildEngine = engine,
+ SourceRoot = new MockItem("/src/", KVP("RepositoryUrl", "http://bitbucket.domain.com:100/a/b" + s1), KVP("SourceControl", "git"), KVP("RevisionId", "0123456789abcdefABCDEF000000000000000000")),
+ Hosts = new[]
+ {
+ new MockItem("domain.com", KVP("ContentUrl", "https://bitbucket.domain.com" + s2), isEnterpriseEditionSetting, version),
+ }
+ };
+
+ bool result = task.Execute();
+ AssertEx.AssertEqualToleratingWhitespaceDifferences("", engine.Log);
+ AssertEx.AreEqual(ExpectedUrlForEnterpriseEditionNewVersion, task.SourceLinkUrl);
+ Assert.True(result);
+ }
+
+ [Theory]
+ [InlineData("", "", "")]
+ [InlineData("", "", "4.7")]
+ [InlineData("", "/", "4.7")]
+ [InlineData("/", "", "4.7")]
+ [InlineData("/", "/", "4.7")]
+ [InlineData("", "", "5.6")]
+ [InlineData("", "/", "5.6")]
+ [InlineData("/", "", "5.6")]
+ [InlineData("/", "/", "5.6")]
+ public void BuildSourceLinkUrl_BitbucketEnterpriseNewVersionHttps(string s1, string s2, string bitbucketVersion)
+ {
+ var isEnterpriseEditionSetting = KVP("EnterpriseEdition", "true");
+ var version = KVP("Version", bitbucketVersion);
+ var engine = new MockEngine();
+ var task = new GetSourceLinkUrl()
+ {
+ BuildEngine = engine,
+ SourceRoot = new MockItem("/src/", KVP("RepositoryUrl", "http://bitbucket.domain.com:100/scm/a/b" + s1), KVP("SourceControl", "git"), KVP("RevisionId", "0123456789abcdefABCDEF000000000000000000")),
+ Hosts = new[]
+ {
+ new MockItem("domain.com", KVP("ContentUrl", "https://bitbucket.domain.com" + s2), isEnterpriseEditionSetting, version),
+ }
+ };
+
+ bool result = task.Execute();
+ AssertEx.AssertEqualToleratingWhitespaceDifferences("", engine.Log);
+ AssertEx.AreEqual(ExpectedUrlForEnterpriseEditionNewVersion, task.SourceLinkUrl);
+ Assert.True(result);
+ }
+
+ [Fact]
+ public void BuildSourceLinkUrl_IncorrectVersionForEnterpriseEdition_ERROR()
+ {
+ var isEnterpriseEditionSetting = KVP("EnterpriseEdition", "true");
+ var version = KVP("Version", "incorrect_version");
+ var engine = new MockEngine();
+ var task = new GetSourceLinkUrl()
+ {
+ BuildEngine = engine,
+ SourceRoot = new MockItem("/src/", KVP("RepositoryUrl", "http://bitbucket.domain.com:100/a/b"), KVP("SourceControl", "git"), KVP("RevisionId", "0123456789abcdefABCDEF000000000000000000")),
+ Hosts = new[]
+ {
+ new MockItem("domain.com", KVP("ContentUrl", "https://bitbucket.domain.com"), isEnterpriseEditionSetting, version),
+ }
+ };
+
+ bool result = task.Execute();
+
+ AssertEx.AssertEqualToleratingWhitespaceDifferences(
+ "ERROR : " + string.Format(CommonResources.ItemOfItemGroupMustSpecifyMetadata, "domain.com", "SourceLinkBitbucketGitHost", "Version"), engine.Log);
+ Assert.False(result);
+ }
}
}
diff --git a/src/SourceLink.Bitbucket.Git/GetSourceLinkUrl.cs b/src/SourceLink.Bitbucket.Git/GetSourceLinkUrl.cs
index 9a6e2031..7870674c 100644
--- a/src/SourceLink.Bitbucket.Git/GetSourceLinkUrl.cs
+++ b/src/SourceLink.Bitbucket.Git/GetSourceLinkUrl.cs
@@ -16,7 +16,78 @@ public sealed class GetSourceLinkUrl : GetSourceLinkUrlGitTask
protected override string HostsItemGroupName => "SourceLinkBitbucketGitHost";
protected override string ProviderDisplayName => "Bitbucket.Git";
+ private const string IsEnterpriseEditionMetadataName = "EnterpriseEdition";
+ private const string VersionMetadataName = "Version";
+ private const string VersionWithNewUrlFormat = "4.7";
+
protected override string BuildSourceLinkUrl(Uri contentUri, Uri gitUri, string relativeUrl, string revisionId, ITaskItem hostItem)
- => UriUtilities.Combine(UriUtilities.Combine(contentUri.ToString(), relativeUrl), "raw/" + revisionId + "/*");
+ {
+ return
+ bool.TryParse(hostItem?.GetMetadata(IsEnterpriseEditionMetadataName), out var isEnterpriseEdition) && !isEnterpriseEdition
+ ? BuildSourceLinkUrlForCloudEdition(contentUri, relativeUrl, revisionId)
+ : BuildSourceLinkUrlForEnterpriseEdition(contentUri, relativeUrl, revisionId, hostItem);
+ }
+
+ private string BuildSourceLinkUrlForEnterpriseEdition(Uri contentUri, string relativeUrl, string revisionId,
+ ITaskItem hostItem)
+ {
+ var bitbucketEnterpriseVersion = GetBitbucketEnterpriseVersion(hostItem);
+
+ var splits = relativeUrl.Split(new[] {'/'}, StringSplitOptions.RemoveEmptyEntries);
+ var isSshRepoUri = !(splits.Length == 3 && splits[0] == "scm");
+ var projectName = isSshRepoUri ? splits[0] : splits[1];
+ var repositoryName = isSshRepoUri ? splits[1] : splits[2];
+
+ var relativeUrlForBitbucketEnterprise =
+ GetRelativeUrlForBitbucketEnterprise(projectName, repositoryName, revisionId,
+ bitbucketEnterpriseVersion);
+
+ var result = UriUtilities.Combine(contentUri.ToString(), relativeUrlForBitbucketEnterprise);
+
+ return result;
+ }
+
+ private Version GetBitbucketEnterpriseVersion(ITaskItem hostItem)
+ {
+ var bitbucketEnterpriseVersionAsString = hostItem?.GetMetadata(VersionMetadataName);
+ Version bitbucketEnterpriseVersion;
+ if (!string.IsNullOrEmpty(bitbucketEnterpriseVersionAsString))
+ {
+ if (!Version.TryParse(bitbucketEnterpriseVersionAsString, out bitbucketEnterpriseVersion))
+ {
+ Log.LogError(CommonResources.ItemOfItemGroupMustSpecifyMetadata, hostItem.ItemSpec,
+ HostsItemGroupName, VersionMetadataName);
+
+ return null;
+ }
+ }
+ else
+ {
+ bitbucketEnterpriseVersion = Version.Parse(VersionWithNewUrlFormat);
+ }
+
+ return bitbucketEnterpriseVersion;
+ }
+
+ private static string BuildSourceLinkUrlForCloudEdition(Uri contentUri, string relativeUrl, string revisionId)
+ {
+ return UriUtilities.Combine(UriUtilities.Combine(contentUri.ToString(), relativeUrl),
+ "raw/" + revisionId + "/*");
+ }
+
+ private static string GetRelativeUrlForBitbucketEnterprise(string projectName, string repositoryName, string commitId, Version bitbucketVersion)
+ {
+ string relativeUrl;
+ if (bitbucketVersion >= Version.Parse(VersionWithNewUrlFormat))
+ {
+ relativeUrl = $"projects/{projectName}/repos/{repositoryName}/raw/*?at={commitId}";
+ }
+ else
+ {
+ relativeUrl = $"projects/{projectName}/repos/{repositoryName}/browse/*?at={commitId}&raw";
+ }
+
+ return relativeUrl;
+ }
}
}
diff --git a/src/SourceLink.Bitbucket.Git/build/Microsoft.SourceLink.Bitbucket.Git.props b/src/SourceLink.Bitbucket.Git/build/Microsoft.SourceLink.Bitbucket.Git.props
index 08469bed..8710d6aa 100644
--- a/src/SourceLink.Bitbucket.Git/build/Microsoft.SourceLink.Bitbucket.Git.props
+++ b/src/SourceLink.Bitbucket.Git/build/Microsoft.SourceLink.Bitbucket.Git.props
@@ -1,6 +1,6 @@
-
+
diff --git a/src/SourceLink.Git.IntegrationTests/BitbucketGitTests.cs b/src/SourceLink.Git.IntegrationTests/BitbucketGitTests.cs
index b1f85036..70000639 100644
--- a/src/SourceLink.Git.IntegrationTests/BitbucketGitTests.cs
+++ b/src/SourceLink.Git.IntegrationTests/BitbucketGitTests.cs
@@ -13,7 +13,7 @@ public BitBucketGitTests()
}
[ConditionalFact(typeof(DotNetSdkAvailable))]
- public void FullValidation_Https()
+ public void FullValidation_CloudHttps()
{
// Test non-ascii characters and escapes in the URL.
// Escaped URI reserved characters should remain escaped, non-reserved characters unescaped in the results.
@@ -27,8 +27,7 @@ public void FullValidation_Https()
customProps: @"
true
-
-",
+",
customTargets: "",
targets: new[]
{
@@ -67,7 +66,180 @@ public void FullValidation_Https()
}
[ConditionalFact(typeof(DotNetSdkAvailable))]
- public void FullValidation_Ssh()
+ public void FullValidation_EnterpriseNewHttps()
+ {
+ // Test non-ascii characters and escapes in the URL.
+ // Escaped URI reserved characters should remain escaped, non-reserved characters unescaped in the results.
+ var repoUrl = "https://bitbucket.domain.com/scm/test-org/test-%72epo\u1234%24%2572%2F";
+ var repoName = "test-repo\u1234%24%2572%2F";
+
+ var repo = GitUtilities.CreateGitRepositoryWithSingleCommit(ProjectDir.Path, new[] {ProjectFileName},
+ repoUrl);
+ var commitSha = repo.Head.Tip.Sha;
+
+ VerifyValues(
+ customProps: @"
+
+ true
+
+
+
+
+",
+ customTargets: "",
+ targets: new[]
+ {
+ "Build", "Pack"
+ },
+ expressions: new[]
+ {
+ "@(SourceRoot)",
+ "@(SourceRoot->'%(SourceLinkUrl)')",
+ "$(SourceLink)",
+ "$(PrivateRepositoryUrl)",
+ "$(RepositoryUrl)"
+ },
+ expectedResults: new[]
+ {
+ ProjectSourceRoot,
+ $"https://bitbucket.domain.com/projects/test-org/repos/{repoName}/raw/*?at={commitSha}",
+ s_relativeSourceLinkJsonPath,
+ $"https://bitbucket.domain.com/scm/test-org/{repoName}",
+ $"https://bitbucket.domain.com/scm/test-org/{repoName}"
+ });
+
+ AssertEx.AreEqual(
+ $@"{{""documents"":{{""{ProjectSourceRoot.Replace(@"\", @"\\")}*"":""https://bitbucket.domain.com/projects/test-org/repos/{repoName}/raw/*?at={commitSha}""}}}}",
+ File.ReadAllText(Path.Combine(ProjectDir.Path, s_relativeSourceLinkJsonPath)));
+
+ TestUtilities.ValidateAssemblyInformationalVersion(
+ Path.Combine(ProjectDir.Path, s_relativeOutputFilePath),
+ "1.0.0+" + commitSha);
+
+ TestUtilities.ValidateNuSpecRepository(
+ Path.Combine(ProjectDir.Path, s_relativePackagePath),
+ type: "git",
+ commit: commitSha,
+ url: $"https://bitbucket.domain.com/scm/test-org/{repoName}");
+ }
+
+ [ConditionalFact(typeof(DotNetSdkAvailable))]
+ public void FullValidation_EnterpriseNewHttpsWithDefaultFlags()
+ {
+ // Test non-ascii characters and escapes in the URL.
+ // Escaped URI reserved characters should remain escaped, non-reserved characters unescaped in the results.
+ var repoUrl = "https://bitbucket.domain.com/scm/test-org/test-%72epo\u1234%24%2572%2F";
+ var repoName = "test-repo\u1234%24%2572%2F";
+
+ var repo = GitUtilities.CreateGitRepositoryWithSingleCommit(ProjectDir.Path, new[] { ProjectFileName },
+ repoUrl);
+ var commitSha = repo.Head.Tip.Sha;
+
+ VerifyValues(
+ customProps: @"
+
+ true
+
+
+
+
+",
+ customTargets: "",
+ targets: new[]
+ {
+ "Build", "Pack"
+ },
+ expressions: new[]
+ {
+ "@(SourceRoot)",
+ "@(SourceRoot->'%(SourceLinkUrl)')",
+ "$(SourceLink)",
+ "$(PrivateRepositoryUrl)",
+ "$(RepositoryUrl)"
+ },
+ expectedResults: new[]
+ {
+ ProjectSourceRoot,
+ $"https://bitbucket.domain.com/projects/test-org/repos/{repoName}/raw/*?at={commitSha}",
+ s_relativeSourceLinkJsonPath,
+ $"https://bitbucket.domain.com/scm/test-org/{repoName}",
+ $"https://bitbucket.domain.com/scm/test-org/{repoName}"
+ });
+
+ AssertEx.AreEqual(
+ $@"{{""documents"":{{""{ProjectSourceRoot.Replace(@"\", @"\\")}*"":""https://bitbucket.domain.com/projects/test-org/repos/{repoName}/raw/*?at={commitSha}""}}}}",
+ File.ReadAllText(Path.Combine(ProjectDir.Path, s_relativeSourceLinkJsonPath)));
+
+ TestUtilities.ValidateAssemblyInformationalVersion(
+ Path.Combine(ProjectDir.Path, s_relativeOutputFilePath),
+ "1.0.0+" + commitSha);
+
+ TestUtilities.ValidateNuSpecRepository(
+ Path.Combine(ProjectDir.Path, s_relativePackagePath),
+ type: "git",
+ commit: commitSha,
+ url: $"https://bitbucket.domain.com/scm/test-org/{repoName}");
+ }
+
+ [ConditionalFact(typeof(DotNetSdkAvailable))]
+ public void FullValidation_EnterpriseOldHttps()
+ {
+ // Test non-ascii characters and escapes in the URL.
+ // Escaped URI reserved characters should remain escaped, non-reserved characters unescaped in the results.
+ var repoUrl = "https://bitbucket.domain.com/scm/test-org/test-%72epo\u1234%24%2572%2F";
+ var repoName = "test-repo\u1234%24%2572%2F";
+
+ var repo = GitUtilities.CreateGitRepositoryWithSingleCommit(ProjectDir.Path, new[] { ProjectFileName }, repoUrl);
+ var commitSha = repo.Head.Tip.Sha;
+
+ VerifyValues(
+ customProps: @"
+
+ true
+
+
+
+
+ ",
+ customTargets: "",
+ targets: new[]
+ {
+ "Build", "Pack"
+ },
+ expressions: new[]
+ {
+ "@(SourceRoot)",
+ "@(SourceRoot->'%(SourceLinkUrl)')",
+ "$(SourceLink)",
+ "$(PrivateRepositoryUrl)",
+ "$(RepositoryUrl)"
+ },
+ expectedResults: new[]
+ {
+ ProjectSourceRoot,
+ $"https://bitbucket.domain.com/projects/test-org/repos/{repoName}/browse/*?at={commitSha}&raw",
+ s_relativeSourceLinkJsonPath,
+ $"https://bitbucket.domain.com/scm/test-org/{repoName}",
+ $"https://bitbucket.domain.com/scm/test-org/{repoName}"
+ });
+
+ AssertEx.AreEqual(
+ $@"{{""documents"":{{""{ProjectSourceRoot.Replace(@"\", @"\\")}*"":""https://bitbucket.domain.com/projects/test-org/repos/{repoName}/browse/*?at={commitSha}&raw""}}}}",
+ File.ReadAllText(Path.Combine(ProjectDir.Path, s_relativeSourceLinkJsonPath)));
+
+ TestUtilities.ValidateAssemblyInformationalVersion(
+ Path.Combine(ProjectDir.Path, s_relativeOutputFilePath),
+ "1.0.0+" + commitSha);
+
+ TestUtilities.ValidateNuSpecRepository(
+ Path.Combine(ProjectDir.Path, s_relativePackagePath),
+ type: "git",
+ commit: commitSha,
+ url: $"https://bitbucket.domain.com/scm/test-org/{repoName}");
+ }
+
+ [ConditionalFact(typeof(DotNetSdkAvailable))]
+ public void FullValidation_CloudSsh()
{
// Test non-ascii characters and escapes in the URL.
// Escaped URI reserved characters should remain escaped, non-reserved characters unescaped in the results.
@@ -83,7 +255,7 @@ public void FullValidation_Ssh()
true
-
+
",
customTargets: "",
@@ -122,5 +294,119 @@ public void FullValidation_Ssh()
commit: commitSha,
url: $"https://噸.com/test-org/{repoName}");
}
+
+ [ConditionalFact(typeof(DotNetSdkAvailable))]
+ public void FullValidation_EnterpriseOldSsh()
+ {
+ // Test non-ascii characters and escapes in the URL.
+ // Escaped URI reserved characters should remain escaped, non-reserved characters unescaped in the results.
+ var repoUrl = "test-user@噸.com:test-org/test-%72epo\u1234%24%2572%2F";
+ var repoName = "test-repo\u1234%24%2572%2F";
+
+ var repo = GitUtilities.CreateGitRepositoryWithSingleCommit(ProjectDir.Path, new[] { ProjectFileName }, repoUrl);
+ var commitSha = repo.Head.Tip.Sha;
+
+ VerifyValues(
+ customProps: @"
+
+ true
+
+
+
+
+",
+ customTargets: "",
+ targets: new[]
+ {
+ "Build", "Pack"
+ },
+ expressions: new[]
+ {
+ "@(SourceRoot)",
+ "@(SourceRoot->'%(SourceLinkUrl)')",
+ "$(SourceLink)",
+ "$(PrivateRepositoryUrl)",
+ "$(RepositoryUrl)"
+ },
+ expectedResults: new[]
+ {
+ ProjectSourceRoot,
+ $"https://噸.com/projects/test-org/repos/{repoName}/browse/*?at={commitSha}&raw",
+ s_relativeSourceLinkJsonPath,
+ $"https://噸.com/test-org/{repoName}",
+ $"https://噸.com/test-org/{repoName}"
+ });
+
+ AssertEx.AreEqual(
+ $@"{{""documents"":{{""{ProjectSourceRoot.Replace(@"\", @"\\")}*"":""https://噸.com/projects/test-org/repos/{repoName}/browse/*?at={commitSha}&raw""}}}}",
+ File.ReadAllText(Path.Combine(ProjectDir.Path, s_relativeSourceLinkJsonPath)));
+
+ TestUtilities.ValidateAssemblyInformationalVersion(
+ Path.Combine(ProjectDir.Path, s_relativeOutputFilePath),
+ "1.0.0+" + commitSha);
+
+ TestUtilities.ValidateNuSpecRepository(
+ Path.Combine(ProjectDir.Path, s_relativePackagePath),
+ type: "git",
+ commit: commitSha,
+ url: $"https://噸.com/test-org/{repoName}");
+ }
+
+ [ConditionalFact(typeof(DotNetSdkAvailable))]
+ public void FullValidation_EnterpriseNewSsh()
+ {
+ // Test non-ascii characters and escapes in the URL.
+ // Escaped URI reserved characters should remain escaped, non-reserved characters unescaped in the results.
+ var repoUrl = "test-user@噸.com:test-org/test-%72epo\u1234%24%2572%2F";
+ var repoName = "test-repo\u1234%24%2572%2F";
+
+ var repo = GitUtilities.CreateGitRepositoryWithSingleCommit(ProjectDir.Path, new[] { ProjectFileName }, repoUrl);
+ var commitSha = repo.Head.Tip.Sha;
+
+ VerifyValues(
+ customProps: @"
+
+ true
+
+
+
+
+",
+ customTargets: "",
+ targets: new[]
+ {
+ "Build", "Pack"
+ },
+ expressions: new[]
+ {
+ "@(SourceRoot)",
+ "@(SourceRoot->'%(SourceLinkUrl)')",
+ "$(SourceLink)",
+ "$(PrivateRepositoryUrl)",
+ "$(RepositoryUrl)"
+ },
+ expectedResults: new[]
+ {
+ ProjectSourceRoot,
+ $"https://噸.com/projects/test-org/repos/{repoName}/raw/*?at={commitSha}",
+ s_relativeSourceLinkJsonPath,
+ $"https://噸.com/test-org/{repoName}",
+ $"https://噸.com/test-org/{repoName}"
+ });
+
+ AssertEx.AreEqual(
+ $@"{{""documents"":{{""{ProjectSourceRoot.Replace(@"\", @"\\")}*"":""https://噸.com/projects/test-org/repos/{repoName}/raw/*?at={commitSha}""}}}}",
+ File.ReadAllText(Path.Combine(ProjectDir.Path, s_relativeSourceLinkJsonPath)));
+
+ TestUtilities.ValidateAssemblyInformationalVersion(
+ Path.Combine(ProjectDir.Path, s_relativeOutputFilePath),
+ "1.0.0+" + commitSha);
+
+ TestUtilities.ValidateNuSpecRepository(
+ Path.Combine(ProjectDir.Path, s_relativePackagePath),
+ type: "git",
+ commit: commitSha,
+ url: $"https://噸.com/test-org/{repoName}");
+ }
}
}