diff --git a/apps/sim/blocks/blocks/gitlab.ts b/apps/sim/blocks/blocks/gitlab.ts index 078422bedac..6de2a6ba07b 100644 --- a/apps/sim/blocks/blocks/gitlab.ts +++ b/apps/sim/blocks/blocks/gitlab.ts @@ -54,6 +54,8 @@ export const GitLabBlock: BlockConfig = { { label: 'List Commits', id: 'gitlab_list_commits' }, { label: 'List Branches', id: 'gitlab_list_branches' }, { label: 'Create Branch', id: 'gitlab_create_branch' }, + { label: 'Delete Branch', id: 'gitlab_delete_branch' }, + { label: 'Compare Branches', id: 'gitlab_compare_branches' }, // Additional Merge Request Operations { label: 'Get MR Changes', id: 'gitlab_get_merge_request_changes' }, { label: 'Approve Merge Request', id: 'gitlab_approve_merge_request' }, @@ -61,6 +63,9 @@ export const GitLabBlock: BlockConfig = { { label: 'List Pipeline Jobs', id: 'gitlab_list_pipeline_jobs' }, { label: 'Get Job Log', id: 'gitlab_get_job_log' }, { label: 'Play Job', id: 'gitlab_play_job' }, + // Release Operations + { label: 'List Releases', id: 'gitlab_list_releases' }, + { label: 'Create Release', id: 'gitlab_create_release' }, ], value: () => 'gitlab_list_projects', }, @@ -116,11 +121,15 @@ export const GitLabBlock: BlockConfig = { 'gitlab_list_commits', 'gitlab_list_branches', 'gitlab_create_branch', + 'gitlab_delete_branch', + 'gitlab_compare_branches', 'gitlab_get_merge_request_changes', 'gitlab_approve_merge_request', 'gitlab_list_pipeline_jobs', 'gitlab_get_job_log', 'gitlab_play_job', + 'gitlab_list_releases', + 'gitlab_create_release', ], }, }, @@ -210,16 +219,18 @@ Return ONLY the title - no explanations, no extra text.`, 'gitlab_update_issue', 'gitlab_create_merge_request', 'gitlab_update_merge_request', + 'gitlab_create_release', ], }, wandConfig: { enabled: true, - prompt: `Generate a comprehensive description for a GitLab issue or merge request based on the user's request. + prompt: `Generate a comprehensive description for a GitLab issue, merge request, or release based on the user's request. Include relevant sections as appropriate: - Summary of changes or problem - Context and motivation - Testing done (for MRs) - Steps to reproduce (for bugs) +- Highlights and notable changes (for releases) Use Markdown formatting for readability. @@ -278,11 +289,19 @@ Return ONLY the comment text - no explanations, no extra formatting.`, title: 'Branch/Tag', type: 'short-input', placeholder: 'Enter branch or tag name', - required: true, - condition: { + required: { field: 'operation', value: ['gitlab_create_pipeline', 'gitlab_get_file', 'gitlab_create_branch'], }, + condition: { + field: 'operation', + value: [ + 'gitlab_create_pipeline', + 'gitlab_get_file', + 'gitlab_create_branch', + 'gitlab_create_release', + ], + }, }, // File Path { @@ -305,7 +324,102 @@ Return ONLY the comment text - no explanations, no extra formatting.`, required: true, condition: { field: 'operation', - value: ['gitlab_create_file', 'gitlab_update_file', 'gitlab_create_branch'], + value: [ + 'gitlab_create_file', + 'gitlab_update_file', + 'gitlab_create_branch', + 'gitlab_delete_branch', + ], + }, + }, + // Compare from ref + { + id: 'compareFrom', + title: 'From', + type: 'short-input', + placeholder: 'Branch, tag, or commit SHA to compare from', + required: true, + condition: { + field: 'operation', + value: ['gitlab_compare_branches'], + }, + }, + // Compare to ref + { + id: 'compareTo', + title: 'To', + type: 'short-input', + placeholder: 'Branch, tag, or commit SHA to compare to', + required: true, + condition: { + field: 'operation', + value: ['gitlab_compare_branches'], + }, + }, + // Compare directly instead of using merge base + { + id: 'straight', + title: 'Compare Directly', + type: 'switch', + mode: 'advanced', + condition: { + field: 'operation', + value: ['gitlab_compare_branches'], + }, + }, + // Release tag name + { + id: 'tagName', + title: 'Tag Name', + type: 'short-input', + placeholder: 'Enter the Git tag for the release (e.g., v1.0.0)', + required: true, + condition: { + field: 'operation', + value: ['gitlab_create_release'], + }, + }, + // Release name + { + id: 'releaseName', + title: 'Release Name', + type: 'short-input', + placeholder: 'Enter release name (optional)', + condition: { + field: 'operation', + value: ['gitlab_create_release'], + }, + }, + // Release date + { + id: 'releasedAt', + title: 'Released At', + type: 'short-input', + placeholder: 'ISO 8601 date for an upcoming or historical release (optional)', + mode: 'advanced', + condition: { + field: 'operation', + value: ['gitlab_create_release'], + }, + wandConfig: { + enabled: true, + prompt: `Generate an ISO 8601 timestamp based on the user's description of when the release happened or will happen. + +Return ONLY the timestamp string - no explanations, no extra text.`, + generationType: 'timestamp', + placeholder: 'Describe when the release happened...', + }, + }, + // Release milestones + { + id: 'releaseMilestones', + title: 'Milestones', + type: 'short-input', + placeholder: 'Milestone titles (comma-separated, optional)', + mode: 'advanced', + condition: { + field: 'operation', + value: ['gitlab_create_release'], }, }, // File Content @@ -593,6 +707,7 @@ Return ONLY the commit message - no explanations, no extra text.`, 'gitlab_list_branches', 'gitlab_list_commits', 'gitlab_list_pipeline_jobs', + 'gitlab_list_releases', ], }, }, @@ -614,6 +729,7 @@ Return ONLY the commit message - no explanations, no extra text.`, 'gitlab_list_branches', 'gitlab_list_commits', 'gitlab_list_pipeline_jobs', + 'gitlab_list_releases', ], }, }, @@ -650,6 +766,8 @@ Return ONLY the commit message - no explanations, no extra text.`, 'gitlab_create_file', 'gitlab_update_file', 'gitlab_create_branch', + 'gitlab_delete_branch', + 'gitlab_compare_branches', 'gitlab_list_branches', 'gitlab_list_commits', 'gitlab_get_merge_request_changes', @@ -657,6 +775,8 @@ Return ONLY the commit message - no explanations, no extra text.`, 'gitlab_list_pipeline_jobs', 'gitlab_get_job_log', 'gitlab_play_job', + 'gitlab_list_releases', + 'gitlab_create_release', ], config: { tool: (params) => { @@ -960,6 +1080,32 @@ Return ONLY the commit message - no explanations, no extra text.`, page: params.page ? Number(params.page) : undefined, } + case 'gitlab_delete_branch': + if (!params.projectId?.trim() || !params.branch?.trim()) { + throw new Error('Project ID and branch name are required.') + } + return { + ...baseParams, + projectId: params.projectId.trim(), + branch: params.branch.trim(), + } + + case 'gitlab_compare_branches': + if ( + !params.projectId?.trim() || + !params.compareFrom?.trim() || + !params.compareTo?.trim() + ) { + throw new Error('Project ID, from ref, and to ref are required.') + } + return { + ...baseParams, + projectId: params.projectId.trim(), + from: params.compareFrom.trim(), + to: params.compareTo.trim(), + straight: params.straight || undefined, + } + case 'gitlab_list_commits': if (!params.projectId?.trim()) { throw new Error('Project ID is required.') @@ -1026,6 +1172,37 @@ Return ONLY the commit message - no explanations, no extra text.`, jobId: Number(params.jobId), } + case 'gitlab_list_releases': + if (!params.projectId?.trim()) { + throw new Error('Project ID is required.') + } + return { + ...baseParams, + projectId: params.projectId.trim(), + perPage: params.perPage ? Number(params.perPage) : undefined, + page: params.page ? Number(params.page) : undefined, + } + + case 'gitlab_create_release': + if (!params.projectId?.trim() || !params.tagName?.trim()) { + throw new Error('Project ID and tag name are required.') + } + return { + ...baseParams, + projectId: params.projectId.trim(), + tagName: params.tagName.trim(), + name: params.releaseName?.trim() || undefined, + description: params.description?.trim() || undefined, + ref: params.ref?.trim() || undefined, + releasedAt: params.releasedAt?.trim() || undefined, + milestones: params.releaseMilestones + ? params.releaseMilestones + .split(',') + .map((title: string) => title.trim()) + .filter(Boolean) + : undefined, + } + default: return baseParams } @@ -1071,6 +1248,13 @@ Return ONLY the commit message - no explanations, no extra text.`, refName: { type: 'string', description: 'Branch or tag name filter' }, scope: { type: 'string', description: 'Job scope filter' }, sha: { type: 'string', description: 'Commit SHA' }, + compareFrom: { type: 'string', description: 'Branch, tag, or commit SHA to compare from' }, + compareTo: { type: 'string', description: 'Branch, tag, or commit SHA to compare to' }, + straight: { type: 'boolean', description: 'Compare directly instead of using the merge base' }, + tagName: { type: 'string', description: 'Git tag for the release' }, + releaseName: { type: 'string', description: 'Release name' }, + releasedAt: { type: 'string', description: 'ISO 8601 date for the release' }, + releaseMilestones: { type: 'string', description: 'Milestone titles (comma-separated)' }, }, outputs: { // Project outputs @@ -1082,6 +1266,7 @@ Return ONLY the commit message - no explanations, no extra text.`, // Merge request outputs mergeRequests: { type: 'json', description: 'List of merge requests' }, mergeRequest: { type: 'json', description: 'Merge request details' }, + mergeRequestIid: { type: 'number', description: 'Merge request internal ID (IID)' }, // Pipeline outputs pipelines: { type: 'json', description: 'List of pipelines' }, pipeline: { type: 'json', description: 'Pipeline details' }, @@ -1091,17 +1276,38 @@ Return ONLY the commit message - no explanations, no extra text.`, tree: { type: 'json', description: 'Repository tree entries' }, content: { type: 'string', description: 'File contents (decoded)' }, fileName: { type: 'string', description: 'File name' }, + filePath: { type: 'string', description: 'Path to the file in the repository' }, + branch: { type: 'string', description: 'Branch the file was committed to' }, branches: { type: 'json', description: 'List of branches' }, commits: { type: 'json', description: 'List of commits' }, + commit: { type: 'json', description: 'A single commit (e.g. latest commit in a comparison)' }, name: { type: 'string', description: 'Created branch name' }, + protected: { type: 'boolean', description: 'Whether the branch is protected' }, + size: { type: 'number', description: 'File size in bytes' }, + ref: { type: 'string', description: 'The branch, tag, or commit SHA' }, + blobId: { type: 'string', description: 'The blob ID' }, + lastCommitId: { type: 'string', description: 'The last commit ID that modified the file' }, webUrl: { type: 'string', description: 'Web URL' }, // Merge request change outputs changes: { type: 'json', description: 'Merge request file changes/diffs' }, + changesCount: { type: 'number', description: 'Number of changed files returned' }, approvalsRequired: { type: 'number', description: 'Approvals required' }, approvalsLeft: { type: 'number', description: 'Approvals remaining' }, + approvedBy: { type: 'json', description: 'List of approvers' }, // Job outputs jobs: { type: 'json', description: 'Pipeline jobs' }, log: { type: 'string', description: 'Job log output' }, + id: { type: 'number', description: 'Job ID' }, + status: { type: 'string', description: 'Job status' }, + // Compare outputs + diffs: { type: 'json', description: 'File diffs between two compared references' }, + compareTimeout: { type: 'boolean', description: 'Whether the comparison timed out' }, + compareSameRef: { type: 'boolean', description: 'Whether both compared references match' }, + // Release outputs + releases: { type: 'json', description: 'List of releases' }, + release: { type: 'json', description: 'Release details' }, + // Pagination + total: { type: 'number', description: 'Total number of items available across all pages' }, // Success indicator success: { type: 'boolean', description: 'Operation success status' }, }, @@ -1213,5 +1419,12 @@ export const GitLabBlockMeta = { content: '# Monitor Pipeline Status\n\nUse GitLab to keep an eye on CI pipelines.\n\n## Steps\n1. List pipelines for the project and identify the most recent runs.\n2. Get the pipeline details for any that failed to read the status and reason.\n3. If a failure looks transient, use Retry Pipeline to re-run it.\n\n## Output\nReturn a summary of recent pipeline runs (ref, status, when) and call out any failures. If a retry was triggered, include the retried pipeline ID.', }, + { + name: 'draft-release-notes', + description: + 'Compare two refs, summarize the merged changes, and publish a GitLab release with generated notes.', + content: + "# Draft Release Notes\n\nUse GitLab to publish a release with notes generated from the changes since the last tag.\n\n## Steps\n1. Compare Branches between the previous release tag and the target ref to list the commits and diffs.\n2. Summarize the changes into readable release notes, grouped by feature, fix, or chore.\n3. Use Create Release with the new tag name, the generated description, and the target ref.\n\n## Output\nReturn the created release's tag name and a confirmation that the notes were published, along with the release notes text.", + }, ], } as const satisfies BlockMeta diff --git a/apps/sim/tools/gitlab/compare_branches.ts b/apps/sim/tools/gitlab/compare_branches.ts new file mode 100644 index 00000000000..ae6df3deedd --- /dev/null +++ b/apps/sim/tools/gitlab/compare_branches.ts @@ -0,0 +1,123 @@ +import type { + GitLabCompareBranchesParams, + GitLabCompareBranchesResponse, +} from '@/tools/gitlab/types' +import { getGitLabApiBase } from '@/tools/gitlab/utils' +import type { ToolConfig } from '@/tools/types' + +export const gitlabCompareBranchesTool: ToolConfig< + GitLabCompareBranchesParams, + GitLabCompareBranchesResponse +> = { + id: 'gitlab_compare_branches', + name: 'GitLab Compare Branches', + description: 'Compare two branches, tags, or commits in a GitLab project repository', + version: '1.0.0', + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'GitLab Personal Access Token', + }, + host: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Self-managed GitLab host (e.g. gitlab.example.com). Defaults to gitlab.com.', + }, + projectId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Project ID or URL-encoded path', + }, + from: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Commit SHA or branch/tag name to compare from', + }, + to: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Commit SHA or branch/tag name to compare to', + }, + straight: { + type: 'boolean', + required: false, + visibility: 'user-or-llm', + description: 'Compare directly from..to instead of using the merge base (defaults to false)', + }, + }, + + request: { + url: (params) => { + const encodedId = encodeURIComponent(String(params.projectId).trim()) + const queryParams = new URLSearchParams() + queryParams.append('from', params.from) + queryParams.append('to', params.to) + if (params.straight) queryParams.append('straight', 'true') + + return `${getGitLabApiBase(params.host)}/projects/${encodedId}/repository/compare?${queryParams.toString()}` + }, + method: 'GET', + headers: (params) => ({ + 'PRIVATE-TOKEN': params.accessToken, + }), + }, + + transformResponse: async (response) => { + if (!response.ok) { + const errorText = await response.text() + return { + success: false, + error: `GitLab API error: ${response.status} ${errorText}`, + output: {}, + } + } + + const data = await response.json() + + return { + success: true, + output: { + commit: data.commit ?? null, + commits: data.commits ?? [], + diffs: data.diffs ?? [], + compareTimeout: data.compare_timeout ?? null, + compareSameRef: data.compare_same_ref ?? null, + webUrl: data.web_url ?? null, + }, + } + }, + + outputs: { + commit: { + type: 'object', + description: 'The latest commit in the comparison', + }, + commits: { + type: 'array', + description: 'Commits between the two references', + }, + diffs: { + type: 'array', + description: 'File diffs between the two references', + }, + compareTimeout: { + type: 'boolean', + description: 'Whether the comparison exceeded size limits or timed out', + }, + compareSameRef: { + type: 'boolean', + description: 'Whether both references point to the same commit', + }, + webUrl: { + type: 'string', + description: 'The web URL for viewing the comparison', + }, + }, +} diff --git a/apps/sim/tools/gitlab/create_release.ts b/apps/sim/tools/gitlab/create_release.ts new file mode 100644 index 00000000000..38d15f27e86 --- /dev/null +++ b/apps/sim/tools/gitlab/create_release.ts @@ -0,0 +1,122 @@ +import type { GitLabCreateReleaseParams, GitLabCreateReleaseResponse } from '@/tools/gitlab/types' +import { getGitLabApiBase } from '@/tools/gitlab/utils' +import type { ToolConfig } from '@/tools/types' + +export const gitlabCreateReleaseTool: ToolConfig< + GitLabCreateReleaseParams, + GitLabCreateReleaseResponse +> = { + id: 'gitlab_create_release', + name: 'GitLab Create Release', + description: 'Create a new release in a GitLab project', + version: '1.0.0', + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'GitLab Personal Access Token', + }, + host: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Self-managed GitLab host (e.g. gitlab.example.com). Defaults to gitlab.com.', + }, + projectId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Project ID or URL-encoded path', + }, + tagName: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Git tag for the release', + }, + name: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'The release name', + }, + description: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Release description/notes (Markdown supported)', + }, + ref: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Commit SHA, branch, or tag to create the tag from if it does not already exist', + }, + releasedAt: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'ISO 8601 date for an upcoming or historical release', + }, + milestones: { + type: 'array', + required: false, + visibility: 'user-or-llm', + description: 'Array of milestone titles to associate with the release', + }, + }, + + request: { + url: (params) => { + const encodedId = encodeURIComponent(String(params.projectId).trim()) + return `${getGitLabApiBase(params.host)}/projects/${encodedId}/releases` + }, + method: 'POST', + headers: (params) => ({ + 'Content-Type': 'application/json', + 'PRIVATE-TOKEN': params.accessToken, + }), + body: (params) => { + const body: Record = { + tag_name: params.tagName, + } + + if (params.name) body.name = params.name + if (params.description) body.description = params.description + if (params.ref) body.ref = params.ref + if (params.releasedAt) body.released_at = params.releasedAt + if (params.milestones && params.milestones.length > 0) body.milestones = params.milestones + + return body + }, + }, + + transformResponse: async (response) => { + if (!response.ok) { + const errorText = await response.text() + return { + success: false, + error: `GitLab API error: ${response.status} ${errorText}`, + output: {}, + } + } + + const release = await response.json() + + return { + success: true, + output: { + release, + }, + } + }, + + outputs: { + release: { + type: 'object', + description: 'The created GitLab release', + }, + }, +} diff --git a/apps/sim/tools/gitlab/delete_branch.ts b/apps/sim/tools/gitlab/delete_branch.ts new file mode 100644 index 00000000000..2570b90bdbc --- /dev/null +++ b/apps/sim/tools/gitlab/delete_branch.ts @@ -0,0 +1,77 @@ +import type { GitLabDeleteBranchParams, GitLabDeleteBranchResponse } from '@/tools/gitlab/types' +import { getGitLabApiBase } from '@/tools/gitlab/utils' +import type { ToolConfig } from '@/tools/types' + +export const gitlabDeleteBranchTool: ToolConfig< + GitLabDeleteBranchParams, + GitLabDeleteBranchResponse +> = { + id: 'gitlab_delete_branch', + name: 'GitLab Delete Branch', + description: 'Delete a branch from a GitLab project repository', + version: '1.0.0', + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'GitLab Personal Access Token', + }, + host: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Self-managed GitLab host (e.g. gitlab.example.com). Defaults to gitlab.com.', + }, + projectId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Project ID or URL-encoded path', + }, + branch: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Name of the branch to delete', + }, + }, + + request: { + url: (params) => { + const encodedId = encodeURIComponent(String(params.projectId).trim()) + const encodedBranch = encodeURIComponent(String(params.branch).trim()) + return `${getGitLabApiBase(params.host)}/projects/${encodedId}/repository/branches/${encodedBranch}` + }, + method: 'DELETE', + headers: (params) => ({ + 'PRIVATE-TOKEN': params.accessToken, + }), + }, + + transformResponse: async (response) => { + if (!response.ok) { + const errorText = await response.text() + return { + success: false, + error: `GitLab API error: ${response.status} ${errorText}`, + output: {}, + } + } + + return { + success: true, + output: { + success: true, + }, + } + }, + + outputs: { + success: { + type: 'boolean', + description: 'Whether the branch was deleted successfully', + }, + }, +} diff --git a/apps/sim/tools/gitlab/get_merge_request_changes.ts b/apps/sim/tools/gitlab/get_merge_request_changes.ts index 4bd6ba78e5e..add4e90af10 100644 --- a/apps/sim/tools/gitlab/get_merge_request_changes.ts +++ b/apps/sim/tools/gitlab/get_merge_request_changes.ts @@ -44,7 +44,7 @@ export const gitlabGetMergeRequestChangesTool: ToolConfig< request: { /** * Uses the `/diffs` endpoint (the `/changes` endpoint was deprecated in - * GitLab 15.7 and removed in 18.0). `/diffs` returns the diff array directly + * GitLab 15.7, with removal scheduled for API v5). `/diffs` returns the diff array directly * and is paginated; we request the max page size (100) to return the changes * in a single call, which covers the vast majority of merge requests. */ diff --git a/apps/sim/tools/gitlab/index.ts b/apps/sim/tools/gitlab/index.ts index 25d7ba9e6cd..a87fd9de27f 100644 --- a/apps/sim/tools/gitlab/index.ts +++ b/apps/sim/tools/gitlab/index.ts @@ -1,5 +1,6 @@ import { gitlabApproveMergeRequestTool } from '@/tools/gitlab/approve_merge_request' import { gitlabCancelPipelineTool } from '@/tools/gitlab/cancel_pipeline' +import { gitlabCompareBranchesTool } from '@/tools/gitlab/compare_branches' import { gitlabCreateBranchTool } from '@/tools/gitlab/create_branch' import { gitlabCreateFileTool } from '@/tools/gitlab/create_file' import { gitlabCreateIssueTool } from '@/tools/gitlab/create_issue' @@ -7,6 +8,8 @@ import { gitlabCreateIssueNoteTool } from '@/tools/gitlab/create_issue_note' import { gitlabCreateMergeRequestTool } from '@/tools/gitlab/create_merge_request' import { gitlabCreateMergeRequestNoteTool } from '@/tools/gitlab/create_merge_request_note' import { gitlabCreatePipelineTool } from '@/tools/gitlab/create_pipeline' +import { gitlabCreateReleaseTool } from '@/tools/gitlab/create_release' +import { gitlabDeleteBranchTool } from '@/tools/gitlab/delete_branch' import { gitlabDeleteIssueTool } from '@/tools/gitlab/delete_issue' import { gitlabGetFileTool } from '@/tools/gitlab/get_file' import { gitlabGetIssueTool } from '@/tools/gitlab/get_issue' @@ -22,6 +25,7 @@ import { gitlabListMergeRequestsTool } from '@/tools/gitlab/list_merge_requests' import { gitlabListPipelineJobsTool } from '@/tools/gitlab/list_pipeline_jobs' import { gitlabListPipelinesTool } from '@/tools/gitlab/list_pipelines' import { gitlabListProjectsTool } from '@/tools/gitlab/list_projects' +import { gitlabListReleasesTool } from '@/tools/gitlab/list_releases' import { gitlabListRepositoryTreeTool } from '@/tools/gitlab/list_repository_tree' import { gitlabMergeMergeRequestTool } from '@/tools/gitlab/merge_merge_request' import { gitlabPlayJobTool } from '@/tools/gitlab/play_job' @@ -68,6 +72,11 @@ export { // Branches gitlabListBranchesTool, gitlabCreateBranchTool, + gitlabDeleteBranchTool, + gitlabCompareBranchesTool, // Commits gitlabListCommitsTool, + // Releases + gitlabListReleasesTool, + gitlabCreateReleaseTool, } diff --git a/apps/sim/tools/gitlab/list_issues.ts b/apps/sim/tools/gitlab/list_issues.ts index 8a46a915314..a2bb9d1416b 100644 --- a/apps/sim/tools/gitlab/list_issues.ts +++ b/apps/sim/tools/gitlab/list_issues.ts @@ -61,7 +61,8 @@ export const gitlabListIssuesTool: ToolConfig = { + id: 'gitlab_list_releases', + name: 'GitLab List Releases', + description: 'List releases in a GitLab project', + version: '1.0.0', + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'GitLab Personal Access Token', + }, + host: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Self-managed GitLab host (e.g. gitlab.example.com). Defaults to gitlab.com.', + }, + projectId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Project ID or URL-encoded path', + }, + orderBy: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Order by field (released_at, created_at)', + }, + sort: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Sort direction (asc, desc)', + }, + perPage: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Number of results per page (default 20, max 100)', + }, + page: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Page number for pagination', + }, + }, + + request: { + url: (params) => { + const encodedId = encodeURIComponent(String(params.projectId).trim()) + const queryParams = new URLSearchParams() + + if (params.orderBy) queryParams.append('order_by', params.orderBy) + if (params.sort) queryParams.append('sort', params.sort) + if (params.perPage) queryParams.append('per_page', String(params.perPage)) + if (params.page) queryParams.append('page', String(params.page)) + + const query = queryParams.toString() + return `${getGitLabApiBase(params.host)}/projects/${encodedId}/releases${query ? `?${query}` : ''}` + }, + method: 'GET', + headers: (params) => ({ + 'PRIVATE-TOKEN': params.accessToken, + }), + }, + + transformResponse: async (response) => { + if (!response.ok) { + const errorText = await response.text() + return { + success: false, + error: `GitLab API error: ${response.status} ${errorText}`, + output: {}, + } + } + + const releases = await response.json() + const total = response.headers.get('x-total') + + return { + success: true, + output: { + releases: releases ?? [], + total: total ? Number.parseInt(total, 10) : (releases?.length ?? 0), + }, + } + }, + + outputs: { + releases: { + type: 'array', + description: 'List of GitLab releases', + }, + total: { + type: 'number', + description: 'Total number of releases', + }, + }, +} diff --git a/apps/sim/tools/gitlab/types.ts b/apps/sim/tools/gitlab/types.ts index d87a10d67b6..694244d6325 100644 --- a/apps/sim/tools/gitlab/types.ts +++ b/apps/sim/tools/gitlab/types.ts @@ -196,36 +196,29 @@ interface GitLabNote { noteable_iid?: number } -interface GitLabUser { - id: number - name: string - username: string - email?: string - state: string - avatar_url: string - web_url: string -} - -interface GitLabLabel { - id: number - name: string - color: string +interface GitLabRelease { + tag_name: string + name?: string description?: string - text_color: string -} - -interface GitLabMilestone { - id: number - iid: number - project_id: number - title: string - description?: string - state: string created_at: string - updated_at: string - due_date?: string - start_date?: string - web_url: string + released_at?: string + author?: { + id: number + name: string + username: string + } + commit?: { + id: string + short_id: string + title: string + } + milestones?: unknown[] + assets?: { + count?: number + sources?: unknown[] + links?: unknown[] + } + _links?: Record } interface GitLabBaseParams { @@ -404,20 +397,22 @@ export interface GitLabListBranchesParams extends GitLabBaseParams { page?: number } -interface GitLabGetBranchParams extends GitLabBaseParams { +export interface GitLabCreateBranchParams extends GitLabBaseParams { projectId: string | number branch: string + ref: string } -export interface GitLabCreateBranchParams extends GitLabBaseParams { +export interface GitLabDeleteBranchParams extends GitLabBaseParams { projectId: string | number branch: string - ref: string } -interface GitLabDeleteBranchParams extends GitLabBaseParams { +export interface GitLabCompareBranchesParams extends GitLabBaseParams { projectId: string | number - branch: string + from: string + to: string + straight?: boolean } export interface GitLabListRepositoryTreeParams extends GitLabBaseParams { @@ -493,56 +488,34 @@ export interface GitLabPlayJobParams extends GitLabBaseParams { jobId: number } -interface GitLabListIssueNotesParams extends GitLabBaseParams { - projectId: string | number - issueIid: number - orderBy?: 'created_at' | 'updated_at' - sort?: 'asc' | 'desc' - perPage?: number - page?: number -} - export interface GitLabCreateIssueNoteParams extends GitLabBaseParams { projectId: string | number issueIid: number body: string } -interface GitLabListMergeRequestNotesParams extends GitLabBaseParams { - projectId: string | number - mergeRequestIid: number - orderBy?: 'created_at' | 'updated_at' - sort?: 'asc' | 'desc' - perPage?: number - page?: number -} - export interface GitLabCreateMergeRequestNoteParams extends GitLabBaseParams { projectId: string | number mergeRequestIid: number body: string } -interface GitLabListLabelsParams extends GitLabBaseParams { +export interface GitLabListReleasesParams extends GitLabBaseParams { projectId: string | number - search?: string + orderBy?: 'released_at' | 'created_at' + sort?: 'asc' | 'desc' perPage?: number page?: number } -interface GitLabCreateLabelParams extends GitLabBaseParams { +export interface GitLabCreateReleaseParams extends GitLabBaseParams { projectId: string | number - name: string - color: string + tagName: string + name?: string description?: string -} - -interface GitLabGetCurrentUserParams extends GitLabBaseParams {} - -interface GitLabListUsersParams extends GitLabBaseParams { - search?: string - perPage?: number - page?: number + ref?: string + releasedAt?: string + milestones?: string[] } export interface GitLabListProjectsResponse extends ToolResponse { @@ -658,12 +631,6 @@ export interface GitLabListBranchesResponse extends ToolResponse { } } -interface GitLabGetBranchResponse extends ToolResponse { - output: { - branch?: GitLabBranch - } -} - export interface GitLabCreateBranchResponse extends ToolResponse { output: { name?: string | null @@ -673,16 +640,20 @@ export interface GitLabCreateBranchResponse extends ToolResponse { } } -interface GitLabDeleteBranchResponse extends ToolResponse { +export interface GitLabDeleteBranchResponse extends ToolResponse { output: { success?: boolean } } -interface GitLabListNotesResponse extends ToolResponse { +export interface GitLabCompareBranchesResponse extends ToolResponse { output: { - notes?: GitLabNote[] - total?: number + commit?: unknown + commits?: unknown[] + diffs?: unknown[] + compareTimeout?: boolean | null + compareSameRef?: boolean | null + webUrl?: string | null } } @@ -692,29 +663,16 @@ export interface GitLabCreateNoteResponse extends ToolResponse { } } -interface GitLabListLabelsResponse extends ToolResponse { +export interface GitLabListReleasesResponse extends ToolResponse { output: { - labels?: GitLabLabel[] + releases?: GitLabRelease[] total?: number } } -interface GitLabCreateLabelResponse extends ToolResponse { +export interface GitLabCreateReleaseResponse extends ToolResponse { output: { - label?: GitLabLabel - } -} - -interface GitLabGetCurrentUserResponse extends ToolResponse { - output: { - user?: GitLabUser - } -} - -interface GitLabListUsersResponse extends ToolResponse { - output: { - users?: GitLabUser[] - total?: number + release?: GitLabRelease } } @@ -815,15 +773,12 @@ export type GitLabResponse = | GitLabRetryPipelineResponse | GitLabCancelPipelineResponse | GitLabListBranchesResponse - | GitLabGetBranchResponse | GitLabCreateBranchResponse | GitLabDeleteBranchResponse - | GitLabListNotesResponse + | GitLabCompareBranchesResponse | GitLabCreateNoteResponse - | GitLabListLabelsResponse - | GitLabCreateLabelResponse - | GitLabGetCurrentUserResponse - | GitLabListUsersResponse + | GitLabListReleasesResponse + | GitLabCreateReleaseResponse | GitLabListRepositoryTreeResponse | GitLabGetFileResponse | GitLabCreateFileResponse diff --git a/apps/sim/tools/registry.ts b/apps/sim/tools/registry.ts index f32edc49219..f1feb55d3f3 100644 --- a/apps/sim/tools/registry.ts +++ b/apps/sim/tools/registry.ts @@ -1170,6 +1170,7 @@ import { import { gitlabApproveMergeRequestTool, gitlabCancelPipelineTool, + gitlabCompareBranchesTool, gitlabCreateBranchTool, gitlabCreateFileTool, gitlabCreateIssueNoteTool, @@ -1177,6 +1178,8 @@ import { gitlabCreateMergeRequestNoteTool, gitlabCreateMergeRequestTool, gitlabCreatePipelineTool, + gitlabCreateReleaseTool, + gitlabDeleteBranchTool, gitlabDeleteIssueTool, gitlabGetFileTool, gitlabGetIssueTool, @@ -1192,6 +1195,7 @@ import { gitlabListPipelineJobsTool, gitlabListPipelinesTool, gitlabListProjectsTool, + gitlabListReleasesTool, gitlabListRepositoryTreeTool, gitlabMergeMergeRequestTool, gitlabPlayJobTool, @@ -5948,6 +5952,7 @@ export const tools: Record = { github_list_stargazers_v2: githubListStargazersV2Tool, gitlab_approve_merge_request: gitlabApproveMergeRequestTool, gitlab_cancel_pipeline: gitlabCancelPipelineTool, + gitlab_compare_branches: gitlabCompareBranchesTool, gitlab_create_branch: gitlabCreateBranchTool, gitlab_create_file: gitlabCreateFileTool, gitlab_create_issue: gitlabCreateIssueTool, @@ -5955,6 +5960,8 @@ export const tools: Record = { gitlab_create_merge_request: gitlabCreateMergeRequestTool, gitlab_create_merge_request_note: gitlabCreateMergeRequestNoteTool, gitlab_create_pipeline: gitlabCreatePipelineTool, + gitlab_create_release: gitlabCreateReleaseTool, + gitlab_delete_branch: gitlabDeleteBranchTool, gitlab_delete_issue: gitlabDeleteIssueTool, gitlab_get_file: gitlabGetFileTool, gitlab_get_issue: gitlabGetIssueTool, @@ -5970,6 +5977,7 @@ export const tools: Record = { gitlab_list_pipeline_jobs: gitlabListPipelineJobsTool, gitlab_list_pipelines: gitlabListPipelinesTool, gitlab_list_projects: gitlabListProjectsTool, + gitlab_list_releases: gitlabListReleasesTool, gitlab_list_repository_tree: gitlabListRepositoryTreeTool, gitlab_merge_merge_request: gitlabMergeMergeRequestTool, gitlab_play_job: gitlabPlayJobTool,