opencode-gitlab-plugin 2.2.0 → 2.3.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 +7 -0
- package/dist/index.js +158 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.cjs +159 -2
- package/dist/mcp-server.cjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
## [2.3.0](https://gitlab.com/vglafirov/opencode-gitlab-plugin/compare/v2.2.0...v2.3.0) (2026-05-18)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### ✨ Features
|
|
9
|
+
|
|
10
|
+
* **merge-requests:** add smart merge with detailed context ([d03da5d](https://gitlab.com/vglafirov/opencode-gitlab-plugin/commit/d03da5d19d3851e1d3a59a07dd3155d307a0369c))
|
|
11
|
+
|
|
5
12
|
## [2.2.0](https://gitlab.com/vglafirov/opencode-gitlab-plugin/compare/v2.1.0...v2.2.0) (2026-04-07)
|
|
6
13
|
|
|
7
14
|
|
package/dist/index.js
CHANGED
|
@@ -545,6 +545,107 @@ var MergeRequestsClient = class extends GitLabApiClient {
|
|
|
545
545
|
`/projects/${encodedProject}/merge_requests/${mrIid}/unapprove`
|
|
546
546
|
);
|
|
547
547
|
}
|
|
548
|
+
/**
|
|
549
|
+
* Merge a merge request immediately
|
|
550
|
+
* Requires the MR to be in a mergeable state (approved, pipeline passed, no conflicts)
|
|
551
|
+
*/
|
|
552
|
+
async mergeMergeRequest(projectId, mrIid, options) {
|
|
553
|
+
const encodedProject = this.encodeProjectId(projectId);
|
|
554
|
+
const body = {};
|
|
555
|
+
if (options?.sha) body.sha = options.sha;
|
|
556
|
+
if (options?.squash !== void 0) body.squash = options.squash;
|
|
557
|
+
if (options?.shouldRemoveSourceBranch !== void 0) {
|
|
558
|
+
body.should_remove_source_branch = options.shouldRemoveSourceBranch;
|
|
559
|
+
}
|
|
560
|
+
return this.fetch(
|
|
561
|
+
"PUT",
|
|
562
|
+
`/projects/${encodedProject}/merge_requests/${mrIid}/merge`,
|
|
563
|
+
Object.keys(body).length > 0 ? body : void 0
|
|
564
|
+
);
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Smart merge: merge immediately if checks pass, otherwise set auto-merge
|
|
568
|
+
* Returns detailed context about what happened
|
|
569
|
+
*/
|
|
570
|
+
async smartMerge(projectId, mrIid, sha, strategy = "MERGE_WHEN_CHECKS_PASS") {
|
|
571
|
+
const mr = await this.getMergeRequest(projectId, mrIid);
|
|
572
|
+
const context = {
|
|
573
|
+
state: mr.state,
|
|
574
|
+
detailedMergeStatus: mr.detailed_merge_status,
|
|
575
|
+
pipelineStatus: mr.head_pipeline?.status || null,
|
|
576
|
+
hasConflicts: mr.has_conflicts,
|
|
577
|
+
hasAnyApproval: (mr.approved_by?.length || 0) > 0
|
|
578
|
+
};
|
|
579
|
+
if (mr.state !== "opened") {
|
|
580
|
+
return {
|
|
581
|
+
action: "failed",
|
|
582
|
+
message: `MR is not open (state: ${mr.state})`,
|
|
583
|
+
context
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
if (mr.has_conflicts) {
|
|
587
|
+
return {
|
|
588
|
+
action: "failed",
|
|
589
|
+
message: "MR has merge conflicts that must be resolved",
|
|
590
|
+
context
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
if (mr.detailed_merge_status === "mergeable") {
|
|
594
|
+
try {
|
|
595
|
+
const result = await this.mergeMergeRequest(projectId, mrIid, { sha: mr.sha });
|
|
596
|
+
return {
|
|
597
|
+
action: "merged",
|
|
598
|
+
message: "MR merged successfully",
|
|
599
|
+
mergeRequest: result,
|
|
600
|
+
context
|
|
601
|
+
};
|
|
602
|
+
} catch (error) {
|
|
603
|
+
return {
|
|
604
|
+
action: "failed",
|
|
605
|
+
message: `Direct merge failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
606
|
+
context
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
const autoMergeStatuses = ["ci_still_running", "not_approved", "checking"];
|
|
611
|
+
if (autoMergeStatuses.includes(mr.detailed_merge_status)) {
|
|
612
|
+
try {
|
|
613
|
+
const result = await this.setAutoMerge(projectId, mrIid, sha, strategy);
|
|
614
|
+
const autoMergeMessages = {
|
|
615
|
+
ci_still_running: "pipeline passes",
|
|
616
|
+
not_approved: "approved",
|
|
617
|
+
checking: "checks complete"
|
|
618
|
+
};
|
|
619
|
+
return {
|
|
620
|
+
action: "auto_merge_enabled",
|
|
621
|
+
message: `Auto-merge enabled (${strategy}). MR will merge when ${autoMergeMessages[mr.detailed_merge_status]}.`,
|
|
622
|
+
mergeRequest: result,
|
|
623
|
+
context
|
|
624
|
+
};
|
|
625
|
+
} catch (error) {
|
|
626
|
+
return {
|
|
627
|
+
action: "failed",
|
|
628
|
+
message: `Failed to enable auto-merge: ${error instanceof Error ? error.message : String(error)}. MR status: ${mr.detailed_merge_status}, pipeline: ${mr.head_pipeline?.status || "none"}`,
|
|
629
|
+
context
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
const statusHints = {
|
|
634
|
+
discussions_not_resolved: "Resolve all open discussion threads before merging.",
|
|
635
|
+
draft_status: "MR is in draft. Mark as ready before merging.",
|
|
636
|
+
need_rebase: "Source branch needs to be rebased onto the target branch.",
|
|
637
|
+
requested_changes: "A reviewer requested changes that must be addressed.",
|
|
638
|
+
policies_denied: "Merge is blocked by a security/compliance policy.",
|
|
639
|
+
external_status_checks: "External status checks must pass before merging.",
|
|
640
|
+
jira_association_missing: "MR must be linked to a Jira issue.",
|
|
641
|
+
conflict: "MR has merge conflicts that must be resolved."
|
|
642
|
+
};
|
|
643
|
+
return {
|
|
644
|
+
action: "failed",
|
|
645
|
+
message: statusHints[mr.detailed_merge_status] ?? `Cannot merge: ${mr.detailed_merge_status}`,
|
|
646
|
+
context
|
|
647
|
+
};
|
|
648
|
+
}
|
|
548
649
|
};
|
|
549
650
|
|
|
550
651
|
// src/client/issues.ts
|
|
@@ -2709,7 +2810,7 @@ Note: You must provide the current HEAD SHA of the MR to prevent race conditions
|
|
|
2709
2810
|
"The HEAD SHA of the merge request. Get this from the MR details (diff_refs.head_sha or sha field)."
|
|
2710
2811
|
),
|
|
2711
2812
|
strategy: z.enum(["MERGE_WHEN_CHECKS_PASS", "ADD_TO_MERGE_TRAIN_WHEN_CHECKS_PASS"]).optional().describe(
|
|
2712
|
-
"
|
|
2813
|
+
"MERGE_WHEN_CHECKS_PASS (default) waits for all checks. ADD_TO_MERGE_TRAIN_WHEN_CHECKS_PASS adds to merge train."
|
|
2713
2814
|
)
|
|
2714
2815
|
},
|
|
2715
2816
|
execute: async (args, _ctx) => {
|
|
@@ -2723,6 +2824,62 @@ Note: You must provide the current HEAD SHA of the MR to prevent race conditions
|
|
|
2723
2824
|
return JSON.stringify(result, null, 2);
|
|
2724
2825
|
}
|
|
2725
2826
|
}),
|
|
2827
|
+
gitlab_smart_merge_mr: tool({
|
|
2828
|
+
description: `Smart merge: merges immediately if checks pass, otherwise enables auto-merge (MWPS).
|
|
2829
|
+
This tool automatically determines the best merge action based on MR state:
|
|
2830
|
+
- If MR is mergeable (pipeline passed, approved): merges immediately
|
|
2831
|
+
- If pipeline is running or awaiting approval: enables auto-merge
|
|
2832
|
+
- Returns detailed context about what happened and why
|
|
2833
|
+
|
|
2834
|
+
Provides actionable feedback on failures including MR state, pipeline status, and remediation hints.
|
|
2835
|
+
Note: You must provide the current HEAD SHA of the MR to prevent race conditions.`,
|
|
2836
|
+
args: {
|
|
2837
|
+
project_id: z.string().describe('The project ID or path (e.g., "gitlab-org/gitlab")'),
|
|
2838
|
+
mr_iid: z.number().describe("The internal ID of the merge request"),
|
|
2839
|
+
sha: z.string().describe(
|
|
2840
|
+
"The HEAD SHA of the merge request. Get this from the MR details (diff_refs.head_sha or sha field)."
|
|
2841
|
+
),
|
|
2842
|
+
strategy: z.enum(["MERGE_WHEN_CHECKS_PASS", "ADD_TO_MERGE_TRAIN_WHEN_CHECKS_PASS"]).optional().describe(
|
|
2843
|
+
"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."
|
|
2844
|
+
)
|
|
2845
|
+
},
|
|
2846
|
+
execute: async (args, _ctx) => {
|
|
2847
|
+
const client = getGitLabClient();
|
|
2848
|
+
const result = await client.smartMerge(
|
|
2849
|
+
args.project_id,
|
|
2850
|
+
args.mr_iid,
|
|
2851
|
+
args.sha,
|
|
2852
|
+
args.strategy || "MERGE_WHEN_CHECKS_PASS"
|
|
2853
|
+
);
|
|
2854
|
+
return JSON.stringify(result, null, 2);
|
|
2855
|
+
}
|
|
2856
|
+
}),
|
|
2857
|
+
gitlab_merge_mr: tool({
|
|
2858
|
+
description: `Merge a merge request immediately.
|
|
2859
|
+
Use this when you know the MR is ready to merge (pipeline passed, approved, no conflicts).
|
|
2860
|
+
For automatic handling based on MR state, use gitlab_smart_merge_mr instead.
|
|
2861
|
+
|
|
2862
|
+
WARNING: If sha is omitted, the merge may succeed against a newer commit than what was reviewed/approved.
|
|
2863
|
+
Always provide sha when you want to ensure you're merging the exact code that was reviewed.`,
|
|
2864
|
+
args: {
|
|
2865
|
+
project_id: z.string().describe('The project ID or path (e.g., "gitlab-org/gitlab")'),
|
|
2866
|
+
mr_iid: z.number().describe("The internal ID of the merge request"),
|
|
2867
|
+
sha: z.string().optional().describe(
|
|
2868
|
+
"HEAD SHA to verify before merging. Recommended to prevent merging unreviewed code if new commits were pushed."
|
|
2869
|
+
),
|
|
2870
|
+
squash: z.boolean().optional().describe("Whether to squash commits (uses project default if not specified)"),
|
|
2871
|
+
should_remove_source_branch: z.boolean().optional().describe("Whether to delete source branch after merge")
|
|
2872
|
+
},
|
|
2873
|
+
execute: async (args, _ctx) => {
|
|
2874
|
+
const client = getGitLabClient();
|
|
2875
|
+
const result = await client.mergeMergeRequest(args.project_id, args.mr_iid, {
|
|
2876
|
+
sha: args.sha,
|
|
2877
|
+
squash: args.squash,
|
|
2878
|
+
shouldRemoveSourceBranch: args.should_remove_source_branch
|
|
2879
|
+
});
|
|
2880
|
+
return JSON.stringify(result, null, 2);
|
|
2881
|
+
}
|
|
2882
|
+
}),
|
|
2726
2883
|
gitlab_approve_merge_request: tool({
|
|
2727
2884
|
description: `Approve a merge request.
|
|
2728
2885
|
Adds the current user's approval to the merge request.
|