diff --git a/package.json b/package.json index df389c8..1a29c63 100644 --- a/package.json +++ b/package.json @@ -949,6 +949,11 @@ "title": "Open Changed Files", "category": "GitLens" }, + { + "command": "gitlens.openBranchesInRemote", + "title": "Open Branches in Remote", + "category": "GitLens" + }, { "command": "gitlens.openBranchInRemote", "title": "Open Branch in Remote", @@ -1183,6 +1188,10 @@ "command": "gitlens.openChangedFiles", "when": "gitlens:enabled" }, + { + "command": "gitlens.openBranchesInRemote", + "when": "gitlens:hasRemotes" + }, { "command": "gitlens.openBranchInRemote", "when": "gitlens:hasRemotes" @@ -1472,6 +1481,11 @@ } ], "view/item/context": [ + { + "command": "gitlens.openBranchesInRemote", + "when": "gitlens:enabled && view == gitlens.gitExplorer && viewItem == gitlens:branches", + "group": "1_gitlens@1" + }, { "command": "gitlens.openBranchInRemote", "when": "gitlens:enabled && view == gitlens.gitExplorer && viewItem == gitlens:branch-history", @@ -1617,6 +1631,11 @@ "when": "gitlens:isTracked && view == gitlens.gitExplorer && viewItem == gitlens:stash-file", "group": "5_gitlens@1" }, + { + "command": "gitlens.openRepoInRemote", + "when": "gitlens:enabled && view == gitlens.gitExplorer && viewItem == gitlens:status", + "group": "1_gitlens@1" + }, { "command": "gitlens.gitExplorer.refresh", "when": "gitlens:enabled && view == gitlens.gitExplorer && viewItem != gitlens:commit-file && viewItem != gitlens:stash-file", diff --git a/src/commands.ts b/src/commands.ts index 6e2919f..b00bde4 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -14,6 +14,7 @@ export * from './commands/diffWithPrevious'; export * from './commands/diffWithRevision'; export * from './commands/diffWithWorking'; export * from './commands/openChangedFiles'; +export * from './commands/openBranchesInRemote'; export * from './commands/openBranchInRemote'; export * from './commands/openCommitInRemote'; export * from './commands/openFileInRemote'; diff --git a/src/commands/common.ts b/src/commands/common.ts index 2ef0cad..b7129f3 100644 --- a/src/commands/common.ts +++ b/src/commands/common.ts @@ -19,6 +19,7 @@ export type Commands = 'gitlens.diffWithWorking' | 'gitlens.diffLineWithWorking' | 'gitlens.openChangedFiles' | + 'gitlens.openBranchesInRemote' | 'gitlens.openBranchInRemote' | 'gitlens.openCommitInRemote' | 'gitlens.openFileInRemote' | @@ -59,6 +60,7 @@ export const Commands = { DiffWithWorking: 'gitlens.diffWithWorking' as Commands, DiffLineWithWorking: 'gitlens.diffLineWithWorking' as Commands, OpenChangedFiles: 'gitlens.openChangedFiles' as Commands, + OpenBranchesInRemote: 'gitlens.openBranchesInRemote' as Commands, OpenBranchInRemote: 'gitlens.openBranchInRemote' as Commands, OpenCommitInRemote: 'gitlens.openCommitInRemote' as Commands, OpenFileInRemote: 'gitlens.openFileInRemote' as Commands, diff --git a/src/commands/openBranchesInRemote.ts b/src/commands/openBranchesInRemote.ts new file mode 100644 index 0000000..1ebdc1c --- /dev/null +++ b/src/commands/openBranchesInRemote.ts @@ -0,0 +1,37 @@ +'use strict'; +import { Arrays } from '../system'; +import { commands, TextEditor, Uri, window } from 'vscode'; +import { ActiveEditorCommand, Commands, getCommandUri } from './common'; +import { GitService, GitUri } from '../gitService'; +import { Logger } from '../logger'; +import { OpenInRemoteCommandArgs } from './openInRemote'; + +export class OpenBranchesInRemoteCommand extends ActiveEditorCommand { + + constructor(private git: GitService) { + super(Commands.OpenBranchesInRemote); + } + + async execute(editor?: TextEditor, uri?: Uri) { + uri = getCommandUri(uri, editor); + + const gitUri = uri && await GitUri.fromUri(uri, this.git); + + const repoPath = gitUri === undefined ? this.git.repoPath : gitUri.repoPath; + if (!repoPath) return undefined; + + try { + const remotes = Arrays.uniqueBy(await this.git.getRemotes(repoPath), _ => _.url, _ => !!_.provider); + return commands.executeCommand(Commands.OpenInRemote, uri, { + resource: { + type: 'branches' + }, + remotes + } as OpenInRemoteCommandArgs); + } + catch (ex) { + Logger.error(ex, 'OpenBranchesInRemoteCommand'); + return window.showErrorMessage(`Unable to open branches in remote provider. See output channel for more details`); + } + } +} \ No newline at end of file diff --git a/src/extension.ts b/src/extension.ts index 5164786..b74b6f1 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -3,7 +3,7 @@ import { commands, ExtensionContext, extensions, languages, window, workspace } from 'vscode'; import { AnnotationController } from './annotations/annotationController'; import { CloseUnchangedFilesCommand, OpenChangedFilesCommand } from './commands'; -import { OpenBranchInRemoteCommand, OpenCommitInRemoteCommand, OpenFileInRemoteCommand, OpenInRemoteCommand, OpenRepoInRemoteCommand } from './commands'; +import { OpenBranchesInRemoteCommand, OpenBranchInRemoteCommand, OpenCommitInRemoteCommand, OpenFileInRemoteCommand, OpenInRemoteCommand, OpenRepoInRemoteCommand } from './commands'; import { CopyMessageToClipboardCommand, CopyShaToClipboardCommand } from './commands'; import { DiffDirectoryCommand, DiffLineWithPreviousCommand, DiffLineWithWorkingCommand, DiffWithBranchCommand, DiffWithNextCommand, DiffWithPreviousCommand, DiffWithRevisionCommand, DiffWithWorkingCommand } from './commands'; import { ResetSuppressedWarningsCommand } from './commands'; @@ -108,6 +108,7 @@ export async function activate(context: ExtensionContext) { context.subscriptions.push(new DiffWithPreviousCommand(git)); context.subscriptions.push(new DiffWithRevisionCommand(git)); context.subscriptions.push(new DiffWithWorkingCommand(git)); + context.subscriptions.push(new OpenBranchesInRemoteCommand(git)); context.subscriptions.push(new OpenBranchInRemoteCommand(git)); context.subscriptions.push(new OpenCommitInRemoteCommand(git)); context.subscriptions.push(new OpenFileInRemoteCommand(git)); diff --git a/src/git/remotes/bitbucket.ts b/src/git/remotes/bitbucket.ts index fdf07be..28d2951 100644 --- a/src/git/remotes/bitbucket.ts +++ b/src/git/remotes/bitbucket.ts @@ -12,6 +12,10 @@ export class BitbucketService extends RemoteProvider { return 'Bitbucket'; } + protected getUrlForBranches(): string { + return `${this.baseUrl}/branches`; + } + protected getUrlForBranch(branch: string): string { return `${this.baseUrl}/commits/branch/${branch}`; } diff --git a/src/git/remotes/github.ts b/src/git/remotes/github.ts index bde91db..6f6c88c 100644 --- a/src/git/remotes/github.ts +++ b/src/git/remotes/github.ts @@ -12,6 +12,10 @@ export class GitHubService extends RemoteProvider { return 'GitHub'; } + protected getUrlForBranches(): string { + return `${this.baseUrl}/branches`; + } + protected getUrlForBranch(branch: string): string { return `${this.baseUrl}/commits/${branch}`; } diff --git a/src/git/remotes/provider.ts b/src/git/remotes/provider.ts index c17f5a1..1c0933c 100644 --- a/src/git/remotes/provider.ts +++ b/src/git/remotes/provider.ts @@ -3,9 +3,10 @@ import { commands, Range, Uri } from 'vscode'; import { BuiltInCommands } from '../../constants'; import { GitLogCommit } from '../../gitService'; -export type RemoteResourceType = 'branch' | 'commit' | 'file' | 'repo' | 'revision'; +export type RemoteResourceType = 'branch' | 'branches' | 'commit' | 'file' | 'repo' | 'revision'; export type RemoteResource = { type: 'branch', branch: string } | + { type: 'branches' } | { type: 'commit', sha: string } | { type: 'file', branch?: string, fileName: string, range?: Range } | { type: 'repo' } | @@ -14,6 +15,7 @@ export type RemoteResource = export function getNameFromRemoteResource(resource: RemoteResource) { switch (resource.type) { case 'branch': return 'Branch'; + case 'branches': return 'Branches'; case 'commit': return 'Commit'; case 'file': return 'File'; case 'repo': return 'Repository'; @@ -32,6 +34,7 @@ export abstract class RemoteProvider { return `https://${this.domain}/${this.path}`; } + protected abstract getUrlForBranches(): string; protected abstract getUrlForBranch(branch: string): string; protected abstract getUrlForCommit(sha: string): string; protected abstract getUrlForFile(fileName: string, branch?: string, sha?: string, range?: Range): string; @@ -45,6 +48,7 @@ export abstract class RemoteProvider { open(resource: RemoteResource): Promise<{} | undefined> { switch (resource.type) { case 'branch': return this.openBranch(resource.branch); + case 'branches': return this.openBranches(); case 'commit': return this.openCommit(resource.sha); case 'file': return this.openFile(resource.fileName, resource.branch, undefined, resource.range); case 'repo': return this.openRepo(); @@ -56,6 +60,10 @@ export abstract class RemoteProvider { return this._openUrl(this.baseUrl); } + openBranches() { + return this._openUrl(this.getUrlForBranches()); + } + openBranch(branch: string) { return this._openUrl(this.getUrlForBranch(branch)); } diff --git a/src/git/remotes/visualStudio.ts b/src/git/remotes/visualStudio.ts index 89b5e08..f87d29a 100644 --- a/src/git/remotes/visualStudio.ts +++ b/src/git/remotes/visualStudio.ts @@ -12,6 +12,10 @@ export class VisualStudioService extends RemoteProvider { return 'Visual Studio Team Services'; } + protected getUrlForBranches(): string { + return `${this.baseUrl}/branches`; + } + protected getUrlForBranch(branch: string): string { return `${this.baseUrl}/?version=GB${branch}&_a=history`; } diff --git a/src/quickPicks/remotes.ts b/src/quickPicks/remotes.ts index 7777b74..a405bd1 100644 --- a/src/quickPicks/remotes.ts +++ b/src/quickPicks/remotes.ts @@ -38,6 +38,10 @@ export class OpenRemotesCommandQuickPickItem extends CommandQuickPickItem { description = `$(git-branch) ${resource.branch}`; break; + case 'branches': + description = `$(git-branch) Branches`; + break; + case 'commit': const shortSha = resource.sha.substring(0, 8); description = `$(git-commit) ${shortSha}`;