@zereight/mcp-gitlab 1.0.65 → 1.0.66
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/README.md +32 -2
- package/build/index.js +82 -62
- package/build/schemas.js +7 -23
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -35,11 +35,39 @@ When using with the Claude App, you need to set up your API key and URLs directl
|
|
|
35
35
|
}
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
+
#### vscode .vscode/mcp.json
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"inputs": [
|
|
43
|
+
{
|
|
44
|
+
"type": "promptString",
|
|
45
|
+
"id": "gitlab-token",
|
|
46
|
+
"description": "Gitlab Token to read API",
|
|
47
|
+
"password": true
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
"servers": {
|
|
51
|
+
"GitLab-MCP": {
|
|
52
|
+
"type": "stdio",
|
|
53
|
+
"command": "npx",
|
|
54
|
+
"args": ["-y", "@zereight/mcp-gitlab"],
|
|
55
|
+
"env": {
|
|
56
|
+
"GITLAB_PERSONAL_ACCESS_TOKEN": "${input:gitlab-token}",
|
|
57
|
+
"GITLAB_API_URL": "your-fancy-gitlab-url",
|
|
58
|
+
"GITLAB_READ_ONLY_MODE": "true",
|
|
59
|
+
...
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
38
66
|
#### Docker
|
|
39
67
|
|
|
40
|
-
- stdio
|
|
68
|
+
- stdio mcp.json
|
|
41
69
|
|
|
42
|
-
```
|
|
70
|
+
```json
|
|
43
71
|
{
|
|
44
72
|
"mcpServers": {
|
|
45
73
|
"GitLab communication server": {
|
|
@@ -94,6 +122,7 @@ docker run -i --rm \
|
|
|
94
122
|
{
|
|
95
123
|
"mcpServers": {
|
|
96
124
|
"GitLab communication server": {
|
|
125
|
+
"type": "sse",
|
|
97
126
|
"url": "http://localhost:3333/sse"
|
|
98
127
|
}
|
|
99
128
|
}
|
|
@@ -110,6 +139,7 @@ $ sh scripts/image_push.sh docker_user_name
|
|
|
110
139
|
|
|
111
140
|
- `GITLAB_PERSONAL_ACCESS_TOKEN`: Your GitLab personal access token.
|
|
112
141
|
- `GITLAB_API_URL`: Your GitLab API URL. (Default: `https://gitlab.com/api/v4`)
|
|
142
|
+
- `GITLAB_PROJECT_ID`: Default project ID. If set, Overwrite this value when making an API request.
|
|
113
143
|
- `GITLAB_READ_ONLY_MODE`: When set to 'true', restricts the server to only expose read-only operations. Useful for enhanced security or when write access is not needed. Also useful for using with Cursor and it's 40 tool limit.
|
|
114
144
|
- `USE_GITLAB_WIKI`: When set to 'true', enables the wiki-related tools (list_wiki_pages, get_wiki_page, create_wiki_page, update_wiki_page, delete_wiki_page). By default, wiki features are disabled.
|
|
115
145
|
- `USE_MILESTONE`: When set to 'true', enables the milestone-related tools (list_milestones, get_milestone, create_milestone, edit_milestone, delete_milestone, get_milestone_issue, get_milestone_merge_requests, promote_milestone, get_milestone_burndown_events). By default, milestone features are disabled.
|
package/build/index.js
CHANGED
|
@@ -626,6 +626,7 @@ function normalizeGitLabApiUrl(url) {
|
|
|
626
626
|
}
|
|
627
627
|
// Use the normalizeGitLabApiUrl function to handle various URL formats
|
|
628
628
|
const GITLAB_API_URL = normalizeGitLabApiUrl(process.env.GITLAB_API_URL || "");
|
|
629
|
+
const GITLAB_PROJECT_ID = process.env.GITLAB_PROJECT_ID;
|
|
629
630
|
if (!GITLAB_PERSONAL_ACCESS_TOKEN) {
|
|
630
631
|
console.error("GITLAB_PERSONAL_ACCESS_TOKEN environment variable is not set");
|
|
631
632
|
process.exit(1);
|
|
@@ -652,6 +653,13 @@ async function handleGitLabError(response) {
|
|
|
652
653
|
}
|
|
653
654
|
}
|
|
654
655
|
}
|
|
656
|
+
/**
|
|
657
|
+
* @param {string} projectId - The project ID parameter passed to the function
|
|
658
|
+
* @returns {string} The project ID to use for the API call
|
|
659
|
+
*/
|
|
660
|
+
function getEffectiveProjectId(projectId) {
|
|
661
|
+
return GITLAB_PROJECT_ID || projectId;
|
|
662
|
+
}
|
|
655
663
|
/**
|
|
656
664
|
* Create a fork of a GitLab project
|
|
657
665
|
* 프로젝트 포크 생성 (Create a project fork)
|
|
@@ -662,7 +670,8 @@ async function handleGitLabError(response) {
|
|
|
662
670
|
*/
|
|
663
671
|
async function forkProject(projectId, namespace) {
|
|
664
672
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
665
|
-
const
|
|
673
|
+
const effectiveProjectId = getEffectiveProjectId(projectId);
|
|
674
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(effectiveProjectId)}/fork`);
|
|
666
675
|
if (namespace) {
|
|
667
676
|
url.searchParams.append("namespace", namespace);
|
|
668
677
|
}
|
|
@@ -688,7 +697,8 @@ async function forkProject(projectId, namespace) {
|
|
|
688
697
|
*/
|
|
689
698
|
async function createBranch(projectId, options) {
|
|
690
699
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
691
|
-
const
|
|
700
|
+
const effectiveProjectId = getEffectiveProjectId(projectId);
|
|
701
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(effectiveProjectId)}/repository/branches`);
|
|
692
702
|
const response = await fetch(url.toString(), {
|
|
693
703
|
...DEFAULT_FETCH_CONFIG,
|
|
694
704
|
method: "POST",
|
|
@@ -709,7 +719,8 @@ async function createBranch(projectId, options) {
|
|
|
709
719
|
*/
|
|
710
720
|
async function getDefaultBranchRef(projectId) {
|
|
711
721
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
712
|
-
const
|
|
722
|
+
const effectiveProjectId = getEffectiveProjectId(projectId);
|
|
723
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(effectiveProjectId)}`);
|
|
713
724
|
const response = await fetch(url.toString(), {
|
|
714
725
|
...DEFAULT_FETCH_CONFIG,
|
|
715
726
|
});
|
|
@@ -728,12 +739,13 @@ async function getDefaultBranchRef(projectId) {
|
|
|
728
739
|
*/
|
|
729
740
|
async function getFileContents(projectId, filePath, ref) {
|
|
730
741
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
742
|
+
const effectiveProjectId = getEffectiveProjectId(projectId);
|
|
731
743
|
const encodedPath = encodeURIComponent(filePath);
|
|
732
744
|
// ref가 없는 경우 default branch를 가져옴
|
|
733
745
|
if (!ref) {
|
|
734
746
|
ref = await getDefaultBranchRef(projectId);
|
|
735
747
|
}
|
|
736
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(
|
|
748
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(effectiveProjectId)}/repository/files/${encodedPath}`);
|
|
737
749
|
url.searchParams.append("ref", ref);
|
|
738
750
|
const response = await fetch(url.toString(), {
|
|
739
751
|
...DEFAULT_FETCH_CONFIG,
|
|
@@ -762,7 +774,8 @@ async function getFileContents(projectId, filePath, ref) {
|
|
|
762
774
|
*/
|
|
763
775
|
async function createIssue(projectId, options) {
|
|
764
776
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
765
|
-
const
|
|
777
|
+
const effectiveProjectId = getEffectiveProjectId(projectId);
|
|
778
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(effectiveProjectId)}/issues`);
|
|
766
779
|
const response = await fetch(url.toString(), {
|
|
767
780
|
...DEFAULT_FETCH_CONFIG,
|
|
768
781
|
method: "POST",
|
|
@@ -793,7 +806,8 @@ async function createIssue(projectId, options) {
|
|
|
793
806
|
*/
|
|
794
807
|
async function listIssues(projectId, options = {}) {
|
|
795
808
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
796
|
-
const
|
|
809
|
+
const effectiveProjectId = getEffectiveProjectId(projectId);
|
|
810
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(effectiveProjectId)}/issues`);
|
|
797
811
|
// Add all query parameters
|
|
798
812
|
Object.entries(options).forEach(([key, value]) => {
|
|
799
813
|
if (value !== undefined) {
|
|
@@ -830,7 +844,7 @@ async function listIssues(projectId, options = {}) {
|
|
|
830
844
|
*/
|
|
831
845
|
async function listMergeRequests(projectId, options = {}) {
|
|
832
846
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
833
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/merge_requests`);
|
|
847
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/merge_requests`);
|
|
834
848
|
// Add all query parameters
|
|
835
849
|
Object.entries(options).forEach(([key, value]) => {
|
|
836
850
|
if (value !== undefined) {
|
|
@@ -860,7 +874,7 @@ async function listMergeRequests(projectId, options = {}) {
|
|
|
860
874
|
*/
|
|
861
875
|
async function getIssue(projectId, issueIid) {
|
|
862
876
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
863
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/issues/${issueIid}`);
|
|
877
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/issues/${issueIid}`);
|
|
864
878
|
const response = await fetch(url.toString(), {
|
|
865
879
|
...DEFAULT_FETCH_CONFIG,
|
|
866
880
|
});
|
|
@@ -879,7 +893,7 @@ async function getIssue(projectId, issueIid) {
|
|
|
879
893
|
*/
|
|
880
894
|
async function updateIssue(projectId, issueIid, options) {
|
|
881
895
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
882
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/issues/${issueIid}`);
|
|
896
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/issues/${issueIid}`);
|
|
883
897
|
// Convert labels array to comma-separated string if present
|
|
884
898
|
const body = { ...options };
|
|
885
899
|
if (body.labels && Array.isArray(body.labels)) {
|
|
@@ -904,7 +918,7 @@ async function updateIssue(projectId, issueIid, options) {
|
|
|
904
918
|
*/
|
|
905
919
|
async function deleteIssue(projectId, issueIid) {
|
|
906
920
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
907
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/issues/${issueIid}`);
|
|
921
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/issues/${issueIid}`);
|
|
908
922
|
const response = await fetch(url.toString(), {
|
|
909
923
|
...DEFAULT_FETCH_CONFIG,
|
|
910
924
|
method: "DELETE",
|
|
@@ -921,7 +935,7 @@ async function deleteIssue(projectId, issueIid) {
|
|
|
921
935
|
*/
|
|
922
936
|
async function listIssueLinks(projectId, issueIid) {
|
|
923
937
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
924
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/issues/${issueIid}/links`);
|
|
938
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/issues/${issueIid}/links`);
|
|
925
939
|
const response = await fetch(url.toString(), {
|
|
926
940
|
...DEFAULT_FETCH_CONFIG,
|
|
927
941
|
});
|
|
@@ -940,7 +954,7 @@ async function listIssueLinks(projectId, issueIid) {
|
|
|
940
954
|
*/
|
|
941
955
|
async function getIssueLink(projectId, issueIid, issueLinkId) {
|
|
942
956
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
943
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/issues/${issueIid}/links/${issueLinkId}`);
|
|
957
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/issues/${issueIid}/links/${issueLinkId}`);
|
|
944
958
|
const response = await fetch(url.toString(), {
|
|
945
959
|
...DEFAULT_FETCH_CONFIG,
|
|
946
960
|
});
|
|
@@ -962,7 +976,7 @@ async function getIssueLink(projectId, issueIid, issueLinkId) {
|
|
|
962
976
|
async function createIssueLink(projectId, issueIid, targetProjectId, targetIssueIid, linkType = "relates_to") {
|
|
963
977
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
964
978
|
targetProjectId = decodeURIComponent(targetProjectId); // Decode target project ID as well
|
|
965
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/issues/${issueIid}/links`);
|
|
979
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/issues/${issueIid}/links`);
|
|
966
980
|
const response = await fetch(url.toString(), {
|
|
967
981
|
...DEFAULT_FETCH_CONFIG,
|
|
968
982
|
method: "POST",
|
|
@@ -987,7 +1001,7 @@ async function createIssueLink(projectId, issueIid, targetProjectId, targetIssue
|
|
|
987
1001
|
*/
|
|
988
1002
|
async function deleteIssueLink(projectId, issueIid, issueLinkId) {
|
|
989
1003
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
990
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/issues/${issueIid}/links/${issueLinkId}`);
|
|
1004
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/issues/${issueIid}/links/${issueLinkId}`);
|
|
991
1005
|
const response = await fetch(url.toString(), {
|
|
992
1006
|
...DEFAULT_FETCH_CONFIG,
|
|
993
1007
|
method: "DELETE",
|
|
@@ -1004,7 +1018,7 @@ async function deleteIssueLink(projectId, issueIid, issueLinkId) {
|
|
|
1004
1018
|
*/
|
|
1005
1019
|
async function createMergeRequest(projectId, options) {
|
|
1006
1020
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
1007
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/merge_requests`);
|
|
1021
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/merge_requests`);
|
|
1008
1022
|
const response = await fetch(url.toString(), {
|
|
1009
1023
|
...DEFAULT_FETCH_CONFIG,
|
|
1010
1024
|
method: "POST",
|
|
@@ -1045,7 +1059,7 @@ async function createMergeRequest(projectId, options) {
|
|
|
1045
1059
|
*/
|
|
1046
1060
|
async function listDiscussions(projectId, resourceType, resourceIid, options = {}) {
|
|
1047
1061
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
1048
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/${resourceType}/${resourceIid}/discussions`);
|
|
1062
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/${resourceType}/${resourceIid}/discussions`);
|
|
1049
1063
|
// Add query parameters for pagination and sorting
|
|
1050
1064
|
if (options.page) {
|
|
1051
1065
|
url.searchParams.append("page", options.page.toString());
|
|
@@ -1117,7 +1131,7 @@ async function listIssueDiscussions(projectId, issueIid, options = {}) {
|
|
|
1117
1131
|
*/
|
|
1118
1132
|
async function updateMergeRequestNote(projectId, mergeRequestIid, discussionId, noteId, body, resolved) {
|
|
1119
1133
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
1120
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/discussions/${discussionId}/notes/${noteId}`);
|
|
1134
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/merge_requests/${mergeRequestIid}/discussions/${discussionId}/notes/${noteId}`);
|
|
1121
1135
|
// Only one of body or resolved can be sent according to GitLab API
|
|
1122
1136
|
const payload = {};
|
|
1123
1137
|
if (body !== undefined) {
|
|
@@ -1146,7 +1160,7 @@ async function updateMergeRequestNote(projectId, mergeRequestIid, discussionId,
|
|
|
1146
1160
|
*/
|
|
1147
1161
|
async function updateIssueNote(projectId, issueIid, discussionId, noteId, body) {
|
|
1148
1162
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
1149
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/issues/${issueIid}/discussions/${discussionId}/notes/${noteId}`);
|
|
1163
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/issues/${issueIid}/discussions/${discussionId}/notes/${noteId}`);
|
|
1150
1164
|
const payload = { body };
|
|
1151
1165
|
const response = await fetch(url.toString(), {
|
|
1152
1166
|
...DEFAULT_FETCH_CONFIG,
|
|
@@ -1168,7 +1182,7 @@ async function updateIssueNote(projectId, issueIid, discussionId, noteId, body)
|
|
|
1168
1182
|
*/
|
|
1169
1183
|
async function createIssueNote(projectId, issueIid, discussionId, body, createdAt) {
|
|
1170
1184
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
1171
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/issues/${issueIid}/discussions/${discussionId}/notes`);
|
|
1185
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/issues/${issueIid}/discussions/${discussionId}/notes`);
|
|
1172
1186
|
const payload = { body };
|
|
1173
1187
|
if (createdAt) {
|
|
1174
1188
|
payload.created_at = createdAt;
|
|
@@ -1195,7 +1209,7 @@ async function createIssueNote(projectId, issueIid, discussionId, body, createdA
|
|
|
1195
1209
|
*/
|
|
1196
1210
|
async function createMergeRequestNote(projectId, mergeRequestIid, discussionId, body, createdAt) {
|
|
1197
1211
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
1198
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/discussions/${discussionId}/notes`);
|
|
1212
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/merge_requests/${mergeRequestIid}/discussions/${discussionId}/notes`);
|
|
1199
1213
|
const payload = { body };
|
|
1200
1214
|
if (createdAt) {
|
|
1201
1215
|
payload.created_at = createdAt;
|
|
@@ -1224,7 +1238,7 @@ async function createMergeRequestNote(projectId, mergeRequestIid, discussionId,
|
|
|
1224
1238
|
async function createOrUpdateFile(projectId, filePath, content, commitMessage, branch, previousPath, last_commit_id, commit_id) {
|
|
1225
1239
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
1226
1240
|
const encodedPath = encodeURIComponent(filePath);
|
|
1227
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/repository/files/${encodedPath}`);
|
|
1241
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/repository/files/${encodedPath}`);
|
|
1228
1242
|
const body = {
|
|
1229
1243
|
branch,
|
|
1230
1244
|
content,
|
|
@@ -1291,7 +1305,7 @@ async function createOrUpdateFile(projectId, filePath, content, commitMessage, b
|
|
|
1291
1305
|
*/
|
|
1292
1306
|
async function createTree(projectId, files, ref) {
|
|
1293
1307
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
1294
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/repository/tree`);
|
|
1308
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/repository/tree`);
|
|
1295
1309
|
if (ref) {
|
|
1296
1310
|
url.searchParams.append("ref", ref);
|
|
1297
1311
|
}
|
|
@@ -1329,7 +1343,7 @@ async function createTree(projectId, files, ref) {
|
|
|
1329
1343
|
*/
|
|
1330
1344
|
async function createCommit(projectId, message, branch, actions) {
|
|
1331
1345
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
1332
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/repository/commits`);
|
|
1346
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/repository/commits`);
|
|
1333
1347
|
const response = await fetch(url.toString(), {
|
|
1334
1348
|
...DEFAULT_FETCH_CONFIG,
|
|
1335
1349
|
method: "POST",
|
|
@@ -1430,10 +1444,10 @@ async function getMergeRequest(projectId, mergeRequestIid, branchName) {
|
|
|
1430
1444
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
1431
1445
|
let url;
|
|
1432
1446
|
if (mergeRequestIid) {
|
|
1433
|
-
url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}`);
|
|
1447
|
+
url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/merge_requests/${mergeRequestIid}`);
|
|
1434
1448
|
}
|
|
1435
1449
|
else if (branchName) {
|
|
1436
|
-
url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/merge_requests?source_branch=${encodeURIComponent(branchName)}`);
|
|
1450
|
+
url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/merge_requests?source_branch=${encodeURIComponent(branchName)}`);
|
|
1437
1451
|
}
|
|
1438
1452
|
else {
|
|
1439
1453
|
throw new Error("Either mergeRequestIid or branchName must be provided");
|
|
@@ -1468,7 +1482,7 @@ async function getMergeRequestDiffs(projectId, mergeRequestIid, branchName, view
|
|
|
1468
1482
|
const mergeRequest = await getMergeRequest(projectId, undefined, branchName);
|
|
1469
1483
|
mergeRequestIid = mergeRequest.iid;
|
|
1470
1484
|
}
|
|
1471
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/changes`);
|
|
1485
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/merge_requests/${mergeRequestIid}/changes`);
|
|
1472
1486
|
if (view) {
|
|
1473
1487
|
url.searchParams.append("view", view);
|
|
1474
1488
|
}
|
|
@@ -1498,7 +1512,7 @@ async function listMergeRequestDiffs(projectId, mergeRequestIid, branchName, pag
|
|
|
1498
1512
|
const mergeRequest = await getMergeRequest(projectId, undefined, branchName);
|
|
1499
1513
|
mergeRequestIid = mergeRequest.iid;
|
|
1500
1514
|
}
|
|
1501
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/diffs`);
|
|
1515
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/merge_requests/${mergeRequestIid}/diffs`);
|
|
1502
1516
|
if (page) {
|
|
1503
1517
|
url.searchParams.append("page", page.toString());
|
|
1504
1518
|
}
|
|
@@ -1525,7 +1539,7 @@ async function listMergeRequestDiffs(projectId, mergeRequestIid, branchName, pag
|
|
|
1525
1539
|
*/
|
|
1526
1540
|
async function getBranchDiffs(projectId, from, to, straight) {
|
|
1527
1541
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
1528
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/repository/compare`);
|
|
1542
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/repository/compare`);
|
|
1529
1543
|
url.searchParams.append("from", from);
|
|
1530
1544
|
url.searchParams.append("to", to);
|
|
1531
1545
|
if (straight !== undefined) {
|
|
@@ -1560,7 +1574,7 @@ async function updateMergeRequest(projectId, options, mergeRequestIid, branchNam
|
|
|
1560
1574
|
const mergeRequest = await getMergeRequest(projectId, undefined, branchName);
|
|
1561
1575
|
mergeRequestIid = mergeRequest.iid;
|
|
1562
1576
|
}
|
|
1563
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}`);
|
|
1577
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/merge_requests/${mergeRequestIid}`);
|
|
1564
1578
|
const response = await fetch(url.toString(), {
|
|
1565
1579
|
...DEFAULT_FETCH_CONFIG,
|
|
1566
1580
|
method: "PUT",
|
|
@@ -1584,7 +1598,7 @@ async function createNote(projectId, noteableType, // 'issue' 또는 'merge_requ
|
|
|
1584
1598
|
noteableIid, body) {
|
|
1585
1599
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
1586
1600
|
// ⚙️ 응답 타입은 GitLab API 문서에 따라 조정 가능
|
|
1587
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/${noteableType}s/${noteableIid}/notes` // Using plural form (issues/merge_requests) as per GitLab API documentation
|
|
1601
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/${noteableType}s/${noteableIid}/notes` // Using plural form (issues/merge_requests) as per GitLab API documentation
|
|
1588
1602
|
);
|
|
1589
1603
|
const response = await fetch(url.toString(), {
|
|
1590
1604
|
...DEFAULT_FETCH_CONFIG,
|
|
@@ -1616,7 +1630,7 @@ noteableIid, body) {
|
|
|
1616
1630
|
*/
|
|
1617
1631
|
async function createMergeRequestThread(projectId, mergeRequestIid, body, position, createdAt) {
|
|
1618
1632
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
1619
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/discussions`);
|
|
1633
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/merge_requests/${mergeRequestIid}/discussions`);
|
|
1620
1634
|
const payload = { body };
|
|
1621
1635
|
// Add optional parameters if provided
|
|
1622
1636
|
if (position) {
|
|
@@ -1711,7 +1725,7 @@ async function verifyNamespaceExistence(namespacePath, parentId) {
|
|
|
1711
1725
|
*/
|
|
1712
1726
|
async function getProject(projectId, options = {}) {
|
|
1713
1727
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
1714
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}`);
|
|
1728
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}`);
|
|
1715
1729
|
if (options.license) {
|
|
1716
1730
|
url.searchParams.append("license", "true");
|
|
1717
1731
|
}
|
|
@@ -1768,7 +1782,7 @@ async function listProjects(options = {}) {
|
|
|
1768
1782
|
async function listLabels(projectId, options = {}) {
|
|
1769
1783
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
1770
1784
|
// Construct the URL with project path
|
|
1771
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/labels`);
|
|
1785
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/labels`);
|
|
1772
1786
|
// Add query parameters
|
|
1773
1787
|
Object.entries(options).forEach(([key, value]) => {
|
|
1774
1788
|
if (value !== undefined) {
|
|
@@ -1800,7 +1814,7 @@ async function listLabels(projectId, options = {}) {
|
|
|
1800
1814
|
*/
|
|
1801
1815
|
async function getLabel(projectId, labelId, includeAncestorGroups) {
|
|
1802
1816
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
1803
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/labels/${encodeURIComponent(String(labelId))}`);
|
|
1817
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/labels/${encodeURIComponent(String(labelId))}`);
|
|
1804
1818
|
// Add query parameters
|
|
1805
1819
|
if (includeAncestorGroups !== undefined) {
|
|
1806
1820
|
url.searchParams.append("include_ancestor_groups", includeAncestorGroups ? "true" : "false");
|
|
@@ -1825,7 +1839,7 @@ async function getLabel(projectId, labelId, includeAncestorGroups) {
|
|
|
1825
1839
|
async function createLabel(projectId, options) {
|
|
1826
1840
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
1827
1841
|
// Make the API request
|
|
1828
|
-
const response = await fetch(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/labels`, {
|
|
1842
|
+
const response = await fetch(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/labels`, {
|
|
1829
1843
|
...DEFAULT_FETCH_CONFIG,
|
|
1830
1844
|
method: "POST",
|
|
1831
1845
|
body: JSON.stringify(options),
|
|
@@ -1847,7 +1861,7 @@ async function createLabel(projectId, options) {
|
|
|
1847
1861
|
async function updateLabel(projectId, labelId, options) {
|
|
1848
1862
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
1849
1863
|
// Make the API request
|
|
1850
|
-
const response = await fetch(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/labels/${encodeURIComponent(String(labelId))}`, {
|
|
1864
|
+
const response = await fetch(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/labels/${encodeURIComponent(String(labelId))}`, {
|
|
1851
1865
|
...DEFAULT_FETCH_CONFIG,
|
|
1852
1866
|
method: "PUT",
|
|
1853
1867
|
body: JSON.stringify(options),
|
|
@@ -1867,7 +1881,7 @@ async function updateLabel(projectId, labelId, options) {
|
|
|
1867
1881
|
async function deleteLabel(projectId, labelId) {
|
|
1868
1882
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
1869
1883
|
// Make the API request
|
|
1870
|
-
const response = await fetch(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/labels/${encodeURIComponent(String(labelId))}`, {
|
|
1884
|
+
const response = await fetch(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/labels/${encodeURIComponent(String(labelId))}`, {
|
|
1871
1885
|
...DEFAULT_FETCH_CONFIG,
|
|
1872
1886
|
method: "DELETE",
|
|
1873
1887
|
});
|
|
@@ -1928,7 +1942,7 @@ async function listGroupProjects(options) {
|
|
|
1928
1942
|
*/
|
|
1929
1943
|
async function listWikiPages(projectId, options = {}) {
|
|
1930
1944
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
1931
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/wikis`);
|
|
1945
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/wikis`);
|
|
1932
1946
|
if (options.page)
|
|
1933
1947
|
url.searchParams.append("page", options.page.toString());
|
|
1934
1948
|
if (options.per_page)
|
|
@@ -1947,7 +1961,7 @@ async function listWikiPages(projectId, options = {}) {
|
|
|
1947
1961
|
*/
|
|
1948
1962
|
async function getWikiPage(projectId, slug) {
|
|
1949
1963
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
1950
|
-
const response = await fetch(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/wikis/${encodeURIComponent(slug)}`, { ...DEFAULT_FETCH_CONFIG });
|
|
1964
|
+
const response = await fetch(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/wikis/${encodeURIComponent(slug)}`, { ...DEFAULT_FETCH_CONFIG });
|
|
1951
1965
|
await handleGitLabError(response);
|
|
1952
1966
|
const data = await response.json();
|
|
1953
1967
|
return GitLabWikiPageSchema.parse(data);
|
|
@@ -1960,7 +1974,7 @@ async function createWikiPage(projectId, title, content, format) {
|
|
|
1960
1974
|
const body = { title, content };
|
|
1961
1975
|
if (format)
|
|
1962
1976
|
body.format = format;
|
|
1963
|
-
const response = await fetch(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/wikis`, {
|
|
1977
|
+
const response = await fetch(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/wikis`, {
|
|
1964
1978
|
...DEFAULT_FETCH_CONFIG,
|
|
1965
1979
|
method: "POST",
|
|
1966
1980
|
body: JSON.stringify(body),
|
|
@@ -1981,7 +1995,7 @@ async function updateWikiPage(projectId, slug, title, content, format) {
|
|
|
1981
1995
|
body.content = content;
|
|
1982
1996
|
if (format)
|
|
1983
1997
|
body.format = format;
|
|
1984
|
-
const response = await fetch(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/wikis/${encodeURIComponent(slug)}`, {
|
|
1998
|
+
const response = await fetch(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/wikis/${encodeURIComponent(slug)}`, {
|
|
1985
1999
|
...DEFAULT_FETCH_CONFIG,
|
|
1986
2000
|
method: "PUT",
|
|
1987
2001
|
body: JSON.stringify(body),
|
|
@@ -1995,7 +2009,7 @@ async function updateWikiPage(projectId, slug, title, content, format) {
|
|
|
1995
2009
|
*/
|
|
1996
2010
|
async function deleteWikiPage(projectId, slug) {
|
|
1997
2011
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
1998
|
-
const response = await fetch(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/wikis/${encodeURIComponent(slug)}`, {
|
|
2012
|
+
const response = await fetch(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/wikis/${encodeURIComponent(slug)}`, {
|
|
1999
2013
|
...DEFAULT_FETCH_CONFIG,
|
|
2000
2014
|
method: "DELETE",
|
|
2001
2015
|
});
|
|
@@ -2010,7 +2024,7 @@ async function deleteWikiPage(projectId, slug) {
|
|
|
2010
2024
|
*/
|
|
2011
2025
|
async function listPipelines(projectId, options = {}) {
|
|
2012
2026
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
2013
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/pipelines`);
|
|
2027
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/pipelines`);
|
|
2014
2028
|
// Add all query parameters
|
|
2015
2029
|
Object.entries(options).forEach(([key, value]) => {
|
|
2016
2030
|
if (value !== undefined) {
|
|
@@ -2033,7 +2047,7 @@ async function listPipelines(projectId, options = {}) {
|
|
|
2033
2047
|
*/
|
|
2034
2048
|
async function getPipeline(projectId, pipelineId) {
|
|
2035
2049
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
2036
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/pipelines/${pipelineId}`);
|
|
2050
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/pipelines/${pipelineId}`);
|
|
2037
2051
|
const response = await fetch(url.toString(), {
|
|
2038
2052
|
...DEFAULT_FETCH_CONFIG,
|
|
2039
2053
|
});
|
|
@@ -2054,7 +2068,7 @@ async function getPipeline(projectId, pipelineId) {
|
|
|
2054
2068
|
*/
|
|
2055
2069
|
async function listPipelineJobs(projectId, pipelineId, options = {}) {
|
|
2056
2070
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
2057
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/pipelines/${pipelineId}/jobs`);
|
|
2071
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/pipelines/${pipelineId}/jobs`);
|
|
2058
2072
|
// Add all query parameters
|
|
2059
2073
|
Object.entries(options).forEach(([key, value]) => {
|
|
2060
2074
|
if (value !== undefined) {
|
|
@@ -2078,7 +2092,7 @@ async function listPipelineJobs(projectId, pipelineId, options = {}) {
|
|
|
2078
2092
|
}
|
|
2079
2093
|
async function getPipelineJob(projectId, jobId) {
|
|
2080
2094
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
2081
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/jobs/${jobId}`);
|
|
2095
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/jobs/${jobId}`);
|
|
2082
2096
|
const response = await fetch(url.toString(), {
|
|
2083
2097
|
...DEFAULT_FETCH_CONFIG,
|
|
2084
2098
|
});
|
|
@@ -2100,7 +2114,7 @@ async function getPipelineJob(projectId, jobId) {
|
|
|
2100
2114
|
*/
|
|
2101
2115
|
async function getPipelineJobOutput(projectId, jobId, limit, offset) {
|
|
2102
2116
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
2103
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/jobs/${jobId}/trace`);
|
|
2117
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/jobs/${jobId}/trace`);
|
|
2104
2118
|
const response = await fetch(url.toString(), {
|
|
2105
2119
|
...DEFAULT_FETCH_CONFIG,
|
|
2106
2120
|
headers: {
|
|
@@ -2145,7 +2159,7 @@ async function getPipelineJobOutput(projectId, jobId, limit, offset) {
|
|
|
2145
2159
|
*/
|
|
2146
2160
|
async function createPipeline(projectId, ref, variables) {
|
|
2147
2161
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
2148
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/pipeline`);
|
|
2162
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/pipeline`);
|
|
2149
2163
|
const body = { ref };
|
|
2150
2164
|
if (variables && variables.length > 0) {
|
|
2151
2165
|
body.variables = variables.reduce((acc, { key, value }) => {
|
|
@@ -2171,7 +2185,7 @@ async function createPipeline(projectId, ref, variables) {
|
|
|
2171
2185
|
*/
|
|
2172
2186
|
async function retryPipeline(projectId, pipelineId) {
|
|
2173
2187
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
2174
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/pipelines/${pipelineId}/retry`);
|
|
2188
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/pipelines/${pipelineId}/retry`);
|
|
2175
2189
|
const response = await fetch(url.toString(), {
|
|
2176
2190
|
method: "POST",
|
|
2177
2191
|
headers: DEFAULT_HEADERS,
|
|
@@ -2189,7 +2203,7 @@ async function retryPipeline(projectId, pipelineId) {
|
|
|
2189
2203
|
*/
|
|
2190
2204
|
async function cancelPipeline(projectId, pipelineId) {
|
|
2191
2205
|
projectId = decodeURIComponent(projectId); // Decode project ID
|
|
2192
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/pipelines/${pipelineId}/cancel`);
|
|
2206
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/pipelines/${pipelineId}/cancel`);
|
|
2193
2207
|
const response = await fetch(url.toString(), {
|
|
2194
2208
|
method: "POST",
|
|
2195
2209
|
headers: DEFAULT_HEADERS,
|
|
@@ -2248,7 +2262,7 @@ async function getRepositoryTree(options) {
|
|
|
2248
2262
|
*/
|
|
2249
2263
|
async function listProjectMilestones(projectId, options) {
|
|
2250
2264
|
projectId = decodeURIComponent(projectId);
|
|
2251
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/milestones`);
|
|
2265
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/milestones`);
|
|
2252
2266
|
Object.entries(options).forEach(([key, value]) => {
|
|
2253
2267
|
if (value !== undefined) {
|
|
2254
2268
|
if (key === "iids" && Array.isArray(value) && value.length > 0) {
|
|
@@ -2276,7 +2290,7 @@ async function listProjectMilestones(projectId, options) {
|
|
|
2276
2290
|
*/
|
|
2277
2291
|
async function getProjectMilestone(projectId, milestoneId) {
|
|
2278
2292
|
projectId = decodeURIComponent(projectId);
|
|
2279
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/milestones/${milestoneId}`);
|
|
2293
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/milestones/${milestoneId}`);
|
|
2280
2294
|
const response = await fetch(url.toString(), {
|
|
2281
2295
|
...DEFAULT_FETCH_CONFIG,
|
|
2282
2296
|
});
|
|
@@ -2292,7 +2306,7 @@ async function getProjectMilestone(projectId, milestoneId) {
|
|
|
2292
2306
|
*/
|
|
2293
2307
|
async function createProjectMilestone(projectId, options) {
|
|
2294
2308
|
projectId = decodeURIComponent(projectId);
|
|
2295
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/milestones`);
|
|
2309
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/milestones`);
|
|
2296
2310
|
const response = await fetch(url.toString(), {
|
|
2297
2311
|
...DEFAULT_FETCH_CONFIG,
|
|
2298
2312
|
method: "POST",
|
|
@@ -2311,7 +2325,7 @@ async function createProjectMilestone(projectId, options) {
|
|
|
2311
2325
|
*/
|
|
2312
2326
|
async function editProjectMilestone(projectId, milestoneId, options) {
|
|
2313
2327
|
projectId = decodeURIComponent(projectId);
|
|
2314
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/milestones/${milestoneId}`);
|
|
2328
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/milestones/${milestoneId}`);
|
|
2315
2329
|
const response = await fetch(url.toString(), {
|
|
2316
2330
|
...DEFAULT_FETCH_CONFIG,
|
|
2317
2331
|
method: "PUT",
|
|
@@ -2329,7 +2343,7 @@ async function editProjectMilestone(projectId, milestoneId, options) {
|
|
|
2329
2343
|
*/
|
|
2330
2344
|
async function deleteProjectMilestone(projectId, milestoneId) {
|
|
2331
2345
|
projectId = decodeURIComponent(projectId);
|
|
2332
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/milestones/${milestoneId}`);
|
|
2346
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/milestones/${milestoneId}`);
|
|
2333
2347
|
const response = await fetch(url.toString(), {
|
|
2334
2348
|
...DEFAULT_FETCH_CONFIG,
|
|
2335
2349
|
method: "DELETE",
|
|
@@ -2344,7 +2358,7 @@ async function deleteProjectMilestone(projectId, milestoneId) {
|
|
|
2344
2358
|
*/
|
|
2345
2359
|
async function getMilestoneIssues(projectId, milestoneId) {
|
|
2346
2360
|
projectId = decodeURIComponent(projectId);
|
|
2347
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/milestones/${milestoneId}/issues`);
|
|
2361
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/milestones/${milestoneId}/issues`);
|
|
2348
2362
|
const response = await fetch(url.toString(), {
|
|
2349
2363
|
...DEFAULT_FETCH_CONFIG,
|
|
2350
2364
|
});
|
|
@@ -2360,7 +2374,7 @@ async function getMilestoneIssues(projectId, milestoneId) {
|
|
|
2360
2374
|
*/
|
|
2361
2375
|
async function getMilestoneMergeRequests(projectId, milestoneId) {
|
|
2362
2376
|
projectId = decodeURIComponent(projectId);
|
|
2363
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/milestones/${milestoneId}/merge_requests`);
|
|
2377
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/milestones/${milestoneId}/merge_requests`);
|
|
2364
2378
|
const response = await fetch(url.toString(), {
|
|
2365
2379
|
...DEFAULT_FETCH_CONFIG,
|
|
2366
2380
|
});
|
|
@@ -2376,7 +2390,7 @@ async function getMilestoneMergeRequests(projectId, milestoneId) {
|
|
|
2376
2390
|
*/
|
|
2377
2391
|
async function promoteProjectMilestone(projectId, milestoneId) {
|
|
2378
2392
|
projectId = decodeURIComponent(projectId);
|
|
2379
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/milestones/${milestoneId}/promote`);
|
|
2393
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/milestones/${milestoneId}/promote`);
|
|
2380
2394
|
const response = await fetch(url.toString(), {
|
|
2381
2395
|
...DEFAULT_FETCH_CONFIG,
|
|
2382
2396
|
method: "POST",
|
|
@@ -2393,7 +2407,7 @@ async function promoteProjectMilestone(projectId, milestoneId) {
|
|
|
2393
2407
|
*/
|
|
2394
2408
|
async function getMilestoneBurndownEvents(projectId, milestoneId) {
|
|
2395
2409
|
projectId = decodeURIComponent(projectId);
|
|
2396
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/milestones/${milestoneId}/burndown_events`);
|
|
2410
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/milestones/${milestoneId}/burndown_events`);
|
|
2397
2411
|
const response = await fetch(url.toString(), {
|
|
2398
2412
|
...DEFAULT_FETCH_CONFIG,
|
|
2399
2413
|
});
|
|
@@ -2463,7 +2477,7 @@ async function getUsers(usernames) {
|
|
|
2463
2477
|
*/
|
|
2464
2478
|
async function listCommits(projectId, options = {}) {
|
|
2465
2479
|
projectId = decodeURIComponent(projectId);
|
|
2466
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/repository/commits`);
|
|
2480
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/repository/commits`);
|
|
2467
2481
|
// Add query parameters
|
|
2468
2482
|
if (options.ref_name)
|
|
2469
2483
|
url.searchParams.append("ref_name", options.ref_name);
|
|
@@ -2507,7 +2521,7 @@ async function listCommits(projectId, options = {}) {
|
|
|
2507
2521
|
*/
|
|
2508
2522
|
async function getCommit(projectId, sha, stats) {
|
|
2509
2523
|
projectId = decodeURIComponent(projectId);
|
|
2510
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/repository/commits/${encodeURIComponent(sha)}`);
|
|
2524
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/repository/commits/${encodeURIComponent(sha)}`);
|
|
2511
2525
|
if (stats) {
|
|
2512
2526
|
url.searchParams.append("stats", "true");
|
|
2513
2527
|
}
|
|
@@ -2528,7 +2542,7 @@ async function getCommit(projectId, sha, stats) {
|
|
|
2528
2542
|
*/
|
|
2529
2543
|
async function getCommitDiff(projectId, sha) {
|
|
2530
2544
|
projectId = decodeURIComponent(projectId);
|
|
2531
|
-
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/repository/commits/${encodeURIComponent(sha)}/diff`);
|
|
2545
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/repository/commits/${encodeURIComponent(sha)}/diff`);
|
|
2532
2546
|
const response = await fetch(url.toString(), {
|
|
2533
2547
|
...DEFAULT_FETCH_CONFIG,
|
|
2534
2548
|
});
|
|
@@ -3305,6 +3319,12 @@ async function runServer() {
|
|
|
3305
3319
|
res.status(400).send("No transport found for sessionId");
|
|
3306
3320
|
}
|
|
3307
3321
|
});
|
|
3322
|
+
app.get("/health", (_, res) => {
|
|
3323
|
+
res.status(200).json({
|
|
3324
|
+
status: "healthy",
|
|
3325
|
+
version: process.env.npm_package_version || "unknown",
|
|
3326
|
+
});
|
|
3327
|
+
});
|
|
3308
3328
|
const PORT = process.env.PORT || 3002;
|
|
3309
3329
|
app.listen(PORT, () => {
|
|
3310
3330
|
console.log(`Server is running on port ${PORT}`);
|
package/build/schemas.js
CHANGED
|
@@ -608,13 +608,13 @@ export const GitLabMergeRequestSchema = z.object({
|
|
|
608
608
|
export const LineRangeSchema = z.object({
|
|
609
609
|
start: z.object({
|
|
610
610
|
line_code: z.string().nullable().optional().describe("CRITICAL: Line identifier in format '{file_path_sha1_hash}_{old_line_number}_{new_line_number}'. USUALLY REQUIRED for GitLab diff comments despite being optional in schema. Example: 'a1b2c3d4e5f6_10_15'. Get this from GitLab diff API response, never fabricate."),
|
|
611
|
-
type: z.enum(["new", "old"]).nullable().optional().describe("Line type: 'old' = deleted/original line, 'new' = added/modified line, null = unchanged context. MUST match the line_code format and old_line/new_line values."),
|
|
611
|
+
type: z.enum(["new", "old", "expanded"]).nullable().optional().describe("Line type: 'old' = deleted/original line, 'new' = added/modified line, null = unchanged context. MUST match the line_code format and old_line/new_line values."),
|
|
612
612
|
old_line: z.number().nullable().optional().describe("Line number in original file (before changes). REQUIRED when type='old', NULL when type='new' (for purely added lines), can be present for context lines."),
|
|
613
613
|
new_line: z.number().nullable().optional().describe("Line number in modified file (after changes). REQUIRED when type='new', NULL when type='old' (for purely deleted lines), can be present for context lines."),
|
|
614
614
|
}).describe("Start line position for multiline comment range. MUST specify either old_line OR new_line (or both for context), never neither."),
|
|
615
615
|
end: z.object({
|
|
616
616
|
line_code: z.string().nullable().optional().describe("CRITICAL: Line identifier in format '{file_path_sha1_hash}_{old_line_number}_{new_line_number}'. USUALLY REQUIRED for GitLab diff comments despite being optional in schema. Example: 'a1b2c3d4e5f6_12_17'. Must be from same file as start.line_code."),
|
|
617
|
-
type: z.enum(["new", "old"]).nullable().optional().describe("Line type: 'old' = deleted/original line, 'new' = added/modified line, null = unchanged context. SHOULD MATCH start.type for consistent ranges (don't mix old/new types)."),
|
|
617
|
+
type: z.enum(["new", "old", "expanded"]).nullable().optional().describe("Line type: 'old' = deleted/original line, 'new' = added/modified line, null = unchanged context. SHOULD MATCH start.type for consistent ranges (don't mix old/new types)."),
|
|
618
618
|
old_line: z.number().nullable().optional().describe("Line number in original file (before changes). REQUIRED when type='old', NULL when type='new' (for purely added lines), can be present for context lines. MUST be >= start.old_line if both specified."),
|
|
619
619
|
new_line: z.number().nullable().optional().describe("Line number in modified file (after changes). REQUIRED when type='new', NULL when type='old' (for purely deleted lines), can be present for context lines. MUST be >= start.new_line if both specified."),
|
|
620
620
|
}).describe("End line position for multiline comment range. MUST specify either old_line OR new_line (or both for context), never neither. Range must be valid (end >= start)."),
|
|
@@ -643,28 +643,12 @@ export const GitLabDiscussionNoteSchema = z.object({
|
|
|
643
643
|
base_sha: z.string(),
|
|
644
644
|
start_sha: z.string(),
|
|
645
645
|
head_sha: z.string(),
|
|
646
|
-
old_path: z.string().optional().describe("File path before change"),
|
|
647
|
-
new_path: z.string().optional().describe("File path after change"),
|
|
646
|
+
old_path: z.string().nullable().optional().describe("File path before change"),
|
|
647
|
+
new_path: z.string().nullable().optional().describe("File path after change"),
|
|
648
648
|
position_type: z.enum(["text", "image", "file"]),
|
|
649
649
|
new_line: z.number().nullable().optional().describe("Line number in the modified file (after changes). Used for added lines and context lines. Null for deleted lines."),
|
|
650
650
|
old_line: z.number().nullable().optional().describe("Line number in the original file (before changes). Used for deleted lines and context lines. Null for newly added lines."),
|
|
651
|
-
line_range:
|
|
652
|
-
.object({
|
|
653
|
-
start: z.object({
|
|
654
|
-
line_code: z.string().nullable().optional().describe("Line identifier in format: '{file_path_sha1_hash}_{old_line_number}_{new_line_number}'. Used to uniquely identify a specific line in the diff."),
|
|
655
|
-
type: z.enum(["new", "old", "expanded"]),
|
|
656
|
-
old_line: z.number().nullable().optional().describe("Line number in the original file (before changes). Null for newly added lines or unchanged context lines."),
|
|
657
|
-
new_line: z.number().nullable().optional().describe("Line number in the modified file (after changes). Null for deleted lines or unchanged context lines."),
|
|
658
|
-
}),
|
|
659
|
-
end: z.object({
|
|
660
|
-
line_code: z.string().nullable().optional().describe("Line identifier in format: '{file_path_sha1_hash}_{old_line_number}_{new_line_number}'. Used to uniquely identify a specific line in the diff."),
|
|
661
|
-
type: z.enum(["new", "old", "expanded"]),
|
|
662
|
-
old_line: z.number().nullable().optional().describe("Line number in the original file (before changes). Null for newly added lines or unchanged context lines."),
|
|
663
|
-
new_line: z.number().nullable().optional().describe("Line number in the modified file (after changes). Null for deleted lines or unchanged context lines."),
|
|
664
|
-
}),
|
|
665
|
-
})
|
|
666
|
-
.nullable()
|
|
667
|
-
.optional(), // For multi-line diff notes
|
|
651
|
+
line_range: LineRangeSchema.nullable().optional(), // For multi-line diff notes
|
|
668
652
|
width: z.number().optional(), // For image diff notes
|
|
669
653
|
height: z.number().optional(), // For image diff notes
|
|
670
654
|
x: z.number().optional(), // For image diff notes
|
|
@@ -1156,8 +1140,8 @@ export const MergeRequestThreadPositionSchema = z.object({
|
|
|
1156
1140
|
head_sha: z.string().describe("REQUIRED: SHA referencing HEAD of the source branch. Get this from merge request diff_refs.head_sha."),
|
|
1157
1141
|
start_sha: z.string().describe("REQUIRED: SHA referencing the start commit of the source branch. Get this from merge request diff_refs.start_sha."),
|
|
1158
1142
|
position_type: z.enum(["text", "image", "file"]).describe("REQUIRED: Position type. Use 'text' for code diffs, 'image' for image diffs, 'file' for file-level comments."),
|
|
1159
|
-
new_path: z.string().optional().describe("File path after changes. REQUIRED for most diff comments. Use same as old_path if file wasn't renamed."),
|
|
1160
|
-
old_path: z.string().optional().describe("File path before changes. REQUIRED for most diff comments. Use same as new_path if file wasn't renamed."),
|
|
1143
|
+
new_path: z.string().nullable().optional().describe("File path after changes. REQUIRED for most diff comments. Use same as old_path if file wasn't renamed."),
|
|
1144
|
+
old_path: z.string().nullable().optional().describe("File path before changes. REQUIRED for most diff comments. Use same as new_path if file wasn't renamed."),
|
|
1161
1145
|
new_line: z.number().nullable().optional().describe("Line number in modified file (after changes). Use for added lines or context lines. NULL for deleted lines. For single-line comments on new lines."),
|
|
1162
1146
|
old_line: z.number().nullable().optional().describe("Line number in original file (before changes). Use for deleted lines or context lines. NULL for added lines. For single-line comments on old lines."),
|
|
1163
1147
|
line_range: LineRangeSchema.optional().describe("MULTILINE COMMENTS: Specify start/end line positions for commenting on multiple lines. Alternative to single old_line/new_line."),
|