diff --git a/nuspec/nuget/Cake.Tfs.nuspec b/nuspec/nuget/Cake.Tfs.nuspec index 0464da79..32476fa9 100644 --- a/nuspec/nuget/Cake.Tfs.nuspec +++ b/nuspec/nuget/Cake.Tfs.nuspec @@ -17,7 +17,7 @@ Copyright © Pascal Berger Cake Script Team-Foundation-Server TFS Azure-DevOps - https://github.com/cake-contrib/Cake.Tfs/releases/tag/0.2.5 + https://github.com/cake-contrib/Cake.Tfs/releases/tag/0.2.6 diff --git a/src/Cake.Tfs.Tests/ExceptionAssertExtensions.cs b/src/Cake.Tfs.Tests/ExceptionAssertExtensions.cs index 643dd331..0ff49ace 100644 --- a/src/Cake.Tfs.Tests/ExceptionAssertExtensions.cs +++ b/src/Cake.Tfs.Tests/ExceptionAssertExtensions.cs @@ -72,10 +72,21 @@ public static void IsTfsPullRequestNotFoundException(this Exception exception) /// /// Checks if an exception is of type /// - /// Exceptino to check. + /// Exception to check. public static void IsTfsException(this Exception exception) { Assert.IsType(exception); } + + /// + /// Checks if an exception is of type + /// + /// Exception to check. + /// Exception message which should be checked. + public static void IsTfsBranchNotFoundException(this Exception exception, string message) + { + Assert.IsType(exception); + Assert.Equal(message, exception.Message); + } } } diff --git a/src/Cake.Tfs.Tests/PullRequest/BasePullRequestFixture.cs b/src/Cake.Tfs.Tests/PullRequest/BasePullRequestFixture.cs new file mode 100644 index 00000000..4678f982 --- /dev/null +++ b/src/Cake.Tfs.Tests/PullRequest/BasePullRequestFixture.cs @@ -0,0 +1,27 @@ +namespace Cake.Tfs.Tests.PullRequest +{ + using Cake.Testing; + using Cake.Tfs.Tests.PullRequest.Fakes; + + internal abstract class BasePullRequestFixture + { + public const string ValidTfsUrl = "http://MyServer/tfs/MyCollection/MyTeamProject/_git/MyRepoName"; + public const string ValidAzureDevOpsUrl = "https://my-account.visualstudio.com/DefaultCollection/MyProject/_git/MyRepoName"; + public const string InvalidTfsUrl = "http://example.com"; + + public BasePullRequestFixture() + { + this.InitializeFakes(); + } + + public FakeLog Log { get; set; } + + public IGitClientFactory GitClientFactory { get; set; } + + private void InitializeFakes() + { + this.Log = new FakeLog(); + this.GitClientFactory = new FakeAllSetGitClientFactory(); + } + } +} diff --git a/src/Cake.Tfs.Tests/PullRequest/CommentThread/TfsCommentTests.cs b/src/Cake.Tfs.Tests/PullRequest/CommentThread/TfsCommentTests.cs new file mode 100644 index 00000000..953cbe58 --- /dev/null +++ b/src/Cake.Tfs.Tests/PullRequest/CommentThread/TfsCommentTests.cs @@ -0,0 +1,95 @@ +namespace Cake.Tfs.Tests.PullRequest.CommentThread +{ + using Cake.Tfs.PullRequest.CommentThread; + using Microsoft.TeamFoundation.SourceControl.WebApi; + using Shouldly; + using Xunit; + + public sealed class TfsCommentTests + { + public sealed class TheCtor + { + [Fact] + public void Should_Throw_If_Comment_Is_Null() + { + // Given, When + var result = Record.Exception(() => new TfsComment(null)); + + // Then + result.IsArgumentNullException("comment"); + } + + [Fact] + public void Should_Throw_If_Comment_Content_Is_Null() + { + // Given, When + var result = Record.Exception(() => new TfsComment(null, false)); + + // Then + result.IsArgumentNullException("content"); + } + + [Fact] + public void Should_Throw_If_Comment_Content_Is_Empty() + { + // Given, When + var result = Record.Exception(() => new TfsComment(string.Empty, false)); + + // Then + result.IsArgumentOutOfRangeException("content"); + } + + [Fact] + public void Should_Return_Empty_Comment() + { + // Given, When + var comment = new TfsComment(); + + // Then + comment.ShouldNotBeNull(); + comment.Content.ShouldBe(default(string)); + comment.IsDeleted.ShouldBe(default(bool)); + comment.CommentType.ShouldBe(default(TfsCommentType)); + } + + [Fact] + public void Should_Return_Valid_Comment_With_Default_Comment_Type() + { + // Given, When + var comment = new TfsComment("Hello", false); + + // Then + comment.ShouldNotBeNull(); + comment.Content.ShouldBe("Hello"); + comment.IsDeleted.ShouldBeFalse(); + comment.CommentType.ShouldBe(default(TfsCommentType)); + } + + [Fact] + public void Should_Return_Valid_Comment_Via_With_Specific_Comment_Type() + { + // Given, When + var comment = new TfsComment("What's up?", true, CommentType.Text); + + // Then + comment.ShouldNotBeNull(); + comment.Content.ShouldBe("What's up?"); + comment.IsDeleted.ShouldBeTrue(); + comment.CommentType.ShouldBe(TfsCommentType.Text); + } + + [Fact] + public void Should_Return_Valid_Comment_Via_Initializers() + { + // Given, When + var comment = new TfsComment { Content = "All good", IsDeleted = false, CommentType = TfsCommentType.CodeChange }; + + // Then + comment.ShouldNotBeNull(); + comment.Content.ShouldBe("All good"); + comment.IsDeleted.ShouldBeFalse(); + comment.CommentType.ShouldBe(TfsCommentType.CodeChange); + } + } + } +} diff --git a/src/Cake.Tfs.Tests/PullRequest/TfsPullRequestCommentThreadTests.cs b/src/Cake.Tfs.Tests/PullRequest/CommentThread/TfsPullRequestCommentThreadTests.cs similarity index 96% rename from src/Cake.Tfs.Tests/PullRequest/TfsPullRequestCommentThreadTests.cs rename to src/Cake.Tfs.Tests/PullRequest/CommentThread/TfsPullRequestCommentThreadTests.cs index fbe75317..f9e07fdd 100644 --- a/src/Cake.Tfs.Tests/PullRequest/TfsPullRequestCommentThreadTests.cs +++ b/src/Cake.Tfs.Tests/PullRequest/CommentThread/TfsPullRequestCommentThreadTests.cs @@ -1,4 +1,4 @@ -namespace Cake.Tfs.Tests.PullRequest +namespace Cake.Tfs.Tests.PullRequest.CommentThread { using System.Collections.Generic; using System.Linq; @@ -10,7 +10,7 @@ public sealed class TfsPullRequestCommentThreadTests { - public sealed class Ctor + public sealed class TheCtor { [Fact] public void Should_Throw_If_Input_Thread_IsNull() @@ -76,7 +76,7 @@ public void Should_Return_Valid_Comment_Thread() } } - public sealed class FilePath + public sealed class TheFilePathProperty { [Fact] public void Should_Return_Null_If_Not_Initialized() @@ -107,8 +107,10 @@ public void Should_Set_And_Trimmed_Properly() }; // When - var tfsThread = new TfsPullRequestCommentThread(thread); - tfsThread.FilePath = "/path/to/myclass.cs"; + var tfsThread = new TfsPullRequestCommentThread(thread) + { + FilePath = "/path/to/myclass.cs" + }; // Then tfsThread.FilePath.ShouldNotBeNull(); @@ -116,7 +118,7 @@ public void Should_Set_And_Trimmed_Properly() } } - public sealed class Comments + public sealed class TheCommentsProperty { [Fact] public void Should_Throw_If_Not_Set() @@ -163,7 +165,7 @@ public void Should_Set_Properly() } } - public sealed class Properties + public sealed class ThePropertiesProperty { [Fact] public void Should_Return_Null_If_Not_Set() @@ -228,7 +230,7 @@ public void Should_Set_Colletion_With_Single_Element() } } - public sealed class GetValue + public sealed class TheGetValueMethod { [Fact] public void Should_Throw_If_Property_Name_Is_Null() @@ -300,7 +302,7 @@ public void Should_Get_Valid_Properties() } } - public sealed class SetValue + public sealed class TheSetValueMethod { [Fact] public void Should_Throw_If_Property_Name_Is_Null() diff --git a/src/Cake.Tfs.Tests/PullRequest/CreatePullRequestFixture.cs b/src/Cake.Tfs.Tests/PullRequest/CreatePullRequestFixture.cs new file mode 100644 index 00000000..973e13c7 --- /dev/null +++ b/src/Cake.Tfs.Tests/PullRequest/CreatePullRequestFixture.cs @@ -0,0 +1,25 @@ +namespace Cake.Tfs.Tests.PullRequest +{ + using System; + using Cake.Tfs.Authentication; + using Cake.Tfs.PullRequest; + + internal class CreatePullRequestFixture + : BasePullRequestFixture + { + public CreatePullRequestFixture(string repoUrl, string sourceRefName, string targetRefName, string title, string description) + : base() + { + this.Settings = + new TfsCreatePullRequestSettings( + new Uri(repoUrl), + sourceRefName, + targetRefName, + title, + description, + new TfsNtlmCredentials()); + } + + public TfsCreatePullRequestSettings Settings { get; set; } + } +} diff --git a/src/Cake.Tfs.Tests/PullRequest/Fakes/FakeAllSetGitClientFactory.cs b/src/Cake.Tfs.Tests/PullRequest/Fakes/FakeAllSetGitClientFactory.cs index a9fc58c6..ac010929 100644 --- a/src/Cake.Tfs.Tests/PullRequest/Fakes/FakeAllSetGitClientFactory.cs +++ b/src/Cake.Tfs.Tests/PullRequest/Fakes/FakeAllSetGitClientFactory.cs @@ -239,6 +239,50 @@ protected override Mock Setup(Mock m) .ReturnsAsync((Guid repoId, int prId, int iterId, int? t, int? s, int? ct, object o, CancellationToken c) => changes); + // Setup pull request creation + m.Setup(arg => arg.GetRefsAsync(It.IsAny(), "MyRepoName", "NotExistingBranch", null, null, null, CancellationToken.None)) + .ReturnsAsync(() => new List()); + + m.Setup(args => args.GetRepositoryAsync(It.IsAny(), "MyRepoName", null, null, CancellationToken.None)) + .ReturnsAsync(() => new GitRepository() { DefaultBranch = "master" }); + + m.Setup(arg => arg.GetRefsAsync(It.IsAny(), "MyRepoName", "master", null, null, null, CancellationToken.None)) + .ReturnsAsync(() => new List() + { + new GitRef("master") + }); + + m.Setup( + arg => + arg.CreatePullRequestAsync( + It.IsAny(), + It.IsAny(), + It.IsAny(), + null, + null, + CancellationToken.None)) + .ReturnsAsync( + ( + GitPullRequest gitPullRequestToCreate, + string project, + string repositoryId, + bool? supportsIterations, + object userState, + CancellationToken cancellationToken) => + { + gitPullRequestToCreate.PullRequestId = 777; + gitPullRequestToCreate.Repository = new GitRepository + { + Id = Guid.NewGuid(), + Name = repositoryId + }; + gitPullRequestToCreate.CodeReviewId = 123; + gitPullRequestToCreate.LastMergeSourceCommit = new GitCommitRef { CommitId = "4a92b977" }; + gitPullRequestToCreate.LastMergeTargetCommit = new GitCommitRef { CommitId = "78a3c113" }; + + return gitPullRequestToCreate; + }); + return m; } } diff --git a/src/Cake.Tfs.Tests/PullRequest/PullRequestFixture.cs b/src/Cake.Tfs.Tests/PullRequest/PullRequestFixture.cs index 0dc94bbf..87b91722 100644 --- a/src/Cake.Tfs.Tests/PullRequest/PullRequestFixture.cs +++ b/src/Cake.Tfs.Tests/PullRequest/PullRequestFixture.cs @@ -1,41 +1,24 @@ namespace Cake.Tfs.Tests.PullRequest { using System; - using Cake.Testing; using Cake.Tfs.Authentication; using Cake.Tfs.PullRequest; - using Cake.Tfs.Tests.PullRequest.Fakes; internal class PullRequestFixture + : BasePullRequestFixture { - public const string ValidTfsUrl = "http://MyServer/tfs/MyCollection/MyTeamProject/_git/MyRepoName"; - public const string ValidAzureDevOpsUrl = "https://my-account.visualstudio.com/DefaultCollection/MyProject/_git/MyRepoName"; - public const string InvalidTfsUrl = "http://example.com"; - public PullRequestFixture(string repoUrl, int prId) + : base() { this.Settings = new TfsPullRequestSettings(new Uri(repoUrl), prId, new TfsNtlmCredentials()); - - this.InitializeFakes(); } - public PullRequestFixture(string repoUrl, string sourceBranch) + public PullRequestFixture(string repoUrl, string sourceRefName) + : base() { - this.Settings = new TfsPullRequestSettings(new Uri(repoUrl), sourceBranch, new TfsNtlmCredentials()); - - this.InitializeFakes(); + this.Settings = new TfsPullRequestSettings(new Uri(repoUrl), sourceRefName, new TfsNtlmCredentials()); } - public FakeLog Log { get; set; } - public TfsPullRequestSettings Settings { get; set; } - - public IGitClientFactory GitClientFactory { get; set; } - - private void InitializeFakes() - { - this.Log = new FakeLog(); - this.GitClientFactory = new FakeAllSetGitClientFactory(); - } } } diff --git a/src/Cake.Tfs.Tests/PullRequest/TfsCommentTests.cs b/src/Cake.Tfs.Tests/PullRequest/TfsCommentTests.cs deleted file mode 100644 index 16833497..00000000 --- a/src/Cake.Tfs.Tests/PullRequest/TfsCommentTests.cs +++ /dev/null @@ -1,92 +0,0 @@ -namespace Cake.Tfs.Tests.PullRequest -{ - using Cake.Tfs.PullRequest.CommentThread; - using Microsoft.TeamFoundation.SourceControl.WebApi; - using Shouldly; - using Xunit; - - public sealed class TfsCommentTests - { - [Fact] - public void Should_Throw_If_Comment_Is_Null() - { - // Given, When - var result = Record.Exception(() => new TfsComment(null)); - - // Then - result.IsArgumentNullException("comment"); - } - - [Fact] - public void Should_Throw_If_Comment_Content_Is_Null() - { - // Given, When - var result = Record.Exception(() => new TfsComment(null, false)); - - // Then - result.IsArgumentNullException("content"); - } - - [Fact] - public void Should_Throw_If_Comment_Content_Is_Empty() - { - // Given, When - var result = Record.Exception(() => new TfsComment(string.Empty, false)); - - // Then - result.IsArgumentOutOfRangeException("content"); - } - - [Fact] - public void Should_Return_Empty_Comment() - { - // Given, When - var comment = new TfsComment(); - - // Then - comment.ShouldNotBeNull(); - comment.Content.ShouldBe(default(string)); - comment.IsDeleted.ShouldBe(default(bool)); - comment.CommentType.ShouldBe(default(TfsCommentType)); - } - - [Fact] - public void Should_Return_Valid_Comment_With_Default_Comment_Type() - { - // Given, When - var comment = new TfsComment("Hello", false); - - // Then - comment.ShouldNotBeNull(); - comment.Content.ShouldBe("Hello"); - comment.IsDeleted.ShouldBeFalse(); - comment.CommentType.ShouldBe(default(TfsCommentType)); - } - - [Fact] - public void Should_Return_Valid_Comment_Via_Ctor() - { - // Given, When - var comment = new TfsComment("What's up?", true, CommentType.Text); - - // Then - comment.ShouldNotBeNull(); - comment.Content.ShouldBe("What's up?"); - comment.IsDeleted.ShouldBeTrue(); - comment.CommentType.ShouldBe(TfsCommentType.Text); - } - - [Fact] - public void Should_Return_Valid_Comment_Via_Initializers() - { - // Given, When - var comment = new TfsComment { Content = "All good", IsDeleted = false, CommentType = TfsCommentType.CodeChange }; - - // Then - comment.ShouldNotBeNull(); - comment.Content.ShouldBe("All good"); - comment.IsDeleted.ShouldBeFalse(); - comment.CommentType.ShouldBe(TfsCommentType.CodeChange); - } - } -} diff --git a/src/Cake.Tfs.Tests/PullRequest/TfsCreatePullRequestSettingsTests.cs b/src/Cake.Tfs.Tests/PullRequest/TfsCreatePullRequestSettingsTests.cs new file mode 100644 index 00000000..2759adfa --- /dev/null +++ b/src/Cake.Tfs.Tests/PullRequest/TfsCreatePullRequestSettingsTests.cs @@ -0,0 +1,311 @@ +namespace Cake.Tfs.Tests.PullRequest +{ + using System; + using Cake.Tfs.Authentication; + using Cake.Tfs.PullRequest; + using Shouldly; + using Xunit; + + public sealed class TfsCreatePullRequestSettingsTests + { + public sealed class TheCtor + { + [Fact] + public void Should_Throw_If_RepositoryUrl_Is_Null() + { + // Given + Uri repositoryUrl = null; + var sourceRefName = "foo"; + var targetRefName = "master"; + var title = "foo"; + var description = "bar"; + var credentials = AuthenticationProvider.AuthenticationNtlm(); + + // When + var result = + Record.Exception(() => + new TfsCreatePullRequestSettings(repositoryUrl, sourceRefName, targetRefName, title, description, credentials)); + + // Then + result.IsArgumentNullException("repositoryUrl"); + } + + [Fact] + public void Should_Throw_If_SourceRefName_Is_Null() + { + // Given + var repositoryUrl = new Uri("http://example.com"); + string sourceRefName = null; + var targetRefName = "master"; + var title = "foo"; + var description = "bar"; + var credentials = AuthenticationProvider.AuthenticationNtlm(); + + // When + var result = + Record.Exception(() => + new TfsCreatePullRequestSettings(repositoryUrl, sourceRefName, targetRefName, title, description, credentials)); + + // Then + result.IsArgumentNullException("sourceRefName"); + } + + [Fact] + public void Should_Throw_If_SourceRefName_Is_Empty() + { + // Given + var repositoryUrl = new Uri("http://example.com"); + var sourceRefName = string.Empty; + var targetRefName = "master"; + var title = "foo"; + var description = "bar"; + var credentials = AuthenticationProvider.AuthenticationNtlm(); + + // When + var result = + Record.Exception(() => + new TfsCreatePullRequestSettings(repositoryUrl, sourceRefName, targetRefName, title, description, credentials)); + + // Then + result.IsArgumentOutOfRangeException("sourceRefName"); + } + + [Fact] + public void Should_Throw_If_SourceRefName_Is_WhiteSpace() + { + // Given + var repositoryUrl = new Uri("http://example.com"); + var sourceRefName = " "; + var targetRefName = "master"; + var title = "foo"; + var description = "bar"; + var credentials = AuthenticationProvider.AuthenticationNtlm(); + + // When + var result = + Record.Exception(() => + new TfsCreatePullRequestSettings(repositoryUrl, sourceRefName, targetRefName, title, description, credentials)); + + // Then + result.IsArgumentOutOfRangeException("sourceRefName"); + } + + [Fact] + public void Should_Throw_If_Title_Is_Null() + { + // Given + var repositoryUrl = new Uri("http://example.com"); + var sourceRefName = "foo"; + var targetRefName = "master"; + string title = null; + var description = "bar"; + var credentials = AuthenticationProvider.AuthenticationNtlm(); + + // When + var result = + Record.Exception(() => + new TfsCreatePullRequestSettings(repositoryUrl, sourceRefName, targetRefName, title, description, credentials)); + + // Then + result.IsArgumentNullException("title"); + } + + [Fact] + public void Should_Throw_If_Title_Is_Empty() + { + // Given + var repositoryUrl = new Uri("http://example.com"); + var sourceRefName = "foo"; + var targetRefName = "master"; + var title = string.Empty; + var description = "bar"; + var credentials = AuthenticationProvider.AuthenticationNtlm(); + + // When + var result = + Record.Exception(() => + new TfsCreatePullRequestSettings(repositoryUrl, sourceRefName, targetRefName, title, description, credentials)); + + // Then + result.IsArgumentOutOfRangeException("title"); + } + + [Fact] + public void Should_Throw_If_Title_Is_WhiteSpace() + { + // Given + var repositoryUrl = new Uri("http://example.com"); + var sourceRefName = "foo"; + var targetRefName = "master"; + var title = " "; + var description = "bar"; + var credentials = AuthenticationProvider.AuthenticationNtlm(); + + // When + var result = + Record.Exception(() => + new TfsCreatePullRequestSettings(repositoryUrl, sourceRefName, targetRefName, title, description, credentials)); + + // Then + result.IsArgumentOutOfRangeException("title"); + } + + [Fact] + public void Should_Throw_If_Description_Is_Null() + { + // Given + var repositoryUrl = new Uri("http://example.com"); + var sourceRefName = "foo"; + var targetRefName = "master"; + var title = "foo"; + string description = null; + var credentials = AuthenticationProvider.AuthenticationNtlm(); + + // When + var result = + Record.Exception(() => + new TfsCreatePullRequestSettings(repositoryUrl, sourceRefName, targetRefName, title, description, credentials)); + + // Then + result.IsArgumentNullException("description"); + } + + [Fact] + public void Should_Throw_If_Credentials_Are_Null() + { + // Given + var repositoryUrl = new Uri("http://example.com"); + var sourceRefName = "foo"; + var targetRefName = "master"; + var title = "foo"; + var description = "bar"; + ITfsCredentials credentials = null; + + // When + var result = + Record.Exception(() => + new TfsCreatePullRequestSettings(repositoryUrl, sourceRefName, targetRefName, title, description, credentials)); + + // Then + result.IsArgumentNullException("credentials"); + } + + [Fact] + public void Should_Set_Repository_Url() + { + // Given + var repositoryUrl = new Uri("http://example.com"); + var sourceRefName = "foo"; + var targetRefName = "master"; + var title = "foo"; + var description = "bar"; + var credentials = AuthenticationProvider.AuthenticationNtlm(); + + // When + var result = + new TfsCreatePullRequestSettings(repositoryUrl, sourceRefName, targetRefName, title, description, credentials); + + // Then + result.RepositoryUrl.ShouldBe(repositoryUrl); + } + + [Fact] + public void Should_Set_SourceRefName() + { + // Given + var repositoryUrl = new Uri("http://example.com"); + var sourceRefName = "foo"; + var targetRefName = "master"; + var title = "foo"; + var description = "bar"; + var credentials = AuthenticationProvider.AuthenticationNtlm(); + + // When + var result = + new TfsCreatePullRequestSettings(repositoryUrl, sourceRefName, targetRefName, title, description, credentials); + + // Then + result.SourceRefName.ShouldBe(sourceRefName); + } + + [Theory] + [InlineData("master")] + [InlineData(null)] + public void Should_Set_TargetRefName(string targetRefName) + { + // Given + var repositoryUrl = new Uri("http://example.com"); + var sourceRefName = "foo"; + var title = "foo"; + var description = "bar"; + var credentials = AuthenticationProvider.AuthenticationNtlm(); + + // When + var result = + new TfsCreatePullRequestSettings(repositoryUrl, sourceRefName, targetRefName, title, description, credentials); + + // Then + result.TargetRefName.ShouldBe(targetRefName); + } + + [Fact] + public void Should_Set_Title() + { + // Given + var repositoryUrl = new Uri("http://example.com"); + var sourceRefName = "foo"; + var targetRefName = "master"; + var title = "foo"; + var description = "bar"; + var credentials = AuthenticationProvider.AuthenticationNtlm(); + + // When + var result = + new TfsCreatePullRequestSettings(repositoryUrl, sourceRefName, targetRefName, title, description, credentials); + + // Then + result.Title.ShouldBe(title); + } + + [Theory] + [InlineData("Foo")] + [InlineData("")] + [InlineData(" ")] + public void Should_Set_Description(string description) + { + // Given + var repositoryUrl = new Uri("http://example.com"); + var sourceRefName = "foo"; + var targetRefName = "master"; + var title = "foo"; + var credentials = AuthenticationProvider.AuthenticationNtlm(); + + // When + var result = + new TfsCreatePullRequestSettings(repositoryUrl, sourceRefName, targetRefName, title, description, credentials); + + // Then + result.Description.ShouldBe(description); + } + + [Fact] + public void Should_Set_Credentials() + { + // Given + var repositoryUrl = new Uri("http://example.com"); + var sourceRefName = "foo"; + var targetRefName = "master"; + var title = "foo"; + var description = "bar"; + var credentials = AuthenticationProvider.AuthenticationNtlm(); + + // When + var result = + new TfsCreatePullRequestSettings(repositoryUrl, sourceRefName, targetRefName, title, description, credentials); + + // Then + result.Credentials.ShouldBe(credentials); + } + } + } +} diff --git a/src/Cake.Tfs.Tests/PullRequest/TfsPullRequestSettingsTests.cs b/src/Cake.Tfs.Tests/PullRequest/TfsPullRequestSettingsTests.cs index e341f000..624b12b8 100644 --- a/src/Cake.Tfs.Tests/PullRequest/TfsPullRequestSettingsTests.cs +++ b/src/Cake.Tfs.Tests/PullRequest/TfsPullRequestSettingsTests.cs @@ -8,7 +8,7 @@ public sealed class TfsPullRequestSettingsTests { - public sealed class TheCtorForSourceBranch + public sealed class TheCtorForSourceRefName { [Fact] public void Should_Throw_If_RepositoryUrl_Is_Null() @@ -16,7 +16,7 @@ public void Should_Throw_If_RepositoryUrl_Is_Null() // Given Uri repositoryUrl = null; var sourceBranch = "foo"; - ITfsCredentials credentials = AuthenticationProvider.AuthenticationNtlm(); + var credentials = AuthenticationProvider.AuthenticationNtlm(); // When var result = Record.Exception(() => new TfsPullRequestSettings(repositoryUrl, sourceBranch, credentials)); @@ -26,48 +26,48 @@ public void Should_Throw_If_RepositoryUrl_Is_Null() } [Fact] - public void Should_Throw_If_SourceBranch_Is_Null() + public void Should_Throw_If_SourceRefName_Is_Null() { // Given var repositoryUrl = new Uri("http://example.com"); - string sourceBranch = null; - ITfsCredentials credentials = AuthenticationProvider.AuthenticationNtlm(); + string sourceRefName = null; + var credentials = AuthenticationProvider.AuthenticationNtlm(); // When - var result = Record.Exception(() => new TfsPullRequestSettings(repositoryUrl, sourceBranch, credentials)); + var result = Record.Exception(() => new TfsPullRequestSettings(repositoryUrl, sourceRefName, credentials)); // Then - result.IsArgumentNullException("sourceBranch"); + result.IsArgumentNullException("sourceRefName"); } [Fact] - public void Should_Throw_If_SourceBranch_Is_Empty() + public void Should_Throw_If_SourceRefName_Is_Empty() { // Given var repositoryUrl = new Uri("http://example.com"); - var sourceBranch = string.Empty; - ITfsCredentials credentials = AuthenticationProvider.AuthenticationNtlm(); + var sourceRefName = string.Empty; + var credentials = AuthenticationProvider.AuthenticationNtlm(); // When - var result = Record.Exception(() => new TfsPullRequestSettings(repositoryUrl, sourceBranch, credentials)); + var result = Record.Exception(() => new TfsPullRequestSettings(repositoryUrl, sourceRefName, credentials)); // Then - result.IsArgumentOutOfRangeException("sourceBranch"); + result.IsArgumentOutOfRangeException("sourceRefName"); } [Fact] - public void Should_Throw_If_SourceBranch_Is_WhiteSpace() + public void Should_Throw_If_SourceRefName_Is_WhiteSpace() { // Given var repositoryUrl = new Uri("http://example.com"); - var sourceBranch = " "; - ITfsCredentials credentials = AuthenticationProvider.AuthenticationNtlm(); + var sourceRefName = " "; + var credentials = AuthenticationProvider.AuthenticationNtlm(); // When - var result = Record.Exception(() => new TfsPullRequestSettings(repositoryUrl, sourceBranch, credentials)); + var result = Record.Exception(() => new TfsPullRequestSettings(repositoryUrl, sourceRefName, credentials)); // Then - result.IsArgumentOutOfRangeException("sourceBranch"); + result.IsArgumentOutOfRangeException("sourceRefName"); } [Fact] @@ -91,7 +91,7 @@ public void Should_Set_Repository_Url() // Given var repositoryUrl = new Uri("http://example.com"); var sourceBranch = "foo"; - ITfsCredentials credentials = AuthenticationProvider.AuthenticationNtlm(); + var credentials = AuthenticationProvider.AuthenticationNtlm(); // When var result = new TfsPullRequestSettings(repositoryUrl, sourceBranch, credentials); @@ -101,18 +101,18 @@ public void Should_Set_Repository_Url() } [Fact] - public void Should_Set_SourceBranch() + public void Should_Set_SourceRefName() { // Given var repositoryUrl = new Uri("http://example.com"); - var sourceBranch = "foo"; - ITfsCredentials credentials = AuthenticationProvider.AuthenticationNtlm(); + var sourceRefName = "foo"; + var credentials = AuthenticationProvider.AuthenticationNtlm(); // When - var result = new TfsPullRequestSettings(repositoryUrl, sourceBranch, credentials); + var result = new TfsPullRequestSettings(repositoryUrl, sourceRefName, credentials); // Then - result.SourceBranch.ShouldBe(sourceBranch); + result.SourceRefName.ShouldBe(sourceRefName); } [Fact] @@ -121,7 +121,7 @@ public void Should_Set_Credentials() // Given var repositoryUrl = new Uri("http://example.com"); var sourceBranch = "foo"; - ITfsCredentials credentials = AuthenticationProvider.AuthenticationNtlm(); + var credentials = AuthenticationProvider.AuthenticationNtlm(); // When var result = new TfsPullRequestSettings(repositoryUrl, sourceBranch, credentials); @@ -139,7 +139,7 @@ public void Should_Throw_If_RepositoryUrl_Is_Null() // Given Uri repositoryUrl = null; var pullRequestId = 41; - ITfsCredentials credentials = AuthenticationProvider.AuthenticationNtlm(); + var credentials = AuthenticationProvider.AuthenticationNtlm(); // When var result = Record.Exception(() => new TfsPullRequestSettings(repositoryUrl, pullRequestId, credentials)); @@ -154,7 +154,7 @@ public void Should_Throw_If_PullRequestId_Is_Zero() // Given var repositoryUrl = new Uri("http://example.com"); var pullRequestId = 0; - ITfsCredentials credentials = AuthenticationProvider.AuthenticationNtlm(); + var credentials = AuthenticationProvider.AuthenticationNtlm(); // When var result = Record.Exception(() => new TfsPullRequestSettings(repositoryUrl, pullRequestId, credentials)); @@ -170,7 +170,7 @@ public void Should_Throw_If_PullRequestId_Is_Negative(int pullRequestId) { // Given var repositoryUrl = new Uri("http://example.com"); - ITfsCredentials credentials = AuthenticationProvider.AuthenticationNtlm(); + var credentials = AuthenticationProvider.AuthenticationNtlm(); // When var result = Record.Exception(() => new TfsPullRequestSettings(repositoryUrl, pullRequestId, credentials)); @@ -200,7 +200,7 @@ public void Should_Set_Repository_Url() // Given var repositoryUrl = new Uri("http://example.com"); var pullRequestId = 41; - ITfsCredentials credentials = AuthenticationProvider.AuthenticationNtlm(); + var credentials = AuthenticationProvider.AuthenticationNtlm(); // When var result = new TfsPullRequestSettings(repositoryUrl, pullRequestId, credentials); @@ -216,7 +216,7 @@ public void Should_Set_PullRequestId(int pullRequestId) { // Given var repositoryUrl = new Uri("http://example.com"); - ITfsCredentials credentials = AuthenticationProvider.AuthenticationNtlm(); + var credentials = AuthenticationProvider.AuthenticationNtlm(); // When var result = new TfsPullRequestSettings(repositoryUrl, pullRequestId, credentials); @@ -231,7 +231,7 @@ public void Should_Set_Credentials() // Given var repositoryUrl = new Uri("http://example.com"); var pullRequestId = 41; - ITfsCredentials credentials = AuthenticationProvider.AuthenticationNtlm(); + var credentials = AuthenticationProvider.AuthenticationNtlm(); // When var result = new TfsPullRequestSettings(repositoryUrl, pullRequestId, credentials); @@ -262,7 +262,7 @@ public void Should_Set_Repository_Url() // Given var repositoryUrl = new Uri("http://example.com"); var pullRequestId = 41; - ITfsCredentials credentials = AuthenticationProvider.AuthenticationNtlm(); + var credentials = AuthenticationProvider.AuthenticationNtlm(); var settings = new TfsPullRequestSettings(repositoryUrl, pullRequestId, credentials); // When @@ -279,7 +279,7 @@ public void Should_Set_PullRequestId(int pullRequestId) { // Given var repositoryUrl = new Uri("http://example.com"); - ITfsCredentials credentials = AuthenticationProvider.AuthenticationNtlm(); + var credentials = AuthenticationProvider.AuthenticationNtlm(); var settings = new TfsPullRequestSettings(repositoryUrl, pullRequestId, credentials); // When @@ -295,14 +295,14 @@ public void Should_Set_SourceBranch() // Given var repositoryUrl = new Uri("http://example.com"); var sourceBranch = "foo"; - ITfsCredentials credentials = AuthenticationProvider.AuthenticationNtlm(); + var credentials = AuthenticationProvider.AuthenticationNtlm(); var settings = new TfsPullRequestSettings(repositoryUrl, sourceBranch, credentials); // When var result = new TfsPullRequestSettings(settings); // Then - result.SourceBranch.ShouldBe(sourceBranch); + result.SourceRefName.ShouldBe(sourceBranch); } [Fact] @@ -311,7 +311,7 @@ public void Should_Set_Credentials() // Given var repositoryUrl = new Uri("http://example.com"); var pullRequestId = 41; - ITfsCredentials credentials = AuthenticationProvider.AuthenticationNtlm(); + var credentials = AuthenticationProvider.AuthenticationNtlm(); var settings = new TfsPullRequestSettings(repositoryUrl, pullRequestId, credentials); // When @@ -329,9 +329,11 @@ public void Should_Set_ThrowExceptionIfPullRequestCouldNotBeFound(bool value) // Given var repositoryUrl = new Uri("http://example.com"); var pullRequestId = 41; - ITfsCredentials credentials = AuthenticationProvider.AuthenticationNtlm(); - var settings = new TfsPullRequestSettings(repositoryUrl, pullRequestId, credentials); - settings.ThrowExceptionIfPullRequestCouldNotBeFound = value; + var credentials = AuthenticationProvider.AuthenticationNtlm(); + var settings = new TfsPullRequestSettings(repositoryUrl, pullRequestId, credentials) + { + ThrowExceptionIfPullRequestCouldNotBeFound = value + }; // When var result = new TfsPullRequestSettings(settings); diff --git a/src/Cake.Tfs.Tests/PullRequest/TfsPullRequestTests.cs b/src/Cake.Tfs.Tests/PullRequest/TfsPullRequestTests.cs index 80292839..49274a02 100644 --- a/src/Cake.Tfs.Tests/PullRequest/TfsPullRequestTests.cs +++ b/src/Cake.Tfs.Tests/PullRequest/TfsPullRequestTests.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Linq; + using Cake.Core.Diagnostics; using Cake.Core.IO; using Cake.Tfs.PullRequest; using Cake.Tfs.PullRequest.CommentThread; @@ -19,49 +20,65 @@ public sealed class TheCtor public void Should_Throw_If_Log_Is_Null() { // Given - var fixture = new PullRequestFixture(PullRequestFixture.ValidTfsUrl, "foo") { Log = null }; + var fixture = new PullRequestFixture(BasePullRequestFixture.ValidTfsUrl, "foo") { Log = null }; // When - var result = Record.Exception(() => new TfsPullRequest(fixture.Log, fixture.Settings, fixture.GitClientFactory)); + var result = Record.Exception(() => new TfsPullRequest(fixture.Log, fixture.Settings)); // Then result.IsArgumentNullException("log"); } [Fact] - public void Should_Throw_If_Log_Is_Null_Overload() + public void Should_Throw_If_Settings_Are_Null() { // Given - var fixture = new PullRequestFixture(PullRequestFixture.ValidTfsUrl, "foo") { Log = null }; + var fixture = new PullRequestFixture(BasePullRequestFixture.ValidTfsUrl, 42) { Settings = null }; // When var result = Record.Exception(() => new TfsPullRequest(fixture.Log, fixture.Settings)); // Then - result.IsArgumentNullException("log"); + result.IsArgumentNullException("settings"); } [Fact] - public void Should_Throw_If_Settings_Are_Null() + public void Should_Throw_If_Tfs_Url_Is_Invalid() + { + // Given + var fixture = new PullRequestFixture(BasePullRequestFixture.InvalidTfsUrl, 42); + + // When + var result = Record.Exception(() => new TfsPullRequest(fixture.Log, fixture.Settings)); + + // Then + result.IsUrlFormatException(); + } + } + + public sealed class TheCtorWithGitClientFactory + { + [Fact] + public void Should_Throw_If_Log_Is_Null() { // Given - var fixture = new PullRequestFixture(PullRequestFixture.ValidTfsUrl, 42) { Settings = null }; + var fixture = new PullRequestFixture(BasePullRequestFixture.ValidTfsUrl, "foo") { Log = null }; // When var result = Record.Exception(() => new TfsPullRequest(fixture.Log, fixture.Settings, fixture.GitClientFactory)); // Then - result.IsArgumentNullException("settings"); + result.IsArgumentNullException("log"); } [Fact] - public void Should_Throw_If_Settings_Are_Null_Overload() + public void Should_Throw_If_Settings_Are_Null() { // Given - var fixture = new PullRequestFixture(PullRequestFixture.ValidTfsUrl, 42) { Settings = null }; + var fixture = new PullRequestFixture(BasePullRequestFixture.ValidTfsUrl, 42) { Settings = null }; // When - var result = Record.Exception(() => new TfsPullRequest(fixture.Log, fixture.Settings)); + var result = Record.Exception(() => new TfsPullRequest(fixture.Log, fixture.Settings, fixture.GitClientFactory)); // Then result.IsArgumentNullException("settings"); @@ -71,7 +88,7 @@ public void Should_Throw_If_Settings_Are_Null_Overload() public void Should_Throw_If_Git_Client_Factory_Is_Null() { // Given - var fixture = new PullRequestFixture(PullRequestFixture.ValidTfsUrl, 42) { GitClientFactory = null }; + var fixture = new PullRequestFixture(BasePullRequestFixture.ValidTfsUrl, 42) { GitClientFactory = null }; // When var result = Record.Exception(() => new TfsPullRequest(fixture.Log, fixture.Settings, fixture.GitClientFactory)); @@ -84,7 +101,7 @@ public void Should_Throw_If_Git_Client_Factory_Is_Null() public void Should_Throw_If_Tfs_Url_Is_Invalid() { // Given - var fixture = new PullRequestFixture(PullRequestFixture.InvalidTfsUrl, 42); + var fixture = new PullRequestFixture(BasePullRequestFixture.InvalidTfsUrl, 42); // When var result = Record.Exception(() => new TfsPullRequest(fixture.Log, fixture.Settings, fixture.GitClientFactory)); @@ -97,7 +114,7 @@ public void Should_Throw_If_Tfs_Url_Is_Invalid() public void Should_Return_Valid_Tfs_Pull_Request_By_Id() { // Given - var fixture = new PullRequestFixture(PullRequestFixture.ValidTfsUrl, 42); + var fixture = new PullRequestFixture(BasePullRequestFixture.ValidTfsUrl, 42); // When var pullRequest = new TfsPullRequest(fixture.Log, fixture.Settings, fixture.GitClientFactory); @@ -120,7 +137,7 @@ public void Should_Return_Valid_Tfs_Pull_Request_By_Id() public void Should_Return_Valid_Azure_DevOps_Pull_Request_By_Id() { // Given - var fixture = new PullRequestFixture(PullRequestFixture.ValidAzureDevOpsUrl, 16); + var fixture = new PullRequestFixture(BasePullRequestFixture.ValidAzureDevOpsUrl, 16); // When var pullRequest = new TfsPullRequest(fixture.Log, fixture.Settings, fixture.GitClientFactory); @@ -143,7 +160,7 @@ public void Should_Return_Valid_Azure_DevOps_Pull_Request_By_Id() public void Should_Return_Valid_Tfs_Pull_Request_By_Source_Branch() { // Given - var fixture = new PullRequestFixture(PullRequestFixture.ValidTfsUrl, "feature"); + var fixture = new PullRequestFixture(BasePullRequestFixture.ValidTfsUrl, "feature"); // When var pullRequest = new TfsPullRequest(fixture.Log, fixture.Settings, fixture.GitClientFactory); @@ -166,7 +183,7 @@ public void Should_Return_Valid_Tfs_Pull_Request_By_Source_Branch() public void Should_Return_Valid_Azure_DevOps_Pull_Request_By_Source_Branch() { // Given - var fixture = new PullRequestFixture(PullRequestFixture.ValidAzureDevOpsUrl, "feature"); + var fixture = new PullRequestFixture(BasePullRequestFixture.ValidAzureDevOpsUrl, "feature"); // When var pullRequest = new TfsPullRequest(fixture.Log, fixture.Settings, fixture.GitClientFactory); @@ -190,7 +207,7 @@ public void Should_Return_Null_Tfs_Pull_Request_By_Id() { // Given var fixture = - new PullRequestFixture(PullRequestFixture.ValidTfsUrl, 101) + new PullRequestFixture(BasePullRequestFixture.ValidTfsUrl, 101) { GitClientFactory = new FakeNullGitClientFactory(), Settings = { ThrowExceptionIfPullRequestCouldNotBeFound = false } @@ -218,7 +235,7 @@ public void Should_Return_Null_Azure_DevOps_Pull_Request_By_Id() { // Given var fixture = - new PullRequestFixture(PullRequestFixture.ValidAzureDevOpsUrl, 101) + new PullRequestFixture(BasePullRequestFixture.ValidAzureDevOpsUrl, 101) { GitClientFactory = new FakeNullGitClientFactory(), Settings = { ThrowExceptionIfPullRequestCouldNotBeFound = false } @@ -246,7 +263,7 @@ public void Should_Return_Null_Tfs_Pull_Request_By_Branch() { // Given var fixture = - new PullRequestFixture(PullRequestFixture.ValidTfsUrl, "somebranch") + new PullRequestFixture(BasePullRequestFixture.ValidTfsUrl, "somebranch") { GitClientFactory = new FakeNullGitClientFactory(), Settings = { ThrowExceptionIfPullRequestCouldNotBeFound = false } @@ -274,7 +291,7 @@ public void Should_Return_Null_Azure_DevOps_Pull_Request_By_Branch() { // Given var fixture = - new PullRequestFixture(PullRequestFixture.ValidAzureDevOpsUrl, "somebranch") + new PullRequestFixture(BasePullRequestFixture.ValidAzureDevOpsUrl, "somebranch") { GitClientFactory = new FakeNullGitClientFactory(), Settings = { ThrowExceptionIfPullRequestCouldNotBeFound = false } @@ -302,7 +319,7 @@ public void Should_Throw_If_Strict_Is_On_And_Pull_Request_Is_Null_By_Id() { // Given var fixture = - new PullRequestFixture(PullRequestFixture.ValidTfsUrl, 1) + new PullRequestFixture(BasePullRequestFixture.ValidTfsUrl, 1) { GitClientFactory = new FakeNullGitClientFactory() }; @@ -319,7 +336,7 @@ public void Should_Throw_If_Strict_Is_On_And_Pull_Request_Is_Null_By_Branch() { // Given var fixture = - new PullRequestFixture(PullRequestFixture.ValidTfsUrl, "feature") + new PullRequestFixture(BasePullRequestFixture.ValidTfsUrl, "feature") { GitClientFactory = new FakeNullGitClientFactory() }; @@ -332,13 +349,147 @@ public void Should_Throw_If_Strict_Is_On_And_Pull_Request_Is_Null_By_Branch() } } - public sealed class Vote + public sealed class TheCreateMethod + { + [Fact] + public void Should_Throw_If_Log_Is_Null() + { + // Given + var fixture = + new CreatePullRequestFixture( + BasePullRequestFixture.ValidTfsUrl, + "testBranch", + "NotExistingBranch", + "test", + "test"); + ICakeLog log = null; + + // When + var result = + Record.Exception(() => TfsPullRequest.Create(log, fixture.GitClientFactory, fixture.Settings)); + + // Then + result.IsArgumentNullException("log"); + } + + [Fact] + public void Should_Throw_If_GitClientFactory_Is_Null() + { + // Given + var fixture = + new CreatePullRequestFixture( + BasePullRequestFixture.ValidTfsUrl, + "testBranch", + "NotExistingBranch", + "test", + "test"); + IGitClientFactory gitClientFactory = null; + + // When + var result = + Record.Exception(() => TfsPullRequest.Create(fixture.Log, gitClientFactory, fixture.Settings)); + + // Then + result.IsArgumentNullException("gitClientFactory"); + } + + [Fact] + public void Should_Throw_If_Settings_Are_Null() + { + // Given + var fixture = + new CreatePullRequestFixture( + BasePullRequestFixture.ValidTfsUrl, + "testBranch", + "NotExistingBranch", + "test", + "test"); + TfsCreatePullRequestSettings settings = null; + + // When + var result = + Record.Exception(() => TfsPullRequest.Create(fixture.Log, fixture.GitClientFactory, settings)); + + // Then + result.IsArgumentNullException("settings"); + } + + [Fact] + public void Should_Throw_If_Target_Branch_Not_Found() + { + // Given + var fixture = + new CreatePullRequestFixture( + BasePullRequestFixture.ValidTfsUrl, + "testBranch", + "NotExistingBranch", + "test", + "test"); + + // When + var result = + Record.Exception(() => TfsPullRequest.Create(fixture.Log, fixture.GitClientFactory, fixture.Settings)); + + // Then + result.IsTfsBranchNotFoundException($"Branch not found \"NotExistingBranch\""); + } + + [Fact] + public void Should_Return_A_PullRequest() + { + // Given + var sourceRefName = "testBranch"; + var targetRefName = "master"; + var title = "foo"; + var description = "bar"; + var fixture = + new CreatePullRequestFixture( + BasePullRequestFixture.ValidTfsUrl, + sourceRefName, + targetRefName, + title, + description); + + // When + var result = + TfsPullRequest.Create(fixture.Log, fixture.GitClientFactory, fixture.Settings); + + // Then + // Return is a mocked pull request unrelated to the input values + } + + [Fact] + public void Should_Return_A_PullRequest_With_Fallback_To_Default_Target_Branch() + { + // Given + var sourceRefName = "testBranch"; + string targetRefName = null; + var title = "foo"; + var description = "bar"; + var fixture = + new CreatePullRequestFixture( + BasePullRequestFixture.ValidTfsUrl, + sourceRefName, + targetRefName, + title, + description); + + // When + var result = + TfsPullRequest.Create(fixture.Log, fixture.GitClientFactory, fixture.Settings); + + // Then + // Return is a mocked pull request unrelated to the input values + } + } + + public sealed class TheVoteMethod { [Fact] public void Should_Set_Approved_Vote_On_Tfs_Pull_Request() { // Given - var fixture = new PullRequestFixture(PullRequestFixture.ValidTfsUrl, 23); + var fixture = new PullRequestFixture(BasePullRequestFixture.ValidTfsUrl, 23); var pullRequest = new TfsPullRequest(fixture.Log, fixture.Settings, fixture.GitClientFactory); // When @@ -352,7 +503,7 @@ public void Should_Set_Approved_Vote_On_Tfs_Pull_Request() public void Should_Throw_If_Vote_Value_Is_Invalid_On_Tfs_Pull_Request() { // Given - var fixture = new PullRequestFixture(PullRequestFixture.ValidTfsUrl, 23); + var fixture = new PullRequestFixture(BasePullRequestFixture.ValidTfsUrl, 23); var pullRequest = new TfsPullRequest(fixture.Log, fixture.Settings, fixture.GitClientFactory); // When @@ -368,7 +519,7 @@ public void Should_Throw_If_Vote_Value_Is_Invalid_On_Tfs_Pull_Request() public void Should_Throw_If_Null_Is_Returned_On_Tfs_Pull_Request() { // Given - var fixture = new PullRequestFixture(PullRequestFixture.ValidTfsUrl, 23) + var fixture = new PullRequestFixture(BasePullRequestFixture.ValidTfsUrl, 23) { GitClientFactory = new FakeNullForMethodsGitClientFactory() }; @@ -384,13 +535,13 @@ public void Should_Throw_If_Null_Is_Returned_On_Tfs_Pull_Request() } } - public sealed class SetStatus + public sealed class TheSetStatusMethod { [Fact] public void Should_Throw_If_Tfs_Pull_Request_Status_Is_Null() { // Given - var fixture = new PullRequestFixture(PullRequestFixture.ValidTfsUrl, 16); + var fixture = new PullRequestFixture(BasePullRequestFixture.ValidTfsUrl, 16); var pullRequest = new TfsPullRequest(fixture.Log, fixture.Settings, fixture.GitClientFactory); // When @@ -404,7 +555,7 @@ public void Should_Throw_If_Tfs_Pull_Request_Status_Is_Null() public void Should_Throw_If_Tfs_Pull_Request_State_Is_Invalid() { // Given - var fixture = new PullRequestFixture(PullRequestFixture.ValidTfsUrl, 16); + var fixture = new PullRequestFixture(BasePullRequestFixture.ValidTfsUrl, 16); var pullRequest = new TfsPullRequest(fixture.Log, fixture.Settings, fixture.GitClientFactory); var status = new TfsPullRequestStatus("whatever") { State = (TfsPullRequestStatusState)123 }; @@ -421,7 +572,7 @@ public void Should_Throw_If_Tfs_Pull_Request_State_Is_Invalid() public void Should_Set_Valid_Status_On_Tfs_Pull_Request() { // Given - var fixture = new PullRequestFixture(PullRequestFixture.ValidTfsUrl, 16); + var fixture = new PullRequestFixture(BasePullRequestFixture.ValidTfsUrl, 16); var pullRequest = new TfsPullRequest(fixture.Log, fixture.Settings, fixture.GitClientFactory); var status = new TfsPullRequestStatus("Hello") { State = TfsPullRequestStatusState.Succeeded }; @@ -436,7 +587,7 @@ public void Should_Set_Valid_Status_On_Tfs_Pull_Request() public void Should_Throw_If_Null_Is_Returned_On_Tfs_Pull_Request() { // Given - var fixture = new PullRequestFixture(PullRequestFixture.ValidTfsUrl, 16) + var fixture = new PullRequestFixture(BasePullRequestFixture.ValidTfsUrl, 16) { GitClientFactory = new FakeNullForMethodsGitClientFactory() }; @@ -453,13 +604,13 @@ public void Should_Throw_If_Null_Is_Returned_On_Tfs_Pull_Request() } } - public sealed class GetModifiedFiles + public sealed class TheGetModifiedFilesMethod { [Fact] public void Should_Return_Empty_Collection_If_No_Changes_Found() { // Given - var fixture = new PullRequestFixture(PullRequestFixture.ValidTfsUrl, 42) { GitClientFactory = new FakeNullForMethodsGitClientFactory() }; + var fixture = new PullRequestFixture(BasePullRequestFixture.ValidTfsUrl, 42) { GitClientFactory = new FakeNullForMethodsGitClientFactory() }; var pullRequest = new TfsPullRequest(fixture.Log, fixture.Settings, fixture.GitClientFactory); // When @@ -475,7 +626,7 @@ public void Should_Return_Empty_Collection_If_No_Changes_Found() public void Should_Return_Valid_Collection_Of_Modified_Files() { // Given - var fixture = new PullRequestFixture(PullRequestFixture.ValidTfsUrl, 42); + var fixture = new PullRequestFixture(BasePullRequestFixture.ValidTfsUrl, 42); var pullRequest = new TfsPullRequest(fixture.Log, fixture.Settings, fixture.GitClientFactory); // When @@ -494,13 +645,13 @@ public void Should_Return_Valid_Collection_Of_Modified_Files() } } - public sealed class SetCommentThreadStatus + public sealed class TheSetCommentThreadStatusMethod { [Fact] public void Should_Activate_Comment_Thread() { // Given - var fixture = new PullRequestFixture(PullRequestFixture.ValidTfsUrl, 12); + var fixture = new PullRequestFixture(BasePullRequestFixture.ValidTfsUrl, 12); var pullRequest = new TfsPullRequest(fixture.Log, fixture.Settings, fixture.GitClientFactory); // When @@ -514,7 +665,7 @@ public void Should_Activate_Comment_Thread() public void Should_Resolve_Comment_Thread() { // Given - var fixture = new PullRequestFixture(PullRequestFixture.ValidAzureDevOpsUrl, 21); + var fixture = new PullRequestFixture(BasePullRequestFixture.ValidAzureDevOpsUrl, 21); var pullRequest = new TfsPullRequest(fixture.Log, fixture.Settings, fixture.GitClientFactory); // When @@ -528,7 +679,7 @@ public void Should_Resolve_Comment_Thread() public void Should_Not_Throw_If_Null_Is_Returned() { // Given - var fixture = new PullRequestFixture(PullRequestFixture.ValidTfsUrl, 11) + var fixture = new PullRequestFixture(BasePullRequestFixture.ValidTfsUrl, 11) { GitClientFactory = new FakeNullForMethodsGitClientFactory() }; @@ -543,13 +694,13 @@ public void Should_Not_Throw_If_Null_Is_Returned() } } - public sealed class GetCommentThreads + public sealed class TheGetCommentThreadsMethod { [Fact] public void Should_Not_Fail_If_Empty_List_Is_Returned() { // Given - var fixture = new PullRequestFixture(PullRequestFixture.ValidTfsUrl, 33) + var fixture = new PullRequestFixture(BasePullRequestFixture.ValidTfsUrl, 33) { GitClientFactory = new FakeNullForMethodsGitClientFactory() }; @@ -567,7 +718,7 @@ public void Should_Not_Fail_If_Empty_List_Is_Returned() public void Should_Return_Valid_Comment_Threads() { // Given - var fixture = new PullRequestFixture(PullRequestFixture.ValidAzureDevOpsUrl, 44); + var fixture = new PullRequestFixture(BasePullRequestFixture.ValidAzureDevOpsUrl, 44); var pullRequest = new TfsPullRequest(fixture.Log, fixture.Settings, fixture.GitClientFactory); // When @@ -609,13 +760,13 @@ public void Should_Return_Valid_Comment_Threads() } } - public sealed class CreateCommentThread + public sealed class TheCreateCommentThreadMethod { [Fact] public void Should_Throw_If_Input_Thread_Is_Null() { // Given - var fixture = new PullRequestFixture(PullRequestFixture.ValidTfsUrl, 100); + var fixture = new PullRequestFixture(BasePullRequestFixture.ValidTfsUrl, 100); var pullRequest = new TfsPullRequest(fixture.Log, fixture.Settings, fixture.GitClientFactory); // When @@ -629,7 +780,7 @@ public void Should_Throw_If_Input_Thread_Is_Null() public void Should_Not_Throw_If_Null_Is_Returned() { // Given - var fixture = new PullRequestFixture(PullRequestFixture.ValidTfsUrl, 100) + var fixture = new PullRequestFixture(BasePullRequestFixture.ValidTfsUrl, 100) { GitClientFactory = new FakeNullForMethodsGitClientFactory() }; @@ -646,7 +797,7 @@ public void Should_Not_Throw_If_Null_Is_Returned() public void Should_Create_Valid_Comment_Thread() { // Given - var fixture = new PullRequestFixture(PullRequestFixture.ValidAzureDevOpsUrl, 200); + var fixture = new PullRequestFixture(BasePullRequestFixture.ValidAzureDevOpsUrl, 200); var pullRequest = new TfsPullRequest(fixture.Log, fixture.Settings, fixture.GitClientFactory); // When @@ -657,13 +808,13 @@ public void Should_Create_Valid_Comment_Thread() } } - public sealed class GetLatestIterationId + public sealed class TheGetLatestIterationIdMethod { [Fact] public void Should_Throw_If_Null_Is_Returned() { // Given - var fixture = new PullRequestFixture(PullRequestFixture.ValidTfsUrl, 11) + var fixture = new PullRequestFixture(BasePullRequestFixture.ValidTfsUrl, 11) { GitClientFactory = new FakeNullForMethodsGitClientFactory() }; @@ -680,7 +831,7 @@ public void Should_Throw_If_Null_Is_Returned() public void Should_Return_Valid_Iteration_Id() { // Given - var fixture = new PullRequestFixture(PullRequestFixture.ValidAzureDevOpsUrl, 12); + var fixture = new PullRequestFixture(BasePullRequestFixture.ValidAzureDevOpsUrl, 12); var pullRequest = new TfsPullRequest(fixture.Log, fixture.Settings, fixture.GitClientFactory); // When @@ -694,7 +845,7 @@ public void Should_Return_Valid_Iteration_Id() public void Should_Return_Invalid_Id_If_Something_Is_Wrong_With_Iteration() { // Given - var fixture = new PullRequestFixture(PullRequestFixture.ValidTfsUrl, 13); + var fixture = new PullRequestFixture(BasePullRequestFixture.ValidTfsUrl, 13); var pullRequest = new TfsPullRequest(fixture.Log, fixture.Settings, fixture.GitClientFactory); // When @@ -705,13 +856,13 @@ public void Should_Return_Invalid_Id_If_Something_Is_Wrong_With_Iteration() } } - public sealed class GetIterationChanges + public sealed class TheGetIterationChangesMethod { [Fact] public void Should_Not_Throw_If_Null_Is_Returned() { // Given - var fixture = new PullRequestFixture(PullRequestFixture.ValidAzureDevOpsUrl, 21) + var fixture = new PullRequestFixture(BasePullRequestFixture.ValidAzureDevOpsUrl, 21) { GitClientFactory = new FakeNullForMethodsGitClientFactory() }; @@ -728,7 +879,7 @@ public void Should_Not_Throw_If_Null_Is_Returned() public void Should_Return_Collection_Of_Valid_Iteration_Changes() { // Given - var fixture = new PullRequestFixture(PullRequestFixture.ValidTfsUrl, 22); + var fixture = new PullRequestFixture(BasePullRequestFixture.ValidTfsUrl, 22); var pullRequest = new TfsPullRequest(fixture.Log, fixture.Settings, fixture.GitClientFactory); // When diff --git a/src/Cake.Tfs/Cake.Tfs.csproj b/src/Cake.Tfs/Cake.Tfs.csproj index b37d641d..51311a7d 100644 --- a/src/Cake.Tfs/Cake.Tfs.csproj +++ b/src/Cake.Tfs/Cake.Tfs.csproj @@ -23,8 +23,8 @@ - - + + diff --git a/src/Cake.Tfs/PullRequest/BaseTfsPullRequestSettings.cs b/src/Cake.Tfs/PullRequest/BaseTfsPullRequestSettings.cs new file mode 100644 index 00000000..0cc99fbf --- /dev/null +++ b/src/Cake.Tfs/PullRequest/BaseTfsPullRequestSettings.cs @@ -0,0 +1,111 @@ +namespace Cake.Tfs.PullRequest +{ + using System; + using Cake.Tfs.Authentication; + + /// + /// Base class for settings for aliases handling pull requests. + /// + public abstract class BaseTfsPullRequestSettings + { + /// + /// Initializes a new instance of the class. + /// + /// Full URL of the Git repository, + /// eg. http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository. + /// Supported URL schemes are HTTP, HTTPS and SSH. + /// URLs using SSH scheme are converted to HTTPS. + /// Credentials to use to authenticate against Team Foundation Server or + /// Azure DevOps. + protected BaseTfsPullRequestSettings(Uri repositoryUrl, ITfsCredentials credentials) + { + repositoryUrl.NotNull(nameof(repositoryUrl)); + credentials.NotNull(nameof(credentials)); + + this.RepositoryUrl = repositoryUrl; + this.Credentials = credentials; + } + + /// + /// Initializes a new instance of the class. + /// + /// Full URL of the Git repository, + /// eg. http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository. + /// Supported URL schemes are HTTP, HTTPS and SSH. + /// URLs using SSH scheme are converted to HTTPS. + /// Branch for which the pull request is made. + /// if or . + /// Credentials to use to authenticate against Team Foundation Server or + /// Azure DevOps. + /// if . + protected BaseTfsPullRequestSettings(Uri repositoryUrl, string sourceRefName, ITfsCredentials credentials) + { + repositoryUrl.NotNull(nameof(repositoryUrl)); + sourceRefName.NotNullOrWhiteSpace(nameof(sourceRefName)); + credentials.NotNull(nameof(credentials)); + + this.RepositoryUrl = repositoryUrl; + this.SourceRefName = sourceRefName; + this.Credentials = credentials; + } + + /// + /// Initializes a new instance of the class + /// based on the instance of a class. + /// + /// Settings containing the parameters. + /// if . + protected BaseTfsPullRequestSettings(BaseTfsPullRequestSettings settings) + { + settings.NotNull(nameof(settings)); + + this.RepositoryUrl = settings.RepositoryUrl; + this.SourceRefName = settings.SourceRefName; + this.Credentials = settings.Credentials; + } + + /// + /// Initializes a new instance of the class using environment variables + /// as set by a Azure Pipelines or Team Foundation Server build. + /// + /// Credentials to use to authenticate against Team Foundation Server or + /// Azure DevOps. + protected BaseTfsPullRequestSettings(ITfsCredentials credentials) + { + credentials.NotNull(nameof(credentials)); + + this.Credentials = credentials; + + var repositoryUrl = Environment.GetEnvironmentVariable("BUILD_REPOSITORY_URI", EnvironmentVariableTarget.Process); + if (string.IsNullOrWhiteSpace(repositoryUrl)) + { + throw new InvalidOperationException( + "Failed to read the BUILD_REPOSITORY_URI environment variable. Make sure you are running in an Azure Pipelines or Team Foundation Server build."); + } + + this.RepositoryUrl = new Uri(repositoryUrl); + } + + /// + /// Gets the full URL of the Git repository, eg. http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository. + /// + public Uri RepositoryUrl { get; private set; } + + /// + /// Gets the branch for which the pull request is made. + /// + [Obsolete("Use SourceRefName instead.")] + public string SourceBranch => this.SourceRefName; + + /// + /// Gets the branch for which the pull request is made. + /// + public string SourceRefName { get; private set; } + + /// + /// Gets the credentials used to authenticate against Team Foundation Server or + /// Azure DevOps. + /// + public ITfsCredentials Credentials { get; private set; } + } +} diff --git a/src/Cake.Tfs/PullRequest/TfsBranchNotFoundException.cs b/src/Cake.Tfs/PullRequest/TfsBranchNotFoundException.cs new file mode 100644 index 00000000..1112d766 --- /dev/null +++ b/src/Cake.Tfs/PullRequest/TfsBranchNotFoundException.cs @@ -0,0 +1,52 @@ +namespace Cake.Tfs.PullRequest +{ + using System; + using System.Runtime.Serialization; + + /// + /// Represents an error if a branch was not found. + /// + [Serializable] + public class TfsBranchNotFoundException : TfsException + { + /// + /// Initializes a new instance of the class. + /// + public TfsBranchNotFoundException() + { + } + + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// The message that describes the error. + public TfsBranchNotFoundException(string message) + : base($"Branch not found \"{message}\"") + { + } + + /// + /// Initializes a new instance of the class with a specified error message + /// and a reference to the inner exception that is the cause of this exception. + /// + /// The error message that explains the reason for the exception. + /// The exception that is the cause of the current exception, or a null + /// reference if no inner exception is specified. + public TfsBranchNotFoundException(string message, Exception innerException) + : base($"Branch not found \"{message}\"", innerException) + { + } + + /// + /// Initializes a new instance of the class with serialized data. + /// + /// The that holds the serialized object data about + /// the exception being thrown. + /// The that contains contextual information about + /// the source or destination. + protected TfsBranchNotFoundException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } +} diff --git a/src/Cake.Tfs/PullRequest/TfsCreatePullRequestSettings.cs b/src/Cake.Tfs/PullRequest/TfsCreatePullRequestSettings.cs new file mode 100644 index 00000000..450c7314 --- /dev/null +++ b/src/Cake.Tfs/PullRequest/TfsCreatePullRequestSettings.cs @@ -0,0 +1,58 @@ +namespace Cake.Tfs.PullRequest +{ + using System; + using Cake.Tfs.Authentication; + + /// + /// Settings for aliases creating pull requests. + /// + public class TfsCreatePullRequestSettings : BaseTfsPullRequestSettings + { + /// + /// Initializes a new instance of the class. + /// + /// Full URL of the Git repository, + /// eg. http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository. + /// Supported URL schemes are HTTP, HTTPS and SSH. + /// URLs using SSH scheme are converted to HTTPS. + /// Branch for which the pull request is made. + /// Target branch of the pull request. + /// If or the default branch of the repository will be used. + /// Title of the pull request. + /// Description of the pull request. + /// Credentials to use to authenticate against Team Foundation Server or + /// Azure DevOps. + public TfsCreatePullRequestSettings( + Uri repositoryUrl, + string sourceRefName, + string targetRefName, + string title, + string description, + ITfsCredentials credentials) + : base(repositoryUrl, sourceRefName, credentials) + { + title.NotNullOrWhiteSpace(nameof(title)); + description.NotNull(nameof(description)); + + this.TargetRefName = targetRefName; + this.Title = title; + this.Description = description; + } + + /// + /// Gets the target branch of the pull request. + /// If or the default branch of the repository will be used. + /// + public string TargetRefName { get; private set; } + + /// + /// Gets the title of the pull request. + /// + public string Title { get; private set; } + + /// + /// Gets the description of the pull request. + /// + public string Description { get; private set; } + } +} diff --git a/src/Cake.Tfs/PullRequest/TfsPullRequest.cs b/src/Cake.Tfs/PullRequest/TfsPullRequest.cs index f8419bd0..c81c400d 100644 --- a/src/Cake.Tfs/PullRequest/TfsPullRequest.cs +++ b/src/Cake.Tfs/PullRequest/TfsPullRequest.cs @@ -7,6 +7,7 @@ using Cake.Core.Diagnostics; using Cake.Core.IO; using Cake.Tfs; + using Cake.Tfs.Authentication; using Cake.Tfs.PullRequest.CommentThread; using Microsoft.TeamFoundation.Common; using Microsoft.TeamFoundation.SourceControl.WebApi; @@ -18,7 +19,8 @@ public sealed class TfsPullRequest { private readonly ICakeLog log; - private readonly TfsPullRequestSettings settings; + private readonly ITfsCredentials credentials; + private readonly bool throwExceptionIfPullRequestCouldNotBeFound; private readonly IGitClientFactory gitClientFactory; private readonly RepositoryDescription repositoryDescription; private readonly GitPullRequest pullRequest; @@ -50,8 +52,9 @@ public TfsPullRequest(ICakeLog log, TfsPullRequestSettings settings, IGitClientF gitClientFactory.NotNull(nameof(gitClientFactory)); this.log = log; - this.settings = settings; this.gitClientFactory = gitClientFactory; + this.credentials = settings.Credentials; + this.throwExceptionIfPullRequestCouldNotBeFound = settings.ThrowExceptionIfPullRequestCouldNotBeFound; this.repositoryDescription = new RepositoryDescription(settings.RepositoryUrl); @@ -78,15 +81,15 @@ public TfsPullRequest(ICakeLog log, TfsPullRequestSettings settings, IGitClientF this.repositoryDescription.RepositoryName, settings.PullRequestId.Value).Result; } - else if (!string.IsNullOrWhiteSpace(settings.SourceBranch)) + else if (!string.IsNullOrWhiteSpace(settings.SourceRefName)) { - this.log.Verbose("Read pull request for branch {0}", settings.SourceBranch); + this.log.Verbose("Read pull request for branch {0}", settings.SourceRefName); var pullRequestSearchCriteria = new GitPullRequestSearchCriteria() { Status = PullRequestStatus.Active, - SourceRefName = settings.SourceBranch + SourceRefName = settings.SourceRefName }; this.pullRequest = @@ -100,13 +103,13 @@ public TfsPullRequest(ICakeLog log, TfsPullRequestSettings settings, IGitClientF { throw new ArgumentOutOfRangeException( nameof(settings), - "Either PullRequestId or SourceBranch needs to be set"); + "Either PullRequestId or SourceRefName needs to be set"); } } if (this.pullRequest == null) { - if (this.settings.ThrowExceptionIfPullRequestCouldNotBeFound) + if (this.throwExceptionIfPullRequestCouldNotBeFound) { throw new TfsPullRequestNotFoundException("Pull request not found"); } @@ -215,7 +218,7 @@ public int CodeReviewId } /// - /// Gets the name of the source branch + /// Gets the name of the source branch from the pull request /// /// Returns if no pull request could be found and /// is set to false. @@ -294,6 +297,73 @@ public string LastTargetCommitId } } + /// + /// Create a pull request. + /// + /// The Cake log context. + /// Git client factory. + /// Settings for accessing TFS. + /// Instance of the created pull request. + public static TfsPullRequest Create(ICakeLog log, IGitClientFactory gitClientFactory, TfsCreatePullRequestSettings settings) + { + log.NotNull(nameof(log)); + gitClientFactory.NotNull(nameof(gitClientFactory)); + settings.NotNull(nameof(settings)); + + var repositoryDescription = new RepositoryDescription(settings.RepositoryUrl); + + using (var gitClient = gitClientFactory.CreateGitClient(repositoryDescription.CollectionUrl, settings.Credentials)) + { + var repository = + gitClient + .GetRepositoryAsync(repositoryDescription.ProjectName, repositoryDescription.RepositoryName) + .GetAwaiter().GetResult(); + + var targetBranchName = settings.TargetRefName; + if (targetBranchName == null) + { + targetBranchName = repository.DefaultBranch; + } + + var targetBranch = + gitClient.GetRefsAsync( + repositoryDescription.ProjectName, + repositoryDescription.RepositoryName, + filter: targetBranchName.Replace("refs/", string.Empty)) + .GetAwaiter().GetResult() + .SingleOrDefault(); + + if (targetBranch == null) + { + throw new TfsBranchNotFoundException(targetBranchName); + } + + var pullRequest = new GitPullRequest() + { + SourceRefName = settings.SourceRefName, + TargetRefName = targetBranch.Name, + Title = settings.Title, + Description = settings.Description + }; + + var createdPullRequest = + gitClient + .CreatePullRequestAsync( + pullRequest, + repositoryDescription.ProjectName, + repositoryDescription.RepositoryName) + .GetAwaiter().GetResult(); + + var pullRequestReadSettings = + new TfsPullRequestSettings( + settings.RepositoryUrl, + createdPullRequest.PullRequestId, + settings.Credentials); + + return new TfsPullRequest(log, pullRequestReadSettings, gitClientFactory); + } + } + /// /// Votes for the pullrequest. /// @@ -307,7 +377,7 @@ public void Vote(TfsPullRequestVote vote) return; } - using (var gitClient = this.gitClientFactory.CreateGitClient(this.CollectionUrl, this.settings.Credentials, out var authorizedIdenity)) + using (var gitClient = this.gitClientFactory.CreateGitClient(this.CollectionUrl, this.credentials, out var authorizedIdenity)) { var request = gitClient.CreatePullRequestReviewerAsync( @@ -354,7 +424,7 @@ public void SetStatus(TfsPullRequestStatus status) return; } - using (var gitClient = this.gitClientFactory.CreateGitClient(this.CollectionUrl, this.settings.Credentials)) + using (var gitClient = this.gitClientFactory.CreateGitClient(this.CollectionUrl, this.credentials)) { var request = gitClient.CreatePullRequestStatusAsync( @@ -419,7 +489,7 @@ public IEnumerable GetModifiedFiles() Version = this.LastTargetCommitId }; - using (var gitClient = this.gitClientFactory.CreateGitClient(this.CollectionUrl, this.settings.Credentials)) + using (var gitClient = this.gitClientFactory.CreateGitClient(this.CollectionUrl, this.credentials)) { var commitDiffs = gitClient.GetCommitDiffsAsync( this.ProjectName, @@ -462,7 +532,7 @@ public IEnumerable GetCommentThreads() return new List(); } - using (var gitClient = this.gitClientFactory.CreateGitClient(this.CollectionUrl, this.settings.Credentials)) + using (var gitClient = this.gitClientFactory.CreateGitClient(this.CollectionUrl, this.credentials)) { var threads = gitClient.GetThreadsAsync(this.RepositoryId, this.PullRequestId, null, null, null, CancellationToken.None).Result; @@ -499,7 +569,7 @@ public void CreateCommentThread(TfsPullRequestCommentThread thread) return; } - using (var gitClient = this.gitClientFactory.CreateGitClient(this.CollectionUrl, this.settings.Credentials)) + using (var gitClient = this.gitClientFactory.CreateGitClient(this.CollectionUrl, this.credentials)) { gitClient.CreateThreadAsync( thread.InnerThread, @@ -522,7 +592,7 @@ public int GetLatestIterationId() return -1; } - using (var gitClient = this.gitClientFactory.CreateGitClient(this.CollectionUrl, this.settings.Credentials)) + using (var gitClient = this.gitClientFactory.CreateGitClient(this.CollectionUrl, this.credentials)) { var iterations = gitClient.GetPullRequestIterationsAsync( this.RepositoryId, @@ -553,7 +623,7 @@ public IEnumerable GetIterationChanges(int iterat return null; } - using (var gitClient = this.gitClientFactory.CreateGitClient(this.CollectionUrl, this.settings.Credentials)) + using (var gitClient = this.gitClientFactory.CreateGitClient(this.CollectionUrl, this.credentials)) { var changes = gitClient.GetPullRequestIterationChangesAsync( @@ -590,7 +660,7 @@ private void SetCommentThreadStatus(int threadId, CommentThreadStatus status) return; } - using (var gitClient = this.gitClientFactory.CreateGitClient(this.CollectionUrl, this.settings.Credentials)) + using (var gitClient = this.gitClientFactory.CreateGitClient(this.CollectionUrl, this.credentials)) { var newThread = new GitPullRequestCommentThread { @@ -622,7 +692,7 @@ private bool ValidatePullRequest() return true; } - if (this.settings.ThrowExceptionIfPullRequestCouldNotBeFound) + if (this.throwExceptionIfPullRequestCouldNotBeFound) { throw new TfsPullRequestNotFoundException("Pull request not found"); } diff --git a/src/Cake.Tfs/PullRequest/TfsPullRequestSettings.cs b/src/Cake.Tfs/PullRequest/TfsPullRequestSettings.cs index 56f38f9d..9ca502ae 100644 --- a/src/Cake.Tfs/PullRequest/TfsPullRequestSettings.cs +++ b/src/Cake.Tfs/PullRequest/TfsPullRequestSettings.cs @@ -4,9 +4,9 @@ using Cake.Tfs.Authentication; /// - /// Settings for pull request aliases. + /// Settings for aliases handling pull requests. /// - public class TfsPullRequestSettings + public class TfsPullRequestSettings : BaseTfsPullRequestSettings { /// /// Initializes a new instance of the class. @@ -19,14 +19,8 @@ public class TfsPullRequestSettings /// Credentials to use to authenticate against Team Foundation Server or /// Azure DevOps. public TfsPullRequestSettings(Uri repositoryUrl, string sourceBranch, ITfsCredentials credentials) + : base(repositoryUrl, sourceBranch, credentials) { - repositoryUrl.NotNull(nameof(repositoryUrl)); - sourceBranch.NotNullOrWhiteSpace(nameof(sourceBranch)); - credentials.NotNull(nameof(credentials)); - - this.RepositoryUrl = repositoryUrl; - this.SourceBranch = sourceBranch; - this.Credentials = credentials; } /// @@ -40,14 +34,11 @@ public TfsPullRequestSettings(Uri repositoryUrl, string sourceBranch, ITfsCreden /// Credentials to use to authenticate against Team Foundation Server or /// Azure DevOps. public TfsPullRequestSettings(Uri repositoryUrl, int pullRequestId, ITfsCredentials credentials) + : base(repositoryUrl, credentials) { - repositoryUrl.NotNull(nameof(repositoryUrl)); pullRequestId.NotNegativeOrZero(nameof(pullRequestId)); - credentials.NotNull(nameof(credentials)); - this.RepositoryUrl = repositoryUrl; this.PullRequestId = pullRequestId; - this.Credentials = credentials; } /// @@ -56,13 +47,9 @@ public TfsPullRequestSettings(Uri repositoryUrl, int pullRequestId, ITfsCredenti /// /// Settings containing the parameters. public TfsPullRequestSettings(TfsPullRequestSettings settings) + : base(settings) { - settings.NotNull(nameof(settings)); - - this.RepositoryUrl = settings.RepositoryUrl; - this.SourceBranch = settings.SourceBranch; this.PullRequestId = settings.PullRequestId; - this.Credentials = settings.Credentials; this.ThrowExceptionIfPullRequestCouldNotBeFound = settings.ThrowExceptionIfPullRequestCouldNotBeFound; } @@ -73,20 +60,8 @@ public TfsPullRequestSettings(TfsPullRequestSettings settings) /// Credentials to use to authenticate against Team Foundation Server or /// Azure DevOps. public TfsPullRequestSettings(ITfsCredentials credentials) + : base(credentials) { - credentials.NotNull(nameof(credentials)); - - this.Credentials = credentials; - - var repositoryUrl = Environment.GetEnvironmentVariable("BUILD_REPOSITORY_URI", EnvironmentVariableTarget.Process); - if (string.IsNullOrWhiteSpace(repositoryUrl)) - { - throw new InvalidOperationException( - "Failed to read the BUILD_REPOSITORY_URI environment variable. Make sure you are running in an Azure Pipelines or Team Foundation Server build."); - } - - this.RepositoryUrl = new Uri(repositoryUrl); - var pullRequestId = Environment.GetEnvironmentVariable("SYSTEM_PULLREQUEST_PULLREQUESTID", EnvironmentVariableTarget.Process); if (string.IsNullOrWhiteSpace(pullRequestId)) { @@ -107,30 +82,14 @@ public TfsPullRequestSettings(ITfsCredentials credentials) this.PullRequestId = pullRequestIdValue; } - /// - /// Gets the full URL of the Git repository, eg. http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository. - /// - public Uri RepositoryUrl { get; private set; } - - /// - /// Gets the branch for which the pull request is made. - /// - public string SourceBranch { get; private set; } - /// /// Gets the ID of the pull request. /// public int? PullRequestId { get; private set; } - /// - /// Gets the credentials used to authenticate against Team Foundation Server or - /// Azure DevOps. - /// - public ITfsCredentials Credentials { get; private set; } - /// /// Gets or sets a value indicating whether an exception should be thrown if - /// pull request for or could not be found. + /// pull request for or could not be found. /// public bool ThrowExceptionIfPullRequestCouldNotBeFound { get; set; } = true; diff --git a/src/Cake.Tfs/TfsAliases.PullRequest.cs b/src/Cake.Tfs/TfsAliases.PullRequest.cs index 4bf6a07a..3acc7575 100644 --- a/src/Cake.Tfs/TfsAliases.PullRequest.cs +++ b/src/Cake.Tfs/TfsAliases.PullRequest.cs @@ -174,5 +174,43 @@ public static void TfsSetPullRequestStatus( new TfsPullRequest(context.Log, settings, new GitClientFactory()).SetStatus(status); } + + /// + /// Creates a pull request in Team Foundation Server or Azure DevOps + /// using the specified settings. + /// + /// The context. + /// Settings for creating the pull request. + /// Returns a initialized with the + /// created pull request. + /// + /// Creates a pull request: + /// + /// + /// + /// + /// If the target branch could not be found. + [CakeMethodAlias] + [CakeAliasCategory("Pull Request")] + public static TfsPullRequest TfsCreatePullRequest( + this ICakeContext context, + TfsCreatePullRequestSettings settings) + { + context.NotNull(nameof(context)); + context.NotNull(nameof(settings)); + + return PullRequest.TfsPullRequest.Create(context.Log, new GitClientFactory(), settings); + } } } \ No newline at end of file