@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.
Files changed (37) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/build/__tests__/bitbucket-service.test.d.ts +2 -0
  3. package/build/__tests__/bitbucket-service.test.d.ts.map +1 -0
  4. package/build/__tests__/bitbucket-service.test.js +269 -0
  5. package/build/__tests__/bitbucket-service.test.js.map +1 -0
  6. package/build/__tests__/pr-changes-mapper.test.d.ts +2 -0
  7. package/build/__tests__/pr-changes-mapper.test.d.ts.map +1 -0
  8. package/build/__tests__/pr-changes-mapper.test.js +396 -0
  9. package/build/__tests__/pr-changes-mapper.test.js.map +1 -0
  10. package/build/__tests__/pr-comment-mapper.test.d.ts +2 -0
  11. package/build/__tests__/pr-comment-mapper.test.d.ts.map +1 -0
  12. package/build/__tests__/pr-comment-mapper.test.js +210 -0
  13. package/build/__tests__/pr-comment-mapper.test.js.map +1 -0
  14. package/build/bitbucket-service.d.ts +84 -1
  15. package/build/bitbucket-service.d.ts.map +1 -1
  16. package/build/bitbucket-service.js +148 -1
  17. package/build/bitbucket-service.js.map +1 -1
  18. package/build/index.js +13 -1
  19. package/build/index.js.map +1 -1
  20. package/build/pr-changes-mapper.d.ts +32 -0
  21. package/build/pr-changes-mapper.d.ts.map +1 -0
  22. package/build/pr-changes-mapper.js +111 -0
  23. package/build/pr-changes-mapper.js.map +1 -0
  24. package/build/pr-comment-mapper.d.ts +48 -0
  25. package/build/pr-comment-mapper.d.ts.map +1 -0
  26. package/build/pr-comment-mapper.js +128 -0
  27. package/build/pr-comment-mapper.js.map +1 -0
  28. package/jest.config.js +23 -0
  29. package/package.json +5 -3
  30. package/src/__tests__/bitbucket-service.test.ts +419 -0
  31. package/src/__tests__/pr-changes-mapper.test.ts +420 -0
  32. package/src/__tests__/pr-comment-mapper.test.ts +230 -0
  33. package/src/bitbucket-service.ts +215 -2
  34. package/src/index.ts +33 -2
  35. package/src/pr-changes-mapper.ts +216 -0
  36. package/src/pr-comment-mapper.ts +318 -0
  37. 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
+ }