Skip to content

Commit 23d6633

Browse files
committed
Caches and stores Bitbucket inermediate data e.g. workspaces and repos
(#4046)
1 parent 4a67841 commit 23d6633

File tree

2 files changed

+100
-0
lines changed

2 files changed

+100
-0
lines changed

src/constants.storage.ts

+26
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,10 @@ export type GlobalStorage = {
9393
[key in `azure:${string}:organizations`]: Stored<StoredAzureOrganization[] | undefined>;
9494
} & {
9595
[key in `azure:${string}:projects`]: Stored<StoredAzureProject[] | undefined>;
96+
} & { [key in `bitbucket:${string}:account`]: Stored<StoredBitbucketAccount | undefined> } & {
97+
[key in `bitbucket:${string}:workspaces`]: Stored<StoredBitbucketWorkspace[] | undefined>;
98+
} & {
99+
[key in `bitbucket:${string}:repositories`]: Stored<StoredBitbucketRepository[] | undefined>;
96100
};
97101

98102
export type StoredIntegrationConfigurations = Record<string, StoredConfiguredIntegrationDescriptor[] | undefined>;
@@ -245,6 +249,28 @@ export interface StoredAzureProject {
245249
resourceName: string;
246250
}
247251

252+
export interface StoredBitbucketAccount {
253+
id: string;
254+
name: string | undefined;
255+
username: string | undefined;
256+
email: string | undefined;
257+
avatarUrl: string | undefined;
258+
}
259+
260+
export interface StoredBitbucketWorkspace {
261+
key: string;
262+
id: string;
263+
name: string;
264+
slug: string;
265+
}
266+
267+
export interface StoredBitbucketRepository {
268+
key: string;
269+
owner: string;
270+
name: string;
271+
resourceId: string;
272+
}
273+
248274
export interface StoredAvatar {
249275
uri: string;
250276
timestamp: number;

src/plus/integrations/providers/bitbucket.ts

+74
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { AuthenticationSession, CancellationToken } from 'vscode';
2+
import { md5 } from '@env/crypto';
23
import { HostingIntegrationId } from '../../../constants.integrations';
34
import type { Account } from '../../../git/models/author';
45
import type { DefaultBranch } from '../../../git/models/defaultBranch';
@@ -28,6 +29,7 @@ interface BitbucketWorkspaceDescriptor extends ResourceDescriptor {
2829
}
2930

3031
interface BitbucketRemoteRepositoryDescriptor extends ResourceDescriptor {
32+
resourceId: string;
3133
owner: string;
3234
name: string;
3335
cloneUrlHttps?: string;
@@ -238,6 +240,7 @@ export class BitbucketIntegration extends HostingIntegration<
238240
`${accessToken}:${resource.id}`,
239241
resourceRepos.map(r => ({
240242
id: `${r.owner}/${r.name}`,
243+
resourceId: r.owner,
241244
owner: r.owner,
242245
name: r.name,
243246
key: `${r.owner}/${r.name}`,
@@ -299,6 +302,77 @@ export class BitbucketIntegration extends HostingIntegration<
299302
remotePullRequest.graphQLId = remotePullRequest.id;
300303
return fromProviderPullRequest(remotePullRequest, this);
301304
}
305+
306+
protected override async providerOnConnect(): Promise<void> {
307+
if (this._session == null) return;
308+
309+
const accountStorageKey = md5(this._session.accessToken);
310+
311+
const storedAccount = this.container.storage.get(`bitbucket:${accountStorageKey}:account`);
312+
const storedWorkspaces = this.container.storage.get(`bitbucket:${accountStorageKey}:workspaces`);
313+
const storedRepositories = this.container.storage.get(`bitbucket:${accountStorageKey}:repositories`);
314+
315+
let account: Account | undefined = storedAccount?.data ? { ...storedAccount.data, provider: this } : undefined;
316+
let workspaces = storedWorkspaces?.data?.map(o => ({ ...o }));
317+
let repositories = storedRepositories?.data?.map(p => ({ ...p }));
318+
319+
if (storedAccount == null) {
320+
account = await this.getProviderCurrentAccount(this._session);
321+
if (account != null) {
322+
// Clear all other stored workspaces and repositories and accounts when our session changes
323+
await this.container.storage.deleteWithPrefix('bitbucket');
324+
await this.container.storage.store(`bitbucket:${accountStorageKey}:account`, {
325+
v: 1,
326+
timestamp: Date.now(),
327+
data: {
328+
id: account.id,
329+
name: account.name,
330+
email: account.email,
331+
avatarUrl: account.avatarUrl,
332+
username: account.username,
333+
},
334+
});
335+
}
336+
}
337+
this._accounts ??= new Map<string, Account | undefined>();
338+
this._accounts.set(this._session.accessToken, account);
339+
340+
if (storedWorkspaces == null) {
341+
workspaces = await this.getProviderResourcesForUser(this._session, true);
342+
await this.container.storage.store(`bitbucket:${accountStorageKey}:workspaces`, {
343+
v: 1,
344+
timestamp: Date.now(),
345+
data: workspaces,
346+
});
347+
}
348+
this._workspaces ??= new Map<string, BitbucketWorkspaceDescriptor[] | undefined>();
349+
this._workspaces.set(this._session.accessToken, workspaces);
350+
351+
if (storedRepositories == null && workspaces?.length) {
352+
repositories = await this.getProviderProjectsForResources(this._session, workspaces);
353+
await this.container.storage.store(`bitbucket:${accountStorageKey}:repositories`, {
354+
v: 1,
355+
timestamp: Date.now(),
356+
data: repositories,
357+
});
358+
}
359+
this._repositories ??= new Map<string, BitbucketRemoteRepositoryDescriptor[] | undefined>();
360+
for (const repository of repositories ?? []) {
361+
const resourceKey = `${this._session.accessToken}:${repository.resourceId}`;
362+
const repos = this._repositories.get(resourceKey);
363+
if (repos == null) {
364+
this._repositories.set(resourceKey, [repository]);
365+
} else if (!repos.some(r => r.key === repository.key)) {
366+
repos.push(repository);
367+
}
368+
}
369+
}
370+
371+
protected override providerOnDisconnect(): void {
372+
this._accounts = undefined;
373+
this._workspaces = undefined;
374+
this._repositories = undefined;
375+
}
302376
}
303377

304378
const bitbucketCloudDomainRegex = /^bitbucket\.org$/i;

0 commit comments

Comments
 (0)