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

Commit 0054884

Browse files
Merge pull request #2241 from YuPeiHenry/2126-empty-directory-when-clone-fails
Remove empty directory when clone fails
2 parents 8e90ce9 + 72c146d commit 0054884

File tree

3 files changed

+59
-58
lines changed

3 files changed

+59
-58
lines changed

src/GitHub.App/Services/RepositoryCloneService.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ public async Task CloneRepository(
224224
catch (Exception ex)
225225
{
226226
log.Error(ex, "Could not clone {CloneUrl} to {Path}", cloneUrl, repositoryPath);
227+
operatingSystem.Directory.DeleteDirectory(repositoryPath);
227228
throw;
228229
}
229230
}

test/GitHub.App.UnitTests/Services/RepositoryCloneServiceTests.cs

Lines changed: 54 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
1-
using System.Reactive.Linq;
1+
using System;
2+
using System.Linq.Expressions;
3+
using System.Reactive.Linq;
24
using System.Threading.Tasks;
5+
using GitHub.Api;
6+
using GitHub.Models;
7+
using GitHub.Services;
38
using NSubstitute;
49
using NUnit.Framework;
5-
using UnitTests;
6-
using GitHub.Services;
7-
using System.Linq.Expressions;
8-
using System;
9-
using GitHub.Models;
10+
using Rothko;
1011

1112
public class RepositoryCloneServiceTests
1213
{
13-
public class TheCloneRepositoryMethod : TestBaseClass
14+
public class TheCloneRepositoryMethod
1415
{
1516
[Test]
1617
public async Task ClonesToRepositoryPathAsync()
1718
{
18-
var serviceProvider = Substitutes.GetServiceProvider();
19-
var operatingSystem = serviceProvider.GetOperatingSystem();
20-
var vsGitServices = serviceProvider.GetVSGitServices();
21-
var cloneService = CreateRepositoryCloneService(serviceProvider);
19+
var operatingSystem = Substitute.For<IOperatingSystem>();
20+
var vsGitServices = Substitute.For<IVSGitServices>();
21+
var cloneService = CreateRepositoryCloneService(operatingSystem, vsGitServices);
2222

2323
await cloneService.CloneRepository("https://github.com/foo/bar", @"c:\dev\bar");
2424

@@ -34,9 +34,9 @@ public async Task ClonesToRepositoryPathAsync()
3434
[TestCase("https://enterprise.com/foo/bar", 0, nameof(UsageModel.MeasuresModel.NumberOfGitHubClones))]
3535
public async Task UpdatesMetricsWhenRepositoryClonedAsync(string cloneUrl, int numberOfCalls, string counterName)
3636
{
37-
var serviceProvider = Substitutes.GetServiceProvider();
38-
var usageTracker = serviceProvider.GetUsageTracker();
39-
var cloneService = CreateRepositoryCloneService(serviceProvider);
37+
var vsGitServices = Substitute.For<IVSGitServices>();
38+
var usageTracker = Substitute.For<IUsageTracker>();
39+
var cloneService = CreateRepositoryCloneService(vsGitServices: vsGitServices, usageTracker: usageTracker);
4040

4141
await cloneService.CloneRepository(cloneUrl, @"c:\dev\bar");
4242
var model = UsageModel.Create(Guid.NewGuid());
@@ -58,8 +58,9 @@ public async Task Skip_OpenRepository_When_Already_Open(string repositoryPath, s
5858
{
5959
var repositoryUrl = "https://github.com/owner/repo";
6060
var cloneDialogResult = new CloneDialogResult(repositoryPath, repositoryUrl);
61-
var serviceProvider = Substitutes.GetServiceProvider();
62-
var operatingSystem = serviceProvider.GetOperatingSystem();
61+
var operatingSystem = Substitute.For<IOperatingSystem>();
62+
var serviceProvider = Substitute.For<IGitHubServiceProvider>();
63+
var teamExplorerServices = Substitute.For<ITeamExplorerServices>();
6364
operatingSystem.Directory.DirectoryExists(repositoryPath).Returns(true);
6465
var dte = Substitute.For<EnvDTE.DTE>();
6566
serviceProvider.GetService<EnvDTE.DTE>().Returns(dte);
@@ -68,11 +69,11 @@ public async Task Skip_OpenRepository_When_Already_Open(string repositoryPath, s
6869
{
6970
operatingSystem.Directory.DirectoryExists(solutionPath).Returns(true);
7071
}
71-
var cloneService = CreateRepositoryCloneService(serviceProvider);
72+
var cloneService = CreateRepositoryCloneService(operatingSystem: operatingSystem,
73+
teamExplorerServices: teamExplorerServices, serviceProvider: serviceProvider);
7274

7375
await cloneService.CloneOrOpenRepository(cloneDialogResult);
7476

75-
var teamExplorerServices = serviceProvider.GetTeamExplorerServices();
7677
teamExplorerServices.Received(openRepository).OpenRepository(repositoryPath);
7778
}
7879

@@ -91,11 +92,10 @@ public async Task UpdatesMetricsWhenCloneOrOpenRepositoryAsync(string cloneUrl,
9192
{
9293
var repositoryPath = @"c:\dev\bar";
9394
var cloneDialogResult = new CloneDialogResult(repositoryPath, cloneUrl);
94-
var serviceProvider = Substitutes.GetServiceProvider();
95-
var operatingSystem = serviceProvider.GetOperatingSystem();
95+
var operatingSystem = Substitute.For<IOperatingSystem>();
96+
var usageTracker = Substitute.For<IUsageTracker>();
9697
operatingSystem.Directory.DirectoryExists(repositoryPath).Returns(dirExists);
97-
var usageTracker = serviceProvider.GetUsageTracker();
98-
var cloneService = CreateRepositoryCloneService(serviceProvider);
98+
var cloneService = CreateRepositoryCloneService(operatingSystem: operatingSystem, usageTracker: usageTracker);
9999

100100
await cloneService.CloneOrOpenRepository(cloneDialogResult);
101101

@@ -108,11 +108,10 @@ await usageTracker.Received(numberOfCalls).IncrementCounter(
108108
[TestCase(@"c:\not_default\repo", @"c:\default", 0, nameof(UsageModel.MeasuresModel.NumberOfClonesToDefaultClonePath))]
109109
public async Task UpdatesMetricsWhenDefaultClonePath(string targetPath, string defaultPath, int numberOfCalls, string counterName)
110110
{
111-
var serviceProvider = Substitutes.GetServiceProvider();
112-
var vsGitServices = serviceProvider.GetVSGitServices();
111+
var vsGitServices = Substitute.For<IVSGitServices>();
113112
vsGitServices.GetLocalClonePathFromGitProvider().Returns(defaultPath);
114-
var usageTracker = serviceProvider.GetUsageTracker();
115-
var cloneService = CreateRepositoryCloneService(serviceProvider);
113+
var usageTracker = Substitute.For<IUsageTracker>();
114+
var cloneService = CreateRepositoryCloneService(usageTracker: usageTracker, vsGitServices: vsGitServices);
116115

117116
await cloneService.CloneRepository("https://github.com/foo/bar", targetPath);
118117
var model = UsageModel.Create(Guid.NewGuid());
@@ -122,10 +121,36 @@ await usageTracker.Received(numberOfCalls).IncrementCounter(
122121
((MemberExpression)x.Body).Member.Name == counterName));
123122
}
124123

125-
static RepositoryCloneService CreateRepositoryCloneService(IGitHubServiceProvider sp)
124+
[TestCase("https://github.com/failing/url", @"c:\dev\bar")]
125+
public async Task CleansDirectoryOnCloneFailed(string cloneUrl, string clonePath)
126126
{
127-
return new RepositoryCloneService(sp.GetOperatingSystem(), sp.GetVSGitServices(), sp.GetTeamExplorerServices(),
128-
sp.GetGraphQLClientFactory(), sp.GetGitHubContextService(), sp.GetUsageTracker(), sp);
127+
var operatingSystem = Substitute.For<IOperatingSystem>();
128+
var vsGitServices = Substitute.For<IVSGitServices>();
129+
vsGitServices.Clone(cloneUrl, clonePath, true).Returns(x => { throw new Exception(); });
130+
var cloneService = CreateRepositoryCloneService(operatingSystem: operatingSystem, vsGitServices: vsGitServices);
131+
132+
Assert.ThrowsAsync<Exception>(() => cloneService.CloneRepository(cloneUrl, clonePath));
133+
134+
operatingSystem.Directory.Received().CreateDirectory(clonePath);
135+
operatingSystem.Directory.Received().DeleteDirectory(clonePath);
136+
await vsGitServices.Received().Clone(cloneUrl, clonePath, true);
137+
}
138+
139+
static RepositoryCloneService CreateRepositoryCloneService(IOperatingSystem operatingSystem = null,
140+
IVSGitServices vsGitServices = null, IUsageTracker usageTracker = null,
141+
ITeamExplorerServices teamExplorerServices = null, IGitHubServiceProvider serviceProvider = null)
142+
{
143+
operatingSystem = operatingSystem ?? Substitute.For<IOperatingSystem>();
144+
vsGitServices = vsGitServices ?? Substitute.For<IVSGitServices>();
145+
usageTracker = usageTracker ?? Substitute.For<IUsageTracker>();
146+
teamExplorerServices = teamExplorerServices ?? Substitute.For<ITeamExplorerServices>();
147+
serviceProvider = serviceProvider ?? Substitute.For<IGitHubServiceProvider>();
148+
149+
operatingSystem.Environment.ExpandEnvironmentVariables(Args.String).Returns(x => x[0]);
150+
151+
return new RepositoryCloneService(operatingSystem, vsGitServices, teamExplorerServices,
152+
Substitute.For<IGraphQLClientFactory>(), Substitute.For<IGitHubContextService>(),
153+
usageTracker, serviceProvider);
129154
}
130155
}
131156
}

test/GitHub.App.UnitTests/Substitutes.cs

Lines changed: 4 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -30,32 +30,8 @@ public static T1 For<T1, T2, T3, T4>(params object[] constructorArguments)
3030
}, constructorArguments);
3131
}
3232

33-
34-
// public static IGitRepositoriesExt IGitRepositoriesExt { get { return Substitute.For<IGitRepositoriesExt>(); } }
3533
public static IGitService IGitService { get { return Substitute.For<IGitService>(); } }
3634

37-
public static IVSGitServices IVSGitServices
38-
{
39-
get
40-
{
41-
var ret = Substitute.For<IVSGitServices>();
42-
ret.GetLocalClonePathFromGitProvider().Returns(@"c:\foo\bar");
43-
return ret;
44-
}
45-
}
46-
47-
public static IOperatingSystem OperatingSystem
48-
{
49-
get
50-
{
51-
var ret = Substitute.For<IOperatingSystem>();
52-
// this expansion happens when the GetLocalClonePathFromGitProvider call is setup by default
53-
// see IVSServices property above
54-
ret.Environment.ExpandEnvironmentVariables(Args.String).Returns(x => x[0]);
55-
return ret;
56-
}
57-
}
58-
5935
public static IViewViewModelFactory ViewViewModelFactory { get { return Substitute.For<IViewViewModelFactory>(); } }
6036

6137
public static IRepositoryCreationService RepositoryCreationService { get { return Substitute.For<IRepositoryCreationService>(); } }
@@ -109,9 +85,8 @@ public static IGitHubServiceProvider GetServiceProvider(
10985
ret.GetService(typeof(SComponentModel)).Returns(cm);
11086
Services.UnitTestServiceProvider = ret;
11187

112-
var os = OperatingSystem;
113-
var vsgit = IVSGitServices;
114-
var clone = cloneService ?? new RepositoryCloneService(os, vsgit, Substitute.For<ITeamExplorerServices>(),
88+
var clone = cloneService ?? new RepositoryCloneService(Substitute.For<IOperatingSystem>(),
89+
Substitute.For<IVSGitServices>(), Substitute.For<ITeamExplorerServices>(),
11590
Substitute.For<IGraphQLClientFactory>(), Substitute.For<IGitHubContextService>(),
11691
Substitute.For<IUsageTracker>(), ret);
11792
var create = creationService ?? new RepositoryCreationService(clone);
@@ -123,8 +98,8 @@ public static IGitHubServiceProvider GetServiceProvider(
12398
ret.GetService(typeof(IGitHubContextService)).Returns(Substitute.For<IGitHubContextService>());
12499
ret.GetService(typeof(IVSGitExt)).Returns(Substitute.For<IVSGitExt>());
125100
ret.GetService(typeof(IUsageTracker)).Returns(Substitute.For<IUsageTracker>());
126-
ret.GetService(typeof(IVSGitServices)).Returns(vsgit);
127-
ret.GetService(typeof(IOperatingSystem)).Returns(os);
101+
ret.GetService(typeof(IVSGitServices)).Returns(Substitute.For<IVSGitServices>());
102+
ret.GetService(typeof(IOperatingSystem)).Returns(Substitute.For<IOperatingSystem>());
128103
ret.GetService(typeof(IRepositoryCloneService)).Returns(clone);
129104
ret.GetService(typeof(IRepositoryCreationService)).Returns(create);
130105
ret.GetService(typeof(IViewViewModelFactory)).Returns(ViewViewModelFactory);

0 commit comments

Comments
 (0)