/// <summary> /// Builds a collection of <see cref="PullRequestReviewSummaryViewModel"/>s by user. /// </summary> /// <param name="currentUser">The current user.</param> /// <param name="pullRequest">The pull request model.</param> /// <remarks> /// This method builds a list similar to that found in the "Reviewers" section at the top- /// right of the Pull Request page on GitHub. /// </remarks> public static IEnumerable <PullRequestReviewSummaryViewModel> BuildByUser( IAccount currentUser, IPullRequestModel pullRequest) { var existing = new Dictionary <string, PullRequestReviewSummaryViewModel>(); foreach (var review in pullRequest.Reviews.OrderBy(x => x.Id)) { if (review.State == PullRequestReviewState.Pending && review.User.Login != currentUser.Login) { continue; } PullRequestReviewSummaryViewModel previous; existing.TryGetValue(review.User.Login, out previous); var previousPriority = ToPriority(previous); var reviewPriority = ToPriority(review.State); if (reviewPriority >= previousPriority) { var count = pullRequest.ReviewComments .Where(x => x.PullRequestReviewId == review.Id) .Count(); existing[review.User.Login] = new PullRequestReviewSummaryViewModel { Id = review.Id, User = review.User, State = review.State, FileCommentCount = count }; } } var result = existing.Values.OrderBy(x => x.User).AsEnumerable(); if (!result.Any(x => x.State == PullRequestReviewState.Pending)) { var newReview = new PullRequestReviewSummaryViewModel { State = PullRequestReviewState.Pending, User = currentUser, }; result = result.Concat(new[] { newReview }); } return(result); }
/// <summary> /// Builds a collection of <see cref="PullRequestReviewSummaryViewModel"/>s by user. /// </summary> /// <param name="currentUser">The current user.</param> /// <param name="pullRequest">The pull request model.</param> /// <remarks> /// This method builds a list similar to that found in the "Reviewers" section at the top- /// right of the Pull Request page on GitHub. /// </remarks> public static IEnumerable <PullRequestReviewSummaryViewModel> BuildByUser( ActorModel currentUser, PullRequestDetailModel pullRequest) { var existing = new Dictionary <string, PullRequestReviewSummaryViewModel>(); foreach (var review in pullRequest.Reviews.OrderBy(x => x.SubmittedAt)) { if (review.State == PullRequestReviewState.Pending && review.Author.Login != currentUser.Login) { continue; } PullRequestReviewSummaryViewModel previous; existing.TryGetValue(review.Author.Login, out previous); var previousPriority = ToPriority(previous); var reviewPriority = ToPriority(review.State); if (reviewPriority >= previousPriority) { existing[review.Author.Login] = new PullRequestReviewSummaryViewModel { Id = review.Id, User = new ActorViewModel(review.Author), State = review.State, FileCommentCount = review.Comments.Count, }; } } var result = existing.Values.OrderBy(x => x.User.Login).AsEnumerable(); if (!result.Any(x => x.State == PullRequestReviewState.Pending)) { var newReview = new PullRequestReviewSummaryViewModel { State = PullRequestReviewState.Pending, User = new ActorViewModel(currentUser), }; result = result.Concat(new[] { newReview }); } return(result); }
/// <summary> /// Loads the view model from octokit models. /// </summary> /// <param name="pullRequest">The pull request model.</param> public async Task Load(PullRequestDetailModel pullRequest) { try { var firstLoad = (Model == null); Model = pullRequest; Author = new ActorViewModel(pullRequest.Author); Title = Resources.PullRequestNavigationItemText + " #" + pullRequest.Number; IsBusy = true; IsFromFork = !pullRequestsService.IsPullRequestFromRepository(LocalRepository, pullRequest); SourceBranchDisplayName = GetBranchDisplayName(IsFromFork, pullRequest.HeadRepositoryOwner, pullRequest.HeadRefName); TargetBranchDisplayName = GetBranchDisplayName(IsFromFork, pullRequest.BaseRepositoryOwner, pullRequest.BaseRefName); Body = !string.IsNullOrWhiteSpace(pullRequest.Body) ? pullRequest.Body : Resources.NoDescriptionProvidedMarkdown; Reviews = PullRequestReviewSummaryViewModel.BuildByUser(Session.User, pullRequest).ToList(); Checks = (IReadOnlyList <IPullRequestCheckViewModel>)PullRequestCheckViewModel.Build(viewViewModelFactory, pullRequest)?.ToList() ?? Array.Empty <IPullRequestCheckViewModel>(); // Only show unresolved comments await Files.InitializeAsync(Session, c => !c.IsResolved); var localBranches = await pullRequestsService.GetLocalBranches(LocalRepository, pullRequest).ToList(); var currentBranch = gitService.GetBranch(LocalRepository); IsCheckedOut = localBranches.Contains(currentBranch); if (IsCheckedOut) { var divergence = await pullRequestsService.CalculateHistoryDivergence(LocalRepository, Model.Number); var pullEnabled = divergence.BehindBy > 0; var pushEnabled = divergence.AheadBy > 0 && !pullEnabled; string pullToolTip; string pushToolTip; if (pullEnabled) { pullToolTip = string.Format( CultureInfo.InvariantCulture, Resources.PullRequestDetailsPullToolTip, IsFromFork ? Resources.Fork : Resources.Remote, SourceBranchDisplayName); } else { pullToolTip = Resources.NoCommitsToPull; } if (pushEnabled) { pushToolTip = string.Format( CultureInfo.InvariantCulture, Resources.PullRequestDetailsPushToolTip, IsFromFork ? Resources.Fork : Resources.Remote, SourceBranchDisplayName); } else if (divergence.AheadBy == 0) { pushToolTip = Resources.NoCommitsToPush; } else { pushToolTip = Resources.MustPullBeforePush; } var submodulesToSync = await pullRequestsService.CountSubmodulesToSync(LocalRepository); var syncSubmodulesToolTip = string.Format(CultureInfo.InvariantCulture, Resources.SyncSubmodules, submodulesToSync); UpdateState = new UpdateCommandState(divergence, pullEnabled, pushEnabled, pullToolTip, pushToolTip, syncSubmodulesToolTip, submodulesToSync); CheckoutState = null; } else { var caption = localBranches.Count > 0 ? string.Format( CultureInfo.InvariantCulture, Resources.PullRequestDetailsCheckout, localBranches.First().DisplayName) : string.Format( CultureInfo.InvariantCulture, Resources.PullRequestDetailsCheckoutTo, await pullRequestsService.GetDefaultLocalBranchName(LocalRepository, Model.Number, Model.Title)); var clean = await pullRequestsService.IsWorkingDirectoryClean(LocalRepository); string disabled = null; if (pullRequest.HeadRepositoryOwner == null) { disabled = Resources.SourceRepositoryNoLongerAvailable; } else if (!clean) { disabled = Resources.WorkingDirectoryHasUncommittedCHanges; } CheckoutState = new CheckoutCommandState(caption, disabled); UpdateState = null; } sessionSubscription?.Dispose(); sessionSubscription = Session.WhenAnyValue(x => x.HasPendingReview) .Skip(1) .Subscribe(x => Reviews = PullRequestReviewSummaryViewModel.BuildByUser(Session.User, Session.PullRequest).ToList()); if (firstLoad) { usageTracker.IncrementCounter(x => x.NumberOfPullRequestsOpened).Forget(); } if (!isInCheckout) { pullRequestsService.RemoveUnusedRemotes(LocalRepository).Subscribe(_ => { }); } } finally { IsBusy = false; } }
static int ToPriority(PullRequestReviewSummaryViewModel review) { return(review != null?ToPriority(review.State) : 0); }