Exemple #1
0
 static void SetRepository(IRepositoryCloneTabViewModel vm, IRepositoryModel repository)
 {
     vm.Repository.Returns(repository);
     vm.PropertyChanged += Raise.Event <PropertyChangedEventHandler>(
         vm,
         new PropertyChangedEventArgs(nameof(vm.Repository)));
 }
Exemple #2
0
        public IObservable <Unit> SwitchRemotes(IRepositoryModel destinationRepository, bool updateOrigin, bool addUpstream, bool trackMasterUpstream)
        {
            return(Observable.Defer(() => Observable.Return(new object())
                                    .ObserveOn(RxApp.MainThreadScheduler)
                                    .Select(_ => vsGitServices.GetActiveRepo()))
                   .SelectMany(async activeRepo =>
            {
                using (activeRepo)
                {
                    Uri currentOrigin = null;

                    if (addUpstream)
                    {
                        var remote = await gitClient.GetHttpRemote(activeRepo, "origin");
                        currentOrigin = new Uri(remote.Url);
                    }

                    await SwitchRemotes(activeRepo, updateOrigin ? destinationRepository.CloneUrl.ToUri() : null,
                                        currentOrigin, trackMasterUpstream);
                }

                if (updateOrigin)
                {
                    vsGitExt.RefreshActiveRepositories();

                    var updatedRepository = vsGitExt.ActiveRepositories.FirstOrDefault();
                    log.Assert(updatedRepository?.CloneUrl == destinationRepository.CloneUrl,
                               "CloneUrl is {UpdatedRepository} not {DestinationRepository}", updatedRepository?.CloneUrl ?? "[NULL]", destinationRepository.CloneUrl);
                }

                return Unit.Default;
            }));
        }
        public async Task LoadsRepositories()
        {
            var repos = new IRepositoryModel[]
            {
                Substitute.For <IRepositoryModel>(),
                Substitute.For <IRepositoryModel>(),
                Substitute.For <IRepositoryModel>()
            };
            var col            = TrackingCollection.Create(repos.ToObservable());
            var repositoryHost = Substitute.For <IRepositoryHost>();

            repositoryHost.ModelService.GetRepositories(Arg.Any <ITrackingCollection <IRepositoryModel> >()).Returns(_ => col);

            var cloneService = Substitute.For <IRepositoryCloneService>();
            var vm           = GetVM(
                repositoryHost,
                cloneService,
                Substitute.For <IOperatingSystem>(),
                Substitute.For <INotificationService>(),
                Substitute.For <IUsageTracker>());

            await col.OriginalCompleted;

            Assert.Equal(3, vm.Repositories.Count);
        }
Exemple #4
0
        public Task <string> ShowReCloneDialog(IRepositoryModel repository)
        {
            Guard.ArgumentNotNull(repository, nameof(repository));

            var controller = uiProvider.Configure(UIControllerFlow.ReClone);
            var basePath   = default(string);

            controller.TransitionSignal.Subscribe(x =>
            {
                var vm = x.View.ViewModel as IBaseCloneViewModel;

                if (vm != null)
                {
                    vm.SelectedRepository = repository;
                }

                vm.Done.Subscribe(_ =>
                {
                    basePath = vm?.BaseRepositoryPath;
                });
            });

            uiProvider.RunInDialog(controller);

            return(Task.FromResult(basePath));
        }
Exemple #5
0
        public IObservable <Repository> ForkRepository(IApiClient apiClient, IRepositoryModel sourceRepository, NewRepositoryFork repositoryFork, bool updateOrigin, bool addUpstream, bool trackMasterUpstream)
        {
            log.Verbose("ForkRepository Source:{SourceOwner}/{SourceName} To:{DestinationOwner}", sourceRepository.Owner, sourceRepository.Name, repositoryFork.Organization ?? "[Current User]");
            log.Verbose("ForkRepository updateOrigin:{UpdateOrigin} addUpstream:{AddUpstream} trackMasterUpstream:{TrackMasterUpstream}", updateOrigin, addUpstream, trackMasterUpstream);

            usageTracker.IncrementCounter(model => model.NumberOfReposForked).Forget();

            return(Observable.Defer(() => apiClient.ForkRepository(sourceRepository.Owner, sourceRepository.Name, repositoryFork)
                                    .ObserveOn(RxApp.MainThreadScheduler)
                                    .Select(remoteRepo => new { RemoteRepo = remoteRepo, ActiveRepo = updateOrigin ? vsGitServices.GetActiveRepo() : null }))
                   .SelectMany(async repo =>
            {
                if (repo.ActiveRepo != null)
                {
                    using (repo.ActiveRepo)
                    {
                        var originUri = repo.RemoteRepo != null ? new Uri(repo.RemoteRepo.CloneUrl) : null;
                        var upstreamUri = addUpstream ? sourceRepository.CloneUrl.ToUri() : null;

                        await SwitchRemotes(repo.ActiveRepo, originUri, upstreamUri, trackMasterUpstream);
                    }
                }

                return repo.RemoteRepo;
            }));
        }
Exemple #6
0
 public bool Equals([AllowNull] IRepositoryModel other)
 {
     if (ReferenceEquals(this, other))
     {
         return(true);
     }
     return(other != null && Id == other.Id);
 }
Exemple #7
0
 public void CopyFrom(IRepositoryModel other)
 {
     if (!Equals(other))
     {
         throw new ArgumentException("Instance to copy from doesn't match this instance. this:(" + this + ") other:(" + other + ")", nameof(other));
     }
     Icon = other.Icon;
 }
Exemple #8
0
        public BranchModel(Octokit.Branch branch, IRepositoryModel repo)
        {
            Extensions.Guard.ArgumentNotNull(branch, nameof(branch));
            Extensions.Guard.ArgumentNotNull(repo, nameof(repo));

            Name       = DisplayName = branch.Name;
            Repository = repo;
            Id         = String.Format(CultureInfo.InvariantCulture, "{0}/{1}", Repository.Owner, Name);
        }
Exemple #9
0
        public BranchModel(string name, IRepositoryModel repo)
        {
            Extensions.Guard.ArgumentNotEmptyString(name, nameof(name));
            Extensions.Guard.ArgumentNotNull(repo, nameof(repo));

            Name       = DisplayName = name;
            Repository = repo;
            Id         = String.Format(CultureInfo.InvariantCulture, "{0}/{1}", Repository.Owner, Name);
        }
Exemple #10
0
        public async Task <string> ShowReCloneDialog(IRepositoryModel repository)
        {
            Guard.ArgumentNotNull(repository, nameof(repository));

            var viewModel = factory.CreateViewModel <IRepositoryRecloneViewModel>();

            viewModel.SelectedRepository = repository;
            return((string)await showDialog.ShowWithFirstConnection(viewModel));
        }
 public IssueCommentThreadViewModel(
     IRepositoryModel repository,
     int number,
     IAccount currentUser)
     : base(currentUser)
 {
     Repository = repository;
     Number     = number;
 }
Exemple #12
0
        public IObservable <IBranch> GetBranches(IRepositoryModel repo)
        {
            var keyobs = GetUserFromCache()
                         .Select(user => string.Format(CultureInfo.InvariantCulture, "{0}|{1}|branch", user.Login, repo.Name));

            return(Observable.Defer(() => keyobs
                                    .SelectMany(key => apiClient.GetBranches(repo.CloneUrl.Owner, repo.CloneUrl.RepositoryName)))
                   .Select(x => new BranchModel(x, repo)));
        }
        public BranchModel(LibGit2Sharp.Branch branch, IRepositoryModel repo)
        {
            Extensions.Guard.ArgumentNotNull(branch, nameof(branch));
            Extensions.Guard.ArgumentNotNull(repo, nameof(repo));

            Name       = DisplayName = branch.FriendlyName;
            Repository = branch.IsRemote ? new LocalRepositoryModel(branch.Remote.Url) : repo;
            IsTracking = branch.IsTracking;
            Id         = String.Format(CultureInfo.InvariantCulture, "{0}/{1}", Repository.Owner, Name);
        }
        public static Task <IConnection> GetConnection(this IConnectionManager cm, IRepositoryModel repository)
        {
            if (repository?.CloneUrl != null)
            {
                var hostAddress = HostAddress.Create(repository.CloneUrl);
                return(cm.GetConnection(hostAddress));
            }

            return(null);
        }
Exemple #15
0
        bool FilterRepository(IRepositoryModel repo, int position, IList <IRepositoryModel> list)
        {
            if (string.IsNullOrWhiteSpace(FilterText))
            {
                return(true);
            }

            // Not matching on NameWithOwner here since that's already been filtered on by the selected account
            return(repo.Name.IndexOf(FilterText ?? "", StringComparison.OrdinalIgnoreCase) != -1);
        }
Exemple #16
0
        public BranchModel(LibGit2Sharp.Branch branch, IRepositoryModel repo)
        {
            Extensions.Guard.ArgumentNotNull(branch, nameof(branch));
            Extensions.Guard.ArgumentNotNull(repo, nameof(repo));
            Name = DisplayName = branch.FriendlyName;
#pragma warning disable 0618 // TODO: Replace `Branch.Remote` with `Repository.Network.Remotes[branch.RemoteName]`.
            Repository = branch.IsRemote ? new LocalRepositoryModel(branch.Remote.Url) : repo;
#pragma warning restore 0618
            IsTracking = branch.IsTracking;
            Id         = String.Format(CultureInfo.InvariantCulture, "{0}/{1}", Repository.Owner, Name);
        }
        /// <inheritdoc/>
        public async Task InitializeAsync(ILocalRepositoryModel repository, IConnection connection)
        {
            try
            {
                LocalRepository = repository;
                SelectedState   = States.FirstOrDefault();
                AuthorFilter    = new UserFilterViewModel(LoadAuthors);
                IsLoading       = true;

                var parent = await repositoryService.FindParent(
                    HostAddress.Create(repository.CloneUrl),
                    repository.Owner,
                    repository.Name);

                if (parent == null)
                {
                    RemoteRepository = repository;
                }
                else
                {
                    // TODO: Handle forks with different names.
                    RemoteRepository = new RepositoryModel(
                        repository.Name,
                        UriString.ToUriString(repository.CloneUrl.ToRepositoryUrl(parent.Value.owner)));

                    Forks = new IRepositoryModel[]
                    {
                        RemoteRepository,
                        repository,
                    };
                }

                this.WhenAnyValue(x => x.SelectedState, x => x.RemoteRepository)
                .Skip(1)
                .Subscribe(_ => Refresh().Forget());

                Observable.Merge(
                    this.WhenAnyValue(x => x.SearchQuery).Skip(1).SelectUnit(),
                    AuthorFilter.WhenAnyValue(x => x.Selected).Skip(1).SelectUnit())
                .Subscribe(_ => FilterChanged());

                await Refresh();
            }
            catch (Exception ex)
            {
                Error     = ex;
                IsLoading = false;
                log.Error(ex, "Error initializing IssueListViewModelBase");
            }
        }
        public IObservable<IPullRequestModel> CreatePullRequest(IRepositoryHost host,
            ILocalRepositoryModel sourceRepository, IRepositoryModel targetRepository,
            IBranch sourceBranch, IBranch targetBranch,
            string title, string body
        )
        {
            Extensions.Guard.ArgumentNotNull(host, nameof(host));
            Extensions.Guard.ArgumentNotNull(sourceRepository, nameof(sourceRepository));
            Extensions.Guard.ArgumentNotNull(targetRepository, nameof(targetRepository));
            Extensions.Guard.ArgumentNotNull(sourceBranch, nameof(sourceBranch));
            Extensions.Guard.ArgumentNotNull(targetBranch, nameof(targetBranch));
            Extensions.Guard.ArgumentNotNull(title, nameof(title));
            Extensions.Guard.ArgumentNotNull(body, nameof(body));

            return PushAndCreatePR(host, sourceRepository, targetRepository, sourceBranch, targetBranch, title, body).ToObservable();
        }
        async Task <CloneDialogResult> ShowCloneDialog(
            IGitHubServiceProvider gitHubServiceProvider,
            IProgress <ServiceProgressData> progress,
            IRepositoryModel repository = null)
        {
            var dialogService        = gitHubServiceProvider.GetService <IDialogService>();
            var cloneService         = gitHubServiceProvider.GetService <IRepositoryCloneService>();
            var usageTracker         = gitHubServiceProvider.GetService <IUsageTracker>();
            CloneDialogResult result = null;

            if (repository == null)
            {
                result = await dialogService.ShowCloneDialog(null);
            }
            else
            {
                var basePath = await dialogService.ShowReCloneDialog(repository);

                if (basePath != null)
                {
                    result = new CloneDialogResult(basePath, repository);
                }
            }

            if (result != null)
            {
                try
                {
                    await cloneService.CloneRepository(
                        result.Repository.CloneUrl,
                        result.Repository.Name,
                        result.Path,
                        progress);

                    usageTracker.IncrementCounter(x => x.NumberOfStartPageClones).Forget();
                }
                catch
                {
                    var teServices = gitHubServiceProvider.TryGetService <ITeamExplorerServices>();
                    teServices.ShowError($"Failed to clone the repository '{result.Repository.Name}'");
                    result = null;
                }
            }

            return(result);
        }
Exemple #20
0
        public IObservable <string> GetFileContents(IRepositoryModel repo, string commitSha, string path, string fileSha)
        {
            return(Observable.Defer(() => Task.Run(async() =>
            {
                // Store cached file contents a the temp directory so they can be deleted by disk cleanup etc.
                var tempDir = Path.Combine(Path.GetTempPath(), TempFilesDirectory, CachedFilesDirectory, fileSha.Substring(0, 2));
                var tempFile = Path.Combine(tempDir, Path.GetFileNameWithoutExtension(path) + '@' + fileSha + Path.GetExtension(path));

                if (!File.Exists(tempFile))
                {
                    var contents = await ApiClient.GetFileContents(repo.Owner, repo.Name, commitSha, path);
                    Directory.CreateDirectory(tempDir);
                    File.WriteAllBytes(tempFile, Convert.FromBase64String(contents.EncodedContent));
                }

                return Observable.Return(tempFile);
            })));
        }
        public async Task LoadsRepositories()
        {
            var repos = new IRepositoryModel[]
            {
                Substitute.For<IRepositoryModel>(),
                Substitute.For<IRepositoryModel>(),
                Substitute.For<IRepositoryModel>()
            };
            var repositoryHost = Substitute.For<IRepositoryHost>();
            repositoryHost.ModelService.GetRepositories().Returns(Observable.Return(repos));
            var cloneService = Substitute.For<IRepositoryCloneService>();
            var vm = new RepositoryCloneViewModel(
                repositoryHost,
                cloneService,
                Substitute.For<IOperatingSystem>(),
                Substitute.For<IVSServices>());

            await vm.LoadRepositoriesCommand.ExecuteAsync();

            Assert.Equal(3, vm.FilteredRepositories.Count);
        }
        public async Task LoadsRepositories()
        {
            var repos = new IRepositoryModel[]
            {
                Substitute.For <IRepositoryModel>(),
                Substitute.For <IRepositoryModel>(),
                Substitute.For <IRepositoryModel>()
            };
            var repositoryHost = Substitute.For <IRepositoryHost>();

            repositoryHost.ModelService.GetRepositories().Returns(Observable.Return(repos));
            var cloneService = Substitute.For <IRepositoryCloneService>();
            var vm           = new RepositoryCloneViewModel(
                repositoryHost,
                cloneService,
                Substitute.For <IOperatingSystem>(),
                Substitute.For <IVSServices>());

            await vm.LoadRepositoriesCommand.ExecuteAsync();

            Assert.Equal(3, vm.FilteredRepositories.Count);
        }
Exemple #23
0
        /// <summary>
        /// Gets a collection of Pull Requests. If you want to refresh existing data, pass a collection in
        /// </summary>
        /// <param name="repo"></param>
        /// <param name="collection"></param>
        /// <returns></returns>
        public ITrackingCollection <IPullRequestModel> GetPullRequests(IRepositoryModel repo,
                                                                       ITrackingCollection <IPullRequestModel> collection)
        {
            // Since the api to list pull requests returns all the data for each pr, cache each pr in its own entry
            // and also cache an index that contains all the keys for each pr. This way we can fetch prs in bulk
            // but also individually without duplicating information. We store things in a custom observable collection
            // that checks whether an item is being updated (coming from the live stream after being retrieved from cache)
            // and replaces it instead of appending, so items get refreshed in-place as they come in.

            var keyobs = GetUserFromCache()
                         .Select(user => string.Format(CultureInfo.InvariantCulture, "{0}|{1}:{2}", CacheIndex.PRPrefix, repo.Owner, repo.Name));

            var source = Observable.Defer(() => keyobs
                                          .SelectMany(key =>
                                                      hostCache.GetAndFetchLatestFromIndex(key, () =>
                                                                                           ApiClient.GetPullRequestsForRepository(repo.CloneUrl.Owner, repo.CloneUrl.RepositoryName)
                                                                                           .Select(PullRequestCacheItem.Create),
                                                                                           item =>
            {
                if (collection.Disposed)
                {
                    return;
                }

                // this could blow up due to the collection being disposed somewhere else
                try { collection.RemoveItem(Create(item)); }
                catch (ObjectDisposedException) { }
            },
                                                                                           TimeSpan.Zero,
                                                                                           TimeSpan.FromDays(7))
                                                      )
                                          .Select(Create)
                                          );

            collection.Listen(source);
            return(collection);
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="CloneDialogResult"/> class.
 /// </summary>
 /// <param name="basePath">The selected base path for the clone.</param>
 /// <param name="repository">The selected repository.</param>
 public CloneDialogResult(string basePath, IRepositoryModel repository)
 {
     BasePath   = basePath;
     Repository = repository;
 }
        async Task <CodeContainer> RunAcquisition(IProgress <ServiceProgressData> downloadProgress, CancellationToken cancellationToken, IRepositoryModel repository)
        {
            CloneDialogResult request = null;

            try
            {
                var uiProvider = await Task.Run(() => Package.GetGlobalService(typeof(IGitHubServiceProvider)) as IGitHubServiceProvider);
                await ShowTeamExplorerPage(uiProvider);

                request = await ShowCloneDialog(uiProvider, downloadProgress, repository);
            }
            catch (Exception e)
            {
                log.Error(e, "Error showing Start Page clone dialog");
            }

            if (request == null)
            {
                return(null);
            }

            var uri = request.Repository.CloneUrl.ToRepositoryUrl();

            return(new CodeContainer(
                       localProperties: new CodeContainerLocalProperties(request.Path, CodeContainerType.Folder,
                                                                         new CodeContainerSourceControlProperties(request.Repository.Name, request.Path, new Guid(Guids.GitSccProviderId))),
                       remote: new RemoteCodeContainer(request.Repository.Name,
                                                       new Guid(Guids.CodeContainerProviderId),
                                                       uri,
                                                       new Uri(uri.ToString().TrimSuffix(".git")),
                                                       DateTimeOffset.UtcNow),
                       isFavorite: false,
                       lastAccessed: DateTimeOffset.UtcNow));
        }
Exemple #26
0
        public IObservable<IBranch> GetBranches(IRepositoryModel repo)
        {
            var keyobs = GetUserFromCache()
                .Select(user => string.Format(CultureInfo.InvariantCulture, "{0}|{1}|branch", user.Login, repo.Name));

            return Observable.Defer(() => keyobs
                    .SelectMany(key => apiClient.GetBranches(repo.CloneUrl.Owner, repo.CloneUrl.RepositoryName)))
                .Select(x => new BranchModel(x, repo));
        }
 public static IObservable <IPullRequestModel> GetPullRequest(this IModelService service, IRepositoryModel repo, int number)
 {
     return(service.GetPullRequest(repo.Owner, repo.Name, number));
 }
Exemple #28
0
        public IObservable <IPullRequestModel> CreatePullRequest(ILocalRepositoryModel sourceRepository, IRepositoryModel targetRepository,
                                                                 IBranch sourceBranch, IBranch targetBranch,
                                                                 string title, string body)
        {
            var keyobs = GetUserFromCache()
                         .Select(user => string.Format(CultureInfo.InvariantCulture, "{0}|{1}:{2}", CacheIndex.PRPrefix, targetRepository.Owner, targetRepository.Name));

            return(Observable.Defer(() => keyobs
                                    .SelectMany(key =>
                                                hostCache.PutAndUpdateIndex(key, () =>
                                                                            apiClient.CreatePullRequest(
                                                                                new NewPullRequest(title,
                                                                                                   string.Format(CultureInfo.InvariantCulture, "{0}:{1}", sourceRepository.Owner, sourceBranch.Name),
                                                                                                   targetBranch.Name)
            {
                Body = body
            },
                                                                                targetRepository.Owner,
                                                                                targetRepository.Name)
                                                                            .Select(PullRequestCacheItem.Create)
                                                                            ,
                                                                            TimeSpan.FromMinutes(30))
                                                )
                                    .Select(Create)
                                    ));
        }
 public EmployeesController(IRepositoryModel irm, ILogger <EmployeesController> ilg)
 {
     _irepositoryModel = irm;
     _Logging          = ilg;
 }
 public ProductCategoriesController(IRepositoryModel irm)
 {
     _irepositoryModel = irm;
 }
Exemple #31
0
        public IObservable <IPullRequestModel> CreatePullRequest(IModelService modelService,
                                                                 ILocalRepositoryModel sourceRepository, IRepositoryModel targetRepository,
                                                                 IBranch sourceBranch, IBranch targetBranch,
                                                                 string title, string body
                                                                 )
        {
            Extensions.Guard.ArgumentNotNull(modelService, nameof(modelService));
            Extensions.Guard.ArgumentNotNull(sourceRepository, nameof(sourceRepository));
            Extensions.Guard.ArgumentNotNull(targetRepository, nameof(targetRepository));
            Extensions.Guard.ArgumentNotNull(sourceBranch, nameof(sourceBranch));
            Extensions.Guard.ArgumentNotNull(targetBranch, nameof(targetBranch));
            Extensions.Guard.ArgumentNotNull(title, nameof(title));
            Extensions.Guard.ArgumentNotNull(body, nameof(body));

            return(PushAndCreatePR(modelService, sourceRepository, targetRepository, sourceBranch, targetBranch, title, body).ToObservable());
        }
Exemple #32
0
 public CRUDController(IRepositoryModel irm)
 {
     _irepositoryModel = irm;
 }
        bool FilterRepository(IRepositoryModel repo)
        {
            if (string.IsNullOrWhiteSpace(FilterText))
                return true;

            // Not matching on NameWithOwner here since that's already been filtered on by the selected account
            return repo.Name.IndexOf(FilterText ?? "", StringComparison.OrdinalIgnoreCase) != -1;
        }
Exemple #34
0
        public IObservable<IPullRequestModel> CreatePullRequest(ILocalRepositoryModel sourceRepository, IRepositoryModel targetRepository,
            IBranch sourceBranch, IBranch targetBranch,
            string title, string body)
        {
            var keyobs = GetUserFromCache()
                .Select(user => string.Format(CultureInfo.InvariantCulture, "{0}|{1}:{2}", CacheIndex.PRPrefix, targetRepository.Owner, targetRepository.Name));

            return Observable.Defer(() => keyobs
                .SelectMany(key =>
                    hostCache.PutAndUpdateIndex(key, () =>
                        apiClient.CreatePullRequest(
                                new NewPullRequest(title,
                                                   string.Format(CultureInfo.InvariantCulture, "{0}:{1}", sourceRepository.Owner, sourceBranch.Name),
                                                   targetBranch.Name)
                                                   { Body = body },
                                targetRepository.Owner,
                                targetRepository.Name)
                            .Select(PullRequestCacheItem.Create)
                        ,
                        TimeSpan.FromMinutes(30))
                )
                .Select(Create)
            );
        }
Exemple #35
0
        public IObservable<string> GetFileContents(IRepositoryModel repo, string commitSha, string path, string fileSha)
        {
            return Observable.Defer(() => Task.Run(async () =>
            {
                // Store cached file contents a the temp directory so they can be deleted by disk cleanup etc.
                var tempDir = Path.Combine(Path.GetTempPath(), TempFilesDirectory, CachedFilesDirectory, fileSha.Substring(0, 2));
                var tempFile = Path.Combine(tempDir, Path.GetFileNameWithoutExtension(path) + '@' + fileSha + Path.GetExtension(path));

                if (!File.Exists(tempFile))
                {
                    var contents = await apiClient.GetFileContents(repo.Owner, repo.Name, commitSha, path);
                    Directory.CreateDirectory(tempDir);
                    File.WriteAllBytes(tempFile, Convert.FromBase64String(contents.EncodedContent));
                }

                return Observable.Return(tempFile);
            }));
        }
Exemple #36
0
        async Task <IPullRequestModel> PushAndCreatePR(IModelService modelService,
                                                       ILocalRepositoryModel sourceRepository, IRepositoryModel targetRepository,
                                                       IBranch sourceBranch, IBranch targetBranch,
                                                       string title, string body)
        {
            // PullRequestModel doesn't keep a reference to repo
            using (var repo = await Task.Run(() => gitService.GetRepository(sourceRepository.LocalPath)))
            {
                var remote = await gitClient.GetHttpRemote(repo, "origin");

                await gitClient.Push(repo, sourceBranch.Name, remote.Name);

                if (!repo.Branches[sourceBranch.Name].IsTracking)
                {
                    await gitClient.SetTrackingBranch(repo, sourceBranch.Name, remote.Name);
                }

                // delay things a bit to avoid a race between pushing a new branch and creating a PR on it
                if (!Splat.ModeDetector.Current.InUnitTestRunner().GetValueOrDefault())
                {
                    await Task.Delay(TimeSpan.FromSeconds(5));
                }

                var ret = await modelService.CreatePullRequest(sourceRepository, targetRepository, sourceBranch, targetBranch, title, body);

                await usageTracker.IncrementCounter(x => x.NumberOfUpstreamPullRequests);

                return(ret);
            }
        }
        async Task<IPullRequestModel> PushAndCreatePR(IRepositoryHost host,
            ILocalRepositoryModel sourceRepository, IRepositoryModel targetRepository,
            IBranch sourceBranch, IBranch targetBranch,
            string title, string body)
        {
            var repo = await Task.Run(() => gitService.GetRepository(sourceRepository.LocalPath));
            var remote = await gitClient.GetHttpRemote(repo, "origin");
            await gitClient.Push(repo, sourceBranch.Name, remote.Name);

            if (!repo.Branches[sourceBranch.Name].IsTracking)
                await gitClient.SetTrackingBranch(repo, sourceBranch.Name, remote.Name);

            // delay things a bit to avoid a race between pushing a new branch and creating a PR on it
            if (!Splat.ModeDetector.Current.InUnitTestRunner().GetValueOrDefault())
                await Task.Delay(TimeSpan.FromSeconds(5));

            var ret = await host.ModelService.CreatePullRequest(sourceRepository, targetRepository, sourceBranch, targetBranch, title, body);
            await usageTracker.IncrementUpstreamPullRequestCount();
            return ret;
        }