Skip to content
Merged
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
1 change: 1 addition & 0 deletions src/constants.commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ export type CoreCommands =
| 'workbench.action.closeActiveEditor'
| 'workbench.action.closeAllEditors'
| 'workbench.action.closePanel'
| 'workbench.action.closeWindow'
| 'workbench.action.focusRightGroup'
| 'workbench.action.nextEditor'
| 'workbench.action.newGroupRight'
Expand Down
4 changes: 2 additions & 2 deletions src/constants.storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import type { DeepLinkServiceState } from './uris/deepLinks/deepLink';
export type SecretKeys =
| IntegrationAuthenticationKeys
| `gitlens.${AIProviders}.key`
| `gitlens.plus.auth:${Environment}`;
| `gitlens.plus.auth:${Environment}`
| 'deepLinks:pending';

export type IntegrationAuthenticationKeys =
| `gitlens.integration.auth:${IntegrationId}|${string}`
Expand Down Expand Up @@ -64,7 +65,6 @@ export type GlobalStorage = {
avatars: [string, StoredAvatar][];
'confirm:ai:tos': boolean;
repoVisibility: [string, StoredRepoVisibilityInfo][];
'deepLinks:pending': StoredDeepLinkContext;
pendingWhatsNewOnFocus: boolean;
// Don't change this key name ('premium`) as its the stored subscription
'premium:subscription': Stored<Subscription & { lastValidatedAt: number | undefined }>;
Expand Down
6 changes: 3 additions & 3 deletions src/git/models/repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -625,11 +625,11 @@ export class Repository implements Disposable {
@gate()
@log({ exit: true })
async getCommonRepository(): Promise<Repository | undefined> {
const gitDir = await this.git.config().getGitDir?.();
if (gitDir?.commonUri == null) return this;
const uri = await this.getCommonRepositoryUri();
if (uri == null) return this;

// If the repository isn't already opened, then open it as a "closed" repo (won't show up in the UI)
return this.container.git.getOrOpenRepository(gitDir.commonUri, {
return this.container.git.getOrOpenRepository(uri, {
detectNested: false,
force: true,
closeOnOpen: true,
Expand Down
80 changes: 61 additions & 19 deletions src/uris/deepLinks/deepLinkService.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { QuickPickItem } from 'vscode';
import type { QuickPickItem, SecretStorageChangeEvent } from 'vscode';
import { Disposable, env, EventEmitter, ProgressLocation, Range, Uri, window, workspace } from 'vscode';
import type { OpenCloudPatchCommandArgs } from '../../commands/patches';
import type { StoredDeepLinkContext, StoredNamedRef } from '../../constants.storage';
Expand Down Expand Up @@ -72,16 +72,43 @@ export class DeepLinkService implements Disposable {
this._disposables.push(
this._onDeepLinkProgressUpdated,
container.uri.onDidReceiveUri(async (uri: Uri) => this.processDeepLinkUri(uri)),
container.storage.onDidChangeSecrets(this.onDidChangeStorage, this),
);

const pendingDeepLink = this.container.storage.get('deepLinks:pending');
void this.processPendingDeepLink(pendingDeepLink);
void this.container.storage.getSecret('deepLinks:pending').then(pendingDeepLink => {
if (pendingDeepLink != null) {
const link = JSON.parse(pendingDeepLink) as StoredDeepLinkContext;
void this.processPendingDeepLink(link);
}
});
}

dispose(): void {
Disposable.from(...this._disposables).dispose();
}

private async onDidChangeStorage(e: SecretStorageChangeEvent): Promise<void> {
if (e.key === 'deepLinks:pending') {
const pendingDeepLinkStored = await this.container.storage.getSecret('deepLinks:pending');
if (pendingDeepLinkStored == null) return;

const pendingDeepLink = JSON.parse(pendingDeepLinkStored) as StoredDeepLinkContext;
if (pendingDeepLink?.url == null) return;

const link = parseDeepLinkUri(Uri.parse(pendingDeepLink.url));
if (link == null) return;

// TODO: See if we can remove this condition without breaking other link flows
if (link.action !== DeepLinkActionType.DeleteBranch) return;

// see if there is a matching repo in the current window
await this.findMatchingRepositoryFromCurrentWindow(link.repoPath, link.remoteUrl, link.mainId, true);
if (this._context.repo != null) {
void this.processPendingDeepLink(pendingDeepLink);
}
}
}

private resetContext() {
this._context = {
state: DeepLinkServiceState.Idle,
Expand Down Expand Up @@ -203,14 +230,24 @@ export class DeepLinkService implements Disposable {
repoPath: string | undefined,
remoteUrl: string | undefined,
repoId: string | undefined,
openOnly: boolean = false,
): Promise<void> {
if (repoPath != null) {
const repoOpenUri = maybeUri(repoPath) ? Uri.parse(repoPath) : repoPath;
try {
const openRepo = await this.container.git.getOrOpenRepository(repoOpenUri, { detectNested: false });
if (openRepo != null) {
this._context.repo = openRepo;
return;
if (openOnly) {
for (const repo of this.container.git.openRepositories) {
if (repo.path === repoPath || repo.uri.fsPath === repoPath) {
this._context.repo = repo;
return;
}
}
} else {
const openRepo = await this.container.git.getOrOpenRepository(repoOpenUri, { detectNested: false });
if (openRepo != null) {
this._context.repo = openRepo;
return;
}
}
} catch {}
}
Expand All @@ -223,7 +260,7 @@ export class DeepLinkService implements Disposable {

// Try to match a repo using the remote URL first, since that saves us some steps.
// As a fallback, try to match using the repo id.
for (const repo of this.container.git.repositories) {
for (const repo of openOnly ? this.container.git.openRepositories : this.container.git.repositories) {
if (repoPath != null && normalizePath(repo.path.toLowerCase()) === normalizePath(repoPath.toLowerCase())) {
this._context.repo = repo;
return;
Expand Down Expand Up @@ -254,7 +291,7 @@ export class DeepLinkService implements Disposable {
@debug()
private async processPendingDeepLink(pendingDeepLink: StoredDeepLinkContext | undefined) {
if (pendingDeepLink == null) return;
void this.container.storage.delete('deepLinks:pending');
void this.container.storage.deleteSecret('deepLinks:pending');
if (pendingDeepLink?.url == null) return;
const link = parseDeepLinkUri(Uri.parse(pendingDeepLink.url));
if (link == null) return;
Expand Down Expand Up @@ -1061,13 +1098,16 @@ export class DeepLinkService implements Disposable {
action = DeepLinkServiceAction.RepoOpening;
if (!(repoOpenLocation === 'addToWorkspace' && (workspace.workspaceFolders?.length || 0) > 1)) {
// Deep link will resolve in a different service instance
await this.container.storage.store('deepLinks:pending', {
url: this._context.url,
repoPath: repoOpenUri.toString(),
targetSha: this._context.targetSha,
secondaryTargetSha: this._context.secondaryTargetSha,
useProgress: useProgress,
});
await this.container.storage.storeSecret(
'deepLinks:pending',
JSON.stringify({
url: this._context.url,
repoPath: repoOpenUri.toString(),
targetSha: this._context.targetSha,
secondaryTargetSha: this._context.secondaryTargetSha,
useProgress: useProgress,
}),
);
action = DeepLinkServiceAction.DeepLinkStored;
}

Expand Down Expand Up @@ -1349,9 +1389,11 @@ export class DeepLinkService implements Disposable {

// Storing link info in case the switch causes a new window to open
const onWorkspaceChanging = async (isNewWorktree?: boolean) =>
this.container.storage.store(
this.container.storage.storeSecret(
'deepLinks:pending',
isNewWorktree ? pendingDeepLink : { ...pendingDeepLink, url: nonPrUrl },
isNewWorktree
? JSON.stringify(pendingDeepLink)
: JSON.stringify({ ...pendingDeepLink, url: nonPrUrl }),
);

await executeGitCommand({
Expand Down Expand Up @@ -1406,7 +1448,7 @@ export class DeepLinkService implements Disposable {
}
case DeepLinkServiceState.OpenInspect: {
// If we arrive at this step, clear any stored data used for the "new window" option
await this.container.storage.delete('deepLinks:pending');
await this.container.storage.deleteSecret('deepLinks:pending');
if (!repo) {
action = DeepLinkServiceAction.DeepLinkErrored;
message = 'Missing repository.';
Expand Down
13 changes: 11 additions & 2 deletions src/webviews/home/homeWebview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1236,8 +1236,17 @@ export class HomeWebviewProvider implements WebviewProvider<State, State, HomeWe
subcommand: 'open',
repo: defaultWorktree.repoPath,
worktree: defaultWorktree,
onWorkspaceChanging: async (_isNewWorktree?: boolean) =>
this.container.storage.store('deepLinks:pending', deleteBranchDeepLink),
onWorkspaceChanging: async (_isNewWorktree?: boolean) => {
await this.container.storage.storeSecret(
'deepLinks:pending',
JSON.stringify(deleteBranchDeepLink),
);
// Close the current window. This should only occur if there was already a different
// window open for the default worktree.
setTimeout(() => {
void executeCoreCommand('workbench.action.closeWindow');
}, 2000);
},
worktreeDefaultOpen: 'current',
},
});
Expand Down