opencode-gitlab-plugin 2.2.0 → 2.4.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.
@@ -29310,6 +29310,107 @@ var MergeRequestsClient = class extends GitLabApiClient {
29310
29310
  `/projects/${encodedProject}/merge_requests/${mrIid}/unapprove`
29311
29311
  );
29312
29312
  }
29313
+ /**
29314
+ * Merge a merge request immediately
29315
+ * Requires the MR to be in a mergeable state (approved, pipeline passed, no conflicts)
29316
+ */
29317
+ async mergeMergeRequest(projectId, mrIid, options) {
29318
+ const encodedProject = this.encodeProjectId(projectId);
29319
+ const body = {};
29320
+ if (options?.sha) body.sha = options.sha;
29321
+ if (options?.squash !== void 0) body.squash = options.squash;
29322
+ if (options?.shouldRemoveSourceBranch !== void 0) {
29323
+ body.should_remove_source_branch = options.shouldRemoveSourceBranch;
29324
+ }
29325
+ return this.fetch(
29326
+ "PUT",
29327
+ `/projects/${encodedProject}/merge_requests/${mrIid}/merge`,
29328
+ Object.keys(body).length > 0 ? body : void 0
29329
+ );
29330
+ }
29331
+ /**
29332
+ * Smart merge: merge immediately if checks pass, otherwise set auto-merge
29333
+ * Returns detailed context about what happened
29334
+ */
29335
+ async smartMerge(projectId, mrIid, sha, strategy = "MERGE_WHEN_CHECKS_PASS") {
29336
+ const mr = await this.getMergeRequest(projectId, mrIid);
29337
+ const context = {
29338
+ state: mr.state,
29339
+ detailedMergeStatus: mr.detailed_merge_status,
29340
+ pipelineStatus: mr.head_pipeline?.status || null,
29341
+ hasConflicts: mr.has_conflicts,
29342
+ hasAnyApproval: (mr.approved_by?.length || 0) > 0
29343
+ };
29344
+ if (mr.state !== "opened") {
29345
+ return {
29346
+ action: "failed",
29347
+ message: `MR is not open (state: ${mr.state})`,
29348
+ context
29349
+ };
29350
+ }
29351
+ if (mr.has_conflicts) {
29352
+ return {
29353
+ action: "failed",
29354
+ message: "MR has merge conflicts that must be resolved",
29355
+ context
29356
+ };
29357
+ }
29358
+ if (mr.detailed_merge_status === "mergeable") {
29359
+ try {
29360
+ const result = await this.mergeMergeRequest(projectId, mrIid, { sha: mr.sha });
29361
+ return {
29362
+ action: "merged",
29363
+ message: "MR merged successfully",
29364
+ mergeRequest: result,
29365
+ context
29366
+ };
29367
+ } catch (error45) {
29368
+ return {
29369
+ action: "failed",
29370
+ message: `Direct merge failed: ${error45 instanceof Error ? error45.message : String(error45)}`,
29371
+ context
29372
+ };
29373
+ }
29374
+ }
29375
+ const autoMergeStatuses = ["ci_still_running", "not_approved", "checking"];
29376
+ if (autoMergeStatuses.includes(mr.detailed_merge_status)) {
29377
+ try {
29378
+ const result = await this.setAutoMerge(projectId, mrIid, sha, strategy);
29379
+ const autoMergeMessages = {
29380
+ ci_still_running: "pipeline passes",
29381
+ not_approved: "approved",
29382
+ checking: "checks complete"
29383
+ };
29384
+ return {
29385
+ action: "auto_merge_enabled",
29386
+ message: `Auto-merge enabled (${strategy}). MR will merge when ${autoMergeMessages[mr.detailed_merge_status]}.`,
29387
+ mergeRequest: result,
29388
+ context
29389
+ };
29390
+ } catch (error45) {
29391
+ return {
29392
+ action: "failed",
29393
+ message: `Failed to enable auto-merge: ${error45 instanceof Error ? error45.message : String(error45)}. MR status: ${mr.detailed_merge_status}, pipeline: ${mr.head_pipeline?.status || "none"}`,
29394
+ context
29395
+ };
29396
+ }
29397
+ }
29398
+ const statusHints = {
29399
+ discussions_not_resolved: "Resolve all open discussion threads before merging.",
29400
+ draft_status: "MR is in draft. Mark as ready before merging.",
29401
+ need_rebase: "Source branch needs to be rebased onto the target branch.",
29402
+ requested_changes: "A reviewer requested changes that must be addressed.",
29403
+ policies_denied: "Merge is blocked by a security/compliance policy.",
29404
+ external_status_checks: "External status checks must pass before merging.",
29405
+ jira_association_missing: "MR must be linked to a Jira issue.",
29406
+ conflict: "MR has merge conflicts that must be resolved."
29407
+ };
29408
+ return {
29409
+ action: "failed",
29410
+ message: statusHints[mr.detailed_merge_status] ?? `Cannot merge: ${mr.detailed_merge_status}`,
29411
+ context
29412
+ };
29413
+ }
29313
29414
  };
29314
29415
 
29315
29416
  // src/client/issues.ts
@@ -31480,7 +31581,7 @@ Note: You must provide the current HEAD SHA of the MR to prevent race conditions
31480
31581
  "The HEAD SHA of the merge request. Get this from the MR details (diff_refs.head_sha or sha field)."
31481
31582
  ),
31482
31583
  strategy: z.enum(["MERGE_WHEN_CHECKS_PASS", "ADD_TO_MERGE_TRAIN_WHEN_CHECKS_PASS"]).optional().describe(
31483
- "Auto-merge strategy. MERGE_WHEN_CHECKS_PASS (default) waits for all checks including approvals. ADD_TO_MERGE_TRAIN_WHEN_CHECKS_PASS adds to merge train when checks pass."
31584
+ "MERGE_WHEN_CHECKS_PASS (default) waits for all checks. ADD_TO_MERGE_TRAIN_WHEN_CHECKS_PASS adds to merge train."
31484
31585
  )
31485
31586
  },
31486
31587
  execute: async (args, _ctx) => {
@@ -31494,6 +31595,62 @@ Note: You must provide the current HEAD SHA of the MR to prevent race conditions
31494
31595
  return JSON.stringify(result, null, 2);
31495
31596
  }
31496
31597
  }),
31598
+ gitlab_smart_merge_mr: tool({
31599
+ description: `Smart merge: merges immediately if checks pass, otherwise enables auto-merge (MWPS).
31600
+ This tool automatically determines the best merge action based on MR state:
31601
+ - If MR is mergeable (pipeline passed, approved): merges immediately
31602
+ - If pipeline is running or awaiting approval: enables auto-merge
31603
+ - Returns detailed context about what happened and why
31604
+
31605
+ Provides actionable feedback on failures including MR state, pipeline status, and remediation hints.
31606
+ Note: You must provide the current HEAD SHA of the MR to prevent race conditions.`,
31607
+ args: {
31608
+ project_id: z.string().describe('The project ID or path (e.g., "gitlab-org/gitlab")'),
31609
+ mr_iid: z.number().describe("The internal ID of the merge request"),
31610
+ sha: z.string().describe(
31611
+ "The HEAD SHA of the merge request. Get this from the MR details (diff_refs.head_sha or sha field)."
31612
+ ),
31613
+ strategy: z.enum(["MERGE_WHEN_CHECKS_PASS", "ADD_TO_MERGE_TRAIN_WHEN_CHECKS_PASS"]).optional().describe(
31614
+ "Auto-merge strategy when immediate merge is not possible. MERGE_WHEN_CHECKS_PASS (default) waits for all checks. ADD_TO_MERGE_TRAIN_WHEN_CHECKS_PASS adds to merge train."
31615
+ )
31616
+ },
31617
+ execute: async (args, _ctx) => {
31618
+ const client = getGitLabClient();
31619
+ const result = await client.smartMerge(
31620
+ args.project_id,
31621
+ args.mr_iid,
31622
+ args.sha,
31623
+ args.strategy || "MERGE_WHEN_CHECKS_PASS"
31624
+ );
31625
+ return JSON.stringify(result, null, 2);
31626
+ }
31627
+ }),
31628
+ gitlab_merge_mr: tool({
31629
+ description: `Merge a merge request immediately.
31630
+ Use this when you know the MR is ready to merge (pipeline passed, approved, no conflicts).
31631
+ For automatic handling based on MR state, use gitlab_smart_merge_mr instead.
31632
+
31633
+ WARNING: If sha is omitted, the merge may succeed against a newer commit than what was reviewed/approved.
31634
+ Always provide sha when you want to ensure you're merging the exact code that was reviewed.`,
31635
+ args: {
31636
+ project_id: z.string().describe('The project ID or path (e.g., "gitlab-org/gitlab")'),
31637
+ mr_iid: z.number().describe("The internal ID of the merge request"),
31638
+ sha: z.string().optional().describe(
31639
+ "HEAD SHA to verify before merging. Recommended to prevent merging unreviewed code if new commits were pushed."
31640
+ ),
31641
+ squash: z.boolean().optional().describe("Whether to squash commits (uses project default if not specified)"),
31642
+ should_remove_source_branch: z.boolean().optional().describe("Whether to delete source branch after merge")
31643
+ },
31644
+ execute: async (args, _ctx) => {
31645
+ const client = getGitLabClient();
31646
+ const result = await client.mergeMergeRequest(args.project_id, args.mr_iid, {
31647
+ sha: args.sha,
31648
+ squash: args.squash,
31649
+ shouldRemoveSourceBranch: args.should_remove_source_branch
31650
+ });
31651
+ return JSON.stringify(result, null, 2);
31652
+ }
31653
+ }),
31497
31654
  gitlab_approve_merge_request: tool({
31498
31655
  description: `Approve a merge request.
31499
31656
  Adds the current user's approval to the merge request.
@@ -33777,7 +33934,7 @@ async function main() {
33777
33934
  ...auditTools,
33778
33935
  ...awardEmojiTools
33779
33936
  };
33780
- const version2 = true ? "2.2.0" : "0.0.0";
33937
+ const version2 = true ? "2.4.0" : "0.0.0";
33781
33938
  const server = new McpServer({ name: "gitlab", version: version2 });
33782
33939
  adaptToolsToMcp(server, allTools);
33783
33940
  const transport = new StdioServerTransport();