Skip to content

Commit 84e8e04

Browse files
committed
Caches and stores Bitbucket inermediate data e.g. workspaces and repos
(#4046)
1 parent cae3faa commit 84e8e04

File tree

2 files changed

+100
-0
lines changed

2 files changed

+100
-0
lines changed

src/constants.storage.ts

Lines changed: 26 additions & 0 deletions
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

Lines changed: 74 additions & 0 deletions
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';
@@ -33,6 +34,7 @@ interface BitbucketWorkspaceDescriptor extends ResourceDescriptor {
3334
}
3435

3536
interface BitbucketRemoteRepositoryDescriptor extends ResourceDescriptor {
37+
resourceId: string;
3638
owner: string;
3739
name: string;
3840
cloneUrlHttps?: string;
@@ -243,6 +245,7 @@ export class BitbucketIntegration extends HostingIntegration<
243245
`${accessToken}:${resource.id}`,
244246
resourceRepos.map(r => ({
245247
id: `${r.owner}/${r.name}`,
248+
resourceId: r.owner,
246249
owner: r.owner,
247250
name: r.name,
248251
key: `${r.owner}/${r.name}`,
@@ -307,6 +310,77 @@ export class BitbucketIntegration extends HostingIntegration<
307310
remotePullRequest.graphQLId = remotePullRequest.id;
308311
return fromProviderPullRequest(remotePullRequest, this);
309312
}
313+
314+
protected override async providerOnConnect(): Promise<void> {
315+
if (this._session == null) return;
316+
317+
const accountStorageKey = md5(this._session.accessToken);
318+
319+
const storedAccount = this.container.storage.get(`bitbucket:${accountStorageKey}:account`);
320+
const storedWorkspaces = this.container.storage.get(`bitbucket:${accountStorageKey}:workspaces`);
321+
const storedRepositories = this.container.storage.get(`bitbucket:${accountStorageKey}:repositories`);
322+
323+
let account: Account | undefined = storedAccount?.data ? { ...storedAccount.data, provider: this } : undefined;
324+
let workspaces = storedWorkspaces?.data?.map(o => ({ ...o }));
325+
let repositories = storedRepositories?.data?.map(p => ({ ...p }));
326+
327+
if (storedAccount == null) {
328+
account = await this.getProviderCurrentAccount(this._session);
329+
if (account != null) {
330+
// Clear all other stored workspaces and repositories and accounts when our session changes
331+
await this.container.storage.deleteWithPrefix('bitbucket');
332+
await this.container.storage.store(`bitbucket:${accountStorageKey}:account`, {
333+
v: 1,
334+
timestamp: Date.now(),
335+
data: {
336+
id: account.id,
337+
name: account.name,
338+
email: account.email,
339+
avatarUrl: account.avatarUrl,
340+
username: account.username,
341+
},
342+
});
343+
}
344+
}
345+
this._accounts ??= new Map<string, Account | undefined>();
346+
this._accounts.set(this._session.accessToken, account);
347+
348+
if (storedWorkspaces == null) {
349+
workspaces = await this.getProviderResourcesForUser(this._session, true);
350+
await this.container.storage.store(`bitbucket:${accountStorageKey}:workspaces`, {
351+
v: 1,
352+
timestamp: Date.now(),
353+
data: workspaces,
354+
});
355+
}
356+
this._workspaces ??= new Map<string, BitbucketWorkspaceDescriptor[] | undefined>();
357+
this._workspaces.set(this._session.accessToken, workspaces);
358+
359+
if (storedRepositories == null && workspaces?.length) {
360+
repositories = await this.getProviderProjectsForResources(this._session, workspaces);
361+
await this.container.storage.store(`bitbucket:${accountStorageKey}:repositories`, {
362+
v: 1,
363+
timestamp: Date.now(),
364+
data: repositories,
365+
});
366+
}
367+
this._repositories ??= new Map<string, BitbucketRemoteRepositoryDescriptor[] | undefined>();
368+
for (const repository of repositories ?? []) {
369+
const resourceKey = `${this._session.accessToken}:${repository.resourceId}`;
370+
const repos = this._repositories.get(resourceKey);
371+
if (repos == null) {
372+
this._repositories.set(resourceKey, [repository]);
373+
} else if (!repos.some(r => r.key === repository.key)) {
374+
repos.push(repository);
375+
}
376+
}
377+
}
378+
379+
protected override providerOnDisconnect(): void {
380+
this._accounts = undefined;
381+
this._workspaces = undefined;
382+
this._repositories = undefined;
383+
}
310384
}
311385

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

0 commit comments

Comments
 (0)