зеркало из https://github.com/github/VisualStudio.git
Merge branch 'master' into fixes/823-pr-list-crash
This commit is contained in:
Коммит
2935efe9e9
|
@ -0,0 +1,3 @@
|
|||
@set PATH=%ProgramFiles(x86)%\Microsoft Visual Studio 14.0\Common7\IDE;%PATH%
|
||||
vsixinstaller /q /u:"c3d3dc68-c977-411f-b3e8-03b0dccf7dfc"
|
||||
vsixinstaller "%cd%\build\Debug\GitHub.VisualStudio.vsix"
|
|
@ -244,6 +244,10 @@
|
|||
<Project>{08dd4305-7787-4823-a53f-4d0f725a07f3}</Project>
|
||||
<Name>Octokit</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\submodules\Rothko\src\Rothko.csproj">
|
||||
<Project>{4A84E568-CA86-4510-8CD0-90D3EF9B65F9}</Project>
|
||||
<Name>Rothko</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\GitHub.Extensions\GitHub.Extensions.csproj">
|
||||
<Project>{6afe2e2d-6db0-4430-a2ea-f5f5388d2f78}</Project>
|
||||
<Name>GitHub.Extensions</Name>
|
||||
|
|
|
@ -10,5 +10,6 @@ namespace GitHub.Services
|
|||
void ActivityLogMessage(string message);
|
||||
void ActivityLogWarning(string message);
|
||||
void ActivityLogError(string message);
|
||||
bool TryOpenRepository(string directory);
|
||||
}
|
||||
}
|
|
@ -4,7 +4,6 @@ using EnvDTE80;
|
|||
using GitHub.Info;
|
||||
using GitHub.Primitives;
|
||||
using GitHub.Services;
|
||||
using LibGit2Sharp;
|
||||
using Microsoft.VisualStudio;
|
||||
using Microsoft.VisualStudio.ComponentModelHost;
|
||||
using Microsoft.VisualStudio.Shell.Interop;
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Globalization;
|
||||
using GitHub.VisualStudio;
|
||||
using Microsoft.VisualStudio;
|
||||
using Microsoft.VisualStudio.Shell.Interop;
|
||||
using System.Linq;
|
||||
using DTE = EnvDTE.DTE;
|
||||
using Rothko;
|
||||
|
||||
namespace GitHub.Services
|
||||
{
|
||||
|
@ -16,6 +17,10 @@ namespace GitHub.Services
|
|||
{
|
||||
readonly IGitHubServiceProvider serviceProvider;
|
||||
|
||||
// Use a prefix (~$) that is defined in the default VS gitignore.
|
||||
public const string TempSolutionName = "~$GitHubVSTemp$~";
|
||||
|
||||
|
||||
[ImportingConstructor]
|
||||
public VSServices(IGitHubServiceProvider serviceProvider)
|
||||
{
|
||||
|
@ -68,6 +73,73 @@ namespace GitHub.Services
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>Open a repository in Team Explorer</summary>
|
||||
/// <remarks>
|
||||
/// There doesn't appear to be a command that directly opens a target repo.
|
||||
/// Our workaround is to create, open and delete a solution in the repo directory.
|
||||
/// This triggers an event that causes the target repo to open. ;)
|
||||
/// </remarks>
|
||||
/// <param name="repoPath">The path to the repository to open</param>
|
||||
/// <returns>True if a transient solution was successfully created in target directory (which should trigger opening of repository).</returns>
|
||||
public bool TryOpenRepository(string repoPath)
|
||||
{
|
||||
var os = serviceProvider.TryGetService<IOperatingSystem>();
|
||||
if (os == null)
|
||||
{
|
||||
VsOutputLogger.WriteLine("TryOpenRepository couldn't find IOperatingSystem service.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var dte = serviceProvider.TryGetService<DTE>();
|
||||
if (dte == null)
|
||||
{
|
||||
VsOutputLogger.WriteLine("TryOpenRepository couldn't find DTE service.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var repoDir = os.Directory.GetDirectory(repoPath);
|
||||
if(!repoDir.Exists)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool solutionCreated = false;
|
||||
try
|
||||
{
|
||||
dte.Solution.Create(repoPath, TempSolutionName);
|
||||
solutionCreated = true;
|
||||
|
||||
dte.Solution.Close(false); // Don't create a .sln file when we close.
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
VsOutputLogger.WriteLine("Error opening repository. {0}", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
TryCleanupSolutionUserFiles(os, repoPath, TempSolutionName);
|
||||
}
|
||||
return solutionCreated;
|
||||
}
|
||||
|
||||
void TryCleanupSolutionUserFiles(IOperatingSystem os, string repoPath, string slnName)
|
||||
{
|
||||
var vsTempPath = Path.Combine(repoPath, ".vs", slnName);
|
||||
try
|
||||
{
|
||||
// Clean up the dummy solution's subdirectory inside `.vs`.
|
||||
var vsTempDir = os.Directory.GetDirectory(vsTempPath);
|
||||
if (vsTempDir.Exists)
|
||||
{
|
||||
vsTempDir.Delete(true);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
VsOutputLogger.WriteLine("Couldn't clean up {0}. {1}", vsTempPath, e);
|
||||
}
|
||||
}
|
||||
|
||||
const string RegistryRootKey = @"Software\Microsoft\VisualStudio";
|
||||
const string EnvVersionKey = "EnvVersion";
|
||||
string GetVSVersion()
|
||||
|
|
|
@ -25,10 +25,12 @@ namespace GitHub.VisualStudio.TeamExplorer.Connect
|
|||
{
|
||||
public class GitHubConnectSection : TeamExplorerSectionBase, IGitHubConnectSection
|
||||
{
|
||||
readonly IPackageSettings packageSettings;
|
||||
readonly IVSServices vsServices;
|
||||
readonly int sectionIndex;
|
||||
|
||||
bool isCloning;
|
||||
bool isCreating;
|
||||
IPackageSettings packageSettings;
|
||||
GitHubConnectSectionState settings;
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")]
|
||||
|
@ -92,6 +94,7 @@ namespace GitHub.VisualStudio.TeamExplorer.Connect
|
|||
ITeamExplorerServiceHolder holder,
|
||||
IConnectionManager manager,
|
||||
IPackageSettings packageSettings,
|
||||
IVSServices vsServices,
|
||||
int index)
|
||||
: base(serviceProvider, apiFactory, holder, manager)
|
||||
{
|
||||
|
@ -102,6 +105,7 @@ namespace GitHub.VisualStudio.TeamExplorer.Connect
|
|||
sectionIndex = index;
|
||||
|
||||
this.packageSettings = packageSettings;
|
||||
this.vsServices = vsServices;
|
||||
|
||||
connectionManager.Connections.CollectionChanged += RefreshConnections;
|
||||
PropertyChanged += OnPropertyChange;
|
||||
|
@ -344,22 +348,23 @@ namespace GitHub.VisualStudio.TeamExplorer.Connect
|
|||
public bool OpenRepository()
|
||||
{
|
||||
var old = Repositories.FirstOrDefault(x => x.Equals(Holder.ActiveRepo));
|
||||
// open the solution selection dialog when the user wants to switch to a different repo
|
||||
// since there's no other way of changing the source control context in VS
|
||||
if (!Equals(SelectedRepository, old))
|
||||
{
|
||||
if (ErrorHandler.Succeeded(ServiceProvider.GetSolution().OpenSolutionViaDlg(SelectedRepository.LocalPath, 1)))
|
||||
var opened = vsServices.TryOpenRepository(SelectedRepository.LocalPath);
|
||||
if (!opened)
|
||||
{
|
||||
ServiceProvider.TryGetService<ITeamExplorer>()?.NavigateToPage(new Guid(TeamExplorerPageIds.Home), null);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedRepository = old;
|
||||
return false;
|
||||
// TryOpenRepository might fail because dir no longer exists. Let user find solution themselves.
|
||||
opened = ErrorHandler.Succeeded(ServiceProvider.GetSolution().OpenSolutionViaDlg(SelectedRepository.LocalPath, 1));
|
||||
if (!opened)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
// Navigate away when we're on the correct source control contexts.
|
||||
ServiceProvider.TryGetService<ITeamExplorer>()?.NavigateToPage(new Guid(TeamExplorerPageIds.Home), null);
|
||||
return true;
|
||||
}
|
||||
|
||||
void StartFlow(UIControllerFlow controllerFlow)
|
||||
|
|
|
@ -18,8 +18,9 @@ namespace GitHub.VisualStudio.TeamExplorer.Connect
|
|||
ISimpleApiClientFactory apiFactory,
|
||||
ITeamExplorerServiceHolder holder,
|
||||
IConnectionManager manager,
|
||||
IPackageSettings settings)
|
||||
: base(serviceProvider, apiFactory, holder, manager, settings, 0)
|
||||
IPackageSettings settings,
|
||||
IVSServices vsServices)
|
||||
: base(serviceProvider, apiFactory, holder, manager, settings, vsServices, 0)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,8 +18,9 @@ namespace GitHub.VisualStudio.TeamExplorer.Connect
|
|||
ISimpleApiClientFactory apiFactory,
|
||||
ITeamExplorerServiceHolder holder,
|
||||
IConnectionManager manager,
|
||||
IPackageSettings settings)
|
||||
: base(serviceProvider, apiFactory, holder, manager, settings, 1)
|
||||
IPackageSettings settings,
|
||||
IVSServices vsServices)
|
||||
: base(serviceProvider, apiFactory, holder, manager, settings, vsServices, 1)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,112 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using GitHub.Services;
|
||||
using Microsoft.TeamFoundation.Git.Controls.Extensibility;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
using DTE = EnvDTE.DTE;
|
||||
using Rothko;
|
||||
|
||||
public class VSServicesTests
|
||||
{
|
||||
public class TheTryOpenRepositoryMethod : TestBaseClass
|
||||
{
|
||||
[Fact]
|
||||
public void NoExceptions_ReturnsTrue()
|
||||
{
|
||||
var repoDir = @"x:\repo";
|
||||
var target = CreateVSServices(repoDir);
|
||||
|
||||
var success = target.TryOpenRepository(repoDir);
|
||||
|
||||
Assert.True(success);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SolutionCreateThrows_ReturnsFalse()
|
||||
{
|
||||
var repoDir = @"x:\repo";
|
||||
var dte = Substitute.For<DTE>();
|
||||
dte.Solution.When(s => s.Create(Arg.Any<string>(), Arg.Any<string>())).Do(
|
||||
ci => { throw new COMException(); });
|
||||
var target = CreateVSServices(repoDir, dte: dte);
|
||||
|
||||
var success = target.TryOpenRepository("");
|
||||
|
||||
Assert.False(success);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RepoDirExistsFalse_ReturnFalse()
|
||||
{
|
||||
var repoDir = @"x:\repo";
|
||||
var os = Substitute.For<IOperatingSystem>();
|
||||
//var directoryInfo = Substitute.For<IDirectoryInfo>();
|
||||
//directoryInfo.Exists.Returns(false);
|
||||
//os.Directory.GetDirectory(repoDir).Returns(directoryInfo);
|
||||
var target = CreateVSServices(null, os: os);
|
||||
|
||||
var success = target.TryOpenRepository(repoDir);
|
||||
|
||||
Assert.False(success);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DeleteThrowsIOException_ReturnTrue()
|
||||
{
|
||||
var repoDir = @"x:\repo";
|
||||
var tempDir = Path.Combine(repoDir, ".vs", VSServices.TempSolutionName);
|
||||
var os = Substitute.For<IOperatingSystem>();
|
||||
var directoryInfo = Substitute.For<IDirectoryInfo>();
|
||||
directoryInfo.Exists.Returns(true);
|
||||
os.Directory.GetDirectory(tempDir).Returns(directoryInfo);
|
||||
directoryInfo.When(di => di.Delete(true)).Do(
|
||||
ci => { throw new IOException(); });
|
||||
var target = CreateVSServices(repoDir, os: os);
|
||||
|
||||
var success = target.TryOpenRepository(repoDir);
|
||||
|
||||
Assert.True(success);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SolutionCreate_DeleteVsSolutionSubdir()
|
||||
{
|
||||
var repoDir = @"x:\repo";
|
||||
var tempDir = Path.Combine(repoDir, ".vs", VSServices.TempSolutionName);
|
||||
var os = Substitute.For<IOperatingSystem>();
|
||||
var directoryInfo = Substitute.For<IDirectoryInfo>();
|
||||
directoryInfo.Exists.Returns(true);
|
||||
os.Directory.GetDirectory(tempDir).Returns(directoryInfo);
|
||||
var target = CreateVSServices(repoDir, os: os);
|
||||
|
||||
var success = target.TryOpenRepository(repoDir);
|
||||
|
||||
directoryInfo.Received().Delete(true);
|
||||
}
|
||||
|
||||
VSServices CreateVSServices(string repoDir, IOperatingSystem os = null, DTE dte = null)
|
||||
{
|
||||
os = os ?? Substitute.For<IOperatingSystem>();
|
||||
dte = dte ?? Substitute.For<DTE>();
|
||||
|
||||
if (repoDir != null)
|
||||
{
|
||||
var directoryInfo = Substitute.For<IDirectoryInfo>();
|
||||
directoryInfo.Exists.Returns(true);
|
||||
os.Directory.GetDirectory(repoDir).Returns(directoryInfo);
|
||||
}
|
||||
|
||||
var provider = Substitute.For<IGitHubServiceProvider>();
|
||||
provider.TryGetService<DTE>().Returns(dte);
|
||||
provider.TryGetService<IOperatingSystem>().Returns(os);
|
||||
return new VSServices(provider);
|
||||
}
|
||||
}
|
||||
|
||||
public class TheCloneMethod : TestBaseClass
|
||||
{
|
||||
/*
|
||||
[Theory]
|
||||
[InlineData(true, CloneOptions.RecurseSubmodule)]
|
||||
[InlineData(false, CloneOptions.None)]
|
||||
|
@ -24,5 +123,6 @@ public class VSServicesTests
|
|||
gitRepositoriesExt.Received()
|
||||
.Clone("https://github.com/github/visualstudio", @"c:\fake\ghfvs", expectedCloneOptions);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,9 @@
|
|||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="envdte, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<EmbedInteropTypes>False</EmbedInteropTypes>
|
||||
</Reference>
|
||||
<Reference Include="LibGit2Sharp, Version=0.22.0.0, Culture=neutral, PublicKeyToken=7cbde695407f0333, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\LibGit2Sharp.0.22.0\lib\net40\LibGit2Sharp.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
|
@ -238,7 +241,7 @@
|
|||
<Compile Include="GitHub.App\ViewModels\RepositoryPublishViewModelTests.cs" />
|
||||
<Compile Include="GitHub.Exports.Reactive\Caches\AccountCacheItemTests.cs" />
|
||||
<Compile Include="GitHub.Exports\GitServiceTests.cs" />
|
||||
<None Include="GitHub.Exports\VSServicesTests.cs" />
|
||||
<Compile Include="GitHub.Exports\VSServicesTests.cs" />
|
||||
<Compile Include="GitHub.Exports\HostAddressTests.cs" />
|
||||
<Compile Include="GitHub.Exports\LocalRepositoryModelTests.cs" />
|
||||
<Compile Include="GitHub.Extensions\GuardTests.cs" />
|
||||
|
|
Загрузка…
Ссылка в новой задаче