@atlassian-dc-mcp/bitbucket 0.6.0 → 0.7.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 +29 -0
- package/build/__tests__/bitbucket-service.test.d.ts +2 -0
- package/build/__tests__/bitbucket-service.test.d.ts.map +1 -0
- package/build/__tests__/bitbucket-service.test.js +269 -0
- package/build/__tests__/bitbucket-service.test.js.map +1 -0
- package/build/__tests__/pr-changes-mapper.test.d.ts +2 -0
- package/build/__tests__/pr-changes-mapper.test.d.ts.map +1 -0
- package/build/__tests__/pr-changes-mapper.test.js +396 -0
- package/build/__tests__/pr-changes-mapper.test.js.map +1 -0
- package/build/__tests__/pr-comment-mapper.test.d.ts +2 -0
- package/build/__tests__/pr-comment-mapper.test.d.ts.map +1 -0
- package/build/__tests__/pr-comment-mapper.test.js +210 -0
- package/build/__tests__/pr-comment-mapper.test.js.map +1 -0
- package/build/bitbucket-service.d.ts +84 -1
- package/build/bitbucket-service.d.ts.map +1 -1
- package/build/bitbucket-service.js +148 -1
- package/build/bitbucket-service.js.map +1 -1
- package/build/index.js +13 -1
- package/build/index.js.map +1 -1
- package/build/pr-changes-mapper.d.ts +32 -0
- package/build/pr-changes-mapper.d.ts.map +1 -0
- package/build/pr-changes-mapper.js +111 -0
- package/build/pr-changes-mapper.js.map +1 -0
- package/build/pr-comment-mapper.d.ts +48 -0
- package/build/pr-comment-mapper.d.ts.map +1 -0
- package/build/pr-comment-mapper.js +128 -0
- package/build/pr-comment-mapper.js.map +1 -0
- package/jest.config.js +23 -0
- package/package.json +5 -3
- package/src/__tests__/bitbucket-service.test.ts +419 -0
- package/src/__tests__/pr-changes-mapper.test.ts +420 -0
- package/src/__tests__/pr-comment-mapper.test.ts +230 -0
- package/src/bitbucket-service.ts +215 -2
- package/src/index.ts +33 -2
- package/src/pr-changes-mapper.ts +216 -0
- package/src/pr-comment-mapper.ts +318 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
interface BitbucketUserLinks {
|
|
2
|
+
self: Array<{
|
|
3
|
+
href: string;
|
|
4
|
+
}>;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
interface BitbucketUser {
|
|
8
|
+
name: string;
|
|
9
|
+
emailAddress: string;
|
|
10
|
+
active: boolean;
|
|
11
|
+
displayName: string;
|
|
12
|
+
id: number;
|
|
13
|
+
slug: string;
|
|
14
|
+
type: string;
|
|
15
|
+
links: BitbucketUserLinks;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface CommentAnchor {
|
|
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
|
+
|
|
29
|
+
interface CommentProperties {
|
|
30
|
+
repositoryId: number;
|
|
31
|
+
|
|
32
|
+
[key: string]: unknown; // Allow additional properties
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface PermittedOperations {
|
|
36
|
+
editable: boolean;
|
|
37
|
+
transitionable: boolean;
|
|
38
|
+
deletable: boolean;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface Comment {
|
|
42
|
+
properties: CommentProperties;
|
|
43
|
+
id: number;
|
|
44
|
+
version: number;
|
|
45
|
+
text: string;
|
|
46
|
+
author: BitbucketUser;
|
|
47
|
+
createdDate: number;
|
|
48
|
+
updatedDate: number;
|
|
49
|
+
comments: Comment[]; // Nested comments have the same structure
|
|
50
|
+
anchor?: CommentAnchor;
|
|
51
|
+
threadResolved: boolean;
|
|
52
|
+
severity: string;
|
|
53
|
+
state: string;
|
|
54
|
+
permittedOperations: PermittedOperations;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
interface DiffDestination {
|
|
58
|
+
components: string[];
|
|
59
|
+
parent: string;
|
|
60
|
+
name: string;
|
|
61
|
+
extension: string;
|
|
62
|
+
toString: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
interface DiffLine {
|
|
66
|
+
destination: number;
|
|
67
|
+
source: number;
|
|
68
|
+
line: string;
|
|
69
|
+
truncated: boolean;
|
|
70
|
+
commentIds?: number[];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
interface DiffSegment {
|
|
74
|
+
type: string;
|
|
75
|
+
lines: DiffLine[];
|
|
76
|
+
truncated: boolean;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
interface DiffHunk {
|
|
80
|
+
sourceLine: number;
|
|
81
|
+
sourceSpan: number;
|
|
82
|
+
destinationLine: number;
|
|
83
|
+
destinationSpan: number;
|
|
84
|
+
segments: DiffSegment[];
|
|
85
|
+
truncated: boolean;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
interface DiffProperties {
|
|
89
|
+
toHash: string;
|
|
90
|
+
current: boolean;
|
|
91
|
+
fromHash: string;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
interface Diff {
|
|
95
|
+
destination: DiffDestination;
|
|
96
|
+
hunks: DiffHunk[];
|
|
97
|
+
truncated: boolean;
|
|
98
|
+
properties?: DiffProperties;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
interface PRActivity {
|
|
102
|
+
id: number;
|
|
103
|
+
createdDate: number;
|
|
104
|
+
user: BitbucketUser;
|
|
105
|
+
action: string;
|
|
106
|
+
commentAction?: string;
|
|
107
|
+
comment?: Comment;
|
|
108
|
+
commentAnchor?: CommentAnchor;
|
|
109
|
+
diff?: Diff;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// This represents the actual API response structure (without the ApiErrorResponse wrapper)
|
|
113
|
+
// Note: We use 'unknown[]' for values to handle the mismatch between the generated
|
|
114
|
+
// RestPullRequestActivity type (which is empty) and the actual API response structure
|
|
115
|
+
export interface BitbucketPRApiResponse {
|
|
116
|
+
size?: number;
|
|
117
|
+
limit?: number;
|
|
118
|
+
isLastPage?: boolean;
|
|
119
|
+
values?: unknown[]; // Will be validated with type guards in the implementation
|
|
120
|
+
start?: number;
|
|
121
|
+
nextPageStart?: number;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Simplified types for the output
|
|
125
|
+
interface SimplifiedUser {
|
|
126
|
+
name: string;
|
|
127
|
+
displayName: string;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
interface SimplifiedAnchor {
|
|
131
|
+
line: number;
|
|
132
|
+
path: string;
|
|
133
|
+
fileType?: string;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
interface SimplifiedComment {
|
|
137
|
+
id: number;
|
|
138
|
+
text: string;
|
|
139
|
+
author: SimplifiedUser;
|
|
140
|
+
createdDate: number;
|
|
141
|
+
anchor?: SimplifiedAnchor;
|
|
142
|
+
threadResolved: boolean;
|
|
143
|
+
state: string;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
interface SimplifiedActivity {
|
|
147
|
+
id: number;
|
|
148
|
+
createdDate: number;
|
|
149
|
+
user: SimplifiedUser;
|
|
150
|
+
action: string;
|
|
151
|
+
commentAction?: string;
|
|
152
|
+
comment?: SimplifiedComment;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export interface SimplifiedPRResponse {
|
|
156
|
+
isLastPage: boolean;
|
|
157
|
+
activities: SimplifiedActivity[];
|
|
158
|
+
summary: {
|
|
159
|
+
totalActivities: number;
|
|
160
|
+
prAuthor?: SimplifiedUser;
|
|
161
|
+
commentCount: number;
|
|
162
|
+
unresolvedCount: number;
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Type guard functions to validate object structure
|
|
167
|
+
function isBitbucketUser(obj: unknown): obj is BitbucketUser {
|
|
168
|
+
return (
|
|
169
|
+
typeof obj === 'object' &&
|
|
170
|
+
obj !== null &&
|
|
171
|
+
typeof (obj as any).name === 'string' &&
|
|
172
|
+
typeof (obj as any).emailAddress === 'string' &&
|
|
173
|
+
typeof (obj as any).active === 'boolean' &&
|
|
174
|
+
typeof (obj as any).displayName === 'string' &&
|
|
175
|
+
typeof (obj as any).id === 'number' &&
|
|
176
|
+
typeof (obj as any).slug === 'string' &&
|
|
177
|
+
typeof (obj as any).type === 'string' &&
|
|
178
|
+
typeof (obj as any).links === 'object'
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function isCommentAnchor(obj: unknown): obj is CommentAnchor {
|
|
183
|
+
return (
|
|
184
|
+
typeof obj === 'object' &&
|
|
185
|
+
obj !== null &&
|
|
186
|
+
typeof (obj as any).fromHash === 'string' &&
|
|
187
|
+
typeof (obj as any).toHash === 'string' &&
|
|
188
|
+
typeof (obj as any).line === 'number' &&
|
|
189
|
+
typeof (obj as any).lineType === 'string' &&
|
|
190
|
+
typeof (obj as any).fileType === 'string' &&
|
|
191
|
+
typeof (obj as any).path === 'string' &&
|
|
192
|
+
typeof (obj as any).diffType === 'string' &&
|
|
193
|
+
typeof (obj as any).orphaned === 'boolean'
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function isComment(obj: unknown): obj is Comment {
|
|
198
|
+
return (
|
|
199
|
+
typeof obj === 'object' &&
|
|
200
|
+
obj !== null &&
|
|
201
|
+
typeof (obj as any).id === 'number' &&
|
|
202
|
+
typeof (obj as any).version === 'number' &&
|
|
203
|
+
typeof (obj as any).text === 'string' &&
|
|
204
|
+
isBitbucketUser((obj as any).author) &&
|
|
205
|
+
typeof (obj as any).createdDate === 'number' &&
|
|
206
|
+
typeof (obj as any).updatedDate === 'number' &&
|
|
207
|
+
Array.isArray((obj as any).comments) &&
|
|
208
|
+
typeof (obj as any).threadResolved === 'boolean' &&
|
|
209
|
+
typeof (obj as any).severity === 'string' &&
|
|
210
|
+
typeof (obj as any).state === 'string' &&
|
|
211
|
+
typeof (obj as any).properties === 'object' &&
|
|
212
|
+
typeof (obj as any).permittedOperations === 'object'
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function isPRActivity(obj: unknown): obj is PRActivity {
|
|
217
|
+
return (
|
|
218
|
+
typeof obj === 'object' &&
|
|
219
|
+
obj !== null &&
|
|
220
|
+
typeof (obj as any).id === 'number' &&
|
|
221
|
+
typeof (obj as any).createdDate === 'number' &&
|
|
222
|
+
isBitbucketUser((obj as any).user) &&
|
|
223
|
+
typeof (obj as any).action === 'string'
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function simplifyUser(user: BitbucketUser): SimplifiedUser {
|
|
228
|
+
return {
|
|
229
|
+
name: user.name,
|
|
230
|
+
displayName: user.displayName
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function simplifyAnchor(anchor: CommentAnchor): SimplifiedAnchor {
|
|
235
|
+
return {
|
|
236
|
+
line: anchor.line,
|
|
237
|
+
path: anchor.path,
|
|
238
|
+
fileType: anchor.fileType
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function simplifyComment(comment: Comment): SimplifiedComment {
|
|
243
|
+
return {
|
|
244
|
+
id: comment.id,
|
|
245
|
+
text: comment.text,
|
|
246
|
+
author: simplifyUser(comment.author),
|
|
247
|
+
createdDate: comment.createdDate,
|
|
248
|
+
...(comment.anchor && { anchor: simplifyAnchor(comment.anchor) }),
|
|
249
|
+
threadResolved: comment.threadResolved,
|
|
250
|
+
state: comment.state
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function simplifyActivity(activity: PRActivity): SimplifiedActivity {
|
|
255
|
+
return {
|
|
256
|
+
id: activity.id,
|
|
257
|
+
createdDate: activity.createdDate,
|
|
258
|
+
user: simplifyUser(activity.user),
|
|
259
|
+
action: activity.action,
|
|
260
|
+
...(activity.commentAction && { commentAction: activity.commentAction }),
|
|
261
|
+
...(activity.comment && { comment: simplifyComment(activity.comment) })
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
export function simplifyBitbucketPRComments(response: BitbucketPRApiResponse): SimplifiedPRResponse | BitbucketPRApiResponse {
|
|
266
|
+
const activities: SimplifiedActivity[] = [];
|
|
267
|
+
|
|
268
|
+
// Process each activity with type guard validation
|
|
269
|
+
for (const activity of response.values || []) {
|
|
270
|
+
if (isPRActivity(activity)) {
|
|
271
|
+
activities.push(simplifyActivity(activity));
|
|
272
|
+
}
|
|
273
|
+
// If type guard fails, we skip the invalid activity but continue processing
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// If no valid activities were found, return the original response
|
|
277
|
+
if (activities.length === 0 && (response.values || []).length > 0) {
|
|
278
|
+
return response;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Find PR author (usually the one who OPENED the PR)
|
|
282
|
+
const prAuthor = activities.find(a => a.action === 'OPENED')?.user;
|
|
283
|
+
|
|
284
|
+
// Count comments and unresolved threads
|
|
285
|
+
const comments = activities.filter(a => a.action === 'COMMENTED' && a.comment);
|
|
286
|
+
const unresolvedCount = comments.filter(a => a.comment && !a.comment.threadResolved).length;
|
|
287
|
+
|
|
288
|
+
return {
|
|
289
|
+
isLastPage: response.isLastPage ?? true,
|
|
290
|
+
activities,
|
|
291
|
+
summary: {
|
|
292
|
+
totalActivities: activities.length,
|
|
293
|
+
...(prAuthor && { prAuthor }),
|
|
294
|
+
commentCount: comments.length,
|
|
295
|
+
unresolvedCount
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
export function getCommentSummary(response: BitbucketPRApiResponse): string[] {
|
|
301
|
+
const commentSummaries: string[] = [];
|
|
302
|
+
|
|
303
|
+
for (const activity of response.values || []) {
|
|
304
|
+
// Use type guard to validate activity structure
|
|
305
|
+
if (isPRActivity(activity) && activity.action === 'COMMENTED' && activity.comment) {
|
|
306
|
+
// Additional validation for comment structure
|
|
307
|
+
if (isComment(activity.comment)) {
|
|
308
|
+
const comment = activity.comment;
|
|
309
|
+
commentSummaries.push(
|
|
310
|
+
`${comment.author.displayName} on ${comment.anchor?.path || 'PR'}:${comment.anchor?.line || ''}: ${comment.text}`
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
// If type guard fails, we skip the invalid activity but continue processing
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return commentSummaries;
|
|
318
|
+
}
|