Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@
"title": "Copy Link to Selection (at current commit)",
"category": "Git Web Links"
},
{
"command": "gitweblinks.copySelectionToTag",
"title": "Copy Link to Selection (at current tag)",
"category": "Git Web Links"
},
{
"command": "gitweblinks.copySelectionToChoice",
"title": "Copy Link to Selection (choose type)",
Expand Down Expand Up @@ -194,12 +199,14 @@
"enum": [
"defaultBranch",
"commit",
"branch"
"branch",
"tag"
],
"enumDescriptions": [
"Create a link to the default branch.",
"Create a link to the current commit.",
"Create a link to the current branch."
"Create a link to the current branch.",
"Create a link to the current tag."
],
"default": "commit"
},
Expand Down
65 changes: 50 additions & 15 deletions vscode/src/commands/get-link-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,8 @@ export class GetLinkCommand {
targets = await Promise.all([
this.tryGetRef(info, 'branch'),
this.tryGetRef(info, 'commit'),
this.tryGetRef(info, 'defaultBranch')
this.tryGetRef(info, 'defaultBranch'),
this.tryGetRef(info, 'tag')
]);

defaultType = this.settings.getDefaultLinkType();
Expand Down Expand Up @@ -322,6 +323,14 @@ export class GetLinkCommand {
target: { preset: 'defaultBranch' }
},
default: defaultType === 'defaultBranch'
},
{
item: {
label: 'Current tag',
description: targets[3],
target: { preset: 'tag' }
},
default: defaultType === 'tag'
}
];

Expand Down Expand Up @@ -361,27 +370,40 @@ export class GetLinkCommand {
): Promise<(QuickPickItem | QuickPickLinkTargetItem)[]> {
let branches: (QuickPickItem | QuickPickLinkTargetItem)[];
let commits: (QuickPickItem | QuickPickLinkTargetItem)[];
let lines: string[];
let tags: (QuickPickItem | QuickPickLinkTargetItem)[];
let branchLines: string[];
let tagLines: string[];
let useShortHashes: boolean;

lines = (
await this.git.exec(
info.repository.root,
'branch',
'--list',
'--no-color',
'--format',
'%(refname:short) %(refname) %(objectname:short) %(objectname)'
)
)
.split(/\r?\n/)
.filter((x) => x.length > 0);
// Get branches and tags in parallel.
[branchLines, tagLines] = await Promise.all([
this.git
.exec(
info.repository.root,
'branch',
'--list',
'--no-color',
'--format',
'%(refname:short) %(refname) %(objectname:short) %(objectname)'
)
.then((output) => output.split(/\r?\n/).filter((x) => x.length > 0)),
this.git
.exec(
info.repository.root,
'tag',
'-l',
'--format',
'%(refname:short) %(objectname:short) %(objectname)'
)
.then((output) => output.split(/\r?\n/).filter((x) => x.length > 0))
]);

branches = [];
commits = [];
tags = [];
useShortHashes = this.settings.getUseShortHash();

for (let line of lines) {
for (let line of branchLines) {
let [branchName, branchRef, shortHash, fullHash] = line.split(' ');

branches.push({
Expand All @@ -397,12 +419,25 @@ export class GetLinkCommand {
});
}

for (let line of tagLines) {
let [tagName, shortHash, fullHash] = line.split(' ');

tags.push({
label: tagName,
description: useShortHashes ? shortHash : fullHash,
target: { ref: { abbreviated: tagName, symbolic: tagName }, type: 'tag' }
});
}

branches.sort((x, y) => x.label.localeCompare(y.label));
commits.sort((x, y) => x.label.localeCompare(y.label));
tags.sort((x, y) => x.label.localeCompare(y.label));

return [
{ label: 'Branches', kind: QuickPickItemKind.Separator },
...branches,
{ label: 'Tags', kind: QuickPickItemKind.Separator },
...tags,
{ label: 'Commits', kind: QuickPickItemKind.Separator },
...commits
];
Expand Down
14 changes: 14 additions & 0 deletions vscode/src/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,20 @@ export function registerGetLinkCommands(
)
);

subscriptions.push(
registerGetLinkCommand(
COMMANDS.copySelectionToTag,
repositoryFinder,
handlerProvider,
git,
{
linkType: 'tag',
includeSelection: true,
action: 'copy'
}
)
);

// And add a command where you can choose what to generate the link to.
subscriptions.push(
registerGetLinkCommand(
Expand Down
1 change: 1 addition & 0 deletions vscode/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export const COMMANDS = {
copySelectionToDefaultBranch: `${EXTENSION.id}.copySelectionToDefaultBranch`,
copySelectionToBranch: `${EXTENSION.id}.copySelectionToBranch`,
copySelectionToCommit: `${EXTENSION.id}.copySelectionToCommit`,
copySelectionToTag: `${EXTENSION.id}.copySelectionToTag`,
copySelectionToChoice: `${EXTENSION.id}.copySelectionToChoice`,
openFile: `${EXTENSION.id}.openFile`,
openSelection: `${EXTENSION.id}.openSelection`,
Expand Down
18 changes: 16 additions & 2 deletions vscode/src/link-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@ export class LinkHandler {
this.definition.branchRef === 'abbreviated'
? options.target.ref.abbreviated
: options.target.ref.symbolic;
} else if (options.target.type === 'tag') {
type = 'tag';
ref = options.target.ref.abbreviated;
} else {
type = 'commit';
ref = this.settings.getUseShortHash()
Expand All @@ -164,7 +167,7 @@ export class LinkHandler {
ref,
commit: await this.getRef('commit', repository),
file: relativePath,
type: type === 'commit' ? 'commit' : 'branch',
type: type === 'commit' ? 'commit' : type === 'tag' ? 'tag' : 'branch',
sshUserSpecification: getSshUserSpecification(remoteUrl),
...file.selection
};
Expand Down Expand Up @@ -315,6 +318,17 @@ export class LinkHandler {
return (await this.git.exec(repository.root, 'rev-parse', 'HEAD')).trim();
}

case 'tag':
return (
await this.git.exec(
repository.root,
'describe',
'--exact-match',
'--tags',
'HEAD'
)
).trim();

default:
// Use the default branch if one is specified in the settings; otherwise find the
// name of the default branch by getting the name of the "remote_name/HEAD" ref.
Expand Down Expand Up @@ -571,7 +585,7 @@ interface UrlData {
/**
* The type of link being generated.
*/
readonly type: 'branch' | 'commit';
readonly type: 'branch' | 'commit' | 'tag';

/**
* The Git ref to generate the link to. This will be a branch name or commit hash depending on the link type.
Expand Down
3 changes: 3 additions & 0 deletions vscode/src/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ export class Settings {
case 'defaultBranch':
return 'defaultBranch';

case 'tag':
return 'tag';

default:
return 'commit';
}
Expand Down
4 changes: 2 additions & 2 deletions vscode/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { StaticServer } from './schema';
/**
* The type of link to generate.
*/
export type LinkType = 'branch' | 'commit' | 'defaultBranch';
export type LinkType = 'branch' | 'commit' | 'defaultBranch' | 'tag';

/**
* The format to use when copying a link.
Expand Down Expand Up @@ -103,7 +103,7 @@ export interface LinkTargetRef {
/**
* What the ref refers to.
*/
readonly type: 'branch' | 'commit';
readonly type: 'branch' | 'commit' | 'tag';
}

export interface LinkTargetPreset {
Expand Down
14 changes: 7 additions & 7 deletions vscode/test/commands/get-link-command.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -653,7 +653,7 @@ describe('GetLinkCommand', () => {
});

it(`should use the selected branch.`, async () => {
showQuickPick.callsFake(async (items) => (await items)[4]);
showQuickPick.callsFake(async (items) => (await items)[5]);
await command.execute(file);

expect(createUrl, 'branch #1').to.have.been.calledWithExactly(
Expand All @@ -668,7 +668,7 @@ describe('GetLinkCommand', () => {
}
);

showQuickPick.callsFake(async (items) => (await items)[5]);
showQuickPick.callsFake(async (items) => (await items)[6]);
await command.execute(file);

expect(createUrl, 'branch #2').to.have.been.calledWithExactly(
Expand All @@ -683,7 +683,7 @@ describe('GetLinkCommand', () => {
}
);

showQuickPick.callsFake(async (items) => (await items)[6]);
showQuickPick.callsFake(async (items) => (await items)[7]);
await command.execute(file);

expect(createUrl, 'branch #3').to.have.been.calledWithExactly(
Expand All @@ -700,7 +700,7 @@ describe('GetLinkCommand', () => {
});

it(`should use the selected commit.`, async () => {
showQuickPick.callsFake(async (items) => (await items)[8]);
showQuickPick.callsFake(async (items) => (await items)[10]);
await command.execute(file);

expect(createUrl, 'commit #1').to.have.been.calledWithExactly(
Expand All @@ -710,7 +710,7 @@ describe('GetLinkCommand', () => {
{ target: { ref: commits[0], type: 'commit' } }
);

showQuickPick.callsFake(async (items) => (await items)[9]);
showQuickPick.callsFake(async (items) => (await items)[11]);
await command.execute(file);

expect(createUrl, 'commit #2').to.have.been.calledWithExactly(
Expand All @@ -720,7 +720,7 @@ describe('GetLinkCommand', () => {
{ target: { ref: commits[1], type: 'commit' } }
);

showQuickPick.callsFake(async (items) => (await items)[10]);
showQuickPick.callsFake(async (items) => (await items)[12]);
await command.execute(file);

expect(createUrl, 'commit #3').to.have.been.calledWithExactly(
Expand Down Expand Up @@ -783,6 +783,6 @@ describe('GetLinkCommand', () => {
}

function getLinkTypes(): (LinkType | undefined)[] {
return ['commit', 'branch', 'defaultBranch', undefined];
return ['commit', 'branch', 'defaultBranch', 'tag', undefined];
}
});