@atlassian-dc-mcp/bitbucket 0.12.2 → 0.13.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 +12 -0
- package/README.md +45 -2
- package/build/__tests__/bitbucket-service.test.js +106 -17
- package/build/__tests__/bitbucket-service.test.js.map +1 -1
- package/build/__tests__/bitbucket-token-optimization.test.d.ts +2 -0
- package/build/__tests__/bitbucket-token-optimization.test.d.ts.map +1 -0
- package/build/__tests__/bitbucket-token-optimization.test.js +281 -0
- package/build/__tests__/bitbucket-token-optimization.test.js.map +1 -0
- package/build/__tests__/config.test.d.ts +2 -0
- package/build/__tests__/config.test.d.ts.map +1 -0
- package/build/__tests__/config.test.js +49 -0
- package/build/__tests__/config.test.js.map +1 -0
- package/build/bitbucket-response-mapper.d.ts +8 -0
- package/build/bitbucket-response-mapper.d.ts.map +1 -0
- package/build/bitbucket-response-mapper.js +95 -0
- package/build/bitbucket-response-mapper.js.map +1 -0
- package/build/bitbucket-service.d.ts +24 -22
- package/build/bitbucket-service.d.ts.map +1 -1
- package/build/bitbucket-service.js +88 -54
- package/build/bitbucket-service.js.map +1 -1
- package/build/config.d.ts +4 -0
- package/build/config.d.ts.map +1 -0
- package/build/config.js +11 -0
- package/build/config.js.map +1 -0
- package/build/index.js +15 -15
- package/build/index.js.map +1 -1
- package/package.json +3 -3
- package/server.json +11 -4
- package/src/__tests__/bitbucket-service.test.ts +109 -17
- package/src/__tests__/bitbucket-token-optimization.test.ts +314 -0
- package/src/__tests__/config.test.ts +64 -0
- package/src/bitbucket-response-mapper.ts +112 -0
- package/src/bitbucket-service.ts +117 -57
- package/src/config.ts +13 -0
- package/src/index.ts +18 -17
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import { BitbucketService } from '../bitbucket-service.js';
|
|
2
|
+
import { PullRequestsService } from '../bitbucket-client/index.js';
|
|
3
|
+
|
|
4
|
+
jest.mock('../bitbucket-client/index.js', () => ({
|
|
5
|
+
PullRequestsService: {
|
|
6
|
+
getActivities: jest.fn(),
|
|
7
|
+
streamChanges1: jest.fn(),
|
|
8
|
+
createComment2: jest.fn(),
|
|
9
|
+
create: jest.fn(),
|
|
10
|
+
update: jest.fn(),
|
|
11
|
+
},
|
|
12
|
+
ProjectService: {},
|
|
13
|
+
RepositoryService: {},
|
|
14
|
+
OpenAPI: {
|
|
15
|
+
BASE: '',
|
|
16
|
+
TOKEN: '',
|
|
17
|
+
VERSION: '',
|
|
18
|
+
},
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
function createUser(name: string, displayName: string) {
|
|
22
|
+
return {
|
|
23
|
+
name,
|
|
24
|
+
emailAddress: `${name}@example.com`,
|
|
25
|
+
active: true,
|
|
26
|
+
displayName,
|
|
27
|
+
id: 1,
|
|
28
|
+
slug: name,
|
|
29
|
+
type: 'NORMAL',
|
|
30
|
+
links: {
|
|
31
|
+
self: [{ href: `https://bitbucket.example.com/users/${name}` }],
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function createComment(overrides: Record<string, unknown> = {}) {
|
|
37
|
+
return {
|
|
38
|
+
properties: { repositoryId: 1 },
|
|
39
|
+
id: 101,
|
|
40
|
+
version: 1,
|
|
41
|
+
text: 'Looks good',
|
|
42
|
+
author: createUser('reviewer', 'Reviewer'),
|
|
43
|
+
createdDate: 20,
|
|
44
|
+
updatedDate: 21,
|
|
45
|
+
comments: [],
|
|
46
|
+
anchor: {
|
|
47
|
+
fromHash: 'abc',
|
|
48
|
+
toHash: 'def',
|
|
49
|
+
line: 10,
|
|
50
|
+
lineType: 'ADDED',
|
|
51
|
+
fileType: 'TO',
|
|
52
|
+
path: 'src/app.ts',
|
|
53
|
+
diffType: 'EFFECTIVE',
|
|
54
|
+
orphaned: false,
|
|
55
|
+
},
|
|
56
|
+
threadResolved: false,
|
|
57
|
+
severity: 'NORMAL',
|
|
58
|
+
state: 'OPEN',
|
|
59
|
+
permittedOperations: {
|
|
60
|
+
editable: true,
|
|
61
|
+
transitionable: true,
|
|
62
|
+
deletable: true,
|
|
63
|
+
},
|
|
64
|
+
...overrides,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
describe('BitbucketService token optimization paths', () => {
|
|
69
|
+
let service: BitbucketService;
|
|
70
|
+
|
|
71
|
+
beforeEach(() => {
|
|
72
|
+
service = new BitbucketService('test-host', 'test-token');
|
|
73
|
+
jest.clearAllMocks();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
describe('getPullRequestCommentsAndActions', () => {
|
|
77
|
+
const mockActivityResponse = {
|
|
78
|
+
isLastPage: false,
|
|
79
|
+
values: [
|
|
80
|
+
{
|
|
81
|
+
id: 1,
|
|
82
|
+
createdDate: 10,
|
|
83
|
+
user: createUser('author', 'Author'),
|
|
84
|
+
action: 'OPENED',
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
id: 2,
|
|
88
|
+
createdDate: 20,
|
|
89
|
+
user: createUser('reviewer', 'Reviewer'),
|
|
90
|
+
action: 'COMMENTED',
|
|
91
|
+
comment: createComment(),
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
it('returns compact output by default', async () => {
|
|
97
|
+
(PullRequestsService.getActivities as jest.Mock).mockResolvedValue(mockActivityResponse);
|
|
98
|
+
|
|
99
|
+
const result = await service.getPullRequestCommentsAndActions('TEST', 'repo', '123');
|
|
100
|
+
|
|
101
|
+
expect(result.success).toBe(true);
|
|
102
|
+
expect(result.data).toEqual({
|
|
103
|
+
isLastPage: false,
|
|
104
|
+
activities: [
|
|
105
|
+
{
|
|
106
|
+
id: 1,
|
|
107
|
+
createdDate: 10,
|
|
108
|
+
user: { name: 'author', displayName: 'Author' },
|
|
109
|
+
action: 'OPENED',
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
id: 2,
|
|
113
|
+
createdDate: 20,
|
|
114
|
+
user: { name: 'reviewer', displayName: 'Reviewer' },
|
|
115
|
+
action: 'COMMENTED',
|
|
116
|
+
comment: {
|
|
117
|
+
id: 101,
|
|
118
|
+
text: 'Looks good',
|
|
119
|
+
author: { name: 'reviewer', displayName: 'Reviewer' },
|
|
120
|
+
createdDate: 20,
|
|
121
|
+
anchor: {
|
|
122
|
+
line: 10,
|
|
123
|
+
path: 'src/app.ts',
|
|
124
|
+
fileType: 'TO',
|
|
125
|
+
},
|
|
126
|
+
comments: [],
|
|
127
|
+
threadResolved: false,
|
|
128
|
+
state: 'OPEN',
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
summary: {
|
|
133
|
+
totalActivities: 2,
|
|
134
|
+
prAuthor: { name: 'author', displayName: 'Author' },
|
|
135
|
+
commentCount: 1,
|
|
136
|
+
unresolvedCount: 1,
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
expect(PullRequestsService.getActivities).toHaveBeenCalledWith('TEST', '123', 'repo', undefined, undefined, undefined, 25);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('returns summary output when requested', async () => {
|
|
143
|
+
(PullRequestsService.getActivities as jest.Mock).mockResolvedValue(mockActivityResponse);
|
|
144
|
+
|
|
145
|
+
const result = await service.getPullRequestCommentsAndActions('TEST', 'repo', '123', 5, 10, 'summary');
|
|
146
|
+
|
|
147
|
+
expect(result.success).toBe(true);
|
|
148
|
+
expect(result.data).toEqual({
|
|
149
|
+
isLastPage: false,
|
|
150
|
+
summary: {
|
|
151
|
+
totalActivities: 2,
|
|
152
|
+
prAuthor: { name: 'author', displayName: 'Author' },
|
|
153
|
+
commentCount: 1,
|
|
154
|
+
unresolvedCount: 1,
|
|
155
|
+
},
|
|
156
|
+
items: ['Reviewer on src/app.ts:10: Looks good'],
|
|
157
|
+
});
|
|
158
|
+
expect(PullRequestsService.getActivities).toHaveBeenCalledWith('TEST', '123', 'repo', undefined, undefined, 5, 10);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('returns the raw payload when output is full', async () => {
|
|
162
|
+
(PullRequestsService.getActivities as jest.Mock).mockResolvedValue(mockActivityResponse);
|
|
163
|
+
|
|
164
|
+
const result = await service.getPullRequestCommentsAndActions('TEST', 'repo', '123', undefined, undefined, 'full');
|
|
165
|
+
|
|
166
|
+
expect(result.success).toBe(true);
|
|
167
|
+
expect(result.data).toBe(mockActivityResponse);
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
describe('getPullRequestChanges', () => {
|
|
172
|
+
const mockChangesResponse = {
|
|
173
|
+
fromHash: 'abc',
|
|
174
|
+
toHash: 'def',
|
|
175
|
+
properties: { changeScope: 'ALL' },
|
|
176
|
+
values: [
|
|
177
|
+
{
|
|
178
|
+
contentId: 'content-1',
|
|
179
|
+
fromContentId: 'from-content-1',
|
|
180
|
+
path: {
|
|
181
|
+
components: ['src', 'app.ts'],
|
|
182
|
+
parent: 'src',
|
|
183
|
+
name: 'app.ts',
|
|
184
|
+
extension: 'ts',
|
|
185
|
+
toString: 'src/app.ts',
|
|
186
|
+
},
|
|
187
|
+
type: 'MODIFY',
|
|
188
|
+
properties: {
|
|
189
|
+
gitChangeType: 'MODIFY',
|
|
190
|
+
activeComments: 2,
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
],
|
|
194
|
+
size: 1,
|
|
195
|
+
isLastPage: true,
|
|
196
|
+
start: 0,
|
|
197
|
+
limit: 25,
|
|
198
|
+
nextPageStart: null,
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
it('returns compact output by default', async () => {
|
|
202
|
+
(PullRequestsService.streamChanges1 as jest.Mock).mockResolvedValue(mockChangesResponse);
|
|
203
|
+
|
|
204
|
+
const result = await service.getPullRequestChanges('TEST', 'repo', '123');
|
|
205
|
+
|
|
206
|
+
expect(result.success).toBe(true);
|
|
207
|
+
expect(result.data).toEqual({
|
|
208
|
+
fromHash: 'abc',
|
|
209
|
+
toHash: 'def',
|
|
210
|
+
changeScope: 'ALL',
|
|
211
|
+
changes: [
|
|
212
|
+
{
|
|
213
|
+
contentId: 'content-1',
|
|
214
|
+
path: {
|
|
215
|
+
name: 'app.ts',
|
|
216
|
+
path: 'src/app.ts',
|
|
217
|
+
extension: 'ts',
|
|
218
|
+
},
|
|
219
|
+
type: 'MODIFY',
|
|
220
|
+
gitChangeType: 'MODIFY',
|
|
221
|
+
comments: 2,
|
|
222
|
+
},
|
|
223
|
+
],
|
|
224
|
+
summary: {
|
|
225
|
+
totalChanges: 1,
|
|
226
|
+
additions: 0,
|
|
227
|
+
deletions: 0,
|
|
228
|
+
modifications: 1,
|
|
229
|
+
moves: 0,
|
|
230
|
+
filesWithComments: 1,
|
|
231
|
+
},
|
|
232
|
+
isLastPage: true,
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
it('returns summary output when requested', async () => {
|
|
237
|
+
(PullRequestsService.streamChanges1 as jest.Mock).mockResolvedValue(mockChangesResponse);
|
|
238
|
+
|
|
239
|
+
const result = await service.getPullRequestChanges('TEST', 'repo', '123', undefined, undefined, undefined, undefined, undefined, undefined, 'summary');
|
|
240
|
+
|
|
241
|
+
expect(result.success).toBe(true);
|
|
242
|
+
expect(result.data).toEqual({
|
|
243
|
+
fromHash: 'abc',
|
|
244
|
+
toHash: 'def',
|
|
245
|
+
changeScope: 'ALL',
|
|
246
|
+
isLastPage: true,
|
|
247
|
+
summary: {
|
|
248
|
+
totalChanges: 1,
|
|
249
|
+
additions: 0,
|
|
250
|
+
deletions: 0,
|
|
251
|
+
modifications: 1,
|
|
252
|
+
moves: 0,
|
|
253
|
+
filesWithComments: 1,
|
|
254
|
+
},
|
|
255
|
+
items: ['Modified: src/app.ts [2 comments]'],
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it('returns the raw payload when output is full', async () => {
|
|
260
|
+
(PullRequestsService.streamChanges1 as jest.Mock).mockResolvedValue(mockChangesResponse);
|
|
261
|
+
|
|
262
|
+
const result = await service.getPullRequestChanges('TEST', 'repo', '123', undefined, undefined, undefined, undefined, undefined, undefined, 'full');
|
|
263
|
+
|
|
264
|
+
expect(result.success).toBe(true);
|
|
265
|
+
expect(result.data).toBe(mockChangesResponse);
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
describe('full mutation output', () => {
|
|
270
|
+
it('returns the raw comment response when requested', async () => {
|
|
271
|
+
const mockComment = {
|
|
272
|
+
id: 222,
|
|
273
|
+
text: 'Raw comment',
|
|
274
|
+
state: 'OPEN',
|
|
275
|
+
};
|
|
276
|
+
(PullRequestsService.createComment2 as jest.Mock).mockResolvedValue(mockComment);
|
|
277
|
+
|
|
278
|
+
const result = await service.postPullRequestComment('TEST', 'repo', '123', 'Raw comment', undefined, undefined, undefined, undefined, undefined, 'full');
|
|
279
|
+
|
|
280
|
+
expect(result.success).toBe(true);
|
|
281
|
+
expect(result.data).toBe(mockComment);
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it('returns the raw PR create response when requested', async () => {
|
|
285
|
+
const mockPullRequest = {
|
|
286
|
+
id: 10,
|
|
287
|
+
version: 1,
|
|
288
|
+
title: 'Raw create',
|
|
289
|
+
state: 'OPEN',
|
|
290
|
+
};
|
|
291
|
+
(PullRequestsService.create as jest.Mock).mockResolvedValue(mockPullRequest);
|
|
292
|
+
|
|
293
|
+
const result = await service.createPullRequest('TEST', 'repo', 'Raw create', undefined, 'refs/heads/feature', 'refs/heads/main', undefined, 'full');
|
|
294
|
+
|
|
295
|
+
expect(result.success).toBe(true);
|
|
296
|
+
expect(result.data).toBe(mockPullRequest);
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
it('returns the raw PR update response when requested', async () => {
|
|
300
|
+
const mockPullRequest = {
|
|
301
|
+
id: 11,
|
|
302
|
+
version: 2,
|
|
303
|
+
title: 'Raw update',
|
|
304
|
+
state: 'OPEN',
|
|
305
|
+
};
|
|
306
|
+
(PullRequestsService.update as jest.Mock).mockResolvedValue(mockPullRequest);
|
|
307
|
+
|
|
308
|
+
const result = await service.updatePullRequest('TEST', 'repo', '123', 1, 'Raw update', undefined, undefined, 'full');
|
|
309
|
+
|
|
310
|
+
expect(result.success).toBe(true);
|
|
311
|
+
expect(result.data).toBe(mockPullRequest);
|
|
312
|
+
});
|
|
313
|
+
});
|
|
314
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
|
|
5
|
+
describe('Bitbucket config', () => {
|
|
6
|
+
const originalEnv = process.env;
|
|
7
|
+
const originalCwd = process.cwd();
|
|
8
|
+
let tempDir: string;
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
jest.resetModules();
|
|
12
|
+
process.env = { ...originalEnv };
|
|
13
|
+
delete process.env.ATLASSIAN_DC_MCP_CONFIG_FILE;
|
|
14
|
+
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'bitbucket-config-'));
|
|
15
|
+
process.chdir(tempDir);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
afterEach(() => {
|
|
19
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
20
|
+
process.chdir(originalCwd);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
afterAll(() => {
|
|
24
|
+
process.env = originalEnv;
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('uses the configured page size when the env var is a positive integer', async () => {
|
|
28
|
+
process.env.BITBUCKET_DEFAULT_PAGE_SIZE = '40';
|
|
29
|
+
|
|
30
|
+
const { getDefaultPageSize } = await import('../config.js');
|
|
31
|
+
|
|
32
|
+
expect(getDefaultPageSize()).toBe(40);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('falls back to 25 when the env var is invalid', async () => {
|
|
36
|
+
process.env.BITBUCKET_DEFAULT_PAGE_SIZE = '-1';
|
|
37
|
+
|
|
38
|
+
const { getDefaultPageSize } = await import('../config.js');
|
|
39
|
+
|
|
40
|
+
expect(getDefaultPageSize()).toBe(25);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('reads the page size from the shared config file', async () => {
|
|
44
|
+
const sharedConfigPath = path.join(tempDir, 'shared.env');
|
|
45
|
+
fs.writeFileSync(sharedConfigPath, 'BITBUCKET_HOST=file-host\nBITBUCKET_API_TOKEN=file-token\nBITBUCKET_DEFAULT_PAGE_SIZE=35\n');
|
|
46
|
+
process.env.ATLASSIAN_DC_MCP_CONFIG_FILE = sharedConfigPath;
|
|
47
|
+
|
|
48
|
+
const { getBitbucketRuntimeConfig, getDefaultPageSize } = await import('../config.js');
|
|
49
|
+
|
|
50
|
+
expect(getDefaultPageSize()).toBe(35);
|
|
51
|
+
expect(getBitbucketRuntimeConfig().token).toBe('file-token');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('keeps env values higher priority than the shared config file', async () => {
|
|
55
|
+
const sharedConfigPath = path.join(tempDir, 'shared.env');
|
|
56
|
+
fs.writeFileSync(sharedConfigPath, 'BITBUCKET_HOST=file-host\nBITBUCKET_API_TOKEN=file-token\nBITBUCKET_DEFAULT_PAGE_SIZE=35\n');
|
|
57
|
+
process.env.ATLASSIAN_DC_MCP_CONFIG_FILE = sharedConfigPath;
|
|
58
|
+
process.env.BITBUCKET_DEFAULT_PAGE_SIZE = '45';
|
|
59
|
+
|
|
60
|
+
const { getDefaultPageSize } = await import('../config.js');
|
|
61
|
+
|
|
62
|
+
expect(getDefaultPageSize()).toBe(45);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { BitbucketPRApiResponse, getCommentSummary, simplifyBitbucketPRComments } from './pr-comment-mapper.js';
|
|
2
|
+
import { getChangesSummary, simplifyBitbucketPRChanges } from './pr-changes-mapper.js';
|
|
3
|
+
|
|
4
|
+
export type BitbucketOutputMode = 'summary' | 'compact' | 'full';
|
|
5
|
+
export type BitbucketMutationOutputMode = 'ack' | 'full';
|
|
6
|
+
|
|
7
|
+
function getLink(links: any): string | undefined {
|
|
8
|
+
const selfLinks = links?.self;
|
|
9
|
+
if (Array.isArray(selfLinks)) {
|
|
10
|
+
const link = selfLinks.find(item => typeof item?.href === 'string');
|
|
11
|
+
return link?.href;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (typeof selfLinks === 'string') {
|
|
15
|
+
return selfLinks;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function hasSummary(value: any): value is { summary: unknown; isLastPage?: boolean } {
|
|
22
|
+
return Boolean(value) && typeof value === 'object' && 'summary' in value;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function shapePullRequestCommentsResponse(
|
|
26
|
+
response: BitbucketPRApiResponse,
|
|
27
|
+
output: BitbucketOutputMode = 'compact',
|
|
28
|
+
): Record<string, any> {
|
|
29
|
+
if (output === 'full') {
|
|
30
|
+
return response;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const compact = simplifyBitbucketPRComments(response);
|
|
34
|
+
if (output === 'compact') {
|
|
35
|
+
return compact;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
isLastPage: hasSummary(compact) ? compact.isLastPage ?? true : response.isLastPage ?? true,
|
|
40
|
+
summary: hasSummary(compact)
|
|
41
|
+
? compact.summary
|
|
42
|
+
: {
|
|
43
|
+
totalActivities: Array.isArray(response.values) ? response.values.length : 0,
|
|
44
|
+
commentCount: getCommentSummary(response).length,
|
|
45
|
+
unresolvedCount: 0,
|
|
46
|
+
},
|
|
47
|
+
items: getCommentSummary(response),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function shapePullRequestChangesResponse(response: any, output: BitbucketOutputMode = 'compact'): Record<string, any> {
|
|
52
|
+
if (output === 'full') {
|
|
53
|
+
return response;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const compact = simplifyBitbucketPRChanges(response);
|
|
57
|
+
if (output === 'compact') {
|
|
58
|
+
return compact;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
...(typeof response?.fromHash === 'string' ? { fromHash: response.fromHash } : {}),
|
|
63
|
+
...(typeof response?.toHash === 'string' ? { toHash: response.toHash } : {}),
|
|
64
|
+
...(typeof response?.properties?.changeScope === 'string' ? { changeScope: response.properties.changeScope } : {}),
|
|
65
|
+
isLastPage: hasSummary(compact) ? compact.isLastPage ?? true : response?.isLastPage ?? true,
|
|
66
|
+
summary: hasSummary(compact)
|
|
67
|
+
? compact.summary
|
|
68
|
+
: {
|
|
69
|
+
totalChanges: Array.isArray(response?.values) ? response.values.length : 0,
|
|
70
|
+
additions: 0,
|
|
71
|
+
deletions: 0,
|
|
72
|
+
modifications: 0,
|
|
73
|
+
moves: 0,
|
|
74
|
+
filesWithComments: 0,
|
|
75
|
+
},
|
|
76
|
+
items: getChangesSummary(response),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function shapePullRequestAck(pullRequest: any): Record<string, any> {
|
|
81
|
+
const link = getLink(pullRequest?.links);
|
|
82
|
+
return {
|
|
83
|
+
...(pullRequest?.id !== undefined ? { id: pullRequest.id } : {}),
|
|
84
|
+
...(pullRequest?.version !== undefined ? { version: pullRequest.version } : {}),
|
|
85
|
+
...(typeof pullRequest?.title === 'string' ? { title: pullRequest.title } : {}),
|
|
86
|
+
...(typeof pullRequest?.state === 'string' ? { state: pullRequest.state } : {}),
|
|
87
|
+
...(typeof pullRequest?.fromRef?.id === 'string' ? { fromRefId: pullRequest.fromRef.id } : {}),
|
|
88
|
+
...(typeof pullRequest?.toRef?.id === 'string' ? { toRefId: pullRequest.toRef.id } : {}),
|
|
89
|
+
reviewerCount: Array.isArray(pullRequest?.reviewers) ? pullRequest.reviewers.length : 0,
|
|
90
|
+
...(link ? { link } : {}),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function shapePullRequestCommentAck(comment: any): Record<string, any> {
|
|
95
|
+
const link = getLink(comment?.links);
|
|
96
|
+
return {
|
|
97
|
+
...(comment?.id !== undefined ? { id: comment.id } : {}),
|
|
98
|
+
...(comment?.parent?.id !== undefined ? { parentId: comment.parent.id } : {}),
|
|
99
|
+
...(typeof comment?.state === 'string' ? { state: comment.state } : {}),
|
|
100
|
+
pending: comment?.state === 'PENDING',
|
|
101
|
+
...(typeof comment?.anchor?.path === 'string'
|
|
102
|
+
? {
|
|
103
|
+
anchor: {
|
|
104
|
+
path: comment.anchor.path,
|
|
105
|
+
...(comment.anchor.line !== undefined ? { line: comment.anchor.line } : {}),
|
|
106
|
+
...(typeof comment.anchor.lineType === 'string' ? { lineType: comment.anchor.lineType } : {}),
|
|
107
|
+
},
|
|
108
|
+
}
|
|
109
|
+
: {}),
|
|
110
|
+
...(link ? { link } : {}),
|
|
111
|
+
};
|
|
112
|
+
}
|