@atercates/bitbucket-mcp 1.0.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/LICENSE +21 -0
- package/README.md +347 -0
- package/dist/client.d.ts +16 -0
- package/dist/client.js +35 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +11 -0
- package/dist/config.js +54 -0
- package/dist/config.js.map +1 -0
- package/dist/handlers/branching-model.d.ts +2 -0
- package/dist/handlers/branching-model.js +324 -0
- package/dist/handlers/branching-model.js.map +1 -0
- package/dist/handlers/commits.d.ts +2 -0
- package/dist/handlers/commits.js +78 -0
- package/dist/handlers/commits.js.map +1 -0
- package/dist/handlers/index.d.ts +17 -0
- package/dist/handlers/index.js +29 -0
- package/dist/handlers/index.js.map +1 -0
- package/dist/handlers/pipelines.d.ts +2 -0
- package/dist/handlers/pipelines.js +538 -0
- package/dist/handlers/pipelines.js.map +1 -0
- package/dist/handlers/pr-comments.d.ts +2 -0
- package/dist/handlers/pr-comments.js +509 -0
- package/dist/handlers/pr-comments.js.map +1 -0
- package/dist/handlers/pr-content.d.ts +2 -0
- package/dist/handlers/pr-content.js +332 -0
- package/dist/handlers/pr-content.js.map +1 -0
- package/dist/handlers/pr-tasks.d.ts +2 -0
- package/dist/handlers/pr-tasks.js +275 -0
- package/dist/handlers/pr-tasks.js.map +1 -0
- package/dist/handlers/pull-requests.d.ts +2 -0
- package/dist/handlers/pull-requests.js +902 -0
- package/dist/handlers/pull-requests.js.map +1 -0
- package/dist/handlers/refs.d.ts +2 -0
- package/dist/handlers/refs.js +225 -0
- package/dist/handlers/refs.js.map +1 -0
- package/dist/handlers/repositories.d.ts +2 -0
- package/dist/handlers/repositories.js +131 -0
- package/dist/handlers/repositories.js.map +1 -0
- package/dist/handlers/source.d.ts +2 -0
- package/dist/handlers/source.js +35 -0
- package/dist/handlers/source.js.map +1 -0
- package/dist/handlers/types.d.ts +42 -0
- package/dist/handlers/types.js +2 -0
- package/dist/handlers/types.js.map +1 -0
- package/dist/handlers/users.d.ts +2 -0
- package/dist/handlers/users.js +38 -0
- package/dist/handlers/users.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +3 -0
- package/dist/logger.js +60 -0
- package/dist/logger.js.map +1 -0
- package/dist/pagination.d.ts +32 -0
- package/dist/pagination.js +116 -0
- package/dist/pagination.js.map +1 -0
- package/dist/schemas.d.ts +21 -0
- package/dist/schemas.js +23 -0
- package/dist/schemas.js.map +1 -0
- package/dist/server.d.ts +33 -0
- package/dist/server.js +124 -0
- package/dist/server.js.map +1 -0
- package/dist/types.d.ts +296 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +18 -0
- package/dist/utils.js +17 -0
- package/dist/utils.js.map +1 -0
- package/docs/README.md +216 -0
- package/docs/TOOLS.md +464 -0
- package/docs/architecture/ARCHITECTURE.md +302 -0
- package/docs/guides/ENVIRONMENT_VARIABLES.md +306 -0
- package/docs/guides/GETTING_STARTED.md +267 -0
- package/docs/guides/GITHUB_ACTIONS_SETUP.md +148 -0
- package/docs/guides/NPM_DEPLOYMENT.md +266 -0
- package/docs/guides/PROJECT_STRUCTURE.md +317 -0
- package/package.json +84 -0
|
@@ -0,0 +1,902 @@
|
|
|
1
|
+
import { PAGINATION_BASE_SCHEMA, PAGINATION_ALL_SCHEMA, LEGACY_LIMIT_SCHEMA } from "../schemas.js";
|
|
2
|
+
import { jsonResponse, textResponse } from "../utils.js";
|
|
3
|
+
import { logger } from "../logger.js";
|
|
4
|
+
import { ErrorCode, McpError } from "@modelcontextprotocol/sdk/types.js";
|
|
5
|
+
import { BITBUCKET_MAX_PAGELEN } from "../pagination.js";
|
|
6
|
+
export const pullRequestsModule = {
|
|
7
|
+
tools: [
|
|
8
|
+
{
|
|
9
|
+
name: "getPullRequests",
|
|
10
|
+
description: "Get pull requests for a repository",
|
|
11
|
+
inputSchema: {
|
|
12
|
+
type: "object",
|
|
13
|
+
properties: {
|
|
14
|
+
workspace: {
|
|
15
|
+
type: "string",
|
|
16
|
+
description: "Bitbucket workspace name",
|
|
17
|
+
},
|
|
18
|
+
repo_slug: { type: "string", description: "Repository slug" },
|
|
19
|
+
state: {
|
|
20
|
+
type: "string",
|
|
21
|
+
enum: ["OPEN", "MERGED", "DECLINED", "SUPERSEDED"],
|
|
22
|
+
description: "Pull request state",
|
|
23
|
+
},
|
|
24
|
+
...PAGINATION_BASE_SCHEMA,
|
|
25
|
+
all: PAGINATION_ALL_SCHEMA,
|
|
26
|
+
limit: LEGACY_LIMIT_SCHEMA,
|
|
27
|
+
},
|
|
28
|
+
required: ["workspace", "repo_slug"],
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: "createPullRequest",
|
|
33
|
+
description: "Create a new pull request",
|
|
34
|
+
inputSchema: {
|
|
35
|
+
type: "object",
|
|
36
|
+
properties: {
|
|
37
|
+
workspace: {
|
|
38
|
+
type: "string",
|
|
39
|
+
description: "Bitbucket workspace name",
|
|
40
|
+
},
|
|
41
|
+
repo_slug: { type: "string", description: "Repository slug" },
|
|
42
|
+
title: { type: "string", description: "Pull request title" },
|
|
43
|
+
description: {
|
|
44
|
+
type: "string",
|
|
45
|
+
description: "Pull request description",
|
|
46
|
+
},
|
|
47
|
+
sourceBranch: {
|
|
48
|
+
type: "string",
|
|
49
|
+
description: "Source branch name",
|
|
50
|
+
},
|
|
51
|
+
targetBranch: {
|
|
52
|
+
type: "string",
|
|
53
|
+
description: "Target branch name",
|
|
54
|
+
},
|
|
55
|
+
reviewers: {
|
|
56
|
+
type: "array",
|
|
57
|
+
items: { type: "string" },
|
|
58
|
+
description: "List of reviewer UUIDs (e.g., '{04776764-62c7-453b-b97e-302f60395ceb}')",
|
|
59
|
+
},
|
|
60
|
+
draft: {
|
|
61
|
+
type: "boolean",
|
|
62
|
+
description: "Whether to create the pull request as a draft",
|
|
63
|
+
},
|
|
64
|
+
close_source_branch: {
|
|
65
|
+
type: "boolean",
|
|
66
|
+
description: "Whether to close source branch after merge (default: true)",
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
required: [
|
|
70
|
+
"workspace",
|
|
71
|
+
"repo_slug",
|
|
72
|
+
"title",
|
|
73
|
+
"description",
|
|
74
|
+
"sourceBranch",
|
|
75
|
+
"targetBranch",
|
|
76
|
+
],
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: "getPullRequest",
|
|
81
|
+
description: "Get details for a specific pull request",
|
|
82
|
+
inputSchema: {
|
|
83
|
+
type: "object",
|
|
84
|
+
properties: {
|
|
85
|
+
workspace: {
|
|
86
|
+
type: "string",
|
|
87
|
+
description: "Bitbucket workspace name",
|
|
88
|
+
},
|
|
89
|
+
repo_slug: { type: "string", description: "Repository slug" },
|
|
90
|
+
pull_request_id: {
|
|
91
|
+
type: "string",
|
|
92
|
+
description: "Pull request ID",
|
|
93
|
+
},
|
|
94
|
+
...PAGINATION_BASE_SCHEMA,
|
|
95
|
+
all: PAGINATION_ALL_SCHEMA,
|
|
96
|
+
},
|
|
97
|
+
required: ["workspace", "repo_slug", "pull_request_id"],
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
name: "updatePullRequest",
|
|
102
|
+
description: "Update a pull request",
|
|
103
|
+
inputSchema: {
|
|
104
|
+
type: "object",
|
|
105
|
+
properties: {
|
|
106
|
+
workspace: {
|
|
107
|
+
type: "string",
|
|
108
|
+
description: "Bitbucket workspace name",
|
|
109
|
+
},
|
|
110
|
+
repo_slug: { type: "string", description: "Repository slug" },
|
|
111
|
+
pull_request_id: {
|
|
112
|
+
type: "string",
|
|
113
|
+
description: "Pull request ID",
|
|
114
|
+
},
|
|
115
|
+
title: { type: "string", description: "New pull request title" },
|
|
116
|
+
description: {
|
|
117
|
+
type: "string",
|
|
118
|
+
description: "New pull request description",
|
|
119
|
+
},
|
|
120
|
+
reviewers: {
|
|
121
|
+
type: "array",
|
|
122
|
+
items: { type: "string" },
|
|
123
|
+
description: "List of reviewer UUIDs (e.g., '{04776764-62c7-453b-b97e-302f60395ceb}')",
|
|
124
|
+
},
|
|
125
|
+
destination: {
|
|
126
|
+
type: "string",
|
|
127
|
+
description: "New destination branch name",
|
|
128
|
+
},
|
|
129
|
+
close_source_branch: {
|
|
130
|
+
type: "boolean",
|
|
131
|
+
description: "Whether to close source branch after merge",
|
|
132
|
+
},
|
|
133
|
+
draft: {
|
|
134
|
+
type: "boolean",
|
|
135
|
+
description: "Whether the pull request is a draft",
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
required: ["workspace", "repo_slug", "pull_request_id"],
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
name: "approvePullRequest",
|
|
143
|
+
description: "Approve a pull request",
|
|
144
|
+
inputSchema: {
|
|
145
|
+
type: "object",
|
|
146
|
+
properties: {
|
|
147
|
+
workspace: {
|
|
148
|
+
type: "string",
|
|
149
|
+
description: "Bitbucket workspace name",
|
|
150
|
+
},
|
|
151
|
+
repo_slug: { type: "string", description: "Repository slug" },
|
|
152
|
+
pull_request_id: {
|
|
153
|
+
type: "string",
|
|
154
|
+
description: "Pull request ID",
|
|
155
|
+
},
|
|
156
|
+
...PAGINATION_BASE_SCHEMA,
|
|
157
|
+
all: PAGINATION_ALL_SCHEMA,
|
|
158
|
+
},
|
|
159
|
+
required: ["workspace", "repo_slug", "pull_request_id"],
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
name: "unapprovePullRequest",
|
|
164
|
+
description: "Remove approval from a pull request",
|
|
165
|
+
inputSchema: {
|
|
166
|
+
type: "object",
|
|
167
|
+
properties: {
|
|
168
|
+
workspace: {
|
|
169
|
+
type: "string",
|
|
170
|
+
description: "Bitbucket workspace name",
|
|
171
|
+
},
|
|
172
|
+
repo_slug: { type: "string", description: "Repository slug" },
|
|
173
|
+
pull_request_id: {
|
|
174
|
+
type: "string",
|
|
175
|
+
description: "Pull request ID",
|
|
176
|
+
},
|
|
177
|
+
...PAGINATION_BASE_SCHEMA,
|
|
178
|
+
all: PAGINATION_ALL_SCHEMA,
|
|
179
|
+
},
|
|
180
|
+
required: ["workspace", "repo_slug", "pull_request_id"],
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
name: "declinePullRequest",
|
|
185
|
+
description: "Decline a pull request",
|
|
186
|
+
inputSchema: {
|
|
187
|
+
type: "object",
|
|
188
|
+
properties: {
|
|
189
|
+
workspace: {
|
|
190
|
+
type: "string",
|
|
191
|
+
description: "Bitbucket workspace name",
|
|
192
|
+
},
|
|
193
|
+
repo_slug: { type: "string", description: "Repository slug" },
|
|
194
|
+
pull_request_id: {
|
|
195
|
+
type: "string",
|
|
196
|
+
description: "Pull request ID",
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
required: ["workspace", "repo_slug", "pull_request_id"],
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
name: "mergePullRequest",
|
|
204
|
+
description: "Merge a pull request",
|
|
205
|
+
inputSchema: {
|
|
206
|
+
type: "object",
|
|
207
|
+
properties: {
|
|
208
|
+
workspace: {
|
|
209
|
+
type: "string",
|
|
210
|
+
description: "Bitbucket workspace name",
|
|
211
|
+
},
|
|
212
|
+
repo_slug: { type: "string", description: "Repository slug" },
|
|
213
|
+
pull_request_id: {
|
|
214
|
+
type: "string",
|
|
215
|
+
description: "Pull request ID",
|
|
216
|
+
},
|
|
217
|
+
message: { type: "string", description: "Merge commit message" },
|
|
218
|
+
merge_strategy: {
|
|
219
|
+
type: "string",
|
|
220
|
+
enum: [
|
|
221
|
+
"merge_commit",
|
|
222
|
+
"squash",
|
|
223
|
+
"fast_forward",
|
|
224
|
+
"squash_fast_forward",
|
|
225
|
+
"rebase_fast_forward",
|
|
226
|
+
"rebase_merge",
|
|
227
|
+
],
|
|
228
|
+
description: "Merge strategy",
|
|
229
|
+
},
|
|
230
|
+
close_source_branch: {
|
|
231
|
+
type: "boolean",
|
|
232
|
+
description: "Whether to close the source branch after merge",
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
required: ["workspace", "repo_slug", "pull_request_id"],
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
name: "createDraftPullRequest",
|
|
240
|
+
description: "Create a new draft pull request",
|
|
241
|
+
inputSchema: {
|
|
242
|
+
type: "object",
|
|
243
|
+
properties: {
|
|
244
|
+
workspace: {
|
|
245
|
+
type: "string",
|
|
246
|
+
description: "Bitbucket workspace name",
|
|
247
|
+
},
|
|
248
|
+
repo_slug: { type: "string", description: "Repository slug" },
|
|
249
|
+
title: { type: "string", description: "Pull request title" },
|
|
250
|
+
description: {
|
|
251
|
+
type: "string",
|
|
252
|
+
description: "Pull request description",
|
|
253
|
+
},
|
|
254
|
+
sourceBranch: {
|
|
255
|
+
type: "string",
|
|
256
|
+
description: "Source branch name",
|
|
257
|
+
},
|
|
258
|
+
targetBranch: {
|
|
259
|
+
type: "string",
|
|
260
|
+
description: "Target branch name",
|
|
261
|
+
},
|
|
262
|
+
reviewers: {
|
|
263
|
+
type: "array",
|
|
264
|
+
items: { type: "string" },
|
|
265
|
+
description: "List of reviewer UUIDs (e.g., '{04776764-62c7-453b-b97e-302f60395ceb}')",
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
required: [
|
|
269
|
+
"workspace",
|
|
270
|
+
"repo_slug",
|
|
271
|
+
"title",
|
|
272
|
+
"description",
|
|
273
|
+
"sourceBranch",
|
|
274
|
+
"targetBranch",
|
|
275
|
+
],
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
name: "publishDraftPullRequest",
|
|
280
|
+
description: "Publish a draft pull request to make it ready for review",
|
|
281
|
+
inputSchema: {
|
|
282
|
+
type: "object",
|
|
283
|
+
properties: {
|
|
284
|
+
workspace: {
|
|
285
|
+
type: "string",
|
|
286
|
+
description: "Bitbucket workspace name",
|
|
287
|
+
},
|
|
288
|
+
repo_slug: { type: "string", description: "Repository slug" },
|
|
289
|
+
pull_request_id: {
|
|
290
|
+
type: "string",
|
|
291
|
+
description: "Pull request ID",
|
|
292
|
+
},
|
|
293
|
+
},
|
|
294
|
+
required: ["workspace", "repo_slug", "pull_request_id"],
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
name: "convertTodraft",
|
|
299
|
+
description: "Convert a regular pull request to draft status",
|
|
300
|
+
inputSchema: {
|
|
301
|
+
type: "object",
|
|
302
|
+
properties: {
|
|
303
|
+
workspace: {
|
|
304
|
+
type: "string",
|
|
305
|
+
description: "Bitbucket workspace name",
|
|
306
|
+
},
|
|
307
|
+
repo_slug: { type: "string", description: "Repository slug" },
|
|
308
|
+
pull_request_id: {
|
|
309
|
+
type: "string",
|
|
310
|
+
description: "Pull request ID",
|
|
311
|
+
},
|
|
312
|
+
},
|
|
313
|
+
required: ["workspace", "repo_slug", "pull_request_id"],
|
|
314
|
+
},
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
name: "getPendingReviewPRs",
|
|
318
|
+
description: "List all open pull requests in the workspace where the authenticated user is a reviewer and has not yet approved.",
|
|
319
|
+
inputSchema: {
|
|
320
|
+
type: "object",
|
|
321
|
+
properties: {
|
|
322
|
+
workspace: {
|
|
323
|
+
type: "string",
|
|
324
|
+
description: "Bitbucket workspace name (optional, defaults to BITBUCKET_WORKSPACE)",
|
|
325
|
+
},
|
|
326
|
+
limit: {
|
|
327
|
+
type: "number",
|
|
328
|
+
description: "Maximum number of PRs to return (optional)",
|
|
329
|
+
},
|
|
330
|
+
repositoryList: {
|
|
331
|
+
type: "array",
|
|
332
|
+
items: { type: "string" },
|
|
333
|
+
description: "List of repository slugs to check (optional)",
|
|
334
|
+
},
|
|
335
|
+
},
|
|
336
|
+
},
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
name: "requestChanges",
|
|
340
|
+
description: "Request changes on a pull request",
|
|
341
|
+
inputSchema: {
|
|
342
|
+
type: "object",
|
|
343
|
+
properties: {
|
|
344
|
+
workspace: { type: "string", description: "Bitbucket workspace name" },
|
|
345
|
+
repo_slug: { type: "string", description: "Repository slug" },
|
|
346
|
+
pull_request_id: { type: "string", description: "Pull request ID" },
|
|
347
|
+
},
|
|
348
|
+
required: ["workspace", "repo_slug", "pull_request_id"],
|
|
349
|
+
},
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
name: "removeRequestChanges",
|
|
353
|
+
description: "Remove request changes from a pull request",
|
|
354
|
+
inputSchema: {
|
|
355
|
+
type: "object",
|
|
356
|
+
properties: {
|
|
357
|
+
workspace: { type: "string", description: "Bitbucket workspace name" },
|
|
358
|
+
repo_slug: { type: "string", description: "Repository slug" },
|
|
359
|
+
pull_request_id: { type: "string", description: "Pull request ID" },
|
|
360
|
+
},
|
|
361
|
+
required: ["workspace", "repo_slug", "pull_request_id"],
|
|
362
|
+
},
|
|
363
|
+
},
|
|
364
|
+
],
|
|
365
|
+
createHandlers: (client) => ({
|
|
366
|
+
getPullRequests: async (args) => {
|
|
367
|
+
const workspace = args.workspace;
|
|
368
|
+
const repo_slug = args.repo_slug;
|
|
369
|
+
const state = args.state;
|
|
370
|
+
const pagelen = args.pagelen;
|
|
371
|
+
const page = args.page;
|
|
372
|
+
const all = args.all;
|
|
373
|
+
const legacyLimit = args.limit;
|
|
374
|
+
try {
|
|
375
|
+
logger.info("Getting Bitbucket pull requests", {
|
|
376
|
+
workspace,
|
|
377
|
+
repo_slug,
|
|
378
|
+
state,
|
|
379
|
+
pagelen: pagelen ?? legacyLimit,
|
|
380
|
+
page,
|
|
381
|
+
all,
|
|
382
|
+
});
|
|
383
|
+
const params = {};
|
|
384
|
+
if (state) {
|
|
385
|
+
params.state = state;
|
|
386
|
+
}
|
|
387
|
+
const result = await client.paginator.fetchValues(`/repositories/${workspace}/${repo_slug}/pullrequests`, {
|
|
388
|
+
pagelen: pagelen ?? legacyLimit,
|
|
389
|
+
page,
|
|
390
|
+
all,
|
|
391
|
+
params,
|
|
392
|
+
description: "getPullRequests",
|
|
393
|
+
});
|
|
394
|
+
return jsonResponse(result.values);
|
|
395
|
+
}
|
|
396
|
+
catch (error) {
|
|
397
|
+
logger.error("Error getting pull requests", {
|
|
398
|
+
error,
|
|
399
|
+
workspace,
|
|
400
|
+
repo_slug,
|
|
401
|
+
});
|
|
402
|
+
throw new McpError(ErrorCode.InternalError, `Failed to get pull requests: ${error instanceof Error ? error.message : String(error)}`);
|
|
403
|
+
}
|
|
404
|
+
},
|
|
405
|
+
createPullRequest: async (args) => {
|
|
406
|
+
const workspace = args.workspace;
|
|
407
|
+
const repo_slug = args.repo_slug;
|
|
408
|
+
const title = args.title;
|
|
409
|
+
const description = args.description;
|
|
410
|
+
const sourceBranch = args.sourceBranch;
|
|
411
|
+
const targetBranch = args.targetBranch;
|
|
412
|
+
const reviewers = args.reviewers;
|
|
413
|
+
const draft = args.draft;
|
|
414
|
+
const close_source_branch = args.close_source_branch;
|
|
415
|
+
try {
|
|
416
|
+
logger.info("Creating Bitbucket pull request", {
|
|
417
|
+
workspace,
|
|
418
|
+
repo_slug,
|
|
419
|
+
title,
|
|
420
|
+
sourceBranch,
|
|
421
|
+
targetBranch,
|
|
422
|
+
});
|
|
423
|
+
// Prepare reviewers format if provided
|
|
424
|
+
// Bitbucket API expects reviewers as array of objects: [{uuid: "{...}"}]
|
|
425
|
+
// Input is string array of UUIDs: ["{04776764-62c7-453b-b97e-302f60395ceb}", ...]
|
|
426
|
+
// Convert to API format: [{uuid: "{...}"}, ...]
|
|
427
|
+
let reviewersArray;
|
|
428
|
+
if (reviewers && reviewers.length > 0) {
|
|
429
|
+
reviewersArray = reviewers
|
|
430
|
+
.filter((uuid) => typeof uuid === "string" && uuid.trim().length > 0)
|
|
431
|
+
.map((uuid) => ({ uuid: uuid.trim() }));
|
|
432
|
+
if (reviewersArray.length === 0) {
|
|
433
|
+
reviewersArray = undefined;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
// Build request payload - only include reviewers if provided
|
|
437
|
+
const requestPayload = {
|
|
438
|
+
title,
|
|
439
|
+
description,
|
|
440
|
+
source: {
|
|
441
|
+
branch: {
|
|
442
|
+
name: sourceBranch,
|
|
443
|
+
},
|
|
444
|
+
},
|
|
445
|
+
destination: {
|
|
446
|
+
branch: {
|
|
447
|
+
name: targetBranch,
|
|
448
|
+
},
|
|
449
|
+
},
|
|
450
|
+
close_source_branch: close_source_branch ?? true,
|
|
451
|
+
};
|
|
452
|
+
// Only include reviewers field if there are reviewers to add
|
|
453
|
+
if (reviewersArray && reviewersArray.length > 0) {
|
|
454
|
+
requestPayload.reviewers = reviewersArray;
|
|
455
|
+
}
|
|
456
|
+
// Only include draft field if explicitly set to true
|
|
457
|
+
if (draft === true) {
|
|
458
|
+
requestPayload.draft = true;
|
|
459
|
+
}
|
|
460
|
+
// Create the pull request
|
|
461
|
+
const response = await client.api.post(`/repositories/${workspace}/${repo_slug}/pullrequests`, requestPayload);
|
|
462
|
+
return jsonResponse(response.data);
|
|
463
|
+
}
|
|
464
|
+
catch (error) {
|
|
465
|
+
logger.error("Error creating pull request", {
|
|
466
|
+
error,
|
|
467
|
+
workspace,
|
|
468
|
+
repo_slug,
|
|
469
|
+
});
|
|
470
|
+
throw new McpError(ErrorCode.InternalError, `Failed to create pull request: ${error instanceof Error ? error.message : String(error)}`);
|
|
471
|
+
}
|
|
472
|
+
},
|
|
473
|
+
getPullRequest: async (args) => {
|
|
474
|
+
const workspace = args.workspace;
|
|
475
|
+
const repo_slug = args.repo_slug;
|
|
476
|
+
const pull_request_id = args.pull_request_id;
|
|
477
|
+
try {
|
|
478
|
+
logger.info("Getting Bitbucket pull request details", {
|
|
479
|
+
workspace,
|
|
480
|
+
repo_slug,
|
|
481
|
+
pull_request_id,
|
|
482
|
+
});
|
|
483
|
+
const response = await client.api.get(`/repositories/${workspace}/${repo_slug}/pullrequests/${pull_request_id}`);
|
|
484
|
+
return jsonResponse(response.data);
|
|
485
|
+
}
|
|
486
|
+
catch (error) {
|
|
487
|
+
logger.error("Error getting pull request details", {
|
|
488
|
+
error,
|
|
489
|
+
workspace,
|
|
490
|
+
repo_slug,
|
|
491
|
+
pull_request_id,
|
|
492
|
+
});
|
|
493
|
+
throw new McpError(ErrorCode.InternalError, `Failed to get pull request details: ${error instanceof Error ? error.message : String(error)}`);
|
|
494
|
+
}
|
|
495
|
+
},
|
|
496
|
+
updatePullRequest: async (args) => {
|
|
497
|
+
const workspace = args.workspace;
|
|
498
|
+
const repo_slug = args.repo_slug;
|
|
499
|
+
const pull_request_id = args.pull_request_id;
|
|
500
|
+
const title = args.title;
|
|
501
|
+
const description = args.description;
|
|
502
|
+
const reviewers = args.reviewers;
|
|
503
|
+
const destination = args.destination;
|
|
504
|
+
const close_source_branch = args.close_source_branch;
|
|
505
|
+
const draft = args.draft;
|
|
506
|
+
try {
|
|
507
|
+
logger.info("Updating Bitbucket pull request", {
|
|
508
|
+
workspace,
|
|
509
|
+
repo_slug,
|
|
510
|
+
pull_request_id,
|
|
511
|
+
});
|
|
512
|
+
// Only include fields that are provided
|
|
513
|
+
const updateData = {};
|
|
514
|
+
if (title !== undefined)
|
|
515
|
+
updateData.title = title;
|
|
516
|
+
if (description !== undefined)
|
|
517
|
+
updateData.description = description;
|
|
518
|
+
if (reviewers !== undefined) {
|
|
519
|
+
updateData.reviewers = reviewers
|
|
520
|
+
.filter((uuid) => typeof uuid === "string" && uuid.trim().length > 0)
|
|
521
|
+
.map((uuid) => ({ uuid: uuid.trim() }));
|
|
522
|
+
}
|
|
523
|
+
if (destination !== undefined) {
|
|
524
|
+
updateData.destination = { branch: { name: destination } };
|
|
525
|
+
}
|
|
526
|
+
if (close_source_branch !== undefined)
|
|
527
|
+
updateData.close_source_branch = close_source_branch;
|
|
528
|
+
if (draft !== undefined)
|
|
529
|
+
updateData.draft = draft;
|
|
530
|
+
const response = await client.api.put(`/repositories/${workspace}/${repo_slug}/pullrequests/${pull_request_id}`, updateData);
|
|
531
|
+
return jsonResponse(response.data);
|
|
532
|
+
}
|
|
533
|
+
catch (error) {
|
|
534
|
+
logger.error("Error updating pull request", {
|
|
535
|
+
error,
|
|
536
|
+
workspace,
|
|
537
|
+
repo_slug,
|
|
538
|
+
pull_request_id,
|
|
539
|
+
});
|
|
540
|
+
throw new McpError(ErrorCode.InternalError, `Failed to update pull request: ${error instanceof Error ? error.message : String(error)}`);
|
|
541
|
+
}
|
|
542
|
+
},
|
|
543
|
+
approvePullRequest: async (args) => {
|
|
544
|
+
const workspace = args.workspace;
|
|
545
|
+
const repo_slug = args.repo_slug;
|
|
546
|
+
const pull_request_id = args.pull_request_id;
|
|
547
|
+
try {
|
|
548
|
+
logger.info("Approving Bitbucket pull request", {
|
|
549
|
+
workspace,
|
|
550
|
+
repo_slug,
|
|
551
|
+
pull_request_id,
|
|
552
|
+
});
|
|
553
|
+
const response = await client.api.post(`/repositories/${workspace}/${repo_slug}/pullrequests/${pull_request_id}/approve`);
|
|
554
|
+
return jsonResponse(response.data);
|
|
555
|
+
}
|
|
556
|
+
catch (error) {
|
|
557
|
+
logger.error("Error approving pull request", {
|
|
558
|
+
error,
|
|
559
|
+
workspace,
|
|
560
|
+
repo_slug,
|
|
561
|
+
pull_request_id,
|
|
562
|
+
});
|
|
563
|
+
throw new McpError(ErrorCode.InternalError, `Failed to approve pull request: ${error instanceof Error ? error.message : String(error)}`);
|
|
564
|
+
}
|
|
565
|
+
},
|
|
566
|
+
unapprovePullRequest: async (args) => {
|
|
567
|
+
const workspace = args.workspace;
|
|
568
|
+
const repo_slug = args.repo_slug;
|
|
569
|
+
const pull_request_id = args.pull_request_id;
|
|
570
|
+
try {
|
|
571
|
+
logger.info("Unapproving Bitbucket pull request", {
|
|
572
|
+
workspace,
|
|
573
|
+
repo_slug,
|
|
574
|
+
pull_request_id,
|
|
575
|
+
});
|
|
576
|
+
await client.api.delete(`/repositories/${workspace}/${repo_slug}/pullrequests/${pull_request_id}/approve`);
|
|
577
|
+
return textResponse("Pull request approval removed successfully.");
|
|
578
|
+
}
|
|
579
|
+
catch (error) {
|
|
580
|
+
logger.error("Error unapproving pull request", {
|
|
581
|
+
error,
|
|
582
|
+
workspace,
|
|
583
|
+
repo_slug,
|
|
584
|
+
pull_request_id,
|
|
585
|
+
});
|
|
586
|
+
throw new McpError(ErrorCode.InternalError, `Failed to unapprove pull request: ${error instanceof Error ? error.message : String(error)}`);
|
|
587
|
+
}
|
|
588
|
+
},
|
|
589
|
+
declinePullRequest: async (args) => {
|
|
590
|
+
const workspace = args.workspace;
|
|
591
|
+
const repo_slug = args.repo_slug;
|
|
592
|
+
const pull_request_id = args.pull_request_id;
|
|
593
|
+
try {
|
|
594
|
+
logger.info("Declining Bitbucket pull request", {
|
|
595
|
+
workspace,
|
|
596
|
+
repo_slug,
|
|
597
|
+
pull_request_id,
|
|
598
|
+
});
|
|
599
|
+
const response = await client.api.post(`/repositories/${workspace}/${repo_slug}/pullrequests/${pull_request_id}/decline`);
|
|
600
|
+
return jsonResponse(response.data);
|
|
601
|
+
}
|
|
602
|
+
catch (error) {
|
|
603
|
+
logger.error("Error declining pull request", {
|
|
604
|
+
error,
|
|
605
|
+
workspace,
|
|
606
|
+
repo_slug,
|
|
607
|
+
pull_request_id,
|
|
608
|
+
});
|
|
609
|
+
throw new McpError(ErrorCode.InternalError, `Failed to decline pull request: ${error instanceof Error ? error.message : String(error)}`);
|
|
610
|
+
}
|
|
611
|
+
},
|
|
612
|
+
mergePullRequest: async (args) => {
|
|
613
|
+
const workspace = args.workspace;
|
|
614
|
+
const repo_slug = args.repo_slug;
|
|
615
|
+
const pull_request_id = args.pull_request_id;
|
|
616
|
+
const message = args.message;
|
|
617
|
+
const merge_strategy = args.merge_strategy;
|
|
618
|
+
const close_source_branch = args.close_source_branch;
|
|
619
|
+
try {
|
|
620
|
+
logger.info("Merging Bitbucket pull request", {
|
|
621
|
+
workspace,
|
|
622
|
+
repo_slug,
|
|
623
|
+
pull_request_id,
|
|
624
|
+
merge_strategy,
|
|
625
|
+
});
|
|
626
|
+
// Build request data
|
|
627
|
+
const data = {};
|
|
628
|
+
if (message)
|
|
629
|
+
data.message = message;
|
|
630
|
+
if (merge_strategy)
|
|
631
|
+
data.merge_strategy = merge_strategy;
|
|
632
|
+
if (close_source_branch !== undefined)
|
|
633
|
+
data.close_source_branch = close_source_branch;
|
|
634
|
+
const response = await client.api.post(`/repositories/${workspace}/${repo_slug}/pullrequests/${pull_request_id}/merge`, data);
|
|
635
|
+
return jsonResponse(response.data);
|
|
636
|
+
}
|
|
637
|
+
catch (error) {
|
|
638
|
+
logger.error("Error merging pull request", {
|
|
639
|
+
error,
|
|
640
|
+
workspace,
|
|
641
|
+
repo_slug,
|
|
642
|
+
pull_request_id,
|
|
643
|
+
});
|
|
644
|
+
throw new McpError(ErrorCode.InternalError, `Failed to merge pull request: ${error instanceof Error ? error.message : String(error)}`);
|
|
645
|
+
}
|
|
646
|
+
},
|
|
647
|
+
createDraftPullRequest: async (args) => {
|
|
648
|
+
const workspace = args.workspace;
|
|
649
|
+
const repo_slug = args.repo_slug;
|
|
650
|
+
const title = args.title;
|
|
651
|
+
const description = args.description;
|
|
652
|
+
const sourceBranch = args.sourceBranch;
|
|
653
|
+
const targetBranch = args.targetBranch;
|
|
654
|
+
const reviewers = args.reviewers;
|
|
655
|
+
try {
|
|
656
|
+
logger.info("Creating draft Bitbucket pull request", {
|
|
657
|
+
workspace,
|
|
658
|
+
repo_slug,
|
|
659
|
+
title,
|
|
660
|
+
sourceBranch,
|
|
661
|
+
targetBranch,
|
|
662
|
+
});
|
|
663
|
+
// Prepare reviewers format if provided
|
|
664
|
+
let reviewersArray;
|
|
665
|
+
if (reviewers && reviewers.length > 0) {
|
|
666
|
+
reviewersArray = reviewers
|
|
667
|
+
.filter((uuid) => typeof uuid === "string" && uuid.trim().length > 0)
|
|
668
|
+
.map((uuid) => ({ uuid: uuid.trim() }));
|
|
669
|
+
if (reviewersArray.length === 0) {
|
|
670
|
+
reviewersArray = undefined;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
// Build request payload with draft=true
|
|
674
|
+
const requestPayload = {
|
|
675
|
+
title,
|
|
676
|
+
description,
|
|
677
|
+
source: {
|
|
678
|
+
branch: {
|
|
679
|
+
name: sourceBranch,
|
|
680
|
+
},
|
|
681
|
+
},
|
|
682
|
+
destination: {
|
|
683
|
+
branch: {
|
|
684
|
+
name: targetBranch,
|
|
685
|
+
},
|
|
686
|
+
},
|
|
687
|
+
close_source_branch: true,
|
|
688
|
+
draft: true,
|
|
689
|
+
};
|
|
690
|
+
// Only include reviewers field if there are reviewers to add
|
|
691
|
+
if (reviewersArray && reviewersArray.length > 0) {
|
|
692
|
+
requestPayload.reviewers = reviewersArray;
|
|
693
|
+
}
|
|
694
|
+
// Create the draft pull request
|
|
695
|
+
const response = await client.api.post(`/repositories/${workspace}/${repo_slug}/pullrequests`, requestPayload);
|
|
696
|
+
return jsonResponse(response.data);
|
|
697
|
+
}
|
|
698
|
+
catch (error) {
|
|
699
|
+
logger.error("Error creating draft pull request", {
|
|
700
|
+
error,
|
|
701
|
+
workspace,
|
|
702
|
+
repo_slug,
|
|
703
|
+
});
|
|
704
|
+
throw new McpError(ErrorCode.InternalError, `Failed to create draft pull request: ${error instanceof Error ? error.message : String(error)}`);
|
|
705
|
+
}
|
|
706
|
+
},
|
|
707
|
+
publishDraftPullRequest: async (args) => {
|
|
708
|
+
const workspace = args.workspace;
|
|
709
|
+
const repo_slug = args.repo_slug;
|
|
710
|
+
const pull_request_id = args.pull_request_id;
|
|
711
|
+
try {
|
|
712
|
+
logger.info("Publishing draft pull request", {
|
|
713
|
+
workspace,
|
|
714
|
+
repo_slug,
|
|
715
|
+
pull_request_id,
|
|
716
|
+
});
|
|
717
|
+
// Update the pull request to set draft=false
|
|
718
|
+
const response = await client.api.put(`/repositories/${workspace}/${repo_slug}/pullrequests/${pull_request_id}`, {
|
|
719
|
+
draft: false,
|
|
720
|
+
});
|
|
721
|
+
return jsonResponse(response.data);
|
|
722
|
+
}
|
|
723
|
+
catch (error) {
|
|
724
|
+
logger.error("Error publishing draft pull request", {
|
|
725
|
+
error,
|
|
726
|
+
workspace,
|
|
727
|
+
repo_slug,
|
|
728
|
+
pull_request_id,
|
|
729
|
+
});
|
|
730
|
+
throw new McpError(ErrorCode.InternalError, `Failed to publish draft pull request: ${error instanceof Error ? error.message : String(error)}`);
|
|
731
|
+
}
|
|
732
|
+
},
|
|
733
|
+
convertTodraft: async (args) => {
|
|
734
|
+
const workspace = args.workspace;
|
|
735
|
+
const repo_slug = args.repo_slug;
|
|
736
|
+
const pull_request_id = args.pull_request_id;
|
|
737
|
+
try {
|
|
738
|
+
logger.info("Converting pull request to draft", {
|
|
739
|
+
workspace,
|
|
740
|
+
repo_slug,
|
|
741
|
+
pull_request_id,
|
|
742
|
+
});
|
|
743
|
+
// Update the pull request to set draft=true
|
|
744
|
+
const response = await client.api.put(`/repositories/${workspace}/${repo_slug}/pullrequests/${pull_request_id}`, {
|
|
745
|
+
draft: true,
|
|
746
|
+
});
|
|
747
|
+
return jsonResponse(response.data);
|
|
748
|
+
}
|
|
749
|
+
catch (error) {
|
|
750
|
+
logger.error("Error converting pull request to draft", {
|
|
751
|
+
error,
|
|
752
|
+
workspace,
|
|
753
|
+
repo_slug,
|
|
754
|
+
pull_request_id,
|
|
755
|
+
});
|
|
756
|
+
throw new McpError(ErrorCode.InternalError, `Failed to convert pull request to draft: ${error instanceof Error ? error.message : String(error)}`);
|
|
757
|
+
}
|
|
758
|
+
},
|
|
759
|
+
getPendingReviewPRs: async (args) => {
|
|
760
|
+
const workspace = args.workspace;
|
|
761
|
+
const limit = args.limit || 50;
|
|
762
|
+
const repositoryList = args.repositoryList;
|
|
763
|
+
try {
|
|
764
|
+
const wsName = client.resolveWorkspace(workspace);
|
|
765
|
+
// Get current user's account_id from /user endpoint (works with both token and basic auth)
|
|
766
|
+
const currentUserResponse = await client.api.get("/user");
|
|
767
|
+
const currentUserAccountId = currentUserResponse.data.account_id;
|
|
768
|
+
if (!currentUserAccountId) {
|
|
769
|
+
throw new McpError(ErrorCode.InternalError, "Could not determine current user's account_id");
|
|
770
|
+
}
|
|
771
|
+
logger.info("Getting pending review PRs", {
|
|
772
|
+
workspace: wsName,
|
|
773
|
+
account_id: currentUserAccountId,
|
|
774
|
+
repositoryList: repositoryList?.length || "all repositories",
|
|
775
|
+
limit,
|
|
776
|
+
});
|
|
777
|
+
let repositoriesToCheck = [];
|
|
778
|
+
if (repositoryList && repositoryList.length > 0) {
|
|
779
|
+
// Use the provided repository list
|
|
780
|
+
repositoriesToCheck = repositoryList;
|
|
781
|
+
logger.info(`Checking specific repositories: ${repositoryList.join(", ")}`);
|
|
782
|
+
}
|
|
783
|
+
else {
|
|
784
|
+
// Get all repositories in the workspace (existing behavior)
|
|
785
|
+
logger.info("Getting all repositories in workspace...");
|
|
786
|
+
const reposResponse = await client.paginator.fetchValues(`/repositories/${wsName}`, {
|
|
787
|
+
pagelen: BITBUCKET_MAX_PAGELEN,
|
|
788
|
+
all: true,
|
|
789
|
+
description: "getPendingReviewPRs.repositories",
|
|
790
|
+
});
|
|
791
|
+
if (!reposResponse.values) {
|
|
792
|
+
throw new McpError(ErrorCode.InternalError, "Failed to fetch repositories");
|
|
793
|
+
}
|
|
794
|
+
repositoriesToCheck = reposResponse.values.map((repo) => repo.name);
|
|
795
|
+
logger.info(`Found ${repositoriesToCheck.length} repositories to check`);
|
|
796
|
+
}
|
|
797
|
+
const pendingPRs = [];
|
|
798
|
+
const batchSize = 5; // Process repositories in batches to avoid overwhelming the API
|
|
799
|
+
// Process repositories in batches
|
|
800
|
+
for (let i = 0; i < repositoriesToCheck.length; i += batchSize) {
|
|
801
|
+
const batch = repositoriesToCheck.slice(i, i + batchSize);
|
|
802
|
+
// Process batch in parallel
|
|
803
|
+
const batchPromises = batch.map(async (repoSlug) => {
|
|
804
|
+
try {
|
|
805
|
+
logger.info(`Checking repository: ${repoSlug}`);
|
|
806
|
+
// Get open PRs for this repository with participants expanded
|
|
807
|
+
const prsResponse = await client.api.get(`/repositories/${wsName}/${repoSlug}/pullrequests`, {
|
|
808
|
+
params: {
|
|
809
|
+
state: "OPEN",
|
|
810
|
+
pagelen: Math.min(limit, 50), // Limit per repo to avoid too much data
|
|
811
|
+
fields: "values.id,values.title,values.description,values.state,values.created_on,values.updated_on,values.author,values.source,values.destination,values.participants.user.account_id,values.participants.user.nickname,values.participants.role,values.participants.approved,values.links",
|
|
812
|
+
},
|
|
813
|
+
});
|
|
814
|
+
if (!prsResponse.data.values) {
|
|
815
|
+
return [];
|
|
816
|
+
}
|
|
817
|
+
// Filter PRs where current user is a reviewer and hasn't approved
|
|
818
|
+
const reposPendingPRs = prsResponse.data.values.filter((pr) => {
|
|
819
|
+
if (!pr.participants || !Array.isArray(pr.participants)) {
|
|
820
|
+
logger.debug(`PR ${pr.id} has no participants array`);
|
|
821
|
+
return false;
|
|
822
|
+
}
|
|
823
|
+
logger.debug(`PR ${pr.id} participants:`, pr.participants.map((p) => ({
|
|
824
|
+
account_id: p.user?.account_id,
|
|
825
|
+
nickname: p.user?.nickname,
|
|
826
|
+
role: p.role,
|
|
827
|
+
approved: p.approved,
|
|
828
|
+
})));
|
|
829
|
+
// Check if current user is a reviewer who hasn't approved (using account_id)
|
|
830
|
+
const userParticipant = pr.participants.find((participant) => participant.user?.account_id === currentUserAccountId &&
|
|
831
|
+
participant.role === "REVIEWER" &&
|
|
832
|
+
participant.approved === false);
|
|
833
|
+
logger.debug(`PR ${pr.id} - User ${currentUserAccountId} is pending reviewer:`, !!userParticipant);
|
|
834
|
+
return !!userParticipant;
|
|
835
|
+
});
|
|
836
|
+
// Add repository info to each PR
|
|
837
|
+
return reposPendingPRs.map((pr) => ({
|
|
838
|
+
...pr,
|
|
839
|
+
repository: {
|
|
840
|
+
name: repoSlug,
|
|
841
|
+
full_name: `${wsName}/${repoSlug}`,
|
|
842
|
+
},
|
|
843
|
+
}));
|
|
844
|
+
}
|
|
845
|
+
catch (error) {
|
|
846
|
+
logger.error(`Error checking repository ${repoSlug}:`, error);
|
|
847
|
+
return [];
|
|
848
|
+
}
|
|
849
|
+
});
|
|
850
|
+
// Wait for batch to complete
|
|
851
|
+
const batchResults = await Promise.all(batchPromises);
|
|
852
|
+
// Flatten and add to results
|
|
853
|
+
for (const repoPRs of batchResults) {
|
|
854
|
+
pendingPRs.push(...repoPRs);
|
|
855
|
+
// Stop if we've reached the limit
|
|
856
|
+
if (pendingPRs.length >= limit) {
|
|
857
|
+
break;
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
// Stop processing if we've reached the limit
|
|
861
|
+
if (pendingPRs.length >= limit) {
|
|
862
|
+
break;
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
// Trim to exact limit and sort by updated date
|
|
866
|
+
const finalResults = pendingPRs
|
|
867
|
+
.slice(0, limit)
|
|
868
|
+
.sort((a, b) => new Date(b.updated_on).getTime() -
|
|
869
|
+
new Date(a.updated_on).getTime());
|
|
870
|
+
logger.info(`Found ${finalResults.length} pending review PRs`);
|
|
871
|
+
return jsonResponse({
|
|
872
|
+
pending_review_prs: finalResults,
|
|
873
|
+
total_found: finalResults.length,
|
|
874
|
+
searched_repositories: repositoriesToCheck.length,
|
|
875
|
+
user_account_id: currentUserAccountId,
|
|
876
|
+
workspace: wsName,
|
|
877
|
+
});
|
|
878
|
+
}
|
|
879
|
+
catch (error) {
|
|
880
|
+
logger.error("Error getting pending review PRs:", error);
|
|
881
|
+
throw new McpError(ErrorCode.InternalError, `Failed to get pending review PRs: ${error instanceof Error ? error.message : String(error)}`);
|
|
882
|
+
}
|
|
883
|
+
},
|
|
884
|
+
requestChanges: async (args) => {
|
|
885
|
+
const workspace = client.resolveWorkspace(args.workspace);
|
|
886
|
+
const repo_slug = args.repo_slug;
|
|
887
|
+
const pull_request_id = args.pull_request_id;
|
|
888
|
+
logger.info(`Requesting changes on PR #${pull_request_id} in ${workspace}/${repo_slug}`);
|
|
889
|
+
await client.api.post(`/repositories/${workspace}/${repo_slug}/pullrequests/${pull_request_id}/request-changes`);
|
|
890
|
+
return jsonResponse({ success: true });
|
|
891
|
+
},
|
|
892
|
+
removeRequestChanges: async (args) => {
|
|
893
|
+
const workspace = client.resolveWorkspace(args.workspace);
|
|
894
|
+
const repo_slug = args.repo_slug;
|
|
895
|
+
const pull_request_id = args.pull_request_id;
|
|
896
|
+
logger.info(`Removing request changes from PR #${pull_request_id} in ${workspace}/${repo_slug}`);
|
|
897
|
+
await client.api.delete(`/repositories/${workspace}/${repo_slug}/pullrequests/${pull_request_id}/request-changes`);
|
|
898
|
+
return jsonResponse({ success: true });
|
|
899
|
+
},
|
|
900
|
+
}),
|
|
901
|
+
};
|
|
902
|
+
//# sourceMappingURL=pull-requests.js.map
|