@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
package/src/bitbucket-service.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { OpenAPI, ProjectService, PullRequestsService, RepositoryService } from './bitbucket-client/index.js';
|
|
3
|
+
import { request as __request } from './bitbucket-client/core/request.js';
|
|
3
4
|
import { handleApiOperation } from '@atlassian-dc-mcp/common';
|
|
5
|
+
import { simplifyBitbucketPRComments } from './pr-comment-mapper.js';
|
|
6
|
+
import { simplifyBitbucketPRChanges } from './pr-changes-mapper.js';
|
|
4
7
|
|
|
5
8
|
export class BitbucketService {
|
|
6
9
|
constructor(host: string, token: string, fullBaseUrl?: string) {
|
|
@@ -99,7 +102,7 @@ export class BitbucketService {
|
|
|
99
102
|
async getPullRequestCommentsAndActions(projectKey: string, repositorySlug: string, pullRequestId: string, start?: number,
|
|
100
103
|
limit: number = 25
|
|
101
104
|
) {
|
|
102
|
-
|
|
105
|
+
const result = await handleApiOperation(
|
|
103
106
|
() => PullRequestsService.getActivities(
|
|
104
107
|
projectKey,
|
|
105
108
|
pullRequestId,
|
|
@@ -110,7 +113,184 @@ export class BitbucketService {
|
|
|
110
113
|
limit
|
|
111
114
|
),
|
|
112
115
|
'Error fetching pull request comments'
|
|
113
|
-
)
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
// Apply simplification if the API call was successful
|
|
119
|
+
if (result.success && result.data) {
|
|
120
|
+
const simplifiedData = simplifyBitbucketPRComments(result.data);
|
|
121
|
+
return {
|
|
122
|
+
success: true,
|
|
123
|
+
data: simplifiedData
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return result;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Get pull request changes
|
|
132
|
+
* @param projectKey The project key
|
|
133
|
+
* @param repositorySlug The repository slug
|
|
134
|
+
* @param pullRequestId The pull request ID
|
|
135
|
+
* @param sinceId Optional since commit hash to stream changes for a RANGE arbitrary change scope
|
|
136
|
+
* @param changeScope Optional scope: 'UNREVIEWED' for unreviewed changes, 'RANGE' for changes between commits, 'ALL' for all changes (default)
|
|
137
|
+
* @param untilId Optional until commit hash to stream changes for a RANGE arbitrary change scope
|
|
138
|
+
* @param withComments Optional flag to include comment counts (default: true)
|
|
139
|
+
* @param start Optional pagination start
|
|
140
|
+
* @param limit Optional pagination limit (default: 25)
|
|
141
|
+
* @returns Promise with PR changes data
|
|
142
|
+
*/
|
|
143
|
+
async getPullRequestChanges(
|
|
144
|
+
projectKey: string,
|
|
145
|
+
repositorySlug: string,
|
|
146
|
+
pullRequestId: string,
|
|
147
|
+
sinceId?: string,
|
|
148
|
+
changeScope?: string,
|
|
149
|
+
untilId?: string,
|
|
150
|
+
withComments?: string,
|
|
151
|
+
start?: number,
|
|
152
|
+
limit: number = 25
|
|
153
|
+
) {
|
|
154
|
+
const result = await handleApiOperation(
|
|
155
|
+
() => PullRequestsService.streamChanges1(
|
|
156
|
+
projectKey,
|
|
157
|
+
pullRequestId,
|
|
158
|
+
repositorySlug,
|
|
159
|
+
sinceId,
|
|
160
|
+
changeScope,
|
|
161
|
+
untilId,
|
|
162
|
+
withComments,
|
|
163
|
+
start,
|
|
164
|
+
limit
|
|
165
|
+
),
|
|
166
|
+
'Error fetching pull request changes'
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
// Apply simplification if the API call was successful
|
|
170
|
+
if (result.success && result.data) {
|
|
171
|
+
const simplifiedData = simplifyBitbucketPRChanges(result.data);
|
|
172
|
+
return {
|
|
173
|
+
...result,
|
|
174
|
+
data: simplifiedData
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return result;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Post a comment to a pull request
|
|
183
|
+
* @param projectKey The project key
|
|
184
|
+
* @param repositorySlug The repository slug
|
|
185
|
+
* @param pullRequestId The pull request ID
|
|
186
|
+
* @param text The comment text
|
|
187
|
+
* @param parentId Optional parent comment ID for replies
|
|
188
|
+
* @param filePath Optional file path for file-specific comments
|
|
189
|
+
* @param line Optional line number for line-specific comments
|
|
190
|
+
* @param lineType Optional line type ('ADDED', 'REMOVED', 'CONTEXT') for line comments
|
|
191
|
+
* @returns Promise with created comment data
|
|
192
|
+
*/
|
|
193
|
+
async postPullRequestComment(
|
|
194
|
+
projectKey: string,
|
|
195
|
+
repositorySlug: string,
|
|
196
|
+
pullRequestId: string,
|
|
197
|
+
text: string,
|
|
198
|
+
parentId?: number,
|
|
199
|
+
filePath?: string,
|
|
200
|
+
line?: number,
|
|
201
|
+
lineType?: 'ADDED' | 'REMOVED' | 'CONTEXT'
|
|
202
|
+
) {
|
|
203
|
+
const comment: any = {
|
|
204
|
+
text
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
// Add parent reference for replies
|
|
208
|
+
if (parentId) {
|
|
209
|
+
comment.parent = { id: parentId };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Add anchor for file/line comments
|
|
213
|
+
if (filePath) {
|
|
214
|
+
comment.anchor = {
|
|
215
|
+
path: filePath,
|
|
216
|
+
diffType: 'EFFECTIVE'
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
// Add line-specific anchor properties
|
|
220
|
+
if (line !== undefined && lineType) {
|
|
221
|
+
comment.anchor.line = line;
|
|
222
|
+
comment.anchor.lineType = lineType;
|
|
223
|
+
comment.anchor.fileType = 'TO'; // Default to destination file
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return handleApiOperation(
|
|
228
|
+
() => PullRequestsService.createComment2(
|
|
229
|
+
projectKey,
|
|
230
|
+
pullRequestId,
|
|
231
|
+
repositorySlug,
|
|
232
|
+
comment
|
|
233
|
+
),
|
|
234
|
+
'Error posting pull request comment'
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Get text diff for a specific file in a pull request
|
|
241
|
+
* @param projectKey The project key
|
|
242
|
+
* @param repositorySlug The repository slug
|
|
243
|
+
* @param pullRequestId The pull request ID
|
|
244
|
+
* @param path The path to the file which should be diffed
|
|
245
|
+
* @param contextLines Optional number of context lines to include around added/removed lines
|
|
246
|
+
* @param sinceId Optional since commit hash to stream a diff between two arbitrary hashes
|
|
247
|
+
* @param srcPath Optional previous path to the file, if the file has been copied, moved or renamed
|
|
248
|
+
* @param diffType Optional type of diff being requested
|
|
249
|
+
* @param untilId Optional until commit hash to stream a diff between two arbitrary hashes
|
|
250
|
+
* @param whitespace Optional whitespace flag which can be set to 'ignore-all'
|
|
251
|
+
* @returns Promise with text diff data
|
|
252
|
+
*/
|
|
253
|
+
async getPullRequestDiff(
|
|
254
|
+
projectKey: string,
|
|
255
|
+
repositorySlug: string,
|
|
256
|
+
pullRequestId: string,
|
|
257
|
+
path: string,
|
|
258
|
+
contextLines?: string,
|
|
259
|
+
sinceId?: string,
|
|
260
|
+
srcPath?: string,
|
|
261
|
+
diffType?: string,
|
|
262
|
+
untilId?: string,
|
|
263
|
+
whitespace?: string
|
|
264
|
+
) {
|
|
265
|
+
return handleApiOperation(
|
|
266
|
+
() => __request(OpenAPI, {
|
|
267
|
+
method: 'GET',
|
|
268
|
+
url: '/api/latest/projects/{projectKey}/repos/{repositorySlug}/pull-requests/{pullRequestId}/diff/{path}',
|
|
269
|
+
path: {
|
|
270
|
+
'path': path,
|
|
271
|
+
'projectKey': projectKey,
|
|
272
|
+
'pullRequestId': pullRequestId,
|
|
273
|
+
'repositorySlug': repositorySlug,
|
|
274
|
+
},
|
|
275
|
+
query: {
|
|
276
|
+
'contextLines': contextLines,
|
|
277
|
+
'sinceId': sinceId,
|
|
278
|
+
'srcPath': srcPath,
|
|
279
|
+
'diffType': diffType,
|
|
280
|
+
'untilId': untilId,
|
|
281
|
+
'whitespace': whitespace,
|
|
282
|
+
},
|
|
283
|
+
headers: {
|
|
284
|
+
'Accept': 'text/plain'
|
|
285
|
+
},
|
|
286
|
+
errors: {
|
|
287
|
+
400: `If the request was malformed.`,
|
|
288
|
+
401: `The currently authenticated user has insufficient permissions to view the repository or pull request.`,
|
|
289
|
+
404: `The repository or pull request does not exist.`,
|
|
290
|
+
},
|
|
291
|
+
}),
|
|
292
|
+
'Error fetching pull request diff'
|
|
293
|
+
);
|
|
114
294
|
}
|
|
115
295
|
|
|
116
296
|
static validateConfig(): string[] {
|
|
@@ -160,5 +340,38 @@ export const bitbucketToolSchemas = {
|
|
|
160
340
|
pullRequestId: z.string().describe("The pull request ID"),
|
|
161
341
|
start: z.number().optional().describe("Start number for pagination"),
|
|
162
342
|
limit: z.number().optional().default(25).describe("Number of items to return")
|
|
343
|
+
},
|
|
344
|
+
getPullRequestChanges: {
|
|
345
|
+
projectKey: z.string().describe("The project key"),
|
|
346
|
+
repositorySlug: z.string().describe("The repository slug"),
|
|
347
|
+
pullRequestId: z.string().describe("The pull request ID"),
|
|
348
|
+
sinceId: z.string().optional().describe("The since commit hash to stream changes for a RANGE arbitrary change scope"),
|
|
349
|
+
changeScope: z.string().optional().describe("UNREVIEWED for unreviewed changes, RANGE for changes between commits, ALL for all changes (default)"),
|
|
350
|
+
untilId: z.string().optional().describe("The until commit hash to stream changes for a RANGE arbitrary change scope"),
|
|
351
|
+
withComments: z.string().optional().describe("true to apply comment counts in the changes (default), false to stream changes without comment counts"),
|
|
352
|
+
start: z.number().optional().describe("Start number for pagination"),
|
|
353
|
+
limit: z.number().optional().default(25).describe("Number of items to return")
|
|
354
|
+
},
|
|
355
|
+
postPullRequestComment: {
|
|
356
|
+
projectKey: z.string().describe("The project key"),
|
|
357
|
+
repositorySlug: z.string().describe("The repository slug"),
|
|
358
|
+
pullRequestId: z.string().describe("The pull request ID"),
|
|
359
|
+
text: z.string().describe("The comment text"),
|
|
360
|
+
parentId: z.number().optional().describe("Parent comment ID for replies"),
|
|
361
|
+
filePath: z.string().optional().describe("File path for file-specific comments"),
|
|
362
|
+
line: z.number().optional().describe("Line number for line-specific comments"),
|
|
363
|
+
lineType: z.enum(['ADDED', 'REMOVED', 'CONTEXT']).optional().describe("Line type for line comments")
|
|
364
|
+
},
|
|
365
|
+
getPullRequestDiff: {
|
|
366
|
+
projectKey: z.string().describe("The project key"),
|
|
367
|
+
repositorySlug: z.string().describe("The repository slug"),
|
|
368
|
+
pullRequestId: z.string().describe("The pull request ID"),
|
|
369
|
+
path: z.string().describe("The path to the file which should be diffed. Note: Before getting diff, use getPullRequestChanges to understand what files were changed in the PR"),
|
|
370
|
+
contextLines: z.string().optional().describe("Number of context lines to include around added/removed lines in the diff"),
|
|
371
|
+
sinceId: z.string().optional().describe("The since commit hash to stream a diff between two arbitrary hashes"),
|
|
372
|
+
srcPath: z.string().optional().describe("The previous path to the file, if the file has been copied, moved or renamed"),
|
|
373
|
+
diffType: z.string().optional().describe("The type of diff being requested"),
|
|
374
|
+
untilId: z.string().optional().describe("The until commit hash to stream a diff between two arbitrary hashes"),
|
|
375
|
+
whitespace: z.string().optional().describe("Optional whitespace flag which can be set to 'ignore-all'")
|
|
163
376
|
}
|
|
164
377
|
};
|
package/src/index.ts
CHANGED
|
@@ -73,13 +73,44 @@ server.tool(
|
|
|
73
73
|
);
|
|
74
74
|
|
|
75
75
|
server.tool(
|
|
76
|
-
"
|
|
76
|
+
"bitbucket_getPR_CommentsAndAction",
|
|
77
77
|
"Get comments for a Bitbucket pull request and other actions, like approvals",
|
|
78
78
|
bitbucketToolSchemas.getPullRequestComments,
|
|
79
79
|
async ({ projectKey, repositorySlug, pullRequestId, start, limit }) => {
|
|
80
80
|
const result = await bitbucketService.getPullRequestCommentsAndActions(projectKey, repositorySlug, pullRequestId, start, limit);
|
|
81
81
|
return formatToolResponse(result);
|
|
82
82
|
}
|
|
83
|
-
)
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
server.tool(
|
|
86
|
+
"bitbucket_getPullRequestChanges",
|
|
87
|
+
"Get the changes for a Bitbucket pull request",
|
|
88
|
+
bitbucketToolSchemas.getPullRequestChanges,
|
|
89
|
+
async ({ projectKey, repositorySlug, pullRequestId, sinceId, changeScope, untilId, withComments, start, limit }) => {
|
|
90
|
+
const result = await bitbucketService.getPullRequestChanges(projectKey, repositorySlug, pullRequestId, sinceId, changeScope, untilId, withComments, start, limit);
|
|
91
|
+
return formatToolResponse(result);
|
|
92
|
+
}
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
server.tool(
|
|
96
|
+
"bitbucket_postPullRequestComment",
|
|
97
|
+
"Post a comment to a Bitbucket pull request",
|
|
98
|
+
bitbucketToolSchemas.postPullRequestComment,
|
|
99
|
+
async ({ projectKey, repositorySlug, pullRequestId, text, parentId, filePath, line, lineType }) => {
|
|
100
|
+
const result = await bitbucketService.postPullRequestComment(projectKey, repositorySlug, pullRequestId, text, parentId, filePath, line, lineType);
|
|
101
|
+
return formatToolResponse(result);
|
|
102
|
+
}
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
server.tool(
|
|
107
|
+
"bitbucket_getPullRequestDiff",
|
|
108
|
+
"Get text diff for a specific file in a Bitbucket pull request. Returns plain text diff format. Note: Before getting diff, use getPullRequestChanges to understand what files were changed in the PR",
|
|
109
|
+
bitbucketToolSchemas.getPullRequestDiff,
|
|
110
|
+
async ({ projectKey, repositorySlug, pullRequestId, path, contextLines, sinceId, srcPath, diffType, untilId, whitespace }) => {
|
|
111
|
+
const result = await bitbucketService.getPullRequestDiff(projectKey, repositorySlug, pullRequestId, path, contextLines, sinceId, srcPath, diffType, untilId, whitespace);
|
|
112
|
+
return formatToolResponse(result);
|
|
113
|
+
}
|
|
114
|
+
);
|
|
84
115
|
|
|
85
116
|
await connectServer(server);
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
// Original API response interfaces
|
|
2
|
+
interface PathInfo {
|
|
3
|
+
components: string[];
|
|
4
|
+
parent: string;
|
|
5
|
+
name: string;
|
|
6
|
+
extension: string;
|
|
7
|
+
toString: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface ChangeProperties {
|
|
11
|
+
gitChangeType: string;
|
|
12
|
+
orphanedComments?: number;
|
|
13
|
+
activeComments?: number;
|
|
14
|
+
changeScope?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface ChangeLinks {
|
|
18
|
+
self: (null | string)[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface PRChange {
|
|
22
|
+
contentId: string;
|
|
23
|
+
fromContentId: string;
|
|
24
|
+
path: PathInfo;
|
|
25
|
+
srcPath?: PathInfo;
|
|
26
|
+
percentUnchanged?: number;
|
|
27
|
+
type: string;
|
|
28
|
+
nodeType?: string;
|
|
29
|
+
executable?: boolean;
|
|
30
|
+
srcExecutable?: boolean;
|
|
31
|
+
links?: ChangeLinks;
|
|
32
|
+
properties: ChangeProperties;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface PRChangesResponse {
|
|
36
|
+
fromHash: string;
|
|
37
|
+
toHash: string;
|
|
38
|
+
properties: {
|
|
39
|
+
changeScope: string;
|
|
40
|
+
};
|
|
41
|
+
values: PRChange[];
|
|
42
|
+
size: number;
|
|
43
|
+
isLastPage: boolean;
|
|
44
|
+
start: number;
|
|
45
|
+
limit: number;
|
|
46
|
+
nextPageStart: number | null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Simplified interfaces
|
|
50
|
+
interface SimplifiedPath {
|
|
51
|
+
name: string;
|
|
52
|
+
path: string;
|
|
53
|
+
extension?: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
interface SimplifiedChange {
|
|
57
|
+
contentId: string;
|
|
58
|
+
path: SimplifiedPath;
|
|
59
|
+
srcPath?: SimplifiedPath;
|
|
60
|
+
type: string;
|
|
61
|
+
gitChangeType: string;
|
|
62
|
+
comments?: number;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
interface SimplifiedPRChangesResponse {
|
|
66
|
+
fromHash: string;
|
|
67
|
+
toHash: string;
|
|
68
|
+
changeScope: string;
|
|
69
|
+
changes: SimplifiedChange[];
|
|
70
|
+
summary: {
|
|
71
|
+
totalChanges: number;
|
|
72
|
+
additions: number;
|
|
73
|
+
deletions: number;
|
|
74
|
+
modifications: number;
|
|
75
|
+
moves: number;
|
|
76
|
+
filesWithComments: number;
|
|
77
|
+
};
|
|
78
|
+
isLastPage: boolean;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Type guards
|
|
82
|
+
function isPathInfo(obj: unknown): obj is PathInfo {
|
|
83
|
+
return (
|
|
84
|
+
typeof obj === 'object' &&
|
|
85
|
+
obj !== null &&
|
|
86
|
+
Array.isArray((obj as any).components) &&
|
|
87
|
+
typeof (obj as any).name === 'string' &&
|
|
88
|
+
typeof (obj as any).toString === 'string'
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function isPRChange(obj: unknown): obj is PRChange {
|
|
93
|
+
return (
|
|
94
|
+
typeof obj === 'object' &&
|
|
95
|
+
obj !== null &&
|
|
96
|
+
typeof (obj as any).contentId === 'string' &&
|
|
97
|
+
typeof (obj as any).type === 'string' &&
|
|
98
|
+
isPathInfo((obj as any).path) &&
|
|
99
|
+
typeof (obj as any).properties === 'object' &&
|
|
100
|
+
typeof (obj as any).properties.gitChangeType === 'string'
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function isPRChangesResponse(obj: unknown): obj is PRChangesResponse {
|
|
105
|
+
return (
|
|
106
|
+
typeof obj === 'object' &&
|
|
107
|
+
obj !== null &&
|
|
108
|
+
typeof (obj as any).fromHash === 'string' &&
|
|
109
|
+
typeof (obj as any).toHash === 'string' &&
|
|
110
|
+
Array.isArray((obj as any).values) &&
|
|
111
|
+
typeof (obj as any).isLastPage === 'boolean'
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Transformation functions
|
|
116
|
+
function simplifyPath(path: PathInfo): SimplifiedPath {
|
|
117
|
+
return {
|
|
118
|
+
name: path.name,
|
|
119
|
+
path: path.toString,
|
|
120
|
+
...(path.extension && { extension: path.extension })
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function simplifyChange(change: PRChange): SimplifiedChange {
|
|
125
|
+
const result: SimplifiedChange = {
|
|
126
|
+
contentId: change.contentId,
|
|
127
|
+
path: simplifyPath(change.path),
|
|
128
|
+
type: change.type,
|
|
129
|
+
gitChangeType: change.properties.gitChangeType
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
// Add source path for moves/renames
|
|
133
|
+
if (change.srcPath) {
|
|
134
|
+
result.srcPath = simplifyPath(change.srcPath);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Add comment count if present
|
|
138
|
+
const commentCount = (change.properties.orphanedComments || 0) + (change.properties.activeComments || 0);
|
|
139
|
+
if (commentCount > 0) {
|
|
140
|
+
result.comments = commentCount;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function simplifyBitbucketPRChanges(response: any): SimplifiedPRChangesResponse | any {
|
|
147
|
+
// Validate response structure
|
|
148
|
+
if (!isPRChangesResponse(response)) {
|
|
149
|
+
return response;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const changes: SimplifiedChange[] = [];
|
|
153
|
+
|
|
154
|
+
// Process each change with type guard validation
|
|
155
|
+
for (const change of response.values || []) {
|
|
156
|
+
if (isPRChange(change)) {
|
|
157
|
+
changes.push(simplifyChange(change));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// If no valid changes were found, return the original response
|
|
162
|
+
if (changes.length === 0 && (response.values || []).length > 0) {
|
|
163
|
+
return response;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Calculate summary statistics
|
|
167
|
+
const additions = changes.filter(c => c.type === 'ADD').length;
|
|
168
|
+
const deletions = changes.filter(c => c.type === 'DELETE').length;
|
|
169
|
+
const modifications = changes.filter(c => c.type === 'MODIFY').length;
|
|
170
|
+
const moves = changes.filter(c => c.type === 'MOVE').length;
|
|
171
|
+
const filesWithComments = changes.filter(c => c.comments && c.comments > 0).length;
|
|
172
|
+
|
|
173
|
+
return {
|
|
174
|
+
fromHash: response.fromHash,
|
|
175
|
+
toHash: response.toHash,
|
|
176
|
+
changeScope: response.properties.changeScope,
|
|
177
|
+
changes,
|
|
178
|
+
summary: {
|
|
179
|
+
totalChanges: changes.length,
|
|
180
|
+
additions,
|
|
181
|
+
deletions,
|
|
182
|
+
modifications,
|
|
183
|
+
moves,
|
|
184
|
+
filesWithComments
|
|
185
|
+
},
|
|
186
|
+
isLastPage: response.isLastPage
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export function getChangesSummary(response: any): string[] {
|
|
191
|
+
const changeSummaries: string[] = [];
|
|
192
|
+
|
|
193
|
+
for (const change of response.values || []) {
|
|
194
|
+
if (isPRChange(change)) {
|
|
195
|
+
const action = change.type === 'ADD' ? 'Added' :
|
|
196
|
+
change.type === 'DELETE' ? 'Deleted' :
|
|
197
|
+
change.type === 'MODIFY' ? 'Modified' :
|
|
198
|
+
change.type === 'MOVE' ? 'Moved' : change.type;
|
|
199
|
+
|
|
200
|
+
let summary = `${action}: ${change.path.toString}`;
|
|
201
|
+
|
|
202
|
+
if (change.srcPath && change.type === 'MOVE') {
|
|
203
|
+
summary += ` (from ${change.srcPath.toString})`;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const commentCount = (change.properties.orphanedComments || 0) + (change.properties.activeComments || 0);
|
|
207
|
+
if (commentCount > 0) {
|
|
208
|
+
summary += ` [${commentCount} comment${commentCount > 1 ? 's' : ''}]`;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
changeSummaries.push(summary);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return changeSummaries;
|
|
216
|
+
}
|