@atlassian-dc-mcp/bitbucket 0.12.0 → 0.12.2
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 +19 -0
- package/build/__tests__/pr-comment-mapper.test.js +192 -63
- package/build/__tests__/pr-comment-mapper.test.js.map +1 -1
- package/build/pr-comment-mapper.d.ts +1 -0
- package/build/pr-comment-mapper.d.ts.map +1 -1
- package/build/pr-comment-mapper.js +10 -2
- package/build/pr-comment-mapper.js.map +1 -1
- package/package.json +3 -3
- package/src/__tests__/pr-comment-mapper.test.ts +232 -63
- package/src/pr-comment-mapper.ts +12 -2
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -4,6 +4,83 @@ import {
|
|
|
4
4
|
type BitbucketPRApiResponse,
|
|
5
5
|
type SimplifiedPRResponse
|
|
6
6
|
} from '../pr-comment-mapper.js';
|
|
7
|
+
import { formatToolResponse } from '@atlassian-dc-mcp/common';
|
|
8
|
+
|
|
9
|
+
interface TestComment {
|
|
10
|
+
properties: { repositoryId: number };
|
|
11
|
+
id: number;
|
|
12
|
+
version: number;
|
|
13
|
+
text: string;
|
|
14
|
+
author: ReturnType<typeof createUser>;
|
|
15
|
+
createdDate: number;
|
|
16
|
+
updatedDate: number;
|
|
17
|
+
comments: TestComment[];
|
|
18
|
+
anchor?: {
|
|
19
|
+
fromHash: string;
|
|
20
|
+
toHash: string;
|
|
21
|
+
line: number;
|
|
22
|
+
lineType: string;
|
|
23
|
+
fileType: string;
|
|
24
|
+
path: string;
|
|
25
|
+
diffType: string;
|
|
26
|
+
orphaned: boolean;
|
|
27
|
+
};
|
|
28
|
+
threadResolved: boolean;
|
|
29
|
+
severity: string;
|
|
30
|
+
state: string;
|
|
31
|
+
permittedOperations: {
|
|
32
|
+
editable: boolean;
|
|
33
|
+
transitionable: boolean;
|
|
34
|
+
deletable: boolean;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function createUser(name: string, id: number, displayName: string) {
|
|
39
|
+
return {
|
|
40
|
+
name,
|
|
41
|
+
emailAddress: `${name}@company.local`,
|
|
42
|
+
active: true,
|
|
43
|
+
displayName,
|
|
44
|
+
id,
|
|
45
|
+
slug: name,
|
|
46
|
+
type: "NORMAL",
|
|
47
|
+
links: {
|
|
48
|
+
self: [{ href: `https://bitbucket.company.local/users/${name}` }]
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function createComment(overrides: Partial<TestComment> = {}): TestComment {
|
|
54
|
+
return {
|
|
55
|
+
properties: { repositoryId: 1001 },
|
|
56
|
+
id: 2001,
|
|
57
|
+
version: 0,
|
|
58
|
+
text: "This needs review",
|
|
59
|
+
author: createUser('testuser1', 101, 'User A'),
|
|
60
|
+
createdDate: 1600000000000,
|
|
61
|
+
updatedDate: 1600000000000,
|
|
62
|
+
comments: [],
|
|
63
|
+
anchor: {
|
|
64
|
+
fromHash: "abc123def456789012345678901234567890abcd",
|
|
65
|
+
toHash: "def456abc789012345678901234567890123cdef",
|
|
66
|
+
line: 6,
|
|
67
|
+
lineType: "ADDED",
|
|
68
|
+
fileType: "TO",
|
|
69
|
+
path: "config.yml",
|
|
70
|
+
diffType: "EFFECTIVE",
|
|
71
|
+
orphaned: false
|
|
72
|
+
},
|
|
73
|
+
threadResolved: false,
|
|
74
|
+
severity: "NORMAL",
|
|
75
|
+
state: "OPEN",
|
|
76
|
+
permittedOperations: {
|
|
77
|
+
editable: false,
|
|
78
|
+
transitionable: true,
|
|
79
|
+
deletable: false
|
|
80
|
+
},
|
|
81
|
+
...overrides
|
|
82
|
+
};
|
|
83
|
+
}
|
|
7
84
|
|
|
8
85
|
describe('PR Comment Mapper', () => {
|
|
9
86
|
// Test data from the original ad-hoc test
|
|
@@ -15,75 +92,15 @@ describe('PR Comment Mapper', () => {
|
|
|
15
92
|
{
|
|
16
93
|
id: 1001,
|
|
17
94
|
createdDate: 1600000000000,
|
|
18
|
-
user:
|
|
19
|
-
name: "testuser1",
|
|
20
|
-
emailAddress: "testuser1@company.local",
|
|
21
|
-
active: true,
|
|
22
|
-
displayName: "User A",
|
|
23
|
-
id: 101,
|
|
24
|
-
slug: "testuser1",
|
|
25
|
-
type: "NORMAL",
|
|
26
|
-
links: {
|
|
27
|
-
self: [{ href: "https://bitbucket.company.local/users/testuser1" }]
|
|
28
|
-
}
|
|
29
|
-
},
|
|
95
|
+
user: createUser('testuser1', 101, 'User A'),
|
|
30
96
|
action: "COMMENTED",
|
|
31
97
|
commentAction: "ADDED",
|
|
32
|
-
comment:
|
|
33
|
-
properties: { repositoryId: 1001 },
|
|
34
|
-
id: 2001,
|
|
35
|
-
version: 0,
|
|
36
|
-
text: "This needs review",
|
|
37
|
-
author: {
|
|
38
|
-
name: "testuser1",
|
|
39
|
-
emailAddress: "testuser1@company.local",
|
|
40
|
-
active: true,
|
|
41
|
-
displayName: "User A",
|
|
42
|
-
id: 101,
|
|
43
|
-
slug: "testuser1",
|
|
44
|
-
type: "NORMAL",
|
|
45
|
-
links: {
|
|
46
|
-
self: [{ href: "https://bitbucket.company.local/users/testuser1" }]
|
|
47
|
-
}
|
|
48
|
-
},
|
|
49
|
-
createdDate: 1600000000000,
|
|
50
|
-
updatedDate: 1600000000000,
|
|
51
|
-
comments: [],
|
|
52
|
-
anchor: {
|
|
53
|
-
fromHash: "abc123def456789012345678901234567890abcd",
|
|
54
|
-
toHash: "def456abc789012345678901234567890123cdef",
|
|
55
|
-
line: 6,
|
|
56
|
-
lineType: "ADDED",
|
|
57
|
-
fileType: "TO",
|
|
58
|
-
path: "config.yml",
|
|
59
|
-
diffType: "EFFECTIVE",
|
|
60
|
-
orphaned: false
|
|
61
|
-
},
|
|
62
|
-
threadResolved: false,
|
|
63
|
-
severity: "NORMAL",
|
|
64
|
-
state: "OPEN",
|
|
65
|
-
permittedOperations: {
|
|
66
|
-
editable: false,
|
|
67
|
-
transitionable: true,
|
|
68
|
-
deletable: false
|
|
69
|
-
}
|
|
70
|
-
}
|
|
98
|
+
comment: createComment()
|
|
71
99
|
},
|
|
72
100
|
{
|
|
73
101
|
id: 1002,
|
|
74
102
|
createdDate: 1600000001000,
|
|
75
|
-
user:
|
|
76
|
-
name: "testuser2",
|
|
77
|
-
emailAddress: "testuser2@company.local",
|
|
78
|
-
active: true,
|
|
79
|
-
displayName: "User B",
|
|
80
|
-
id: 102,
|
|
81
|
-
slug: "testuser2",
|
|
82
|
-
type: "NORMAL",
|
|
83
|
-
links: {
|
|
84
|
-
self: [{ href: "https://bitbucket.company.local/users/testuser2" }]
|
|
85
|
-
}
|
|
86
|
-
},
|
|
103
|
+
user: createUser('testuser2', 102, 'User B'),
|
|
87
104
|
action: "OPENED"
|
|
88
105
|
}
|
|
89
106
|
],
|
|
@@ -119,6 +136,7 @@ describe('PR Comment Mapper', () => {
|
|
|
119
136
|
path: "config.yml",
|
|
120
137
|
fileType: "TO"
|
|
121
138
|
},
|
|
139
|
+
comments: [],
|
|
122
140
|
threadResolved: false,
|
|
123
141
|
state: "OPEN"
|
|
124
142
|
}
|
|
@@ -147,6 +165,157 @@ describe('PR Comment Mapper', () => {
|
|
|
147
165
|
expect(result).toEqual(expectedResult);
|
|
148
166
|
});
|
|
149
167
|
|
|
168
|
+
it('should preserve nested replies recursively', () => {
|
|
169
|
+
const threadedResponse: BitbucketPRApiResponse = {
|
|
170
|
+
...validPRResponse,
|
|
171
|
+
values: [
|
|
172
|
+
{
|
|
173
|
+
id: 1001,
|
|
174
|
+
createdDate: 1600000000000,
|
|
175
|
+
user: createUser('testuser1', 101, 'User A'),
|
|
176
|
+
action: "COMMENTED",
|
|
177
|
+
commentAction: "ADDED",
|
|
178
|
+
comment: createComment({
|
|
179
|
+
comments: [
|
|
180
|
+
createComment({
|
|
181
|
+
id: 2002,
|
|
182
|
+
text: "Author reply",
|
|
183
|
+
author: createUser('author1', 103, 'Author One'),
|
|
184
|
+
anchor: undefined,
|
|
185
|
+
comments: [
|
|
186
|
+
createComment({
|
|
187
|
+
id: 2003,
|
|
188
|
+
text: "Reviewer follow-up",
|
|
189
|
+
author: createUser('reviewer2', 104, 'Reviewer Two'),
|
|
190
|
+
anchor: undefined
|
|
191
|
+
})
|
|
192
|
+
]
|
|
193
|
+
})
|
|
194
|
+
]
|
|
195
|
+
})
|
|
196
|
+
}
|
|
197
|
+
]
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
const result = simplifyBitbucketPRComments(threadedResponse) as SimplifiedPRResponse;
|
|
201
|
+
expect(result.activities[0].comment?.comments).toEqual([
|
|
202
|
+
{
|
|
203
|
+
id: 2002,
|
|
204
|
+
text: "Author reply",
|
|
205
|
+
author: {
|
|
206
|
+
name: "author1",
|
|
207
|
+
displayName: "Author One"
|
|
208
|
+
},
|
|
209
|
+
createdDate: 1600000000000,
|
|
210
|
+
comments: [
|
|
211
|
+
{
|
|
212
|
+
id: 2003,
|
|
213
|
+
text: "Reviewer follow-up",
|
|
214
|
+
author: {
|
|
215
|
+
name: "reviewer2",
|
|
216
|
+
displayName: "Reviewer Two"
|
|
217
|
+
},
|
|
218
|
+
createdDate: 1600000000000,
|
|
219
|
+
comments: [],
|
|
220
|
+
threadResolved: false,
|
|
221
|
+
state: "OPEN"
|
|
222
|
+
}
|
|
223
|
+
],
|
|
224
|
+
threadResolved: false,
|
|
225
|
+
state: "OPEN"
|
|
226
|
+
}
|
|
227
|
+
]);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it('should skip malformed nested replies', () => {
|
|
231
|
+
const malformedNestedResponse: BitbucketPRApiResponse = {
|
|
232
|
+
...validPRResponse,
|
|
233
|
+
values: [
|
|
234
|
+
{
|
|
235
|
+
id: 1001,
|
|
236
|
+
createdDate: 1600000000000,
|
|
237
|
+
user: createUser('testuser1', 101, 'User A'),
|
|
238
|
+
action: "COMMENTED",
|
|
239
|
+
commentAction: "ADDED",
|
|
240
|
+
comment: createComment({
|
|
241
|
+
comments: [
|
|
242
|
+
{ id: 'bad-comment-id' } as unknown as TestComment,
|
|
243
|
+
createComment({
|
|
244
|
+
id: 2002,
|
|
245
|
+
text: "Valid reply",
|
|
246
|
+
anchor: undefined
|
|
247
|
+
})
|
|
248
|
+
]
|
|
249
|
+
})
|
|
250
|
+
}
|
|
251
|
+
]
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
const result = simplifyBitbucketPRComments(malformedNestedResponse) as SimplifiedPRResponse;
|
|
255
|
+
expect(result.activities[0].comment?.comments).toEqual([
|
|
256
|
+
{
|
|
257
|
+
id: 2002,
|
|
258
|
+
text: "Valid reply",
|
|
259
|
+
author: {
|
|
260
|
+
name: "testuser1",
|
|
261
|
+
displayName: "User A"
|
|
262
|
+
},
|
|
263
|
+
createdDate: 1600000000000,
|
|
264
|
+
comments: [],
|
|
265
|
+
threadResolved: false,
|
|
266
|
+
state: "OPEN"
|
|
267
|
+
}
|
|
268
|
+
]);
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it('should drop cyclic reply branches and remain JSON serializable', () => {
|
|
272
|
+
const rootComment = createComment();
|
|
273
|
+
const childComment = createComment({
|
|
274
|
+
id: 2002,
|
|
275
|
+
text: "Child reply",
|
|
276
|
+
anchor: undefined
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
rootComment.comments = [childComment];
|
|
280
|
+
childComment.comments = [rootComment];
|
|
281
|
+
|
|
282
|
+
const cyclicResponse: BitbucketPRApiResponse = {
|
|
283
|
+
size: 1,
|
|
284
|
+
limit: 100,
|
|
285
|
+
isLastPage: true,
|
|
286
|
+
values: [
|
|
287
|
+
{
|
|
288
|
+
id: 1001,
|
|
289
|
+
createdDate: 1600000000000,
|
|
290
|
+
user: createUser('testuser1', 101, 'User A'),
|
|
291
|
+
action: "COMMENTED",
|
|
292
|
+
commentAction: "ADDED",
|
|
293
|
+
comment: rootComment
|
|
294
|
+
}
|
|
295
|
+
],
|
|
296
|
+
start: 0
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
const result = simplifyBitbucketPRComments(cyclicResponse) as SimplifiedPRResponse;
|
|
300
|
+
expect(result.activities[0].comment?.comments).toEqual([
|
|
301
|
+
{
|
|
302
|
+
id: 2002,
|
|
303
|
+
text: "Child reply",
|
|
304
|
+
author: {
|
|
305
|
+
name: "testuser1",
|
|
306
|
+
displayName: "User A"
|
|
307
|
+
},
|
|
308
|
+
createdDate: 1600000000000,
|
|
309
|
+
comments: [],
|
|
310
|
+
threadResolved: false,
|
|
311
|
+
state: "OPEN"
|
|
312
|
+
}
|
|
313
|
+
]);
|
|
314
|
+
|
|
315
|
+
expect(() => formatToolResponse(result)).not.toThrow();
|
|
316
|
+
expect(JSON.parse(formatToolResponse(result).content[0].text)).toBeTruthy();
|
|
317
|
+
});
|
|
318
|
+
|
|
150
319
|
it('should handle malformed input gracefully', () => {
|
|
151
320
|
const malformedInput = { invalid: 'data' } as any;
|
|
152
321
|
const result = simplifyBitbucketPRComments(malformedInput) as SimplifiedPRResponse;
|
package/src/pr-comment-mapper.ts
CHANGED
|
@@ -139,6 +139,7 @@ interface SimplifiedComment {
|
|
|
139
139
|
author: SimplifiedUser;
|
|
140
140
|
createdDate: number;
|
|
141
141
|
anchor?: SimplifiedAnchor;
|
|
142
|
+
comments: SimplifiedComment[];
|
|
142
143
|
threadResolved: boolean;
|
|
143
144
|
state: string;
|
|
144
145
|
}
|
|
@@ -239,13 +240,20 @@ function simplifyAnchor(anchor: CommentAnchor): SimplifiedAnchor {
|
|
|
239
240
|
};
|
|
240
241
|
}
|
|
241
242
|
|
|
242
|
-
function simplifyComment(comment: Comment): SimplifiedComment {
|
|
243
|
+
function simplifyComment(comment: Comment, ancestorIds: Set<number> = new Set()): SimplifiedComment {
|
|
244
|
+
const nextAncestorIds = new Set(ancestorIds);
|
|
245
|
+
nextAncestorIds.add(comment.id);
|
|
246
|
+
|
|
243
247
|
return {
|
|
244
248
|
id: comment.id,
|
|
245
249
|
text: comment.text,
|
|
246
250
|
author: simplifyUser(comment.author),
|
|
247
251
|
createdDate: comment.createdDate,
|
|
248
252
|
...(comment.anchor && { anchor: simplifyAnchor(comment.anchor) }),
|
|
253
|
+
comments: comment.comments
|
|
254
|
+
.filter(isComment)
|
|
255
|
+
.filter(childComment => !nextAncestorIds.has(childComment.id))
|
|
256
|
+
.map(childComment => simplifyComment(childComment, nextAncestorIds)),
|
|
249
257
|
threadResolved: comment.threadResolved,
|
|
250
258
|
state: comment.state
|
|
251
259
|
};
|
|
@@ -258,7 +266,9 @@ function simplifyActivity(activity: PRActivity): SimplifiedActivity {
|
|
|
258
266
|
user: simplifyUser(activity.user),
|
|
259
267
|
action: activity.action,
|
|
260
268
|
...(activity.commentAction && { commentAction: activity.commentAction }),
|
|
261
|
-
...(activity.comment &&
|
|
269
|
+
...(activity.comment && isComment(activity.comment) && {
|
|
270
|
+
comment: simplifyComment(activity.comment)
|
|
271
|
+
})
|
|
262
272
|
};
|
|
263
273
|
}
|
|
264
274
|
|