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

Commit e021c32

Browse files
committed
Merge pull request #21 from github/haacked/13-handle-http-urls
Handle Enterprise http urls
2 parents febfd94 + 59bb542 commit e021c32

File tree

16 files changed

+471
-256
lines changed

16 files changed

+471
-256
lines changed

src/GitHub.Api/SimpleApiClient.cs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using System.Diagnostics;
33
using System.Threading;
44
using System.Threading.Tasks;
5-
using GitHub.Extensions;
65
using GitHub.Primitives;
76
using GitHub.Services;
87
using Octokit;
@@ -11,8 +10,8 @@ namespace GitHub.Api
1110
{
1211
public class SimpleApiClient : ISimpleApiClient
1312
{
14-
public HostAddress HostAddress { get; private set; }
15-
public Uri OriginalUrl { get; private set; }
13+
public HostAddress HostAddress { get; }
14+
public UriString OriginalUrl { get; }
1615

1716
readonly GitHubClient client;
1817
readonly Lazy<IEnterpriseProbeTask> enterpriseProbe;
@@ -24,7 +23,7 @@ public class SimpleApiClient : ISimpleApiClient
2423
bool? isEnterprise;
2524
bool? hasWiki;
2625

27-
internal SimpleApiClient(HostAddress hostAddress, Uri repoUrl, GitHubClient githubClient,
26+
internal SimpleApiClient(HostAddress hostAddress, UriString repoUrl, GitHubClient githubClient,
2827
Lazy<IEnterpriseProbeTask> enterpriseProbe, Lazy<IWikiProbe> wikiProbe)
2928
{
3029
HostAddress = hostAddress;
@@ -51,19 +50,19 @@ async Task<Repository> GetRepositoryInternal()
5150
{
5251
if (owner == null && OriginalUrl != null)
5352
{
54-
var own = OriginalUrl.GetUser();
55-
var name = OriginalUrl.GetRepo();
53+
var ownerLogin = OriginalUrl.Owner;
54+
var repositoryName = OriginalUrl.RepositoryName;
5655

57-
if (own != null && name != null)
56+
if (ownerLogin != null && repositoryName != null)
5857
{
59-
var repo = await client.Repository.Get(own, name);
58+
var repo = await client.Repository.Get(ownerLogin, repositoryName);
6059
if (repo != null)
6160
{
6261
hasWiki = await HasWikiInternal(repo);
6362
isEnterprise = await IsEnterpriseInternal();
6463
repositoryCache = repo;
6564
}
66-
owner = own;
65+
owner = ownerLogin;
6766
}
6867
}
6968
}

src/GitHub.Api/SimpleApiClientFactory.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public class SimpleApiClientFactory : ISimpleApiClientFactory
1616
readonly Lazy<IEnterpriseProbeTask> lazyEnterpriseProbe;
1717
readonly Lazy<IWikiProbe> lazyWikiProbe;
1818

19-
static readonly Dictionary<Uri, ISimpleApiClient> cache = new Dictionary<Uri, ISimpleApiClient>();
19+
static readonly Dictionary<UriString, ISimpleApiClient> cache = new Dictionary<UriString, ISimpleApiClient>();
2020

2121
[ImportingConstructor]
2222
public SimpleApiClientFactory(IProgram program, Lazy<IEnterpriseProbeTask> enterpriseProbe, Lazy<IWikiProbe> wikiProbe)
@@ -26,21 +26,21 @@ public SimpleApiClientFactory(IProgram program, Lazy<IEnterpriseProbeTask> enter
2626
lazyWikiProbe = wikiProbe;
2727
}
2828

29-
public ISimpleApiClient Create(Uri repoUrl)
29+
public ISimpleApiClient Create(UriString repositoryUrl)
3030
{
31-
var contains = cache.ContainsKey(repoUrl);
31+
var contains = cache.ContainsKey(repositoryUrl);
3232
if (contains)
33-
return cache[repoUrl];
33+
return cache[repositoryUrl];
3434

3535
lock (cache)
3636
{
37-
if (!cache.ContainsKey(repoUrl))
37+
if (!cache.ContainsKey(repositoryUrl))
3838
{
39-
var hostAddress = HostAddress.Create(repoUrl);
39+
var hostAddress = HostAddress.Create(repositoryUrl);
4040
var apiBaseUri = hostAddress.ApiUri;
41-
cache.Add(repoUrl, new SimpleApiClient(hostAddress, repoUrl, new GitHubClient(productHeader, new SimpleCredentialStore(hostAddress), apiBaseUri), lazyEnterpriseProbe, lazyWikiProbe));
41+
cache.Add(repositoryUrl, new SimpleApiClient(hostAddress, repositoryUrl, new GitHubClient(productHeader, new SimpleCredentialStore(hostAddress), apiBaseUri), lazyEnterpriseProbe, lazyWikiProbe));
4242
}
43-
return cache[repoUrl];
43+
return cache[repositoryUrl];
4444
}
4545
}
4646

src/GitHub.Exports/Api/ISimpleApiClient.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
1-
using System;
2-
using System.Threading.Tasks;
1+
using System.Threading.Tasks;
32
using GitHub.Primitives;
4-
using GitHub.Services;
53
using Octokit;
64

75
namespace GitHub.Api
86
{
97
public interface ISimpleApiClient
108
{
119
HostAddress HostAddress { get; }
12-
Uri OriginalUrl { get; }
10+
UriString OriginalUrl { get; }
1311
Task<Repository> GetRepository();
1412
bool HasWiki();
1513
bool IsEnterprise();
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
using System;
1+
using GitHub.Primitives;
22

33
namespace GitHub.Api
44
{
55
public interface ISimpleApiClientFactory
66
{
7-
ISimpleApiClient Create(Uri repoUrl);
7+
ISimpleApiClient Create(UriString repositoryUrl);
88
void ClearFromCache(ISimpleApiClient client);
99
}
1010
}

src/GitHub.Exports/Primitives/UriString.cs

Lines changed: 27 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
using System;
2-
using System.Collections.Generic;
3-
using System.Diagnostics;
42
using System.Diagnostics.CodeAnalysis;
53
using System.Globalization;
64
using System.Linq;
@@ -31,6 +29,7 @@ public class UriString : StringEquivalent<UriString>, IEquatable<UriString>
3129

3230
public UriString(string uriString) : base(NormalizePath(uriString))
3331
{
32+
if (uriString == null) throw new ArgumentNullException(nameof(uriString), "Cannot create a null UriString");
3433
if (uriString.Length == 0) return;
3534
if (Uri.TryCreate(uriString, UriKind.Absolute, out url))
3635
{
@@ -71,43 +70,6 @@ void SetUri(Uri uri)
7170
}
7271

7372
IsHypertextTransferProtocol = uri.IsHypertextTransferProtocol();
74-
75-
if (String.IsNullOrEmpty(uri.Query)) return;
76-
77-
try
78-
{
79-
var query = ParseQueryString(uri);
80-
81-
if (query.ContainsKey("branch") && !String.IsNullOrEmpty(query["branch"]))
82-
{
83-
Branch = query["branch"].Replace("%2F", "/");
84-
}
85-
86-
if (query.ContainsKey("pr") && !String.IsNullOrEmpty(query["pr"]))
87-
{
88-
PullRequest = query["pr"].Replace("%2F", "/");
89-
}
90-
91-
if (query.ContainsKey("filepath") && !String.IsNullOrEmpty(query["filepath"]))
92-
{
93-
RelativePathToOpen = query["filepath"].Replace("%2F", "/").Replace('/', '\\');
94-
}
95-
}
96-
catch //(Exception ex)
97-
{
98-
//log.WarnException("Failed to read URI query", ex);
99-
}
100-
}
101-
102-
// This is not a complete query string parsing algorithm, but it's good enough for our needs.
103-
static IDictionary<string, string> ParseQueryString(Uri uri)
104-
{
105-
Debug.Assert(uri.Query.StartsWith('?'),
106-
String.Format(CultureInfo.InvariantCulture, "Uri.Query doesn't start with '?': '{0}'", uri.Query));
107-
return uri.Query.Substring(1).Split(new[] {'&'}, StringSplitOptions.RemoveEmptyEntries)
108-
.Select(pair => pair.Split('='))
109-
.ToDictionary(pair => pair.First(), pair => pair.Length > 1 ? pair[1] : null,
110-
StringComparer.OrdinalIgnoreCase);
11173
}
11274

11375
void SetFilePath(Uri uri)
@@ -144,8 +106,6 @@ bool ParseScpSyntax(string scpString)
144106
return false;
145107
}
146108

147-
public string Branch { get; private set; }
148-
public string PullRequest { get; set; }
149109
public string Host { get; private set; }
150110

151111
public string Owner { get; private set; }
@@ -154,20 +114,31 @@ bool ParseScpSyntax(string scpString)
154114

155115
public string NameWithOwner { get; private set; }
156116

157-
public string RelativePathToOpen { get; private set; }
158-
159117
public bool IsFileUri { get; private set; }
160118

161-
public bool IsValidUri
162-
{
163-
get { return url != null; }
164-
}
119+
public bool IsValidUri => url != null;
165120

166-
public Uri ToUri()
121+
/// <summary>
122+
/// Attempts a best-effort to convert the remote origin to a GitHub Repository URL.
123+
/// </summary>
124+
/// <returns></returns>
125+
public Uri ToRepositoryUrl()
167126
{
168-
if (url == null)
169-
throw new InvalidOperationException("This Uri String is not a valid Uri");
170-
return url;
127+
if (url != null && IsFileUri) return url;
128+
129+
var scheme = url != null && IsHypertextTransferProtocol
130+
? url.Scheme
131+
: Uri.UriSchemeHttps;
132+
133+
return new UriBuilder
134+
{
135+
Scheme = scheme,
136+
Host = Host,
137+
Path = NameWithOwner,
138+
Port = url?.Port == 80
139+
? -1
140+
: (url?.Port ?? -1)
141+
}.Uri;
171142
}
172143

173144
/// <summary>
@@ -186,9 +157,7 @@ public static implicit operator UriString(string value)
186157
[SuppressMessage("Microsoft.Usage", "CA2225:OperatorOverloadsHaveNamedAlternates")]
187158
public static implicit operator string(UriString uriString)
188159
{
189-
if (uriString == null) return null;
190-
191-
return uriString.Value;
160+
return uriString?.Value;
192161
}
193162

194163
[SuppressMessage("Microsoft.Usage", "CA2234:PassSystemUriObjectsInsteadOfStrings", Justification = "No.")]
@@ -197,7 +166,7 @@ public override UriString Combine(string addition)
197166
if (url != null)
198167
{
199168
var urlBuilder = new UriBuilder(url);
200-
if (!String.IsNullOrEmpty(urlBuilder.Query))
169+
if (!string.IsNullOrEmpty(urlBuilder.Query))
201170
{
202171
var query = urlBuilder.Query;
203172
if (query.StartsWith("?", StringComparison.Ordinal))
@@ -221,7 +190,7 @@ public override UriString Combine(string addition)
221190
}
222191
return ToUriString(urlBuilder.Uri);
223192
}
224-
return String.Concat(Value, addition);
193+
return string.Concat(Value, addition);
225194
}
226195

227196
public override string ToString()
@@ -253,12 +222,12 @@ static string GetSerializedValue(SerializationInfo info)
253222

254223
static string NormalizePath(string path)
255224
{
256-
return path == null ? null : path.Replace('\\', '/');
225+
return path?.Replace('\\', '/');
257226
}
258227

259228
static string GetRepositoryName(string repositoryNameSegment)
260229
{
261-
if (String.IsNullOrEmpty(repositoryNameSegment)
230+
if (string.IsNullOrEmpty(repositoryNameSegment)
262231
|| repositoryNameSegment.Equals("/", StringComparison.Ordinal))
263232
{
264233
return null;

src/GitHub.Exports/Services/ITeamExplorerServiceHolder.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
using Microsoft.VisualStudio.TeamFoundation.Git.Extensibility;
2-
using System;
1+
using System;
2+
using GitHub.Primitives;
3+
using Microsoft.VisualStudio.TeamFoundation.Git.Extensibility;
34

45
namespace GitHub.Services
56
{
@@ -46,7 +47,11 @@ public interface ITeamExplorerServiceHolder
4647
public interface IGitAwareItem
4748
{
4849
IGitRepositoryInfo ActiveRepo { get; }
49-
Uri ActiveRepoUri { get; }
50+
51+
/// <summary>
52+
/// Represents the web URL of the repository on GitHub.com, even if the origin is an SSH address.
53+
/// </summary>
54+
UriString ActiveRepoUri { get; }
5055
string ActiveRepoName { get; }
5156
}
5257
}

src/GitHub.Exports/Services/Services.cs

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using Microsoft.VisualStudio.TeamFoundation.Git.Extensibility;
1313
using GitHub.Models;
1414
using GitHub.Info;
15+
using GitHub.Primitives;
1516

1617
namespace GitHub.VisualStudio
1718
{
@@ -127,7 +128,7 @@ public static Uri GetRepoUrlFromSolution(IVsSolution solution)
127128
return null;
128129
using (var repo = new Repository(repoPath))
129130
{
130-
return GetUriFromRepository(repo);
131+
return GetUriFromRepository(repo)?.ToRepositoryUrl();
131132
}
132133
}
133134

@@ -144,21 +145,13 @@ public static Repository GetRepoFromSolution(this IVsSolution solution)
144145
return new Repository(repoPath);
145146
}
146147

147-
public static Uri GetUriFromRepository(Repository repo)
148+
public static UriString GetUriFromRepository(Repository repo)
148149
{
149-
if (repo == null)
150-
return null;
151-
var remote = repo.Network.Remotes.FirstOrDefault(x => x.Name.Equals("origin", StringComparison.Ordinal));
152-
if (remote == null)
153-
return null;
154-
Uri uri;
155-
var url = remote.Url;
156-
// fixup ssh urls
157-
if (url.StartsWith("[email protected]:", StringComparison.Ordinal))
158-
url = url.Replace("[email protected]:", "https://github.com/");
159-
if (!Uri.TryCreate(url, UriKind.Absolute, out uri))
160-
return null;
161-
return uri;
150+
return repo
151+
?.Network
152+
.Remotes
153+
.FirstOrDefault(x => x.Name.Equals("origin", StringComparison.Ordinal))
154+
?.Url;
162155
}
163156

164157
public static Repository GetRepoFromIGit(this IGitRepositoryInfo repoInfo)

0 commit comments

Comments
 (0)