Ask user to commit/push changes when copying links (#185802)

* Ask user to commit/push changes when copying links

* Don't show an error message for cancellation errors
This commit is contained in:
Joyce Er 2023-06-21 15:28:32 -07:00 committed by GitHub
parent 838ff6266a
commit 31478cefc5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 68 additions and 8 deletions

View file

@ -11,21 +11,25 @@ import { LinkContext, getLink, getVscodeDevHost } from './links';
async function copyVscodeDevLink(gitAPI: GitAPI, useSelection: boolean, context: LinkContext, includeRange = true) {
try {
const permalink = getLink(gitAPI, useSelection, getVscodeDevHost(), 'headlink', context, includeRange);
const permalink = await getLink(gitAPI, useSelection, getVscodeDevHost(), 'headlink', context, includeRange);
if (permalink) {
return vscode.env.clipboard.writeText(permalink);
}
} catch (err) {
vscode.window.showErrorMessage(err.message);
if (!(err instanceof vscode.CancellationError)) {
vscode.window.showErrorMessage(err.message);
}
}
}
async function openVscodeDevLink(gitAPI: GitAPI): Promise<vscode.Uri | undefined> {
try {
const headlink = getLink(gitAPI, true, getVscodeDevHost(), 'headlink');
const headlink = await getLink(gitAPI, true, getVscodeDevHost(), 'headlink');
return headlink ? vscode.Uri.parse(headlink) : undefined;
} catch (err) {
vscode.window.showErrorMessage(err.message);
if (!(err instanceof vscode.CancellationError)) {
vscode.window.showErrorMessage(err.message);
}
return undefined;
}
}

View file

@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { API as GitAPI, Repository } from './typings/git';
import { API as GitAPI, RefType, Repository } from './typings/git';
import { getRepositoryFromUrl } from './util';
export function isFileInRepo(repository: Repository, file: vscode.Uri): boolean {
@ -129,7 +129,7 @@ export function encodeURIComponentExceptSlashes(path: string) {
return path.split('/').map((segment) => encodeURIComponent(segment)).join('/');
}
export function getLink(gitAPI: GitAPI, useSelection: boolean, hostPrefix?: string, linkType: 'permalink' | 'headlink' = 'permalink', context?: LinkContext, useRange?: boolean): string | undefined {
export async function getLink(gitAPI: GitAPI, useSelection: boolean, hostPrefix?: string, linkType: 'permalink' | 'headlink' = 'permalink', context?: LinkContext, useRange?: boolean): Promise<string | undefined> {
hostPrefix = hostPrefix ?? 'https://github.com';
const fileAndPosition = getFileAndPosition(context);
if (!fileAndPosition) {
@ -142,6 +142,9 @@ export function getLink(gitAPI: GitAPI, useSelection: boolean, hostPrefix?: stri
if (!gitRepo) {
return;
}
await ensurePublished(gitRepo, uri);
let repo: { owner: string; repo: string } | undefined;
gitRepo.state.remotes.find(remote => {
if (remote.fetchUrl) {
@ -182,3 +185,54 @@ export function getBranchLink(url: string, branch: string, hostPrefix: string =
export function getVscodeDevHost(): string {
return `https://${vscode.env.appName.toLowerCase().includes('insiders') ? 'insiders.' : ''}vscode.dev/github`;
}
export async function ensurePublished(repository: Repository, file: vscode.Uri) {
if ((repository.state.HEAD?.type === RefType.Head || repository.state.HEAD?.type === RefType.Tag)
// If HEAD is not published, make sure it is
&& !repository?.state.HEAD?.upstream
) {
const publishBranch = vscode.l10n.t('Publish Branch');
const selection = await vscode.window.showInformationMessage(
vscode.l10n.t('The current branch is not published to the remote. Would you like to publish your branch before copying a link?'),
{ modal: true },
publishBranch
);
if (selection !== publishBranch) {
throw new vscode.CancellationError();
}
await vscode.commands.executeCommand('git.publish');
}
const uncommittedChanges = [...repository.state.workingTreeChanges, ...repository.state.indexChanges];
if (uncommittedChanges.find((c) => c.uri.toString() === file.toString())) {
const commitChanges = vscode.l10n.t('Commit Changes');
const copyAnyway = vscode.l10n.t('Copy Anyway');
const selection = await vscode.window.showWarningMessage(
vscode.l10n.t('The current file has uncommitted changes. Please commit your changes before copying a link.'),
{ modal: true },
commitChanges,
copyAnyway
);
if (selection !== copyAnyway) {
// Focus the SCM view
vscode.commands.executeCommand('workbench.view.scm');
throw new vscode.CancellationError();
}
} else if (repository.state.HEAD?.ahead) {
const pushCommits = vscode.l10n.t('Push Commits');
const selection = await vscode.window.showInformationMessage(
vscode.l10n.t('The current branch has unpublished commits. Would you like to push your commits before copying a link?'),
{ modal: true },
pushCommits
);
if (selection !== pushCommits) {
throw new vscode.CancellationError();
}
await repository.push();
}
await repository.status();
}

View file

@ -6,7 +6,7 @@
import * as vscode from 'vscode';
import { API } from './typings/git';
import { getRepositoryFromUrl, repositoryHasGitHubRemote } from './util';
import { encodeURIComponentExceptSlashes, getRepositoryForFile, notebookCellRangeString, rangeString } from './links';
import { encodeURIComponentExceptSlashes, ensurePublished, getRepositoryForFile, notebookCellRangeString, rangeString } from './links';
export class VscodeDevShareProvider implements vscode.ShareProvider, vscode.Disposable {
readonly id: string = 'copyVscodeDevLink';
@ -63,12 +63,14 @@ export class VscodeDevShareProvider implements vscode.ShareProvider, vscode.Disp
}
}
provideShare(item: vscode.ShareableItem, _token: vscode.CancellationToken): vscode.ProviderResult<vscode.Uri> {
async provideShare(item: vscode.ShareableItem, _token: vscode.CancellationToken): Promise<vscode.Uri | undefined> {
const repository = getRepositoryForFile(this.gitAPI, item.resourceUri);
if (!repository) {
return;
}
await ensurePublished(repository, item.resourceUri);
let repo: { owner: string; repo: string } | undefined;
repository.state.remotes.find(remote => {
if (remote.fetchUrl) {