@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,774 @@
1
+ import type { Account, CommitAuthor, UnidentifiedAuthor } from '../../../../git/models/author.js';
2
+ import type { Issue } from '../../../../git/models/issue.js';
3
+ import type { IssueOrPullRequest, IssueOrPullRequestType } from '../../../../git/models/issueOrPullRequest.js';
4
+ import type { PullRequest } from '../../../../git/models/pullRequest.js';
5
+ import type { Provider } from '../../../../git/models/remoteProvider.js';
6
+ import type { RepositoryMetadata } from '../../../../git/models/repositoryMetadata.js';
7
+ import { CancellationError } from '../../../../utils/cancellation.js';
8
+ import { trace } from '../../../../utils/decorators/log.js';
9
+ import type { Disposable } from '../../../../utils/disposable.js';
10
+ import { Logger } from '../../../../utils/logger.js';
11
+ import type { ScopedLogger } from '../../../../utils/logger.scoped.js';
12
+ import { getScopedLogger } from '../../../../utils/logger.scoped.js';
13
+ import { maybeStopWatch } from '../../../../utils/stopwatch.js';
14
+ import type { TokenInfo, TokenWithInfo } from '../../authentication/models.js';
15
+ import type { IntegrationServiceContext } from '../../context.js';
16
+ import {
17
+ AuthenticationError,
18
+ AuthenticationErrorReason,
19
+ ProviderFetchError,
20
+ RequestClientError,
21
+ RequestNotFoundError,
22
+ } from '../../errors.js';
23
+ import type { BitbucketServerCommit, BitbucketServerPullRequest } from '../bitbucket-server/models.js';
24
+ import { normalizeBitbucketServerPullRequest } from '../bitbucket-server/models.js';
25
+ import { fromProviderPullRequest } from '../models.js';
26
+ import type { BitbucketCommit, BitbucketIssue, BitbucketPullRequest, BitbucketRepository } from './models.js';
27
+ import {
28
+ bitbucketIssueStateToState,
29
+ fromBitbucketIssue,
30
+ fromBitbucketPullRequest,
31
+ parseRawBitbucketAuthor,
32
+ } from './models.js';
33
+
34
+ export class BitbucketApi implements Disposable {
35
+ private readonly _disposable: Disposable;
36
+
37
+ constructor(private readonly ctx: IntegrationServiceContext) {
38
+ this._disposable = ctx.config.onDidChange(e => {
39
+ if (e.httpProxy) {
40
+ this.resetCaches();
41
+ }
42
+ });
43
+ }
44
+
45
+ dispose(): void {
46
+ this._disposable.dispose();
47
+ }
48
+
49
+ private resetCaches(): void {}
50
+
51
+ @trace({
52
+ args: (provider, token, owner, repo, branch, baseUrl) => ({
53
+ provider: provider.name,
54
+ token: `<token:${token.microHash}>`,
55
+ owner: owner,
56
+ repo: repo,
57
+ branch: branch,
58
+ baseUrl: baseUrl,
59
+ }),
60
+ })
61
+ public async getPullRequestForBranch(
62
+ provider: Provider,
63
+ token: TokenWithInfo,
64
+ owner: string,
65
+ repo: string,
66
+ branch: string,
67
+ baseUrl: string,
68
+ ): Promise<PullRequest | undefined> {
69
+ const scope = getScopedLogger();
70
+
71
+ const response = await this.request<{
72
+ values: BitbucketPullRequest[];
73
+ pagelen: number;
74
+ size: number;
75
+ page: number;
76
+ }>(
77
+ provider,
78
+ token,
79
+ baseUrl,
80
+ `repositories/${owner}/${repo}/pullrequests?q=source.branch.name="${branch}"&fields=%2Bvalues.reviewers,%2Bvalues.participants`,
81
+ {
82
+ method: 'GET',
83
+ },
84
+ scope,
85
+ );
86
+
87
+ if (!response?.values?.length) {
88
+ return undefined;
89
+ }
90
+ return fromBitbucketPullRequest(response.values[0], provider);
91
+ }
92
+
93
+ @trace({
94
+ args: (provider, token, owner, repo, branch, baseUrl) => ({
95
+ provider: provider.name,
96
+ token: `<token:${token.microHash}>`,
97
+ owner: owner,
98
+ repo: repo,
99
+ branch: branch,
100
+ baseUrl: baseUrl,
101
+ }),
102
+ })
103
+ public async getServerPullRequestForBranch(
104
+ provider: Provider,
105
+ token: TokenWithInfo,
106
+ owner: string,
107
+ repo: string,
108
+ branch: string,
109
+ baseUrl: string,
110
+ ): Promise<PullRequest | undefined> {
111
+ const scope = getScopedLogger();
112
+
113
+ const response = await this.request<{
114
+ values: BitbucketServerPullRequest[];
115
+ pagelen: number;
116
+ size: number;
117
+ page: number;
118
+ }>(
119
+ provider,
120
+ token,
121
+ baseUrl,
122
+ `projects/${owner}/repos/${repo}/pull-requests?at=refs/heads/${branch}&direction=OUTGOING&state=ALL`,
123
+ {
124
+ method: 'GET',
125
+ },
126
+ scope,
127
+ );
128
+
129
+ if (!response?.values?.length) {
130
+ return undefined;
131
+ }
132
+
133
+ const providersPr = normalizeBitbucketServerPullRequest(response.values[0]);
134
+ const gitlensPr = fromProviderPullRequest(providersPr, provider);
135
+ return gitlensPr;
136
+ }
137
+
138
+ @trace({
139
+ args: (provider, token, userUuid, owner, repo, baseUrl) => ({
140
+ provider: provider.name,
141
+ token: `<token:${token.microHash}>`,
142
+ userUuid: userUuid,
143
+ owner: owner,
144
+ repo: repo,
145
+ baseUrl: baseUrl,
146
+ }),
147
+ })
148
+ async getUsersIssuesForRepo(
149
+ provider: Provider,
150
+ token: TokenWithInfo,
151
+ userUuid: string,
152
+ owner: string,
153
+ repo: string,
154
+ baseUrl: string,
155
+ ): Promise<Issue[] | undefined> {
156
+ const scope = getScopedLogger();
157
+ const query = encodeURIComponent(`assignee.uuid="${userUuid}" OR reporter.uuid="${userUuid}"`);
158
+
159
+ const response = await this.request<{
160
+ values: BitbucketIssue[];
161
+ pagelen: number;
162
+ size: number;
163
+ page: number;
164
+ }>(
165
+ provider,
166
+ token,
167
+ baseUrl,
168
+ `repositories/${owner}/${repo}/issues?q=${query}`,
169
+ {
170
+ method: 'GET',
171
+ },
172
+ scope,
173
+ );
174
+
175
+ if (!response?.values?.length) {
176
+ return undefined;
177
+ }
178
+ return response.values.map(issue => fromBitbucketIssue(issue, provider));
179
+ }
180
+
181
+ @trace({
182
+ args: (provider, token, owner, repo, id, baseUrl) => ({
183
+ provider: provider.name,
184
+ token: `<token:${token.microHash}>`,
185
+ owner: owner,
186
+ repo: repo,
187
+ id: id,
188
+ baseUrl: baseUrl,
189
+ }),
190
+ })
191
+ async getIssue(
192
+ provider: Provider,
193
+ token: TokenWithInfo,
194
+ owner: string,
195
+ repo: string,
196
+ id: string,
197
+ baseUrl: string,
198
+ ): Promise<Issue | undefined> {
199
+ const scope = getScopedLogger();
200
+
201
+ try {
202
+ const response = await this.request<BitbucketIssue>(
203
+ provider,
204
+ token,
205
+ baseUrl,
206
+ `repositories/${owner}/${repo}/issues/${id}`,
207
+ {
208
+ method: 'GET',
209
+ },
210
+ scope,
211
+ );
212
+
213
+ if (response) {
214
+ return fromBitbucketIssue(response, provider);
215
+ }
216
+ return undefined;
217
+ } catch (ex) {
218
+ scope?.error(ex);
219
+ return undefined;
220
+ }
221
+ }
222
+
223
+ @trace({
224
+ args: (provider, token, owner, repo, id, baseUrl) => ({
225
+ provider: provider.name,
226
+ token: `<token:${token.microHash}>`,
227
+ owner: owner,
228
+ repo: repo,
229
+ id: id,
230
+ baseUrl: baseUrl,
231
+ }),
232
+ })
233
+ public async getIssueOrPullRequest(
234
+ provider: Provider,
235
+ token: TokenWithInfo,
236
+ owner: string,
237
+ repo: string,
238
+ id: string,
239
+ baseUrl: string,
240
+ options?: {
241
+ type?: IssueOrPullRequestType;
242
+ },
243
+ ): Promise<IssueOrPullRequest | undefined> {
244
+ const scope = getScopedLogger();
245
+
246
+ if (options?.type === undefined || options?.type === 'pullrequest') {
247
+ try {
248
+ const prResponse = await this.request<BitbucketPullRequest>(
249
+ provider,
250
+ token,
251
+ baseUrl,
252
+ `repositories/${owner}/${repo}/pullrequests/${id}?fields=%2Bvalues.reviewers,%2Bvalues.participants`,
253
+ {
254
+ method: 'GET',
255
+ },
256
+ scope,
257
+ );
258
+
259
+ if (prResponse) {
260
+ return fromBitbucketPullRequest(prResponse, provider);
261
+ }
262
+ } catch (ex) {
263
+ if (ex.original?.status !== 404) {
264
+ scope?.error(ex);
265
+ return undefined;
266
+ }
267
+ }
268
+ }
269
+
270
+ if (options?.type === undefined || options?.type === 'issue') {
271
+ try {
272
+ const issueResponse = await this.request<BitbucketIssue>(
273
+ provider,
274
+ token,
275
+ baseUrl,
276
+ `repositories/${owner}/${repo}/issues/${id}`,
277
+ {
278
+ method: 'GET',
279
+ },
280
+ scope,
281
+ );
282
+
283
+ if (issueResponse) {
284
+ return {
285
+ id: issueResponse.id.toString(),
286
+ type: 'issue',
287
+ nodeId: issueResponse.id.toString(),
288
+ provider: provider,
289
+ createdDate: new Date(issueResponse.created_on),
290
+ updatedDate: new Date(issueResponse.updated_on),
291
+ state: bitbucketIssueStateToState(issueResponse.state),
292
+ closed: issueResponse.state === 'closed',
293
+ title: issueResponse.title,
294
+ url: issueResponse.links.html.href,
295
+ };
296
+ }
297
+ } catch (ex) {
298
+ scope?.error(ex);
299
+ return undefined;
300
+ }
301
+ }
302
+
303
+ return undefined;
304
+ }
305
+
306
+ @trace({
307
+ args: (provider, token, owner, repo, id, baseUrl) => ({
308
+ provider: provider.name,
309
+ token: `<token:${token.microHash}>`,
310
+ owner: owner,
311
+ repo: repo,
312
+ id: id,
313
+ baseUrl: baseUrl,
314
+ }),
315
+ })
316
+ public async getServerPullRequestById(
317
+ provider: Provider,
318
+ token: TokenWithInfo,
319
+ owner: string,
320
+ repo: string,
321
+ id: string,
322
+ baseUrl: string,
323
+ ): Promise<IssueOrPullRequest | undefined> {
324
+ const scope = getScopedLogger();
325
+
326
+ try {
327
+ const prResponse = await this.request<BitbucketServerPullRequest>(
328
+ provider,
329
+ token,
330
+ baseUrl,
331
+ `projects/${owner}/repos/${repo}/pull-requests/${id}`,
332
+ {
333
+ method: 'GET',
334
+ },
335
+ scope,
336
+ );
337
+
338
+ if (prResponse) {
339
+ const providersPr = normalizeBitbucketServerPullRequest(prResponse);
340
+ const gitlensPr = fromProviderPullRequest(providersPr, provider);
341
+ return gitlensPr;
342
+ }
343
+ } catch (ex) {
344
+ if (ex.original?.status !== 404) {
345
+ scope?.error(ex);
346
+ return undefined;
347
+ }
348
+ }
349
+
350
+ return undefined;
351
+ }
352
+
353
+ @trace({
354
+ args: (provider, token, workspace) => ({
355
+ provider: provider.name,
356
+ token: `<token:${token.microHash}>`,
357
+ workspace: workspace,
358
+ }),
359
+ })
360
+ async getRepositoriesForWorkspace(
361
+ provider: Provider,
362
+ token: TokenWithInfo,
363
+ workspace: string,
364
+ options: {
365
+ baseUrl: string;
366
+ },
367
+ ): Promise<RepositoryMetadata[] | undefined> {
368
+ const scope = getScopedLogger();
369
+
370
+ try {
371
+ interface BitbucketRepositoriesResponse {
372
+ size: number;
373
+ page: number;
374
+ pagelen: number;
375
+ next?: string;
376
+ previous?: string;
377
+ values: BitbucketRepository[];
378
+ }
379
+
380
+ const response = await this.request<BitbucketRepositoriesResponse>(
381
+ provider,
382
+ token,
383
+ options.baseUrl,
384
+ `repositories/${workspace}?role=contributor&fields=%2Bvalues.parent.workspace`, // field=+<field> must be encoded as field=%2B<field>
385
+ {
386
+ method: 'GET',
387
+ },
388
+ scope,
389
+ );
390
+
391
+ if (response) {
392
+ return response.values.map(repo => {
393
+ return {
394
+ provider: provider,
395
+ owner: repo.workspace.slug,
396
+ name: repo.slug,
397
+ isFork: Boolean(repo.parent),
398
+ parent: repo.parent
399
+ ? {
400
+ owner: repo.parent.workspace.slug,
401
+ name: repo.parent.slug,
402
+ }
403
+ : undefined,
404
+ };
405
+ });
406
+ }
407
+ return undefined;
408
+ } catch (ex) {
409
+ scope?.error(ex);
410
+ return undefined;
411
+ }
412
+ }
413
+
414
+ @trace({
415
+ args: (provider, token, owner, repo, rev, baseUrl) => ({
416
+ provider: provider.name,
417
+ token: `<token:${token.microHash}>`,
418
+ owner: owner,
419
+ repo: repo,
420
+ rev: rev,
421
+ baseUrl: baseUrl,
422
+ }),
423
+ })
424
+ async getServerPullRequestForCommit(
425
+ provider: Provider,
426
+ token: TokenWithInfo,
427
+ owner: string,
428
+ repo: string,
429
+ rev: string,
430
+ baseUrl: string,
431
+ _options?: {
432
+ avatarSize?: number;
433
+ },
434
+ cancellation?: AbortSignal,
435
+ ): Promise<PullRequest | undefined> {
436
+ const scope = getScopedLogger();
437
+
438
+ try {
439
+ const response = await this.request<{ values: BitbucketServerPullRequest[] }>(
440
+ provider,
441
+ token,
442
+ baseUrl,
443
+ `projects/${owner}/repos/${repo}/commits/${rev}/pull-requests`, //?fields=${fieldsParam}`,
444
+ {
445
+ method: 'GET',
446
+ },
447
+ scope,
448
+ cancellation,
449
+ );
450
+ const prResponse = response?.values?.reduce<BitbucketServerPullRequest | undefined>(
451
+ (acc, pr) => (!acc || pr.updatedDate > acc.updatedDate ? pr : acc),
452
+ undefined,
453
+ );
454
+ if (!prResponse) return undefined;
455
+
456
+ const providersPr = normalizeBitbucketServerPullRequest(prResponse);
457
+ const gitlensPr = fromProviderPullRequest(providersPr, provider);
458
+ return gitlensPr;
459
+ } catch (ex) {
460
+ scope?.error(ex);
461
+ return undefined;
462
+ }
463
+ }
464
+
465
+ @trace({
466
+ args: (provider, token, owner, repo, rev, baseUrl) => ({
467
+ provider: provider.name,
468
+ token: `<token:${token.microHash}>`,
469
+ owner: owner,
470
+ repo: repo,
471
+ rev: rev,
472
+ baseUrl: baseUrl,
473
+ }),
474
+ })
475
+ async getPullRequestForCommit(
476
+ provider: Provider,
477
+ token: TokenWithInfo,
478
+ owner: string,
479
+ repo: string,
480
+ rev: string,
481
+ baseUrl: string,
482
+ _options?: {
483
+ avatarSize?: number;
484
+ },
485
+ cancellation?: AbortSignal,
486
+ ): Promise<PullRequest | undefined> {
487
+ const scope = getScopedLogger();
488
+
489
+ try {
490
+ const fields = [
491
+ '+values.*',
492
+ '+values.destination.repository',
493
+ '+values.destination.branch.*',
494
+ '+values.destination.commit.*',
495
+ '+values.source.repository.*',
496
+ '+values.source.branch.*',
497
+ '+values.source.commit.*',
498
+ ];
499
+ const fieldsParam = encodeURIComponent(fields.join(','));
500
+ const response = await this.request<{ values: BitbucketPullRequest[] }>(
501
+ provider,
502
+ token,
503
+ baseUrl,
504
+ `repositories/${owner}/${repo}/commit/${rev}/pullrequests?fields=${fieldsParam}`,
505
+ {
506
+ method: 'GET',
507
+ },
508
+ scope,
509
+ cancellation,
510
+ );
511
+ const pr = response?.values?.reduce<BitbucketPullRequest | undefined>(
512
+ (acc, pr) => (!acc || pr.updated_on > acc.updated_on ? pr : acc),
513
+ undefined,
514
+ );
515
+ if (!pr) return undefined;
516
+ return fromBitbucketPullRequest(pr, provider);
517
+ } catch (ex) {
518
+ if (ex.original instanceof ProviderFetchError) {
519
+ const json = await ex.original.response.json();
520
+ if (json?.error === 'Invalid or unknown installation') {
521
+ // TODO: In future get it on to home as an warning on the integration itself "this integration has issues"
522
+ // even user suppresses the message it's still visible with some capacity. It's a broader thing to get other errors.
523
+ const commitWebUrl = `https://bitbucket.org/${owner}/${repo}/commits/${rev}`;
524
+ this.ctx.hooks?.ui?.onBitbucketCommitLinksAppMissing?.(commitWebUrl);
525
+ return undefined;
526
+ }
527
+ }
528
+
529
+ scope?.error(ex);
530
+ return undefined;
531
+ }
532
+ }
533
+
534
+ @trace({
535
+ args: (provider, token, owner, repo, rev, baseUrl) => ({
536
+ provider: provider.name,
537
+ token: `<token:${token.microHash}>`,
538
+ owner: owner,
539
+ repo: repo,
540
+ rev: rev,
541
+ baseUrl: baseUrl,
542
+ }),
543
+ })
544
+ async getAccountForCommit(
545
+ provider: Provider,
546
+ token: TokenWithInfo,
547
+ owner: string,
548
+ repo: string,
549
+ rev: string,
550
+ baseUrl: string,
551
+ _options?: {
552
+ avatarSize?: number;
553
+ },
554
+ cancellation?: AbortSignal,
555
+ ): Promise<Account | UnidentifiedAuthor | undefined> {
556
+ const scope = getScopedLogger();
557
+
558
+ try {
559
+ const commit = await this.request<BitbucketCommit>(
560
+ provider,
561
+ token,
562
+ baseUrl,
563
+ `repositories/${owner}/${repo}/commit/${rev}`,
564
+ {
565
+ method: 'GET',
566
+ },
567
+ scope,
568
+ cancellation,
569
+ );
570
+ if (!commit) {
571
+ return undefined;
572
+ }
573
+
574
+ const { name, email } = parseRawBitbucketAuthor(commit.author.raw);
575
+ const commitAuthor: CommitAuthor = {
576
+ provider: provider,
577
+ id: commit.author.user?.account_id,
578
+ username: commit.author.user?.nickname,
579
+ name: commit.author.user?.display_name || name,
580
+ email: email,
581
+ avatarUrl: commit.author.user?.links?.avatar?.href,
582
+ };
583
+ if (commitAuthor.id != null && commitAuthor.username != null) {
584
+ return {
585
+ ...commitAuthor,
586
+ id: commitAuthor.id,
587
+ } satisfies Account;
588
+ }
589
+ return {
590
+ ...commitAuthor,
591
+ id: undefined,
592
+ username: undefined,
593
+ } satisfies UnidentifiedAuthor;
594
+ } catch (ex) {
595
+ scope?.error(ex);
596
+ return undefined;
597
+ }
598
+ }
599
+
600
+ @trace({
601
+ args: (provider, token, owner, repo, rev, baseUrl) => ({
602
+ provider: provider.name,
603
+ token: `<token:${token.microHash}>`,
604
+ owner: owner,
605
+ repo: repo,
606
+ rev: rev,
607
+ baseUrl: baseUrl,
608
+ }),
609
+ })
610
+ async getServerAccountForCommit(
611
+ provider: Provider,
612
+ token: TokenWithInfo,
613
+ owner: string,
614
+ repo: string,
615
+ rev: string,
616
+ baseUrl: string,
617
+ _options?: {
618
+ avatarSize?: number;
619
+ },
620
+ cancellation?: AbortSignal,
621
+ ): Promise<Account | UnidentifiedAuthor | undefined> {
622
+ const scope = getScopedLogger();
623
+
624
+ try {
625
+ const commit = await this.request<BitbucketServerCommit>(
626
+ provider,
627
+ token,
628
+ baseUrl,
629
+ `projects/${owner}/repos/${repo}/commits/${rev}`,
630
+ {
631
+ method: 'GET',
632
+ },
633
+ scope,
634
+ cancellation,
635
+ );
636
+ if (!commit?.author) {
637
+ return undefined;
638
+ }
639
+ if (commit.author.id != null) {
640
+ return {
641
+ provider: provider,
642
+ id: commit.author.id.toString(),
643
+ username: commit.author.name,
644
+ name: commit.author.name,
645
+ email: commit.author.emailAddress,
646
+ avatarUrl: commit.author?.avatarUrl,
647
+ } satisfies Account;
648
+ }
649
+ return {
650
+ provider: provider,
651
+ id: undefined,
652
+ username: undefined,
653
+ name: commit.author.name,
654
+ email: commit.author.emailAddress,
655
+ avatarUrl: undefined,
656
+ } satisfies UnidentifiedAuthor;
657
+ } catch (ex) {
658
+ scope?.error(ex);
659
+ return undefined;
660
+ }
661
+ }
662
+
663
+ private async request<T>(
664
+ provider: Provider,
665
+ token: TokenWithInfo,
666
+ baseUrl: string,
667
+ route: string,
668
+ options?: { method: RequestInit['method'] } & Record<string, unknown>,
669
+ scope?: ScopedLogger | undefined,
670
+ cancellation?: AbortSignal | undefined,
671
+ ): Promise<T | undefined> {
672
+ const { accessToken, ...tokenInfo } = token;
673
+ const url = `${baseUrl}/${route}`;
674
+
675
+ let rsp: Response;
676
+ try {
677
+ const sw = maybeStopWatch(`[BITBUCKET] ${options?.method ?? 'GET'} ${url}`, { log: { onlyExit: true } });
678
+
679
+ try {
680
+ if (cancellation?.aborted) throw new CancellationError();
681
+
682
+ rsp = await this.ctx.http.wrapForForcedInsecureSSL(provider.getIgnoreSSLErrors(), () =>
683
+ this.ctx.http.fetch(url, {
684
+ headers: { Authorization: `Bearer ${accessToken}`, 'Content-Type': 'application/json' },
685
+ signal: cancellation,
686
+ ...options,
687
+ }),
688
+ );
689
+
690
+ if (rsp.ok) {
691
+ return (await rsp.json()) as T;
692
+ }
693
+
694
+ throw new ProviderFetchError('Bitbucket', rsp);
695
+ } finally {
696
+ sw?.stop();
697
+ }
698
+ } catch (ex) {
699
+ if (ex instanceof ProviderFetchError || ex.name === 'AbortError') {
700
+ this.handleRequestError(provider, tokenInfo, ex, scope);
701
+ } else if (Logger.isDebugging) {
702
+ this.ctx.hooks?.ui?.onError?.(`Bitbucket request failed: ${ex.message}`);
703
+ }
704
+
705
+ throw ex;
706
+ }
707
+ }
708
+
709
+ private handleRequestError(
710
+ provider: Provider | undefined,
711
+ tokenInfo: TokenInfo,
712
+ ex: ProviderFetchError | (Error & { name: 'AbortError' }),
713
+ scope: ScopedLogger | undefined,
714
+ ): void {
715
+ if (ex.name === 'AbortError' || !(ex instanceof ProviderFetchError)) throw new CancellationError(ex);
716
+
717
+ switch (ex.status) {
718
+ case 404: // Not found
719
+ case 410: // Gone
720
+ case 422: // Unprocessable Entity
721
+ throw new RequestNotFoundError(ex);
722
+ case 401: // Unauthorized
723
+ throw new AuthenticationError(tokenInfo, AuthenticationErrorReason.Unauthorized, ex);
724
+ case 403: // Forbidden
725
+ // TODO: Learn the Bitbucket API docs and put it in order:
726
+ // if (ex.message.includes('rate limit')) {
727
+ // let resetAt: number | undefined;
728
+
729
+ // const reset = ex.response?.headers?.get('x-ratelimit-reset');
730
+ // if (reset != null) {
731
+ // resetAt = parseInt(reset, 10);
732
+ // if (Number.isNaN(resetAt)) {
733
+ // resetAt = undefined;
734
+ // }
735
+ // }
736
+
737
+ // throw new RequestRateLimitError(ex, token, resetAt);
738
+ // }
739
+ throw new AuthenticationError(tokenInfo, AuthenticationErrorReason.Forbidden, ex);
740
+ case 500: // Internal Server Error
741
+ scope?.error(ex);
742
+ if (ex.response != null) {
743
+ provider?.trackRequestException();
744
+ this.ctx.hooks?.ui?.onRequestFailed?.(
745
+ `${provider?.name ?? 'Bitbucket'} failed to respond and might be experiencing issues.${
746
+ provider == null || provider.id === 'bitbucket'
747
+ ? ' Please visit the [Bitbucket status page](https://bitbucket.status.atlassian.com/) for more information.'
748
+ : ''
749
+ }`,
750
+ );
751
+ }
752
+ return;
753
+ case 502: // Bad Gateway
754
+ scope?.error(ex);
755
+ // TODO: Learn the Bitbucket API docs and put it in order:
756
+ // if (ex.message.includes('timeout')) {
757
+ // provider?.trackRequestException();
758
+ // void showIntegrationRequestTimedOutWarningMessage(provider?.name ?? 'Bitbucket');
759
+ // return;
760
+ // }
761
+ break;
762
+ default:
763
+ if (ex.status >= 400 && ex.status < 500) throw new RequestClientError(ex);
764
+ break;
765
+ }
766
+
767
+ scope?.error(ex);
768
+ if (Logger.isDebugging) {
769
+ this.ctx.hooks?.ui?.onError?.(
770
+ `Bitbucket request failed: ${(ex.response as any)?.errors?.[0]?.message ?? ex.message}`,
771
+ );
772
+ }
773
+ }
774
+ }