Exemplo n.º 1
0
        public IObservable <Unit> Checkout(ILocalRepositoryModel repository, IPullRequestModel pullRequest, string localBranchName)
        {
            return(Observable.Defer(async() =>
            {
                var repo = gitService.GetRepository(repository.LocalPath);
                var existing = repo.Branches[localBranchName];

                if (existing != null)
                {
                    await gitClient.Checkout(repo, localBranchName);
                }
                else if (repository.CloneUrl.ToRepositoryUrl() == pullRequest.Head.RepositoryCloneUrl.ToRepositoryUrl())
                {
                    await gitClient.Fetch(repo, "origin");
                    await gitClient.Checkout(repo, localBranchName);
                }
                else
                {
                    var refSpec = $"{pullRequest.Head.Ref}:{localBranchName}";
                    var prConfigKey = $"branch.{localBranchName}.ghfvs-pr";
                    var remoteName = pullRequest.Head.RepositoryCloneUrl.Owner;
                    var remoteUri = pullRequest.Head.RepositoryCloneUrl;

                    await gitClient.SetRemote(repo, remoteName, new Uri(remoteUri));
                    await gitClient.Fetch(repo, remoteName);
                    await gitClient.Fetch(repo, remoteName, new[] { refSpec });
                    await gitClient.Checkout(repo, localBranchName);
                    await gitClient.SetTrackingBranch(repo, localBranchName, $"refs/remotes/{remoteName}/{pullRequest.Head.Ref}");
                    await gitClient.SetConfig(repo, prConfigKey, pullRequest.Number.ToString());
                }

                return Observable.Return(Unit.Default);
            }));
        }
Exemplo n.º 2
0
        async Task <IPullRequestDirectoryNode> CreateChangedFilesTree(IPullRequestModel pullRequest, TreeChanges changes)
        {
            var dirs = new Dictionary <string, PullRequestDirectoryNode>
            {
                { string.Empty, new PullRequestDirectoryNode(string.Empty) }
            };

            foreach (var changedFile in pullRequest.ChangedFiles)
            {
                var node = new PullRequestFileNode(
                    LocalRepository.LocalPath,
                    changedFile.FileName,
                    changedFile.Sha,
                    changedFile.Status,
                    GetOldFileName(changedFile, changes));

                var file = await Session.GetFile(changedFile.FileName);

                var fileCommentCount = file?.WhenAnyValue(x => x.InlineCommentThreads)
                                       .Subscribe(x => node.CommentCount = x.Count(y => y.LineNumber != -1));

                var dir = GetDirectory(node.DirectoryPath, dirs);
                dir.Files.Add(node);
            }

            return(dirs[string.Empty]);
        }
        async Task Load(IPullRequestModel pullRequest)
        {
            try
            {
                session = await sessionManager.GetSession(pullRequest);

                PullRequestModel = pullRequest;

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

                Body = Model.Body;

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

                sessionSubscription = session.PullRequestChanged.Subscribe(_ => UpdateFileComments().Forget());
            }
            finally
            {
                IsBusy = false;
            }
        }
        public IObservable <Tuple <string, string> > ExtractDiffFiles(
            ILocalRepositoryModel repository,
            IModelService modelService,
            IPullRequestModel pullRequest,
            string fileName,
            string fileSha)
        {
            return(Observable.Defer(async() =>
            {
                var repo = gitService.GetRepository(repository.LocalPath);
                var remote = await gitClient.GetHttpRemote(repo, "origin");
                await gitClient.Fetch(repo, remote.Name);

                // The left file is the target of the PR so this should already be fetched.
                var left = await gitClient.ExtractFile(repo, pullRequest.Base.Sha, fileName);

                // The right file - if it comes from a fork - may not be fetched so fall back to
                // getting the file contents from the model service.
                var right = await GetFileFromRepositoryOrApi(repository, repo, modelService, pullRequest.Head.Sha, fileName, fileSha);

                if (left == null)
                {
                    throw new FileNotFoundException($"Could not retrieve {fileName}@{pullRequest.Base.Sha}");
                }

                if (right == null)
                {
                    throw new FileNotFoundException($"Could not retrieve {fileName}@{pullRequest.Head.Sha}");
                }

                return Observable.Return(Tuple.Create(left, right));
            }));
        }
Exemplo n.º 5
0
        public IObservable <Unit> Checkout(ILocalRepositoryModel repository, IPullRequestModel pullRequest, string localBranchName)
        {
            return(Observable.Defer(async() =>
            {
                var repo = gitService.GetRepository(repository.LocalPath);
                var existing = repo.Branches[localBranchName];

                if (existing != null)
                {
                    await gitClient.Checkout(repo, localBranchName);
                }
                else if (repository.CloneUrl.ToRepositoryUrl() == pullRequest.Head.RepositoryCloneUrl.ToRepositoryUrl())
                {
                    var remote = await gitClient.GetHttpRemote(repo, "origin");
                    await gitClient.Fetch(repo, remote.Name);
                    await gitClient.Checkout(repo, localBranchName);
                }
                else
                {
                    var refSpec = $"{pullRequest.Head.Ref}:{localBranchName}";
                    var remoteName = await CreateRemote(repo, pullRequest.Head.RepositoryCloneUrl);

                    await gitClient.Fetch(repo, remoteName);
                    await gitClient.Fetch(repo, remoteName, new[] { refSpec });
                    await gitClient.Checkout(repo, localBranchName);
                    await gitClient.SetTrackingBranch(repo, localBranchName, $"refs/remotes/{remoteName}/{pullRequest.Head.Ref}");
                }

                // Store the PR number in the branch config with the key "ghfvs-pr".
                var prConfigKey = $"branch.{localBranchName}.{SettingGHfVSPullRequest}";
                await gitClient.SetConfig(repo, prConfigKey, BuildGHfVSConfigKeyValue(pullRequest));

                return Observable.Return(Unit.Default);
            }));
        }
        /// <inheritdoc/>
        public IReadOnlyList <IInlineCommentThreadModel> BuildCommentThreads(
            IPullRequestModel pullRequest,
            string relativePath,
            IReadOnlyList <DiffChunk> diff)
        {
            relativePath = relativePath.Replace("\\", "/");

            var commentsByPosition = pullRequest.ReviewComments
                                     .Where(x => x.Path == relativePath && x.OriginalPosition.HasValue)
                                     .OrderBy(x => x.Id)
                                     .GroupBy(x => Tuple.Create(x.OriginalCommitId, x.OriginalPosition.Value));
            var threads = new List <IInlineCommentThreadModel>();

            foreach (var comments in commentsByPosition)
            {
                var hunk      = comments.First().DiffHunk;
                var chunks    = DiffUtilities.ParseFragment(hunk);
                var chunk     = chunks.Last();
                var diffLines = chunk.Lines.Reverse().Take(5).ToList();
                var thread    = new InlineCommentThreadModel(
                    relativePath,
                    comments.Key.Item1,
                    comments.Key.Item2,
                    diffLines,
                    comments);
                threads.Add(thread);
            }

            UpdateCommentThreads(threads, diff);
            return(threads);
        }
Exemplo n.º 7
0
        async Task <PullRequestSession> GetSessionInternal(IPullRequestModel pullRequest)
        {
            PullRequestSession session = null;
            WeakReference <PullRequestSession> weakSession;
            var key = Tuple.Create(pullRequest.Base.RepositoryCloneUrl.Owner, pullRequest.Number);

            if (sessions.TryGetValue(key, out weakSession))
            {
                weakSession.TryGetTarget(out session);
            }

            if (session == null)
            {
                var modelService = hosts.LookupHost(HostAddress.Create(repository.CloneUrl))?.ModelService;

                if (modelService != null)
                {
                    session = new PullRequestSession(
                        sessionService,
                        await modelService.GetCurrentUser(),
                        pullRequest,
                        repository,
                        key.Item1,
                        false);
                    sessions[key] = new WeakReference <PullRequestSession>(session);
                }
            }
            else
            {
                await session.Update(pullRequest);
            }

            return(session);
        }
        /// <inheritdoc/>
        async Task Load(IAccount author, IPullRequestModel pullRequest)
        {
            IsBusy = true;

            try
            {
                session = await sessionManager.GetSession(pullRequest);

                User             = author;
                PullRequestTitle = pullRequest.Title;

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

                foreach (var review in pullRequest.Reviews.OrderByDescending(x => x.SubmittedAt))
                {
                    if (review.User.Login == author.Login &&
                        review.State != PullRequestReviewState.Pending)
                    {
                        var vm = new PullRequestReviewViewModel(editorService, session, pullRequest, review);
                        vm.IsExpanded = isFirst;
                        reviews.Add(vm);
                        isFirst = false;
                    }
                }

                Reviews = reviews;
            }
            finally
            {
                IsBusy = false;
            }
        }
 static PullRequestReviewAuthoringViewModel CreateTarget(
     IPullRequestModel model,
     IPullRequestSession session = null)
 {
     return(CreateTarget(
                sessionManager: CreateSessionManager(session),
                modelServiceFactory: CreateModelServiceFactory(CreateModelService(model))));
 }
        PullRequestStatusViewModel CreatePullRequestStatusViewModel(IPullRequestModel pullRequest)
        {
            var pullRequestStatusViewModel = new PullRequestStatusViewModel(showCurrentPullRequestCommand);

            pullRequestStatusViewModel.Number = pullRequest.Number;
            pullRequestStatusViewModel.Title  = pullRequest.Title;
            return(pullRequestStatusViewModel);
        }
Exemplo n.º 11
0
 bool IEquatable <IPullRequestModel> .Equals([AllowNull] IPullRequestModel other)
 {
     if (ReferenceEquals(this, other))
     {
         return(true);
     }
     return(other != null && Number == other.Number);
 }
Exemplo n.º 12
0
        public bool IsPullRequestFromRepository(ILocalRepositoryModel repository, IPullRequestModel pullRequest)
        {
            if (pullRequest.Head?.RepositoryCloneUrl != null)
            {
                return(repository.CloneUrl?.ToRepositoryUrl() == pullRequest.Head.RepositoryCloneUrl.ToRepositoryUrl());
            }

            return(false);
        }
        public async Task Update(IPullRequestModel pullRequest)
        {
            PullRequest = pullRequest;

            foreach (var file in this.fileIndex.Values.ToList())
            {
                await UpdateFile(file);
            }
        }
        static IModelService CreateModelService(IPullRequestModel pullRequest = null)
        {
            pullRequest = pullRequest ?? CreatePullRequest();

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

            result.GetPullRequest(null, null, 0).ReturnsForAnyArgs(Observable.Return(pullRequest));
            return(result);
        }
Exemplo n.º 15
0
        PullRequestStatusViewModel CreatePullRequestStatusViewModel(IPullRequestModel pullRequest)
        {
            var dte     = serviceProvider.TryGetService <EnvDTE.DTE>();
            var command = new RaisePullRequestCommand(dte, usageTracker);
            var pullRequestStatusViewModel = new PullRequestStatusViewModel(command);

            pullRequestStatusViewModel.Number = pullRequest.Number;
            pullRequestStatusViewModel.Title  = pullRequest.Title;
            return(pullRequestStatusViewModel);
        }
Exemplo n.º 16
0
        public bool IsPullRequestFromFork(ILocalRepositoryModel repository, IPullRequestModel pullRequest)
        {
            if (pullRequest.Head?.Label != null && pullRequest.Base?.Label != null)
            {
                var headOwner = pullRequest.Head.Label.Split(':')[0];
                var baseOwner = pullRequest.Base.Label.Split(':')[0];
                return(headOwner != baseOwner);
            }

            return(false);
        }
Exemplo n.º 17
0
 public void CopyFrom(IPullRequestModel other)
 {
     if (!Equals(other))
     {
         throw new ArgumentException("Instance to copy from doesn't match this instance. this:(" + this + ") other:(" + other + ")", nameof(other));
     }
     Title          = other.Title;
     UpdatedAt      = other.UpdatedAt;
     CommentCount   = other.CommentCount;
     HasNewComments = other.HasNewComments;
 }
Exemplo n.º 18
0
        /// <inheritdoc/>
        public async Task <IPullRequestSession> GetSession(IPullRequestModel pullRequest)
        {
            if (await service.EnsureLocalBranchesAreMarkedAsPullRequests(repository, pullRequest))
            {
                // The branch for the PR was not previously marked with the PR number in the git
                // config so we didn't pick up that the current branch is a PR branch. That has
                // now been corrected, so call RepoChanged to make sure everything is up-to-date.
                await RepoChanged(repository);
            }

            return(await GetSessionInternal(pullRequest));
        }
Exemplo n.º 19
0
        /// <summary>
        /// Loads the view model from octokit models.
        /// </summary>
        /// <param name="pullRequest">The pull request model.</param>
        /// <param name="files">The pull request's changed files.</param>
        public async Task Load(IPullRequestModel pullRequest)
        {
            Model = pullRequest;
            Title = Resources.PullRequestNavigationItemText + " #" + pullRequest.Number;
            SourceBranchDisplayName = GetBranchDisplayName(pullRequest.Head?.Label);
            TargetBranchDisplayName = GetBranchDisplayName(pullRequest.Base.Label);
            Body = !string.IsNullOrWhiteSpace(pullRequest.Body) ? pullRequest.Body : "*No description provided.*";

            ChangedFilesTree.Clear();
            ChangedFilesList.Clear();

            // WPF doesn't support AddRange here so iterate through the changes.
            foreach (var change in CreateChangedFilesList(pullRequest.ChangedFiles))
            {
                ChangedFilesList.Add(change);
            }

            foreach (var change in CreateChangedFilesTree(ChangedFilesList).Children)
            {
                ChangedFilesTree.Add(change);
            }

            var localBranches = await pullRequestsService.GetLocalBranches(repository, pullRequest).ToList();

            var isCheckedOut = localBranches.Contains(repository.CurrentBranch);

            if (isCheckedOut)
            {
                var divergence = await pullRequestsService.CalculateHistoryDivergence(repository, Model.Number);

                var pullDisabled = divergence.BehindBy == 0 ? "No commits to pull" : null;
                var pushDisabled = divergence.AheadBy == 0 ?
                                   "No commits to push" :
                                   divergence.BehindBy > 0 ? "You must pull before you can push" : null;

                UpdateState   = new UpdateCommandState(divergence, pullDisabled, pushDisabled);
                CheckoutState = null;
            }
            else
            {
                var caption = localBranches.Count > 0 ?
                              "Checkout " + localBranches.First().DisplayName :
                              "Checkout to " + (await pullRequestsService.GetDefaultLocalBranchName(repository, Model.Number, Model.Title));
                var disabled = await pullRequestsService.IsWorkingDirectoryClean(repository) ?
                               null :
                               "Cannot checkout as your working directory has uncommitted changes.";

                CheckoutState = new CheckoutCommandState(caption, disabled);
                UpdateState   = null;
            }

            IsBusy = false;
        }
Exemplo n.º 20
0
        public async Task Update(IPullRequestModel pullRequest)
        {
            PullRequest = pullRequest;
            mergeBase   = null;

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

            pullRequestChanged.OnNext(pullRequest);
        }
Exemplo n.º 21
0
 public async Task <string> GetMergeBase(ILocalRepositoryModel repository, IPullRequestModel pullRequest)
 {
     using (var repo = gitService.GetRepository(repository.LocalPath))
     {
         return(await gitClient.GetPullRequestMergeBase(
                    repo,
                    pullRequest.Base.RepositoryCloneUrl,
                    pullRequest.Base.Sha,
                    pullRequest.Head.Sha,
                    pullRequest.Base.Ref,
                    pullRequest.Number));
     }
 }
Exemplo n.º 22
0
        /// <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);
        }
Exemplo n.º 23
0
        PullRequestReviewViewModel CreateTarget(
            IPullRequestEditorService editorService = null,
            IPullRequestSession session             = null,
            IPullRequestModel pullRequest           = null,
            IPullRequestReviewModel 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,
                       pullRequest,
                       model));
        }
Exemplo n.º 24
0
        IModelServiceFactory CreateModelServiceFactory(IPullRequestModel pullRequest = null)
        {
            var modelService = Substitute.For <IModelService>();

            modelService.GetPullRequest(null, null, 0).ReturnsForAnyArgs(x =>
            {
                var cloneUrl = $"https://github.com/{x.ArgAt<string>(0)}/{x.ArgAt<string>(1)}";
                var pr       = pullRequest ?? CreatePullRequestModel(x.ArgAt <int>(2), cloneUrl);
                return(Observable.Return(pr));
            });

            var factory = Substitute.For <IModelServiceFactory>();

            factory.CreateAsync(null).ReturnsForAnyArgs(modelService);
            factory.CreateBlocking(null).ReturnsForAnyArgs(modelService);
            return(factory);
        }
Exemplo n.º 25
0
 IEnumerable <string> GetLocalBranchesInternal(
     ILocalRepositoryModel localRepository,
     IRepository repository,
     IPullRequestModel pullRequest)
 {
     if (!IsPullRequestFromFork(localRepository, pullRequest))
     {
         return(new[] { pullRequest.Head.Ref });
     }
     else
     {
         var pr = pullRequest.Number.ToString(CultureInfo.InvariantCulture);
         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 == pr)
                .Select(x => x.Branch));
     }
 }
Exemplo n.º 26
0
        public PullRequestSession(
            IPullRequestSessionService service,
            IAccount user,
            IPullRequestModel pullRequest,
            ILocalRepositoryModel repository,
            bool isCheckedOut)
        {
            Guard.ArgumentNotNull(service, nameof(service));
            Guard.ArgumentNotNull(user, nameof(user));
            Guard.ArgumentNotNull(pullRequest, nameof(pullRequest));
            Guard.ArgumentNotNull(repository, nameof(repository));

            this.service      = service;
            this.isCheckedOut = isCheckedOut;
            User        = user;
            PullRequest = pullRequest;
            Repository  = repository;
        }
Exemplo n.º 27
0
        /// <summary>
        /// Initializes a new instance of the <see cref="PullRequestReviewViewModel"/> class.
        /// </summary>
        /// <param name="editorService">The pull request editor service.</param>
        /// <param name="session">The pull request session.</param>
        /// <param name="pullRequest">The pull request model.</param>
        /// <param name="model">The pull request review model.</param>
        public PullRequestReviewViewModel(
            IPullRequestEditorService editorService,
            IPullRequestSession session,
            IPullRequestModel pullRequest,
            IPullRequestReviewModel model)
        {
            Guard.ArgumentNotNull(editorService, nameof(editorService));
            Guard.ArgumentNotNull(session, nameof(session));
            Guard.ArgumentNotNull(model, nameof(model));

            Model        = model;
            Body         = string.IsNullOrWhiteSpace(Model.Body) ? null : Model.Body;
            StateDisplay = ToString(Model.State);

            var comments = new List <IPullRequestReviewFileCommentViewModel>();
            var outdated = new List <IPullRequestReviewFileCommentViewModel>();

            foreach (var comment in pullRequest.ReviewComments)
            {
                if (comment.PullRequestReviewId == model.Id)
                {
                    var vm = new PullRequestReviewFileCommentViewModel(
                        editorService,
                        session,
                        comment);

                    if (comment.Position.HasValue)
                    {
                        comments.Add(vm);
                    }
                    else
                    {
                        outdated.Add(vm);
                    }
                }
            }

            FileComments         = comments;
            OutdatedFileComments = outdated;

            HasDetails = Body != null ||
                         FileComments.Count > 0 ||
                         OutdatedFileComments.Count > 0;
        }
Exemplo n.º 28
0
        IEnumerable <string> GetLocalBranchesInternal(
            ILocalRepositoryModel localRepository,
            IRepository repository,
            IPullRequestModel pullRequest)
        {
            if (IsPullRequestFromRepository(localRepository, pullRequest))
            {
                return(new[] { pullRequest.Head.Ref });
            }
            else
            {
                var key = BuildGHfVSConfigKeyValue(pullRequest);

                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));
            }
        }
        IRepositoryHosts CreateRepositoryHosts(IPullRequestModel pullRequest = null)
        {
            var modelService = Substitute.For <IModelService>();

            modelService.GetPullRequest(null, null, 0).ReturnsForAnyArgs(x =>
            {
                var cloneUrl = $"https://github.com/{x.ArgAt<string>(0)}/{x.ArgAt<string>(1)}";
                var pr       = pullRequest ?? CreatePullRequestModel(x.ArgAt <int>(2), cloneUrl);
                return(Observable.Return(pr));
            });

            var repositoryHost = Substitute.For <IRepositoryHost>();

            repositoryHost.ModelService.Returns(modelService);

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

            result.LookupHost(null).ReturnsForAnyArgs(repositoryHost);
            return(result);
        }
Exemplo n.º 30
0
        public async Task <string> ExtractToTempFile(
            ILocalRepositoryModel repository,
            IPullRequestModel 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);
        }
Exemplo n.º 31
0
        public IObservable<Unit> SwitchToBranch(ILocalRepositoryModel repository, IPullRequestModel pullRequest)
        {
            return Observable.Defer(async () =>
            {
                var repo = gitService.GetRepository(repository.LocalPath);
                var branchName = GetLocalBranchesInternal(repository, repo, pullRequest).FirstOrDefault();

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

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

                    var branch = repo.Branches[branchName];

                    if (branch == null)
                    {
                        var trackedBranchName = $"refs/remotes/origin/" + 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);
                }

                return Observable.Empty<Unit>();
            });
        }
 IEnumerable<IPullRequestFileNode> CreateChangedFilesList(IPullRequestModel pullRequest, TreeChanges changes)
 {
     return pullRequest.ChangedFiles
         .Select(x => new PullRequestFileNode(repository.LocalPath, x.FileName, x.Sha, x.Status, GetStatusDisplay(x, changes)));
 }
Exemplo n.º 33
0
 public IObservable<TreeChanges> GetTreeChanges(ILocalRepositoryModel repository, IPullRequestModel pullRequest)
 {
     return Observable.Defer(async () =>
     {
         var repo = gitService.GetRepository(repository.LocalPath);
         await gitClient.Fetch(repo, "origin");
         var changes = await gitClient.Compare(repo, pullRequest.Base.Sha, pullRequest.Head.Sha, detectRenames: true);
         return Observable.Return(changes);
     });
 }
Exemplo n.º 34
0
        public IObservable<Tuple<string, string>> ExtractDiffFiles(
            ILocalRepositoryModel repository,
            IModelService modelService,
            IPullRequestModel pullRequest,
            string fileName,
            string fileSha)
        {
            return Observable.Defer(async () =>
            {
                var repo = gitService.GetRepository(repository.LocalPath);
                await gitClient.Fetch(repo, "origin");

                // The left file is the target of the PR so this should already be fetched.
                var left = await gitClient.ExtractFile(repo, pullRequest.Base.Sha, fileName);

                // The right file - if it comes from a fork - may not be fetched so fall back to
                // getting the file contents from the model service.
                var right = await GetFileFromRepositoryOrApi(repository, repo, modelService, pullRequest.Head.Sha, fileName, fileSha);

                if (left == null)
                {
                    throw new FileNotFoundException($"Could not retrieve {fileName}@{pullRequest.Base.Sha}");
                }

                if (right == null)
                {
                    throw new FileNotFoundException($"Could not retrieve {fileName}@{pullRequest.Head.Sha}");
                }

                return Observable.Return(Tuple.Create(left, right));
            });
        }
        /// <summary>
        /// Loads the view model from octokit models.
        /// </summary>
        /// <param name="pullRequest">The pull request model.</param>
        /// <param name="files">The pull request's changed files.</param>
        public async Task Load(IPullRequestModel pullRequest)
        {
            Model = pullRequest;
            Title = Resources.PullRequestNavigationItemText + " #" + pullRequest.Number;
            SourceBranchDisplayName = GetBranchDisplayName(pullRequest.Head?.Label);
            TargetBranchDisplayName = GetBranchDisplayName(pullRequest.Base.Label);
            Body = !string.IsNullOrWhiteSpace(pullRequest.Body) ? pullRequest.Body : "*No description provided.*";

            ChangedFilesTree.Clear();
            ChangedFilesList.Clear();

            // WPF doesn't support AddRange here so iterate through the changes.
            foreach (var change in CreateChangedFilesList(pullRequest.ChangedFiles))
            {
                ChangedFilesList.Add(change);
            }

            foreach (var change in CreateChangedFilesTree(ChangedFilesList).Children)
            {
                ChangedFilesTree.Add(change);
            }

            var localBranches = await pullRequestsService.GetLocalBranches(repository, pullRequest).ToList();
            var isCheckedOut = localBranches.Contains(repository.CurrentBranch);

            if (isCheckedOut)
            {
                var divergence = await pullRequestsService.CalculateHistoryDivergence(repository, Model.Number);
                var pullDisabled = divergence.BehindBy == 0 ? "No commits to pull" : null;
                var pushDisabled = divergence.AheadBy == 0 ? 
                    "No commits to push" : 
                    divergence.BehindBy > 0 ? "You must pull before you can push" : null;

                UpdateState = new UpdateCommandState(divergence, pullDisabled, pushDisabled);
                CheckoutState = null;
            }
            else
            {
                var caption = localBranches.Count > 0 ?
                    "Checkout " + localBranches.First().DisplayName :
                    "Checkout to " + (await pullRequestsService.GetDefaultLocalBranchName(repository, Model.Number, Model.Title));
                var disabled = await pullRequestsService.IsWorkingDirectoryClean(repository) ?
                    null :
                    "Cannot checkout as your working directory has uncommitted changes.";

                CheckoutState = new CheckoutCommandState(caption, disabled);
                UpdateState = null;
            }

            IsBusy = false;

            pullRequestsService.RemoteUnusedRemotes(repository).Subscribe(_ => { });
        }
Exemplo n.º 36
0
        public IObservable<Unit> Checkout(ILocalRepositoryModel repository, IPullRequestModel pullRequest, string localBranchName)
        {
            return Observable.Defer(async () =>
            {
                var repo = gitService.GetRepository(repository.LocalPath);
                var existing = repo.Branches[localBranchName];

                if (existing != null)
                {
                    await gitClient.Checkout(repo, localBranchName);
                }
                else if (repository.CloneUrl.ToRepositoryUrl() == pullRequest.Head.RepositoryCloneUrl.ToRepositoryUrl())
                {
                    await gitClient.Fetch(repo, "origin");
                    await gitClient.Checkout(repo, localBranchName);
                }
                else
                {
                    var refSpec = $"{pullRequest.Head.Ref}:{localBranchName}";
                    var prConfigKey = $"branch.{localBranchName}.{SettingGHfVSPullRequest}";
                    var remoteName = await CreateRemote(repo, pullRequest.Head.RepositoryCloneUrl);

                    await gitClient.Fetch(repo, remoteName);
                    await gitClient.Fetch(repo, remoteName, new[] { refSpec });
                    await gitClient.Checkout(repo, localBranchName);
                    await gitClient.SetTrackingBranch(repo, localBranchName, $"refs/remotes/{remoteName}/{pullRequest.Head.Ref}");
                    await gitClient.SetConfig(repo, prConfigKey, pullRequest.Number.ToString());
                }

                return Observable.Return(Unit.Default);
            });
        }
Exemplo n.º 37
0
 public IObservable<IBranch> GetLocalBranches(ILocalRepositoryModel repository, IPullRequestModel pullRequest)
 {
     return Observable.Defer(() =>
     {
         var repo = gitService.GetRepository(repository.LocalPath);
         var result = GetLocalBranchesInternal(repository, repo, pullRequest).Select(x => new BranchModel(x, repository));
         return result.ToObservable();
     });
 }
Exemplo n.º 38
0
 public bool IsPullRequestFromFork(ILocalRepositoryModel repository, IPullRequestModel pullRequest)
 {
     return pullRequest.Head.RepositoryCloneUrl?.ToRepositoryUrl() != repository.CloneUrl.ToRepositoryUrl();
 }
Exemplo n.º 39
0
 public IObservable<Tuple<string, string>> ExtractDiffFiles(ILocalRepositoryModel repository, IPullRequestModel pullRequest, string fileName)
 {
     return Observable.Defer(async () =>
     {
         var repo = gitService.GetRepository(repository.LocalPath);
         await gitClient.Fetch(repo, "origin");
         var left = await gitClient.ExtractFile(repo, pullRequest.Base.Sha, fileName);
         var right = await gitClient.ExtractFile(repo, pullRequest.Head.Sha, fileName);
         return Observable.Return(Tuple.Create(left, right));
     });
 }
Exemplo n.º 40
0
 IEnumerable<string> GetLocalBranchesInternal(
     ILocalRepositoryModel localRepository,
     IRepository repository,
     IPullRequestModel pullRequest)
 {
     if (!IsPullRequestFromFork(localRepository, pullRequest))
     {
         return new[] { pullRequest.Head.Ref };
     }
     else
     {
         var pr = pullRequest.Number.ToString(CultureInfo.InvariantCulture);
         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 == pr)
             .Select(x => x.Branch);
     }
 }