public async Task ShouldCheckoutLocalBranchAsync()
        {
            var gitClient = MockGitClient();
            var service   = CreateTarget(gitClient, MockGitService());

            var localRepo = Substitute.For <ILocalRepositoryModel>();

            localRepo.CloneUrl.Returns(new UriString("https://foo.bar/owner/repo"));

            var pr = new PullRequestDetailModel
            {
                Number              = 5,
                BaseRefName         = "master",
                BaseRefSha          = "123",
                BaseRepositoryOwner = "owner",
                HeadRefName         = "prbranch",
                HeadRefSha          = "123",
                HeadRepositoryOwner = "owner",
            };

            await service.Checkout(localRepo, pr, "prbranch");

            gitClient.Received().Fetch(Arg.Any <IRepository>(), "origin").Forget();
            gitClient.Received().Checkout(Arg.Any <IRepository>(), "prbranch").Forget();
            gitClient.Received().SetConfig(Arg.Any <IRepository>(), "branch.prbranch.ghfvs-pr-owner-number", "owner#5").Forget();

            Assert.That(4, Is.EqualTo(gitClient.ReceivedCalls().Count()));
        }
Exemple #2
0
        static void BuildPullRequestThreads(PullRequestDetailModel model)
        {
            var commentsByReplyId = new Dictionary <string, List <CommentAdapter> >();

            // Get all comments that are not replies.
            foreach (CommentAdapter comment in model.Reviews.SelectMany(x => x.Comments))
            {
                if (comment.ReplyTo == null)
                {
                    commentsByReplyId.Add(comment.Id, new List <CommentAdapter> {
                        comment
                    });
                }
            }

            // Get the comments that are replies and place them into the relevant list.
            foreach (CommentAdapter comment in model.Reviews.SelectMany(x => x.Comments).OrderBy(x => x.CreatedAt))
            {
                if (comment.ReplyTo != null)
                {
                    List <CommentAdapter> thread = null;

                    if (commentsByReplyId.TryGetValue(comment.ReplyTo, out thread))
                    {
                        thread.Add(comment);
                    }
                }
            }

            // Build a collection of threads for the information collected above.
            var threads = new List <PullRequestReviewThreadModel>();

            foreach (var threadSource in commentsByReplyId)
            {
                var adapter = threadSource.Value[0];

                var thread = new PullRequestReviewThreadModel
                {
                    Comments          = threadSource.Value,
                    CommitSha         = adapter.CommitSha,
                    DiffHunk          = adapter.DiffHunk,
                    Id                = adapter.Id,
                    IsOutdated        = adapter.Position == null,
                    OriginalCommitSha = adapter.OriginalCommitId,
                    OriginalPosition  = adapter.OriginalPosition,
                    Path              = adapter.Path,
                    Position          = adapter.Position,
                };

                // Set a reference to the thread in the comment.
                foreach (var comment in threadSource.Value)
                {
                    comment.Thread = thread;
                }

                threads.Add(thread);
            }

            model.Threads = threads;
        }
        public async Task ShouldCheckoutBranchFromForkAsync()
        {
            var gitClient = MockGitClient();
            var service   = CreateTarget(gitClient, MockGitService());

            var localRepo = Substitute.For <ILocalRepositoryModel>();

            localRepo.CloneUrl.Returns(new UriString("https://foo.bar/owner/repo"));

            var pr = new PullRequestDetailModel
            {
                Number              = 5,
                BaseRefName         = "master",
                BaseRefSha          = "123",
                BaseRepositoryOwner = "owner",
                HeadRefName         = "prbranch",
                HeadRefSha          = "123",
                HeadRepositoryOwner = "fork",
            };

            await service.Checkout(localRepo, pr, "pr/5-fork-branch");

            gitClient.Received().SetRemote(Arg.Any <IRepository>(), "fork", new Uri("https://foo.bar/fork/repo")).Forget();
            gitClient.Received().SetConfig(Arg.Any <IRepository>(), "remote.fork.created-by-ghfvs", "true").Forget();
            gitClient.Received().Fetch(Arg.Any <IRepository>(), "fork").Forget();
            gitClient.Received().Fetch(Arg.Any <IRepository>(), "fork", "prbranch:pr/5-fork-branch").Forget();
            gitClient.Received().Checkout(Arg.Any <IRepository>(), "pr/5-fork-branch").Forget();
            gitClient.Received().SetTrackingBranch(Arg.Any <IRepository>(), "pr/5-fork-branch", "refs/remotes/fork/prbranch").Forget();
            gitClient.Received().SetConfig(Arg.Any <IRepository>(), "branch.pr/5-fork-branch.ghfvs-pr-owner-number", "owner#5").Forget();
            Assert.That(7, Is.EqualTo(gitClient.ReceivedCalls().Count()));
        }
        public async Task ShouldUseUniquelyNamedRemoteForForkAsync()
        {
            var gitClient  = MockGitClient();
            var gitService = MockGitService();
            var service    = CreateTarget(gitClient, gitService);

            var localRepo = Substitute.For <ILocalRepositoryModel>();

            localRepo.CloneUrl.Returns(new UriString("https://foo.bar/owner/repo"));

            using (var repo = gitService.GetRepository(localRepo.CloneUrl))
            {
                var remote           = Substitute.For <Remote>();
                var remoteCollection = Substitute.For <RemoteCollection>();
                remoteCollection["fork"].Returns(remote);
                repo.Network.Remotes.Returns(remoteCollection);

                var pr = new PullRequestDetailModel
                {
                    Number              = 5,
                    BaseRefName         = "master",
                    BaseRefSha          = "123",
                    BaseRepositoryOwner = "owner",
                    HeadRefName         = "prbranch",
                    HeadRefSha          = "123",
                    HeadRepositoryOwner = "fork",
                };

                await service.Checkout(localRepo, pr, "pr/5-fork-branch");

                gitClient.Received().SetRemote(Arg.Any <IRepository>(), "fork1", new Uri("https://foo.bar/fork/repo")).Forget();
                gitClient.Received().SetConfig(Arg.Any <IRepository>(), "remote.fork1.created-by-ghfvs", "true").Forget();
            }
        }
        async Task Load(PullRequestDetailModel pullRequest)
        {
            try
            {
                PullRequestModel = pullRequest;

                Model = pullRequest.Reviews.FirstOrDefault(x =>
                                                           x.State == PullRequestReviewState.Pending && x.Author.Login == session.User.Login) ??
                        new PullRequestReviewModel
                {
                    Body   = string.Empty,
                    Author = session.User,
                    State  = PullRequestReviewState.Pending,
                };

                Body = Model.Body;

                sessionSubscription?.Dispose();
                await UpdateFileComments();

                sessionSubscription = session.PullRequestChanged.Subscribe(_ => UpdateFileComments().Forget());
            }
            finally
            {
                IsBusy = false;
            }
        }
        public PullRequestReviewAuthoringViewModelDesigner()
        {
            PullRequestModel = new PullRequestDetailModel
            {
                Number = 419,
                Title  = "Fix a ton of potential crashers, odd code and redundant calls in ModelService",
                Author = new ActorModel {
                    Login = "******"
                },
                UpdatedAt = DateTimeOffset.Now - TimeSpan.FromDays(2),
            };

            Files = new PullRequestFilesViewModelDesigner();

            FileComments = new[]
            {
                new PullRequestReviewFileCommentViewModelDesigner
                {
                    Body         = @"These should probably be properties. Most likely they should be readonly properties. I know that makes creating instances of these not look as nice as using property initializers when constructing an instance, but if these properties should never be mutated after construction, then it guides future consumers to the right behavior.

However, if you're two-way binding these properties to a UI, then ignore the readonly part and make them properties. But in that case they should probably be reactive properties (or implement INPC).",
                    RelativePath = "src/GitHub.Exports.Reactive/ViewModels/IPullRequestListViewModel.cs",
                },
                new PullRequestReviewFileCommentViewModelDesigner
                {
                    Body         = "While I have no problems with naming a variable ass I think we should probably avoid swear words in case Microsoft runs their Policheck tool against this code.",
                    RelativePath = "src/GitHub.App/ViewModels/PullRequestListViewModel.cs",
                },
            };
        }
Exemple #7
0
        PullRequestDetailModel CreatePullRequestModel(
            int number = 5,
            params PullRequestReviewThreadModel[] threads)
        {
            var result = new PullRequestDetailModel
            {
                Number      = number,
                BaseRefName = "BASEREF",
                BaseRefSha  = "BASESHA",
                HeadRefName = "HEADREF",
                HeadRefSha  = "HEADSHA",
                Threads     = threads,
            };

            if (threads.Length > 0)
            {
                result.Reviews = new[]
                {
                    new PullRequestReviewModel
                    {
                        Comments = threads.SelectMany(x => x.Comments).ToList(),
                        Author   = CurrentUser,
                    },
                };
            }
            else
            {
                result.Reviews = new PullRequestReviewModel[0];
            }

            return(result);
        }
 static void UpdateReadPullRequest(IPullRequestSessionService service, PullRequestDetailModel pullRequest)
 {
     service.ReadPullRequestDetail(
         Arg.Any <HostAddress>(),
         Arg.Any <string>(),
         Arg.Any <string>(),
         Arg.Any <int>()).Returns(pullRequest);
 }
        static PullRequestReviewAuthoringViewModel CreateTarget(
            PullRequestDetailModel model,
            IPullRequestSession session = null)
        {
            session = session ?? CreateSession(model: model);

            return(CreateTarget(
                       sessionManager: CreateSessionManager(session)));
        }
        public async Task InitializeAsync_Creates_Reviews_Async()
        {
            var author = new ActorModel {
                Login = AuthorLogin
            };
            var anotherAuthor = new ActorModel {
                Login = "******"
            };

            var pullRequest = new PullRequestDetailModel
            {
                Number  = 5,
                Author  = author,
                Reviews = new[]
                {
                    new PullRequestReviewModel
                    {
                        Author = author,
                        State  = PullRequestReviewState.Approved,
                    },
                    new PullRequestReviewModel
                    {
                        Author = author,
                        State  = PullRequestReviewState.ChangesRequested,
                    },
                    new PullRequestReviewModel
                    {
                        Author = anotherAuthor,
                        State  = PullRequestReviewState.Approved,
                    },
                    new PullRequestReviewModel
                    {
                        Author = author,
                        State  = PullRequestReviewState.Dismissed,
                    },
                    new PullRequestReviewModel
                    {
                        Author = author,
                        State  = PullRequestReviewState.Pending,
                    },
                },
            };

            var user   = Substitute.For <IAccount>();
            var target = CreateTarget(
                sessionManager: CreateSessionManager(pullRequest));

            await InitializeAsync(target);

            // Should load reviews by the correct author which are not Pending.
            Assert.That(target.Reviews, Has.Count.EqualTo(3));
        }
        protected static IPullRequestSessionManager CreateSessionManager(PullRequestDetailModel pullRequest = null)
        {
            pullRequest = pullRequest ?? new PullRequestDetailModel();

            var session = Substitute.For <IPullRequestSession>();

            session.PullRequest.Returns(pullRequest);

            var result = Substitute.For <IPullRequestSessionManager>();

            result.CurrentSession.Returns(session);
            return(result);
        }
Exemple #12
0
 public async Task <string> GetMergeBase(ILocalRepositoryModel repository, PullRequestDetailModel pullRequest)
 {
     using (var repo = gitService.GetRepository(repository.LocalPath))
     {
         return(await gitClient.GetPullRequestMergeBase(
                    repo,
                    repository.CloneUrl.WithOwner(pullRequest.BaseRepositoryOwner),
                    pullRequest.BaseRefSha,
                    pullRequest.HeadRefSha,
                    pullRequest.BaseRefName,
                    pullRequest.Number));
     }
 }
        /// <inheritdoc/>
        async Task Update(PullRequestDetailModel pullRequestModel)
        {
            PullRequest = pullRequestModel;
            mergeBase   = null;

            foreach (var file in this.fileIndex.Values.ToList())
            {
                await UpdateFile(file);
            }

            UpdatePendingReview();
            pullRequestChanged.OnNext(pullRequestModel);
        }
        public PullRequestReviewViewModelDesigner()
        {
            PullRequestModel = new PullRequestDetailModel
            {
                Number = 419,
                Title  = "Fix a ton of potential crashers, odd code and redundant calls in ModelService",
                Author = new ActorModel {
                    Login = "******"
                },
                UpdatedAt = DateTimeOffset.Now - TimeSpan.FromDays(2),
            };

            Model = new PullRequestReviewModel
            {
                SubmittedAt = DateTimeOffset.Now - TimeSpan.FromDays(1),
                Author      = new ActorModel {
                    Login = "******"
                },
            };

            Body = @"Just a few comments. I don't feel too strongly about them though.

Otherwise, very nice work here! ✨";

            StateDisplay = "approved";

            FileComments = new[]
            {
                new PullRequestReviewFileCommentViewModelDesigner
                {
                    Body         = @"These should probably be properties. Most likely they should be readonly properties. I know that makes creating instances of these not look as nice as using property initializers when constructing an instance, but if these properties should never be mutated after construction, then it guides future consumers to the right behavior.

However, if you're two-way binding these properties to a UI, then ignore the readonly part and make them properties. But in that case they should probably be reactive properties (or implement INPC).",
                    RelativePath = "src/GitHub.Exports.Reactive/ViewModels/IPullRequestListViewModel.cs",
                },
                new PullRequestReviewFileCommentViewModelDesigner
                {
                    Body         = "While I have no problems with naming a variable ass I think we should probably avoid swear words in case Microsoft runs their Policheck tool against this code.",
                    RelativePath = "src/GitHub.App/ViewModels/PullRequestListViewModel.cs",
                },
            };

            OutdatedFileComments = new[]
            {
                new PullRequestReviewFileCommentViewModelDesigner
                {
                    Body         = @"So this is just casting a mutable list to an IReadOnlyList which can be cast back to List. I know we probably won't do that, but I'm thinking of the next person to come along. The safe thing to do is to wrap List with a ReadOnlyList. We have an extension method ToReadOnlyList for observables. Wouldn't be hard to write one for IEnumerable.",
                    RelativePath = "src/GitHub.Exports.Reactive/ViewModels/IPullRequestListViewModel.cs",
                },
            };
        }
Exemple #15
0
        /// <inheritdoc/>
        public IReadOnlyList <InlineAnnotationModel> BuildAnnotations(
            PullRequestDetailModel pullRequest,
            string relativePath)
        {
            relativePath = relativePath.Replace("\\", "/");

            return(pullRequest.CheckSuites
                   ?.SelectMany(checkSuite => checkSuite.CheckRuns.Select(checkRun => new { checkSuite, checkRun }))
                   .SelectMany(arg =>
                               arg.checkRun.Annotations
                               .Where(annotation => annotation.Path == relativePath)
                               .Select(annotation => new InlineAnnotationModel(arg.checkSuite, arg.checkRun, annotation)))
                   .OrderBy(tuple => tuple.StartLine)
                   .ToArray());
        }
Exemple #16
0
        IPullRequestSessionService CreateSessionService(
            PullRequestDetailModel pullRequest = null,
            bool isModified = false)
        {
            pullRequest = pullRequest ?? CreatePullRequestModel();

            var sessionService = Substitute.For<IPullRequestSessionService>();
            sessionService.CreateRebuildSignal().Returns(new Subject<ITextSnapshot>());
            sessionService.IsUnmodifiedAndPushed(null, null, null).ReturnsForAnyArgs(!isModified);
            sessionService.GetPullRequestMergeBase(null, null).ReturnsForAnyArgs("MERGE_BASE");
            sessionService.GetTipSha(null).ReturnsForAnyArgs("TIPSHA");
            sessionService.ReadPullRequestDetail(null, null, null, 0).ReturnsForAnyArgs(pullRequest);
            sessionService.ReadViewer(null).ReturnsForAnyArgs(CurrentUser);
            return sessionService;
        }
        PullRequestReviewViewModel CreateTarget(
            IPullRequestEditorService editorService = null,
            IPullRequestSession session             = null,
            PullRequestDetailModel pullRequest      = null,
            PullRequestReviewModel model            = null)
        {
            editorService = editorService ?? Substitute.For <IPullRequestEditorService>();
            session       = session ?? Substitute.For <IPullRequestSession>();
            pullRequest   = pullRequest ?? CreatePullRequest();
            model         = model ?? pullRequest.Reviews[0];

            return(new PullRequestReviewViewModel(
                       editorService,
                       session,
                       model));
        }
        /// <inheritdoc/>
        async Task Load(PullRequestDetailModel pullRequest)
        {
            IsBusy = true;

            try
            {
                await Task.Delay(0);

                PullRequestTitle = pullRequest.Title;

                var reviews = new List <IPullRequestReviewViewModel>();
                var isFirst = true;

                foreach (var review in pullRequest.Reviews.OrderByDescending(x => x.SubmittedAt))
                {
                    if (review.Author.Login == login)
                    {
                        if (User == null)
                        {
                            User = new ActorViewModel(review.Author);
                        }

                        if (review.State != PullRequestReviewState.Pending)
                        {
                            var vm = new PullRequestReviewViewModel(editorService, session, review);
                            vm.IsExpanded = isFirst;
                            reviews.Add(vm);
                            isFirst = false;
                        }
                    }
                }

                Reviews = reviews;

                if (User == null)
                {
                    User = new ActorViewModel(new ActorModel {
                        Login = login
                    });
                }
            }
            finally
            {
                IsBusy = false;
            }
        }
        /// <inheritdoc/>
        public async Task InitializeAsync(
            RemoteRepositoryModel repository,
            LocalRepositoryModel localRepository,
            ActorModel currentUser,
            PullRequestDetailModel model)
        {
            await base.InitializeAsync(repository, localRepository, model).ConfigureAwait(true);

            timeline.Clear();
            CommitCount      = 0;
            currentUserModel = currentUser;
            CurrentUser      = new ActorViewModel(currentUser);

            var commits = new List <CommitSummaryViewModel>();

            foreach (var i in model.Timeline)
            {
                if (!(i is CommitModel) && commits.Count > 0)
                {
                    timeline.Add(new CommitListViewModel(commits));
                    commits.Clear();
                }

                switch (i)
                {
                case CommitModel commit:
                    commits.Add(new CommitSummaryViewModel(commit));
                    ++CommitCount;
                    break;

                case CommentModel comment:
                    await AddComment(comment).ConfigureAwait(true);

                    break;
                }
            }

            if (commits.Count > 0)
            {
                timeline.Add(new CommitListViewModel(commits));
            }

            await AddPlaceholder().ConfigureAwait(true);

            await usageTracker.IncrementCounter(x => x.NumberOfPRConversationsOpened);
        }
        /// <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.Id))
            {
                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);
        }
        static IPullRequestSession CreateSession(
            string userLogin             = "******",
            PullRequestDetailModel model = null,
            params IPullRequestSessionFile[] files)
        {
            model = model ?? CreatePullRequest();

            var result = Substitute.For <IPullRequestSession>();

            result.PendingReviewId.Returns((string)null);
            result.PullRequest.Returns(model);
            result.User.Returns(new ActorModel {
                Login = userLogin
            });
            result.GetAllFiles().Returns(files);
            result.PullRequestChanged.Returns(new Subject <PullRequestDetailModel>());
            return(result);
        }
Exemple #22
0
        IEnumerable <string> GetLocalBranchesInternal(
            ILocalRepositoryModel localRepository,
            IRepository repository,
            PullRequestDetailModel pullRequest)
        {
            if (IsPullRequestFromRepository(localRepository, pullRequest))
            {
                return(new[] { pullRequest.HeadRefName });
            }
            else
            {
                var key = BuildGHfVSConfigKeyValue(pullRequest.BaseRepositoryOwner, pullRequest.Number);

                return(repository.Config
                       .Select(x => new { Branch = BranchCapture.Match(x.Key).Groups["branch"].Value, Value = x.Value })
                       .Where(x => !string.IsNullOrWhiteSpace(x.Branch) && x.Value == key)
                       .Select(x => x.Branch));
            }
        }
        public async Task Orders_Reviews_Descending_Async()
        {
            var author = new ActorModel {
                Login = AuthorLogin
            };

            var pullRequest = new PullRequestDetailModel
            {
                Number  = 5,
                Reviews = new[]
                {
                    new PullRequestReviewModel
                    {
                        Author      = author,
                        State       = PullRequestReviewState.Approved,
                        SubmittedAt = DateTimeOffset.Now - TimeSpan.FromDays(2),
                    },
                    new PullRequestReviewModel
                    {
                        Author      = author,
                        State       = PullRequestReviewState.ChangesRequested,
                        SubmittedAt = DateTimeOffset.Now - TimeSpan.FromDays(3),
                    },
                    new PullRequestReviewModel
                    {
                        Author      = author,
                        State       = PullRequestReviewState.Dismissed,
                        SubmittedAt = DateTimeOffset.Now - TimeSpan.FromDays(1),
                    },
                },
            };

            var user   = Substitute.For <IAccount>();
            var target = CreateTarget(
                sessionManager: CreateSessionManager(pullRequest));

            await InitializeAsync(target);

            Assert.That(target.Reviews, Is.Not.Empty);
            Assert.That(
                target.Reviews.Select(x => x.Model.SubmittedAt),
                Is.EqualTo(target.Reviews.Select(x => x.Model.SubmittedAt).OrderByDescending(x => x)));
        }
Exemple #24
0
        /// <inheritdoc/>
        public IReadOnlyList <IInlineCommentThreadModel> BuildCommentThreads(
            PullRequestDetailModel pullRequest,
            string relativePath,
            IReadOnlyList <DiffChunk> diff,
            string headSha)
        {
            relativePath = relativePath.Replace("\\", "/");

            var threadsByPosition = pullRequest.Threads
                                    .Where(x => x.Path == relativePath && !x.IsOutdated)
                                    .OrderBy(x => x.Id)
                                    .GroupBy(x => Tuple.Create(x.OriginalCommitSha, x.OriginalPosition));
            var threads = new List <IInlineCommentThreadModel>();

            foreach (var thread in threadsByPosition)
            {
                var hunk      = thread.First().DiffHunk;
                var chunks    = DiffUtilities.ParseFragment(hunk);
                var chunk     = chunks.Last();
                var diffLines = chunk.Lines.Reverse().Take(5).ToList();
                var firstLine = diffLines.FirstOrDefault();
                if (firstLine == null)
                {
                    log.Warning("Ignoring in-line comment in {RelativePath} with no diff line context", relativePath);
                    continue;
                }

                var inlineThread = new InlineCommentThreadModel(
                    relativePath,
                    headSha,
                    diffLines,
                    thread.SelectMany(t => t.Comments.Select(c => new InlineCommentModel
                {
                    Comment = c,
                    Review  = pullRequest.Reviews.FirstOrDefault(x => x.Comments.Contains(c)),
                })));
                threads.Add(inlineThread);
            }

            UpdateCommentThreads(threads, diff);
            return(threads);
        }
Exemple #25
0
        public async Task <string> ExtractToTempFile(
            ILocalRepositoryModel repository,
            PullRequestDetailModel pullRequest,
            string relativePath,
            string commitSha,
            Encoding encoding)
        {
            var tempFilePath = CalculateTempFileName(relativePath, commitSha, encoding);

            if (!File.Exists(tempFilePath))
            {
                using (var repo = gitService.GetRepository(repository.LocalPath))
                {
                    var remote = await gitClient.GetHttpRemote(repo, "origin");
                    await ExtractToTempFile(repo, pullRequest.Number, commitSha, relativePath, encoding, tempFilePath);
                }
            }

            return(tempFilePath);
        }
        IPullRequestSessionManager CreateSessionManager(PullRequestDetailModel pullRequest = null)
        {
            pullRequest = pullRequest ?? new PullRequestDetailModel
            {
                Reviews = new PullRequestReviewModel[0],
            };

            var session = Substitute.For <IPullRequestSession>();

            session.User.Returns(new ActorModel {
                Login = AuthorLogin
            });
            session.PullRequest.Returns(pullRequest);

            var result = Substitute.For <IPullRequestSessionManager>();

            result.GetSession(null, null, 0).ReturnsForAnyArgs(session);

            return(result);
        }
Exemple #27
0
        public IObservable <Unit> SwitchToBranch(ILocalRepositoryModel repository, PullRequestDetailModel pullRequest)
        {
            return(Observable.Defer(async() =>
            {
                using (var repo = gitService.GetRepository(repository.LocalPath))
                {
                    var branchName = GetLocalBranchesInternal(repository, repo, pullRequest).FirstOrDefault();

                    Log.Assert(branchName != null, "PullRequestService.SwitchToBranch called but no local branch found");

                    if (branchName != null)
                    {
                        var remote = await gitClient.GetHttpRemote(repo, "origin");
                        await gitClient.Fetch(repo, remote.Name);

                        var branch = repo.Branches[branchName];

                        if (branch == null)
                        {
                            var trackedBranchName = $"refs/remotes/{remote.Name}/" + branchName;
                            var trackedBranch = repo.Branches[trackedBranchName];

                            if (trackedBranch != null)
                            {
                                branch = repo.CreateBranch(branchName, trackedBranch.Tip);
                                await gitClient.SetTrackingBranch(repo, branchName, trackedBranchName);
                            }
                            else
                            {
                                throw new InvalidOperationException($"Could not find branch '{trackedBranchName}'.");
                            }
                        }

                        await gitClient.Checkout(repo, branchName);
                        await MarkBranchAsPullRequest(repo, branchName, pullRequest.BaseRepositoryOwner, pullRequest.Number);
                    }
                }

                return Observable.Return(Unit.Default);
            }));
        }
        void Load(PullRequestDetailModel pullRequest)
        {
            IsBusy = true;

            try
            {
                PullRequestTitle = pullRequest.Title;

                var checkSuiteRun = pullRequest
                                    .CheckSuites.SelectMany(checkSuite => checkSuite.CheckRuns
                                                            .Select(checkRun => new{ checkSuite, checkRun }))
                                    .First(arg => arg.checkRun.Id == CheckRunId);

                CheckSuiteName  = checkSuiteRun.checkSuite.ApplicationName;
                CheckRunName    = checkSuiteRun.checkRun.Name;
                CheckRunSummary = checkSuiteRun.checkRun.Summary;
                CheckRunText    = checkSuiteRun.checkRun.Text;

                var changedFiles = new HashSet <string>(session.PullRequest.ChangedFiles.Select(model => model.FileName));

                var annotationsLookup = checkSuiteRun.checkRun.Annotations
                                        .ToLookup(annotation => annotation.Path);

                AnnotationsDictionary = annotationsLookup
                                        .Select(models => models.Key)
                                        .OrderBy(s => s)
                                        .ToDictionary(
                    path => path,
                    path => annotationsLookup[path]
                    .Select(annotation => new PullRequestAnnotationItemViewModel(annotation, changedFiles.Contains(path), checkSuiteRun.checkSuite, session, pullRequestEditorService))
                    .Cast <IPullRequestAnnotationItemViewModel>()
                    .ToArray()
                    );

                usageTracker.IncrementCounter(x => x.NumberOfPullRequestOpenAnnotationsList).Forget();
            }
            finally
            {
                IsBusy = false;
            }
        }
        public PullRequestSession(
            IPullRequestSessionService service,
            ActorModel user,
            PullRequestDetailModel pullRequest,
            LocalRepositoryModel localRepository,
            string repositoryOwner,
            bool isCheckedOut)
        {
            Guard.ArgumentNotNull(service, nameof(service));
            Guard.ArgumentNotNull(user, nameof(user));
            Guard.ArgumentNotNull(pullRequest, nameof(pullRequest));
            Guard.ArgumentNotNull(localRepository, nameof(localRepository));

            this.service      = service;
            this.isCheckedOut = isCheckedOut;
            this.pullRequest  = pullRequest;
            User            = user;
            LocalRepository = localRepository;
            RepositoryOwner = repositoryOwner;
            UpdatePendingReview();
        }
        public async Task ShouldCheckoutExistingBranchAsync()
        {
            var gitClient = MockGitClient();
            var service   = CreateTarget(gitClient, MockGitService());

            var localRepo = Substitute.For <ILocalRepositoryModel>();

            var pr = new PullRequestDetailModel
            {
                Number              = 4,
                BaseRefName         = "master",
                BaseRefSha          = "123",
                BaseRepositoryOwner = "owner",
            };

            await service.Checkout(localRepo, pr, "pr/123-foo1");

            gitClient.Received().Checkout(Arg.Any <IRepository>(), "pr/123-foo1").Forget();
            gitClient.Received().SetConfig(Arg.Any <IRepository>(), "branch.pr/123-foo1.ghfvs-pr-owner-number", "owner#4").Forget();

            Assert.That(2, Is.EqualTo(gitClient.ReceivedCalls().Count()));
        }