diff --git a/GitHubVS.sln b/GitHubVS.sln index 5f0956828d..1845c57760 100644 --- a/GitHubVS.sln +++ b/GitHubVS.sln @@ -125,6 +125,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GitHub.VisualStudio.UnitTes EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GitHub.Resources", "src\GitHub.Resources\GitHub.Resources.csproj", "{54E8D71A-AABB-4698-95FE-7F11612B8E59}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IntegrationTests", "test\IntegrationTests\IntegrationTests.csproj", "{BF6D17FE-15FD-401C-B5D7-DE21837231F1}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -504,6 +506,16 @@ Global {54E8D71A-AABB-4698-95FE-7F11612B8E59}.Release|Any CPU.Build.0 = Release|Any CPU {54E8D71A-AABB-4698-95FE-7F11612B8E59}.ReleaseWithoutVsix|Any CPU.ActiveCfg = Release|Any CPU {54E8D71A-AABB-4698-95FE-7F11612B8E59}.ReleaseWithoutVsix|Any CPU.Build.0 = Release|Any CPU + {BF6D17FE-15FD-401C-B5D7-DE21837231F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BF6D17FE-15FD-401C-B5D7-DE21837231F1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BF6D17FE-15FD-401C-B5D7-DE21837231F1}.DebugCodeAnalysis|Any CPU.ActiveCfg = Debug|Any CPU + {BF6D17FE-15FD-401C-B5D7-DE21837231F1}.DebugCodeAnalysis|Any CPU.Build.0 = Debug|Any CPU + {BF6D17FE-15FD-401C-B5D7-DE21837231F1}.DebugWithoutVsix|Any CPU.ActiveCfg = Debug|Any CPU + {BF6D17FE-15FD-401C-B5D7-DE21837231F1}.DebugWithoutVsix|Any CPU.Build.0 = Debug|Any CPU + {BF6D17FE-15FD-401C-B5D7-DE21837231F1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BF6D17FE-15FD-401C-B5D7-DE21837231F1}.Release|Any CPU.Build.0 = Release|Any CPU + {BF6D17FE-15FD-401C-B5D7-DE21837231F1}.ReleaseWithoutVsix|Any CPU.ActiveCfg = Release|Any CPU + {BF6D17FE-15FD-401C-B5D7-DE21837231F1}.ReleaseWithoutVsix|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -534,6 +546,7 @@ Global {DE704BBB-6EC6-4173-B695-D9EBF5AEB092} = {8A7DA2E7-262B-4581-807A-1C45CE79CDFD} {93778A89-3E58-4853-B772-948EBB3F17BE} = {8A7DA2E7-262B-4581-807A-1C45CE79CDFD} {8B14F90B-0781-465D-AB94-19C8C56E3A94} = {8A7DA2E7-262B-4581-807A-1C45CE79CDFD} + {BF6D17FE-15FD-401C-B5D7-DE21837231F1} = {8A7DA2E7-262B-4581-807A-1C45CE79CDFD} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {556014CF-5B35-4CE5-B3EF-6AB0007001AC} diff --git a/src/GitHub.App/Services/RepositoryCloneService.cs b/src/GitHub.App/Services/RepositoryCloneService.cs index 7998e73417..8ef95e0215 100644 --- a/src/GitHub.App/Services/RepositoryCloneService.cs +++ b/src/GitHub.App/Services/RepositoryCloneService.cs @@ -66,7 +66,7 @@ public async Task ReadViewerRepositories(HostAddress ad var affiliation = new RepositoryAffiliation?[] { - RepositoryAffiliation.Owner + RepositoryAffiliation.Owner, RepositoryAffiliation.Collaborator }; var repositorySelection = new Fragment( @@ -84,6 +84,7 @@ public async Task ReadViewerRepositories(HostAddress ad .Viewer .Select(viewer => new ViewerRepositoriesModel { + Owner = viewer.Login, Repositories = viewer.Repositories(null, null, null, null, null, order, affiliation, null, null) .AllPages() .Select(repositorySelection).ToList(), diff --git a/src/GitHub.App/ViewModels/Dialog/Clone/RepositorySelectViewModel.cs b/src/GitHub.App/ViewModels/Dialog/Clone/RepositorySelectViewModel.cs index 87fae2b1d0..e48a0b9822 100644 --- a/src/GitHub.App/ViewModels/Dialog/Clone/RepositorySelectViewModel.cs +++ b/src/GitHub.App/ViewModels/Dialog/Clone/RepositorySelectViewModel.cs @@ -111,11 +111,16 @@ public async Task Activate() var results = await service.ReadViewerRepositories(connection.HostAddress).ConfigureAwait(true); var yourRepositories = results.Repositories + .Where(r => r.Owner == results.Owner) .Select(x => new RepositoryItemViewModel(x, "Your repositories")); + var collaboratorRepositories = results.Repositories + .Where(r => r.Owner != results.Owner) + .OrderBy(r => r.Owner) + .Select(x => new RepositoryItemViewModel(x, "Collaborator repositories")); var orgRepositories = results.OrganizationRepositories .OrderBy(x => x.Key) .SelectMany(x => x.Value.Select(y => new RepositoryItemViewModel(y, x.Key))); - Items = yourRepositories.Concat(orgRepositories).ToList(); + Items = yourRepositories.Concat(collaboratorRepositories).Concat(orgRepositories).ToList(); ItemsView = CollectionViewSource.GetDefaultView(Items); ItemsView.GroupDescriptions.Add(new PropertyGroupDescription(nameof(RepositoryItemViewModel.Group))); ItemsView.Filter = FilterItem; @@ -149,7 +154,7 @@ bool FilterItem(object obj) IRepositoryModel CreateRepository(IRepositoryItemViewModel item) { - return item != null ? + return item != null ? new RepositoryModel(item.Name, UriString.ToUriString(item.Url)) : null; } diff --git a/src/GitHub.Exports/Models/ViewerRepositoriesModel.cs b/src/GitHub.Exports/Models/ViewerRepositoriesModel.cs index ce84c2a555..27cba30bd1 100644 --- a/src/GitHub.Exports/Models/ViewerRepositoriesModel.cs +++ b/src/GitHub.Exports/Models/ViewerRepositoriesModel.cs @@ -5,6 +5,7 @@ namespace GitHub.Models { public class ViewerRepositoriesModel { + public string Owner { get; set; } public IReadOnlyList Repositories { get; set; } public IDictionary> OrganizationRepositories { get; set; } } diff --git a/src/GitHub.TeamFoundation.14/Services/VSGitExt.cs b/src/GitHub.TeamFoundation.14/Services/VSGitExt.cs index 6bb382b4c7..65783c6dcf 100644 --- a/src/GitHub.TeamFoundation.14/Services/VSGitExt.cs +++ b/src/GitHub.TeamFoundation.14/Services/VSGitExt.cs @@ -94,7 +94,10 @@ public void RefreshActiveRepositories() gitService.GetHashCode(), gitService.ActiveRepositories.Select(x => x.RepositoryPath)); - ActiveRepositories = gitService?.ActiveRepositories.Select(x => repositoryFactory.Create(x.RepositoryPath)).ToList(); + if (gitService != null) + { + ActiveRepositories = gitService.ActiveRepositories.Select(x => repositoryFactory.Create(x.RepositoryPath)).ToList(); + } } } catch (Exception e) diff --git a/test/IntegrationTests/GitHubPaneIntegrationTests.cs b/test/IntegrationTests/GitHubPaneIntegrationTests.cs new file mode 100644 index 0000000000..59426cf2be --- /dev/null +++ b/test/IntegrationTests/GitHubPaneIntegrationTests.cs @@ -0,0 +1,28 @@ +using GitHub.VisualStudio; +using Xunit; +using EnvDTE; +using Microsoft.VisualStudio.Shell; + +namespace IntegrationTests +{ + public class GitHubPaneIntegrationTests + { + const string GitHubPaneGuid = "{6B0FDC0A-F28E-47A0-8EED-CC296BEFF6D2}"; + + [VsFact(UIThread = true, Version = "2015-")] + public void ShowGitHubPane() + { + var dte = (DTE)ServiceProvider.GlobalProvider.GetService(typeof(DTE)); + var window = dte.Windows.Item(GitHubPaneGuid); + window.Visible = false; + var command = dte.Commands.Item(Guids.guidGitHubCmdSet, PkgCmdIDList.showGitHubPaneCommand); + + Assert.False(window.Visible); + Assert.True(command.IsAvailable); + + dte.Commands.Raise(command.Guid, command.ID, null, null); + + Assert.True(window.Visible); + } + } +} diff --git a/test/IntegrationTests/IntegrationTests.csproj b/test/IntegrationTests/IntegrationTests.csproj new file mode 100644 index 0000000000..e75e2478c6 --- /dev/null +++ b/test/IntegrationTests/IntegrationTests.csproj @@ -0,0 +1,172 @@ + + + + + + + + Debug + AnyCPU + {BF6D17FE-15FD-401C-B5D7-DE21837231F1} + Library + Properties + IntegrationTests + IntegrationTests + v4.6.1 + 512 + + + + + true + full + false + ..\..\build\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\..\build\Release\ + TRACE + prompt + 4 + + + + ..\..\packages\Ben.Demystifier.0.1.1\lib\net45\Ben.Demystifier.dll + + + ..\..\packages\EnvDTE.8.0.2\lib\net10\EnvDTE.dll + True + + + ..\..\packages\EnvDTE80.8.0.3\lib\net10\EnvDTE80.dll + True + + + ..\..\packages\Microsoft.VisualStudio.ComponentModelHost.14.0.25424\lib\net45\Microsoft.VisualStudio.ComponentModelHost.dll + + + ..\..\packages\Microsoft.VisualStudio.Imaging.14.3.25407\lib\net45\Microsoft.VisualStudio.Imaging.dll + + + ..\..\packages\Microsoft.VisualStudio.OLE.Interop.7.10.6070\lib\Microsoft.VisualStudio.OLE.Interop.dll + + + ..\..\packages\Microsoft.VisualStudio.Shell.14.0.14.3.25407\lib\Microsoft.VisualStudio.Shell.14.0.dll + + + ..\..\packages\Microsoft.VisualStudio.Shell.Immutable.10.0.10.0.30319\lib\net40\Microsoft.VisualStudio.Shell.Immutable.10.0.dll + + + ..\..\packages\Microsoft.VisualStudio.Shell.Immutable.11.0.11.0.50727\lib\net45\Microsoft.VisualStudio.Shell.Immutable.11.0.dll + + + ..\..\packages\Microsoft.VisualStudio.Shell.Immutable.12.0.12.0.21003\lib\net45\Microsoft.VisualStudio.Shell.Immutable.12.0.dll + + + ..\..\packages\Microsoft.VisualStudio.Shell.Immutable.14.0.14.3.25407\lib\net45\Microsoft.VisualStudio.Shell.Immutable.14.0.dll + + + ..\..\packages\Microsoft.VisualStudio.Shell.Interop.7.10.6071\lib\Microsoft.VisualStudio.Shell.Interop.dll + + + ..\..\packages\Microsoft.VisualStudio.Shell.Interop.8.0.8.0.50727\lib\Microsoft.VisualStudio.Shell.Interop.8.0.dll + + + ..\..\packages\Microsoft.VisualStudio.Shell.Interop.9.0.9.0.30729\lib\Microsoft.VisualStudio.Shell.Interop.9.0.dll + + + ..\..\packages\Microsoft.VisualStudio.TextManager.Interop.7.10.6070\lib\Microsoft.VisualStudio.TextManager.Interop.dll + + + ..\..\packages\Microsoft.VisualStudio.TextManager.Interop.8.0.8.0.50727\lib\Microsoft.VisualStudio.TextManager.Interop.8.0.dll + + + ..\..\packages\Microsoft.VisualStudio.Threading.14.1.111\lib\net45\Microsoft.VisualStudio.Threading.dll + + + ..\..\packages\Microsoft.VisualStudio.Utilities.14.3.25407\lib\net45\Microsoft.VisualStudio.Utilities.dll + + + ..\..\packages\Microsoft.VisualStudio.Validation.14.1.111\lib\net45\Microsoft.VisualStudio.Validation.dll + + + + ..\..\packages\stdole.7.0.3302\lib\net10\stdole.dll + True + + + + ..\..\packages\System.Collections.Immutable.1.4.0\lib\netstandard2.0\System.Collections.Immutable.dll + + + + ..\..\packages\System.Reflection.Metadata.1.5.0\lib\netstandard2.0\System.Reflection.Metadata.dll + + + + ..\..\packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll + True + True + + + + + + + + + ..\..\packages\VsixTesting.Xunit.0.1.4-beta\lib\net452\VsixTesting.dll + + + ..\..\packages\VsixTesting.Xunit.0.1.4-beta\lib\net452\VsixTesting.Xunit.dll + + + + ..\..\packages\xunit.abstractions.2.0.3\lib\net35\xunit.abstractions.dll + + + ..\..\packages\xunit.assert.2.4.1-pre.build.4059\lib\netstandard2.0\xunit.assert.dll + + + ..\..\packages\xunit.extensibility.core.2.4.1-pre.build.4059\lib\net452\xunit.core.dll + + + ..\..\packages\xunit.extensibility.execution.2.4.1-pre.build.4059\lib\net452\xunit.execution.desktop.dll + + + + + + + + + + {9aea02db-02b5-409c-b0ca-115d05331a6b} + GitHub.Exports + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + \ No newline at end of file diff --git a/test/IntegrationTests/Properties/AssemblyInfo.cs b/test/IntegrationTests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..6dc6c1479d --- /dev/null +++ b/test/IntegrationTests/Properties/AssemblyInfo.cs @@ -0,0 +1,39 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Xunit; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("IntegrationTests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("IntegrationTests")] +[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("bf6d17fe-15fd-401c-b5d7-de21837231f1")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] + +[assembly: TestFramework("Xunit.VsTestFramework", "VsixTesting.Xunit")] diff --git a/test/IntegrationTests/VSGitExtIntegrationTests.cs b/test/IntegrationTests/VSGitExtIntegrationTests.cs new file mode 100644 index 0000000000..0d69817640 --- /dev/null +++ b/test/IntegrationTests/VSGitExtIntegrationTests.cs @@ -0,0 +1,117 @@ +using EnvDTE; +using EnvDTE80; +using GitHub.Services; +using Microsoft.VisualStudio.ComponentModelHost; +using Microsoft.VisualStudio.Shell; +using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Xunit; +using Xunit.Abstractions; +using Task = System.Threading.Tasks.Task; + +namespace IntegrationTests +{ + public class VSGitExtIntegrationTests + { + public class TheActiveRepositoriesProperty + { + readonly ITestOutputHelper output; + + public TheActiveRepositoriesProperty(ITestOutputHelper output) + { + this.output = output; + } + + [VsFact(UIThread = true, Version = "2015-")] + public async Task SolutionNotOnGit_NoActiveRepositoriesAsync() + { + var dte = (DTE)ServiceProvider.GlobalProvider.GetService(typeof(DTE)); + var componentModel = (IComponentModel)await AsyncServiceProvider.GlobalProvider.GetServiceAsync(typeof(SComponentModel)); + var gitExt = componentModel.GetService(); + + dte.Solution.Open(@"C:\test\ClassLibraryNotInGit\ClassLibraryNotInGit.sln"); + Assert.True(await WaitForLocalPath(gitExt, null)); + } + + [VsFact(UIThread = true, Version = "2015-")] + public async Task ClassLibraryInGit_HasActiveRepositoriesAsync() + { + var dte = (DTE)ServiceProvider.GlobalProvider.GetService(typeof(DTE)); + var componentModel = (IComponentModel)await AsyncServiceProvider.GlobalProvider.GetServiceAsync(typeof(SComponentModel)); + var gitExt = componentModel.GetService(); + + dte.Solution.Open(@"C:\test\ClassLibraryInGit\ClassLibraryInGit.sln"); + Assert.True(await WaitForLocalPath(gitExt, @"C:\test\ClassLibraryInGit")); + } + + [VsFact(UIThread = true, Version = "2015-")] + public async Task OpenClassLibraryNotInGitThenClassLibraryInGit_ActiveRepositoriesChangesAsync() + { + var dte = (DTE)ServiceProvider.GlobalProvider.GetService(typeof(DTE)); + var componentModel = (IComponentModel)await AsyncServiceProvider.GlobalProvider.GetServiceAsync(typeof(SComponentModel)); + var gitExt = componentModel.GetService(); + + dte.Solution.Open(@"C:\test\ClassLibraryNotInGit\ClassLibraryNotInGit.sln"); + Assert.True(await WaitForLocalPath(gitExt, null)); + + dte.Solution.Open(@"C:\test\ClassLibraryInGit\ClassLibraryInGit.sln"); + Assert.True(await WaitForLocalPath(gitExt, @"C:\test\ClassLibraryInGit")); + + dte.Solution.Open(@"C:\test\ClassLibraryNotInGit\ClassLibraryNotInGit.sln"); + Assert.True(await WaitForLocalPath(gitExt, null)); + + dte.Solution.Open(@"C:\test\ClassLibraryInGit\ClassLibraryInGit.sln"); + Assert.True(await WaitForLocalPath(gitExt, @"C:\test\ClassLibraryInGit")); + } + + async Task AddSolutionToSourceControlAsync() + { + var dte = (DTE2)ServiceProvider.GlobalProvider.GetService(typeof(DTE)); + dte.ExecuteCommand("Team.Git.AddSolutionToSourceControl"); + await Task.Yield(); + } + + async Task CreateSolutionAsync() + { + var dte = (DTE2)ServiceProvider.GlobalProvider.GetService(typeof(DTE)); + var solution = (Solution2)dte.Solution; + var templatePath = solution.GetProjectTemplate("ClassLibrary.zip", "CSharp"); + var tempDir = Path.Combine(@"c:\test", Guid.NewGuid().ToString()); + var solutionPath = Path.Combine(tempDir, "test.sln"); + solution.Create(tempDir, "test"); + solution.AddFromTemplate(templatePath, tempDir, "MyClassLibrary", false); + solution.SaveAs(solutionPath); + output.WriteLine(solutionPath); + await Task.Yield(); + return (Solution)solution; + } + + Task WaitForLocalPath(IVSGitExt gitExt, string expectLocalPath) + { + return WaitFor(() => + { + var localPath = gitExt.ActiveRepositories.FirstOrDefault()?.LocalPath; + output.WriteLine($"found {localPath}, looking for {expectLocalPath}"); + return localPath == expectLocalPath; + }); + } + + async Task WaitFor(Func condition, int timeout = 20000, int delay = 100) + { + for (int count = 0; count < timeout; count += delay) + { + if (condition()) + { + return true; + } + + await Task.Delay(delay); + } + + return false; + } + } + } +} diff --git a/test/IntegrationTests/packages.config b/test/IntegrationTests/packages.config new file mode 100644 index 0000000000..5aeed15b65 --- /dev/null +++ b/test/IntegrationTests/packages.config @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file