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

Commit

Permalink
Merge pull request #105 from github/shana/fix-gitservice-null
Browse files Browse the repository at this point in the history
Fix IGitService
  • Loading branch information
haacked committed Sep 23, 2015
2 parents 6397fbd + be83fce commit b872d48
Show file tree
Hide file tree
Showing 8 changed files with 125 additions and 90 deletions.
46 changes: 0 additions & 46 deletions src/GitHub.Exports/Extensions/GitHelpers.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.IO;
using GitHub.Models;
using Microsoft.VisualStudio.TeamFoundation.Git.Extensibility;
using GitHub.Services;

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

public static bool HasCommits(this ISimpleRepositoryModel repository)
{
var repo = VisualStudio.Services.IGitService.GetRepo(repository.LocalPath);
var repo = GitService.GitServiceHelper.GetRepo(repository.LocalPath);
return repo?.Commits.Any() ?? false;
}

Expand Down
1 change: 0 additions & 1 deletion src/GitHub.Exports/GitHub.Exports.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@
<None Include="..\..\script\Key.snk" Condition="$(Buildtype) == 'Internal'">
<Link>Key.snk</Link>
</None>
<Compile Include="Extensions\GitHelpers.cs" />
<Compile Include="Helpers\INotifyPropertySource.cs" />
<Compile Include="Extensions\PropertyNotifierExtensions.cs" />
<Compile Include="Extensions\SimpleRepositoryModelExtensions.cs" />
Expand Down
5 changes: 3 additions & 2 deletions src/GitHub.Exports/Models/SimpleRepositoryModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using GitHub.Primitives;
using GitHub.UI;
using GitHub.VisualStudio.Helpers;
using GitHub.Services;

namespace GitHub.Models
{
Expand All @@ -26,7 +27,7 @@ public SimpleRepositoryModel(string path)
var dir = new DirectoryInfo(path);
if (!dir.Exists)
throw new ArgumentException("Path does not exist", nameof(path));
var uri = VisualStudio.Services.IGitService.GetUri(path);
var uri = GitService.GitServiceHelper.GetUri(path);
var name = uri?.NameWithOwner ?? dir.Name;
Name = name;
LocalPath = path;
Expand All @@ -47,7 +48,7 @@ public void Refresh()
{
if (LocalPath == null)
return;
var uri = VisualStudio.Services.IGitService.GetUri(LocalPath);
var uri = GitService.GitServiceHelper.GetUri(LocalPath);
if (CloneUrl != uri)
CloneUrl = uri;
}
Expand Down
101 changes: 90 additions & 11 deletions src/GitHub.Exports/Services/GitService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,52 +7,93 @@

namespace GitHub.Services
{
[Export(typeof(IVSServices))]
[PartCreationPolicy(CreationPolicy.Shared)]
[Export(typeof(IGitService))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class GitService : IGitService
{
/// <summary>
/// Returns the URL of the remote named "origin" for the specified <see cref="repository"/>. If the repository
/// is null or no remote named origin exists, this method returns null
/// </summary>
/// <param name="repository">The repository to look at for the remote.</param>
/// <returns>A <see cref="UriString"/> representing the origin or null if none found.</returns>
/// <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>
public UriString GetUri(IRepository repository)
{
return UriString.ToUriString(GetUriFromRepository(repository)?.ToRepositoryUrl());
return UriString.ToUriString(GetOriginUri(repository)?.ToRepositoryUrl());
}

/// <summary>
/// Probes for a git repository and if one is found, returns a <see cref="UriString"/> for the repository's
/// remote named "origin" if one is found
/// Returns a <see cref="UriString"/> representing the uri of the "origin" remote normalized to a GitHub repository url or null if none found.
/// </summary>
/// <param name="repository"></param>
/// <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>
public static UriString GetGitHubUri(IRepository repository)
{
return GitServiceHelper.GetUri(repository);
}

/// <summary>
/// Probes for a git repository and if one is found, returns a normalized GitHub uri <see cref="UriString"/>
/// for the repository's remote named "origin" if one is found
/// </summary>
/// <remarks>
/// The lookup checks to see if the specified <paramref name="path"/> is a repository. If it's not, it then
/// walks up the parent directories until it either finds a repository, or reaches the root disk.
/// </remarks>
/// <param name="path">The path to start probing</param>
/// <returns>A <see cref="UriString"/> representing the origin or null if none found.</returns>
/// <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>
public UriString GetUri(string path)
{
return GetUri(GetRepo(path));
}

/// <summary>
/// Probes for a git repository and if one is found, returns a <see cref="UriString"/> for the repository's
/// remote named "origin" if one is found
/// Probes for a git repository and if one is found, returns a normalized GitHub uri <see cref="UriString"/>
/// for the repository's remote named "origin" if one is found
/// </summary>
/// <remarks>
/// The lookup checks to see if the specified <paramref name="path"/> is a repository. If it's not, it then
/// walks up the parent directories until it either finds a repository, or reaches the root disk.
/// </remarks>
/// <param name="path">The path to start probing</param>
/// <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>
public static UriString GetUriFromPath(string path)
{
return GitServiceHelper.GetUri(path);
}

/// <summary>
/// Probes for a git repository and if one is found, returns a normalized GitHub uri
/// <see cref="UriString"/> for the repository's remote named "origin" if one is found
/// </summary>
/// <remarks>
/// The lookup checks to see if the path specified by the RepositoryPath property of the specified
/// <see cref="repoInfo"/> is a repository. If it's not, it then walks up the parent directories until it
/// either finds a repository, or reaches the root disk.
/// </remarks>
/// <param name="repoInfo">The repository information containing the path to start probing</param>
/// <returns>A <see cref="UriString"/> representing the origin or null if none found.</returns>
/// <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>
public UriString GetUri(IGitRepositoryInfo repoInfo)
{
return GetUri(GetRepo(repoInfo));
}

/// <summary>
/// Probes for a git repository and if one is found, returns a normalized GitHub uri
/// <see cref="UriString"/> for the repository's remote named "origin" if one is found
/// </summary>
/// <remarks>
/// The lookup checks to see if the path specified by the RepositoryPath property of the specified
/// <see cref="repoInfo"/> is a repository. If it's not, it then walks up the parent directories until it
/// either finds a repository, or reaches the root disk.
/// </remarks>
/// <param name="repoInfo">The repository information containing the path to start probing</param>
/// <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>
public static UriString GetUriFromVSGit(IGitRepositoryInfo repoInfo)
{
return GitServiceHelper.GetUri(repoInfo);
}

/// <summary>
/// Probes for a git repository and if one is found, returns a <see cref="IRepository"/> instance for the
/// repository.
Expand All @@ -70,6 +111,22 @@ public IRepository GetRepo(IGitRepositoryInfo repoInfo)
return GetRepo(repoInfo?.RepositoryPath);
}

/// <summary>
/// Probes for a git repository and if one is found, returns a <see cref="IRepository"/> instance for the
/// repository.
/// </summary>
/// <remarks>
/// The lookup checks to see if the path specified by the RepositoryPath property of the specified
/// <see cref="repoInfo"/> is a repository. If it's not, it then walks up the parent directories until it
/// either finds a repository, or reaches the root disk.
/// </remarks>
/// <param name="repoInfo">The repository information containing the path to start probing</param>
/// <returns>An instance of <see cref="IRepository"/> or null</returns>
public static IRepository GetRepoFromVSGit(IGitRepositoryInfo repoInfo)
{
return GitServiceHelper.GetRepo(repoInfo);
}

/// <summary>
/// Probes for a git repository and if one is found, returns a <see cref="IRepository"/> instance for the
/// repository.
Expand All @@ -86,13 +143,35 @@ public IRepository GetRepo(string path)
return repoPath == null ? null : new Repository(repoPath);
}

internal static UriString GetUriFromRepository(IRepository repo)
/// <summary>
/// Probes for a git repository and if one is found, returns a <see cref="IRepository"/> instance for the
/// repository.
/// </summary>
/// <remarks>
/// The lookup checks to see if the specified <paramref name="path"/> is a repository. If it's not, it then
/// walks up the parent directories until it either finds a repository, or reaches the root disk.
/// </remarks>
/// <param name="path">The path to start probing</param>
/// <returns>An instance of <see cref="IRepository"/> or null</returns>
public static IRepository GetRepoFromPath(string path)
{
return GitServiceHelper.GetRepo(path);
}

/// <summary>
/// Returns a <see cref="UriString"/> representing the uri of the "origin" remote with no modifications.
/// </summary>
/// <param name="repo"></param>
/// <returns></returns>
public static UriString GetOriginUri(IRepository repo)
{
return repo
?.Network
.Remotes
.FirstOrDefault(x => x.Name.Equals("origin", StringComparison.Ordinal))
?.Url;
}

public static IGitService GitServiceHelper => VisualStudio.Services.DefaultExportProvider.GetExportedValueOrDefault<IGitService>() ?? new GitService();
}
}
40 changes: 16 additions & 24 deletions src/GitHub.Exports/Services/Services.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
using System;
using EnvDTE;
using EnvDTE80;
using GitHub.Extensions;
using GitHub.Info;
using GitHub.Primitives;
using GitHub.Services;
using LibGit2Sharp;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Shell;
using System.ComponentModel.Composition.Hosting;

namespace GitHub.VisualStudio
{
Expand All @@ -17,10 +18,11 @@ public static class Services
public static IServiceProvider PackageServiceProvider { get; set; }

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

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

public static IVsWebBrowsingService GetWebBrowsingService(this IServiceProvider provider)
{
Expand All @@ -45,7 +50,7 @@ public static IVsWebBrowsingService GetWebBrowsingService(this IServiceProvider

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

static IVsOutputWindowPane outputWindowPane = null;
static IVsOutputWindowPane outputWindowPane;
public static IVsOutputWindowPane OutputWindowPane
{
get
Expand All @@ -56,7 +61,7 @@ public static IVsOutputWindowPane OutputWindowPane
var uiShell = GetGlobalService<SVsUIShell, IVsUIShell>();
// Get the frame of the output window
var outputWindowGuid = new Guid("{34e76e81-ee4a-11d0-ae2e-00a0c90fffc3}");
IVsWindowFrame outputWindowFrame = null;
IVsWindowFrame outputWindowFrame;
ErrorHandler.ThrowOnFailure(uiShell.FindToolWindow((uint)__VSCREATETOOLWIN.CTW_fForceCreate, ref outputWindowGuid, out outputWindowFrame));
// Show the output window
if (outputWindowFrame != null)
Expand All @@ -73,6 +78,7 @@ public static IVsOutputWindowPane OutputWindowPane

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

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

public static IVsActivityLog GetActivityLog(this IServiceProvider provider)
Expand All @@ -92,13 +98,7 @@ public static UriString GetRepoUrlFromSolution(IVsSolution solution)
return null;
if (solutionDir == null)
return null;
var repoPath = Repository.Discover(solutionDir);
if (repoPath == null)
return null;
using (var repo = new Repository(repoPath))
{
return GetUri(repo);
}
return GitService.GitServiceHelper.GetUri(solutionDir);
}

public static IRepository GetRepoFromSolution(this IVsSolution solution)
Expand All @@ -108,15 +108,7 @@ public static IRepository GetRepoFromSolution(this IVsSolution solution)
return null;
if (solutionDir == null)
return null;
var repoPath = Repository.Discover(solutionDir);
if (repoPath == null)
return null;
return new Repository(repoPath);
}
static UriString GetUri(IRepository repo)
{
return UriString.ToUriString(GitService.GetUriFromRepository(repo)?.ToRepositoryUrl());
return GitService.GitServiceHelper.GetRepo(solutionDir);
}
public static IGitService IGitService => PackageServiceProvider.GetService<IGitService>();
}
}
6 changes: 2 additions & 4 deletions src/UnitTests/GitHub.App/Models/RepositoryModelTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,7 @@ public void NoRemoteUrl()
{
var provider = Substitutes.ServiceProvider;
Services.PackageServiceProvider = provider;
var gitservice = Substitutes.IGitService;
provider.GetService(typeof(IGitService)).Returns(gitservice);
var gitservice = provider.GetGitService();
var repo = Substitute.For<IRepository>();
var path = Directory.CreateSubdirectory("repo-name");
gitservice.GetUri(path.FullName).Returns((UriString)null);
Expand All @@ -74,8 +73,7 @@ public void WithRemoteUrl()
{
var provider = Substitutes.ServiceProvider;
Services.PackageServiceProvider = provider;
var gitservice = Substitutes.IGitService;
provider.GetService(typeof(IGitService)).Returns(gitservice);
var gitservice = provider.GetGitService();
var repo = Substitute.For<IRepository>();
var path = Directory.CreateSubdirectory("repo-name");
gitservice.GetUri(path.FullName).Returns(new UriString("https://github.com/user/repo-name"));
Expand Down
Loading

0 comments on commit b872d48

Please sign in to comment.