Skip to content

Commit

Permalink
Allow Gitiles URL for HTTP remote to be different to URL for the web …
Browse files Browse the repository at this point in the history
…interface (#312)

* Allowed the Gitiles URL for the HTTP remote to be different to the URL for the web interface.

* 2.12.0

* Only run CI workflow on pushes to master.
  • Loading branch information
reduckted authored Sep 22, 2024
1 parent 905141c commit 30665f1
Show file tree
Hide file tree
Showing 36 changed files with 1,238 additions and 448 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ name: CI

on:
push:
branches-ignore:
- "dependabot/**"
branches:
- "master"

tags-ignore:
- "**"
Expand Down
16 changes: 12 additions & 4 deletions shared/handler-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,28 @@
"items": {
"type": "object",
"properties": {
"pattern": {
"remotePattern": {
"type": "string",
"description": "A regular expression to match on a remote URL. The captured groups are provided to the `http` and `ssh` templates."
},
"http": {
"$ref": "#/definitions/template",
"description": "The template to build the HTTP(S) URL of the remote server.\n\nCaptured groups from `pattern` are made available via the `match` variable."
"description": "The template to build the HTTP(S) remote URL.\n\nCaptured groups from `pattern` are made available via the `match` variable."
},
"ssh": {
"$ref": "#/definitions/template",
"description": "The template to build the SSH URL of the remote server.\n\nCaptured groups from `pattern` are made available via the `match` variable."
"description": "The template to build the SSH remote URL.\n\nCaptured groups from `pattern` are made available via the `match` variable."
},
"webPattern": {
"type": "string",
"description": "A regular expression to match on a web interface URL. The captured groups are provided to the `http` and `ssh` templates."
},
"web": {
"$ref": "#/definitions/template",
"description": "The template to build the web interface URL.\n\nCaptured groups from `pattern` are made available via the `match` variable."
}
},
"required": ["pattern", "http", "ssh"],
"required": ["remotePattern", "http", "ssh"],
"additionalProperties": false
}
},
Expand Down
7 changes: 4 additions & 3 deletions shared/handlers/azure-dev-ops-cloud.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
"name": "Azure Dev Ops Cloud",
"server": [
{
"pattern": "^https:\\/\\/(?:.+@)?dev\\.azure\\.com\\/([^\\/]+)\\/([^\\/]+)\\/_git\\/.+",
"remotePattern": "^https:\\/\\/(?:.+@)?dev\\.azure\\.com\\/([^\\/]+)\\/([^\\/]+)\\/_git\\/.+",
"http": "https://dev.azure.com/{{ match[1] }}/{{ match[2] }}/_git",
"ssh": "[email protected]:v3/{{ match[1] }}/{{ match[2] }}"
},
{
"pattern": "^(?:git@)?ssh\\.dev\\.azure\\.com:v3\\/([^\\/]+)\\/([^\\/]+)\\/.+$",
"remotePattern": "^(?:git@)?ssh\\.dev\\.azure\\.com:v3\\/([^\\/]+)\\/([^\\/]+)\\/.+$",
"http": "https://dev.azure.com/{{ match[1] }}/{{ match[2] }}/_git",
"ssh": "[email protected]:v3/{{ match[1] }}/{{ match[2] }}"
"ssh": "[email protected]:v3/{{ match[1] }}/{{ match[2] }}",
"webPattern": "^ONLY MATCH TO SSH REMOTE URLS$"
}
],
"branchRef": "abbreviated",
Expand Down
7 changes: 4 additions & 3 deletions shared/handlers/github.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
"name": "GitHub",
"server": [
{
"pattern": "^https:\\/\\/github.(?:com|dev)",
"remotePattern": "^https:\\/\\/github.(?:com|dev)",
"http": "https://github.com",
"ssh": "[email protected]"
},
{
"pattern": "^(?:git@)?github\\.com",
"remotePattern": "^(?:git@)?github\\.com",
"http": "https://github.com",
"ssh": "[email protected]"
"ssh": "[email protected]",
"webPattern": "^ONLY MATCH TO SSH REMOTE URLS$"
}
],
"branchRef": "abbreviated",
Expand Down
16 changes: 16 additions & 0 deletions shared/handlers/gitiles.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,22 @@
"remote": "https://git.company.com:1368/plugins/gitiles/foo/bar.git",
"result": "https://git.company.com:1368/plugins/gitiles/foo/bar/+/{{ commit }}/src/file.txt"
},
"misc": [
{
"name": "Web URL is different to clone URL",
"settings": {
"gitiles": [
{
"http": "https://git.company.com/a",
"ssh": "ssh://git.company.com:29418",
"web": "https://git.company.com/plugins/gitiles"
}
]
},
"remote": "https://git.company.com/a/foo/bar.git",
"result": "https://git.company.com/plugins/gitiles/foo/bar/+/master/src/file.txt"
}
],
"selection": {
"remote": "https://git.company.com:1368/plugins/gitiles/foo/bar.git",
"point": {
Expand Down
7 changes: 4 additions & 3 deletions shared/handlers/visual-studio-team-services.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
"name": "Visual Studio Team Services",
"server": [
{
"pattern": "^([^.]+)@vs-ssh\\.visualstudio\\.com:22(?:/(.+))?/_ssh/.+$",
"remotePattern": "^([^.]+)@vs-ssh\\.visualstudio\\.com:22(?:/(.+))?/_ssh/.+$",
"http": "https://{{ match[1] }}.visualstudio.com{% if match[2] %}/{{ match[2] }}{% endif %}/_git",
"ssh": "{{ match[1] }}@vs-ssh.visualstudio.com:22{% if match[2] %}/{{ match[2] }}{% endif %}/_ssh"
"ssh": "{{ match[1] }}@vs-ssh.visualstudio.com:22{% if match[2] %}/{{ match[2] }}{% endif %}/_ssh",
"webPattern": "^ONLY MATCH TO SSH REMOTE URLS$"
},
{
"pattern": "^https://([^.]+).visualstudio.com(?:/(.+))?/_git/.+$",
"remotePattern": "^https://([^.]+).visualstudio.com(?:/(.+))?/_git/.+$",
"http": "https://{{ match[1] }}.visualstudio.com{% if match[2] %}/{{ match[2] }}{% endif %}/_git",
"ssh": "{{ match[1] }}@vs-ssh.visualstudio.com:22{% if match[2] %}/{{ match[2] }}{% endif %}/_ssh"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@

<local:ServerDataGrid
ItemsSource="{Binding Servers}"
HasWebAddress="true"
HttpExample="https://git.mygitiles.com:8080/plugins/gitiles"
SshExample="ssh://git.mygitiles.com:29418"
WebExample="https://mygitiles.com/plugins/gitiles"
/>
</StackPanel>
</UserControl>
3 changes: 3 additions & 0 deletions visual-studio/source/GitWebLinks/Options/ServerListItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,7 @@ public class ServerListItem {

public string? Ssh { get; set; } = "";


public string? Web { get; set; } = "";

}
14 changes: 12 additions & 2 deletions visual-studio/source/GitWebLinks/Options/ServerOptionsPageBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@ public abstract class ServerOptionsPageBase : OptionsPageBase {


internal IReadOnlyList<StaticServer> GetServers() {
return Servers.Select((x) => new StaticServer(x.Http ?? "", x.Ssh)).ToList();
return Servers.Select(
(x) => new StaticServer(
x.Http ?? "",
string.IsNullOrEmpty(x.Ssh) ? null : x.Ssh,
string.IsNullOrEmpty(x.Web) ? null : x.Web
)
).ToList();
}


Expand All @@ -38,7 +44,11 @@ public string JsonServers {

protected static string SerializeServers(IEnumerable<ServerListItem> servers) {
return JsonConvert.SerializeObject(
servers.Select((x) => new ServerListItem { Http = x.Http ?? "", Ssh = x.Ssh ?? "" })
servers.Select((x) => new ServerListItem {
Http = x.Http ?? "",
Ssh = x.Ssh,
Web = x.Web
})
);
}

Expand Down
4 changes: 2 additions & 2 deletions visual-studio/source/GitWebLinks/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: AssemblyVersion("2.11.0.0")]
[assembly: AssemblyFileVersion("2.11.0.0")]
[assembly: AssemblyVersion("2.12.0.0")]
[assembly: AssemblyFileVersion("2.12.0.0")]
[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)]
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,20 @@ private class JsonHandlerDefinition {

private class JsonServer {

public string? Pattern { get; set; }
public string? RemotePattern { get; set; }


public string Http { get; set; } = "";


public string Ssh { get; set; } = "";


public string? WebPattern { get; set; }


public string? Web { get; set; }

}


Expand Down Expand Up @@ -89,6 +95,9 @@ private class JsonReverseServerSettings {

public string Ssh { get; set; } = "";


public string? Web { get; set; }

}


Expand Down
17 changes: 13 additions & 4 deletions visual-studio/source/GitWebLinks/Services/DefinitionProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,18 @@ private static IReadOnlyList<IServer> ParseServers(IReadOnlyList<JsonServer> jso
servers = new List<IServer>();

foreach (var server in json) {
if (server.Pattern is not null) {
servers.Add(new DynamicServer(new Regex(server.Pattern), Template.Parse(server.Http), Template.Parse(server.Ssh)));
if (server.RemotePattern is not null) {
servers.Add(
new DynamicServer(
new Regex(server.RemotePattern),
Template.Parse(server.Http),
Template.Parse(server.Ssh),
(server.WebPattern is not null) ? new Regex(server.WebPattern) : null,
(server.Web is not null) ? Template.Parse(server.Web) : null
)
);
} else {
servers.Add(new StaticServer(server.Http, server.Ssh));
servers.Add(new StaticServer(server.Http, server.Ssh, server.Web));
}
}

Expand All @@ -117,7 +125,8 @@ private static ReverseSettings ParseReverseSettings(JsonReverseSettings json) {
json.FileMayStartWithBranch,
new ReverseServerSettings(
Template.Parse(json.Server.Http),
Template.Parse(json.Server.Ssh)
Template.Parse(json.Server.Ssh),
(json.Server.Web is not null) ? Template.Parse(json.Server.Web) : null
),
new ReverseSelectionSettings(
Template.Parse(json.Selection.StartLine),
Expand Down
2 changes: 1 addition & 1 deletion visual-studio/source/GitWebLinks/Services/ILinkHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ public interface ILinkHandler {
Task<UrlInfo?> GetUrlInfoAsync(string url, bool strict);


Task<bool> IsMatchAsync(string remoteUrl);
Task<bool> HandlesRemoteUrlAsync(string remoteUrl);

}
34 changes: 19 additions & 15 deletions visual-studio/source/GitWebLinks/Services/LinkHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ public LinkHandler(HandlerDefinition definition, ISettings settings, Git git) {
public string Name => _definition.Name;


public async Task<bool> IsMatchAsync(string remoteUrl) {
return await _server.MatchAsync(UrlHelpers.Normalize(remoteUrl)) is not null;
public async Task<bool> HandlesRemoteUrlAsync(string remoteUrl) {
return await _server.MatchRemoteUrlAsync(UrlHelpers.Normalize(remoteUrl)) is not null;
}


Expand All @@ -48,7 +48,7 @@ public async Task<CreateUrlResult> CreateUrlAsync(Repository repository, FileInf
throw new InvalidOperationException("The repository must have a remote.");
}

string remote;
string remoteUrl;
StaticServer address;
string refValue;
RefType refType;
Expand Down Expand Up @@ -86,15 +86,15 @@ public async Task<CreateUrlResult> CreateUrlAsync(Repository repository, FileInf

// Adjust the remote URL so that it's in a
// standard format that we can manipulate.
remote = UrlHelpers.Normalize(repository.Remote.Url);
remoteUrl = UrlHelpers.Normalize(repository.Remote.Url);

address = await GetAddressAsync(remote);
address = await GetAddressAsync(remoteUrl);
relativePath = GetRelativePath(repository.Root, file.FilePath);

data = TemplateData
.Create()
.Add("base", address.Http)
.Add("repository", GetRepositoryPath(remote, address))
.Add("base", address.Web ?? address.Http)
.Add("repository", GetRepositoryPath(remoteUrl, address))
.Add("ref", refValue)
.Add("commit", await GetRefAsync(LinkType.Commit, repository.Root, repository.Remote))
.Add("file", relativePath)
Expand Down Expand Up @@ -151,11 +151,11 @@ private static string ApplyModifications(string url, IReadOnlyList<QueryModifica
}


private async Task<StaticServer> GetAddressAsync(string remote) {
private async Task<StaticServer> GetAddressAsync(string remoteUrl) {
StaticServer? address;


address = await _server.MatchAsync(remote);
address = await _server.MatchRemoteUrlAsync(remoteUrl);

if (address is null) {
throw new InvalidOperationException("Could not find a matching address.");
Expand All @@ -168,11 +168,13 @@ private async Task<StaticServer> GetAddressAsync(string remote) {
private static StaticServer NormalizeServerUrls(StaticServer address) {
string http;
string? ssh;
string? web;

http = UrlHelpers.Normalize(address.Http);
ssh = address.Ssh is not null ? UrlHelpers.Normalize(address.Ssh) : null;
web = address.Web is not null ? UrlHelpers.Normalize(address.Web) : null;

return new StaticServer(http, ssh);
return new StaticServer(http, ssh, web);
}


Expand Down Expand Up @@ -298,7 +300,7 @@ private string GetRelativePath(string from, string to) {

// If the file is a symbolic link, or is under a directory that's a
// symbolic link, then we want to resolve the path to the real file
// because the sybmolic link won't be in the Git repository.
// because the symbolic link won't be in the Git repository.
if (IsSymbolicLink(to, from)) {
try {
to = GetRealPath(to);
Expand Down Expand Up @@ -449,13 +451,13 @@ private static bool TryGetFinalPathNameByHandle(IntPtr handle, int bufferSize, o
}


public async Task<UrlInfo?> GetUrlInfoAsync(string url, bool strict) {
public async Task<UrlInfo?> GetUrlInfoAsync(string webUrl, bool strict) {
StaticServer? address;
Match match;


// See if the URL matches the server address for the handler.
address = await _server.MatchAsync(url);
address = await _server.MatchWebUrlAsync(webUrl);

// If we are performing a strict match, then the
// URL must match to this handler's server.
Expand All @@ -467,7 +469,7 @@ private static bool TryGetFinalPathNameByHandle(IntPtr handle, int bufferSize, o
address = NormalizeServerUrls(address);
}

match = _definition.Reverse.Pattern.Match(url);
match = _definition.Reverse.Pattern.Match(webUrl);

if (match.Success) {
Hash hash;
Expand All @@ -480,14 +482,16 @@ private static bool TryGetFinalPathNameByHandle(IntPtr handle, int bufferSize, o
.Create()
.Add("http", address?.Http)
.Add("ssh", address?.Ssh)
.Add("web", address?.Web)
.Add(match)
.ToHash();

file = _definition.Reverse.File.Render(hash);

server = new StaticServer(
_definition.Reverse.Server.Http.Render(hash),
_definition.Reverse.Server.Ssh.Render(hash)
_definition.Reverse.Server.Ssh.Render(hash),
_definition.Reverse.Server.Web?.Render(hash)
);

selection = new PartialSelectedRange(
Expand Down
Loading

0 comments on commit 30665f1

Please sign in to comment.