@gitkraken/core-gitlens 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -1
- package/README.md +13 -10
- package/dist/git/context.d.ts +4 -3
- package/dist/git/context.d.ts.map +1 -1
- package/dist/git/context.js.map +1 -1
- package/dist/git/providers/operations.d.ts +1 -0
- package/dist/git/providers/operations.d.ts.map +1 -1
- package/dist/git/providers/worktrees.d.ts +2 -0
- package/dist/git/providers/worktrees.d.ts.map +1 -1
- package/dist/git/utils/conflictResolution.utils.d.ts +32 -0
- package/dist/git/utils/conflictResolution.utils.d.ts.map +1 -1
- package/dist/git/utils/conflictResolution.utils.js +95 -0
- package/dist/git/utils/conflictResolution.utils.js.map +1 -1
- package/dist/git-cli/providers/operations.d.ts +1 -0
- package/dist/git-cli/providers/operations.d.ts.map +1 -1
- package/dist/git-cli/providers/operations.js +22 -1
- package/dist/git-cli/providers/operations.js.map +1 -1
- package/dist/git-cli/providers/worktrees.d.ts +2 -0
- package/dist/git-cli/providers/worktrees.d.ts.map +1 -1
- package/dist/git-cli/providers/worktrees.js +3 -0
- package/dist/git-cli/providers/worktrees.js.map +1 -1
- package/dist/plus/ai/utils/ai.utils.js +5 -5
- package/dist/plus/ai/utils/ai.utils.js.map +1 -1
- package/dist/plus/git-github/api/github.d.ts +6 -13
- package/dist/plus/git-github/api/github.d.ts.map +1 -1
- package/dist/plus/git-github/api/github.js +5 -10
- package/dist/plus/git-github/api/github.js.map +1 -1
- package/dist/plus/integrations/authentication/cloudIntegrationService.d.ts +11 -0
- package/dist/plus/integrations/authentication/cloudIntegrationService.d.ts.map +1 -0
- package/dist/plus/integrations/authentication/cloudIntegrationService.js +90 -0
- package/dist/plus/integrations/authentication/cloudIntegrationService.js.map +1 -0
- package/dist/plus/integrations/authentication/configuredIntegrationService.d.ts +67 -0
- package/dist/plus/integrations/authentication/configuredIntegrationService.d.ts.map +1 -0
- package/dist/plus/integrations/authentication/configuredIntegrationService.js +295 -0
- package/dist/plus/integrations/authentication/configuredIntegrationService.js.map +1 -0
- package/dist/plus/integrations/authentication/integrationAuthenticationProvider.d.ts +92 -0
- package/dist/plus/integrations/authentication/integrationAuthenticationProvider.d.ts.map +1 -0
- package/dist/plus/integrations/authentication/integrationAuthenticationProvider.js +185 -0
- package/dist/plus/integrations/authentication/integrationAuthenticationProvider.js.map +1 -0
- package/dist/plus/integrations/authentication/integrationAuthenticationService.d.ts +62 -0
- package/dist/plus/integrations/authentication/integrationAuthenticationService.d.ts.map +1 -0
- package/dist/plus/integrations/authentication/integrationAuthenticationService.js +122 -0
- package/dist/plus/integrations/authentication/integrationAuthenticationService.js.map +1 -0
- package/dist/plus/integrations/authentication/manualTokenProvider.d.ts +15 -0
- package/dist/plus/integrations/authentication/manualTokenProvider.d.ts.map +1 -0
- package/dist/plus/integrations/authentication/manualTokenProvider.js +49 -0
- package/dist/plus/integrations/authentication/manualTokenProvider.js.map +1 -0
- package/dist/plus/integrations/authentication/models.d.ts +87 -0
- package/dist/plus/integrations/authentication/models.d.ts.map +1 -0
- package/dist/plus/integrations/authentication/models.js +64 -0
- package/dist/plus/integrations/authentication/models.js.map +1 -0
- package/dist/plus/integrations/constants.d.ts +47 -0
- package/dist/plus/integrations/constants.d.ts.map +1 -0
- package/dist/plus/integrations/constants.js +128 -0
- package/dist/plus/integrations/constants.js.map +1 -0
- package/dist/plus/integrations/context.d.ts +354 -0
- package/dist/plus/integrations/context.d.ts.map +1 -0
- package/dist/plus/integrations/context.js +2 -0
- package/dist/plus/integrations/context.js.map +1 -0
- package/dist/plus/integrations/errors.d.ts +14 -0
- package/dist/plus/integrations/errors.d.ts.map +1 -0
- package/dist/plus/integrations/errors.js +19 -0
- package/dist/plus/integrations/errors.js.map +1 -0
- package/dist/plus/integrations/index.d.ts +32 -0
- package/dist/plus/integrations/index.d.ts.map +1 -0
- package/dist/plus/integrations/index.js +62 -0
- package/dist/plus/integrations/index.js.map +1 -0
- package/dist/plus/integrations/integrationService.d.ts +98 -0
- package/dist/plus/integrations/integrationService.d.ts.map +1 -0
- package/dist/plus/integrations/integrationService.js +627 -0
- package/dist/plus/integrations/integrationService.js.map +1 -0
- package/dist/plus/integrations/models/gitHostIntegration.d.ts +82 -0
- package/dist/plus/integrations/models/gitHostIntegration.d.ts.map +1 -0
- package/dist/plus/integrations/models/gitHostIntegration.js +522 -0
- package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -0
- package/dist/plus/integrations/models/integration.d.ts +127 -0
- package/dist/plus/integrations/models/integration.d.ts.map +1 -0
- package/dist/plus/integrations/models/integration.js +456 -0
- package/dist/plus/integrations/models/integration.js.map +1 -0
- package/dist/plus/integrations/models/issuesIntegration.d.ts +28 -0
- package/dist/plus/integrations/models/issuesIntegration.d.ts.map +1 -0
- package/dist/plus/integrations/models/issuesIntegration.js +101 -0
- package/dist/plus/integrations/models/issuesIntegration.js.map +1 -0
- package/dist/plus/integrations/providers/apiClients.d.ts +25 -0
- package/dist/plus/integrations/providers/apiClients.d.ts.map +1 -0
- package/dist/plus/integrations/providers/apiClients.js +39 -0
- package/dist/plus/integrations/providers/apiClients.js.map +1 -0
- package/dist/plus/integrations/providers/azure/azure.d.ts +47 -0
- package/dist/plus/integrations/providers/azure/azure.d.ts.map +1 -0
- package/dist/plus/integrations/providers/azure/azure.js +444 -0
- package/dist/plus/integrations/providers/azure/azure.js.map +1 -0
- package/dist/plus/integrations/providers/azure/models.d.ts +286 -0
- package/dist/plus/integrations/providers/azure/models.d.ts.map +1 -0
- package/dist/plus/integrations/providers/azure/models.js +203 -0
- package/dist/plus/integrations/providers/azure/models.js.map +1 -0
- package/dist/plus/integrations/providers/azureDevOps.d.ts +95 -0
- package/dist/plus/integrations/providers/azureDevOps.d.ts.map +1 -0
- package/dist/plus/integrations/providers/azureDevOps.js +432 -0
- package/dist/plus/integrations/providers/azureDevOps.js.map +1 -0
- package/dist/plus/integrations/providers/bitbucket/bitbucket.d.ts +42 -0
- package/dist/plus/integrations/providers/bitbucket/bitbucket.d.ts.map +1 -0
- package/dist/plus/integrations/providers/bitbucket/bitbucket.js +513 -0
- package/dist/plus/integrations/providers/bitbucket/bitbucket.js.map +1 -0
- package/dist/plus/integrations/providers/bitbucket/models.d.ts +222 -0
- package/dist/plus/integrations/providers/bitbucket/models.d.ts.map +1 -0
- package/dist/plus/integrations/providers/bitbucket/models.js +158 -0
- package/dist/plus/integrations/providers/bitbucket/models.js.map +1 -0
- package/dist/plus/integrations/providers/bitbucket-server/models.d.ts +120 -0
- package/dist/plus/integrations/providers/bitbucket-server/models.d.ts.map +1 -0
- package/dist/plus/integrations/providers/bitbucket-server/models.js +111 -0
- package/dist/plus/integrations/providers/bitbucket-server/models.js.map +1 -0
- package/dist/plus/integrations/providers/bitbucket-server.d.ts +60 -0
- package/dist/plus/integrations/providers/bitbucket-server.d.ts.map +1 -0
- package/dist/plus/integrations/providers/bitbucket-server.js +138 -0
- package/dist/plus/integrations/providers/bitbucket-server.js.map +1 -0
- package/dist/plus/integrations/providers/bitbucket.d.ts +50 -0
- package/dist/plus/integrations/providers/bitbucket.d.ts.map +1 -0
- package/dist/plus/integrations/providers/bitbucket.js +181 -0
- package/dist/plus/integrations/providers/bitbucket.js.map +1 -0
- package/dist/plus/integrations/providers/github/github.d.ts +5 -0
- package/dist/plus/integrations/providers/github/github.d.ts.map +1 -0
- package/dist/plus/integrations/providers/github/github.js +47 -0
- package/dist/plus/integrations/providers/github/github.js.map +1 -0
- package/dist/plus/integrations/providers/github/github.utils.d.ts +11 -0
- package/dist/plus/integrations/providers/github/github.utils.d.ts.map +1 -0
- package/dist/plus/integrations/providers/github/github.utils.js +6 -0
- package/dist/plus/integrations/providers/github/github.utils.js.map +1 -0
- package/dist/plus/integrations/providers/github/models.d.ts +3 -0
- package/dist/plus/integrations/providers/github/models.d.ts.map +1 -0
- package/dist/plus/integrations/providers/github/models.js +2 -0
- package/dist/plus/integrations/providers/github/models.js.map +1 -0
- package/dist/plus/integrations/providers/github.d.ts +73 -0
- package/dist/plus/integrations/providers/github.d.ts.map +1 -0
- package/dist/plus/integrations/providers/github.js +160 -0
- package/dist/plus/integrations/providers/github.js.map +1 -0
- package/dist/plus/integrations/providers/gitlab/gitlab.d.ts +63 -0
- package/dist/plus/integrations/providers/gitlab/gitlab.d.ts.map +1 -0
- package/dist/plus/integrations/providers/gitlab/gitlab.js +828 -0
- package/dist/plus/integrations/providers/gitlab/gitlab.js.map +1 -0
- package/dist/plus/integrations/providers/gitlab/gitlab.utils.d.ts +21 -0
- package/dist/plus/integrations/providers/gitlab/gitlab.utils.d.ts.map +1 -0
- package/dist/plus/integrations/providers/gitlab/gitlab.utils.js +45 -0
- package/dist/plus/integrations/providers/gitlab/gitlab.utils.js.map +1 -0
- package/dist/plus/integrations/providers/gitlab/models.d.ts +128 -0
- package/dist/plus/integrations/providers/gitlab/models.d.ts.map +1 -0
- package/dist/plus/integrations/providers/gitlab/models.js +96 -0
- package/dist/plus/integrations/providers/gitlab/models.js.map +1 -0
- package/dist/plus/integrations/providers/gitlab.d.ts +79 -0
- package/dist/plus/integrations/providers/gitlab.d.ts.map +1 -0
- package/dist/plus/integrations/providers/gitlab.js +253 -0
- package/dist/plus/integrations/providers/gitlab.js.map +1 -0
- package/dist/plus/integrations/providers/jira.d.ts +46 -0
- package/dist/plus/integrations/providers/jira.d.ts.map +1 -0
- package/dist/plus/integrations/providers/jira.js +255 -0
- package/dist/plus/integrations/providers/jira.js.map +1 -0
- package/dist/plus/integrations/providers/linear.d.ts +47 -0
- package/dist/plus/integrations/providers/linear.d.ts.map +1 -0
- package/dist/plus/integrations/providers/linear.js +198 -0
- package/dist/plus/integrations/providers/linear.js.map +1 -0
- package/dist/plus/integrations/providers/models.d.ts +433 -0
- package/dist/plus/integrations/providers/models.d.ts.map +1 -0
- package/dist/plus/integrations/providers/models.js +602 -0
- package/dist/plus/integrations/providers/models.js.map +1 -0
- package/dist/plus/integrations/providers/providersApi.d.ts +129 -0
- package/dist/plus/integrations/providers/providersApi.d.ts.map +1 -0
- package/dist/plus/integrations/providers/providersApi.js +602 -0
- package/dist/plus/integrations/providers/providersApi.js.map +1 -0
- package/dist/plus/integrations/providers/utils.d.ts +54 -0
- package/dist/plus/integrations/providers/utils.d.ts.map +1 -0
- package/dist/plus/integrations/providers/utils.js +262 -0
- package/dist/plus/integrations/providers/utils.js.map +1 -0
- package/dist/plus/integrations/telemetry.d.ts +26 -0
- package/dist/plus/integrations/telemetry.d.ts.map +1 -0
- package/dist/plus/integrations/telemetry.js +11 -0
- package/dist/plus/integrations/telemetry.js.map +1 -0
- package/dist/plus/integrations/utils/integration.utils.d.ts +14 -0
- package/dist/plus/integrations/utils/integration.utils.d.ts.map +1 -0
- package/dist/plus/integrations/utils/integration.utils.js +111 -0
- package/dist/plus/integrations/utils/integration.utils.js.map +1 -0
- package/dist/utils/disposable.d.ts +15 -2
- package/dist/utils/disposable.d.ts.map +1 -1
- package/dist/utils/disposable.js.map +1 -1
- package/package.json +43 -2
- package/src/git/context.ts +4 -3
- package/src/git/providers/operations.ts +1 -1
- package/src/git/providers/worktrees.ts +14 -2
- package/src/git/utils/conflictResolution.utils.ts +126 -0
- package/src/git-cli/providers/operations.ts +22 -2
- package/src/git-cli/providers/worktrees.ts +17 -2
- package/src/plus/ai/utils/ai.utils.ts +5 -5
- package/src/plus/git-github/api/github.ts +13 -25
- package/src/plus/integrations/authentication/cloudIntegrationService.ts +120 -0
- package/src/plus/integrations/authentication/configuredIntegrationService.ts +414 -0
- package/src/plus/integrations/authentication/integrationAuthenticationProvider.ts +289 -0
- package/src/plus/integrations/authentication/integrationAuthenticationService.ts +144 -0
- package/src/plus/integrations/authentication/manualTokenProvider.ts +72 -0
- package/src/plus/integrations/authentication/models.ts +168 -0
- package/src/plus/integrations/constants.ts +169 -0
- package/src/plus/integrations/context.ts +383 -0
- package/src/plus/integrations/errors.ts +35 -0
- package/src/plus/integrations/index.ts +119 -0
- package/src/plus/integrations/integrationService.ts +924 -0
- package/src/plus/integrations/models/gitHostIntegration.ts +738 -0
- package/src/plus/integrations/models/integration.ts +657 -0
- package/src/plus/integrations/models/issuesIntegration.ts +124 -0
- package/src/plus/integrations/providers/apiClients.ts +72 -0
- package/src/plus/integrations/providers/azure/azure.ts +691 -0
- package/src/plus/integrations/providers/azure/models.ts +605 -0
- package/src/plus/integrations/providers/azureDevOps.ts +677 -0
- package/src/plus/integrations/providers/bitbucket/bitbucket.ts +774 -0
- package/src/plus/integrations/providers/bitbucket/models.ts +445 -0
- package/src/plus/integrations/providers/bitbucket-server/models.ts +252 -0
- package/src/plus/integrations/providers/bitbucket-server.ts +282 -0
- package/src/plus/integrations/providers/bitbucket.ts +350 -0
- package/src/plus/integrations/providers/github/github.ts +64 -0
- package/src/plus/integrations/providers/github/github.utils.ts +23 -0
- package/src/plus/integrations/providers/github/models.ts +29 -0
- package/src/plus/integrations/providers/github.ts +366 -0
- package/src/plus/integrations/providers/gitlab/gitlab.ts +1210 -0
- package/src/plus/integrations/providers/gitlab/gitlab.utils.ts +71 -0
- package/src/plus/integrations/providers/gitlab/models.ts +257 -0
- package/src/plus/integrations/providers/gitlab.ts +473 -0
- package/src/plus/integrations/providers/jira.ts +359 -0
- package/src/plus/integrations/providers/linear.ts +275 -0
- package/src/plus/integrations/providers/models.ts +1114 -0
- package/src/plus/integrations/providers/providersApi.ts +1126 -0
- package/src/plus/integrations/providers/utils.ts +359 -0
- package/src/plus/integrations/telemetry.ts +29 -0
- package/src/plus/integrations/utils/integration.utils.ts +138 -0
- package/src/utils/disposable.ts +15 -2
|
@@ -0,0 +1,657 @@
|
|
|
1
|
+
import type { Account } from '../../../git/models/author.js';
|
|
2
|
+
import type { AutolinkReference, DynamicAutolinkReference } from '../../../git/models/autolink.js';
|
|
3
|
+
import type { Issue, IssueShape } from '../../../git/models/issue.js';
|
|
4
|
+
import type { IssueOrPullRequest, IssueOrPullRequestType } from '../../../git/models/issueOrPullRequest.js';
|
|
5
|
+
import type { PullRequest } from '../../../git/models/pullRequest.js';
|
|
6
|
+
import type { ResourceDescriptor } from '../../../git/models/resourceDescriptor.js';
|
|
7
|
+
import { isCancellationError } from '../../../utils/cancellation.js';
|
|
8
|
+
import { gate } from '../../../utils/decorators/gate.js';
|
|
9
|
+
import { debug, trace } from '../../../utils/decorators/log.js';
|
|
10
|
+
import type { Disposable } from '../../../utils/disposable.js';
|
|
11
|
+
import type { Event } from '../../../utils/event.js';
|
|
12
|
+
import { Emitter } from '../../../utils/event.js';
|
|
13
|
+
import { fnv1aHash64 } from '../../../utils/hash.js';
|
|
14
|
+
import type { ScopedLogger } from '../../../utils/logger.scoped.js';
|
|
15
|
+
import { getScopedLogger } from '../../../utils/logger.scoped.js';
|
|
16
|
+
import type {
|
|
17
|
+
IntegrationAuthenticationProviderDescriptor,
|
|
18
|
+
IntegrationAuthenticationSessionDescriptor,
|
|
19
|
+
} from '../authentication/integrationAuthenticationProvider.js';
|
|
20
|
+
import type { IntegrationAuthenticationService } from '../authentication/integrationAuthenticationService.js';
|
|
21
|
+
import type { ProviderAuthenticationSession } from '../authentication/models.js';
|
|
22
|
+
import type { IntegrationIds, IssuesCloudHostIntegrationId } from '../constants.js';
|
|
23
|
+
import { GitCloudHostIntegrationId } from '../constants.js';
|
|
24
|
+
import type { IntegrationServiceContext } from '../context.js';
|
|
25
|
+
import { AuthenticationError, RequestClientError } from '../errors.js';
|
|
26
|
+
import type { IntegrationConnectionChangeEvent } from '../integrationService.js';
|
|
27
|
+
import type { ProvidersApi } from '../providers/providersApi.js';
|
|
28
|
+
import type { Sources } from '../telemetry.js';
|
|
29
|
+
import type { GitHostIntegration } from './gitHostIntegration.js';
|
|
30
|
+
import type { IssuesIntegration } from './issuesIntegration.js';
|
|
31
|
+
|
|
32
|
+
export type Integration = GitHostIntegration | IssuesIntegration;
|
|
33
|
+
export type IntegrationById<T extends IntegrationIds> = T extends IssuesCloudHostIntegrationId
|
|
34
|
+
? IssuesIntegration
|
|
35
|
+
: GitHostIntegration;
|
|
36
|
+
export type IntegrationType = 'git' | 'issues';
|
|
37
|
+
|
|
38
|
+
export type IntegrationKey<T extends IntegrationIds = IntegrationIds> = T extends
|
|
39
|
+
| GitCloudHostIntegrationId
|
|
40
|
+
| IssuesCloudHostIntegrationId
|
|
41
|
+
? `${T}`
|
|
42
|
+
: `${T}:${string}`;
|
|
43
|
+
|
|
44
|
+
export type IntegrationConnectedKey<T extends IntegrationIds = IntegrationIds> = `connected:${IntegrationKey<T>}`;
|
|
45
|
+
|
|
46
|
+
export type IntegrationResult<T> =
|
|
47
|
+
| { value: T; duration?: number; error?: Error }
|
|
48
|
+
| { error: Error; duration?: number; value?: never }
|
|
49
|
+
| undefined;
|
|
50
|
+
|
|
51
|
+
type SyncReqUsecase = Exclude<
|
|
52
|
+
| 'getAccountForCommit'
|
|
53
|
+
| 'getAccountForEmail'
|
|
54
|
+
| 'getAccountForResource'
|
|
55
|
+
| 'getCurrentAccount'
|
|
56
|
+
| 'getDefaultBranch'
|
|
57
|
+
| 'getIssue'
|
|
58
|
+
| 'getIssueOrPullRequest'
|
|
59
|
+
| 'getIssuesForProject'
|
|
60
|
+
| 'getProjectsForResources'
|
|
61
|
+
| 'getPullRequest'
|
|
62
|
+
| 'getPullRequestForBranch'
|
|
63
|
+
| 'getPullRequestForCommit'
|
|
64
|
+
| 'getRepositoryMetadata'
|
|
65
|
+
| 'getResourcesForUser'
|
|
66
|
+
| 'mergePullRequest'
|
|
67
|
+
| 'searchMyIssues'
|
|
68
|
+
| 'searchMyPullRequests'
|
|
69
|
+
| 'searchPullRequests',
|
|
70
|
+
// excluding to show explicitly that we don't want to add 'all' key occasionally
|
|
71
|
+
'all'
|
|
72
|
+
>;
|
|
73
|
+
|
|
74
|
+
export abstract class IntegrationBase<
|
|
75
|
+
ID extends IntegrationIds = IntegrationIds,
|
|
76
|
+
T extends ResourceDescriptor = ResourceDescriptor,
|
|
77
|
+
> implements Disposable {
|
|
78
|
+
abstract readonly type: IntegrationType;
|
|
79
|
+
|
|
80
|
+
private readonly _onDidChange = new Emitter<void>();
|
|
81
|
+
get onDidChange(): Event<void> {
|
|
82
|
+
return this._onDidChange.event;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
constructor(
|
|
86
|
+
protected readonly ctx: IntegrationServiceContext,
|
|
87
|
+
protected readonly authenticationService: IntegrationAuthenticationService,
|
|
88
|
+
protected readonly getProvidersApi: () => Promise<ProvidersApi>,
|
|
89
|
+
private readonly didChangeConnection: Emitter<IntegrationConnectionChangeEvent>,
|
|
90
|
+
) {}
|
|
91
|
+
|
|
92
|
+
dispose(): void {
|
|
93
|
+
this._onDidChange.dispose();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
abstract get authProvider(): IntegrationAuthenticationProviderDescriptor;
|
|
97
|
+
abstract get id(): ID;
|
|
98
|
+
protected abstract get key(): IntegrationKey<ID>;
|
|
99
|
+
abstract get name(): string;
|
|
100
|
+
abstract get domain(): string;
|
|
101
|
+
|
|
102
|
+
get authProviderDescriptor(): IntegrationAuthenticationSessionDescriptor {
|
|
103
|
+
return { domain: this.domain, scopes: this.authProvider.scopes };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
get icon(): string {
|
|
107
|
+
return this.id;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
access(): Promise<boolean> {
|
|
111
|
+
return this.ctx.account.isTrialOrPaid();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
autolinks():
|
|
115
|
+
| (AutolinkReference | DynamicAutolinkReference)[]
|
|
116
|
+
| Promise<(AutolinkReference | DynamicAutolinkReference)[]> {
|
|
117
|
+
return [];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
private get connectedKey(): IntegrationConnectedKey<ID> {
|
|
121
|
+
return `connected:${this.key}`;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
get maybeConnected(): boolean | undefined {
|
|
125
|
+
return this._session === undefined ? undefined : this._session !== null;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Hash of the current session's access token. Changes on any token change (account switch or refresh). */
|
|
129
|
+
private _sessionFingerprint: { session: ProviderAuthenticationSession; hash: string } | undefined;
|
|
130
|
+
get sessionFingerprint(): string | undefined {
|
|
131
|
+
if (this._session == null) return undefined;
|
|
132
|
+
|
|
133
|
+
if (this._sessionFingerprint?.session !== this._session) {
|
|
134
|
+
this._sessionFingerprint = { session: this._session, hash: fnv1aHash64(this._session.accessToken) };
|
|
135
|
+
}
|
|
136
|
+
return this._sessionFingerprint.hash;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
get connectionExpired(): boolean | undefined {
|
|
140
|
+
if (this._session?.expiresAt == null) return undefined;
|
|
141
|
+
return new Date(this._session.expiresAt) < new Date();
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
protected _session: ProviderAuthenticationSession | null | undefined;
|
|
145
|
+
getSession(
|
|
146
|
+
source: Sources,
|
|
147
|
+
): ProviderAuthenticationSession | Promise<ProviderAuthenticationSession | undefined> | undefined {
|
|
148
|
+
if (this._session === undefined) {
|
|
149
|
+
return this.ensureSession({ createIfNeeded: false, source: source });
|
|
150
|
+
}
|
|
151
|
+
return this._session ?? undefined;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
@debug()
|
|
155
|
+
async connect(source: Sources): Promise<boolean> {
|
|
156
|
+
try {
|
|
157
|
+
return Boolean(await this.ensureSession({ createIfNeeded: true, source: source }));
|
|
158
|
+
} catch (_ex) {
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
protected providerOnConnect?(): void | Promise<void>;
|
|
164
|
+
|
|
165
|
+
@gate()
|
|
166
|
+
@debug()
|
|
167
|
+
async disconnect(options?: { silent?: boolean; currentSessionOnly?: boolean }): Promise<void> {
|
|
168
|
+
if (options?.currentSessionOnly && this._session === null) return;
|
|
169
|
+
|
|
170
|
+
const connected = this._session != null;
|
|
171
|
+
|
|
172
|
+
let signOut = !options?.currentSessionOnly;
|
|
173
|
+
|
|
174
|
+
if (connected && !options?.currentSessionOnly && !options?.silent) {
|
|
175
|
+
const decision = await this.ctx.hooks?.onConfirmDisconnect?.({
|
|
176
|
+
integrationName: this.name,
|
|
177
|
+
offerSignOut: this.authenticationService.supports(this.authProvider.id),
|
|
178
|
+
});
|
|
179
|
+
if (decision == null) return;
|
|
180
|
+
|
|
181
|
+
signOut = decision.signOut;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (signOut) {
|
|
185
|
+
const authProvider = await this.authenticationService.get(this.authProvider.id);
|
|
186
|
+
void authProvider.deleteSession(this.authProviderDescriptor);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
this.resetRequestExceptionCount('all');
|
|
190
|
+
this._session = null;
|
|
191
|
+
|
|
192
|
+
if (connected) {
|
|
193
|
+
// Don't store the disconnected flag if silently disconnecting or disconnecting this only for
|
|
194
|
+
// this current VS Code session (will be re-connected on next restart)
|
|
195
|
+
if (!options?.currentSessionOnly && !options?.silent) {
|
|
196
|
+
void this.ctx.storage.storeWorkspace(this.connectedKey, false).catch();
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
this._onDidChange.fire();
|
|
200
|
+
if (!options?.currentSessionOnly) {
|
|
201
|
+
this.didChangeConnection?.fire({ integration: this, key: this.key, reason: 'disconnected' });
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
await this.providerOnDisconnect?.();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
protected providerOnDisconnect?(): void | Promise<void>;
|
|
209
|
+
|
|
210
|
+
@debug()
|
|
211
|
+
async reauthenticate(): Promise<void> {
|
|
212
|
+
if (this._session === undefined) return;
|
|
213
|
+
|
|
214
|
+
this._session = undefined;
|
|
215
|
+
void (await this.ensureSession({ createIfNeeded: true, forceNewSession: true }));
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
refresh(): void {
|
|
219
|
+
void this.ensureSession({ createIfNeeded: false });
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
private _syncRequestsPerFailedUsecase = new Set<SyncReqUsecase>();
|
|
223
|
+
hasSessionSyncRequests(): boolean {
|
|
224
|
+
return this._syncRequestsPerFailedUsecase.size > 0;
|
|
225
|
+
}
|
|
226
|
+
requestSessionSyncForUsecase(syncReqUsecase: SyncReqUsecase): void {
|
|
227
|
+
this._syncRequestsPerFailedUsecase.add(syncReqUsecase);
|
|
228
|
+
}
|
|
229
|
+
private static readonly requestExceptionLimit = 5;
|
|
230
|
+
private requestExceptionCount = 0;
|
|
231
|
+
|
|
232
|
+
resetRequestExceptionCount(syncReqUsecase: SyncReqUsecase | 'all'): void {
|
|
233
|
+
this.requestExceptionCount = 0;
|
|
234
|
+
if (syncReqUsecase === 'all') {
|
|
235
|
+
this._syncRequestsPerFailedUsecase.clear();
|
|
236
|
+
} else {
|
|
237
|
+
this._syncRequestsPerFailedUsecase.delete(syncReqUsecase);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Resets request exceptions without resetting the amount of syncs
|
|
243
|
+
*/
|
|
244
|
+
smoothifyRequestExceptionCount(): void {
|
|
245
|
+
// On resync we reset exception count only to avoid infinitive syncs on failure
|
|
246
|
+
this.requestExceptionCount = 0;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
async reset(): Promise<void> {
|
|
250
|
+
await this.disconnect({ silent: true });
|
|
251
|
+
await this.ctx.storage.deleteWorkspace(this.connectedKey);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
private skippedNonCloudReported = false;
|
|
255
|
+
@debug()
|
|
256
|
+
async syncCloudConnection(state: 'connected' | 'disconnected', forceSync: boolean): Promise<void> {
|
|
257
|
+
// Initially the condition on `this._session.cloud` has been added here: https://github.com/gitkraken/vscode-gitlens/commit/e95e70c430bd162924cc3bd5c1e8ab90e6293449#diff-4213141a45cccaab7aa2e40028b155a87eb913b07388485831403e60ce5555e4R237
|
|
258
|
+
// I'm not sure about reasons, but it seems we want to replace it with the cloud session if it's connected.
|
|
259
|
+
// Gradually we'll stop having non-cloud sessions.
|
|
260
|
+
// However this is needed to be tested with PATs, e.g. with a GitLab PAT.
|
|
261
|
+
if (this._session?.cloud === false && state !== 'connected') {
|
|
262
|
+
if (this.id !== GitCloudHostIntegrationId.GitHub && !this.skippedNonCloudReported) {
|
|
263
|
+
this.ctx.hooks?.session?.onRefreshSkipped?.({
|
|
264
|
+
id: this.id,
|
|
265
|
+
reason: 'skip-non-cloud',
|
|
266
|
+
cloud: false,
|
|
267
|
+
});
|
|
268
|
+
this.skippedNonCloudReported = true;
|
|
269
|
+
}
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
switch (state) {
|
|
274
|
+
case 'connected': {
|
|
275
|
+
const oldSession = this._session;
|
|
276
|
+
if (forceSync) {
|
|
277
|
+
// Reset our stored session so that we get a new one from the cloud
|
|
278
|
+
const authProvider = await this.authenticationService.get(this.authProvider.id);
|
|
279
|
+
await authProvider.deleteSession(this.authProviderDescriptor);
|
|
280
|
+
// Reset the session and clear our "stay disconnected" flag
|
|
281
|
+
this._session = undefined;
|
|
282
|
+
await this.ctx.storage.deleteWorkspace(this.connectedKey);
|
|
283
|
+
} else {
|
|
284
|
+
// Only sync if we're not connected and not disabled and don't have pending errors
|
|
285
|
+
if (
|
|
286
|
+
this._session != null ||
|
|
287
|
+
this.requestExceptionCount > 0 ||
|
|
288
|
+
this.ctx.storage.getWorkspace(this.connectedKey) === false
|
|
289
|
+
) {
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
forceSync = true;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// sync option, rather than createIfNeeded, makes sure we don't call connectCloudIntegrations and open a gkdev window
|
|
297
|
+
// if there was no session or some problem fetching/refreshing the existing session from the cloud api
|
|
298
|
+
const newSession = await this.ensureSession({ sync: forceSync });
|
|
299
|
+
|
|
300
|
+
if (oldSession && newSession && newSession.accessToken !== oldSession.accessToken) {
|
|
301
|
+
this.resetRequestExceptionCount('all');
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
break;
|
|
305
|
+
}
|
|
306
|
+
case 'disconnected':
|
|
307
|
+
await this.disconnect({ silent: true });
|
|
308
|
+
break;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
protected handleProviderException(
|
|
313
|
+
syncReqUsecase: SyncReqUsecase,
|
|
314
|
+
ex: Error,
|
|
315
|
+
options?: { scope?: ScopedLogger | undefined; silent?: boolean },
|
|
316
|
+
): void {
|
|
317
|
+
if (isCancellationError(ex)) return;
|
|
318
|
+
|
|
319
|
+
options?.scope?.error(ex);
|
|
320
|
+
|
|
321
|
+
if (ex instanceof AuthenticationError && this._session?.cloud) {
|
|
322
|
+
if (!this.hasSessionSyncRequests()) {
|
|
323
|
+
this.requestSessionSyncForUsecase(syncReqUsecase);
|
|
324
|
+
this._session = {
|
|
325
|
+
...this._session,
|
|
326
|
+
expiresAt: new Date(Date.now() - 1),
|
|
327
|
+
};
|
|
328
|
+
} else {
|
|
329
|
+
this.trackRequestException(options);
|
|
330
|
+
}
|
|
331
|
+
} else if (ex instanceof AuthenticationError || ex instanceof RequestClientError) {
|
|
332
|
+
this.trackRequestException(options);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
private missingExpirityReported = false;
|
|
337
|
+
@gate()
|
|
338
|
+
protected async refreshSessionIfExpired(scope?: ScopedLogger): Promise<void> {
|
|
339
|
+
if (this._session?.expiresAt != null && this._session.expiresAt < new Date()) {
|
|
340
|
+
// The current session is expired, so get the latest from the cloud and refresh if needed
|
|
341
|
+
try {
|
|
342
|
+
await this.syncCloudConnection('connected', true);
|
|
343
|
+
} catch (ex) {
|
|
344
|
+
scope?.error(ex);
|
|
345
|
+
}
|
|
346
|
+
} else if (
|
|
347
|
+
this._session?.expiresAt == null &&
|
|
348
|
+
this.id !== GitCloudHostIntegrationId.GitHub &&
|
|
349
|
+
!this.missingExpirityReported
|
|
350
|
+
) {
|
|
351
|
+
this.ctx.hooks?.session?.onRefreshSkipped?.({
|
|
352
|
+
id: this.id,
|
|
353
|
+
reason: 'missing-expiry',
|
|
354
|
+
cloud: this._session?.cloud,
|
|
355
|
+
});
|
|
356
|
+
this.missingExpirityReported = true;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
@trace()
|
|
361
|
+
trackRequestException(options?: { silent?: boolean }): void {
|
|
362
|
+
this.requestExceptionCount++;
|
|
363
|
+
|
|
364
|
+
if (this.requestExceptionCount >= IntegrationBase.requestExceptionLimit && this._session !== null) {
|
|
365
|
+
if (!options?.silent) {
|
|
366
|
+
this.ctx.hooks?.ui?.onDisconnectedAfterTooManyFailures?.(this.name);
|
|
367
|
+
}
|
|
368
|
+
void this.disconnect({ currentSessionOnly: true });
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
@gate()
|
|
373
|
+
@trace({ exit: true })
|
|
374
|
+
async isConnected(): Promise<boolean> {
|
|
375
|
+
return (await this.getSession('integrations')) != null;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
@gate()
|
|
379
|
+
private async ensureSession(
|
|
380
|
+
options:
|
|
381
|
+
| {
|
|
382
|
+
createIfNeeded?: boolean;
|
|
383
|
+
forceNewSession?: boolean;
|
|
384
|
+
sync?: never;
|
|
385
|
+
source?: Sources;
|
|
386
|
+
}
|
|
387
|
+
| {
|
|
388
|
+
createIfNeeded?: never;
|
|
389
|
+
forceNewSession?: never;
|
|
390
|
+
sync: boolean;
|
|
391
|
+
source?: Sources;
|
|
392
|
+
},
|
|
393
|
+
): Promise<ProviderAuthenticationSession | undefined> {
|
|
394
|
+
const { createIfNeeded, forceNewSession, source, sync } = options;
|
|
395
|
+
if (this._session != null) return this._session;
|
|
396
|
+
if (this.ctx.config.isIntegrationsEnabled?.() === false) return undefined;
|
|
397
|
+
|
|
398
|
+
if (createIfNeeded || sync) {
|
|
399
|
+
await this.ctx.storage.deleteWorkspace(this.connectedKey);
|
|
400
|
+
} else if (this.ctx.storage.getWorkspace(this.connectedKey) === false) {
|
|
401
|
+
return undefined;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
let session: ProviderAuthenticationSession | undefined | null;
|
|
405
|
+
try {
|
|
406
|
+
const authProvider = await this.authenticationService.get(this.authProvider.id);
|
|
407
|
+
session = await authProvider.getSession(
|
|
408
|
+
this.authProviderDescriptor,
|
|
409
|
+
sync
|
|
410
|
+
? { sync: sync, source: source }
|
|
411
|
+
: {
|
|
412
|
+
createIfNeeded: createIfNeeded,
|
|
413
|
+
forceNewSession: forceNewSession,
|
|
414
|
+
source: source,
|
|
415
|
+
},
|
|
416
|
+
);
|
|
417
|
+
|
|
418
|
+
if (session?.expiresAt != null && session.expiresAt < new Date()) {
|
|
419
|
+
session = null;
|
|
420
|
+
}
|
|
421
|
+
} catch (ex) {
|
|
422
|
+
await this.ctx.storage.deleteWorkspace(this.connectedKey);
|
|
423
|
+
|
|
424
|
+
if (ex instanceof Error && ex.message.includes('User did not consent')) {
|
|
425
|
+
return undefined;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
session = null;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
if (session === undefined && !createIfNeeded && !sync) {
|
|
432
|
+
await this.ctx.storage.deleteWorkspace(this.connectedKey);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
this._session = session ?? null;
|
|
436
|
+
this.smoothifyRequestExceptionCount();
|
|
437
|
+
|
|
438
|
+
if (session != null) {
|
|
439
|
+
await this.ctx.storage.storeWorkspace(this.connectedKey, true);
|
|
440
|
+
|
|
441
|
+
queueMicrotask(() => {
|
|
442
|
+
this._onDidChange.fire();
|
|
443
|
+
this.didChangeConnection?.fire({ integration: this, key: this.key, reason: 'connected' });
|
|
444
|
+
void this.providerOnConnect?.();
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
return session ?? undefined;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
getIgnoreSSLErrors(): boolean | 'force' {
|
|
452
|
+
return this.authenticationService.ignoreSSLErrors(this);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
async searchMyIssues(resource?: ResourceDescriptor, cancellation?: AbortSignal): Promise<IssueShape[] | undefined>;
|
|
456
|
+
async searchMyIssues(
|
|
457
|
+
resources?: ResourceDescriptor[],
|
|
458
|
+
cancellation?: AbortSignal,
|
|
459
|
+
): Promise<IssueShape[] | undefined>;
|
|
460
|
+
@trace()
|
|
461
|
+
async searchMyIssues(
|
|
462
|
+
resources?: ResourceDescriptor | ResourceDescriptor[],
|
|
463
|
+
cancellation?: AbortSignal,
|
|
464
|
+
): Promise<IssueShape[] | undefined> {
|
|
465
|
+
const scope = getScopedLogger();
|
|
466
|
+
const connected = this.maybeConnected ?? (await this.isConnected());
|
|
467
|
+
if (!connected) return undefined;
|
|
468
|
+
|
|
469
|
+
await this.refreshSessionIfExpired(scope);
|
|
470
|
+
|
|
471
|
+
try {
|
|
472
|
+
const issues = await this.searchProviderMyIssues(
|
|
473
|
+
this._session!,
|
|
474
|
+
resources != null ? (Array.isArray(resources) ? resources : [resources]) : undefined,
|
|
475
|
+
cancellation,
|
|
476
|
+
);
|
|
477
|
+
this.resetRequestExceptionCount('searchMyIssues');
|
|
478
|
+
return issues;
|
|
479
|
+
} catch (ex) {
|
|
480
|
+
this.handleProviderException('searchMyIssues', ex, { scope: scope });
|
|
481
|
+
return undefined;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
protected abstract searchProviderMyIssues(
|
|
486
|
+
session: ProviderAuthenticationSession,
|
|
487
|
+
resources?: ResourceDescriptor[],
|
|
488
|
+
cancellation?: AbortSignal,
|
|
489
|
+
): Promise<IssueShape[] | undefined>;
|
|
490
|
+
|
|
491
|
+
@trace()
|
|
492
|
+
async getLinkedIssueOrPullRequest(
|
|
493
|
+
resource: T,
|
|
494
|
+
link: { id: string; key: string },
|
|
495
|
+
options?: { expiryOverride?: boolean | number; type?: IssueOrPullRequestType },
|
|
496
|
+
): Promise<IssueOrPullRequest | undefined> {
|
|
497
|
+
const scope = getScopedLogger();
|
|
498
|
+
|
|
499
|
+
const connected = this.maybeConnected ?? (await this.isConnected());
|
|
500
|
+
if (!connected) return undefined;
|
|
501
|
+
|
|
502
|
+
await this.refreshSessionIfExpired(scope);
|
|
503
|
+
|
|
504
|
+
const issueOrPR = this.ctx.cache.getIssueOrPullRequest(
|
|
505
|
+
link.key,
|
|
506
|
+
options?.type,
|
|
507
|
+
resource,
|
|
508
|
+
this,
|
|
509
|
+
() => ({
|
|
510
|
+
value: (async () => {
|
|
511
|
+
try {
|
|
512
|
+
const result = await this.getProviderLinkedIssueOrPullRequest(
|
|
513
|
+
this._session!,
|
|
514
|
+
resource,
|
|
515
|
+
link,
|
|
516
|
+
options?.type,
|
|
517
|
+
);
|
|
518
|
+
this.resetRequestExceptionCount('getIssueOrPullRequest');
|
|
519
|
+
return result;
|
|
520
|
+
} catch (ex) {
|
|
521
|
+
this.handleProviderException('getIssueOrPullRequest', ex, { scope: scope });
|
|
522
|
+
return undefined;
|
|
523
|
+
}
|
|
524
|
+
})(),
|
|
525
|
+
}),
|
|
526
|
+
options,
|
|
527
|
+
);
|
|
528
|
+
return issueOrPR;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
protected abstract getProviderLinkedIssueOrPullRequest(
|
|
532
|
+
session: ProviderAuthenticationSession,
|
|
533
|
+
resource: T,
|
|
534
|
+
link: { id: string; key: string },
|
|
535
|
+
type: undefined | IssueOrPullRequestType,
|
|
536
|
+
): Promise<IssueOrPullRequest | undefined>;
|
|
537
|
+
|
|
538
|
+
@trace()
|
|
539
|
+
async getIssue(
|
|
540
|
+
resource: T,
|
|
541
|
+
id: string,
|
|
542
|
+
options?: { expiryOverride?: boolean | number },
|
|
543
|
+
): Promise<Issue | undefined> {
|
|
544
|
+
const scope = getScopedLogger();
|
|
545
|
+
|
|
546
|
+
const connected = this.maybeConnected ?? (await this.isConnected());
|
|
547
|
+
if (!connected) return undefined;
|
|
548
|
+
|
|
549
|
+
await this.refreshSessionIfExpired(scope);
|
|
550
|
+
|
|
551
|
+
const issue = this.ctx.cache.getIssue(
|
|
552
|
+
id,
|
|
553
|
+
resource,
|
|
554
|
+
this,
|
|
555
|
+
() => ({
|
|
556
|
+
value: (async () => {
|
|
557
|
+
try {
|
|
558
|
+
const result = await this.getProviderIssue(this._session!, resource, id);
|
|
559
|
+
this.resetRequestExceptionCount('getIssue');
|
|
560
|
+
return result;
|
|
561
|
+
} catch (ex) {
|
|
562
|
+
this.handleProviderException('getIssue', ex, { scope: scope });
|
|
563
|
+
return undefined;
|
|
564
|
+
}
|
|
565
|
+
})(),
|
|
566
|
+
}),
|
|
567
|
+
options,
|
|
568
|
+
);
|
|
569
|
+
return issue;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
protected abstract getProviderIssue(
|
|
573
|
+
session: ProviderAuthenticationSession,
|
|
574
|
+
resource: T,
|
|
575
|
+
id: string,
|
|
576
|
+
): Promise<Issue | undefined>;
|
|
577
|
+
|
|
578
|
+
async getCurrentAccount(options?: {
|
|
579
|
+
avatarSize?: number;
|
|
580
|
+
expiryOverride?: boolean | number;
|
|
581
|
+
}): Promise<Account | undefined> {
|
|
582
|
+
const scope = getScopedLogger();
|
|
583
|
+
|
|
584
|
+
const connected = this.maybeConnected ?? (await this.isConnected());
|
|
585
|
+
if (!connected) return undefined;
|
|
586
|
+
|
|
587
|
+
await this.refreshSessionIfExpired(scope);
|
|
588
|
+
|
|
589
|
+
const { expiryOverride, ...opts } = options ?? {};
|
|
590
|
+
|
|
591
|
+
const currentAccount = await this.ctx.cache.getCurrentAccount(
|
|
592
|
+
this,
|
|
593
|
+
|
|
594
|
+
(cacheable: any) => ({
|
|
595
|
+
value: (async () => {
|
|
596
|
+
try {
|
|
597
|
+
const account = await this.getProviderCurrentAccount?.(this._session!, opts);
|
|
598
|
+
this.resetRequestExceptionCount('getCurrentAccount');
|
|
599
|
+
return account;
|
|
600
|
+
} catch (ex) {
|
|
601
|
+
if (isCancellationError(ex)) {
|
|
602
|
+
cacheable.invalidate();
|
|
603
|
+
return undefined;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
this.handleProviderException('getCurrentAccount', ex, { scope: scope });
|
|
607
|
+
|
|
608
|
+
// Invalidate the cache on error, except for auth errors
|
|
609
|
+
if (!(ex instanceof AuthenticationError)) {
|
|
610
|
+
cacheable.invalidate();
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// Re-throw to the caller
|
|
614
|
+
throw ex;
|
|
615
|
+
}
|
|
616
|
+
})(),
|
|
617
|
+
}),
|
|
618
|
+
{ expiryOverride: expiryOverride, expireOnError: false },
|
|
619
|
+
);
|
|
620
|
+
return currentAccount;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
protected getProviderCurrentAccount?(
|
|
624
|
+
session: ProviderAuthenticationSession,
|
|
625
|
+
options?: { avatarSize?: number },
|
|
626
|
+
): Promise<Account | undefined>;
|
|
627
|
+
|
|
628
|
+
@trace()
|
|
629
|
+
async getPullRequest(resource: T, id: string): Promise<PullRequest | undefined> {
|
|
630
|
+
const scope = getScopedLogger();
|
|
631
|
+
|
|
632
|
+
const connected = this.maybeConnected ?? (await this.isConnected());
|
|
633
|
+
if (!connected) return undefined;
|
|
634
|
+
|
|
635
|
+
await this.refreshSessionIfExpired(scope);
|
|
636
|
+
|
|
637
|
+
const pr = await this.ctx.cache.getPullRequest(id, resource, this, () => ({
|
|
638
|
+
value: (async () => {
|
|
639
|
+
try {
|
|
640
|
+
const result = await this.getProviderPullRequest?.(this._session!, resource, id);
|
|
641
|
+
this.resetRequestExceptionCount('getPullRequest');
|
|
642
|
+
return result;
|
|
643
|
+
} catch (ex) {
|
|
644
|
+
this.handleProviderException('getPullRequest', ex, { scope: scope });
|
|
645
|
+
return undefined;
|
|
646
|
+
}
|
|
647
|
+
})(),
|
|
648
|
+
}));
|
|
649
|
+
return pr;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
protected getProviderPullRequest?(
|
|
653
|
+
session: ProviderAuthenticationSession,
|
|
654
|
+
resource: T,
|
|
655
|
+
id: string,
|
|
656
|
+
): Promise<PullRequest | undefined>;
|
|
657
|
+
}
|