Skip to content
This repository was archived by the owner on Jun 21, 2023. It is now read-only.

Commit 972ebd5

Browse files
committed
Merge pull request #189 from github/shana/fix-iconnection-when-logged-in
Fix connections not being passed on to view models
2 parents 8d201c3 + 8a95913 commit 972ebd5

File tree

7 files changed

+90
-46
lines changed

7 files changed

+90
-46
lines changed

src/GitHub.App/Controllers/UIController.cs

+20-7
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
using ReactiveUI;
1919
using Stateless;
2020
using System.Collections.Specialized;
21+
using System.Linq;
2122

2223
namespace GitHub.Controllers
2324
{
@@ -227,7 +228,11 @@ public void Start([AllowNull] IConnection connection)
227228
{
228229
if (connection != null)
229230
{
230-
uiProvider.AddService(typeof(IConnection), connection);
231+
if (currentFlow != UIControllerFlow.Authentication)
232+
uiProvider.AddService(connection);
233+
else // sanity check: it makes zero sense to pass a connection in when calling the auth flow
234+
Debug.Assert(false, "Calling the auth flow with a connection makes no sense!");
235+
231236
connection.Login()
232237
.Select(c => hosts.LookupHost(connection.HostAddress))
233238
.Do(host =>
@@ -254,13 +259,21 @@ public void Start([AllowNull] IConnection connection)
254259
.IsLoggedIn(hosts)
255260
.Do(loggedin =>
256261
{
257-
if (!loggedin && currentFlow != UIControllerFlow.Authentication)
262+
if (currentFlow != UIControllerFlow.Authentication)
258263
{
259-
connectionAdded = (s, e) => {
260-
if (e.Action == NotifyCollectionChangedAction.Add)
261-
uiProvider.AddService(typeof(IConnection), e.NewItems[0]);
262-
};
263-
connectionManager.Connections.CollectionChanged += connectionAdded;
264+
if (loggedin) // register the first available connection so the viewmodel can use it
265+
uiProvider.AddService(connectionManager.Connections.First(c => hosts.LookupHost(c.HostAddress).IsLoggedIn));
266+
else
267+
{
268+
// a connection will be added to the list when auth is done, register it so the next
269+
// viewmodel can use it
270+
connectionAdded = (s, e) =>
271+
{
272+
if (e.Action == NotifyCollectionChangedAction.Add)
273+
uiProvider.AddService(typeof(IConnection), e.NewItems[0]);
274+
};
275+
connectionManager.Connections.CollectionChanged += connectionAdded;
276+
}
264277
}
265278

266279
machine.Configure(UIViewType.None)

src/GitHub.App/Models/ConnectionRepositoryHostMap.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ public class ConnectionRepositoryHostMap : IConnectionRepositoryHostMap
1010
{
1111
[ImportingConstructor]
1212
public ConnectionRepositoryHostMap(IUIProvider provider, IRepositoryHosts hosts)
13-
: this(provider.GetService<IConnection>(), hosts)
13+
: this(provider.TryGetService<IConnection>(), hosts)
1414
{
1515
}
1616

src/GitHub.Exports/Extensions/ServiceProviderExtensions.cs

+30-36
Original file line numberDiff line numberDiff line change
@@ -15,50 +15,35 @@ public static class IServiceProviderExtensions
1515
{
1616
static IUIProvider cachedUIProvider = null;
1717

18-
public static T TryGetService<T>(this IServiceProvider serviceProvider) where T : class
19-
{
20-
return serviceProvider.TryGetService(typeof(T)) as T;
21-
}
22-
2318
public static object TryGetService(this IServiceProvider serviceProvider, Type type)
2419
{
2520
if (cachedUIProvider != null && type == typeof(IUIProvider))
2621
return cachedUIProvider;
2722

2823
var ui = serviceProvider as IUIProvider;
29-
if (ui != null)
30-
return ui.TryGetService(type);
31-
else
32-
{
33-
try
34-
{
35-
return GetServiceAndCache(serviceProvider, type, ref cachedUIProvider);
36-
}
37-
catch (Exception ex)
38-
{
39-
Debug.Print(ex.ToString());
40-
}
41-
return null;
42-
}
24+
return ui != null
25+
? ui.TryGetService(type)
26+
: GetServiceAndCache(serviceProvider, type, ref cachedUIProvider);
4327
}
44-
45-
public static T GetService<T>(this IServiceProvider serviceProvider)
28+
public static T GetExportedValue<T>(this IServiceProvider serviceProvider) where T : class
4629
{
4730
if (cachedUIProvider != null && typeof(T) == typeof(IUIProvider))
4831
return (T)cachedUIProvider;
4932

50-
return (T)GetServiceAndCache(serviceProvider, typeof(T), ref cachedUIProvider);
33+
var ui = serviceProvider as IUIProvider;
34+
return ui != null
35+
? ui.TryGetService(typeof(T)) as T
36+
: GetExportedValueAndCache<T, IUIProvider>(ref cachedUIProvider);
5137
}
5238

53-
public static T GetExportedValue<T>(this IServiceProvider serviceProvider)
39+
public static T TryGetService<T>(this IServiceProvider serviceProvider) where T : class
5440
{
55-
if (cachedUIProvider != null && typeof(T) == typeof(IUIProvider))
56-
return (T)cachedUIProvider;
41+
return serviceProvider.TryGetService(typeof(T)) as T;
42+
}
5743

58-
var ui = serviceProvider as IUIProvider;
59-
return ui != null
60-
? ui.GetService<T>()
61-
: GetExportedValueAndCache<T, IUIProvider>(ref cachedUIProvider);
44+
public static T GetService<T>(this IServiceProvider serviceProvider) where T : class
45+
{
46+
return serviceProvider.TryGetService(typeof(T)) as T;
6247
}
6348

6449
public static ITeamExplorerSection GetSection(this IServiceProvider serviceProvider, Guid section)
@@ -68,18 +53,27 @@ public static ITeamExplorerSection GetSection(this IServiceProvider serviceProvi
6853

6954
static object GetServiceAndCache<CacheType>(IServiceProvider provider, Type type, ref CacheType cache)
7055
{
71-
var ret = provider.GetService(type);
72-
if (type == typeof(CacheType))
56+
object ret = null;
57+
try
58+
{
59+
ret = provider.GetService(type);
60+
}
61+
catch (Exception ex)
62+
{
63+
Debug.Print(ex.ToString());
64+
VisualStudio.VsOutputLogger.WriteLine("GetServiceAndCache: Could not obtain instance of '{0}'", type);
65+
}
66+
if (ret != null && type == typeof(CacheType))
7367
cache = (CacheType)ret;
7468
return ret;
7569
}
7670

77-
static T GetExportedValueAndCache<T, CacheType>(ref CacheType cache)
71+
static T GetExportedValueAndCache<T, CacheType>(ref CacheType cache) where T : class
7872
{
79-
var ret = VisualStudio.Services.ComponentModel.DefaultExportProvider.GetExportedValue<T>();
80-
if (typeof(T) == typeof(CacheType))
81-
cache = (CacheType)(object)ret;
82-
return ret;
73+
object ret = VisualStudio.Services.ComponentModel.DefaultExportProvider.GetExportedValueOrDefault<T>();
74+
if (ret != null && typeof(T) == typeof(CacheType))
75+
cache = (CacheType)ret;
76+
return ret as T;
8377
}
8478

8579
public static void AddTopLevelMenuItem(this IServiceProvider provider,

src/GitHub.Exports/Services/IUIProvider.cs

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public interface IUIProvider : IServiceProvider
1818
T TryGetService<T>() where T : class;
1919

2020
void AddService(Type t, object instance);
21+
void AddService<T>(T instance);
2122
void RemoveService(Type t);
2223

2324
IObservable<UserControl> SetupUI(UIControllerFlow controllerFlow, IConnection connection);

src/GitHub.VisualStudio/Services/UIProvider.cs

+5
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,11 @@ public Ret GetService<T, Ret>() where Ret : class
144144
return GetService<T>() as Ret;
145145
}
146146

147+
public void AddService<T>(T instance)
148+
{
149+
AddService(typeof(T), instance);
150+
}
151+
147152
public void AddService(Type t, object instance)
148153
{
149154
if (!Initialized)

src/UnitTests/GitHub.App/Controllers/UIControllerTests.cs

+32-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using ReactiveUI;
1414
using System.Collections.Generic;
1515
using GitHub.Authentication;
16+
using System.Collections.ObjectModel;
1617

1718
public class UIControllerTests
1819
{
@@ -55,8 +56,7 @@ public void ShowingCloneDialogWithoutBeingLoggedInShowsLoginDialog()
5556
var loginView = factory.GetView(GitHub.Exports.UIViewType.Login);
5657
loginView.Value.Cancel.Returns(Observable.Empty<object>());
5758
var cm = provider.GetConnectionManager();
58-
var cons = new System.Collections.ObjectModel.ObservableCollection<IConnection>();
59-
cm.Connections.Returns(cons);
59+
cm.Connections.Returns(new ObservableCollection<IConnection>());
6060

6161
using (var uiController = new UIController((IUIProvider)provider, hosts, factory, cm, LazySubstitute.For<ITwoFactorChallengeHandler>()))
6262
{
@@ -82,6 +82,7 @@ public void ShowingCloneDialogWhenLoggedInShowsCloneDialog()
8282
var connection = provider.GetConnection();
8383
connection.Login().Returns(Observable.Return(connection));
8484
var cm = provider.GetConnectionManager();
85+
cm.Connections.Returns(new ObservableCollection<IConnection> { connection });
8586
var host = hosts.GitHubHost;
8687
hosts.LookupHost(connection.HostAddress).Returns(host);
8788
host.IsLoggedIn.Returns(true);
@@ -99,5 +100,34 @@ public void ShowingCloneDialogWhenLoggedInShowsCloneDialog()
99100
uiController.Start(connection);
100101
}
101102
}
103+
104+
[STAFact]
105+
public void CloneDialogLoggedInWithoutConnection()
106+
{
107+
var provider = Substitutes.GetFullyMockedServiceProvider();
108+
var hosts = provider.GetRepositoryHosts();
109+
var factory = SetupFactory(provider);
110+
var connection = provider.GetConnection();
111+
connection.Login().Returns(Observable.Return(connection));
112+
var cm = provider.GetConnectionManager();
113+
cm.Connections.Returns(new ObservableCollection<IConnection> { connection });
114+
var host = hosts.GitHubHost;
115+
hosts.LookupHost(connection.HostAddress).Returns(host);
116+
host.IsLoggedIn.Returns(true);
117+
118+
using (var uiController = new UIController((IUIProvider)provider, hosts, factory, cm, LazySubstitute.For<ITwoFactorChallengeHandler>()))
119+
{
120+
var list = new List<IView>();
121+
uiController.SelectFlow(UIControllerFlow.Clone)
122+
.Subscribe(uc => list.Add(uc as IView),
123+
() =>
124+
{
125+
Assert.Equal(1, list.Count);
126+
Assert.IsAssignableFrom<IViewFor<IRepositoryCloneViewModel>>(list[0]);
127+
((IUIProvider)provider).Received().AddService(connection);
128+
});
129+
uiController.Start(null);
130+
}
131+
}
102132
}
103133
}

src/UnitTests/GitHub.Exports/VSServicesTests.cs

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public void CallsCloneOnVsProvidedCloneService(bool recurseSubmodules, CloneOpti
1616
var provider = Substitute.For<IUIProvider>();
1717
var gitRepositoriesExt = Substitute.For<IGitRepositoriesExt>();
1818
provider.GetService(typeof(IGitRepositoriesExt)).Returns(gitRepositoriesExt);
19+
provider.TryGetService(typeof(IGitRepositoriesExt)).Returns(gitRepositoriesExt);
1920
var vsServices = new VSServices(provider);
2021

2122
vsServices.Clone("https://github.com/github/visualstudio", @"c:\fake\ghfvs", recurseSubmodules);

0 commit comments

Comments
 (0)