Skip to content

Commit 21e0963

Browse files
committed
Adds bitbucket server support
1 parent 62580da commit 21e0963

File tree

10 files changed

+78
-16
lines changed

10 files changed

+78
-16
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
6363
- Clicking on `Changes` will run the `Compare File Revisions` command (`gitlens.diffWith`)
6464
- Clicking the current and previous commit ids will run the `Show Commit Details` command (`gitlens.showQuickCommitDetails`)
6565
- Adds support for custom remote services - see [#120](https://github.com/eamodio/vscode-gitlens/issues/120)
66+
- Adds support for Bitbucket Server (previously called Stash) remote services - see [#120](https://github.com/eamodio/vscode-gitlens/issues/120)
6667
- Adds `Compare File Revisions` command (`gitlens.diffWith`) - compares the specified file revisions
6768
- Adds `Open Branches in Remote` command (`gitlens.openBranchesInRemote`) - opens the branches in the supported remote service
6869
- Adds `Stash Changes` command (`gitlens.stashSave`) to the source control group context menu -- can now stash a group of files

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ GitLens provides an unobtrusive blame annotation at the end of the current line,
172172
- Adds a `Search Commits` command (`gitlens.showCommitSearch`) with a shortcut of `alt+/` to search for commits by message, author, file(s), or commit id
173173

174174
- Adds commands to open files, commits, branches, and the repository in the supported remote services, currently **BitBucket, GitHub, GitLab, and Visual Studio Team Services** — only available if a Git upstream service is configured in the repository
175+
- Also supports [custom](#custom-remote-settings) remote services, such as **BitBucket, Bitbucket Server (previously called Stash), GitHub, GitLab**
175176
- `Open Branches in Remote` command (`gitlens.openBranchesInRemote`) — opens the branches in the supported remote service
176177
- `Open Branch in Remote` command (`gitlens.openBranchInRemote`) — opens the current branch commits in the supported remote service
177178
- `Open Commit in Remote` command (`gitlens.openCommitInRemote`) — opens the commit revision of the active line in the supported remote service
@@ -350,7 +351,7 @@ GitLens is highly customizable and provides many configuration settings to allow
350351
|`gitlens.gitExplorer.stashFormat`|Specifies the format of stashed changes in the `GitLens` custom view<br />Available tokens<br /> ${id} - commit id<br /> ${author} - commit author<br /> ${message} - commit message<br /> ${ago} - relative commit date (e.g. 1 day ago)<br /> ${date} - formatted commit date (format specified by `gitlens.statusBar.dateFormat`)<br /> ${authorAgo} - commit author, relative commit date<br />See https://github.com/eamodio/vscode-gitlens/wiki/Advanced-Formatting for advanced formatting
351352
|`gitlens.gitExplorer.stashFileFormat`|Specifies the format of a stashed file in the `GitLens` custom view<br />Available tokens<br /> ${file} - file name<br /> ${filePath} - file name and path<br /> ${path} - file path
352353

353-
### GitLens Custom Remotes Settings
354+
### Custom Remotes Settings
354355

355356
|Name | Description
356357
|-----|------------

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,10 +461,11 @@
461461
"type": "string",
462462
"enum": [
463463
"Bitbucket",
464+
"BitbucketServer",
464465
"GitHub",
465466
"GitLab"
466467
],
467-
"description": "Specifies the type of the custom remote service\n `Bitbucket`, `GitHub`, or `GitLab`"
468+
"description": "Specifies the type of the custom remote service\n `Bitbucket`, `BitbucketServer`, `GitHub`, or `GitLab`"
468469
},
469470
"domain": {
470471
"type": "string",

src/configuration.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ export type CustomRemoteType =
4848
'GitLab';
4949
export const CustomRemoteType = {
5050
Bitbucket: 'Bitbucket' as CustomRemoteType,
51+
BitbucketServer: 'BitbucketServer' as CustomRemoteType,
5152
GitHub: 'GitHub' as CustomRemoteType,
5253
GitLab: 'GitLab' as CustomRemoteType
5354
};
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
'use strict';
2+
import { Range } from 'vscode';
3+
import { RemoteProvider } from './provider';
4+
5+
export class BitbucketServerService extends RemoteProvider {
6+
7+
constructor(public domain: string, public path: string, public custom: boolean = false) {
8+
super(domain, path);
9+
}
10+
11+
get name() {
12+
return this.formatName('Bitbucket Server');
13+
}
14+
15+
protected get baseUrl() {
16+
const [project, repo] = super.splitPath();
17+
return `https://${this.domain}/projects/${project}/repos/${repo}`;
18+
}
19+
20+
protected getUrlForBranches(): string {
21+
return `${this.baseUrl}/branches`;
22+
}
23+
24+
protected getUrlForBranch(branch: string): string {
25+
return `${this.baseUrl}/commits?until=${branch}`;
26+
}
27+
28+
protected getUrlForCommit(sha: string): string {
29+
return `${this.baseUrl}/commits/${sha}`;
30+
}
31+
32+
protected getUrlForFile(fileName: string, branch?: string, sha?: string, range?: Range): string {
33+
let line = '';
34+
if (range) {
35+
if (range.start.line === range.end.line) {
36+
line = `#${range.start.line}`;
37+
}
38+
else {
39+
line = `#${range.start.line}-${range.end.line}`;
40+
}
41+
}
42+
43+
if (sha) return `${this.baseUrl}/browse/${fileName}?at=${sha}${line}`;
44+
if (branch) return `${this.baseUrl}/browse/${fileName}?at=${branch}${line}`;
45+
return `${this.baseUrl}/browse/${fileName}${line}`;
46+
}
47+
}

src/git/remotes/bitbucket.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ import { RemoteProvider } from './provider';
44

55
export class BitbucketService extends RemoteProvider {
66

7-
constructor(public domain: string, public path: string) {
7+
constructor(public domain: string, public path: string, public custom: boolean = false) {
88
super(domain, path);
99
}
1010

1111
get name() {
12-
return 'Bitbucket';
12+
return this.formatName('Bitbucket');
1313
}
1414

1515
protected getUrlForBranches(): string {

src/git/remotes/factory.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22
import { ExtensionContext, workspace } from 'vscode';
33
import { BitbucketService } from './bitbucket';
4+
import { BitbucketServerService } from './bitbucket-server';
45
import { CustomRemoteType, IConfig, IRemotesConfig } from '../../configuration';
56
import { ExtensionKey } from '../../constants';
67
import { GitHubService } from './github';
@@ -14,11 +15,12 @@ export { RemoteProvider };
1415

1516
const UrlRegex = /^(?:git:\/\/(.*?)\/|https:\/\/(.*?)\/|http:\/\/(.*?)\/|git@(.*):|ssh:\/\/(?:.*@)?(.*?)(?::.*?)?\/)(.*)$/;
1617

17-
function getProviderKey(type: CustomRemoteType) {
18+
function getCustomProvider(type: CustomRemoteType) {
1819
switch (type) {
19-
case CustomRemoteType.Bitbucket: return 'bitbucket.org';
20-
case CustomRemoteType.GitHub: return 'github.com';
21-
case CustomRemoteType.GitLab: return 'gitlab.com';
20+
case CustomRemoteType.Bitbucket: return (domain: string, path: string) => new BitbucketService(domain, path, true);
21+
case CustomRemoteType.BitbucketServer: return (domain: string, path: string) => new BitbucketServerService(domain, path, true);
22+
case CustomRemoteType.GitHub: return (domain: string, path: string) => new GitHubService(domain, path, true);
23+
case CustomRemoteType.GitLab: return (domain: string, path: string) => new GitLabService(domain, path, true);
2224
}
2325
return undefined;
2426
}
@@ -43,10 +45,10 @@ function onConfigurationChanged() {
4345
remotesCfg = cfg.remotes;
4446
if (remotesCfg != null && remotesCfg.length > 0) {
4547
for (const svc of remotesCfg) {
46-
const key = getProviderKey(svc.type);
47-
if (key === undefined) continue;
48+
const provider = getCustomProvider(svc.type);
49+
if (provider === undefined) continue;
4850

49-
providerMap.set(svc.domain.toLowerCase(), providerMap.get(key)!);
51+
providerMap.set(svc.domain.toLowerCase(), provider);
5052
}
5153
}
5254
}

src/git/remotes/github.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ import { RemoteProvider } from './provider';
44

55
export class GitHubService extends RemoteProvider {
66

7-
constructor(public domain: string, public path: string) {
7+
constructor(public domain: string, public path: string, public custom: boolean = false) {
88
super(domain, path);
99
}
1010

1111
get name() {
12-
return 'GitHub';
12+
return this.formatName('GitHub');
1313
}
1414

1515
protected getUrlForBranches(): string {

src/git/remotes/gitlab.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ import { GitHubService } from './github';
33

44
export class GitLabService extends GitHubService {
55

6-
constructor(public domain: string, public path: string) {
6+
constructor(public domain: string, public path: string, public custom: boolean = false) {
77
super(domain, path);
88
}
99

1010
get name() {
11-
return 'GitLab';
11+
return this.formatName('GitLab');
1212
}
1313
}

src/git/remotes/provider.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,23 @@ export function getNameFromRemoteResource(resource: RemoteResource) {
2626

2727
export abstract class RemoteProvider {
2828

29-
constructor(public domain: string, public path: string) { }
29+
constructor(public domain: string, public path: string, public custom: boolean = false) { }
3030

3131
abstract get name(): string;
3232

3333
protected get baseUrl() {
3434
return `https://${this.domain}/${this.path}`;
3535
}
3636

37+
protected formatName(name: string) {
38+
return `${name}${this.custom ? ` (${this.domain})` : ''}`;
39+
}
40+
41+
protected splitPath(): [string, string] {
42+
const index = this.path.indexOf('/');
43+
return [ this.path.substring(0, index), this.path.substring(index + 1) ];
44+
}
45+
3746
protected abstract getUrlForBranches(): string;
3847
protected abstract getUrlForBranch(branch: string): string;
3948
protected abstract getUrlForCommit(sha: string): string;

0 commit comments

Comments
 (0)