@gitlab/opencode-gitlab-plugin
v1.5.9
Published
GitLab tools plugin for OpenCode - provides GitLab API access for merge requests, issues, pipelines, and more
Readme
OpenCode GitLab Plugin
A comprehensive GitLab API plugin for OpenCode that provides AI-powered access to GitLab's REST and GraphQL APIs. This plugin enables seamless interaction with merge requests, issues, pipelines, repositories, epics, snippets, audit events, and more through natural language commands.
📋 Table of Contents
- Features
- Architecture
- Installation
- Configuration
- Available Tools
- Usage Examples
- Development
- CI/CD Pipeline
- API Reference
- Contributing
- License
✨ Features
Core Capabilities
- 🔀 Merge Requests: Full CRUD operations, discussions, notes, changes, commits, and pipelines
- 📝 Issues: Create, read, update, and comment on issues with advanced filtering
- 🎯 Work Items: Unified interface for issues, epics, tasks, and other work tracking items
- 🚀 CI/CD Pipelines: Monitor, analyze, retry pipeline jobs, and validate CI/CD configurations
- 📦 Repository Operations: File management, commits, branches, tree navigation, and commit discussions
- 🔍 Advanced Search: Multi-scope search across projects, code, issues, merge requests, commits, users, milestones, and documentation
- 📊 Epics: Enterprise-level epic management with issue associations
- 💬 Snippets: Snippet discussions, notes, and comments management
- 🔗 Universal Discussions: Unified interface for discussions across all GitLab resources
- ✅ TODOs: Personal task management and notifications
- 🔒 Security: Vulnerability scanning and security report access
- 📚 Wiki: Wiki page content retrieval
- 🔍 Audit Events: Track project, group, and instance-level security events
- 🔧 Git Commands: Execute safe, read-only git operations
- 👥 Project Management: Member management and project details
Technical Features
- TypeScript: Full type safety with comprehensive type definitions
- ESM Support: Modern ES modules for optimal tree-shaking
- Zod Validation: Runtime schema validation for all API inputs
- GraphQL Support: Native GraphQL API support with type-safe mutations and queries for TODOs, Notes, Discussions, Auto-merge, and Security tools
- Cursor-Based Pagination: GraphQL-powered pagination with
first/afterandlast/beforecursors for efficient data fetching - GID Validation: Automatic validation of GitLab Global IDs with descriptive error messages
- Error Handling: Robust error handling with detailed error messages
- Authentication: Multiple authentication methods (OAuth, API tokens)
- Rate Limiting: Built-in handling for GitLab API rate limits
- Caching: Efficient API response handling
- Modular Architecture: Clean separation of concerns with client and tool modules
- Comprehensive Testing: 180 tests with full coverage of all features
GraphQL-Powered Tools
The following tools use GitLab's GraphQL API for enhanced functionality:
| Category | Tools | Benefits |
| --------------- | ----------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| TODOs | gitlab_list_todos, gitlab_get_todo_count | Cursor-based pagination, rich filtering |
| Notes | gitlab_list_notes, gitlab_get_note, gitlab_create_note | Unified interface for all resource types, efficient pagination |
| Discussions | gitlab_list_discussions, gitlab_get_discussion, gitlab_create_discussion, gitlab_resolve_discussion | Unified interface for all resource types, cursor-based pagination, code position support |
| Auto-merge | gitlab_set_mr_auto_merge | MWPS (Merge When Pipeline Succeeds), merge train support |
| Security | All vulnerability management tools | Type-safe GID validation, mutation support |
🏗️ Architecture
System Architecture
graph TB
subgraph "OpenCode Environment"
AI[AI Assistant]
Plugin[GitLab Plugin]
end
subgraph "Plugin Components"
Tools[Tool Definitions]
Client[GitLab API Client]
Auth[Authentication Manager]
Validator[Zod Schema Validator]
end
subgraph "GitLab API"
REST[REST API v4]
GraphQL[GraphQL API]
MR[Merge Requests]
Issues[Issues]
Pipelines[Pipelines]
Repos[Repositories]
Epics[Epics]
Security[Security]
end
AI -->|Natural Language| Plugin
Plugin --> Tools
Tools --> Validator
Validator --> Client
Client --> Auth
Auth --> REST
Auth --> GraphQL
REST --> MR
REST --> Issues
REST --> Pipelines
REST --> Repos
REST --> Epics
GraphQL --> Security
GraphQL --> MRPlugin Structure
graph LR
subgraph "src/index.ts"
A[GitLabApiClient Class]
B[Authentication Functions]
C[Tool Definitions]
D[Plugin Export]
end
A --> A1[HTTP Methods]
A --> A2[Merge Request APIs]
A --> A3[Issue APIs]
A --> A4[Pipeline APIs]
A --> A5[Repository APIs]
A --> A6[Epic APIs]
A --> A7[Search APIs]
B --> B1[readTokenFromAuthStorage]
B --> B2[getGitLabClient]
C --> C1[69 Tool Definitions]
D --> A
D --> B
D --> CAuthentication Flow
sequenceDiagram
participant User
participant Plugin
participant AuthManager
participant Storage
participant GitLab
User->>Plugin: Initialize Plugin
Plugin->>AuthManager: getGitLabClient()
AuthManager->>AuthManager: Check GITLAB_TOKEN env
alt Token in Environment
AuthManager->>GitLab: Use env token
else No env token
AuthManager->>Storage: Read ~/.local/share/opencode/auth.json
Storage->>AuthManager: Return token
AuthManager->>GitLab: Use stored token
end
GitLab->>Plugin: API Response
Plugin->>User: Tool Result📦 Installation
Prerequisites
- Node.js >= 18.0.0
- npm >= 9.0.0 or Bun
- GitLab account with API access
- GitLab Personal Access Token or OAuth token
Install from npm
# Install the package
npm install @gitlab/opencode-gitlab-plugin
# Or with Bun
bun add @gitlab/opencode-gitlab-plugin
# Or with yarn
yarn add @gitlab/opencode-gitlab-pluginInstall from GitLab Repository (Development)
# Using npm
npm install git+https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin.git
# Using Bun
bun add git+https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin.gitInstall Specific Version
# Install specific version from npm
npm install @gitlab/[email protected]
# Install from specific git tag
npm install git+https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin.git#v1.0.0
# Install from specific branch
npm install git+https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin.git#mainUsing package.json
Add to your package.json:
{
"dependencies": {
"@gitlab/opencode-gitlab-plugin": "^1.0.0"
}
}Then run:
npm install⚙️ Configuration
Environment Variables
# Required: GitLab API Token
export GITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxx
# Optional: Custom GitLab Instance (defaults to https://gitlab.com)
export GITLAB_INSTANCE_URL=https://gitlab.example.comOpenCode Configuration
Add the following plugin to your opencode configuration ~/.config/opencode/opencode.json:
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["@gitlab/opencode-gitlab-plugin"]
}Authentication Storage
The plugin supports reading tokens from OpenCode's auth storage:
Location: ~/.local/share/opencode/auth.json
Format:
{
"gitlab": {
"type": "oauth",
"access": "your-oauth-token"
}
}Or for API tokens:
{
"gitlab": {
"type": "api",
"key": "glpat-xxxxxxxxxxxxxxxxxxxx"
}
}Token Priority
GITLAB_TOKENenvironment variable (highest priority)- OpenCode auth storage (
~/.local/share/opencode/auth.json) - Error if no token found
🛠️ Available Tools
The plugin provides 64 tools organized into the following categories:
Merge Request Tools (8 tools)
| Tool | Description |
| --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| gitlab_get_merge_request | Get details of a specific merge request with title, description, state, author, assignees, reviewers, labels, and diff stats |
| gitlab_list_merge_requests | List merge requests with filtering by state, scope, and labels |
| gitlab_create_merge_request | Create a new merge request |
| gitlab_update_merge_request | Update merge request title, description, state, assignees, reviewers, and labels |
| gitlab_get_mr_changes | Get file changes/diffs for a merge request |
| gitlab_get_mr_details | Get additional MR details (commits or pipelines) with detail_type parameter |
| gitlab_list_merge_request_diffs | List file diffs with pagination support for large changesets |
| gitlab_set_mr_auto_merge | Enable auto-merge (MWPS) using GraphQL API when pipeline succeeds |
Issue Tools (3 tools)
| Tool | Description |
| --------------------- | ---------------------------------------------------------------------------- |
| gitlab_create_issue | Create a new issue with title, description, labels, assignees, and milestone |
| gitlab_get_issue | Get issue details including state, author, assignees, labels, and comments |
| gitlab_list_issues | List issues with filtering by state, labels, assignee, and milestone |
Epic Tools (5 tools)
| Tool | Description |
| --------------------------- | ----------------------------------------------------------------------------- |
| gitlab_get_epic | Get epic details with title, description, state, dates, and associated issues |
| gitlab_list_epics | List epics with filtering by state, author, and labels |
| gitlab_create_epic | Create a new epic in a group |
| gitlab_update_epic | Update epic title, description, labels, dates, and state |
| gitlab_manage_epic_issues | Manage issues linked to an epic (list, add, remove) with action parameter |
Pipeline Tools (7 tools)
| Tool | Description |
| ---------------------------------- | ------------------------------------------------------------------------------- |
| gitlab_list_pipelines | List pipelines with filtering by status, ref, and username |
| gitlab_get_pipeline | Get pipeline details with jobs and status |
| gitlab_list_pipeline_jobs | List all jobs in a pipeline with optional scope filtering |
| gitlab_get_job_log | Get the log output of a specific CI job |
| gitlab_retry_job | Retry a failed or canceled job |
| gitlab_get_pipeline_failing_jobs | Get only failed jobs for easier debugging |
| gitlab_lint_ci_config | Validate CI/CD YAML config with mode parameter (content or existing repository) |
Repository Tools (7 tools)
| Tool | Description |
| ----------------------------- | ------------------------------------------------------ |
| gitlab_get_file | Get file contents from any branch, tag, or commit |
| gitlab_get_commit | Get commit details with metadata, author, and stats |
| gitlab_list_commits | List commits with filtering by branch, path, and dates |
| gitlab_get_commit_diff | Get diff for a specific commit |
| gitlab_list_repository_tree | List files and directories at a given path |
| gitlab_list_branches | List all branches in a repository |
| gitlab_get_commit_comments | Get all commit comments in flat structure |
Search Tools (2 tools)
| Tool | Description |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| gitlab_search | Unified search across all GitLab resources with scope-specific options (projects, issues, merge_requests, milestones, users, blobs, commits, notes, wiki_blobs, group_projects) |
| gitlab_documentation_search | Search GitLab official documentation at docs.gitlab.com |
Work Item Tools (6 tools)
| Tool | Description |
| ------------------------------ | -------------------------------------------------------- |
| gitlab_get_work_item | Get a work item (unified model for issues, epics, tasks) |
| gitlab_list_work_items | List work items in a project or group |
| gitlab_get_work_item_notes | Get all comments for a work item |
| gitlab_create_work_item | Create a new work item |
| gitlab_update_work_item | Update work item title, description, state, and labels |
| gitlab_create_work_item_note | Add a comment to a work item |
Security Tools (8 tools)
| Tool | Description |
| ----------------------------------------- | ------------------------------------------------------------------------- |
| gitlab_list_vulnerabilities | List security vulnerabilities with filtering by state, severity, and type |
| gitlab_get_vulnerability_details | Get detailed vulnerability information with remediation |
| gitlab_create_vulnerability_issue | Create an issue linked to vulnerabilities (GraphQL) |
| gitlab_dismiss_vulnerability | Dismiss vulnerability with reason (GraphQL) |
| gitlab_confirm_vulnerability | Confirm a vulnerability as valid (GraphQL) |
| gitlab_revert_vulnerability_to_detected | Revert vulnerability state (GraphQL) |
| gitlab_update_vulnerability_severity | Update vulnerability severity level (GraphQL) |
| gitlab_link_vulnerability_to_issue | Link vulnerabilities to existing issue (GraphQL) |
Note: All GraphQL-based security tools include automatic GID (Global ID) format validation.
TODO Tools (3 tools)
| Tool | Description |
| ----------------------- | ------------------------------------------------------ |
| gitlab_list_todos | List TODO items with cursor-based pagination (GraphQL) |
| gitlab_mark_todo_done | Mark TODOs as done with action parameter (one or all) |
| gitlab_get_todo_count | Get count of pending TODOs (GraphQL) |
Project & User Tools (3 tools)
| Tool | Description |
| ----------------------------- | ---------------------------------- |
| gitlab_get_project | Get project details and metadata |
| gitlab_list_project_members | List all members of a project |
| gitlab_get_current_user | Get authenticated user information |
Discussion Tools (4 tools)
| Tool | Description |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| gitlab_list_discussions | List discussions (comment threads) on any GitLab resource (MRs, issues, epics, commits, snippets) with cursor pagination |
| gitlab_get_discussion | Get a specific discussion thread with all replies from any resource type |
| gitlab_create_discussion | Create a new discussion thread OR reply to an existing one (supports code-position comments for MRs and commits) |
| gitlab_resolve_discussion | Mark a discussion thread as resolved or unresolve it (MRs and issues only) |
Notes Tools (3 tools)
| Tool | Description |
| -------------------- | --------------------------------------------------------------------------------------------------- |
| gitlab_list_notes | List all notes/comments on any resource (MRs, issues, epics, snippets) with cursor-based pagination |
| gitlab_get_note | Get a single note by ID (issues and epics only) |
| gitlab_create_note | Add a simple comment to any resource (for thread replies, use gitlab_create_discussion) |
Audit Event Tools (3 tools)
| Tool | Description |
| ----------------------------------- | -------------------------------------------------------- |
| gitlab_list_project_audit_events | List audit events for a project (requires owner role) |
| gitlab_list_group_audit_events | List audit events for a group (requires owner role) |
| gitlab_list_instance_audit_events | List instance-level audit events (requires admin access) |
Git Command Tool (1 tool)
| Tool | Description |
| ----------------- | ------------------------------------------------------------------------------------------------------ |
| run_git_command | Execute safe, read-only git commands (status, log, show, diff, blame, etc.) with security restrictions |
Wiki Tools (1 tool)
| Tool | Description |
| ---------------------- | ---------------------------------- |
| gitlab_get_wiki_page | Get wiki page content and metadata |
💡 Usage Examples
Example 1: Create and Manage Issues
import gitlabPlugin from '@gitlab/opencode-gitlab-plugin';
const plugin = await gitlabPlugin({});
// Create a new issue
const issue = await plugin.tool.gitlab_create_issue.execute({
project_id: 'my-group/my-project',
title: 'Fix authentication bug',
description:
'## Problem\n\nUsers cannot login with OAuth.\n\n## Steps to Reproduce\n1. Go to login page\n2. Click OAuth button\n3. Error occurs',
labels: 'bug,authentication,priority::high',
assignee_ids: [42],
milestone_id: 10,
due_date: '2025-12-31',
});
console.log(`Issue created: ${issue.web_url}`);
// Add a comment to the issue (using unified notes tool)
await plugin.tool.gitlab_create_note.execute({
resource_type: 'issue',
project_id: 'my-group/my-project',
iid: issue.iid,
body: 'I will start working on this today.',
});
// List all issues with specific labels
const issues = await plugin.tool.gitlab_list_issues.execute({
project_id: 'my-group/my-project',
labels: 'bug',
state: 'opened',
});Example 2: Review Merge Request
// Get merge request details
const mr = await plugin.tool.gitlab_get_merge_request.execute({
project_id: 'gitlab-org/gitlab',
mr_iid: 12345,
include_changes: true,
});
// Get discussions (unified tool supports all resource types)
const discussions = await plugin.tool.gitlab_list_discussions.execute({
resource_type: 'merge_request',
project_id: 'gitlab-org/gitlab',
iid: 12345,
});
// Add a review comment (creates a new discussion)
await plugin.tool.gitlab_create_discussion.execute({
resource_type: 'merge_request',
project_id: 'gitlab-org/gitlab',
iid: 12345,
body: 'LGTM! Great work on this feature.',
});
// Reply to an existing discussion thread
await plugin.tool.gitlab_create_discussion.execute({
resource_type: 'merge_request',
project_id: 'gitlab-org/gitlab',
iid: 12345,
discussion_id: discussions.discussions.nodes[0].id,
body: 'Thanks for addressing the feedback!',
});Example 3: Debug Failed Pipeline
// List recent pipelines
const pipelines = await plugin.tool.gitlab_list_pipelines.execute({
project_id: 'my-group/my-project',
status: 'failed',
limit: 5,
});
// Get failed jobs
const failedJobs = await plugin.tool.gitlab_get_pipeline_failing_jobs.execute({
project_id: 'my-group/my-project',
pipeline_id: pipelines[0].id,
});
// Get job logs
for (const job of failedJobs) {
const log = await plugin.tool.gitlab_get_job_log.execute({
project_id: 'my-group/my-project',
job_id: job.id,
});
console.log(`Job ${job.name} failed with:\n${log}`);
}
// Retry failed jobs
await plugin.tool.gitlab_retry_job.execute({
project_id: 'my-group/my-project',
job_id: failedJobs[0].id,
});Example 4: Create and Manage Epic
// Create an epic
const epic = await plugin.tool.gitlab_create_epic.execute({
group_id: 'my-group',
title: 'Q1 2025 Features',
description: 'All features planned for Q1 2025',
start_date: '2025-01-01',
end_date: '2025-03-31',
labels: 'Q1,planning',
});
// Add issues to epic
await plugin.tool.gitlab_add_issue_to_epic.execute({
group_id: 'my-group',
epic_iid: epic.iid,
issue_id: 123,
});
// List all issues in epic
const epicIssues = await plugin.tool.gitlab_list_epic_issues.execute({
group_id: 'my-group',
epic_iid: epic.iid,
});
// Add a comment (creates a new discussion)
await plugin.tool.gitlab_create_discussion.execute({
resource_type: 'epic',
group_id: 'my-group',
iid: epic.iid,
body: 'Epic created and issues linked successfully!',
});Example 5: Search and Analyze Code
// Search for code containing specific patterns
const codeResults = await plugin.tool.gitlab_blob_search.execute({
search: 'async function processPayment',
project_id: 'my-group/my-project',
limit: 10,
});
// Search for related issues
const issues = await plugin.tool.gitlab_issue_search.execute({
search: 'payment processing bug',
project_id: 'my-group/my-project',
state: 'opened',
});
// Get file content
const fileContent = await plugin.tool.gitlab_get_file.execute({
project_id: 'my-group/my-project',
file_path: 'src/payment/processor.ts',
ref: 'main',
});Example 6: Manage TODOs (GraphQL with Pagination)
// Get TODO count (uses GraphQL)
const todoCount = await plugin.tool.gitlab_get_todo_count.execute({});
// List pending TODOs with cursor-based pagination
const firstPage = await plugin.tool.gitlab_list_todos.execute({
state: 'pending',
type: 'MergeRequest',
first: 20,
});
// Get next page using cursor
if (firstPage.todos.pageInfo.hasNextPage) {
const nextPage = await plugin.tool.gitlab_list_todos.execute({
state: 'pending',
type: 'MergeRequest',
first: 20,
after: firstPage.todos.pageInfo.endCursor,
});
}
// Mark specific TODO as done
await plugin.tool.gitlab_mark_todo_done.execute({
todo_id: firstPage.todos.nodes[0].id,
});
// Mark all TODOs as done
await plugin.tool.gitlab_mark_all_todos_done.execute({});Example 7: Create Commit with Multiple Files
// Create a commit with multiple file operations
const commit = await plugin.tool.gitlab_create_commit.execute({
project_id: 'my-group/my-project',
branch: 'feature/new-api',
commit_message: 'feat: add new API endpoints',
actions: [
{
action: 'create',
file_path: 'src/api/v2/users.ts',
content: 'export const getUsers = async () => { ... }',
},
{
action: 'update',
file_path: 'src/api/index.ts',
content: 'export * from "./v2/users";',
},
{
action: 'delete',
file_path: 'src/api/deprecated.ts',
},
],
author_name: 'John Doe',
author_email: '[email protected]',
});Example 8: Enable Auto-Merge (MWPS)
// Get merge request to retrieve current HEAD SHA
const mr = await plugin.tool.gitlab_get_merge_request.execute({
project_id: 'my-group/my-project',
mr_iid: 123,
});
// Enable auto-merge when pipeline succeeds (GraphQL)
const result = await plugin.tool.gitlab_set_mr_auto_merge.execute({
project_id: 'my-group/my-project',
mr_iid: 123,
sha: mr.sha, // Required to prevent race conditions
strategy: 'MERGE_WHEN_CHECKS_PASS', // or 'ADD_TO_MERGE_TRAIN_WHEN_CHECKS_PASS'
});
console.log(`Auto-merge enabled: ${result.mergeRequest.autoMergeEnabled}`);Example 9: Manage Security Vulnerabilities
// List vulnerabilities in a project
const vulnerabilities = await plugin.tool.gitlab_list_vulnerabilities.execute({
project_id: 'my-group/my-project',
state: 'detected',
severity: 'high',
report_type: 'sast',
});
// Create an issue for critical vulnerabilities
const issue = await plugin.tool.gitlab_create_vulnerability_issue.execute({
project_path: 'my-group/my-project',
vulnerability_ids: ['gid://gitlab/Vulnerability/123', 'gid://gitlab/Vulnerability/124'],
});
// Dismiss a false positive
await plugin.tool.gitlab_dismiss_vulnerability.execute({
vulnerability_id: 'gid://gitlab/Vulnerability/125',
reason: 'FALSE_POSITIVE',
comment: 'This is a test file and not part of production code',
});
// Confirm a real vulnerability
await plugin.tool.gitlab_confirm_vulnerability.execute({
vulnerability_id: 'gid://gitlab/Vulnerability/126',
comment: 'Confirmed - needs immediate attention',
});
// Update severity based on assessment
await plugin.tool.gitlab_update_vulnerability_severity.execute({
vulnerability_ids: ['gid://gitlab/Vulnerability/127'],
severity: 'CRITICAL',
comment: 'Upgrading to critical - affects production authentication',
});
// Link vulnerabilities to existing issue
await plugin.tool.gitlab_link_vulnerability_to_issue.execute({
issue_id: 'gid://gitlab/Issue/42',
vulnerability_ids: ['gid://gitlab/Vulnerability/128', 'gid://gitlab/Vulnerability/129'],
});🔧 Development
Project Structure
opencode-gitlab-plugin/
├── src/
│ ├── client/ # API client modules
│ │ ├── base.ts # Base client with HTTP & GraphQL methods
│ │ ├── security.ts # Security/vulnerability management
│ │ ├── issues.ts # Issue management
│ │ ├── merge-requests.ts # Merge request operations
│ │ ├── pipelines.ts # CI/CD pipeline operations
│ │ ├── repository.ts # Repository operations
│ │ ├── epics.ts # Epic management
│ │ ├── search.ts # Search operations
│ │ ├── todos.ts # TODO management
│ │ ├── wikis.ts # Wiki operations
│ │ ├── work-items.ts # Work item operations
│ │ ├── audit.ts # Audit events
│ │ ├── git.ts # Git operations
│ │ └── index.ts # Client exports
│ ├── tools/ # Tool definitions
│ │ ├── security.ts # Security tool definitions
│ │ ├── issues.ts # Issue tool definitions
│ │ ├── merge-requests.ts # MR tool definitions
│ │ ├── pipelines.ts # Pipeline tool definitions
│ │ ├── repository.ts # Repository tool definitions
│ │ ├── discussions-unified.ts # Unified discussion tools (4 tools)
│ │ ├── notes-unified.ts # Unified notes tools (3 tools)
│ │ └── ... # Other tool definitions
│ ├── index.ts # Main plugin entry point
│ ├── utils.ts # Utility functions
│ └── validation.ts # GID validation utilities
├── tests/ # Test suite (180 tests)
│ ├── client/ # Client tests
│ ├── tools/ # Tool tests
│ ├── validation.test.ts # Validation tests
│ └── utils.test.ts # Utility tests
├── dist/ # Compiled output (generated)
│ ├── index.js # ESM bundle
│ └── index.d.ts # TypeScript definitions
├── .husky/ # Git hooks
│ ├── commit-msg # Commitlint hook
│ └── pre-commit # Lint-staged hook
├── .gitlab-ci.yml # CI/CD pipeline configuration
├── package.json # Package metadata
├── tsconfig.json # TypeScript configuration
├── vitest.config.ts # Vitest test configuration
├── .eslintrc.json # ESLint configuration
├── .prettierrc.json # Prettier configuration
├── .commitlintrc.json # Commitlint configuration
├── .releaserc.json # Semantic-release configuration
├── CHANGELOG.md # Auto-generated changelog
├── INSTALLATION.md # Installation guide
└── README.md # This fileSetup Development Environment
# Clone the repository
git clone https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin.git
cd opencode-gitlab-plugin
# Install dependencies
npm install
# Build the plugin
npm run build
# Watch mode for development
npm run dev
# Run linting
npm run lint
# Fix linting issues
npm run lint:fix
# Format code
npm run format
# Check formatting
npm run format:checkGit Hooks
The project uses Husky for Git hooks:
- pre-commit: Runs lint-staged to lint and format staged files
- commit-msg: Validates commit messages using commitlint
Commit Message Convention
This project follows Conventional Commits:
<type>(<scope>): <subject>
<body>
<footer>Types:
feat: New featurefix: Bug fixdocs: Documentation changesstyle: Code style changes (formatting, etc.)refactor: Code refactoringperf: Performance improvementstest: Adding or updating testsbuild: Build system changesci: CI/CD changeschore: Other changes (dependencies, etc.)revert: Revert a previous commit
Examples:
git commit -m "feat: add support for GitLab wiki pages"
git commit -m "fix: handle empty API responses correctly"
git commit -m "docs: update installation instructions"
git commit -m "ci: add automated release workflow"Building
# Build for production
npm run build
# The build process:
# 1. Compiles TypeScript to ESM
# 2. Generates type definitions
# 3. Outputs to dist/ directoryTesting
# Run tests
npm test
# Run tests in watch mode
npm run test:watch
# Run tests with coverage
npm run test:coverageTest Coverage:
- 180 tests across 21 test files
- Client tests for all API methods (REST and GraphQL)
- Tool tests for all tool definitions
- Validation tests for GID utilities
- GraphQL method tests for Notes, Discussions, TODOs
- All tests passing ✅
🚀 CI/CD Pipeline
Pipeline Stages
graph LR
A[Test] --> B[Build]
B --> C[Release]
A --> A1[Lint]
A --> A2[Format Check]
A --> A3[Unit Tests]
B --> B1[TypeScript Build]
B --> B2[Generate Types]
C --> C1[Semantic Release]
C --> C2[Publish to Registry]
C --> C3[Create Git Tag]
C --> C4[Update Changelog]Pipeline Configuration
The .gitlab-ci.yml defines the following stages:
1. Test Stage
- test:lint: Runs ESLint on source code
- test:format: Checks code formatting with Prettier
- test:unit: Runs unit tests (placeholder)
2. Build Stage
- build: Compiles TypeScript and generates artifacts
- Uses tsup for bundling
- Generates ESM output
- Creates TypeScript definitions
- Artifacts expire in 1 week
3. Release Stage
- release: Automated versioning and publishing
- Only runs on main branch
- Uses semantic-release
- Publishes to GitLab Package Registry
- Creates Git tags
- Updates CHANGELOG.md
- Artifacts never expire
Semantic Release Workflow
sequenceDiagram
participant Dev as Developer
participant Git as Git Repository
participant CI as GitLab CI
participant SR as Semantic Release
participant Reg as Package Registry
Dev->>Git: Push to main branch
Git->>CI: Trigger pipeline
CI->>CI: Run tests
CI->>CI: Build package
CI->>SR: Run semantic-release
SR->>SR: Analyze commits
SR->>SR: Determine version
SR->>SR: Generate changelog
SR->>Git: Create tag & commit
SR->>Reg: Publish package
SR->>Git: Create GitLab releaseRelease Process
The release process is fully automated using semantic-release:
- Commit Analysis: Analyzes commit messages since last release
- Version Calculation: Determines next version based on commit types
fix:→ Patch version (1.0.x)feat:→ Minor version (1.x.0)BREAKING CHANGE:→ Major version (x.0.0)
- Changelog Generation: Updates CHANGELOG.md
- Package Publishing: Publishes to GitLab Package Registry
- Git Tagging: Creates and pushes version tag
- GitLab Release: Creates release notes on GitLab
Environment Variables
The CI/CD pipeline uses the following variables:
CI_JOB_TOKEN: GitLab CI token (automatic)CI_PROJECT_ID: Project ID (automatic)CI_API_V4_URL: GitLab API URL (automatic)HUSKY: Set to0to disable hooks in CI
📚 API Reference
GitLabApiClient Class
The core API client that handles all GitLab REST API interactions.
Constructor
constructor(instanceUrl: string, token: string)HTTP Methods
async fetch<T>(method: string, path: string, body?: unknown): Promise<T>
async fetchText(method: string, path: string): Promise<string>GraphQL Methods
/**
* Execute a GraphQL query or mutation
* @template T - The expected type of the data field in the GraphQL response
* @param query - The GraphQL query or mutation string
* @param variables - Optional variables for the query
* @returns The data from the GraphQL response
*/
async fetchGraphQL<T>(query: string, variables?: Record<string, unknown>): Promise<T>Features:
- Full TypeScript type safety with generic return types
- Automatic error handling for both HTTP and GraphQL errors
- Support for query variables
- Cursor-based pagination support for large result sets
- Used by TODOs, Notes, Discussions, Auto-merge, and Security tools
Example:
const result = await client.fetchGraphQL<{ vulnerability: { id: string } }>(
`mutation($id: VulnerabilityID!) {
vulnerabilityConfirm(input: { id: $id }) {
vulnerability { id state }
errors
}
}`,
{ id: 'gid://gitlab/Vulnerability/123' }
);Pagination Example:
// First page
const page1 = await plugin.tool.gitlab_list_todos.execute({ first: 20 });
// Navigate with cursor
const page2 = await plugin.tool.gitlab_list_todos.execute({
first: 20,
after: page1.todos.pageInfo.endCursor,
});Project ID Encoding
private encodeProjectId(projectId: string): stringHandles URL encoding for project paths (e.g., gitlab-org/gitlab → gitlab-org%2Fgitlab)
Authentication Functions
readTokenFromAuthStorage
function readTokenFromAuthStorage(): string | undefined;Reads GitLab token from OpenCode auth storage (~/.local/share/opencode/auth.json).
Supports:
- OAuth tokens:
{ type: "oauth", access: "token" } - API tokens:
{ type: "api", key: "token" }
getGitLabClient
function getGitLabClient(): GitLabApiClient;Creates and returns a configured GitLab API client.
Priority:
GITLAB_TOKENenvironment variable- OpenCode auth storage
- Throws error if no token found
Validation Functions
isValidGid
function isValidGid(gid: string, expectedType?: string): boolean;Validates GitLab Global ID (GID) format.
Parameters:
gid- The GID to validate (e.g.,gid://gitlab/Vulnerability/123)expectedType- Optional expected resource type (e.g.,'Vulnerability','Issue')
Returns: true if valid, false otherwise
Example:
isValidGid('gid://gitlab/Vulnerability/123'); // true
isValidGid('gid://gitlab/Issue/456', 'Issue'); // true
isValidGid('gid://gitlab/Vulnerability/123', 'Issue'); // false (wrong type)
isValidGid('invalid-gid'); // falsevalidateGid
function validateGid(gid: string, expectedType?: string): void;Validates GID format and throws descriptive error if invalid.
Parameters:
gid- The GID to validateexpectedType- Optional expected resource type
Throws: Error with descriptive message if GID format is invalid
Example:
validateGid('gid://gitlab/Vulnerability/123'); // No error
validateGid('invalid-gid'); // Throws: "Invalid GitLab Global ID: 'invalid-gid'. Expected format: gid://gitlab/ResourceType/{id}"
validateGid('gid://gitlab/Issue/123', 'Vulnerability'); // Throws: "Invalid GitLab Global ID of type 'Vulnerability'..."Usage in Security Tools:
All GraphQL-based security tools automatically validate GID parameters:
createVulnerabilityIssue()- validates vulnerability IDsdismissVulnerability()- validates vulnerability IDconfirmVulnerability()- validates vulnerability IDrevertVulnerability()- validates vulnerability IDupdateVulnerabilitySeverity()- validates vulnerability IDslinkVulnerabilityToIssue()- validates both issue ID and vulnerability IDs
Tool Schema Validation
All tools use Zod for runtime validation:
import { tool } from '@opencode-ai/plugin';
const z = tool.schema; // Zod v4 compatible
// Example tool definition
gitlab_get_merge_request: tool({
description: 'Get details of a specific merge request',
args: {
project_id: z.string().describe('The project ID or URL-encoded path'),
mr_iid: z.number().describe('The internal ID of the merge request'),
include_changes: z.boolean().optional().describe('Include file changes'),
},
execute: async (args, ctx) => {
// Implementation
},
});Error Handling
All API calls include comprehensive error handling:
if (!response.ok) {
const errorText = await response.text();
throw new Error(`GitLab API error ${response.status}: ${errorText}`);
}Response Formatting
All tool responses are JSON-formatted:
return JSON.stringify(result, null, 2);🔐 Security Considerations
Token Storage
- Environment Variables: Recommended for CI/CD and production
- Auth Storage: Convenient for local development
- Never commit tokens: Use
.gitignorefor sensitive files
API Permissions
The plugin requires a GitLab token with appropriate scopes:
api: Full API access (recommended)read_api: Read-only access (limited functionality)read_repository: Repository read accesswrite_repository: Repository write access (for commits)
Rate Limiting
GitLab API has rate limits:
- Authenticated requests: 2,000 requests per minute
- Unauthenticated requests: 10 requests per minute
The plugin does not implement rate limiting logic. Consider implementing retry logic in your application.
HTTPS Only
The plugin enforces HTTPS for all API calls. HTTP URLs are not supported.
🤝 Contributing
Contributions are welcome! Please see our Contributing Guide for detailed guidelines on:
- Code style and conventions
- Development workflow
- Testing requirements
- Submitting merge requests
- Developer Certificate of Origin and License
Quick Start for Contributors:
Commit Messages: Use conventional commits format
feat(scope): add new feature fix(scope): fix bug docs(scope): update documentationCode Quality: Ensure all checks pass
npm run lint npm testTesting: Add tests for new features
🔗 Links
- GitLab Repository
- npm Package
- Issue Tracker
- Merge Requests
- Contributing Guide
- Changelog
- CI/CD Pipelines
- GitLab API Documentation
- OpenCode Plugin SDK
🙏 Acknowledgments
- OpenCode Team: For the plugin SDK and framework
- GitLab: For the comprehensive REST API
- Contributors: All contributors to this project
📞 Support
For questions, issues, or feature requests:
- Check existing issues: https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin/-/issues
- Create new issue: Use issue templates for bugs or features
- Discussions: Use GitLab discussions for questions
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
Made with ❤️ for the OpenCode community
