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); }
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); }
/// <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)); }
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); }
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"))); }
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); }
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}")); }
protected override Task <IConnection> LogIn(object args) { return(LogInToHost(HostAddress.Create(EnterpriseUrl))); }
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 }); }
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; }
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; } }
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)); }
protected override Task <IConnection> LogInViaOAuth() { return(LoginToHostViaOAuth(HostAddress.Create(EnterpriseUrl))); }
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)); }
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))); }
static ConnectionDetails FromCache(ConnectionCacheItem c) { return(new ConnectionDetails(HostAddress.Create(c.HostUrl), c.UserName)); }
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); }
/// <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; }