Merge pull request #21 from chad-loder/pr/labels-api-clean
Labels API Support
This commit is contained in:
166
README.md
166
README.md
@ -40,36 +40,146 @@ env GITLAB_PERSONAL_ACCESS_TOKEN=your_gitlab_token GITLAB_API_URL=your_gitlab_ap
|
|||||||
- `GITLAB_PERSONAL_ACCESS_TOKEN`: Your GitLab personal access token.
|
- `GITLAB_PERSONAL_ACCESS_TOKEN`: Your GitLab personal access token.
|
||||||
- `GITLAB_API_URL`: Your GitLab API URL. (Default: `https://gitlab.com/api/v4`)
|
- `GITLAB_API_URL`: Your GitLab API URL. (Default: `https://gitlab.com/api/v4`)
|
||||||
|
|
||||||
## Tools Reference 🛠️
|
## Tools 🛠️
|
||||||
|
|
||||||
|
1. `create_or_update_file`
|
||||||
|
|
||||||
|
- Create or update a single file in a GitLab project. 📝
|
||||||
|
- Inputs:
|
||||||
|
- `project_id` (string): Project ID or namespace/project_path
|
||||||
|
- `file_path` (string): Path to create/update the file
|
||||||
|
- `content` (string): File content
|
||||||
|
- `commit_message` (string): Commit message
|
||||||
|
- `branch` (string): Branch to create/update the file in
|
||||||
|
- `previous_path` (optional string): Previous file path when renaming a file
|
||||||
|
- Returns: File content and commit details
|
||||||
|
|
||||||
|
2. `push_files`
|
||||||
|
|
||||||
|
- Push multiple files in a single commit. 📤
|
||||||
|
- Inputs:
|
||||||
|
- `project_id` (string): Project ID or namespace/project_path
|
||||||
|
- `branch` (string): Branch to push to
|
||||||
|
- `files` (array): Array of files to push, each with `file_path` and `content` properties
|
||||||
|
- `commit_message` (string): Commit message
|
||||||
|
- Returns: Updated branch reference
|
||||||
|
|
||||||
|
3. `search_repositories`
|
||||||
|
|
||||||
|
- Search for GitLab projects. 🔍
|
||||||
|
- Inputs:
|
||||||
|
- `search` (string): Search query
|
||||||
|
- `page` (optional number): Page number (default: 1)
|
||||||
|
- `per_page` (optional number): Results per page (default: 20, max: 100)
|
||||||
|
- Returns: Project search results
|
||||||
|
|
||||||
|
4. `create_repository`
|
||||||
|
|
||||||
|
- Create a new GitLab project. ➕
|
||||||
|
- Inputs:
|
||||||
|
- `name` (string): Project name
|
||||||
|
- `description` (optional string): Project description
|
||||||
|
- `visibility` (optional string): Project visibility level (public, private, internal)
|
||||||
|
- `initialize_with_readme` (optional boolean): Initialize with README
|
||||||
|
- Returns: Details of the created project
|
||||||
|
|
||||||
|
5. `get_file_contents`
|
||||||
|
|
||||||
|
- Get the contents of a file or directory. 📂
|
||||||
|
- Inputs:
|
||||||
|
- `project_id` (string): Project ID or namespace/project_path
|
||||||
|
- `file_path` (string): Path to the file/directory
|
||||||
|
- `ref` (optional string): Branch, tag, or commit SHA (default: default branch)
|
||||||
|
- Returns: File/directory content
|
||||||
|
|
||||||
|
6. `create_issue`
|
||||||
|
|
||||||
|
- Create a new issue. 🐛
|
||||||
|
- Inputs:
|
||||||
|
- `project_id` (string): Project ID or namespace/project_path
|
||||||
|
- `title` (string): Issue title
|
||||||
|
- `description` (string): Issue description
|
||||||
|
- `assignee_ids` (optional number[]): Array of assignee IDs
|
||||||
|
- `milestone_id` (optional number): Milestone ID
|
||||||
|
- `labels` (optional string[]): Array of labels
|
||||||
|
- Returns: Details of the created issue
|
||||||
|
|
||||||
|
7. `create_merge_request`
|
||||||
|
|
||||||
|
- Create a new merge request. 🚀
|
||||||
|
- Inputs:
|
||||||
|
- `project_id` (string): Project ID or namespace/project_path
|
||||||
|
- `title` (string): Merge request title
|
||||||
|
- `description` (string): Merge request description
|
||||||
|
- `source_branch` (string): Branch with changes
|
||||||
|
- `target_branch` (string): Branch to merge into
|
||||||
|
- `allow_collaboration` (optional boolean): Allow collaborators to push commits to the source branch
|
||||||
|
- `draft` (optional boolean): Create as a draft merge request
|
||||||
|
- Returns: Details of the created merge request
|
||||||
|
|
||||||
|
8. `fork_repository`
|
||||||
|
|
||||||
|
- Fork a project. 🍴
|
||||||
|
- Inputs:
|
||||||
|
- `project_id` (string): Project ID or namespace/project_path to fork
|
||||||
|
- `namespace` (optional string): Namespace to fork into (default: user namespace)
|
||||||
|
- Returns: Details of the forked project
|
||||||
|
|
||||||
|
9. `create_branch`
|
||||||
|
|
||||||
|
- Create a new branch. 🌿
|
||||||
|
- Inputs:
|
||||||
|
- `project_id` (string): Project ID or namespace/project_path
|
||||||
|
- `name` (string): New branch name
|
||||||
|
- `ref` (optional string): Ref to create the branch from (branch, tag, commit SHA, default: default branch)
|
||||||
|
- Returns: Created branch reference
|
||||||
|
|
||||||
|
10. `get_merge_request`
|
||||||
|
|
||||||
|
- Get details of a merge request. ℹ️
|
||||||
|
- Inputs:
|
||||||
|
- `project_id` (string): Project ID or namespace/project_path
|
||||||
|
- `merge_request_iid` (number): Merge request IID
|
||||||
|
- Returns: Merge request details
|
||||||
|
|
||||||
|
11. `get_merge_request_diffs`
|
||||||
|
|
||||||
|
- Get changes (diffs) of a merge request. diff
|
||||||
|
- Inputs:
|
||||||
|
- `project_id` (string): Project ID or namespace/project_path
|
||||||
|
- `merge_request_iid` (number): Merge request IID
|
||||||
|
- `view` (optional string): Diff view type ('inline' or 'parallel')
|
||||||
|
- Returns: Array of merge request diff information
|
||||||
|
|
||||||
|
12. `update_merge_request`
|
||||||
|
|
||||||
|
- Update a merge request. 🔄
|
||||||
|
- Inputs:
|
||||||
|
- `project_id` (string): Project ID or namespace/project_path
|
||||||
|
- `merge_request_iid` (number): Merge request IID
|
||||||
|
- `title` (optional string): New title
|
||||||
|
- `description` (string): New description
|
||||||
|
- `target_branch` (optional string): New target branch
|
||||||
|
- `state_event` (optional string): Merge request state change event ('close', 'reopen')
|
||||||
|
- `remove_source_branch` (optional boolean): Remove source branch after merge
|
||||||
|
- `allow_collaboration` (optional boolean): Allow collaborators to push commits to the source branch
|
||||||
|
- Returns: Updated merge request details
|
||||||
|
|
||||||
|
13. `create_note`
|
||||||
|
- Create a new note (comment) to an issue or merge request. 💬
|
||||||
|
- Inputs:
|
||||||
|
- `project_id` (string): Project ID or namespace/project_path
|
||||||
|
- `noteable_type` (string): Type of noteable ("issue" or "merge_request")
|
||||||
|
- `noteable_iid` (number): IID of the issue or merge request
|
||||||
|
- `body` (string): Note content
|
||||||
|
- Returns: Details of the created note
|
||||||
|
|
||||||
| Tool | Description | Parameters | Returns |
|
|
||||||
|------|-------------|------------|---------|
|
|
||||||
| **`create_or_update_file`** | Create or update a single file in a GitLab project 📝 | • `project_id` (string): Project ID or path<br>• `file_path` (string): Path to create/update<br>• `content` (string): File content<br>• `commit_message` (string): Commit message<br>• `branch` (string): Target branch<br>• `previous_path` (optional): Previous path when renaming | File content and commit details |
|
|
||||||
| **`push_files`** | Push multiple files in a single commit 📤 (internally creates a tree and commit) | • `project_id` (string): Project ID or path<br>• `branch` (string): Target branch<br>• `files` (array): Array of files with `file_path` and `content`<br>• `commit_message` (string): Commit message | Updated branch reference |
|
|
||||||
| **`search_repositories`** | Search for GitLab projects 🔍 | • `search` (string): Search query<br>• `page` (optional): Page number (default: 1)<br>• `per_page` (optional): Results per page (default: 20) | Project search results |
|
|
||||||
| **`create_repository`** | Create a new GitLab project ➕ | • `name` (string): Project name<br>• `description` (optional): Project description<br>• `visibility` (optional): Visibility level<br>• `initialize_with_readme` (optional): Initialize with README | Created project details |
|
|
||||||
| **`get_file_contents`** | Get the contents of a file or directory 📂 | • `project_id` (string): Project ID or path<br>• `file_path` (string): Path to file/directory<br>• `ref` (optional): Branch, tag, or commit SHA | File/directory content |
|
|
||||||
| **`create_issue`** | Create a new issue 🐛 | • `project_id` (string): Project ID or path<br>• `title` (string): Issue title<br>• `description` (string): Issue description<br>• `assignee_ids` (optional): Array of assignee IDs<br>• `milestone_id` (optional): Milestone ID<br>• `labels` (optional): Array of labels | Created issue details |
|
|
||||||
| **`list_issues`** | List issues in a project with comprehensive filtering options 📋 | • `project_id` (string): Project ID or path<br>• Optional filters: `assignee_id`, `assignee_username`, `author_id`, `author_username`, `confidential`, `created_after/before`, `due_date`, `label_name`, `milestone`, `scope`, `search`, `state`, `updated_after/before`<br>• Pagination: `page`, `per_page` | Array of issues |
|
|
||||||
| **`get_issue`** | Get details of a specific issue | • `project_id` (string): Project ID or path<br>• `issue_iid` (number): Issue IID | Issue details |
|
|
||||||
| **`update_issue`** | Update an existing issue ✏️ | • `project_id` (string): Project ID or path<br>• `issue_iid` (number): Issue IID<br>• Editable fields: `title`, `description`, `assignee_ids`, `labels`, `milestone_id`, `state_event` (close/reopen), `confidential`, `discussion_locked`, `due_date`, `weight` | Updated issue details |
|
|
||||||
| **`delete_issue`** | Delete an issue | • `project_id` (string): Project ID or path<br>• `issue_iid` (number): Issue IID | Success message |
|
|
||||||
| **`list_issue_links`** | List all links for a specific issue | • `project_id` (string): Project ID or path<br>• `issue_iid` (number): Issue IID | Array of linked issues |
|
|
||||||
| **`get_issue_link`** | Get details of a specific issue link | • `project_id` (string): Project ID or path<br>• `issue_iid` (number): Issue IID<br>• `issue_link_id` (number): Link ID | Issue link details |
|
|
||||||
| **`create_issue_link`** | Create a link between two issues | • `project_id` (string): Project ID or path<br>• `issue_iid` (number): Source issue IID<br>• `target_project_id` (string): Target project ID<br>• `target_issue_iid` (number): Target issue IID<br>• `link_type` (optional): Relationship type | Created link details |
|
|
||||||
| **`delete_issue_link`** | Delete an issue link | • `project_id` (string): Project ID or path<br>• `issue_iid` (number): Issue IID<br>• `issue_link_id` (number): Link ID | Success message |
|
|
||||||
| **`create_merge_request`** | Create a new merge request 🚀 | • `project_id` (string): Project ID or path<br>• `title` (string): MR title<br>• `description` (string): MR description<br>• `source_branch` (string): Branch with changes<br>• `target_branch` (string): Branch to merge into<br>• `allow_collaboration` (optional): Allow collaborators<br>• `draft` (optional): Create as draft | Created merge request details |
|
|
||||||
| **`fork_repository`** | Fork a project 🍴 | • `project_id` (string): Project ID or path to fork<br>• `namespace` (optional): Namespace to fork into | Forked project details |
|
|
||||||
| **`create_branch`** | Create a new branch 🌿 | • `project_id` (string): Project ID or path<br>• `branch` (string): New branch name<br>• `ref` (optional): Reference to create from | Created branch reference |
|
|
||||||
| **`get_merge_request`** | Get details of a merge request ℹ️ | • `project_id` (string): Project ID or path<br>• `merge_request_iid` (number): MR IID | Merge request details |
|
|
||||||
| **`get_merge_request_diffs`** | Get changes of a merge request | • `project_id` (string): Project ID or path<br>• `merge_request_iid` (number): MR IID<br>• `view` (optional): Diff view type | Array of merge request diffs |
|
|
||||||
| **`update_merge_request`** | Update a merge request 🔄 | • `project_id` (string): Project ID or path<br>• `merge_request_iid` (number): MR IID<br>• Editable fields: `title`, `description`, `target_branch`, `assignee_ids`, `labels`, `state_event` (close/reopen), `remove_source_branch`, `squash`, `draft` | Updated merge request details |
|
|
||||||
| **`create_note`** | Create a comment on an issue or MR 💬 | • `project_id` (string): Project ID or path<br>• `noteable_type` (string): "issue" or "merge_request"<br>• `noteable_iid` (number): IID of the issue or MR<br>• `body` (string): Comment content | Created note details |
|
|
||||||
| **`list_namespaces`** | List available namespaces | • `search` (optional): Search term<br>• `page` (optional): Page number<br>• `per_page` (optional): Results per page<br>• `owned` (optional): Filter by ownership | Array of namespaces |
|
|
||||||
| **`get_namespace`** | Get details of a namespace | • `namespace_id` (string): Namespace ID or path | Namespace details |
|
|
||||||
| **`verify_namespace`** | Check if a namespace exists | • `path` (string): Namespace path to verify | Verification result |
|
|
||||||
| **`get_project`** | Get details of a specific project | • `project_id` (string): Project ID or path | Project details |
|
|
||||||
| **`list_projects`** | List accessible projects with rich filtering options 📊 | • Search/filtering: `search`, `owned`, `membership`, `archived`, `visibility`<br>• Features filtering: `with_issues_enabled`, `with_merge_requests_enabled`<br>• Sorting: `order_by`, `sort`<br>• Access control: `min_access_level`<br>• Pagination: `page`, `per_page`, `simple` | Array of projects |
|
| **`list_projects`** | List accessible projects with rich filtering options 📊 | • Search/filtering: `search`, `owned`, `membership`, `archived`, `visibility`<br>• Features filtering: `with_issues_enabled`, `with_merge_requests_enabled`<br>• Sorting: `order_by`, `sort`<br>• Access control: `min_access_level`<br>• Pagination: `page`, `per_page`, `simple` | Array of projects |
|
||||||
|
| **`list_labels`** | List all labels for a project with filtering options 🏷️ | • `project_id` (string): Project ID or path<br>• `with_counts` (optional): Include issue and merge request counts<br>• `include_ancestor_groups` (optional): Include ancestor groups<br>• `search` (optional): Filter labels by keyword | Array of labels |
|
||||||
|
| **`get_label`** | Get a single label from a project 🏷️ | • `project_id` (string): Project ID or path<br>• `label_id` (number/string): Label ID or name<br>• `include_ancestor_groups` (optional): Include ancestor groups | Label details |
|
||||||
|
| **`create_label`** | Create a new label in a project 🏷️➕ | • `project_id` (string): Project ID or path<br>• `name` (string): Label name<br>• `color` (string): Color in hex format (e.g., "#FF0000")<br>• `description` (optional): Label description<br>• `priority` (optional): Label priority | Created label details |
|
||||||
|
| **`update_label`** | Update an existing label in a project 🏷️✏️ | • `project_id` (string): Project ID or path<br>• `label_id` (number/string): Label ID or name<br>• `new_name` (optional): New label name<br>• `color` (optional): New color in hex format<br>• `description` (optional): New description<br>• `priority` (optional): New priority | Updated label details |
|
||||||
|
| **`delete_label`** | Delete a label from a project 🏷️❌ | • `project_id` (string): Project ID or path<br>• `label_id` (number/string): Label ID or name | Success message |
|
||||||
|
|
||||||
## Environment Variable Configuration
|
## Environment Variable Configuration
|
||||||
|
|
||||||
|
250
index.ts
250
index.ts
@ -27,6 +27,7 @@ import {
|
|||||||
GitLabNamespaceSchema,
|
GitLabNamespaceSchema,
|
||||||
GitLabNamespaceExistsResponseSchema,
|
GitLabNamespaceExistsResponseSchema,
|
||||||
GitLabProjectSchema,
|
GitLabProjectSchema,
|
||||||
|
GitLabLabelSchema,
|
||||||
CreateRepositoryOptionsSchema,
|
CreateRepositoryOptionsSchema,
|
||||||
CreateIssueOptionsSchema,
|
CreateIssueOptionsSchema,
|
||||||
CreateMergeRequestOptionsSchema,
|
CreateMergeRequestOptionsSchema,
|
||||||
@ -59,6 +60,11 @@ import {
|
|||||||
VerifyNamespaceSchema,
|
VerifyNamespaceSchema,
|
||||||
GetProjectSchema,
|
GetProjectSchema,
|
||||||
ListProjectsSchema,
|
ListProjectsSchema,
|
||||||
|
ListLabelsSchema,
|
||||||
|
GetLabelSchema,
|
||||||
|
CreateLabelSchema,
|
||||||
|
UpdateLabelSchema,
|
||||||
|
DeleteLabelSchema,
|
||||||
CreateNoteSchema,
|
CreateNoteSchema,
|
||||||
type GitLabFork,
|
type GitLabFork,
|
||||||
type GitLabReference,
|
type GitLabReference,
|
||||||
@ -77,6 +83,7 @@ import {
|
|||||||
type GitLabNamespace,
|
type GitLabNamespace,
|
||||||
type GitLabNamespaceExistsResponse,
|
type GitLabNamespaceExistsResponse,
|
||||||
type GitLabProject,
|
type GitLabProject,
|
||||||
|
type GitLabLabel,
|
||||||
} from "./schemas.js";
|
} from "./schemas.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1204,22 +1211,187 @@ async function getProject(
|
|||||||
* @returns {Promise<GitLabProject[]>} List of projects
|
* @returns {Promise<GitLabProject[]>} List of projects
|
||||||
*/
|
*/
|
||||||
async function listProjects(options: z.infer<typeof ListProjectsSchema> = {}): Promise<GitLabProject[]> {
|
async function listProjects(options: z.infer<typeof ListProjectsSchema> = {}): Promise<GitLabProject[]> {
|
||||||
const url = new URL(`${GITLAB_API_URL}/projects`);
|
// Construct the query parameters
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
for (const [key, value] of Object.entries(options)) {
|
||||||
|
if (value !== undefined && value !== null) {
|
||||||
|
if (typeof value === "boolean") {
|
||||||
|
params.append(key, value ? "true" : "false");
|
||||||
|
} else {
|
||||||
|
params.append(key, String(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Add all the query parameters from options
|
// Make the API request
|
||||||
|
const response = await fetch(
|
||||||
|
`${GITLAB_API_URL}/projects?${params.toString()}`,
|
||||||
|
{
|
||||||
|
method: "GET",
|
||||||
|
headers: DEFAULT_HEADERS,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Handle errors
|
||||||
|
await handleGitLabError(response);
|
||||||
|
|
||||||
|
// Parse and return the data
|
||||||
|
const data = await response.json();
|
||||||
|
return z.array(GitLabProjectSchema).parse(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List labels for a project
|
||||||
|
*
|
||||||
|
* @param projectId The ID or URL-encoded path of the project
|
||||||
|
* @param options Optional parameters for listing labels
|
||||||
|
* @returns Array of GitLab labels
|
||||||
|
*/
|
||||||
|
async function listLabels(
|
||||||
|
projectId: string,
|
||||||
|
options: Omit<z.infer<typeof ListLabelsSchema>, "project_id"> = {}
|
||||||
|
): Promise<GitLabLabel[]> {
|
||||||
|
// Construct the URL with project path
|
||||||
|
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/labels`);
|
||||||
|
|
||||||
|
// Add query parameters
|
||||||
Object.entries(options).forEach(([key, value]) => {
|
Object.entries(options).forEach(([key, value]) => {
|
||||||
if (value !== undefined) {
|
if (value !== undefined) {
|
||||||
url.searchParams.append(key, value.toString());
|
if (typeof value === "boolean") {
|
||||||
|
url.searchParams.append(key, value ? "true" : "false");
|
||||||
|
} else {
|
||||||
|
url.searchParams.append(key, String(value));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Make the API request
|
||||||
const response = await fetch(url.toString(), {
|
const response = await fetch(url.toString(), {
|
||||||
headers: DEFAULT_HEADERS,
|
headers: DEFAULT_HEADERS,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Handle errors
|
||||||
await handleGitLabError(response);
|
await handleGitLabError(response);
|
||||||
|
|
||||||
|
// Parse and return the data
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
return z.array(GitLabRepositorySchema).parse(data);
|
return data as GitLabLabel[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a single label from a project
|
||||||
|
*
|
||||||
|
* @param projectId The ID or URL-encoded path of the project
|
||||||
|
* @param labelId The ID or name of the label
|
||||||
|
* @param includeAncestorGroups Whether to include ancestor groups
|
||||||
|
* @returns GitLab label
|
||||||
|
*/
|
||||||
|
async function getLabel(
|
||||||
|
projectId: string,
|
||||||
|
labelId: number | string,
|
||||||
|
includeAncestorGroups?: boolean
|
||||||
|
): Promise<GitLabLabel> {
|
||||||
|
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/labels/${encodeURIComponent(String(labelId))}`);
|
||||||
|
|
||||||
|
// Add query parameters
|
||||||
|
if (includeAncestorGroups !== undefined) {
|
||||||
|
url.searchParams.append("include_ancestor_groups", includeAncestorGroups ? "true" : "false");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make the API request
|
||||||
|
const response = await fetch(url.toString(), {
|
||||||
|
headers: DEFAULT_HEADERS,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle errors
|
||||||
|
await handleGitLabError(response);
|
||||||
|
|
||||||
|
// Parse and return the data
|
||||||
|
const data = await response.json();
|
||||||
|
return data as GitLabLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new label in a project
|
||||||
|
*
|
||||||
|
* @param projectId The ID or URL-encoded path of the project
|
||||||
|
* @param options Options for creating the label
|
||||||
|
* @returns Created GitLab label
|
||||||
|
*/
|
||||||
|
async function createLabel(
|
||||||
|
projectId: string,
|
||||||
|
options: Omit<z.infer<typeof CreateLabelSchema>, "project_id">
|
||||||
|
): Promise<GitLabLabel> {
|
||||||
|
// Make the API request
|
||||||
|
const response = await fetch(
|
||||||
|
`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/labels`,
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
headers: DEFAULT_HEADERS,
|
||||||
|
body: JSON.stringify(options),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Handle errors
|
||||||
|
await handleGitLabError(response);
|
||||||
|
|
||||||
|
// Parse and return the data
|
||||||
|
const data = await response.json();
|
||||||
|
return data as GitLabLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update an existing label in a project
|
||||||
|
*
|
||||||
|
* @param projectId The ID or URL-encoded path of the project
|
||||||
|
* @param labelId The ID or name of the label to update
|
||||||
|
* @param options Options for updating the label
|
||||||
|
* @returns Updated GitLab label
|
||||||
|
*/
|
||||||
|
async function updateLabel(
|
||||||
|
projectId: string,
|
||||||
|
labelId: number | string,
|
||||||
|
options: Omit<z.infer<typeof UpdateLabelSchema>, "project_id" | "label_id">
|
||||||
|
): Promise<GitLabLabel> {
|
||||||
|
// Make the API request
|
||||||
|
const response = await fetch(
|
||||||
|
`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/labels/${encodeURIComponent(String(labelId))}`,
|
||||||
|
{
|
||||||
|
method: "PUT",
|
||||||
|
headers: DEFAULT_HEADERS,
|
||||||
|
body: JSON.stringify(options),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Handle errors
|
||||||
|
await handleGitLabError(response);
|
||||||
|
|
||||||
|
// Parse and return the data
|
||||||
|
const data = await response.json();
|
||||||
|
return data as GitLabLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a label from a project
|
||||||
|
*
|
||||||
|
* @param projectId The ID or URL-encoded path of the project
|
||||||
|
* @param labelId The ID or name of the label to delete
|
||||||
|
*/
|
||||||
|
async function deleteLabel(
|
||||||
|
projectId: string,
|
||||||
|
labelId: number | string
|
||||||
|
): Promise<void> {
|
||||||
|
// Make the API request
|
||||||
|
const response = await fetch(
|
||||||
|
`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/labels/${encodeURIComponent(String(labelId))}`,
|
||||||
|
{
|
||||||
|
method: "DELETE",
|
||||||
|
headers: DEFAULT_HEADERS,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Handle errors
|
||||||
|
await handleGitLabError(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||||
@ -1358,6 +1530,31 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|||||||
description: "List projects accessible by the current user",
|
description: "List projects accessible by the current user",
|
||||||
inputSchema: zodToJsonSchema(ListProjectsSchema),
|
inputSchema: zodToJsonSchema(ListProjectsSchema),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "list_labels",
|
||||||
|
description: "List labels for a project",
|
||||||
|
inputSchema: zodToJsonSchema(ListLabelsSchema),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "get_label",
|
||||||
|
description: "Get a single label from a project",
|
||||||
|
inputSchema: zodToJsonSchema(GetLabelSchema),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "create_label",
|
||||||
|
description: "Create a new label in a project",
|
||||||
|
inputSchema: zodToJsonSchema(CreateLabelSchema),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "update_label",
|
||||||
|
description: "Update an existing label in a project",
|
||||||
|
inputSchema: zodToJsonSchema(UpdateLabelSchema),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "delete_label",
|
||||||
|
description: "Delete a label from a project",
|
||||||
|
inputSchema: zodToJsonSchema(DeleteLabelSchema),
|
||||||
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@ -1622,10 +1819,14 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const response = await fetch(url.toString(), {
|
const response = await fetch(url.toString(), {
|
||||||
|
method: "GET",
|
||||||
headers: DEFAULT_HEADERS,
|
headers: DEFAULT_HEADERS,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Handle errors
|
||||||
await handleGitLabError(response);
|
await handleGitLabError(response);
|
||||||
|
|
||||||
|
// Parse and return the data
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
const projects = z.array(GitLabProjectSchema).parse(data);
|
const projects = z.array(GitLabProjectSchema).parse(data);
|
||||||
|
|
||||||
@ -1715,6 +1916,47 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case "list_labels": {
|
||||||
|
const args = ListLabelsSchema.parse(request.params.arguments);
|
||||||
|
const labels = await listLabels(args.project_id, args);
|
||||||
|
return {
|
||||||
|
content: [{ type: "text", text: JSON.stringify(labels, null, 2) }],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
case "get_label": {
|
||||||
|
const args = GetLabelSchema.parse(request.params.arguments);
|
||||||
|
const label = await getLabel(args.project_id, args.label_id, args.include_ancestor_groups);
|
||||||
|
return {
|
||||||
|
content: [{ type: "text", text: JSON.stringify(label, null, 2) }],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
case "create_label": {
|
||||||
|
const args = CreateLabelSchema.parse(request.params.arguments);
|
||||||
|
const label = await createLabel(args.project_id, args);
|
||||||
|
return {
|
||||||
|
content: [{ type: "text", text: JSON.stringify(label, null, 2) }],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
case "update_label": {
|
||||||
|
const args = UpdateLabelSchema.parse(request.params.arguments);
|
||||||
|
const { project_id, label_id, ...options } = args;
|
||||||
|
const label = await updateLabel(project_id, label_id, options);
|
||||||
|
return {
|
||||||
|
content: [{ type: "text", text: JSON.stringify(label, null, 2) }],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
case "delete_label": {
|
||||||
|
const args = DeleteLabelSchema.parse(request.params.arguments);
|
||||||
|
await deleteLabel(args.project_id, args.label_id);
|
||||||
|
return {
|
||||||
|
content: [{ type: "text", text: JSON.stringify({ status: "success", message: "Label deleted successfully" }, null, 2) }],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unknown tool: ${request.params.name}`);
|
throw new Error(`Unknown tool: ${request.params.name}`);
|
||||||
}
|
}
|
||||||
|
47
schemas.ts
47
schemas.ts
@ -228,7 +228,15 @@ export const GitLabLabelSchema = z.object({
|
|||||||
id: z.number(),
|
id: z.number(),
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
color: z.string(),
|
color: z.string(),
|
||||||
description: z.string().optional(),
|
text_color: z.string(),
|
||||||
|
description: z.string().nullable(),
|
||||||
|
description_html: z.string().nullable(),
|
||||||
|
open_issues_count: z.number().optional(),
|
||||||
|
closed_issues_count: z.number().optional(),
|
||||||
|
open_merge_requests_count: z.number().optional(),
|
||||||
|
subscribed: z.boolean().optional(),
|
||||||
|
priority: z.number().nullable().optional(),
|
||||||
|
is_project_label: z.boolean().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const GitLabUserSchema = z.object({
|
export const GitLabUserSchema = z.object({
|
||||||
@ -619,6 +627,42 @@ export const ListProjectsSchema = z.object({
|
|||||||
min_access_level: z.number().optional().describe("Filter by minimum access level"),
|
min_access_level: z.number().optional().describe("Filter by minimum access level"),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Label operation schemas
|
||||||
|
export const ListLabelsSchema = z.object({
|
||||||
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
||||||
|
with_counts: z.boolean().optional().describe("Whether or not to include issue and merge request counts"),
|
||||||
|
include_ancestor_groups: z.boolean().optional().describe("Include ancestor groups"),
|
||||||
|
search: z.string().optional().describe("Keyword to filter labels by"),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const GetLabelSchema = z.object({
|
||||||
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
||||||
|
label_id: z.union([z.number(), z.string()]).describe("The ID or title of a project's label"),
|
||||||
|
include_ancestor_groups: z.boolean().optional().describe("Include ancestor groups"),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const CreateLabelSchema = z.object({
|
||||||
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
||||||
|
name: z.string().describe("The name of the label"),
|
||||||
|
color: z.string().describe("The color of the label given in 6-digit hex notation with leading '#' sign"),
|
||||||
|
description: z.string().optional().describe("The description of the label"),
|
||||||
|
priority: z.number().nullable().optional().describe("The priority of the label"),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const UpdateLabelSchema = z.object({
|
||||||
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
||||||
|
label_id: z.union([z.number(), z.string()]).describe("The ID or title of a project's label"),
|
||||||
|
new_name: z.string().optional().describe("The new name of the label"),
|
||||||
|
color: z.string().optional().describe("The color of the label given in 6-digit hex notation with leading '#' sign"),
|
||||||
|
description: z.string().optional().describe("The new description of the label"),
|
||||||
|
priority: z.number().nullable().optional().describe("The new priority of the label"),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const DeleteLabelSchema = z.object({
|
||||||
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
||||||
|
label_id: z.union([z.number(), z.string()]).describe("The ID or title of a project's label"),
|
||||||
|
});
|
||||||
|
|
||||||
// Export types
|
// Export types
|
||||||
export type GitLabAuthor = z.infer<typeof GitLabAuthorSchema>;
|
export type GitLabAuthor = z.infer<typeof GitLabAuthorSchema>;
|
||||||
export type GitLabFork = z.infer<typeof GitLabForkSchema>;
|
export type GitLabFork = z.infer<typeof GitLabForkSchema>;
|
||||||
@ -645,3 +689,4 @@ export type GitLabIssueLink = z.infer<typeof GitLabIssueLinkSchema>;
|
|||||||
export type GitLabNamespace = z.infer<typeof GitLabNamespaceSchema>;
|
export type GitLabNamespace = z.infer<typeof GitLabNamespaceSchema>;
|
||||||
export type GitLabNamespaceExistsResponse = z.infer<typeof GitLabNamespaceExistsResponseSchema>;
|
export type GitLabNamespaceExistsResponse = z.infer<typeof GitLabNamespaceExistsResponseSchema>;
|
||||||
export type GitLabProject = z.infer<typeof GitLabProjectSchema>;
|
export type GitLabProject = z.infer<typeof GitLabProjectSchema>;
|
||||||
|
export type GitLabLabel = z.infer<typeof GitLabLabelSchema>;
|
||||||
|
Reference in New Issue
Block a user