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); }
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); }
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); }
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); }
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); }