public void Should_Throw_If_Property_Collection_Is_Null()
            {
                // Given
                var azureDevOpsThread = new AzureDevOpsPullRequestCommentThread();

                // When
                var result = Record.Exception(() => azureDevOpsThread.SetValue("key", 1));

                // Then
                result.IsInvalidOperationException();
            }
예제 #2
0
            public void Should_Throw_If_Property_Name_Is_Null()
            {
                // Given
                var azureDevOpsThread = new AzureDevOpsPullRequestCommentThread();

                // When
                var result = Record.Exception(() => azureDevOpsThread.GetValue <string>(null));

                // Then
                result.IsArgumentNullException("propertyName");
            }
            public void Should_Throw_If_Thread_Is_Null()
            {
                // Given
                AzureDevOpsPullRequestCommentThread thread = null;

                // When
                var result = Record.Exception(() => thread.ToPullRequestDiscussionThread());

                // Then
                result.IsArgumentNullException("thread");
            }
예제 #4
0
            public void Should_Throw_If_Property_Name_Is_Empty()
            {
                // Given
                var azureDevOpsThread = new AzureDevOpsPullRequestCommentThread();

                // When
                var result = Record.Exception(() => azureDevOpsThread.GetValue <object>(string.Empty));

                // Then
                result.IsArgumentOutOfRangeException("propertyName");
            }
            public void Should_Return_Default_Value_If_Property_Collection_Is_Null_For_Integer_Value()
            {
                // Given
                var azureDevOpsThread = new AzureDevOpsPullRequestCommentThread();

                // When
                var result = azureDevOpsThread.GetValue <int>("key");

                // Then
                result.ShouldBe(default(int));
            }
예제 #6
0
        private bool AddThreadProperties(
            AzureDevOpsPullRequestCommentThread thread,
            IEnumerable <AzureDevOpsPullRequestIterationChange> changes,
            IIssue issue,
            int iterationId,
            string commentSource)
        {
            thread.NotNull(nameof(thread));
            changes.NotNull(nameof(changes));
            issue.NotNull(nameof(issue));

            var properties = new Dictionary <string, object>();

            if (issue.AffectedFileRelativePath != null)
            {
                if (this.azureDevOpsPullRequest.CodeReviewId > 0)
                {
                    var changeTrackingId =
                        this.TryGetCodeFlowChangeTrackingId(changes, issue.AffectedFileRelativePath);
                    if (changeTrackingId < 0)
                    {
                        // Don't post comment if we couldn't determine the change.
                        return(false);
                    }

                    AddCodeFlowProperties(issue, iterationId, changeTrackingId, properties);
                }
                else
                {
                    throw new NotSupportedException("Legacy code reviews are not supported.");
                }
            }

            // An Azure DevOps UI extension will recognize this and format the comments differently.
            properties.Add("CodeAnalysisThreadType", "CodeAnalysisIssue");

            thread.Properties = properties;

            // Add a custom property to be able to distinguish all comments created this way.
            thread.SetCommentSource(commentSource);

            // Add custom property for identifying the comment for subsequent runs
            thread.SetCommentIdentifier(issue.Identifier);

            // Add a custom property to be able to distinguish all comments by provider type later on
            thread.SetProviderType(issue.ProviderType);

            // Add a custom property to be able to return issue message from existing threads,
            // without any formatting done by this addin, back to Cake.Issues.PullRequests.
            thread.SetIssueMessage(issue.MessageText);

            return(true);
        }
예제 #7
0
        /// <summary>
        /// Converts a <see cref="AzureDevOpsPullRequestCommentThread"/> from Azure DevOps to a <see cref="IPullRequestDiscussionThread"/> as used in this addin.
        /// </summary>
        /// <param name="thread">Azure DevOps thread to convert.</param>
        /// <returns>Converted thread.</returns>
        public static IPullRequestDiscussionThread ToPullRequestDiscussionThread(this AzureDevOpsPullRequestCommentThread thread)
        {
            thread.NotNull(nameof(thread));

            return(new PullRequestDiscussionThread(
                       thread.Id,
                       thread.Status.ToPullRequestDiscussionStatus(),
                       thread.FilePath,
                       thread.Comments.Select(x => x.ToPullRequestDiscussionComment()))
            {
                CommentSource = thread.GetCommentSource(),
                Resolution = thread.Status.ToPullRequestDiscussionResolution(),
            });
        }
예제 #8
0
            public void Should_Return_Null_If_Not_Set()
            {
                // Given
                var thread = new GitPullRequestCommentThread
                {
                    Id     = 16,
                    Status = CommentThreadStatus.Active,
                };

                // When
                var azureDevOpsThread = new AzureDevOpsPullRequestCommentThread(thread);

                // Then
                azureDevOpsThread.Properties.ShouldBeNull();
            }
예제 #9
0
            public void Should_Return_Empty_Comment_Thread()
            {
                // Given, When
                var thread            = new AzureDevOpsPullRequestCommentThread();
                var getCommentsResult = Record.Exception(() => thread.Comments);

                // Then
                thread.ShouldNotBeNull();
                thread.InnerThread.ShouldBeOfType(typeof(GitPullRequestCommentThread));
                thread.Id.ShouldBe(default(int));
                thread.FilePath.ShouldBeNull();
                thread.Status.ShouldBe(default(AzureDevOpsCommentThreadStatus));
                thread.Properties.ShouldBeNull();

                getCommentsResult.IsInvalidOperationException();
            }
예제 #10
0
            public void Should_Return_Null_If_Not_Initialized()
            {
                // Given
                var thread = new GitPullRequestCommentThread
                {
                    Id     = 16,
                    Status = CommentThreadStatus.Active,
                };

                // When
                var azureDevOpsThread = new AzureDevOpsPullRequestCommentThread(thread);
                var filePath          = azureDevOpsThread.FilePath;

                // Then
                filePath.ShouldBeNull();
            }
예제 #11
0
            public void Should_Throw_If_Not_Set()
            {
                // Given
                var thread = new GitPullRequestCommentThread
                {
                    Id     = 15,
                    Status = CommentThreadStatus.Active,
                };

                // When
                var azureDevOpsThread = new AzureDevOpsPullRequestCommentThread(thread);
                var result            = Record.Exception(() => azureDevOpsThread.Comments);

                // Then
                result.IsInvalidOperationException();
            }
예제 #12
0
            public void Should_Return_Valid_Comment_Threads()
            {
                // Given
                var fixture     = new PullRequestFixture(BasePullRequestFixture.ValidAzureDevOpsUrl, 44);
                var pullRequest = new AzureDevOpsPullRequest(fixture.Log, fixture.Settings, fixture.GitClientFactory);

                // When
                var threads = pullRequest.GetCommentThreads();

                // Then
                threads.ShouldNotBeNull();
                threads.ShouldNotBeEmpty();
                threads.Count().ShouldBe(2);

                AzureDevOpsPullRequestCommentThread thread1 = threads.First();

                thread1.Id.ShouldBe(11);
                thread1.Status.ShouldBe(AzureDevOpsCommentThreadStatus.Active);
                thread1.FilePath.ShouldNotBeNull();
                thread1.FilePath.FullPath.ShouldBe("some/path/to/file.cs");

                thread1.Comments.ShouldNotBeNull();
                thread1.Comments.ShouldNotBeEmpty();
                thread1.Comments.Count().ShouldBe(2);

                AzureDevOpsComment comment11 = thread1.Comments.First();

                comment11.ShouldNotBeNull();
                comment11.Content.ShouldBe("Hello");
                comment11.IsDeleted.ShouldBe(false);
                comment11.CommentType.ShouldBe(AzureDevOpsCommentType.CodeChange);

                AzureDevOpsComment comment12 = thread1.Comments.Last();

                comment12.ShouldNotBeNull();
                comment12.Content.ShouldBe("Goodbye");
                comment12.IsDeleted.ShouldBe(true);
                comment12.CommentType.ShouldBe(AzureDevOpsCommentType.Text);

                AzureDevOpsPullRequestCommentThread thread2 = threads.Last();

                thread2.Id.ShouldBe(22);
                thread2.Status.ShouldBe(AzureDevOpsCommentThreadStatus.Fixed);
                thread2.FilePath.ShouldBeNull();
                thread2.Comments.ShouldNotBeNull();
                thread2.Comments.ShouldBeEmpty();
            }
예제 #13
0
            public void Should_Return_Default_Value_If_Property_Does_Not_Exist_For_Int_Value()
            {
                // Given
                var azureDevOpsThread = new AzureDevOpsPullRequestCommentThread(
                    new GitPullRequestCommentThread
                {
                    Id         = 42,
                    Status     = CommentThreadStatus.Active,
                    Properties = new PropertiesCollection(),
                });

                // When
                var result = azureDevOpsThread.GetValue <int>("key");

                // Then
                result.ShouldBe(default(int));
            }
예제 #14
0
            public void Should_Create_Valid_Comment_Thread()
            {
                // Given
                var fixture     = new PullRequestFixture(BasePullRequestFixture.ValidAzureDevOpsUrl, 200);
                var pullRequest = new AzureDevOpsPullRequest(fixture.Log, fixture.Settings, fixture.GitClientFactory);
                var inThread    = new AzureDevOpsPullRequestCommentThread {
                    Id = 300, Status = AzureDevOpsCommentThreadStatus.Pending, FilePath = "/index.html"
                };

                // When
                var outThread = pullRequest.CreateCommentThread(inThread);

                // Then
                outThread.Id.ShouldBe(inThread.Id);
                outThread.Status.ShouldBe(inThread.Status);
                outThread.FilePath.ShouldBeEquivalentTo(inThread.FilePath);
            }
예제 #15
0
        /// <summary>
        /// Creates a new comment thread in the pull request.
        /// </summary>
        /// <param name="thread">The instance of the thread.</param>
        public void CreateCommentThread(AzureDevOpsPullRequestCommentThread thread)
        {
            if (!this.ValidatePullRequest())
            {
                return;
            }

            using (var gitClient = this.gitClientFactory.CreateGitClient(this.CollectionUrl, this.credentials))
            {
                gitClient.CreateThreadAsync(
                    thread.InnerThread,
                    this.RepositoryId,
                    this.PullRequestId,
                    null,
                    CancellationToken.None).Wait();
            }
        }
            public void Should_Not_Throw_If_Properties_Are_Null()
            {
                // Given
                var thread =
                    new AzureDevOpsPullRequestCommentThread
                {
                    Id         = 123,
                    Status     = AzureDevOpsCommentThreadStatus.Active,
                    FilePath   = "/foo.cs",
                    Comments   = new List <AzureDevOpsComment>(),
                    Properties = null,
                };

                // When
                var result = thread.ToPullRequestDiscussionThread();

                // Then
                result.CommentSource.ShouldBe(default);
            public void Should_Throw_If_Comments_Are_Null()
            {
                // Given
                var thread =
                    new AzureDevOpsPullRequestCommentThread
                {
                    Id         = 123,
                    Status     = AzureDevOpsCommentThreadStatus.Active,
                    FilePath   = "/foo.cs",
                    Comments   = null,
                    Properties = new Dictionary <string, object>(),
                };

                // When
                var result = Record.Exception(() => thread.ToPullRequestDiscussionThread());

                // Then
                result.IsInvalidOperationException("Comments list is not created.");
            }
예제 #18
0
            public void Should_Set_And_Trimmed_Properly()
            {
                // Given
                var thread = new GitPullRequestCommentThread
                {
                    Id     = 100,
                    Status = CommentThreadStatus.Active,
                };

                // When
                var azureDevOpsThread = new AzureDevOpsPullRequestCommentThread(thread)
                {
                    FilePath = "/path/to/myclass.cs",
                };

                // Then
                azureDevOpsThread.FilePath.ShouldNotBeNull();
                azureDevOpsThread.FilePath.FullPath.ShouldBe("path/to/myclass.cs");
            }
        /// <summary>
        /// Creates a new comment thread with a single comment in the pull request.
        /// </summary>
        /// <param name="comment">Comment which should be added.</param>
        public void CreateComment(string comment)
        {
            comment.NotNullOrWhiteSpace(nameof(comment));

            var thread = new AzureDevOpsPullRequestCommentThread
            {
                Status   = AzureDevOpsCommentThreadStatus.Active,
                Comments = new List <AzureDevOpsComment>
                {
                    new AzureDevOpsComment
                    {
                        CommentType = AzureDevOpsCommentType.System,
                        IsDeleted   = false,
                        Content     = comment,
                    },
                },
            };

            this.CreateCommentThread(thread);
        }
예제 #20
0
            public void Should_Set_Empty_Collection()
            {
                // Given
                var thread = new GitPullRequestCommentThread
                {
                    Id     = 16,
                    Status = CommentThreadStatus.Active,
                };

                // When
                var azureDevOpsThread = new AzureDevOpsPullRequestCommentThread(thread)
                {
                    Properties = new Dictionary <string, object>(),
                };

                // Then
                azureDevOpsThread.Properties.ShouldNotBeNull();
                azureDevOpsThread.Properties.ShouldBeOfType <PropertiesCollection>();
                azureDevOpsThread.Properties.ShouldBeEmpty();
            }
        /// <summary>
        /// Creates a new comment thread in the pull request.
        /// </summary>
        /// <param name="thread">The instance of the thread.</param>
        public void CreateCommentThread(AzureDevOpsPullRequestCommentThread thread)
        {
            thread.NotNull(nameof(thread));

            if (!this.ValidatePullRequest())
            {
                return;
            }

            using (var gitClient = this.gitClientFactory.CreateGitClient(this.CollectionUrl, this.credentials))
            {
                gitClient
                .CreateThreadAsync(
                    thread.InnerThread,
                    this.RepositoryId,
                    this.PullRequestId)
                .ConfigureAwait(false)
                .GetAwaiter()
                .GetResult();
            }
        }
예제 #22
0
            public void Should_Return_Valid_Comment_Thread()
            {
                // Given
                var gitCommentThread = new GitPullRequestCommentThread
                {
                    Id            = 42,
                    Status        = CommentThreadStatus.Pending,
                    ThreadContext = new CommentThreadContext {
                        FilePath = "/src/myclass.cs"
                    },
                    Comments = new List <Comment> {
                        new Comment {
                            Content = "Hello", CommentType = CommentType.Text, IsDeleted = false
                        }
                    },
                    Properties = new PropertiesCollection(),
                };

                // When
                var azureDevOpsCommentThread = new AzureDevOpsPullRequestCommentThread(gitCommentThread);

                // Then
                azureDevOpsCommentThread.ShouldNotBeNull();
                azureDevOpsCommentThread.Id.ShouldBe(42);
                azureDevOpsCommentThread.Status.ShouldBe(AzureDevOpsCommentThreadStatus.Pending);
                azureDevOpsCommentThread.FilePath.ShouldNotBeNull();
                azureDevOpsCommentThread.FilePath.FullPath.ShouldBe("src/myclass.cs");

                azureDevOpsCommentThread.Comments.ShouldNotBeNull();
                azureDevOpsCommentThread.Comments.ShouldNotBeEmpty();
                azureDevOpsCommentThread.Comments.ShouldHaveSingleItem();
                azureDevOpsCommentThread.Comments.First().ShouldNotBeNull();
                azureDevOpsCommentThread.Comments.First().Content.ShouldBe("Hello");
                azureDevOpsCommentThread.Comments.First().CommentType.ShouldBe(AzureDevOpsCommentType.Text);
                azureDevOpsCommentThread.Comments.First().IsDeleted.ShouldBeFalse();

                azureDevOpsCommentThread.Properties.ShouldNotBeNull();
                azureDevOpsCommentThread.Properties.ShouldBeEmpty();
            }
예제 #23
0
            public void Should_Set_Valid_Properties()
            {
                // Given
                var azureDevOpsThread = new AzureDevOpsPullRequestCommentThread(
                    new GitPullRequestCommentThread
                {
                    Id         = 42,
                    Status     = CommentThreadStatus.Active,
                    Properties = new PropertiesCollection {
                        { "one", 1 }
                    },
                });

                // When
                azureDevOpsThread.SetValue("one", "string");
                azureDevOpsThread.SetValue("two", 2);

                // Then
                azureDevOpsThread.Properties.ShouldNotBeNull();
                azureDevOpsThread.Properties.ShouldNotBeEmpty();
                azureDevOpsThread.Properties.ShouldContainKeyAndValue("one", "string");
                azureDevOpsThread.Properties.ShouldContainKeyAndValue("two", 2);
            }
예제 #24
0
            public void Should_Set_Colletion_With_Single_Element()
            {
                // Given
                var thread = new GitPullRequestCommentThread
                {
                    Id         = 16,
                    Status     = CommentThreadStatus.Active,
                    Properties = new PropertiesCollection(),
                };

                // When
                var azureDevOpsThread = new AzureDevOpsPullRequestCommentThread(thread)
                {
                    Properties = { ["fake"] = "value" }
                };

                // Then
                azureDevOpsThread.Properties.ShouldNotBeNull();
                azureDevOpsThread.Properties.ShouldNotBeEmpty();
                azureDevOpsThread.Properties.ShouldHaveSingleItem();

                azureDevOpsThread.Properties["fake"].ShouldNotBeNull();
                azureDevOpsThread.Properties["fake"].ShouldBe("value");
            }
        /// <summary>
        /// Sets the comment identifier value used to identify the issue for which the comment was created.
        /// </summary>
        /// <param name="thread">Thread for which the value should be set.</param>
        /// <param name="value">Value to set as comment identifier.</param>
        public static void SetCommentIdentifier(this AzureDevOpsPullRequestCommentThread thread, string value)
        {
            thread.NotNull(nameof(thread));

            thread.SetValue(CommentIdentifierPropertyName, value);
        }
        /// <summary>
        /// Gets the comment identifier to identify the issue for which the comment was created.
        /// </summary>
        /// <param name="thread">Thread to get the value from.</param>
        /// <returns>Comment identifier value.</returns>
        public static string GetCommentIdentifier(this AzureDevOpsPullRequestCommentThread thread)
        {
            thread.NotNull(nameof(thread));

            return(thread.GetValue <string>(CommentIdentifierPropertyName));
        }
        /// <summary>
        /// Checks if the custom comment source value used to decorate comments created by this addin
        /// has a specific value.
        /// </summary>
        /// <param name="thread">Thread to check.</param>
        /// <param name="value">Value to check for.</param>
        /// <returns><c>True</c> if the value is identical, <c>False</c> otherwise.</returns>
        public static bool IsCommentSource(this AzureDevOpsPullRequestCommentThread thread, string value)
        {
            thread.NotNull(nameof(thread));

            return(thread.GetCommentSource() == value);
        }
        /// <summary>
        /// Sets the provider type value used to identify specific provider origins later on when reading back existing issues.
        /// </summary>
        /// <param name="thread">Thread for which the value should be set.</param>
        /// <param name="value">Value to set as comment source.</param>
        public static void SetProviderType(this AzureDevOpsPullRequestCommentThread thread, string value)
        {
            thread.NotNull(nameof(thread));

            thread.SetValue(ProviderTypePropertyName, value);
        }
        /// <summary>
        /// Gets the provider type value used to identify specific provider origins later on when reading back existing issues.
        /// </summary>
        /// <param name="thread">Thread to get the value from.</param>
        /// <returns>Comment source value.</returns>
        public static string GetProviderType(this AzureDevOpsPullRequestCommentThread thread)
        {
            thread.NotNull(nameof(thread));

            return(thread.GetValue <string>(ProviderTypePropertyName));
        }
        /// <summary>
        /// Sets the original message of the issue as provided by Cake.Issues.PullRequests.
        /// </summary>
        /// <param name="thread">Thread for which the value should be set.</param>
        /// <param name="value">Value to set as the original message.</param>
        public static void SetIssueMessage(this AzureDevOpsPullRequestCommentThread thread, string value)
        {
            thread.NotNull(nameof(thread));

            thread.SetValue(IssueMessagePropertyName, value);
        }