async Task <PullRequestSession> GetSessionInternal(string owner, string name, int number)
        {
            var cloneUrl = repository.CloneUrl;

            if (cloneUrl == null)
            {
                // Can't create a session from a repository with no origin
                return(null);
            }

            PullRequestSession session = null;
            WeakReference <PullRequestSession> weakSession;
            var key = Tuple.Create(owner.ToLowerInvariant(), number);

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

            if (session == null)
            {
                var address     = HostAddress.Create(cloneUrl);
                var pullRequest = await sessionService.ReadPullRequestDetail(address, owner, name, number);

                session = new PullRequestSession(
                    sessionService,
                    await sessionService.ReadViewer(address),
                    pullRequest,
                    repository,
                    key.Item1,
                    false);
                sessions[key] = new WeakReference <PullRequestSession>(session);
            }

            return(session);
        }
Beispiel #2
0
        public async Task RetriesUsingOldScopeWhenAuthenticationFailsAndIsEnterprise()
        {
            var enterpriseHostAddress = HostAddress.Create("https://enterprise.example.com/");
            var apiClient             = Substitute.For <IApiClient>();

            apiClient.HostAddress.Returns(enterpriseHostAddress);
            apiClient.GetOrCreateApplicationAuthenticationCode(Args.TwoFactorChallengCallback, null, false, true)
            .Returns(Observable.Throw <ApplicationAuthorization>(new ApiException("Bad scopes", (HttpStatusCode)422)));
            apiClient.GetOrCreateApplicationAuthenticationCode(Args.TwoFactorChallengCallback, null, true, false)
            .Returns(Observable.Return(new ApplicationAuthorization("T0k3n")));
            apiClient.GetUser().Returns(Observable.Return(CreateOctokitUser("jiminy")));
            var hostCache    = new InMemoryBlobCache();
            var modelService = new ModelService(apiClient, hostCache, Substitute.For <IAvatarProvider>());
            var loginCache   = new TestLoginCache();
            var host         = new RepositoryHost(apiClient, modelService, loginCache, Substitute.For <ITwoFactorChallengeHandler>());

            await host.LogIn("jiminy", "aPassowrd");

            Assert.True(host.IsLoggedIn);
            var loginInfo = await loginCache.GetLoginAsync(enterpriseHostAddress);

            Assert.Equal("jiminy", loginInfo.UserName);
            Assert.Equal("T0k3n", loginInfo.Password);
        }
Beispiel #3
0
        /// <inheritdoc/>
        public async Task <PullRequestDetailModel> CancelPendingReview(
            ILocalRepositoryModel localRepository,
            string reviewId)
        {
            var address = HostAddress.Create(localRepository.CloneUrl.Host);
            var graphql = await graphqlFactory.CreateConnection(address);

            var delete = new DeletePullRequestReviewInput
            {
                PullRequestReviewId = new ID(reviewId),
            };

            var mutation = new Mutation()
                           .DeletePullRequestReview(delete)
                           .Select(x => new
            {
                x.PullRequestReview.Repository.Owner.Login,
                x.PullRequestReview.PullRequest.Number
            });

            var result = await graphql.Run(mutation);

            return(await ReadPullRequestDetail(address, result.Login, localRepository.Name, result.Number));
        }
Beispiel #4
0
        public static void SetupConnections(IRepositoryHosts hosts, IConnectionManager cm,
                                            List <HostAddress> adds, List <IConnection> conns, List <IRepositoryHost> hsts,
                                            string uri)
        {
            var add  = HostAddress.Create(new Uri(uri));
            var host = Substitute.For <IRepositoryHost>();
            var conn = Substitute.For <IConnection>();

            host.Address.Returns(add);
            conn.HostAddress.Returns(add);
            adds.Add(add);
            hsts.Add(host);
            conns.Add(conn);

            if (add.IsGitHubDotCom())
            {
                hosts.GitHubHost.Returns(host);
            }
            else
            {
                hosts.EnterpriseHost.Returns(host);
            }
            hosts.LookupHost(Arg.Is(add)).Returns(host);
        }
Beispiel #5
0
        public async Task SavesConnectionToCache()
        {
            var cache  = CreateConnectionCache();
            var target = new ConnectionManager(
                CreateProgram(),
                cache,
                Substitute.For <IKeychain>(),
                CreateLoginManager(),
                Substitute.For <IUsageTracker>(),
                Substitute.For <IVisualStudioBrowser>());

            await target.LogIn(HostAddress.GitHubDotComHostAddress, "user", "pass");

            await cache.Received(1).Save(Arg.Is <IEnumerable <ConnectionDetails> >(x =>
                                                                                   x.Count() == 1 && x.ElementAt(0).HostAddress == HostAddress.Create("https://github.com")));
        }
Beispiel #6
0
        protected void StartFlow(UIControllerFlow controllerFlow)
        {
            IConnection connection = null;

            if (controllerFlow != UIControllerFlow.Authentication)
            {
                var activeRepo = GetActiveRepo();
                connection = ServiceProvider.TryGetService <IConnectionManager>()?.Connections
                             .FirstOrDefault(c => activeRepo?.CloneUrl?.RepositoryName != null && c.HostAddress.Equals(HostAddress.Create(activeRepo.CloneUrl)));
            }
            ServiceProvider.TryGetService <IUIProvider>().RunInDialog(controllerFlow, connection);
        }
Beispiel #7
0
        public void RefreshRepositories()
        {
            var list = vsServices.GetKnownRepositories();

            list.GroupBy(r => Connections.FirstOrDefault(c => r.CloneUrl != null && c.HostAddress.Equals(HostAddress.Create(r.CloneUrl))))
            .Where(g => g.Key != null)
            .ForEach(g =>
            {
                var repos = g.Key.Repositories;
                repos.Except(g).ToList().ForEach(c => repos.Remove(c));
                g.Except(repos).ToList().ForEach(c => repos.Add(c));
            });
        }
 public void CreateInvalidHost()
 {
     Assert.Throws<InvalidOperationException>(() => HostAddress.Create("{0}"));
 }
Beispiel #9
0
 protected override Task <IConnection> LogIn(object args)
 {
     return(LogInToHost(HostAddress.Create(EnterpriseUrl)));
 }
Beispiel #10
0
    static TestData PrepareTestData(
        string repoName, string sourceRepoOwner, string sourceBranchName,
        string targetRepoOwner, string targetBranchName,
        string remote,
        bool repoIsFork, bool sourceBranchIsTracking)
    {
        var serviceProvider = Substitutes.ServiceProvider;
        var gitService      = serviceProvider.GetGitService();
        var gitClient       = Substitute.For <IGitClient>();
        var notifications   = Substitute.For <INotificationService>();
        var connection      = Substitute.For <IConnection>();
        var api             = Substitute.For <IApiClient>();
        var ms = Substitute.For <IModelService>();

        connection.HostAddress.Returns(HostAddress.Create("https://github.com"));

        var activeRepo = new LocalRepositoryModel
        {
            LocalPath = "",
            Name      = repoName,
            CloneUrl  = new UriString("http://github.com/" + sourceRepoOwner + "/" + repoName)
        };

        Repository githubRepoParent = null;

        if (repoIsFork)
        {
            githubRepoParent = CreateRepository(targetRepoOwner, repoName, id: 1);
        }
        var githubRepo   = CreateRepository(sourceRepoOwner, repoName, id: 2, parent: githubRepoParent);
        var sourceBranch = new BranchModel(sourceBranchName, activeRepo);
        var sourceRepo   = CreateRemoteRepositoryModel(githubRepo);
        var targetRepo   = targetRepoOwner == sourceRepoOwner ? sourceRepo : sourceRepo.Parent;
        var targetBranch = targetBranchName != targetRepo.DefaultBranch.Name ? new BranchModel(targetBranchName, targetRepo) : targetRepo.DefaultBranch;

        gitService.GetBranch(activeRepo).Returns(sourceBranch);
        api.GetRepository(Args.String, Args.String).Returns(Observable.Return(githubRepo));
        ms.ApiClient.Returns(api);

        // Default to returning no branches
        ms.GetBranches(null).ReturnsForAnyArgs(Observable.Empty <BranchModel>());

        // sets up the libgit2sharp repo and branch objects
        var l2repo = SetupLocalRepoMock(gitClient, gitService, remote, sourceBranchName, sourceBranchIsTracking);

        return(new TestData
        {
            ServiceProvider = serviceProvider,
            ActiveRepo = activeRepo,
            L2Repo = l2repo,
            SourceRepo = sourceRepo,
            SourceBranch = sourceBranch,
            TargetRepo = targetRepo,
            TargetBranch = targetBranch,
            GitClient = gitClient,
            GitService = gitService,
            NotificationService = notifications,
            Connection = connection,
            ApiClient = api,
            ModelService = ms
        });
    }
Beispiel #11
0
    public GitHubPaneViewModelTests()
    {
        var repositoryHosts = Substitutes.RepositoryHosts;

        repositoryHosts.IsLoggedInToAnyHost.Returns(true);

        var teamExplorerServiceHolder = Substitute.For <ITeamExplorerServiceHolder>();
        var activeRepo = Substitute.For <ILocalRepositoryModel>();

        activeRepo.CloneUrl.Returns(new UriString("https://github.com/foo/foo"));
        teamExplorerServiceHolder
        .When(x => x.Subscribe(Arg.Any <object>(), Arg.Any <Action <ILocalRepositoryModel> >()))
        .Do(x =>
        {
            var invokeAction = x.Arg <Action <ILocalRepositoryModel> >();
            invokeAction(activeRepo);
        });

        var connectionManager     = Substitutes.ConnectionManager;
        var connection            = Substitutes.Connection;
        var connectionHostAddress = HostAddress.Create(activeRepo.CloneUrl.ToString());

        connection.HostAddress.Returns(connectionHostAddress);
        connectionManager.Connections.Returns(new ObservableCollection <IConnection>(new[] {
            connection
        }));
        connection.Login().Returns(Observable.Return(connection));

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

        host.IsLoggedIn.Returns(true);
        repositoryHosts.LookupHost(connectionHostAddress).Returns(host);

        serviceProvider    = Substitutes.GetFullyMockedServiceProvider();
        menuCommandService = new FakeMenuCommandService();
        serviceProvider.GetService(typeof(IMenuCommandService)).Returns(menuCommandService);

        var uiProvider = serviceProvider as IUIProvider;

        uiProvider.TryGetService(typeof(IUIProvider)).Returns(serviceProvider);

        uiController = Substitute.For <IUIController>();
        uiController.CurrentFlow.Returns(UIControllerFlow.PullRequests);
        uiController.SelectedFlow.Returns(UIControllerFlow.PullRequests);
        uiController
        .When(x => x.Jump(Arg.Any <ViewWithData>()))
        .Do(x => lastUiControllerJump = x.Arg <ViewWithData>().ViewType);

        var exportFactoryProvider = Substitutes.ExportFactoryProvider;

        uiProvider.TryGetService(typeof(IExportFactoryProvider)).Returns(exportFactoryProvider);
        exportFactoryProvider.UIControllerFactory.Returns(new ExportFactory <IUIController>(
                                                              () => Tuple.Create <IUIController, Action>(uiController, () => { })));

        viewModel = new GitHubPaneViewModel(
            Substitute.For <ISimpleApiClientFactory>(),
            teamExplorerServiceHolder,
            connectionManager,
            repositoryHosts,
            Substitute.For <INotificationDispatcher>());

        viewModel.ActiveRepo = activeRepo;
    }
Beispiel #12
0
        async Task UpdateContent(LocalRepositoryModel repository)
        {
            log.Debug("UpdateContent called with {CloneUrl}", repository?.CloneUrl);

            LocalRepository = repository;
            connectionSubscription?.Dispose();
            connectionSubscription = null;
            Connection             = null;
            Content = null;
            navigator.Clear();

            if (repository == null)
            {
                log.Debug("Not a git repository: {CloneUrl}", repository?.CloneUrl);
                Content = notAGitRepository;
                return;
            }
            else if (string.IsNullOrWhiteSpace(repository.CloneUrl))
            {
                if (repository.HasRemotesButNoOrigin)
                {
                    log.Debug("No origin remote");
                    Content = noRemoteOrigin;
                }
                else
                {
                    log.Debug("Not a GitHub repository: {CloneUrl}", repository?.CloneUrl);
                    Content = notAGitHubRepository;
                }

                return;
            }

            var repositoryUrl = repository.CloneUrl.ToRepositoryUrl();
            var isDotCom      = HostAddress.IsGitHubDotComUri(repositoryUrl);
            var client        = await apiClientFactory.Create(repository.CloneUrl);

            var isEnterprise = isDotCom ? false : await client.IsEnterprise();

            var notGitHubRepo = true;

            if (isDotCom || isEnterprise)
            {
                var hostAddress = HostAddress.Create(repository.CloneUrl);

                notGitHubRepo = false;

                Connection = await connectionManager.GetConnection(hostAddress);

                Connection?.WhenAnyValue(
                    x => x.IsLoggedIn,
                    x => x.IsLoggingIn,
                    (_, __) => Unit.Default)
                .Skip(1)
                .Throttle(TimeSpan.FromMilliseconds(100))
                .ObserveOn(RxApp.MainThreadScheduler)
                .Subscribe(_ => UpdateContent(LocalRepository).Forget());

                if (Connection?.IsLoggedIn == true)
                {
                    if (await IsValidRepository(client) == true)
                    {
                        log.Debug("Found a GitHub repository: {CloneUrl}", repository?.CloneUrl);
                        Content = navigator;
                        await ShowDefaultPage();
                    }
                    else
                    {
                        notGitHubRepo = true;
                    }
                }
                else if (Connection?.IsLoggingIn == true)
                {
                    log.Debug("Found a GitHub repository: {CloneUrl} and logging in", repository?.CloneUrl);
                    Content = null;
                }
                else if (Connection?.ConnectionError != null)
                {
                    log.Debug("Found a GitHub repository: {CloneUrl} with login error", repository?.CloneUrl);
                    loginFailed.Initialize(Connection.ConnectionError.GetUserFriendlyError(ErrorType.LoginFailed));
                    Content = loginFailed;
                }
                else
                {
                    log.Debug("Found a a GitHub repository but not logged in: {CloneUrl}", repository?.CloneUrl);
                    Content = loggedOut;
                }
            }

            if (notGitHubRepo)
            {
                log.Debug("Not a GitHub repository: {CloneUrl}", repository?.CloneUrl);
                Content = notAGitHubRepository;
            }
        }
Beispiel #13
0
        public IObservable <AutoCompleteSuggestion> GetSuggestions()
        {
            var localRepositoryModel = teamExplorerContext.ActiveRepository;

            var hostAddress = HostAddress.Create(localRepositoryModel.CloneUrl.Host);
            var owner       = localRepositoryModel.Owner;
            var name        = localRepositoryModel.Name;

            string filter;
            string after;

            if (query == null)
            {
                query = new Query().Search(query: Var(nameof(filter)), SearchType.Issue, 100, after: Var(nameof(after)))
                        .Select(item => new Page <SuggestionItem>
                {
                    Items = item.Nodes.Select(searchResultItem =>
                                              searchResultItem.Switch <SuggestionItem>(selector => selector
                                                                                       .Issue(i => new SuggestionItem("#" + i.Number, i.Title)
                    {
                        LastModifiedDate = i.LastEditedAt
                    })
                                                                                       .PullRequest(p => new SuggestionItem("#" + p.Number, p.Title)
                    {
                        LastModifiedDate = p.LastEditedAt
                    }))
                                              ).ToList(),
                    EndCursor   = item.PageInfo.EndCursor,
                    HasNextPage = item.PageInfo.HasNextPage,
                    TotalCount  = item.IssueCount
                })
                        .Compile();
            }

            filter = $"repo:{owner}/{name}";

            return(Observable.FromAsync(async() =>
            {
                var results = new List <SuggestionItem>();

                var variables = new Dictionary <string, object>
                {
                    { nameof(filter), filter },
                };

                var connection = await graphqlFactory.CreateConnection(hostAddress);
                var searchResults = await connection.Run(query, variables);

                results.AddRange(searchResults.Items);

                while (searchResults.HasNextPage)
                {
                    variables[nameof(after)] = searchResults.EndCursor;
                    searchResults = await connection.Run(query, variables);

                    results.AddRange(searchResults.Items);
                }

                return results.Select(item => new IssueAutoCompleteSuggestion(item, Prefix));
            }).SelectMany(observable => observable));
        }
Beispiel #14
0
 protected override Task <IConnection> LogInViaOAuth()
 {
     return(LoginToHostViaOAuth(HostAddress.Create(EnterpriseUrl)));
 }
Beispiel #15
0
 public static IObservable <IConnection> LookupConnection(this IConnectionManager cm, ISimpleRepositoryModel repository)
 {
     return(Observable.Return(repository?.CloneUrl != null
         ? cm.Connections.FirstOrDefault(c => c.HostAddress.Equals(HostAddress.Create(repository.CloneUrl)))
         : null));
 }
Beispiel #16
0
 public DisconnectedRepositoryHost()
 {
     Address       = HostAddress.Create(new Uri("https://null/"));
     Organizations = new ReactiveList <IAccount>();
     Accounts      = new ReactiveList <IAccount>();
 }
        Task <IApiClient> CreateApiClient(ILocalRepositoryModel repository)
        {
            var hostAddress = HostAddress.Create(repository.CloneUrl.Host);

            return(apiClientFactory.Create(hostAddress));
        }
 protected override IObservable <AuthenticationResult> LogIn(object args)
 {
     return(LogInToHost(HostAddress.Create(EnterpriseUrl)));
 }
Beispiel #19
0
 static ConnectionDetails FromCache(ConnectionCacheItem c)
 {
     return(new ConnectionDetails(HostAddress.Create(c.HostUrl), c.UserName));
 }
Beispiel #20
0
        protected void StartFlow(UIControllerFlow controllerFlow)
        {
            var uiProvider = ServiceProvider.GetExportedValue <IUIProvider>();

            Debug.Assert(uiProvider != null, "MenuBase:StartFlow:No UIProvider available.");
            if (uiProvider == null)
            {
                return;
            }

            IConnection connection = null;

            if (controllerFlow != UIControllerFlow.Authentication)
            {
                var activeRepo = GetActiveRepo();
                connection = ServiceProvider.GetExportedValue <IConnectionManager>()?.Connections
                             .FirstOrDefault(c => activeRepo?.CloneUrl?.RepositoryName != null && c.HostAddress.Equals(HostAddress.Create(activeRepo.CloneUrl)));
            }
            uiProvider.RunUI(controllerFlow, connection);
        }
Beispiel #21
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ConnectionDetails"/> struct.
 /// </summary>
 /// <param name="hostAddress">The address of the host.</param>
 /// <param name="userName">The username for the host.</param>
 public ConnectionDetails(string hostAddress, string userName)
 {
     HostAddress = HostAddress.Create(hostAddress);
     UserName    = userName;
 }