opencode-gitlab-plugin 2.6.0 → 2.6.1
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 +8 -0
- package/dist/index.js +85 -64
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.cjs +86 -65
- package/dist/mcp-server.cjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
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.6.1](https://gitlab.com/vglafirov/opencode-gitlab-plugin/compare/v2.6.0...v2.6.1) (2026-08-17)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### 🐛 Bug Fixes
|
|
9
|
+
|
|
10
|
+
* **merge-requests:** resolve MWPS 'checking' race in smartMerge/setAutoMerge ([b9a992f](https://gitlab.com/vglafirov/opencode-gitlab-plugin/commit/b9a992f6ebec655fba271623bf5fc963cfe16f09))
|
|
11
|
+
* **work-items:** avoid nullability mismatch on widget inputs ([1ae3cd7](https://gitlab.com/vglafirov/opencode-gitlab-plugin/commit/1ae3cd79627c6cca88955f90af13694472939331))
|
|
12
|
+
|
|
5
13
|
## [2.6.0](https://gitlab.com/vglafirov/opencode-gitlab-plugin/compare/v2.5.0...v2.6.0) (2026-05-20)
|
|
6
14
|
|
|
7
15
|
|
package/dist/index.js
CHANGED
|
@@ -341,7 +341,7 @@ var RESOLVE_DISCUSSION_MUTATION = `
|
|
|
341
341
|
}
|
|
342
342
|
}
|
|
343
343
|
`;
|
|
344
|
-
var MergeRequestsClient = class extends GitLabApiClient {
|
|
344
|
+
var MergeRequestsClient = class _MergeRequestsClient extends GitLabApiClient {
|
|
345
345
|
async getMergeRequest(projectId, mrIid, includeChanges) {
|
|
346
346
|
const encodedProject = this.encodeProjectId(projectId);
|
|
347
347
|
let path2 = `/projects/${encodedProject}/merge_requests/${mrIid}`;
|
|
@@ -563,20 +563,48 @@ var MergeRequestsClient = class extends GitLabApiClient {
|
|
|
563
563
|
* Set auto-merge (MWPS) on a merge request using GraphQL API
|
|
564
564
|
* Uses the mergeRequestAccept mutation with a merge strategy
|
|
565
565
|
*/
|
|
566
|
-
async setAutoMerge(projectId, mrIid, sha, strategy = "MERGE_WHEN_CHECKS_PASS") {
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
566
|
+
async setAutoMerge(projectId, mrIid, sha, strategy = "MERGE_WHEN_CHECKS_PASS", retries = 3) {
|
|
567
|
+
let lastError = null;
|
|
568
|
+
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
569
|
+
const result = await this.fetchGraphQL(SET_AUTO_MERGE_MUTATION, {
|
|
570
|
+
projectPath: projectId,
|
|
571
|
+
iid: String(mrIid),
|
|
572
|
+
sha,
|
|
573
|
+
strategy
|
|
574
|
+
});
|
|
575
|
+
if (result.mergeRequestAccept.errors.length > 0) {
|
|
576
|
+
const message = result.mergeRequestAccept.errors.join(", ");
|
|
577
|
+
lastError = new Error(`Failed to set auto-merge: ${message}`);
|
|
578
|
+
if (attempt < retries && _MergeRequestsClient.isTransientMergeError(message)) {
|
|
579
|
+
await _MergeRequestsClient.delay(750 * (attempt + 1));
|
|
580
|
+
continue;
|
|
581
|
+
}
|
|
582
|
+
throw lastError;
|
|
583
|
+
}
|
|
584
|
+
if (!result.mergeRequestAccept.mergeRequest) {
|
|
585
|
+
lastError = new Error("Failed to set auto-merge: No merge request returned");
|
|
586
|
+
if (attempt < retries) {
|
|
587
|
+
await _MergeRequestsClient.delay(750 * (attempt + 1));
|
|
588
|
+
continue;
|
|
589
|
+
}
|
|
590
|
+
throw lastError;
|
|
591
|
+
}
|
|
592
|
+
return result.mergeRequestAccept.mergeRequest;
|
|
578
593
|
}
|
|
579
|
-
|
|
594
|
+
throw lastError ?? new Error("Failed to set auto-merge: exhausted retries");
|
|
595
|
+
}
|
|
596
|
+
/**
|
|
597
|
+
* True for GitLab merge errors that are transient because mergeability is
|
|
598
|
+
* still being (re)computed. Such errors clear on their own within a second
|
|
599
|
+
* or two, so callers should retry rather than treat them as real failures.
|
|
600
|
+
*/
|
|
601
|
+
static isTransientMergeError(message) {
|
|
602
|
+
const m = message.toLowerCase();
|
|
603
|
+
return m.includes("being checked") || m.includes("being recomputed") || m.includes("cannot be merged") || m.includes("not mergeable") || m.includes("merge failed") || m.includes("try again");
|
|
604
|
+
}
|
|
605
|
+
/** Small awaitable delay helper (ms). */
|
|
606
|
+
static delay(ms) {
|
|
607
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
580
608
|
}
|
|
581
609
|
/**
|
|
582
610
|
* Approve a merge request
|
|
@@ -624,7 +652,13 @@ var MergeRequestsClient = class extends GitLabApiClient {
|
|
|
624
652
|
* Returns detailed context about what happened
|
|
625
653
|
*/
|
|
626
654
|
async smartMerge(projectId, mrIid, sha, strategy = "MERGE_WHEN_CHECKS_PASS") {
|
|
627
|
-
|
|
655
|
+
let mr = await this.getMergeRequest(projectId, mrIid);
|
|
656
|
+
if (mr.detailed_merge_status === "checking") {
|
|
657
|
+
for (let attempt = 0; attempt < 5 && mr.detailed_merge_status === "checking"; attempt++) {
|
|
658
|
+
await _MergeRequestsClient.delay(1e3 * (attempt + 1));
|
|
659
|
+
mr = await this.getMergeRequest(projectId, mrIid);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
628
662
|
const context = {
|
|
629
663
|
state: mr.state,
|
|
630
664
|
detailedMergeStatus: mr.detailed_merge_status,
|
|
@@ -663,14 +697,13 @@ var MergeRequestsClient = class extends GitLabApiClient {
|
|
|
663
697
|
};
|
|
664
698
|
}
|
|
665
699
|
}
|
|
666
|
-
const autoMergeStatuses = ["ci_still_running", "not_approved"
|
|
700
|
+
const autoMergeStatuses = ["ci_still_running", "not_approved"];
|
|
667
701
|
if (autoMergeStatuses.includes(mr.detailed_merge_status)) {
|
|
668
702
|
try {
|
|
669
703
|
const result = await this.setAutoMerge(projectId, mrIid, sha, strategy);
|
|
670
704
|
const autoMergeMessages = {
|
|
671
705
|
ci_still_running: "pipeline passes",
|
|
672
|
-
not_approved: "approved"
|
|
673
|
-
checking: "checks complete"
|
|
706
|
+
not_approved: "approved"
|
|
674
707
|
};
|
|
675
708
|
return {
|
|
676
709
|
action: "auto_merge_enabled",
|
|
@@ -1029,22 +1062,8 @@ var GET_WORK_ITEM_NOTES_QUERY = `
|
|
|
1029
1062
|
}
|
|
1030
1063
|
`;
|
|
1031
1064
|
var CREATE_WORK_ITEM_MUTATION = `
|
|
1032
|
-
mutation createWorkItem(
|
|
1033
|
-
|
|
1034
|
-
$title: String!
|
|
1035
|
-
$workItemTypeId: WorkItemsTypeID!
|
|
1036
|
-
$description: String
|
|
1037
|
-
$labelIds: [LabelID!]
|
|
1038
|
-
$assigneeIds: [UserID!]
|
|
1039
|
-
) {
|
|
1040
|
-
workItemCreate(input: {
|
|
1041
|
-
projectPath: $projectPath
|
|
1042
|
-
title: $title
|
|
1043
|
-
workItemTypeId: $workItemTypeId
|
|
1044
|
-
descriptionWidget: { description: $description }
|
|
1045
|
-
labelsWidget: { labelIds: $labelIds }
|
|
1046
|
-
assigneesWidget: { assigneeIds: $assigneeIds }
|
|
1047
|
-
}) {
|
|
1065
|
+
mutation createWorkItem($input: WorkItemCreateInput!) {
|
|
1066
|
+
workItemCreate(input: $input) {
|
|
1048
1067
|
workItem {
|
|
1049
1068
|
${WORK_ITEM_FIELDS}
|
|
1050
1069
|
}
|
|
@@ -1053,22 +1072,8 @@ var CREATE_WORK_ITEM_MUTATION = `
|
|
|
1053
1072
|
}
|
|
1054
1073
|
`;
|
|
1055
1074
|
var UPDATE_WORK_ITEM_MUTATION = `
|
|
1056
|
-
mutation updateWorkItem(
|
|
1057
|
-
|
|
1058
|
-
$title: String
|
|
1059
|
-
$description: String
|
|
1060
|
-
$stateEvent: WorkItemStateEvent
|
|
1061
|
-
$labelIds: [LabelID!]
|
|
1062
|
-
$assigneeIds: [UserID!]
|
|
1063
|
-
) {
|
|
1064
|
-
workItemUpdate(input: {
|
|
1065
|
-
id: $id
|
|
1066
|
-
title: $title
|
|
1067
|
-
descriptionWidget: { description: $description }
|
|
1068
|
-
stateEvent: $stateEvent
|
|
1069
|
-
labelsWidget: { labelIds: $labelIds }
|
|
1070
|
-
assigneesWidget: { assigneeIds: $assigneeIds }
|
|
1071
|
-
}) {
|
|
1075
|
+
mutation updateWorkItem($input: WorkItemUpdateInput!) {
|
|
1076
|
+
workItemUpdate(input: $input) {
|
|
1072
1077
|
workItem {
|
|
1073
1078
|
${WORK_ITEM_FIELDS}
|
|
1074
1079
|
}
|
|
@@ -1162,14 +1167,21 @@ var WorkItemsClient = class extends GitLabApiClient {
|
|
|
1162
1167
|
async createWorkItem(projectId, options) {
|
|
1163
1168
|
const labelIds = options.labels?.map((l) => toGid("Label", l));
|
|
1164
1169
|
const assigneeIds = options.assignee_ids?.map((id) => toGid("User", id));
|
|
1165
|
-
const
|
|
1170
|
+
const input = {
|
|
1166
1171
|
projectPath: projectId,
|
|
1167
1172
|
title: options.title,
|
|
1168
|
-
workItemTypeId: toGid("WorkItems::Type", options.work_item_type_id)
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
}
|
|
1173
|
+
workItemTypeId: toGid("WorkItems::Type", options.work_item_type_id)
|
|
1174
|
+
};
|
|
1175
|
+
if (options.description !== void 0) {
|
|
1176
|
+
input.descriptionWidget = { description: options.description };
|
|
1177
|
+
}
|
|
1178
|
+
if (labelIds?.length) {
|
|
1179
|
+
input.labelsWidget = { labelIds };
|
|
1180
|
+
}
|
|
1181
|
+
if (assigneeIds?.length) {
|
|
1182
|
+
input.assigneesWidget = { assigneeIds };
|
|
1183
|
+
}
|
|
1184
|
+
const result = await this.fetchGraphQL(CREATE_WORK_ITEM_MUTATION, { input });
|
|
1173
1185
|
if (result.workItemCreate.errors.length > 0) {
|
|
1174
1186
|
throw new Error(`Failed to create work item: ${result.workItemCreate.errors.join(", ")}`);
|
|
1175
1187
|
}
|
|
@@ -1187,14 +1199,23 @@ var WorkItemsClient = class extends GitLabApiClient {
|
|
|
1187
1199
|
const stateEvent = options.state_event ? options.state_event === "close" ? "CLOSE" : "REOPEN" : void 0;
|
|
1188
1200
|
const labelIds = options.labels?.map((l) => toGid("Label", l));
|
|
1189
1201
|
const assigneeIds = options.assignee_ids?.map((id) => toGid("User", id));
|
|
1190
|
-
const
|
|
1191
|
-
|
|
1192
|
-
title
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1202
|
+
const input = { id: gid };
|
|
1203
|
+
if (options.title !== void 0) {
|
|
1204
|
+
input.title = options.title;
|
|
1205
|
+
}
|
|
1206
|
+
if (options.description !== void 0) {
|
|
1207
|
+
input.descriptionWidget = { description: options.description };
|
|
1208
|
+
}
|
|
1209
|
+
if (stateEvent !== void 0) {
|
|
1210
|
+
input.stateEvent = stateEvent;
|
|
1211
|
+
}
|
|
1212
|
+
if (labelIds?.length) {
|
|
1213
|
+
input.labelsWidget = { addLabelIds: labelIds };
|
|
1214
|
+
}
|
|
1215
|
+
if (assigneeIds?.length) {
|
|
1216
|
+
input.assigneesWidget = { assigneeIds };
|
|
1217
|
+
}
|
|
1218
|
+
const result = await this.fetchGraphQL(UPDATE_WORK_ITEM_MUTATION, { input });
|
|
1198
1219
|
if (result.workItemUpdate.errors.length > 0) {
|
|
1199
1220
|
throw new Error(`Failed to update work item: ${result.workItemUpdate.errors.join(", ")}`);
|
|
1200
1221
|
}
|