@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.
Files changed (230) hide show
  1. package/CHANGELOG.md +13 -1
  2. package/README.md +13 -10
  3. package/dist/git/context.d.ts +4 -3
  4. package/dist/git/context.d.ts.map +1 -1
  5. package/dist/git/context.js.map +1 -1
  6. package/dist/git/providers/operations.d.ts +1 -0
  7. package/dist/git/providers/operations.d.ts.map +1 -1
  8. package/dist/git/providers/worktrees.d.ts +2 -0
  9. package/dist/git/providers/worktrees.d.ts.map +1 -1
  10. package/dist/git/utils/conflictResolution.utils.d.ts +32 -0
  11. package/dist/git/utils/conflictResolution.utils.d.ts.map +1 -1
  12. package/dist/git/utils/conflictResolution.utils.js +95 -0
  13. package/dist/git/utils/conflictResolution.utils.js.map +1 -1
  14. package/dist/git-cli/providers/operations.d.ts +1 -0
  15. package/dist/git-cli/providers/operations.d.ts.map +1 -1
  16. package/dist/git-cli/providers/operations.js +22 -1
  17. package/dist/git-cli/providers/operations.js.map +1 -1
  18. package/dist/git-cli/providers/worktrees.d.ts +2 -0
  19. package/dist/git-cli/providers/worktrees.d.ts.map +1 -1
  20. package/dist/git-cli/providers/worktrees.js +3 -0
  21. package/dist/git-cli/providers/worktrees.js.map +1 -1
  22. package/dist/plus/ai/utils/ai.utils.js +5 -5
  23. package/dist/plus/ai/utils/ai.utils.js.map +1 -1
  24. package/dist/plus/git-github/api/github.d.ts +6 -13
  25. package/dist/plus/git-github/api/github.d.ts.map +1 -1
  26. package/dist/plus/git-github/api/github.js +5 -10
  27. package/dist/plus/git-github/api/github.js.map +1 -1
  28. package/dist/plus/integrations/authentication/cloudIntegrationService.d.ts +11 -0
  29. package/dist/plus/integrations/authentication/cloudIntegrationService.d.ts.map +1 -0
  30. package/dist/plus/integrations/authentication/cloudIntegrationService.js +90 -0
  31. package/dist/plus/integrations/authentication/cloudIntegrationService.js.map +1 -0
  32. package/dist/plus/integrations/authentication/configuredIntegrationService.d.ts +67 -0
  33. package/dist/plus/integrations/authentication/configuredIntegrationService.d.ts.map +1 -0
  34. package/dist/plus/integrations/authentication/configuredIntegrationService.js +295 -0
  35. package/dist/plus/integrations/authentication/configuredIntegrationService.js.map +1 -0
  36. package/dist/plus/integrations/authentication/integrationAuthenticationProvider.d.ts +92 -0
  37. package/dist/plus/integrations/authentication/integrationAuthenticationProvider.d.ts.map +1 -0
  38. package/dist/plus/integrations/authentication/integrationAuthenticationProvider.js +185 -0
  39. package/dist/plus/integrations/authentication/integrationAuthenticationProvider.js.map +1 -0
  40. package/dist/plus/integrations/authentication/integrationAuthenticationService.d.ts +62 -0
  41. package/dist/plus/integrations/authentication/integrationAuthenticationService.d.ts.map +1 -0
  42. package/dist/plus/integrations/authentication/integrationAuthenticationService.js +122 -0
  43. package/dist/plus/integrations/authentication/integrationAuthenticationService.js.map +1 -0
  44. package/dist/plus/integrations/authentication/manualTokenProvider.d.ts +15 -0
  45. package/dist/plus/integrations/authentication/manualTokenProvider.d.ts.map +1 -0
  46. package/dist/plus/integrations/authentication/manualTokenProvider.js +49 -0
  47. package/dist/plus/integrations/authentication/manualTokenProvider.js.map +1 -0
  48. package/dist/plus/integrations/authentication/models.d.ts +87 -0
  49. package/dist/plus/integrations/authentication/models.d.ts.map +1 -0
  50. package/dist/plus/integrations/authentication/models.js +64 -0
  51. package/dist/plus/integrations/authentication/models.js.map +1 -0
  52. package/dist/plus/integrations/constants.d.ts +47 -0
  53. package/dist/plus/integrations/constants.d.ts.map +1 -0
  54. package/dist/plus/integrations/constants.js +128 -0
  55. package/dist/plus/integrations/constants.js.map +1 -0
  56. package/dist/plus/integrations/context.d.ts +354 -0
  57. package/dist/plus/integrations/context.d.ts.map +1 -0
  58. package/dist/plus/integrations/context.js +2 -0
  59. package/dist/plus/integrations/context.js.map +1 -0
  60. package/dist/plus/integrations/errors.d.ts +14 -0
  61. package/dist/plus/integrations/errors.d.ts.map +1 -0
  62. package/dist/plus/integrations/errors.js +19 -0
  63. package/dist/plus/integrations/errors.js.map +1 -0
  64. package/dist/plus/integrations/index.d.ts +32 -0
  65. package/dist/plus/integrations/index.d.ts.map +1 -0
  66. package/dist/plus/integrations/index.js +62 -0
  67. package/dist/plus/integrations/index.js.map +1 -0
  68. package/dist/plus/integrations/integrationService.d.ts +98 -0
  69. package/dist/plus/integrations/integrationService.d.ts.map +1 -0
  70. package/dist/plus/integrations/integrationService.js +627 -0
  71. package/dist/plus/integrations/integrationService.js.map +1 -0
  72. package/dist/plus/integrations/models/gitHostIntegration.d.ts +82 -0
  73. package/dist/plus/integrations/models/gitHostIntegration.d.ts.map +1 -0
  74. package/dist/plus/integrations/models/gitHostIntegration.js +522 -0
  75. package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -0
  76. package/dist/plus/integrations/models/integration.d.ts +127 -0
  77. package/dist/plus/integrations/models/integration.d.ts.map +1 -0
  78. package/dist/plus/integrations/models/integration.js +456 -0
  79. package/dist/plus/integrations/models/integration.js.map +1 -0
  80. package/dist/plus/integrations/models/issuesIntegration.d.ts +28 -0
  81. package/dist/plus/integrations/models/issuesIntegration.d.ts.map +1 -0
  82. package/dist/plus/integrations/models/issuesIntegration.js +101 -0
  83. package/dist/plus/integrations/models/issuesIntegration.js.map +1 -0
  84. package/dist/plus/integrations/providers/apiClients.d.ts +25 -0
  85. package/dist/plus/integrations/providers/apiClients.d.ts.map +1 -0
  86. package/dist/plus/integrations/providers/apiClients.js +39 -0
  87. package/dist/plus/integrations/providers/apiClients.js.map +1 -0
  88. package/dist/plus/integrations/providers/azure/azure.d.ts +47 -0
  89. package/dist/plus/integrations/providers/azure/azure.d.ts.map +1 -0
  90. package/dist/plus/integrations/providers/azure/azure.js +444 -0
  91. package/dist/plus/integrations/providers/azure/azure.js.map +1 -0
  92. package/dist/plus/integrations/providers/azure/models.d.ts +286 -0
  93. package/dist/plus/integrations/providers/azure/models.d.ts.map +1 -0
  94. package/dist/plus/integrations/providers/azure/models.js +203 -0
  95. package/dist/plus/integrations/providers/azure/models.js.map +1 -0
  96. package/dist/plus/integrations/providers/azureDevOps.d.ts +95 -0
  97. package/dist/plus/integrations/providers/azureDevOps.d.ts.map +1 -0
  98. package/dist/plus/integrations/providers/azureDevOps.js +432 -0
  99. package/dist/plus/integrations/providers/azureDevOps.js.map +1 -0
  100. package/dist/plus/integrations/providers/bitbucket/bitbucket.d.ts +42 -0
  101. package/dist/plus/integrations/providers/bitbucket/bitbucket.d.ts.map +1 -0
  102. package/dist/plus/integrations/providers/bitbucket/bitbucket.js +513 -0
  103. package/dist/plus/integrations/providers/bitbucket/bitbucket.js.map +1 -0
  104. package/dist/plus/integrations/providers/bitbucket/models.d.ts +222 -0
  105. package/dist/plus/integrations/providers/bitbucket/models.d.ts.map +1 -0
  106. package/dist/plus/integrations/providers/bitbucket/models.js +158 -0
  107. package/dist/plus/integrations/providers/bitbucket/models.js.map +1 -0
  108. package/dist/plus/integrations/providers/bitbucket-server/models.d.ts +120 -0
  109. package/dist/plus/integrations/providers/bitbucket-server/models.d.ts.map +1 -0
  110. package/dist/plus/integrations/providers/bitbucket-server/models.js +111 -0
  111. package/dist/plus/integrations/providers/bitbucket-server/models.js.map +1 -0
  112. package/dist/plus/integrations/providers/bitbucket-server.d.ts +60 -0
  113. package/dist/plus/integrations/providers/bitbucket-server.d.ts.map +1 -0
  114. package/dist/plus/integrations/providers/bitbucket-server.js +138 -0
  115. package/dist/plus/integrations/providers/bitbucket-server.js.map +1 -0
  116. package/dist/plus/integrations/providers/bitbucket.d.ts +50 -0
  117. package/dist/plus/integrations/providers/bitbucket.d.ts.map +1 -0
  118. package/dist/plus/integrations/providers/bitbucket.js +181 -0
  119. package/dist/plus/integrations/providers/bitbucket.js.map +1 -0
  120. package/dist/plus/integrations/providers/github/github.d.ts +5 -0
  121. package/dist/plus/integrations/providers/github/github.d.ts.map +1 -0
  122. package/dist/plus/integrations/providers/github/github.js +47 -0
  123. package/dist/plus/integrations/providers/github/github.js.map +1 -0
  124. package/dist/plus/integrations/providers/github/github.utils.d.ts +11 -0
  125. package/dist/plus/integrations/providers/github/github.utils.d.ts.map +1 -0
  126. package/dist/plus/integrations/providers/github/github.utils.js +6 -0
  127. package/dist/plus/integrations/providers/github/github.utils.js.map +1 -0
  128. package/dist/plus/integrations/providers/github/models.d.ts +3 -0
  129. package/dist/plus/integrations/providers/github/models.d.ts.map +1 -0
  130. package/dist/plus/integrations/providers/github/models.js +2 -0
  131. package/dist/plus/integrations/providers/github/models.js.map +1 -0
  132. package/dist/plus/integrations/providers/github.d.ts +73 -0
  133. package/dist/plus/integrations/providers/github.d.ts.map +1 -0
  134. package/dist/plus/integrations/providers/github.js +160 -0
  135. package/dist/plus/integrations/providers/github.js.map +1 -0
  136. package/dist/plus/integrations/providers/gitlab/gitlab.d.ts +63 -0
  137. package/dist/plus/integrations/providers/gitlab/gitlab.d.ts.map +1 -0
  138. package/dist/plus/integrations/providers/gitlab/gitlab.js +828 -0
  139. package/dist/plus/integrations/providers/gitlab/gitlab.js.map +1 -0
  140. package/dist/plus/integrations/providers/gitlab/gitlab.utils.d.ts +21 -0
  141. package/dist/plus/integrations/providers/gitlab/gitlab.utils.d.ts.map +1 -0
  142. package/dist/plus/integrations/providers/gitlab/gitlab.utils.js +45 -0
  143. package/dist/plus/integrations/providers/gitlab/gitlab.utils.js.map +1 -0
  144. package/dist/plus/integrations/providers/gitlab/models.d.ts +128 -0
  145. package/dist/plus/integrations/providers/gitlab/models.d.ts.map +1 -0
  146. package/dist/plus/integrations/providers/gitlab/models.js +96 -0
  147. package/dist/plus/integrations/providers/gitlab/models.js.map +1 -0
  148. package/dist/plus/integrations/providers/gitlab.d.ts +79 -0
  149. package/dist/plus/integrations/providers/gitlab.d.ts.map +1 -0
  150. package/dist/plus/integrations/providers/gitlab.js +253 -0
  151. package/dist/plus/integrations/providers/gitlab.js.map +1 -0
  152. package/dist/plus/integrations/providers/jira.d.ts +46 -0
  153. package/dist/plus/integrations/providers/jira.d.ts.map +1 -0
  154. package/dist/plus/integrations/providers/jira.js +255 -0
  155. package/dist/plus/integrations/providers/jira.js.map +1 -0
  156. package/dist/plus/integrations/providers/linear.d.ts +47 -0
  157. package/dist/plus/integrations/providers/linear.d.ts.map +1 -0
  158. package/dist/plus/integrations/providers/linear.js +198 -0
  159. package/dist/plus/integrations/providers/linear.js.map +1 -0
  160. package/dist/plus/integrations/providers/models.d.ts +433 -0
  161. package/dist/plus/integrations/providers/models.d.ts.map +1 -0
  162. package/dist/plus/integrations/providers/models.js +602 -0
  163. package/dist/plus/integrations/providers/models.js.map +1 -0
  164. package/dist/plus/integrations/providers/providersApi.d.ts +129 -0
  165. package/dist/plus/integrations/providers/providersApi.d.ts.map +1 -0
  166. package/dist/plus/integrations/providers/providersApi.js +602 -0
  167. package/dist/plus/integrations/providers/providersApi.js.map +1 -0
  168. package/dist/plus/integrations/providers/utils.d.ts +54 -0
  169. package/dist/plus/integrations/providers/utils.d.ts.map +1 -0
  170. package/dist/plus/integrations/providers/utils.js +262 -0
  171. package/dist/plus/integrations/providers/utils.js.map +1 -0
  172. package/dist/plus/integrations/telemetry.d.ts +26 -0
  173. package/dist/plus/integrations/telemetry.d.ts.map +1 -0
  174. package/dist/plus/integrations/telemetry.js +11 -0
  175. package/dist/plus/integrations/telemetry.js.map +1 -0
  176. package/dist/plus/integrations/utils/integration.utils.d.ts +14 -0
  177. package/dist/plus/integrations/utils/integration.utils.d.ts.map +1 -0
  178. package/dist/plus/integrations/utils/integration.utils.js +111 -0
  179. package/dist/plus/integrations/utils/integration.utils.js.map +1 -0
  180. package/dist/utils/disposable.d.ts +15 -2
  181. package/dist/utils/disposable.d.ts.map +1 -1
  182. package/dist/utils/disposable.js.map +1 -1
  183. package/package.json +43 -2
  184. package/src/git/context.ts +4 -3
  185. package/src/git/providers/operations.ts +1 -1
  186. package/src/git/providers/worktrees.ts +14 -2
  187. package/src/git/utils/conflictResolution.utils.ts +126 -0
  188. package/src/git-cli/providers/operations.ts +22 -2
  189. package/src/git-cli/providers/worktrees.ts +17 -2
  190. package/src/plus/ai/utils/ai.utils.ts +5 -5
  191. package/src/plus/git-github/api/github.ts +13 -25
  192. package/src/plus/integrations/authentication/cloudIntegrationService.ts +120 -0
  193. package/src/plus/integrations/authentication/configuredIntegrationService.ts +414 -0
  194. package/src/plus/integrations/authentication/integrationAuthenticationProvider.ts +289 -0
  195. package/src/plus/integrations/authentication/integrationAuthenticationService.ts +144 -0
  196. package/src/plus/integrations/authentication/manualTokenProvider.ts +72 -0
  197. package/src/plus/integrations/authentication/models.ts +168 -0
  198. package/src/plus/integrations/constants.ts +169 -0
  199. package/src/plus/integrations/context.ts +383 -0
  200. package/src/plus/integrations/errors.ts +35 -0
  201. package/src/plus/integrations/index.ts +119 -0
  202. package/src/plus/integrations/integrationService.ts +924 -0
  203. package/src/plus/integrations/models/gitHostIntegration.ts +738 -0
  204. package/src/plus/integrations/models/integration.ts +657 -0
  205. package/src/plus/integrations/models/issuesIntegration.ts +124 -0
  206. package/src/plus/integrations/providers/apiClients.ts +72 -0
  207. package/src/plus/integrations/providers/azure/azure.ts +691 -0
  208. package/src/plus/integrations/providers/azure/models.ts +605 -0
  209. package/src/plus/integrations/providers/azureDevOps.ts +677 -0
  210. package/src/plus/integrations/providers/bitbucket/bitbucket.ts +774 -0
  211. package/src/plus/integrations/providers/bitbucket/models.ts +445 -0
  212. package/src/plus/integrations/providers/bitbucket-server/models.ts +252 -0
  213. package/src/plus/integrations/providers/bitbucket-server.ts +282 -0
  214. package/src/plus/integrations/providers/bitbucket.ts +350 -0
  215. package/src/plus/integrations/providers/github/github.ts +64 -0
  216. package/src/plus/integrations/providers/github/github.utils.ts +23 -0
  217. package/src/plus/integrations/providers/github/models.ts +29 -0
  218. package/src/plus/integrations/providers/github.ts +366 -0
  219. package/src/plus/integrations/providers/gitlab/gitlab.ts +1210 -0
  220. package/src/plus/integrations/providers/gitlab/gitlab.utils.ts +71 -0
  221. package/src/plus/integrations/providers/gitlab/models.ts +257 -0
  222. package/src/plus/integrations/providers/gitlab.ts +473 -0
  223. package/src/plus/integrations/providers/jira.ts +359 -0
  224. package/src/plus/integrations/providers/linear.ts +275 -0
  225. package/src/plus/integrations/providers/models.ts +1114 -0
  226. package/src/plus/integrations/providers/providersApi.ts +1126 -0
  227. package/src/plus/integrations/providers/utils.ts +359 -0
  228. package/src/plus/integrations/telemetry.ts +29 -0
  229. package/src/plus/integrations/utils/integration.utils.ts +138 -0
  230. package/src/utils/disposable.ts +15 -2
@@ -0,0 +1,282 @@
1
+ import type { Account, UnidentifiedAuthor } from '../../../git/models/author.js';
2
+ import type { DefaultBranch } from '../../../git/models/defaultBranch.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, PullRequestMergeMethod, PullRequestState } from '../../../git/models/pullRequest.js';
6
+ import type { RepositoryMetadata } from '../../../git/models/repositoryMetadata.js';
7
+ import { md5 } from '../../../utils/crypto.js';
8
+ import type { Emitter } from '../../../utils/event.js';
9
+ import type { IntegrationAuthenticationProviderDescriptor } from '../authentication/integrationAuthenticationProvider.js';
10
+ import type { IntegrationAuthenticationService } from '../authentication/integrationAuthenticationService.js';
11
+ import type { IntegrationServiceContext } from '../context.js';
12
+ import type {
13
+ AuthenticationSessionLike as AuthenticationSession,
14
+ ProviderAuthenticationSession,
15
+ } from '../authentication/models.js';
16
+ import { toTokenWithInfo } from '../authentication/models.js';
17
+ import { GitSelfManagedHostIntegrationId } from '../constants.js';
18
+ import type { IntegrationConnectionChangeEvent } from '../integrationService.js';
19
+ import { GitHostIntegration } from '../models/gitHostIntegration.js';
20
+ import type { IntegrationKey } from '../models/integration.js';
21
+ import type { BitbucketRepositoryDescriptor } from './bitbucket/models.js';
22
+ import type { ProviderRepository } from './models.js';
23
+ import { fromProviderPullRequest, providersMetadata } from './models.js';
24
+ import type { ProvidersApi } from './providersApi.js';
25
+
26
+ const metadata = providersMetadata[GitSelfManagedHostIntegrationId.BitbucketServer];
27
+ const authProvider = Object.freeze({ id: metadata.id, scopes: metadata.scopes });
28
+
29
+ export class BitbucketServerIntegration extends GitHostIntegration<
30
+ GitSelfManagedHostIntegrationId.BitbucketServer,
31
+ BitbucketRepositoryDescriptor
32
+ > {
33
+ readonly authProvider: IntegrationAuthenticationProviderDescriptor = authProvider;
34
+ readonly id = GitSelfManagedHostIntegrationId.BitbucketServer;
35
+ protected readonly key =
36
+ `${this.id}:${this.domain}` satisfies IntegrationKey<GitSelfManagedHostIntegrationId.BitbucketServer>;
37
+ readonly name: string = 'Bitbucket Data Center';
38
+
39
+ constructor(
40
+ ctx: IntegrationServiceContext,
41
+ authenticationService: IntegrationAuthenticationService,
42
+ getProvidersApi: () => Promise<ProvidersApi>,
43
+ didChangeConnection: Emitter<IntegrationConnectionChangeEvent>,
44
+ private readonly _domain: string,
45
+ ) {
46
+ super(ctx, authenticationService, getProvidersApi, didChangeConnection);
47
+ }
48
+
49
+ get domain(): string {
50
+ return this._domain;
51
+ }
52
+
53
+ protected get apiBaseUrl(): string {
54
+ const protocol = this._session?.protocol ?? 'https:';
55
+ return `${protocol}//${this.domain}/rest/api/1.0`;
56
+ }
57
+
58
+ protected override async mergeProviderPullRequest(
59
+ session: ProviderAuthenticationSession,
60
+ pr: PullRequest,
61
+ options?: {
62
+ mergeMethod?: PullRequestMergeMethod;
63
+ },
64
+ ): Promise<boolean> {
65
+ const api = await this.getProvidersApi();
66
+ return api.mergePullRequest(toTokenWithInfo(this.id, session), pr, {
67
+ mergeMethod: options?.mergeMethod,
68
+ baseUrl: this.apiBaseUrl,
69
+ });
70
+ }
71
+
72
+ protected override async getProviderAccountForCommit(
73
+ session: ProviderAuthenticationSession,
74
+ repo: BitbucketRepositoryDescriptor,
75
+ rev: string,
76
+ options?: {
77
+ avatarSize?: number;
78
+ },
79
+ ): Promise<Account | UnidentifiedAuthor | undefined> {
80
+ return (await this.authenticationService.apis.bitbucket)?.getServerAccountForCommit(
81
+ this,
82
+ toTokenWithInfo(this.id, session),
83
+ repo.owner,
84
+ repo.name,
85
+ rev,
86
+ this.apiBaseUrl,
87
+ {
88
+ avatarSize: options?.avatarSize,
89
+ },
90
+ );
91
+ }
92
+
93
+ protected override async getProviderAccountForEmail(
94
+ _session: AuthenticationSession,
95
+ _repo: BitbucketRepositoryDescriptor,
96
+ _email: string,
97
+ _options?: {
98
+ avatarSize?: number;
99
+ },
100
+ ): Promise<Account | undefined> {
101
+ return Promise.resolve(undefined);
102
+ }
103
+
104
+ protected override async getProviderDefaultBranch(
105
+ _session: AuthenticationSession,
106
+ _repo: BitbucketRepositoryDescriptor,
107
+ ): Promise<DefaultBranch | undefined> {
108
+ return Promise.resolve(undefined);
109
+ }
110
+
111
+ protected override async getProviderLinkedIssueOrPullRequest(
112
+ session: ProviderAuthenticationSession,
113
+ repo: BitbucketRepositoryDescriptor,
114
+ { id }: { id: string; key: string },
115
+ type: undefined | IssueOrPullRequestType,
116
+ ): Promise<IssueOrPullRequest | undefined> {
117
+ if (type === 'issue') {
118
+ return undefined;
119
+ }
120
+ return (await this.authenticationService.apis.bitbucket)?.getServerPullRequestById(
121
+ this,
122
+ toTokenWithInfo(this.id, session),
123
+ repo.owner,
124
+ repo.name,
125
+ id,
126
+ this.apiBaseUrl,
127
+ );
128
+ }
129
+
130
+ protected override async getProviderIssue(
131
+ _session: AuthenticationSession,
132
+ _repo: BitbucketRepositoryDescriptor,
133
+ _id: string,
134
+ ): Promise<Issue | undefined> {
135
+ return Promise.resolve(undefined);
136
+ }
137
+
138
+ protected override async getProviderPullRequestForBranch(
139
+ session: ProviderAuthenticationSession,
140
+ repo: BitbucketRepositoryDescriptor,
141
+ branch: string,
142
+ _options?: {
143
+ avatarSize?: number;
144
+ include?: PullRequestState[];
145
+ },
146
+ ): Promise<PullRequest | undefined> {
147
+ return (await this.authenticationService.apis.bitbucket)?.getServerPullRequestForBranch(
148
+ this,
149
+ toTokenWithInfo(this.id, session),
150
+ repo.owner,
151
+ repo.name,
152
+ branch,
153
+ this.apiBaseUrl,
154
+ );
155
+ }
156
+
157
+ protected override async getProviderPullRequestForCommit(
158
+ session: ProviderAuthenticationSession,
159
+ repo: BitbucketRepositoryDescriptor,
160
+ rev: string,
161
+ ): Promise<PullRequest | undefined> {
162
+ return (await this.authenticationService.apis.bitbucket)?.getServerPullRequestForCommit(
163
+ this,
164
+ toTokenWithInfo(this.id, session),
165
+ repo.owner,
166
+ repo.name,
167
+ rev,
168
+ this.apiBaseUrl,
169
+ );
170
+ }
171
+
172
+ public override async getRepoInfo(repo: { owner: string; name: string }): Promise<ProviderRepository | undefined> {
173
+ const api = await this.getProvidersApi();
174
+ const tokenOptInfo = this._session ? toTokenWithInfo(this.id, this._session) : { providerId: this.id };
175
+ return api.getRepo(tokenOptInfo, repo.owner, repo.name, undefined, {
176
+ baseUrl: this.apiBaseUrl,
177
+ });
178
+ }
179
+
180
+ protected override async getProviderRepositoryMetadata(
181
+ _session: AuthenticationSession,
182
+ _repo: BitbucketRepositoryDescriptor,
183
+ _cancellation?: AbortSignal,
184
+ ): Promise<RepositoryMetadata | undefined> {
185
+ return Promise.resolve(undefined);
186
+ }
187
+
188
+ private _accounts: Map<string, Account | undefined> | undefined;
189
+ protected override async getProviderCurrentAccount(
190
+ session: ProviderAuthenticationSession,
191
+ ): Promise<Account | undefined> {
192
+ const { accessToken } = session;
193
+ this._accounts ??= new Map<string, Account | undefined>();
194
+
195
+ const cachedAccount = this._accounts.get(accessToken);
196
+ if (cachedAccount == null) {
197
+ const api = await this.getProvidersApi();
198
+ const user = await api.getCurrentUser(toTokenWithInfo(this.id, session), {
199
+ baseUrl: this.apiBaseUrl,
200
+ });
201
+ this._accounts.set(
202
+ accessToken,
203
+ user
204
+ ? {
205
+ provider: this,
206
+ id: user.id,
207
+ name: user.name ?? undefined,
208
+ email: user.email ?? undefined,
209
+ avatarUrl: user.avatarUrl ?? undefined,
210
+ username: user.username ?? undefined,
211
+ }
212
+ : undefined,
213
+ );
214
+ }
215
+
216
+ return this._accounts.get(accessToken);
217
+ }
218
+
219
+ protected override async searchProviderMyPullRequests(
220
+ session: ProviderAuthenticationSession,
221
+ repos?: BitbucketRepositoryDescriptor[],
222
+ ): Promise<PullRequest[] | undefined> {
223
+ if (repos != null) {
224
+ // TODO: implement repos version
225
+ return undefined;
226
+ }
227
+
228
+ const api = await this.getProvidersApi();
229
+ if (!api) {
230
+ return undefined;
231
+ }
232
+
233
+ const prs = await api.getBitbucketServerPullRequestsForCurrentUser(
234
+ toTokenWithInfo(this.id, session),
235
+ this.apiBaseUrl,
236
+ );
237
+ return prs?.map(pr => fromProviderPullRequest(pr, this));
238
+ }
239
+
240
+ protected override async searchProviderMyIssues(
241
+ _session: AuthenticationSession,
242
+ _repos?: BitbucketRepositoryDescriptor[],
243
+ ): Promise<IssueShape[] | undefined> {
244
+ return Promise.resolve(undefined);
245
+ }
246
+
247
+ private readonly storagePrefix = 'bitbucket-server';
248
+ protected override async providerOnConnect(): Promise<void> {
249
+ if (this._session == null) return;
250
+
251
+ const accountStorageKey = md5(this._session.accessToken);
252
+
253
+ const storedAccount = this.ctx.storage.get(`${this.storagePrefix}:${accountStorageKey}:account`);
254
+
255
+ let account: Account | undefined = storedAccount?.data ? { ...storedAccount.data, provider: this } : undefined;
256
+
257
+ if (storedAccount == null) {
258
+ account = await this.getProviderCurrentAccount(this._session);
259
+ if (account != null) {
260
+ // Clear all other stored workspaces and repositories and accounts when our session changes
261
+ await this.ctx.storage.deleteWithPrefix(this.storagePrefix);
262
+ await this.ctx.storage.store(`${this.storagePrefix}:${accountStorageKey}:account`, {
263
+ v: 1,
264
+ timestamp: Date.now(),
265
+ data: {
266
+ id: account.id,
267
+ name: account.name,
268
+ email: account.email,
269
+ avatarUrl: account.avatarUrl,
270
+ username: account.username,
271
+ },
272
+ });
273
+ }
274
+ }
275
+ this._accounts ??= new Map<string, Account | undefined>();
276
+ this._accounts.set(this._session.accessToken, account);
277
+ }
278
+
279
+ protected override providerOnDisconnect(): void {
280
+ this._accounts = undefined;
281
+ }
282
+ }
@@ -0,0 +1,350 @@
1
+ import type { Account, UnidentifiedAuthor } from '../../../git/models/author.js';
2
+ import type { DefaultBranch } from '../../../git/models/defaultBranch.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, PullRequestMergeMethod, PullRequestState } from '../../../git/models/pullRequest.js';
6
+ import type { GitRemote } from '../../../git/models/remote.js';
7
+ import type { RepositoryMetadata } from '../../../git/models/repositoryMetadata.js';
8
+ import { md5 } from '../../../utils/crypto.js';
9
+ import { uniqueBy } from '../../../utils/iterable.js';
10
+ import { flatSettled, nonnullSettled } from '../../../utils/promise.js';
11
+ import type { IntegrationAuthenticationProviderDescriptor } from '../authentication/integrationAuthenticationProvider.js';
12
+ import type {
13
+ AuthenticationSessionLike as AuthenticationSession,
14
+ ProviderAuthenticationSession,
15
+ } from '../authentication/models.js';
16
+ import { toTokenWithInfo } from '../authentication/models.js';
17
+ import { GitCloudHostIntegrationId } from '../constants.js';
18
+ import { GitHostIntegration } from '../models/gitHostIntegration.js';
19
+ import type { BitbucketRepositoryDescriptor, BitbucketWorkspaceDescriptor } from './bitbucket/models.js';
20
+ import { fromProviderPullRequest, providersMetadata } from './models.js';
21
+
22
+ const metadata = providersMetadata[GitCloudHostIntegrationId.Bitbucket];
23
+ const authProvider = Object.freeze({ id: metadata.id, scopes: metadata.scopes });
24
+
25
+ export class BitbucketIntegration extends GitHostIntegration<
26
+ GitCloudHostIntegrationId.Bitbucket,
27
+ BitbucketRepositoryDescriptor
28
+ > {
29
+ readonly authProvider: IntegrationAuthenticationProviderDescriptor = authProvider;
30
+ readonly id = GitCloudHostIntegrationId.Bitbucket;
31
+ protected readonly key = this.id;
32
+ readonly name: string = 'Bitbucket';
33
+ get domain(): string {
34
+ return metadata.domain;
35
+ }
36
+
37
+ protected get apiBaseUrl(): string {
38
+ return 'https://api.bitbucket.org/2.0';
39
+ }
40
+
41
+ protected override async mergeProviderPullRequest(
42
+ session: ProviderAuthenticationSession,
43
+ pr: PullRequest,
44
+ options?: {
45
+ mergeMethod?: PullRequestMergeMethod;
46
+ },
47
+ ): Promise<boolean> {
48
+ const api = await this.getProvidersApi();
49
+ return api.mergePullRequest(toTokenWithInfo(this.id, session), pr, {
50
+ mergeMethod: options?.mergeMethod,
51
+ });
52
+ }
53
+
54
+ protected override async getProviderAccountForCommit(
55
+ session: ProviderAuthenticationSession,
56
+ repo: BitbucketRepositoryDescriptor,
57
+ rev: string,
58
+ options?: {
59
+ avatarSize?: number;
60
+ },
61
+ ): Promise<Account | UnidentifiedAuthor | undefined> {
62
+ return (await this.authenticationService.apis.bitbucket)?.getAccountForCommit(
63
+ this,
64
+ toTokenWithInfo(this.id, session),
65
+ repo.owner,
66
+ repo.name,
67
+ rev,
68
+ this.apiBaseUrl,
69
+ {
70
+ avatarSize: options?.avatarSize,
71
+ },
72
+ );
73
+ }
74
+
75
+ protected override async getProviderAccountForEmail(
76
+ _session: AuthenticationSession,
77
+ _repo: BitbucketRepositoryDescriptor,
78
+ _email: string,
79
+ _options?: {
80
+ avatarSize?: number;
81
+ },
82
+ ): Promise<Account | undefined> {
83
+ return Promise.resolve(undefined);
84
+ }
85
+
86
+ protected override async getProviderDefaultBranch(
87
+ _session: AuthenticationSession,
88
+ _repo: BitbucketRepositoryDescriptor,
89
+ ): Promise<DefaultBranch | undefined> {
90
+ return Promise.resolve(undefined);
91
+ }
92
+
93
+ protected override async getProviderLinkedIssueOrPullRequest(
94
+ session: ProviderAuthenticationSession,
95
+ repo: BitbucketRepositoryDescriptor,
96
+ { id }: { id: string; key: string },
97
+ type: undefined | IssueOrPullRequestType,
98
+ ): Promise<IssueOrPullRequest | undefined> {
99
+ return (await this.authenticationService.apis.bitbucket)?.getIssueOrPullRequest(
100
+ this,
101
+ toTokenWithInfo(this.id, session),
102
+ repo.owner,
103
+ repo.name,
104
+ id,
105
+ this.apiBaseUrl,
106
+ {
107
+ type: type,
108
+ },
109
+ );
110
+ }
111
+
112
+ protected override async getProviderIssue(
113
+ session: ProviderAuthenticationSession,
114
+ repo: BitbucketRepositoryDescriptor,
115
+ id: string,
116
+ ): Promise<Issue | undefined> {
117
+ return (await this.authenticationService.apis.bitbucket)?.getIssue(
118
+ this,
119
+ toTokenWithInfo(this.id, session),
120
+ repo.owner,
121
+ repo.name,
122
+ id,
123
+ this.apiBaseUrl,
124
+ );
125
+ }
126
+
127
+ protected override async getProviderPullRequestForBranch(
128
+ session: ProviderAuthenticationSession,
129
+ repo: BitbucketRepositoryDescriptor,
130
+ branch: string,
131
+ _options?: {
132
+ avatarSize?: number;
133
+ include?: PullRequestState[];
134
+ },
135
+ ): Promise<PullRequest | undefined> {
136
+ return (await this.authenticationService.apis.bitbucket)?.getPullRequestForBranch(
137
+ this,
138
+ toTokenWithInfo(this.id, session),
139
+ repo.owner,
140
+ repo.name,
141
+ branch,
142
+ this.apiBaseUrl,
143
+ );
144
+ }
145
+
146
+ protected override async getProviderPullRequestForCommit(
147
+ session: ProviderAuthenticationSession,
148
+ repo: BitbucketRepositoryDescriptor,
149
+ rev: string,
150
+ ): Promise<PullRequest | undefined> {
151
+ return (await this.authenticationService.apis.bitbucket)?.getPullRequestForCommit(
152
+ this,
153
+ toTokenWithInfo(this.id, session),
154
+ repo.owner,
155
+ repo.name,
156
+ rev,
157
+ this.apiBaseUrl,
158
+ );
159
+ }
160
+
161
+ protected override async getProviderRepositoryMetadata(
162
+ _session: AuthenticationSession,
163
+ _repo: BitbucketRepositoryDescriptor,
164
+ _cancellation?: AbortSignal,
165
+ ): Promise<RepositoryMetadata | undefined> {
166
+ return Promise.resolve(undefined);
167
+ }
168
+
169
+ private _accounts: Map<string, Account | undefined> | undefined;
170
+ protected override async getProviderCurrentAccount(
171
+ session: ProviderAuthenticationSession,
172
+ ): Promise<Account | undefined> {
173
+ const { accessToken } = session;
174
+ this._accounts ??= new Map<string, Account | undefined>();
175
+
176
+ const cachedAccount = this._accounts.get(accessToken);
177
+ if (cachedAccount == null) {
178
+ const api = await this.getProvidersApi();
179
+ const user = await api.getCurrentUser(toTokenWithInfo(this.id, session));
180
+ this._accounts.set(
181
+ accessToken,
182
+ user
183
+ ? {
184
+ provider: this,
185
+ id: user.id,
186
+ name: user.name ?? undefined,
187
+ email: user.email ?? undefined,
188
+ avatarUrl: user.avatarUrl ?? undefined,
189
+ username: user.username ?? undefined,
190
+ }
191
+ : undefined,
192
+ );
193
+ }
194
+
195
+ return this._accounts.get(accessToken);
196
+ }
197
+
198
+ private _workspaces: Map<string, BitbucketWorkspaceDescriptor[] | undefined> | undefined;
199
+ private async getProviderResourcesForCurrentUser(
200
+ session: ProviderAuthenticationSession,
201
+ force: boolean = false,
202
+ ): Promise<BitbucketWorkspaceDescriptor[] | undefined> {
203
+ this._workspaces ??= new Map<string, BitbucketWorkspaceDescriptor[] | undefined>();
204
+ const { accessToken } = session;
205
+ const cachedResources = this._workspaces.get(accessToken);
206
+
207
+ if (cachedResources == null || force) {
208
+ const api = await this.getProvidersApi();
209
+
210
+ const resources = await api.getBitbucketResourcesForCurrentUser(toTokenWithInfo(this.id, session));
211
+ this._workspaces.set(
212
+ accessToken,
213
+ resources != null ? resources.map(r => ({ ...r, key: r.id, name: r.name ?? r.slug })) : undefined,
214
+ );
215
+ }
216
+
217
+ return this._workspaces.get(accessToken);
218
+ }
219
+
220
+ protected override async searchProviderMyPullRequests(
221
+ session: ProviderAuthenticationSession,
222
+ repos?: BitbucketRepositoryDescriptor[],
223
+ ): Promise<PullRequest[] | undefined> {
224
+ if (repos != null) {
225
+ // TODO: implement repos version
226
+ return undefined;
227
+ }
228
+
229
+ const api = await this.getProvidersApi();
230
+ if (!api) {
231
+ return undefined;
232
+ }
233
+
234
+ const remotes = await this.ctx.repositories.getOpenRemotes();
235
+ const workspaceRepos = await nonnullSettled(
236
+ remotes.map(async (r: GitRemote) => {
237
+ const integration = await this.authenticationService.getByRemote(r);
238
+ const [namespace, name] = r.path.split('/');
239
+ return integration?.id === this.id ? { name: name, namespace: namespace } : undefined;
240
+ }),
241
+ );
242
+
243
+ const user = await this.getProviderCurrentAccount(session);
244
+ if (user?.username == null) return undefined;
245
+
246
+ const workspaces = await this.getProviderResourcesForCurrentUser(session);
247
+ if (workspaces == null || workspaces.length === 0) return undefined;
248
+
249
+ const authoredPrs = workspaces.map(async ws => {
250
+ const prs = await api.getBitbucketPullRequestsAuthoredByUserForWorkspace(
251
+ toTokenWithInfo(this.id, session),
252
+ user.id,
253
+ ws.slug,
254
+ );
255
+ return prs?.map(pr => fromProviderPullRequest(pr, this));
256
+ });
257
+
258
+ const reviewingPrs = api
259
+ .getPullRequestsForRepos(toTokenWithInfo(this.id, session), workspaceRepos, {
260
+ query: `state="OPEN" AND reviewers.uuid="${user.id}"`,
261
+ })
262
+ .then(r => r.values?.map(pr => fromProviderPullRequest(pr, this)));
263
+
264
+ return [
265
+ ...uniqueBy(
266
+ await flatSettled([...authoredPrs, reviewingPrs]),
267
+ pr => pr.url,
268
+ (orig, _cur) => orig,
269
+ ),
270
+ ];
271
+ }
272
+
273
+ protected override async searchProviderMyIssues(
274
+ session: ProviderAuthenticationSession,
275
+ repos?: BitbucketRepositoryDescriptor[],
276
+ ): Promise<IssueShape[] | undefined> {
277
+ if (repos == null || repos.length === 0) return undefined;
278
+
279
+ const user = await this.getProviderCurrentAccount(session);
280
+ if (user?.username == null) return undefined;
281
+
282
+ const api = await this.authenticationService.apis.bitbucket;
283
+ if (!api) return undefined;
284
+
285
+ const issueResult = await flatSettled(
286
+ repos.map(repo => {
287
+ return api.getUsersIssuesForRepo(
288
+ this,
289
+ toTokenWithInfo(this.id, session),
290
+ user.id,
291
+ repo.owner,
292
+ repo.name,
293
+ this.apiBaseUrl,
294
+ );
295
+ }),
296
+ );
297
+ return issueResult;
298
+ }
299
+
300
+ private readonly storagePrefix = 'bitbucket';
301
+ protected override async providerOnConnect(): Promise<void> {
302
+ if (this._session == null) return;
303
+
304
+ const accountStorageKey = md5(this._session.accessToken);
305
+
306
+ const storedAccount = this.ctx.storage.get(`${this.storagePrefix}:${accountStorageKey}:account`);
307
+ const storedWorkspaces = this.ctx.storage.get(`${this.storagePrefix}:${accountStorageKey}:workspaces`);
308
+
309
+ let account: Account | undefined = storedAccount?.data ? { ...storedAccount.data, provider: this } : undefined;
310
+
311
+ let workspaces = storedWorkspaces?.data?.map((o: BitbucketWorkspaceDescriptor) => ({ ...o }));
312
+
313
+ if (storedAccount == null) {
314
+ account = await this.getProviderCurrentAccount(this._session);
315
+ if (account != null) {
316
+ // Clear all other stored workspaces and repositories and accounts when our session changes
317
+ await this.ctx.storage.deleteWithPrefix(this.storagePrefix);
318
+ await this.ctx.storage.store(`${this.storagePrefix}:${accountStorageKey}:account`, {
319
+ v: 1,
320
+ timestamp: Date.now(),
321
+ data: {
322
+ id: account.id,
323
+ name: account.name,
324
+ email: account.email,
325
+ avatarUrl: account.avatarUrl,
326
+ username: account.username,
327
+ },
328
+ });
329
+ }
330
+ }
331
+ this._accounts ??= new Map<string, Account | undefined>();
332
+ this._accounts.set(this._session.accessToken, account);
333
+
334
+ if (storedWorkspaces == null) {
335
+ workspaces = await this.getProviderResourcesForCurrentUser(this._session, true);
336
+ await this.ctx.storage.store(`${this.storagePrefix}:${accountStorageKey}:workspaces`, {
337
+ v: 1,
338
+ timestamp: Date.now(),
339
+ data: workspaces,
340
+ });
341
+ }
342
+ this._workspaces ??= new Map<string, BitbucketWorkspaceDescriptor[] | undefined>();
343
+ this._workspaces.set(this._session.accessToken, workspaces);
344
+ }
345
+
346
+ protected override providerOnDisconnect(): void {
347
+ this._accounts = undefined;
348
+ this._workspaces = undefined;
349
+ }
350
+ }
@@ -0,0 +1,64 @@
1
+ import { AuthenticationErrorReason } from '../../../../git/errors.js';
2
+ import type { Provider } from '../../../../git/models/remoteProvider.js';
3
+ import type { GitHubApiConfig } from '../../../git-github/api/config.js';
4
+ import { GitHubApi } from '../../../git-github/api/github.js';
5
+ import type { IntegrationServiceContext } from '../../context.js';
6
+
7
+ export { GitHubApi } from '../../../git-github/api/github.js';
8
+
9
+ export function createGitHubApi(ctx: IntegrationServiceContext): GitHubApi {
10
+ const launchpad = () => ctx.config.getLaunchpadOptions();
11
+
12
+ const config: GitHubApiConfig = {
13
+ isWeb: ctx.http.isWeb,
14
+ fetch: ctx.http.fetch.bind(ctx.http),
15
+ wrapForForcedInsecureSSL: ctx.http.wrapForForcedInsecureSSL.bind(ctx.http),
16
+
17
+ onConfigChanged: (listener: () => void) =>
18
+ ctx.config.onDidChange(e => {
19
+ if (e.httpProxy) {
20
+ listener();
21
+ }
22
+ }),
23
+
24
+ onAuthenticationFailure: async (error, provider: Provider | undefined) => {
25
+ if (
26
+ error.reason === AuthenticationErrorReason.Unauthorized ||
27
+ error.reason === AuthenticationErrorReason.Forbidden
28
+ ) {
29
+ const reauthenticate = await ctx.hooks?.onReauthenticationRequired?.(
30
+ `${error.message}. Would you like to try reauthenticating${
31
+ error.reason === AuthenticationErrorReason.Forbidden ? ' to provide additional access' : ''
32
+ }?`,
33
+ );
34
+
35
+ if (reauthenticate) {
36
+ await provider?.reauthenticate();
37
+ return true;
38
+ }
39
+ } else {
40
+ ctx.hooks?.ui?.onError?.(error.message);
41
+ }
42
+ return false;
43
+ },
44
+
45
+ onRequestError: (provider: Provider | undefined, message: string) => {
46
+ if (message.includes('timeout')) {
47
+ ctx.hooks?.ui?.onRequestTimedOut?.(provider?.name ?? 'GitHub');
48
+ } else {
49
+ ctx.hooks?.ui?.onRequestFailed?.(message);
50
+ }
51
+ },
52
+
53
+ onDebugError: (message: string) => {
54
+ ctx.hooks?.ui?.onError?.(message);
55
+ },
56
+
57
+ getLaunchpadQueryLimit: () => launchpad().queryLimit ?? 100,
58
+ getLaunchpadIgnoredRepositories: () => [...(launchpad().ignoredRepositories ?? [])],
59
+ getLaunchpadIncludedOrganizations: () => [...(launchpad().includedOrganizations ?? [])],
60
+ getLaunchpadIgnoredOrganizations: () => [...(launchpad().ignoredOrganizations ?? [])],
61
+ };
62
+
63
+ return new GitHubApi(config);
64
+ }