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

Commit b872d48

Browse files
committed
Merge pull request #105 from github/shana/fix-gitservice-null
Fix IGitService
2 parents 6397fbd + be83fce commit b872d48

File tree

8 files changed

+125
-90
lines changed

8 files changed

+125
-90
lines changed

src/GitHub.Exports/Extensions/GitHelpers.cs

Lines changed: 0 additions & 46 deletions
This file was deleted.

src/GitHub.Exports/Extensions/SimpleRepositoryModelExtensions.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.IO;
44
using GitHub.Models;
55
using Microsoft.VisualStudio.TeamFoundation.Git.Extensibility;
6+
using GitHub.Services;
67

78
namespace GitHub.Extensions
89
{
@@ -18,7 +19,7 @@ public static ISimpleRepositoryModel ToModel(this IGitRepositoryInfo repo)
1819

1920
public static bool HasCommits(this ISimpleRepositoryModel repository)
2021
{
21-
var repo = VisualStudio.Services.IGitService.GetRepo(repository.LocalPath);
22+
var repo = GitService.GitServiceHelper.GetRepo(repository.LocalPath);
2223
return repo?.Commits.Any() ?? false;
2324
}
2425

src/GitHub.Exports/GitHub.Exports.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,6 @@
9999
<None Include="..\..\script\Key.snk" Condition="$(Buildtype) == 'Internal'">
100100
<Link>Key.snk</Link>
101101
</None>
102-
<Compile Include="Extensions\GitHelpers.cs" />
103102
<Compile Include="Helpers\INotifyPropertySource.cs" />
104103
<Compile Include="Extensions\PropertyNotifierExtensions.cs" />
105104
<Compile Include="Extensions\SimpleRepositoryModelExtensions.cs" />

src/GitHub.Exports/Models/SimpleRepositoryModel.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using GitHub.Primitives;
66
using GitHub.UI;
77
using GitHub.VisualStudio.Helpers;
8+
using GitHub.Services;
89

910
namespace GitHub.Models
1011
{
@@ -26,7 +27,7 @@ public SimpleRepositoryModel(string path)
2627
var dir = new DirectoryInfo(path);
2728
if (!dir.Exists)
2829
throw new ArgumentException("Path does not exist", nameof(path));
29-
var uri = VisualStudio.Services.IGitService.GetUri(path);
30+
var uri = GitService.GitServiceHelper.GetUri(path);
3031
var name = uri?.NameWithOwner ?? dir.Name;
3132
Name = name;
3233
LocalPath = path;
@@ -47,7 +48,7 @@ public void Refresh()
4748
{
4849
if (LocalPath == null)
4950
return;
50-
var uri = VisualStudio.Services.IGitService.GetUri(LocalPath);
51+
var uri = GitService.GitServiceHelper.GetUri(LocalPath);
5152
if (CloneUrl != uri)
5253
CloneUrl = uri;
5354
}

src/GitHub.Exports/Services/GitService.cs

Lines changed: 90 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,52 +7,93 @@
77

88
namespace GitHub.Services
99
{
10-
[Export(typeof(IVSServices))]
11-
[PartCreationPolicy(CreationPolicy.Shared)]
10+
[Export(typeof(IGitService))]
11+
[PartCreationPolicy(CreationPolicy.NonShared)]
1212
public class GitService : IGitService
1313
{
1414
/// <summary>
1515
/// Returns the URL of the remote named "origin" for the specified <see cref="repository"/>. If the repository
1616
/// is null or no remote named origin exists, this method returns null
1717
/// </summary>
1818
/// <param name="repository">The repository to look at for the remote.</param>
19-
/// <returns>A <see cref="UriString"/> representing the origin or null if none found.</returns>
19+
/// <returns>Returns a <see cref="UriString"/> representing the uri of the "origin" remote normalized to a GitHub repository url or null if none found.</returns>
2020
public UriString GetUri(IRepository repository)
2121
{
22-
return UriString.ToUriString(GetUriFromRepository(repository)?.ToRepositoryUrl());
22+
return UriString.ToUriString(GetOriginUri(repository)?.ToRepositoryUrl());
2323
}
2424

2525
/// <summary>
26-
/// Probes for a git repository and if one is found, returns a <see cref="UriString"/> for the repository's
27-
/// remote named "origin" if one is found
26+
/// Returns a <see cref="UriString"/> representing the uri of the "origin" remote normalized to a GitHub repository url or null if none found.
27+
/// </summary>
28+
/// <param name="repository"></param>
29+
/// <returns>Returns a <see cref="UriString"/> representing the uri of the "origin" remote normalized to a GitHub repository url or null if none found.</returns>
30+
public static UriString GetGitHubUri(IRepository repository)
31+
{
32+
return GitServiceHelper.GetUri(repository);
33+
}
34+
35+
/// <summary>
36+
/// Probes for a git repository and if one is found, returns a normalized GitHub uri <see cref="UriString"/>
37+
/// for the repository's remote named "origin" if one is found
2838
/// </summary>
2939
/// <remarks>
3040
/// The lookup checks to see if the specified <paramref name="path"/> is a repository. If it's not, it then
3141
/// walks up the parent directories until it either finds a repository, or reaches the root disk.
3242
/// </remarks>
3343
/// <param name="path">The path to start probing</param>
34-
/// <returns>A <see cref="UriString"/> representing the origin or null if none found.</returns>
44+
/// <returns>Returns a <see cref="UriString"/> representing the uri of the "origin" remote normalized to a GitHub repository url or null if none found.</returns>
3545
public UriString GetUri(string path)
3646
{
3747
return GetUri(GetRepo(path));
3848
}
3949

4050
/// <summary>
41-
/// Probes for a git repository and if one is found, returns a <see cref="UriString"/> for the repository's
42-
/// remote named "origin" if one is found
51+
/// Probes for a git repository and if one is found, returns a normalized GitHub uri <see cref="UriString"/>
52+
/// for the repository's remote named "origin" if one is found
53+
/// </summary>
54+
/// <remarks>
55+
/// The lookup checks to see if the specified <paramref name="path"/> is a repository. If it's not, it then
56+
/// walks up the parent directories until it either finds a repository, or reaches the root disk.
57+
/// </remarks>
58+
/// <param name="path">The path to start probing</param>
59+
/// <returns>Returns a <see cref="UriString"/> representing the uri of the "origin" remote normalized to a GitHub repository url or null if none found.</returns>
60+
public static UriString GetUriFromPath(string path)
61+
{
62+
return GitServiceHelper.GetUri(path);
63+
}
64+
65+
/// <summary>
66+
/// Probes for a git repository and if one is found, returns a normalized GitHub uri
67+
/// <see cref="UriString"/> for the repository's remote named "origin" if one is found
4368
/// </summary>
4469
/// <remarks>
4570
/// The lookup checks to see if the path specified by the RepositoryPath property of the specified
4671
/// <see cref="repoInfo"/> is a repository. If it's not, it then walks up the parent directories until it
4772
/// either finds a repository, or reaches the root disk.
4873
/// </remarks>
4974
/// <param name="repoInfo">The repository information containing the path to start probing</param>
50-
/// <returns>A <see cref="UriString"/> representing the origin or null if none found.</returns>
75+
/// <returns>Returns a <see cref="UriString"/> representing the uri of the "origin" remote normalized to a GitHub repository url or null if none found.</returns>
5176
public UriString GetUri(IGitRepositoryInfo repoInfo)
5277
{
5378
return GetUri(GetRepo(repoInfo));
5479
}
5580

81+
/// <summary>
82+
/// Probes for a git repository and if one is found, returns a normalized GitHub uri
83+
/// <see cref="UriString"/> for the repository's remote named "origin" if one is found
84+
/// </summary>
85+
/// <remarks>
86+
/// The lookup checks to see if the path specified by the RepositoryPath property of the specified
87+
/// <see cref="repoInfo"/> is a repository. If it's not, it then walks up the parent directories until it
88+
/// either finds a repository, or reaches the root disk.
89+
/// </remarks>
90+
/// <param name="repoInfo">The repository information containing the path to start probing</param>
91+
/// <returns>Returns a <see cref="UriString"/> representing the uri of the "origin" remote normalized to a GitHub repository url or null if none found.</returns>
92+
public static UriString GetUriFromVSGit(IGitRepositoryInfo repoInfo)
93+
{
94+
return GitServiceHelper.GetUri(repoInfo);
95+
}
96+
5697
/// <summary>
5798
/// Probes for a git repository and if one is found, returns a <see cref="IRepository"/> instance for the
5899
/// repository.
@@ -70,6 +111,22 @@ public IRepository GetRepo(IGitRepositoryInfo repoInfo)
70111
return GetRepo(repoInfo?.RepositoryPath);
71112
}
72113

114+
/// <summary>
115+
/// Probes for a git repository and if one is found, returns a <see cref="IRepository"/> instance for the
116+
/// repository.
117+
/// </summary>
118+
/// <remarks>
119+
/// The lookup checks to see if the path specified by the RepositoryPath property of the specified
120+
/// <see cref="repoInfo"/> is a repository. If it's not, it then walks up the parent directories until it
121+
/// either finds a repository, or reaches the root disk.
122+
/// </remarks>
123+
/// <param name="repoInfo">The repository information containing the path to start probing</param>
124+
/// <returns>An instance of <see cref="IRepository"/> or null</returns>
125+
public static IRepository GetRepoFromVSGit(IGitRepositoryInfo repoInfo)
126+
{
127+
return GitServiceHelper.GetRepo(repoInfo);
128+
}
129+
73130
/// <summary>
74131
/// Probes for a git repository and if one is found, returns a <see cref="IRepository"/> instance for the
75132
/// repository.
@@ -86,13 +143,35 @@ public IRepository GetRepo(string path)
86143
return repoPath == null ? null : new Repository(repoPath);
87144
}
88145

89-
internal static UriString GetUriFromRepository(IRepository repo)
146+
/// <summary>
147+
/// Probes for a git repository and if one is found, returns a <see cref="IRepository"/> instance for the
148+
/// repository.
149+
/// </summary>
150+
/// <remarks>
151+
/// The lookup checks to see if the specified <paramref name="path"/> is a repository. If it's not, it then
152+
/// walks up the parent directories until it either finds a repository, or reaches the root disk.
153+
/// </remarks>
154+
/// <param name="path">The path to start probing</param>
155+
/// <returns>An instance of <see cref="IRepository"/> or null</returns>
156+
public static IRepository GetRepoFromPath(string path)
157+
{
158+
return GitServiceHelper.GetRepo(path);
159+
}
160+
161+
/// <summary>
162+
/// Returns a <see cref="UriString"/> representing the uri of the "origin" remote with no modifications.
163+
/// </summary>
164+
/// <param name="repo"></param>
165+
/// <returns></returns>
166+
public static UriString GetOriginUri(IRepository repo)
90167
{
91168
return repo
92169
?.Network
93170
.Remotes
94171
.FirstOrDefault(x => x.Name.Equals("origin", StringComparison.Ordinal))
95172
?.Url;
96173
}
174+
175+
public static IGitService GitServiceHelper => VisualStudio.Services.DefaultExportProvider.GetExportedValueOrDefault<IGitService>() ?? new GitService();
97176
}
98177
}

src/GitHub.Exports/Services/Services.cs

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
using System;
22
using EnvDTE;
33
using EnvDTE80;
4-
using GitHub.Extensions;
54
using GitHub.Info;
65
using GitHub.Primitives;
76
using GitHub.Services;
87
using LibGit2Sharp;
98
using Microsoft.VisualStudio;
109
using Microsoft.VisualStudio.ComponentModelHost;
1110
using Microsoft.VisualStudio.Shell.Interop;
11+
using Microsoft.VisualStudio.Shell;
12+
using System.ComponentModel.Composition.Hosting;
1213

1314
namespace GitHub.VisualStudio
1415
{
@@ -17,10 +18,11 @@ public static class Services
1718
public static IServiceProvider PackageServiceProvider { get; set; }
1819

1920
/// <summary>
20-
/// Two ways of getting a service. First, trying the passed-in <paramref name="provider"/>,
21-
/// then <see cref="PackageServiceProvider"/>
22-
/// If the passed-in provider returns null, try PackageServiceProvider, returning the fetched value
23-
/// regardless of whether it's null or not.
21+
/// Three ways of getting a service. First, trying the passed-in <paramref name="provider"/>,
22+
/// then <see cref="PackageServiceProvider"/>, then <see cref="T:Microsoft.VisualStudio.Shell.Package"/>
23+
/// If the passed-in provider returns null, try PackageServiceProvider or Package, returning the fetched value
24+
/// regardless of whether it's null or not. Package.GetGlobalService is never called if PackageServiceProvider is set.
25+
/// This is on purpose, to support easy unit testing outside VS.
2426
/// </summary>
2527
/// <typeparam name="T"></typeparam>
2628
/// <typeparam name="Ret"></typeparam>
@@ -33,10 +35,13 @@ static Ret GetGlobalService<T, Ret>(IServiceProvider provider = null) where T :
3335
ret = provider.GetService(typeof(T)) as Ret;
3436
if (ret != null)
3537
return ret;
36-
return PackageServiceProvider.GetService(typeof(T)) as Ret;
38+
if (PackageServiceProvider != null)
39+
return PackageServiceProvider.GetService(typeof(T)) as Ret;
40+
return Package.GetGlobalService(typeof(T)) as Ret;
3741
}
3842

3943
public static IComponentModel ComponentModel => GetGlobalService<SComponentModel, IComponentModel>();
44+
public static ExportProvider DefaultExportProvider => ComponentModel.DefaultExportProvider;
4045

4146
public static IVsWebBrowsingService GetWebBrowsingService(this IServiceProvider provider)
4247
{
@@ -45,7 +50,7 @@ public static IVsWebBrowsingService GetWebBrowsingService(this IServiceProvider
4550

4651
public static IVsOutputWindow OutputWindow => GetGlobalService<SVsOutputWindow, IVsOutputWindow>();
4752

48-
static IVsOutputWindowPane outputWindowPane = null;
53+
static IVsOutputWindowPane outputWindowPane;
4954
public static IVsOutputWindowPane OutputWindowPane
5055
{
5156
get
@@ -56,7 +61,7 @@ public static IVsOutputWindowPane OutputWindowPane
5661
var uiShell = GetGlobalService<SVsUIShell, IVsUIShell>();
5762
// Get the frame of the output window
5863
var outputWindowGuid = new Guid("{34e76e81-ee4a-11d0-ae2e-00a0c90fffc3}");
59-
IVsWindowFrame outputWindowFrame = null;
64+
IVsWindowFrame outputWindowFrame;
6065
ErrorHandler.ThrowOnFailure(uiShell.FindToolWindow((uint)__VSCREATETOOLWIN.CTW_fForceCreate, ref outputWindowGuid, out outputWindowFrame));
6166
// Show the output window
6267
if (outputWindowFrame != null)
@@ -73,6 +78,7 @@ public static IVsOutputWindowPane OutputWindowPane
7378

7479
public static DTE Dte => GetGlobalService<DTE, DTE>();
7580

81+
// ReSharper disable once SuspiciousTypeConversion.Global
7682
public static DTE2 Dte2 => Dte as DTE2;
7783

7884
public static IVsActivityLog GetActivityLog(this IServiceProvider provider)
@@ -92,13 +98,7 @@ public static UriString GetRepoUrlFromSolution(IVsSolution solution)
9298
return null;
9399
if (solutionDir == null)
94100
return null;
95-
var repoPath = Repository.Discover(solutionDir);
96-
if (repoPath == null)
97-
return null;
98-
using (var repo = new Repository(repoPath))
99-
{
100-
return GetUri(repo);
101-
}
101+
return GitService.GitServiceHelper.GetUri(solutionDir);
102102
}
103103

104104
public static IRepository GetRepoFromSolution(this IVsSolution solution)
@@ -108,15 +108,7 @@ public static IRepository GetRepoFromSolution(this IVsSolution solution)
108108
return null;
109109
if (solutionDir == null)
110110
return null;
111-
var repoPath = Repository.Discover(solutionDir);
112-
if (repoPath == null)
113-
return null;
114-
return new Repository(repoPath);
115-
}
116-
static UriString GetUri(IRepository repo)
117-
{
118-
return UriString.ToUriString(GitService.GetUriFromRepository(repo)?.ToRepositoryUrl());
111+
return GitService.GitServiceHelper.GetRepo(solutionDir);
119112
}
120-
public static IGitService IGitService => PackageServiceProvider.GetService<IGitService>();
121113
}
122114
}

src/UnitTests/GitHub.App/Models/RepositoryModelTests.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,7 @@ public void NoRemoteUrl()
6060
{
6161
var provider = Substitutes.ServiceProvider;
6262
Services.PackageServiceProvider = provider;
63-
var gitservice = Substitutes.IGitService;
64-
provider.GetService(typeof(IGitService)).Returns(gitservice);
63+
var gitservice = provider.GetGitService();
6564
var repo = Substitute.For<IRepository>();
6665
var path = Directory.CreateSubdirectory("repo-name");
6766
gitservice.GetUri(path.FullName).Returns((UriString)null);
@@ -74,8 +73,7 @@ public void WithRemoteUrl()
7473
{
7574
var provider = Substitutes.ServiceProvider;
7675
Services.PackageServiceProvider = provider;
77-
var gitservice = Substitutes.IGitService;
78-
provider.GetService(typeof(IGitService)).Returns(gitservice);
76+
var gitservice = provider.GetGitService();
7977
var repo = Substitute.For<IRepository>();
8078
var path = Directory.CreateSubdirectory("repo-name");
8179
gitservice.GetUri(path.FullName).Returns(new UriString("https://github.com/user/repo-name"));

0 commit comments

Comments
 (0)