Skip to content

Commit f2a3947

Browse files
committed
Extract getting URL of each Git providers into gitProvider module
1 parent ad01b74 commit f2a3947

File tree

4 files changed

+262
-55
lines changed

4 files changed

+262
-55
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,8 @@
9393
"copy-paste": "^1.1.4",
9494
"find-parent-dir": "^0.3.0",
9595
"git-rev-2": "^0.1.0",
96-
"github-url-from-git": "^1.4.0",
96+
"git-url-parse": "^6.1.0",
9797
"open": "0.0.5",
9898
"parse-git-config": "^0.3.1"
9999
}
100-
}
100+
}

src/extension.js

Lines changed: 8 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -10,28 +10,12 @@ var Position = VsCode.Position;
1010
var path = require('path');
1111
var fs = require('fs');
1212
var git = require('parse-git-config');
13-
var parse = require('github-url-from-git');
1413
var open = require('open');
1514
var copy = require('copy-paste').copy;
1615
var gitRev = require('git-rev-2');
1716
var findParentDir = require('find-parent-dir');
1817

19-
function formGitHubLink(parsedUri, branch, subdir, line) {
20-
if (subdir) {
21-
return parsedUri + "/blob/" + branch + subdir + (line ? "#L" + line : "");
22-
}
23-
24-
return parsedUri + "/tree/" + branch;
25-
}
26-
27-
28-
function formBitBucketLink(parsedUri, branch, subdir, line) {
29-
return parsedUri + "/src/" + branch + (subdir ? subdir : "") + (line ? "#cl-" + line : "");
30-
}
31-
32-
function formVisualStudioLink(parsedUri, subdir, branch, line) {
33-
return parsedUri + "#" + (subdir ? "path=" + subdir : "") + "&version=GB" + branch + (line ? "&line=" + line : "");
34-
}
18+
const gitProvider = require('./gitProvider');
3519

3620
function getGitHubLink(cb, fileFsPath, line) {
3721
var cwd = workspace.rootPath;
@@ -40,56 +24,27 @@ function getGitHubLink(cb, fileFsPath, line) {
4024
git({
4125
cwd: repoDir
4226
}, function (err, config) {
43-
var rawUri, parseOpts, parsedUri, branch, projectName,
44-
subdir, gitLink, scUrls, workspaceConfiguration;
45-
46-
workspaceConfiguration = VsCode.workspace.getConfiguration("openInGitHub");
47-
scUrls = {
48-
github: 'https://' + workspaceConfiguration.gitHubDomain,
49-
bitbucket: 'https://bitbucket.org',
50-
visualstudiocom: /^https:\/\/[\w\d-]*\.visualstudio.com\//
51-
}
27+
const rawUri = config['remote \"origin\"'].url;
28+
const provider = gitProvider(rawUri);
5229

53-
rawUri = config['remote \"origin\"'].url;
54-
parseOpts = {
55-
extraBaseUrls: [
56-
'bitbucket.org',
57-
workspaceConfiguration.gitHubDomain
58-
]
59-
}
60-
61-
rawUri = rawUri.replace('bitbucket.org:', 'bitbucket.org/')
62-
63-
parsedUri = parse(rawUri, parseOpts);
64-
if (!parsedUri) {
65-
parsedUri = rawUri;
30+
if (!provider) {
31+
Window.showWarningMessage('Unknown Git provider.');
32+
return;
6633
}
6734

6835
gitRev.branch(cwd, function (branchErr, branch) {
6936
if (branchErr || !branch)
7037
branch = 'master';
7138

72-
projectName = parsedUri.substring(parsedUri.lastIndexOf("/") + 1, parsedUri.length);
73-
subdir = fileFsPath ? fileFsPath.substring(workspace.rootPath.length).replace(/\"/g, "") : undefined;
39+
let subdir = fileFsPath ? fileFsPath.substring(workspace.rootPath.length).replace(/\"/g, "") : undefined;
7440

7541
if (repoDir !== cwd) {
7642
// The workspace directory is a subdirectory of the git repo folder so we need to prepend the the nested path
7743
var repoRelativePath = cwd.replace(repoDir, "/");
7844
subdir = repoRelativePath + subdir;
7945
}
8046

81-
if (parsedUri.startsWith(scUrls.github)) {
82-
gitLink = formGitHubLink(parsedUri, branch, subdir, line);
83-
} else if (parsedUri.startsWith(scUrls.bitbucket)) {
84-
gitLink = formBitBucketLink(parsedUri, branch, subdir, line);
85-
} else if (scUrls.visualstudiocom.test(parsedUri)) {
86-
gitLink = formVisualStudioLink(parsedUri, subdir, branch, line);
87-
} else {
88-
Window.showWarningMessage('Unknown Git provider.');
89-
}
90-
91-
if (gitLink)
92-
cb(gitLink);
47+
cb(provider.webUrl(branch, subdir, line));
9348
});
9449
});
9550
}

src/gitProvider.js

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
'use strict';
2+
3+
const workspace = require('vscode').workspace
4+
const querystring = require('querystring');
5+
const gitUrlParse = require('git-url-parse');
6+
7+
class BaseProvider {
8+
constructor(gitUrl) {
9+
this.gitUrl = gitUrl;
10+
}
11+
12+
get baseUrl() {
13+
return this.gitUrl.toString('https').replace(/\.git/, '');
14+
}
15+
16+
/**
17+
* Get the Web URL.
18+
*
19+
* @param {string} branch
20+
* @param {string} filePath The file path relative to repository root, beginning with '/'.
21+
* @param {number} line
22+
* @return {string} The URL to be opened with the browser.
23+
*/
24+
webUrl(branch, filePath, line) {
25+
return '';
26+
}
27+
}
28+
29+
class GitHub extends BaseProvider {
30+
webUrl(branch, filePath, line) {
31+
if (filePath) {
32+
return `${this.baseUrl}/blob/${branch}${filePath}` + (line ? '#L' + line : '');
33+
}
34+
return `${this.baseUrl}/tree/${branch}`;
35+
}
36+
}
37+
38+
class Bitbucket extends BaseProvider {
39+
webUrl(branch, filePath, line) {
40+
return `${this.baseUrl}/src/${branch}` + (filePath ? `${filePath}` : '') + (line ? `#cl-${line}` : '');
41+
}
42+
}
43+
44+
class VisualStudio extends BaseProvider {
45+
get baseUrl() {
46+
return `https://${this.gitUrl.resource}${this.gitUrl.pathname}`.replace(/\.git/, '');
47+
}
48+
49+
webUrl(branch, filePath, line) {
50+
let query = {
51+
version: `GB${branch}`,
52+
};
53+
if (filePath) {
54+
query['path'] = filePath;
55+
}
56+
if (line) {
57+
query['line'] = line;
58+
}
59+
return `${this.baseUrl}?${querystring.stringify(query)}`;
60+
}
61+
}
62+
63+
const gitHubDomain = workspace.getConfiguration('openInGitHub').get('gitHubDomain', 'github.com');
64+
65+
const providers = {
66+
[gitHubDomain]: GitHub,
67+
'bitbucket.org': Bitbucket,
68+
'visualstudio.com': VisualStudio,
69+
};
70+
71+
/**
72+
* Get the Git provider of the remote URL.
73+
*
74+
* @param {string} remoteUrl
75+
* @return {BaseProvider|null}
76+
*/
77+
function gitProvider(remoteUrl) {
78+
const gitUrl = gitUrlParse(remoteUrl);
79+
for (const domain of Object.keys(providers)) {
80+
if (domain === gitUrl.source) {
81+
return new providers[domain](gitUrl);
82+
}
83+
}
84+
return null;
85+
}
86+
87+
module.exports = gitProvider;

test/gitProvider.test.js

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
'use strict';
2+
3+
const querystring = require('querystring');
4+
const expect = require('chai').expect;
5+
6+
const gitProvider = require('../src/gitProvider');
7+
8+
const userName = 'testUser';
9+
const repoName = 'testRepo';
10+
const filePath = '/sampleDirectory/sampleTestFile.txt';
11+
const branch = 'master';
12+
const line = 123;
13+
14+
suite('gitProvider', function () {
15+
suite('GitHub', function () {
16+
const remoteUrl = `https://github.com/${userName}/${repoName}.git`;
17+
const provider = gitProvider(remoteUrl);
18+
19+
suite('#webUrl(branch, filePath)', function () {
20+
test('should returns file URL', function () {
21+
const expectedUrl = `https://github.com/${userName}/${repoName}/blob/${branch}${filePath}`;
22+
const webUrl = provider.webUrl(branch, filePath);
23+
expect(webUrl).to.equal(expectedUrl);
24+
});
25+
});
26+
27+
suite('#webUrl(branch, filePath, line)', function () {
28+
test('should returns file URL with line hash', function () {
29+
const expectedUrl = `https://github.com/${userName}/${repoName}/blob/${branch}${filePath}#L${line}`;
30+
const webUrl = provider.webUrl(branch, filePath, line);
31+
expect(webUrl).to.equal(expectedUrl);
32+
});
33+
});
34+
35+
suite('#webUrl(branch)', function () {
36+
test('should returns repository root URL', function () {
37+
const expectedUrl = `https://github.com/${userName}/${repoName}/tree/${branch}`;
38+
const webUrl = provider.webUrl(branch);
39+
expect(webUrl).to.equal(expectedUrl);
40+
});
41+
});
42+
43+
suite('with ssh remote URL', function () {
44+
const remoteUrl = `[email protected]:${userName}/${repoName}.git`;
45+
const provider = gitProvider(remoteUrl);
46+
47+
suite('#webUrl(branch, filePath)', function () {
48+
test('should returns HTTPS URL', function () {
49+
const expectedUrl = `https://github.com/${userName}/${repoName}/blob/${branch}${filePath}`;
50+
const webUrl = provider.webUrl(branch, filePath);
51+
expect(webUrl).to.equal(expectedUrl);
52+
});
53+
});
54+
});
55+
});
56+
57+
suite('Bitbucket', function () {
58+
const remoteUrl = `https://bitbucket.org/${userName}/${repoName}.git`;
59+
const provider = gitProvider(remoteUrl);
60+
61+
suite('#webUrl(branch, filePath)', function () {
62+
test('should returns file URL', function () {
63+
const expectedUrl = `https://bitbucket.org/${userName}/${repoName}/src/${branch}${filePath}`;
64+
const webUrl = provider.webUrl(branch, filePath);
65+
expect(webUrl).to.equal(expectedUrl);
66+
});
67+
});
68+
69+
suite('#webUrl(branch, filePath, line)', function () {
70+
test('should returns file URL with line hash', function () {
71+
const expectedUrl = `https://bitbucket.org/${userName}/${repoName}/src/${branch}${filePath}#cl-${line}`;
72+
const webUrl = provider.webUrl(branch, filePath, line);
73+
expect(webUrl).to.equal(expectedUrl);
74+
});
75+
});
76+
77+
suite('#webUrl(branch)', function () {
78+
test('should returns repository root URL', function () {
79+
const expectedUrl = `https://bitbucket.org/${userName}/${repoName}/src/${branch}`;
80+
const webUrl = provider.webUrl(branch);
81+
expect(webUrl).to.equal(expectedUrl);
82+
});
83+
});
84+
85+
suite('with ssh remote URL', function () {
86+
const remoteUrl = `[email protected]:${userName}/${repoName}.git`;
87+
const provider = gitProvider(remoteUrl);
88+
89+
suite('#webUrl(branch, filePath)', function () {
90+
test('should returns HTTPS URL', function () {
91+
const expectedUrl = `https://bitbucket.org/${userName}/${repoName}/src/${branch}${filePath}`;
92+
const webUrl = provider.webUrl(branch, filePath);
93+
expect(webUrl).to.equal(expectedUrl);
94+
});
95+
});
96+
});
97+
});
98+
99+
suite('VisualStudio', function () {
100+
const projectName = 'testProject';
101+
const remoteUrl = `https://test-account.visualstudio.com/${projectName}/_git/${repoName}.git`;
102+
const provider = gitProvider(remoteUrl);
103+
104+
suite('#webUrl(branch, filePath)', function () {
105+
test('should returns file URL', function () {
106+
const expectedUrl = `https://test-account.visualstudio.com/${projectName}/_git/${repoName}`;
107+
const expectedQuery = {
108+
path: filePath,
109+
version: `GB${branch}`,
110+
};
111+
const webUrl = provider.webUrl(branch, filePath);
112+
const [url, query] = webUrl.split('?');
113+
expect(url).to.equal(expectedUrl);
114+
expect(querystring.parse(query)).to.deep.equal(expectedQuery);
115+
});
116+
});
117+
118+
suite('#webUrl(branch, filePath, line)', function () {
119+
test('should returns file URL with line query', function () {
120+
const expectedUrl = `https://test-account.visualstudio.com/${projectName}/_git/${repoName}`;
121+
const expectedQuery = {
122+
path: filePath,
123+
version: `GB${branch}`,
124+
line: String(line),
125+
};
126+
const webUrl = provider.webUrl(branch, filePath, line);
127+
const [url, query] = webUrl.split('?');
128+
expect(url).to.equal(expectedUrl);
129+
expect(querystring.parse(query)).to.deep.equal(expectedQuery);
130+
});
131+
});
132+
133+
suite('#webUrl(branch)', function () {
134+
test('should returns repository root URL', function () {
135+
const expectedUrl = `https://test-account.visualstudio.com/${projectName}/_git/${repoName}`;
136+
const expectedQuery = {
137+
version: `GB${branch}`,
138+
};
139+
const webUrl = provider.webUrl(branch);
140+
const [url, query] = webUrl.split('?');
141+
expect(url).to.equal(expectedUrl);
142+
expect(querystring.parse(query)).to.deep.equal(expectedQuery);
143+
});
144+
});
145+
146+
suite('with ssh remote URL', function () {
147+
const remoteUrl = `ssh://[email protected]:22/${projectName}/_git/${repoName}.git`;
148+
const provider = gitProvider(remoteUrl);
149+
150+
suite('#webUrl(branch, filePath)', function () {
151+
test('should returns HTTPS URL', function () {
152+
const expectedUrl = `https://test-account.visualstudio.com/${projectName}/_git/${repoName}`;
153+
const expectedQuery = {
154+
path: filePath,
155+
version: `GB${branch}`,
156+
};
157+
const webUrl = provider.webUrl(branch, filePath);
158+
const [url, query] = webUrl.split('?');
159+
expect(url).to.equal(expectedUrl);
160+
expect(querystring.parse(query)).to.deep.equal(expectedQuery);
161+
});
162+
});
163+
});
164+
});
165+
});

0 commit comments

Comments
 (0)