Path: blob/main/extensions/git/src/editSessionIdentityProvider.ts
3316 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import * as path from 'path';6import * as vscode from 'vscode';7import { RefType } from './api/git';8import { Model } from './model';910export class GitEditSessionIdentityProvider implements vscode.EditSessionIdentityProvider, vscode.Disposable {1112private providerRegistration: vscode.Disposable;1314constructor(private model: Model) {15this.providerRegistration = vscode.Disposable.from(16vscode.workspace.registerEditSessionIdentityProvider('file', this),17vscode.workspace.onWillCreateEditSessionIdentity((e) => {18e.waitUntil(19this._onWillCreateEditSessionIdentity(e.workspaceFolder).catch(err => {20if (err instanceof vscode.CancellationError) {21throw err;22}23})24);25})26);27}2829dispose() {30this.providerRegistration.dispose();31}3233async provideEditSessionIdentity(workspaceFolder: vscode.WorkspaceFolder, token: vscode.CancellationToken): Promise<string | undefined> {34await this.model.openRepository(path.dirname(workspaceFolder.uri.fsPath));3536const repository = this.model.getRepository(workspaceFolder.uri);37await repository?.status();3839if (!repository || !repository?.HEAD?.upstream) {40return undefined;41}4243const remoteUrl = repository.remotes.find((remote) => remote.name === repository.HEAD?.upstream?.remote)?.pushUrl?.replace(/^(git@[^\/:]+)(:)/i, 'ssh://$1/');44const remote = remoteUrl ? await vscode.workspace.getCanonicalUri(vscode.Uri.parse(remoteUrl), { targetScheme: 'https' }, token) : null;4546return JSON.stringify({47remote: remote?.toString() ?? remoteUrl,48ref: repository.HEAD?.upstream?.name ?? null,49sha: repository.HEAD?.commit ?? null,50});51}5253provideEditSessionIdentityMatch(identity1: string, identity2: string): vscode.EditSessionIdentityMatch {54try {55const normalizedIdentity1 = normalizeEditSessionIdentity(identity1);56const normalizedIdentity2 = normalizeEditSessionIdentity(identity2);5758if (normalizedIdentity1.remote === normalizedIdentity2.remote &&59normalizedIdentity1.ref === normalizedIdentity2.ref &&60normalizedIdentity1.sha === normalizedIdentity2.sha) {61// This is a perfect match62return vscode.EditSessionIdentityMatch.Complete;63} else if (normalizedIdentity1.remote === normalizedIdentity2.remote &&64normalizedIdentity1.ref === normalizedIdentity2.ref &&65normalizedIdentity1.sha !== normalizedIdentity2.sha) {66// Same branch and remote but different SHA67return vscode.EditSessionIdentityMatch.Partial;68} else {69return vscode.EditSessionIdentityMatch.None;70}71} catch (ex) {72return vscode.EditSessionIdentityMatch.Partial;73}74}7576private async _onWillCreateEditSessionIdentity(workspaceFolder: vscode.WorkspaceFolder): Promise<void> {77await this._doPublish(workspaceFolder);78}7980private async _doPublish(workspaceFolder: vscode.WorkspaceFolder) {81await this.model.openRepository(path.dirname(workspaceFolder.uri.fsPath));8283const repository = this.model.getRepository(workspaceFolder.uri);84if (!repository) {85return;86}8788await repository.status();8990if (!repository.HEAD?.commit) {91// Handle publishing empty repository with no commits9293const yes = vscode.l10n.t('Yes');94const selection = await vscode.window.showInformationMessage(95vscode.l10n.t('Would you like to publish this repository to continue working on it elsewhere?'),96{ modal: true },97yes98);99if (selection !== yes) {100throw new vscode.CancellationError();101}102await repository.commit('Initial commit', { all: true });103await vscode.commands.executeCommand('git.publish');104} else if (!repository.HEAD?.upstream && repository.HEAD?.type === RefType.Head) {105// If this branch hasn't been published to the remote yet,106// ensure that it is published before Continue On is invoked107108const publishBranch = vscode.l10n.t('Publish Branch');109const selection = await vscode.window.showInformationMessage(110vscode.l10n.t('The current branch is not published to the remote. Would you like to publish it to access your changes elsewhere?'),111{ modal: true },112publishBranch113);114if (selection !== publishBranch) {115throw new vscode.CancellationError();116}117118await vscode.commands.executeCommand('git.publish');119}120}121}122123function normalizeEditSessionIdentity(identity: string) {124let { remote, ref, sha } = JSON.parse(identity);125126if (typeof remote === 'string' && remote.endsWith('.git')) {127remote = remote.slice(0, remote.length - 4);128}129130return {131remote,132ref,133sha134};135}136137138