Browse Source

Closes #1196 - adds regex pattern for remotes

main
Eric Amodio 3 years ago
parent
commit
1f0559930b
4 changed files with 118 additions and 45 deletions
  1. +1
    -0
      CHANGELOG.md
  2. +31
    -17
      package.json
  3. +17
    -7
      src/config.ts
  4. +69
    -21
      src/git/remotes/factory.ts

+ 1
- 0
CHANGELOG.md View File

@ -19,6 +19,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
- Adds a `gitlens.advanced.abbreviateShaOnCopy` setting to specify to whether to copy full or abbreviated commit SHAs to the clipboard. Abbreviates to the length of `gitlens.advanced.abbreviatedShaLength` — closes [#1062](https://github.com/eamodio/vscode-gitlens/issues/1062) — thanks to [PR #1316](https://github.com/eamodio/vscode-gitlens/pull/1316) by Brendon Smith ([@br3ndonland](https://github.com/br3ndonland)) - Adds a `gitlens.advanced.abbreviateShaOnCopy` setting to specify to whether to copy full or abbreviated commit SHAs to the clipboard. Abbreviates to the length of `gitlens.advanced.abbreviatedShaLength` — closes [#1062](https://github.com/eamodio/vscode-gitlens/issues/1062) — thanks to [PR #1316](https://github.com/eamodio/vscode-gitlens/pull/1316) by Brendon Smith ([@br3ndonland](https://github.com/br3ndonland))
- Adds a `gitlens.advanced.externalDiffTool` setting to specify an optional external diff tool to use when comparing files. Must be a configured [Git difftool](https://git-scm.com/docs/git-config#Documentation/git-config.txt-difftool). - Adds a `gitlens.advanced.externalDiffTool` setting to specify an optional external diff tool to use when comparing files. Must be a configured [Git difftool](https://git-scm.com/docs/git-config#Documentation/git-config.txt-difftool).
- Adds a `gitlens.advanced.externalDirectoryDiffTool` setting to specify an optional external diff tool to use when comparing directories. Must be a configured [Git difftool](https://git-scm.com/docs/git-config#Documentation/git-config.txt-difftool). - Adds a `gitlens.advanced.externalDirectoryDiffTool` setting to specify an optional external diff tool to use when comparing directories. Must be a configured [Git difftool](https://git-scm.com/docs/git-config#Documentation/git-config.txt-difftool).
- Adds a new `regex` option to `gitlens.remotes` to better support custom remote matching — closes [#1196](https://github.com/eamodio/vscode-gitlens/issues/1196)
### Changed ### Changed

+ 31
- 17
package.json View File

@ -1430,16 +1430,27 @@
"items": { "items": {
"type": "object", "type": "object",
"required": [ "required": [
"type",
"domain"
"type"
],
"oneOf": [
{
"required": [
"domain"
]
},
{
"required": [
"regex"
]
}
], ],
"properties": { "properties": {
"type": { "type": {
"type": "string", "type": "string",
"enum": [ "enum": [
"Custom",
"Bitbucket", "Bitbucket",
"BitbucketServer", "BitbucketServer",
"Custom",
"GitHub", "GitHub",
"GitLab" "GitLab"
], ],
@ -1449,6 +1460,10 @@
"type": "string", "type": "string",
"description": "Specifies the domain name of the custom remote service" "description": "Specifies the domain name of the custom remote service"
}, },
"regex": {
"type": "string",
"description": "Specifies a regular expression to capture the \"domain name\" and \"path\" of the custom remote service"
},
"name": { "name": {
"type": "string", "type": "string",
"description": "Specifies an optional friendly name for the custom remote service" "description": "Specifies an optional friendly name for the custom remote service"
@ -1474,45 +1489,44 @@
"properties": { "properties": {
"repository": { "repository": {
"type": "string", "type": "string",
"description": "Specifies the format of a respository url for the custom remote service\nAvailable tokens\n ${repo}` — repository path"
"markdownDescription": "Specifies the format of a respository url for the custom remote service\n\nAvailable tokens\\\n`${repo}` — repository path"
}, },
"branches": { "branches": {
"type": "string", "type": "string",
"description": "Specifies the format of a branches url for the custom remote service\nAvailable tokens\n ${repo}` — repository path\n ${branch}` — branch"
"markdownDescription": "Specifies the format of a branches url for the custom remote service\n\nAvailable tokens\\\n`${repo}` — repository path\\\n`${branch}` — branch"
}, },
"branch": { "branch": {
"type": "string", "type": "string",
"description": "Specifies the format of a branch url for the custom remote service\nAvailable tokens\n ${repo}` — repository path\n ${branch}` — branch"
"markdownDescription": "Specifies the format of a branch url for the custom remote service\n\nAvailable tokens\\\n`${repo}` — repository path\\\n`${branch}` — branch"
}, },
"commit": { "commit": {
"type": "string", "type": "string",
"description": "Specifies the format of a commit url for the custom remote service\nAvailable tokens\n ${repo}` — repository path\n ${id}` — commit SHA"
"markdownDescription": "Specifies the format of a commit url for the custom remote service\n\nAvailable tokens\\\n`${repo}` — repository path\\\n`${id}` — commit SHA"
}, },
"file": { "file": {
"type": "string", "type": "string",
"description": "Specifies the format of a file url for the custom remote service\nAvailable tokens\n ${repo}` — repository path\n ${file}` — file name\n ${line}` — formatted line information"
"markdownDescription": "Specifies the format of a file url for the custom remote service\n\nAvailable tokens\\\n`${repo}` — repository path\\\n`${file}` — file name\\\n`${line}` — formatted line information"
}, },
"fileInBranch": { "fileInBranch": {
"type": "string", "type": "string",
"description": "Specifies the format of a branch file url for the custom remote service\nAvailable tokens\n ${repo}` — repository path\n ${file}` — file name\n ${branch}` — branch\n ${line}` — formatted line information"
"markdownDescription": "Specifies the format of a branch file url for the custom remote service\n\nAvailable tokens\\\n`${repo}` — repository path\\\n`${file}` — file name\\\n`${branch}` — branch\\\n`${line}` — formatted line information"
}, },
"fileInCommit": { "fileInCommit": {
"type": "string", "type": "string",
"description": "Specifies the format of a commit file url for the custom remote service\nAvailable tokens\n ${repo}` — repository path\n ${file}` — file name\n ${id}` — commit SHA\n ${line}` — formatted line information"
"markdownDescription": "Specifies the format of a commit file url for the custom remote service\n\nAvailable tokens\\\n`${repo}` — repository path\\\n`${file}` — file name\\\n`${id}` — commit SHA\\\n`${line}` — formatted line information"
}, },
"fileLine": { "fileLine": {
"type": "string", "type": "string",
"description": "Specifies the format of a line in a file url for the custom remote service\nAvailable tokens\n ${line}` — line"
"markdownDescription": "Specifies the format of a line in a file url for the custom remote service\n\nAvailable tokens\\\n`${line}` — line"
}, },
"fileRange": { "fileRange": {
"type": "string", "type": "string",
"description": "Specifies the format of a range in a file url for the custom remote service\nAvailable tokens\n ${start}` — starting line\n ${end}` — ending line"
"markdownDescription": "Specifies the format of a range in a file url for the custom remote service\n\nAvailable tokens\\\n`${start}` — starting line\\\n`${end}` — ending line"
} }
}
},
"description": "Specifies the url formats of the custom remote service"
},
"additionalProperties": false
},
"additionalProperties": false
}
}
}, },
"uniqueItems": true, "uniqueItems": true,
"markdownDescription": "Specifies user-defined remote (code-hosting) services or custom domains for built-in remote services", "markdownDescription": "Specifies user-defined remote (code-hosting) services or custom domains for built-in remote services",

+ 17
- 7
src/config.ts View File

@ -412,13 +412,23 @@ export interface ModeConfig {
statusBar?: boolean; statusBar?: boolean;
} }
export interface RemotesConfig {
domain: string;
name?: string;
protocol?: string;
type: CustomRemoteType;
urls?: RemotesUrlsConfig;
}
export type RemotesConfig =
| {
domain: string;
regex: null;
name?: string;
protocol?: string;
type: CustomRemoteType;
urls?: RemotesUrlsConfig;
}
| {
domain: null;
regex: string;
name?: string;
protocol?: string;
type: CustomRemoteType;
urls?: RemotesUrlsConfig;
};
export interface RemotesUrlsConfig { export interface RemotesUrlsConfig {
repository: string; repository: string;

+ 69
- 21
src/git/remotes/factory.ts View File

@ -10,19 +10,48 @@ import { Logger } from '../../logger';
import { RemoteProvider, RichRemoteProvider } from './provider'; import { RemoteProvider, RichRemoteProvider } from './provider';
export { RemoteProvider, RichRemoteProvider }; export { RemoteProvider, RichRemoteProvider };
export type RemoteProviders = [string | RegExp, (domain: string, path: string) => RemoteProvider][];
export type RemoteProviders = {
custom: boolean;
matcher: string | RegExp;
creator: (domain: string, path: string) => RemoteProvider;
}[];
const defaultProviders: RemoteProviders = [
['bitbucket.org', (domain: string, path: string) => new BitbucketRemote(domain, path)],
['github.com', (domain: string, path: string) => new GitHubRemote(domain, path)],
['gitlab.com', (domain: string, path: string) => new GitLabRemote(domain, path)],
[/\bdev\.azure\.com$/i, (domain: string, path: string) => new AzureDevOpsRemote(domain, path)],
[/\bbitbucket\b/i, (domain: string, path: string) => new BitbucketServerRemote(domain, path)],
[/\bgitlab\b/i, (domain: string, path: string) => new GitLabRemote(domain, path)],
[
/\bvisualstudio\.com$/i,
(domain: string, path: string) => new AzureDevOpsRemote(domain, path, undefined, undefined, true),
],
const builtInProviders: RemoteProviders = [
{
custom: false,
matcher: 'bitbucket.org',
creator: (domain: string, path: string) => new BitbucketRemote(domain, path),
},
{
custom: false,
matcher: 'github.com',
creator: (domain: string, path: string) => new GitHubRemote(domain, path),
},
{
custom: false,
matcher: 'gitlab.com',
creator: (domain: string, path: string) => new GitLabRemote(domain, path),
},
{
custom: false,
matcher: /\bdev\.azure\.com$/i,
creator: (domain: string, path: string) => new AzureDevOpsRemote(domain, path),
},
{
custom: false,
matcher: /\bbitbucket\b/i,
creator: (domain: string, path: string) => new BitbucketServerRemote(domain, path),
},
{
custom: false,
matcher: /\bgitlab\b/i,
creator: (domain: string, path: string) => new GitLabRemote(domain, path),
},
{
custom: false,
matcher: /\bvisualstudio\.com$/i,
creator: (domain: string, path: string) => new AzureDevOpsRemote(domain, path, undefined, undefined, true),
},
]; ];
export class RemoteProviderFactory { export class RemoteProviderFactory {
@ -33,12 +62,19 @@ export class RemoteProviderFactory {
static create(providers: RemoteProviders, domain: string, path: string): RemoteProvider | undefined { static create(providers: RemoteProviders, domain: string, path: string): RemoteProvider | undefined {
try { try {
const key = domain.toLowerCase(); const key = domain.toLowerCase();
for (const [matcher, creator] of providers) {
if (
(typeof matcher === 'string' && matcher === key) ||
(typeof matcher !== 'string' && matcher.test(key))
) {
return creator(domain, path);
for (const { custom, matcher, creator } of providers) {
if (typeof matcher === 'string') {
if (matcher === key) return creator(domain, path);
continue;
}
if (matcher.test(key)) return creator(domain, path);
if (!custom) continue;
const match = matcher.exec(`${domain}/${path}`);
if (match != null) {
return creator(match[1], match[2]);
} }
} }
@ -55,13 +91,25 @@ export class RemoteProviderFactory {
if (cfg != null && cfg.length > 0) { if (cfg != null && cfg.length > 0) {
for (const rc of cfg) { for (const rc of cfg) {
const provider = this.getCustomProvider(rc); const provider = this.getCustomProvider(rc);
if (provider === undefined) continue;
if (provider == null) continue;
let matcher: string | RegExp | undefined;
try {
matcher = rc.regex ? new RegExp(rc.regex, 'i') : rc.domain?.toLowerCase();
if (matcher == null) throw new Error('No matcher found');
} catch (ex) {
Logger.error(ex, `Loading remote provider '${rc.name ?? ''}' failed`);
}
providers.push([rc.domain.toLowerCase(), provider]);
providers.push({
custom: true,
matcher: matcher!,
creator: provider,
});
} }
} }
providers.push(...defaultProviders);
providers.push(...builtInProviders);
return providers; return providers;
} }

Loading…
Cancel
Save