예제 #1
0
        private async Task <ReviewModel> GetBaseLineReview(string Language, string packageName, PullRequestModel pullRequestModel, bool forceBaseline = false)
        {
            // Get  previously cloned review for this pull request or automatically generated master review for package
            ReviewModel review = null;

            // Force baseline is passed when we need to refresh revision 0 with API revision from main branch(Automatic review revision)
            // If API review is not created for PR then also fetch review from main branch.
            if (forceBaseline || pullRequestModel.ReviewId == null)
            {
                var autoReview = await _reviewsRepository.GetMasterReviewForPackageAsync(Language, packageName);

                if (autoReview != null)
                {
                    review        = CloneReview(autoReview);
                    review.Author = pullRequestModel.Author;
                }
            }

            // If either automatic baseline is not available or if review is already created for PR then return this review to create new revision.
            if (review == null && pullRequestModel.ReviewId != null)
            {
                review = await _reviewsRepository.GetReviewAsync(pullRequestModel.ReviewId);
            }

            return(review);
        }
예제 #2
0
        private async Task <ReviewModel> GetMasterReviewAsync(ClaimsPrincipal user, string language, string packageName)
        {
            if (user == null)
            {
                throw new UnauthorizedAccessException();
            }

            var review = await _reviewsRepository.GetMasterReviewForPackageAsync(language, packageName);

            if (review != null)
            {
                review.UpdateAvailable = IsUpdateAvailable(review);
            }

            return(review);
        }
예제 #3
0
        private async Task <ReviewModel> GetBaseLineReview(string Language, string packageName, PullRequestModel pullRequestModel, bool forceBaseline = false)
        {
            // Get  previously cloned review for this pull request or automatically generated master review for package
            ReviewModel review;

            if (pullRequestModel.ReviewId != null && !forceBaseline)
            {
                review = await _reviewsRepository.GetReviewAsync(pullRequestModel.ReviewId);
            }
            else
            {
                var autoReview = await _reviewsRepository.GetMasterReviewForPackageAsync(Language, packageName);

                review        = CloneReview(autoReview);
                review.Author = pullRequestModel.Author;
            }
            return(review);
        }
예제 #4
0
        public async Task <ReviewModel> CreateMasterReviewAsync(ClaimsPrincipal user, string originalName, string label, Stream fileStream, bool runAnalysis)
        {
            //Generate code file from new uploaded package
            using var memoryStream = new MemoryStream();
            var codeFile = await CreateCodeFile(originalName, fileStream, runAnalysis, memoryStream);

            //Get current master review for package and language
            var review = await _reviewsRepository.GetMasterReviewForPackageAsync(codeFile.Language, codeFile.PackageName);

            bool createNewRevision = true;

            if (review != null)
            {
                // Delete pending revisions if it is not in approved state before adding new revision
                // This is to keep only one pending revision since last approval or from initial review revision
                var lastRevision = review.Revisions.LastOrDefault();
                while (lastRevision.Approvers.Count == 0 && review.Revisions.Count > 1)
                {
                    review.Revisions.Remove(lastRevision);
                    lastRevision = review.Revisions.LastOrDefault();
                }

                var renderedCodeFile = new RenderedCodeFile(codeFile);
                var noDiffFound      = await IsReviewSame(review.Revisions.LastOrDefault(), renderedCodeFile);

                if (noDiffFound)
                {
                    // No change is detected from last revision so no need to update this revision
                    createNewRevision = false;
                }
            }
            else
            {
                // Package and language combination doesn't have automatically created review. Create a new review.
                review = new ReviewModel
                {
                    Author       = user.GetGitHubLogin(),
                    CreationDate = DateTime.UtcNow,
                    RunAnalysis  = runAnalysis,
                    Name         = originalName,
                    IsAutomatic  = true
                };
            }

            // Check if user is authorized to modify automatic review
            await AssertAutomaticReviewModifier(user, review);

            if (createNewRevision)
            {
                // Update or insert review with new revision
                var revision = new ReviewRevisionModel()
                {
                    Author = user.GetGitHubLogin(),
                    Label  = label
                };
                var reviewCodeFileModel = await CreateReviewCodeFileModel(revision.RevisionId, memoryStream, codeFile);

                reviewCodeFileModel.FileName = originalName;
                revision.Files.Add(reviewCodeFileModel);
                review.Revisions.Add(revision);
            }

            // Check if review can be marked as approved if another review with same surface level is in approved status
            if (review.Revisions.Last().Approvers.Count() == 0)
            {
                var matchingApprovedRevision = await FindMatchingApprovedRevision(review);

                if (matchingApprovedRevision != null)
                {
                    foreach (var approver in matchingApprovedRevision.Approvers)
                    {
                        review.Revisions.Last().Approvers.Add(approver);
                    }
                }
            }
            await _reviewsRepository.UpsertReviewAsync(review);

            return(review);
        }
예제 #5
0
        private async Task <ReviewRevisionModel> CreateMasterReviewAsync(ClaimsPrincipal user, CodeFile codeFile, string originalName, string label, MemoryStream memoryStream, bool compareAllRevisions)
        {
            var renderedCodeFile = new RenderedCodeFile(codeFile);

            //Get current master review for package and language
            var review = await _reviewsRepository.GetMasterReviewForPackageAsync(codeFile.Language, codeFile.PackageName);

            bool createNewRevision             = true;
            ReviewRevisionModel reviewRevision = null;

            if (review != null)
            {
                // Delete pending revisions if it is not in approved state and if it doesn't have any comments before adding new revision
                // This is to keep only one pending revision since last approval or from initial review revision
                var lastRevision = review.Revisions.LastOrDefault();
                var comments     = await _commentsRepository.GetCommentsAsync(review.ReviewId);

                while (lastRevision.Approvers.Count == 0 &&
                       review.Revisions.Count > 1 &&
                       !await IsReviewSame(lastRevision, renderedCodeFile) &&
                       !comments.Any(c => lastRevision.RevisionId == c.RevisionId))
                {
                    review.Revisions.Remove(lastRevision);
                    lastRevision = review.Revisions.LastOrDefault();
                }
                // We should compare against only latest revision when calling this API from scheduled CI runs
                // But any manual pipeline run at release time should compare against all approved revisions to ensure hotfix release doesn't have API change
                // If review surface doesn't match with any approved revisions then we will create new revision if it doesn't match pending latest revision
                if (compareAllRevisions)
                {
                    foreach (var approvedRevision in review.Revisions.Where(r => r.IsApproved).Reverse())
                    {
                        if (await IsReviewSame(approvedRevision, renderedCodeFile))
                        {
                            return(approvedRevision);
                        }
                    }
                }

                if (await IsReviewSame(lastRevision, renderedCodeFile))
                {
                    reviewRevision    = lastRevision;
                    createNewRevision = false;
                }
            }
            else
            {
                // Package and language combination doesn't have automatically created review. Create a new review.
                review = new ReviewModel
                {
                    Author       = user.GetGitHubLogin(),
                    CreationDate = DateTime.UtcNow,
                    RunAnalysis  = false,
                    Name         = originalName,
                    FilterType   = ReviewType.Automatic
                };
            }

            // Check if user is authorized to modify automatic review
            await AssertAutomaticReviewModifier(user, review);

            if (createNewRevision)
            {
                // Update or insert review with new revision
                reviewRevision = new ReviewRevisionModel()
                {
                    Author = user.GetGitHubLogin(),
                    Label  = label
                };
                var reviewCodeFileModel = await CreateReviewCodeFileModel(reviewRevision.RevisionId, memoryStream, codeFile);

                reviewCodeFileModel.FileName = originalName;
                reviewRevision.Files.Add(reviewCodeFileModel);
                review.Revisions.Add(reviewRevision);
            }

            // Check if review can be marked as approved if another review with same surface level is in approved status
            if (review.Revisions.Last().Approvers.Count() == 0)
            {
                var matchingApprovedRevision = await FindMatchingApprovedRevision(review);

                if (matchingApprovedRevision != null)
                {
                    foreach (var approver in matchingApprovedRevision.Approvers)
                    {
                        review.Revisions.Last().Approvers.Add(approver);
                    }
                }
            }
            await _reviewsRepository.UpsertReviewAsync(review);

            return(reviewRevision);
        }