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

Commit 762d6cf

Browse files
authored
Merge pull request #2436 from github/feature/open-from-url-active-repo
Make GitHub.OpenFromUrl command use active repository when possible
2 parents 5c41bb8 + 89eabbd commit 762d6cf

File tree

2 files changed

+112
-3
lines changed

2 files changed

+112
-3
lines changed

src/GitHub.VisualStudio/Commands/OpenFromUrlCommand.cs

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using System;
22
using System.ComponentModel.Composition;
33
using GitHub.Commands;
4+
using GitHub.Models;
5+
using GitHub.Primitives;
46
using GitHub.Services;
57
using GitHub.Services.Vssdk.Commands;
68
using Task = System.Threading.Tasks.Task;
@@ -12,6 +14,8 @@ public class OpenFromUrlCommand : VsCommand<string>, IOpenFromUrlCommand
1214
{
1315
readonly Lazy<IDialogService> dialogService;
1416
readonly Lazy<IRepositoryCloneService> repositoryCloneService;
17+
readonly Lazy<ITeamExplorerContext> teamExplorerContext;
18+
readonly Lazy<IGitHubContextService> gitHubContextService;
1519

1620
/// <summary>
1721
/// Gets the GUID of the group the command belongs to.
@@ -26,23 +30,57 @@ public class OpenFromUrlCommand : VsCommand<string>, IOpenFromUrlCommand
2630
[ImportingConstructor]
2731
public OpenFromUrlCommand(
2832
Lazy<IDialogService> dialogService,
29-
Lazy<IRepositoryCloneService> repositoryCloneService) :
33+
Lazy<IRepositoryCloneService> repositoryCloneService,
34+
Lazy<ITeamExplorerContext> teamExplorerContext,
35+
Lazy<IGitHubContextService> gitHubContextService) :
3036
base(CommandSet, CommandId)
3137
{
3238
this.dialogService = dialogService;
3339
this.repositoryCloneService = repositoryCloneService;
40+
this.teamExplorerContext = teamExplorerContext;
41+
this.gitHubContextService = gitHubContextService;
3442

3543
// See https://code.msdn.microsoft.com/windowsdesktop/AllowParams-2005-9442298f
3644
ParametersDescription = "u"; // accept a single url
3745
}
3846

39-
public override async Task Execute(string url)
47+
public override async Task Execute(string targetUrl)
4048
{
41-
var cloneDialogResult = await dialogService.Value.ShowCloneDialog(null, url);
49+
if (targetUrl != null)
50+
{
51+
// Navigate to to active repository when same as target
52+
if (FindActiveRepositoryDir(targetUrl) is string repositoryDir)
53+
{
54+
// Navigate to context for supported URL types (e.g. /blob/ URLs)
55+
if (gitHubContextService.Value.FindContextFromUrl(targetUrl) is GitHubContext context)
56+
{
57+
gitHubContextService.Value.TryNavigateToContext(repositoryDir, context);
58+
return;
59+
}
60+
}
61+
}
62+
63+
var cloneDialogResult = await dialogService.Value.ShowCloneDialog(null, targetUrl);
4264
if (cloneDialogResult != null)
4365
{
4466
await repositoryCloneService.Value.CloneOrOpenRepository(cloneDialogResult);
4567
}
4668
}
69+
70+
string FindActiveRepositoryDir(UriString targetUrl)
71+
{
72+
if (teamExplorerContext.Value.ActiveRepository is LocalRepositoryModel activeRepository)
73+
{
74+
if (activeRepository.CloneUrl is UriString activeUrl)
75+
{
76+
if (UriString.RepositoryUrlsAreEqual(activeUrl, targetUrl))
77+
{
78+
return activeRepository.LocalPath;
79+
}
80+
}
81+
}
82+
83+
return null;
84+
}
4785
}
4886
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using GitHub.Models;
4+
using GitHub.Services;
5+
using GitHub.VisualStudio.Commands;
6+
using NSubstitute;
7+
using NUnit.Framework;
8+
9+
public static class OpenFromUrlCommandTests
10+
{
11+
public class TheExecuteMethod
12+
{
13+
[Test]
14+
public async Task Executed_From_Menu()
15+
{
16+
var target = CreateOpenFromUrlCommand();
17+
18+
await target.Execute(null);
19+
}
20+
21+
[Test]
22+
public async Task Executed_From_Command_Window()
23+
{
24+
var target = CreateOpenFromUrlCommand();
25+
26+
await target.Execute("");
27+
}
28+
29+
[TestCase("https://github.com/github/visualstudio", null, null, 0, 1, Description = "No active repository")]
30+
[TestCase("https://github.com/github/visualstudio", null, @"c:\source\visualstudio", 0, 1, Description = "Active repository with no remote")]
31+
[TestCase("https://github.com/github/visualstudio", "https://github.com/github/visualstudio", @"c:\source\visualstudio", 1, 0, Description = "Matching active repository")]
32+
[TestCase("HTTPS://GITHUB.COM/GITHUB/VISUALSTUDIO", "https://github.com/github/visualstudio", @"c:\source\visualstudio", 1, 0, Description = "Matching active repository with different case")]
33+
[TestCase("https://github.com/jcansdale/visualstudio", "https://github.com/github/visualstudio", @"c:\source\visualstudio", 0, 1, Description = "Fork of target repository")]
34+
[TestCase("https://github.com/owner1/repo1", "https://github.com/owner2/repo2", @"c:\source", 0, 1, Description = "Different repository")]
35+
public async Task Execute(string url, string activeUrl, string activePath, int tryNavigateToContextCalls, int showCloneDialogCalls)
36+
{
37+
var dialogService = Substitute.For<IDialogService>();
38+
var teamExplorerContext = Substitute.For<ITeamExplorerContext>();
39+
var activeRepository = new LocalRepositoryModel { CloneUrl = activeUrl, LocalPath = activePath };
40+
teamExplorerContext.ActiveRepository.Returns(activeRepository);
41+
var gitHubContextService = Substitute.For<IGitHubContextService>();
42+
gitHubContextService.FindContextFromUrl(url).Returns(new GitHubContext());
43+
dialogService.ShowCloneDialog(null, url).Returns(new CloneDialogResult(@"c:\source", url));
44+
var target = CreateOpenFromUrlCommand(dialogService: dialogService,
45+
teamExplorerContext: teamExplorerContext, gitHubContextService: gitHubContextService);
46+
47+
await target.Execute(url);
48+
49+
gitHubContextService.ReceivedWithAnyArgs(tryNavigateToContextCalls).TryNavigateToContext(null, null);
50+
await dialogService.ReceivedWithAnyArgs(showCloneDialogCalls).ShowCloneDialog(null, null);
51+
}
52+
}
53+
54+
static OpenFromUrlCommand CreateOpenFromUrlCommand(
55+
IDialogService dialogService = null,
56+
IRepositoryCloneService repositoryCloneService = null,
57+
ITeamExplorerContext teamExplorerContext = null,
58+
IGitHubContextService gitHubContextService = null)
59+
{
60+
dialogService = dialogService ?? Substitute.For<IDialogService>();
61+
repositoryCloneService = repositoryCloneService ?? Substitute.For<IRepositoryCloneService>();
62+
teamExplorerContext = teamExplorerContext ?? Substitute.For<ITeamExplorerContext>();
63+
gitHubContextService = gitHubContextService ?? Substitute.For<IGitHubContextService>();
64+
65+
return new OpenFromUrlCommand(
66+
new Lazy<IDialogService>(() => dialogService),
67+
new Lazy<IRepositoryCloneService>(() => repositoryCloneService),
68+
new Lazy<ITeamExplorerContext>(() => teamExplorerContext),
69+
new Lazy<IGitHubContextService>(() => gitHubContextService));
70+
}
71+
}

0 commit comments

Comments
 (0)