gitlab-auto-reviewers
v2.1.0
Published
Shared library for GitLab auto-reviewer suggestions with MCP server, CLI, and library modes
Maintainers
Readme
GitLab Auto Reviewers
A shared library for intelligent GitLab merge request reviewer suggestions. Provides MCP server, CLI, and library modes for analyzing git blame data, team member availability with FTE-aware load balancing, CODEOWNERS rules, and current reviewer workload to suggest the most appropriate reviewers.
Table of Contents
- Installation
- Quick Start
- What's New in v2.0
- Features
- Architecture
- Configuration
- Tools
- CLI Usage
- Library Usage
- Data Source Comparison
- Webhook Integration
- MCP Integration
- Team Configuration
- Code Owners
- Known Limitations
- Troubleshooting
- Development
- Contributing
- Migration from v1.x
- Documentation
Installation
Install the package from npm:
npm install gitlab-auto-reviewersQuick Start
The package supports three execution modes:
MCP Server Mode
Run as an MCP server for AI assistants:
# MCP Server mode
npx gitlab-auto-reviewers mcp
# Or using the deprecated command (backward compatibility)
npx auto-reviewers-mcp-serverOr add it to your MCP configuration (see MCP Integration section below).
CLI Mode
Use the command-line interface for posting reviewer suggestions:
# Posts reviewer suggestions as comments (default behavior)
npx gitlab-auto-reviewers cli --project my-group/my-project --mr 123
# Analysis only (use --dry-run for testing)
npx gitlab-auto-reviewers cli --project my-group/my-project --mr 123 --dry-run
# Post suggestions for a branch
npx gitlab-auto-reviewers cli --project my-group/my-project --branch feature/new-feature
# JSON output for automation (still posts comments)
npx gitlab-auto-reviewers cli --project my-group/my-project --mr 123 --format json
# Use local git repository (faster analysis)
npx gitlab-auto-reviewers cli --repo-path /path/to/repo --mr 123See CLI Usage section and Migration Guide for detailed documentation.
Library Mode
Import and use as a library in your Node.js application:
import { ReviewerService, GitLabAPIDataSource } from 'gitlab-auto-reviewers';
const dataSource = new GitLabAPIDataSource(gitlabToken, gitlabUrl);
const service = new ReviewerService(dataSource);
const suggestions = await service.suggestReviewers({
project: 'my-group/my-project',
mergeRequestIid: 123
});See Library Usage section for detailed documentation.
What's New in v2.0
Version 2.0 brings significant improvements to reliability, performance, and developer experience:
🚀 Performance Improvements
- In-memory caching with configurable TTL (default 5 minutes)
- Parallel data fetching for independent operations
- Automatic retry logic with exponential backoff
- Up to 5x faster response times with caching enabled
🛡️ Reliability Enhancements
- Automatic retry for transient failures (network errors, rate limits)
- Smart error classification (retryable vs. permanent)
- Graceful degradation with partial results on partial failures
- Configuration validation on startup with clear error messages
🔍 Developer Experience
- Full TypeScript strict mode with zero
anytypes - Structured logging with DEBUG, INFO, WARN, ERROR levels
- Performance metrics tracking for all operations
- Enhanced error messages with context and suggestions
- Comprehensive documentation including migration and troubleshooting guides
📊 Observability
- Cache statistics (hit rate, size, performance)
- Operation timing for performance monitoring
- Debug mode with detailed diagnostic information
- Contextual logging for easier troubleshooting
🔧 Configuration
- Centralized configuration management
- Environment variable support with validation
- Default values with logging
- Multiple configuration profiles (development, production, etc.)
💬 CLI Enhancement (Breaking Change)
- Comment posting by default - CLI now posts reviewer suggestions as comments
- Dry-run mode with
--dry-runflag for analysis-only - Cross-interface consistency - CLI behavior matches MCP server
- Enhanced help system with actionable error messages
- Migration guide for upgrading from v1.x
See MIGRATION.md and CLI Migration Guide for detailed upgrade instructions.
Features
Core Functionality
Intelligent Reviewer Suggestions: Automatically suggest reviewers based on multiple factors
- Git blame analysis of changed files to find previous contributors
- Team member availability with FTE-aware load balancing
- Code ownership rules from CODEOWNERS file
- Current reviewer workload across open merge requests
Dual Data Source Support: Works with both GitLab API and local git repositories
- API Mode: Fetches data from GitLab API (requires network access)
- Local Git Mode: Analyzes local repository (faster, works offline)
Performance & Reliability (New in v2.0)
In-Memory Caching: Configurable caching with TTL support
- Reduces API calls and improves response times
- Automatic cache invalidation
- Cache statistics tracking
Automatic Retry Logic: Resilient error handling
- Exponential backoff for transient failures
- Configurable retry attempts and delays
- Smart classification of retryable vs. permanent errors
Parallel Operations: Concurrent data fetching
- Multiple API requests in parallel
- Configurable concurrency limits
- Significantly faster response times
Developer Experience (New in v2.0)
Type Safety: Full TypeScript strict mode
- Zero
anytypes in production code - Comprehensive type definitions
- Type guards for runtime validation
- Zero
Structured Logging: Multi-level logging system
- DEBUG, INFO, WARN, ERROR levels
- Contextual information in all logs
- Performance metrics tracking
- Easy debugging and monitoring
Configuration Management: Centralized configuration
- Environment variable support
- Validation on startup with clear error messages
- Default values with logging
- Runtime configuration access
Enhanced Error Messages: Clear, actionable errors
- Error codes for programmatic handling
- Detailed context and suggestions
- Stack traces in debug mode
Architecture
System Overview
┌─────────────────────────────────────────────────────────────────┐
│ gitlab-auto-reviewers │
│ (npm package) │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐ │
│ │ MCP Server │ │ CLI │ │ Shared Library │ │
│ │ (bin/mcp) │ │ (bin/cli) │ │ (exports) │ │
│ └────────┬───────┘ └────────┬───────┘ └────────┬───────┘ │
│ │ │ │ │
│ └───────────────────┴────────────────────┘ │
│ │ │
│ ┌───────────────────────────┴──────────────────────────────┐ │
│ │ Core Services & Data Sources │ │
│ ├───────────────────────────────────────────────────────────┤ │
│ │ • ReviewerService │ │
│ │ • ContributorsService │ │
│ │ • CodeownersService │ │
│ │ • TeamMembersService │ │
│ │ • CommentBuilderService │ │
│ ├───────────────────────────────────────────────────────────┤ │
│ │ Data Sources: │ │
│ │ • GitLabAPIDataSource (API-based, stateless) │ │
│ │ • LocalGitDataSource (local repo, faster) │ │
│ └───────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
│ imported by
↓
┌─────────────────────────────────────────────────────────────────┐
│ oce-gitlab-mr-bot │
│ (NestJS Application) │
├─────────────────────────────────────────────────────────────────┤
│ ┌────────────────────────────────────────────────────────┐ │
│ │ B2B-MFE Webhook Module │ │
│ │ • Controller (receives GitLab webhook events) │ │
│ │ • Service (uses gitlab-auto-reviewers library) │ │
│ │ • Type Guards (validates webhook payloads) │ │
│ └────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘Component Responsibilities
- MCP Server: Handles MCP protocol communication and tool routing
- Config Service: Centralized configuration management with validation
- Logger Service: Structured logging with appropriate log levels
- Error Handler: Consistent error handling with retry logic
- Cache Service: Optional in-memory caching for performance
- Reviewer Service: Core business logic for reviewer suggestions
- Data Sources: Abstract data access (API or local git)
Configuration
The server can be configured through environment variables or tool parameters.
Environment Variables
| Variable | Description | Default | Required |
|----------|-------------|---------|----------|
| GITLAB_TOKEN | GitLab API token | - | Yes* |
| GITLAB_URL | GitLab instance URL | https://gitlab.com | No |
| REPO_PATH | Local repository path | Auto-detected | No |
| CACHE_ENABLED | Enable in-memory caching | true | No |
| CACHE_TTL | Cache TTL in milliseconds | 300000 (5 min) | No |
| MAX_PARALLEL_REQUESTS | Max parallel API requests | 5 | No |
| CONTRIBUTOR_DAYS | Days to analyze for contributors | 352 | No |
| MAX_RETRIES | Max retry attempts for failures | 3 | No |
| RETRY_DELAY_MS | Initial retry delay in ms | 1000 | No |
| LOG_LEVEL | Logging level | info | No |
| DEBUG | Enable debug mode | false | No |
*Can be provided as tool parameter instead
Configuration File
Create a .env file in your project root:
# GitLab Configuration
GITLAB_TOKEN=your_gitlab_token_here
GITLAB_URL=https://gitlab.com
# Performance Configuration
CACHE_ENABLED=true
CACHE_TTL=300000
MAX_PARALLEL_REQUESTS=5
# Git Configuration
CONTRIBUTOR_DAYS=352
MAX_RETRIES=3
RETRY_DELAY_MS=1000
# Logging Configuration
LOG_LEVEL=info
DEBUG=falseConfiguration Examples
High Performance Setup
# Optimized for speed with aggressive caching
CACHE_ENABLED=true
CACHE_TTL=600000 # 10 minutes
MAX_PARALLEL_REQUESTS=10 # More concurrent requests
CONTRIBUTOR_DAYS=90 # Shorter analysis window
MAX_RETRIES=2 # Fewer retriesDevelopment Setup
# Optimized for debugging
CACHE_ENABLED=false # Disable cache for fresh data
LOG_LEVEL=debug # Detailed logging
DEBUG=true # Enable debug mode
MAX_RETRIES=1 # Fail fastProduction Setup
# Balanced for reliability and performance
CACHE_ENABLED=true
CACHE_TTL=300000 # 5 minutes
MAX_PARALLEL_REQUESTS=5 # Moderate concurrency
CONTRIBUTOR_DAYS=352 # Empirically optimized analysis
MAX_RETRIES=3 # Standard retries
LOG_LEVEL=info # Normal logging
DEBUG=false # Disable debug modeOffline/Local Git Setup
# Use local git repository (no API calls)
REPO_PATH=/path/to/repo # Local repository path
CACHE_ENABLED=true # Cache git operations
CONTRIBUTOR_DAYS=180 # Moderate analysis window
LOG_LEVEL=infoLow Memory Setup
# Minimize memory usage
CACHE_ENABLED=false # Disable caching
MAX_PARALLEL_REQUESTS=2 # Reduce concurrency
CONTRIBUTOR_DAYS=90 # Shorter analysisConfiguration Validation
The server validates all configuration on startup and will fail fast with clear error messages if:
- Required values are missing
- Values are invalid (e.g., negative numbers, invalid URLs)
- Values are out of acceptable ranges
Example error message:
Configuration validation failed:
- GITLAB_URL is not a valid URL: not-a-url
- CACHE_TTL must be non-negative, got: -1000
- MAX_PARALLEL_REQUESTS must be at least 1, got: 0
Please check your environment variables and try again.Tools
The MCP server exposes the following tools for AI assistants:
suggest_reviewers
Suggests reviewers for a GitLab merge request based on multiple factors.
Analysis Factors:
- Git blame analysis of changed files to find previous contributors
- Team member availability with FTE-aware load balancing
- Code ownership rules from CODEOWNERS file
- Current reviewer workload across open merge requests
Parameters:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| project | string | number | No* | GitLab project ID or path (e.g., "group/project" or 123) |
| mergeRequestIid | number | No* | Merge request internal ID (IID) |
| branch | string | No* | Branch name (alternative to mergeRequestIid) |
| gitlabToken | string | No** | GitLab API token |
| gitlabUrl | string | No | GitLab instance URL (defaults to https://gitlab.com) |
| repoPath | string | No | Local repository path (auto-detected if not provided) |
*Either mergeRequestIid or branch must be provided
**Required if not set in environment variable GITLAB_TOKEN
Returns:
{
contributors: ReviewerSuggestion[], // Reviewers based on file contributions
teamMembers: ReviewerSuggestion[], // Reviewers based on team membership
codeOwners: ReviewerSuggestion[], // Reviewers based on CODEOWNERS
comment: string // Formatted comment for GitLab MR
}Example:
{
"project": "my-group/my-project",
"mergeRequestIid": 123,
"gitlabToken": "glpat-xxxxxxxxxxxx"
}get_contributor_analysis
Provides detailed analysis of who contributed to the changed files using git blame.
Parameters:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| project | string | number | Yes | GitLab project ID or path |
| mergeRequestIid | number | Yes | Merge request internal ID |
| gitlabToken | string | No* | GitLab API token |
| gitlabUrl | string | No | GitLab instance URL |
*Required if not set in environment variable GITLAB_TOKEN
Returns:
{
files: Array<{
path: string,
contributors: Array<{
username: string,
email: string,
lineCount: number
}>
}>
}Example:
{
"project": 123,
"mergeRequestIid": 456
}get_reviewer_workload
Analyzes current workload of potential reviewers across open merge requests.
Parameters:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| project | string | number | Yes | GitLab project ID or path |
| gitlabToken | string | No* | GitLab API token |
| gitlabUrl | string | No | GitLab instance URL |
*Required if not set in environment variable GITLAB_TOKEN
Returns:
{
reviewers: Array<{
username: string,
openMRCount: number,
fte?: number,
capacity?: number,
utilizationPercent?: number
}>
}Example:
{
"project": "my-group/my-project"
}post_comment
Posts a comment to a GitLab merge request.
Parameters:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| project | string | number | No* | GitLab project ID or path |
| mergeRequestIid | number | No* | Merge request internal ID |
| branch | string | No* | Branch name (alternative to mergeRequestIid) |
| comment | string | Yes | Comment text to post |
| gitlabToken | string | No** | GitLab API token |
| gitlabUrl | string | No | GitLab instance URL |
| repoPath | string | No | Local repository path |
*Either mergeRequestIid or branch must be provided
**Required if not set in environment variable GITLAB_TOKEN
Example:
{
"project": 123,
"mergeRequestIid": 456,
"comment": "Suggested reviewers: @alice, @bob"
}invite_reviewers
Invites suggested reviewers to a GitLab merge request.
Parameters:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| project | string | number | No* | GitLab project ID or path |
| mergeRequestIid | number | No* | Merge request internal ID |
| branch | string | No* | Branch name (alternative to mergeRequestIid) |
| gitlabToken | string | No** | GitLab API token |
| gitlabUrl | string | No | GitLab instance URL |
| repoPath | string | No | Local repository path |
*Either mergeRequestIid or branch must be provided
**Required if not set in environment variable GITLAB_TOKEN
Example:
{
"project": "my-group/my-project",
"branch": "feature/new-feature"
}CLI Usage
The CLI mode allows you to analyze merge requests from the command line, useful for development, CI/CD pipelines, and automation scripts.
For comprehensive CLI documentation, see docs/CLI.md.
Quick Start
# Analyze a merge request
npx gitlab-auto-reviewers cli --repo-path . --mr 123
# Analyze by branch name
npx gitlab-auto-reviewers cli --repo-path . --branch feature/my-feature
# Output as JSON
npx gitlab-auto-reviewers cli --repo-path . --mr 123 --format jsonBasic Options
| Option | Description | Example |
|--------|-------------|---------|
| --repo-path <path> | Path to local git repository | --repo-path . |
| --mr <number> | Merge request IID | --mr 123 |
| --branch <name> | Branch name (alternative to --mr) | --branch feature/new-feature |
| --format <type> | Output format: json or text | --format json |
| --gitlab-token <token> | GitLab API token | --gitlab-token glpat-xxxx |
| --gitlab-url <url> | GitLab instance URL | --gitlab-url https://gitlab.com |
| --verbose | Enable verbose logging | --verbose |
| --help | Show help message | --help |
Development Environment
# Set GitLab token
export GITLAB_TOKEN=glpat-xxxxxxxxxxxx
# Analyze current merge request
cd /path/to/your/project
gitlab-auto-reviewers cli --repo-path . --mr 123
# Enable verbose output for debugging
gitlab-auto-reviewers cli --repo-path . --mr 123 --verboseCI/CD Integration
GitLab CI
suggest-reviewers:
stage: review
image: node:18
script:
- npx gitlab-auto-reviewers cli --repo-path $CI_PROJECT_DIR --mr $CI_MERGE_REQUEST_IID --format json > reviewers.json
artifacts:
paths:
- reviewers.json
only:
- merge_requestsGitHub Actions
- name: Suggest Reviewers
env:
GITLAB_TOKEN: ${{ secrets.GITLAB_TOKEN }}
run: |
npx gitlab-auto-reviewers cli \
--repo-path . \
--mr ${{ github.event.pull_request.number }} \
--format jsonOutput Formats
Text Format (Default):
Suggested Reviewers for MR !123
Contributors (based on file changes):
• alice (85 points) - Contributed 45% of changed lines
• bob (60 points) - Contributed 30% of changed lines
Code Owners:
• charlie - Owner of /backend/JSON Format:
{
"contributors": [
{
"email": "[email protected]",
"username": "alice",
"score": 85,
"reasons": ["Contributed 45% of changed lines"],
"isCodeowner": false,
"contributionCount": 12
}
],
"teamMembers": [...],
"codeOwners": [...],
"comment": "## Suggested Reviewers\n\n..."
}Complete Documentation
For detailed CLI documentation including:
- Complete command reference
- Development environment usage patterns
- CI/CD pipeline integration examples
- Troubleshooting guide
- Performance tips
- Security considerations
See docs/CLI.md
Library Usage
Use gitlab-auto-reviewers as a library in your Node.js or TypeScript application.
Installation
npm install gitlab-auto-reviewersBasic Usage
import {
ReviewerService,
GitLabAPIDataSource,
LocalGitDataSource
} from 'gitlab-auto-reviewers';
// Using GitLab API
const apiDataSource = new GitLabAPIDataSource(
'glpat-xxxxxxxxxxxx', // GitLab token
'https://gitlab.com' // GitLab URL
);
const service = new ReviewerService(apiDataSource);
const suggestions = await service.suggestReviewers({
project: 'my-group/my-project',
mergeRequestIid: 123
});
console.log(suggestions.contributors);
console.log(suggestions.teamMembers);
console.log(suggestions.codeOwners);
console.log(suggestions.comment);Using Local Git Repository
import { ReviewerService, LocalGitDataSource } from 'gitlab-auto-reviewers';
// Using local git repository (faster, works offline)
const localDataSource = new LocalGitDataSource(
'/path/to/repo', // Repository path
'glpat-xxxxxxxxxxxx', // GitLab token (for API fallback)
'https://gitlab.com' // GitLab URL (for API fallback)
);
const service = new ReviewerService(localDataSource);
const suggestions = await service.suggestReviewers({
project: 'my-group/my-project',
mergeRequestIid: 123
});Advanced Usage
Custom Configuration
import {
ReviewerService,
GitLabAPIDataSource,
ConfigService
} from 'gitlab-auto-reviewers';
// Custom configuration
const config = new ConfigService({
cacheEnabled: true,
cacheTTL: 600000, // 10 minutes
maxParallelRequests: 10,
contributorDays: 180,
maxRetries: 5,
logLevel: 'debug'
});
const dataSource = new GitLabAPIDataSource(
process.env.GITLAB_TOKEN!,
process.env.GITLAB_URL,
config
);
const service = new ReviewerService(dataSource, config);Error Handling
import {
ReviewerService,
GitLabAPIDataSource,
MCPError
} from 'gitlab-auto-reviewers';
try {
const suggestions = await service.suggestReviewers({
project: 'my-group/my-project',
mergeRequestIid: 123
});
} catch (error) {
if (error instanceof MCPError) {
console.error(`Error [${error.code}]: ${error.message}`);
console.error('Details:', error.details);
if (error.retryable) {
// Retry logic
console.log('Error is retryable, attempting retry...');
}
} else {
console.error('Unexpected error:', error);
}
}Filtering Reviewers
import {
ReviewerService,
GitLabAPIDataSource,
BlacklistService,
WhitelistService
} from 'gitlab-auto-reviewers';
const dataSource = new GitLabAPIDataSource(token, url);
const service = new ReviewerService(dataSource);
// Apply blacklist
const blacklist = new BlacklistService(dataSource);
await blacklist.load(project);
// Apply whitelist
const whitelist = new WhitelistService(dataSource);
await whitelist.load(project);
const suggestions = await service.suggestReviewers({
project: 'my-group/my-project',
mergeRequestIid: 123,
blacklist: blacklist.getBlacklist(),
whitelist: whitelist.getWhitelist()
});Posting Comments
import {
ReviewerService,
GitLabAPIDataSource,
CommentBuilderService
} from 'gitlab-auto-reviewers';
const dataSource = new GitLabAPIDataSource(token, url);
const service = new ReviewerService(dataSource);
const suggestions = await service.suggestReviewers({
project: 'my-group/my-project',
mergeRequestIid: 123
});
// Post comment to merge request
await dataSource.createNote(
'my-group/my-project',
123,
suggestions.comment
);TypeScript Types
import type {
ReviewerSuggestion,
ReviewerSuggestions,
MergeRequest,
User,
GitDataSource,
ConfigOptions
} from 'gitlab-auto-reviewers';
// ReviewerSuggestion
interface ReviewerSuggestion {
email: string;
username?: string;
score: number;
reasons: string[];
isCodeowner: boolean;
contributionCount?: number;
fte?: number;
openMRCount?: number;
}
// ReviewerSuggestions
interface ReviewerSuggestions {
contributors: ReviewerSuggestion[];
teamMembers: ReviewerSuggestion[];
codeOwners: ReviewerSuggestion[];
comment: string;
}Data Source Comparison
See Data Source Comparison section for detailed comparison of GitLabAPIDataSource vs LocalGitDataSource.
Data Source Comparison
The package supports two data source implementations with different trade-offs:
GitLabAPIDataSource
Use when:
- Running in a stateless environment (webhooks, serverless)
- No local repository available
- Need to analyze any project without cloning
- Running in CI/CD without repository checkout
Advantages:
- ✅ No local repository required
- ✅ Works from anywhere with network access
- ✅ Always up-to-date with GitLab
- ✅ Stateless operation (no disk usage)
- ✅ Can analyze any project with API access
Disadvantages:
- ❌ Slower (network latency)
- ❌ Subject to API rate limits
- ❌ Requires network connectivity
- ❌ May hit API limits for large merge requests
- ❌ Higher API usage costs
Configuration:
import { GitLabAPIDataSource } from 'gitlab-auto-reviewers';
const dataSource = new GitLabAPIDataSource(
'glpat-xxxxxxxxxxxx', // GitLab token
'https://gitlab.com' // GitLab URL
);Environment:
GITLAB_TOKEN=glpat-xxxxxxxxxxxx
GITLAB_URL=https://gitlab.comLocalGitDataSource
Use when:
- Running on developer machine with repository clone
- Running in CI/CD with repository checkout
- Need faster performance
- Want to work offline
- Analyzing large merge requests
Advantages:
- ✅ Much faster (no network latency)
- ✅ Works offline
- ✅ No API rate limits for git operations
- ✅ Can handle large merge requests
- ✅ Lower API usage
Disadvantages:
- ❌ Requires local repository clone
- ❌ Requires disk space
- ❌ Must keep repository up-to-date
- ❌ Falls back to API for some operations
- ❌ Requires git installed
Configuration:
import { LocalGitDataSource } from 'gitlab-auto-reviewers';
const dataSource = new LocalGitDataSource(
'/path/to/repo', // Repository path
'glpat-xxxxxxxxxxxx', // GitLab token (for API fallback)
'https://gitlab.com' // GitLab URL (for API fallback)
);Environment:
REPO_PATH=/path/to/repo
GITLAB_TOKEN=glpat-xxxxxxxxxxxx # For API fallback
GITLAB_URL=https://gitlab.comPerformance Comparison
| Operation | GitLabAPIDataSource | LocalGitDataSource | Speedup | |-----------|--------------------|--------------------|---------| | Get MR details | ~200ms | ~200ms | 1x (same) | | Get diffs | ~300ms | ~50ms | 6x faster | | Get blame (per file) | ~400ms | ~30ms | 13x faster | | Get file content | ~200ms | ~10ms | 20x faster | | Total (typical MR) | ~3-5s | ~500ms-1s | 3-5x faster |
Performance varies based on network latency, repository size, and number of changed files
Feature Comparison
| Feature | GitLabAPIDataSource | LocalGitDataSource | |---------|--------------------|--------------------| | Get merge request | ✅ API | ✅ API (fallback) | | Get diffs | ✅ API | ✅ Git command | | Get blame | ✅ API | ✅ Git command | | Get file content | ✅ API | ✅ Git command | | Get contributors | ✅ API | ✅ Git command | | Post comments | ✅ API | ✅ API (fallback) | | Get open MRs | ✅ API | ✅ API (fallback) | | Works offline | ❌ No | ✅ Yes (partial) | | Requires repository | ❌ No | ✅ Yes | | API rate limits | ⚠️ Subject to limits | ✅ Minimal API usage |
Choosing the Right Data Source
Use GitLabAPIDataSource for:
- Webhook servers (oce-gitlab-mr-bot)
- Serverless functions
- Cloud-based CI/CD without repository
- Multi-project analysis tools
- When disk space is limited
Use LocalGitDataSource for:
- MCP server on developer machine
- CLI usage in development
- CI/CD with repository checkout
- Large merge request analysis
- Offline development
Hybrid Approach:
LocalGitDataSource automatically falls back to API for operations that require it:
- Posting comments
- Getting open merge requests
- Getting project metadata
This provides the best of both worlds: fast local operations with API fallback when needed.
Example: Webhook Server
// oce-gitlab-mr-bot webhook service
import { ReviewerService, GitLabAPIDataSource } from 'gitlab-auto-reviewers';
@Injectable()
export class B2BMfeAutoReviewersService {
async processWebhook(event: MergeRequestEvent): Promise<void> {
// Use API data source (no local repository)
const dataSource = new GitLabAPIDataSource(
this.configService.get('GITLAB_TOKEN'),
this.configService.get('GITLAB_URL')
);
const service = new ReviewerService(dataSource);
const suggestions = await service.suggestReviewers({
project: event.project.id,
mergeRequestIid: event.object_attributes.iid
});
// Post comment to MR
await dataSource.createNote(
event.project.id,
event.object_attributes.iid,
suggestions.comment
);
}
}Example: CLI Tool
// CLI tool for local development
import { ReviewerService, LocalGitDataSource } from 'gitlab-auto-reviewers';
async function analyzeMR(mrIid: number): Promise<void> {
// Use local git data source (faster)
const dataSource = new LocalGitDataSource(
process.cwd(), // Current directory
process.env.GITLAB_TOKEN,
process.env.GITLAB_URL
);
const service = new ReviewerService(dataSource);
const suggestions = await service.suggestReviewers({
project: await dataSource.getProjectFromRemote(),
mergeRequestIid: mrIid
});
console.log(suggestions.comment);
}Webhook Integration
Integrate gitlab-auto-reviewers into your webhook server to automatically suggest reviewers when merge requests are created or updated.
NestJS Integration (oce-gitlab-mr-bot)
Step 1: Install Dependency
npm install gitlab-auto-reviewersStep 2: Create Webhook Module
// src/libs/b2b-mfe-auto-reviewers/b2b-mfe-auto-reviewers.module.ts
import { Module } from '@nestjs/common';
import { B2BMfeAutoReviewersController } from './b2b-mfe-auto-reviewers.controller';
import { B2BMfeAutoReviewersService } from './b2b-mfe-auto-reviewers.service';
@Module({
controllers: [B2BMfeAutoReviewersController],
providers: [B2BMfeAutoReviewersService],
})
export class B2BMfeAutoReviewersModule {}Step 3: Create Type Guards
// src/libs/b2b-mfe-auto-reviewers/b2b-mfe-auto-reviewers.type-guards.ts
import { z } from 'zod';
const MergeRequestEventSchema = z.object({
object_kind: z.literal('merge_request'),
event_type: z.literal('merge_request'),
project: z.object({
id: z.number(),
path_with_namespace: z.string(),
}),
object_attributes: z.object({
iid: z.number(),
title: z.string(),
source_branch: z.string(),
target_branch: z.string(),
action: z.enum(['open', 'update', 'reopen']),
}),
});
export type MergeRequestEvent = z.infer<typeof MergeRequestEventSchema>;
export function isMergeRequestEvent(data: unknown): data is MergeRequestEvent {
return MergeRequestEventSchema.safeParse(data).success;
}Step 4: Create Service
// src/libs/b2b-mfe-auto-reviewers/b2b-mfe-auto-reviewers.service.ts
import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import {
ReviewerService,
GitLabAPIDataSource,
MCPError
} from 'gitlab-auto-reviewers';
import { MergeRequestEvent } from './b2b-mfe-auto-reviewers.type-guards';
@Injectable()
export class B2BMfeAutoReviewersService {
private readonly logger = new Logger(B2BMfeAutoReviewersService.name);
constructor(private readonly configService: ConfigService) {}
async processWebhook(event: MergeRequestEvent): Promise<void> {
try {
this.logger.log(
`Processing MR webhook: ${event.project.path_with_namespace}!${event.object_attributes.iid}`
);
// Create data source
const dataSource = new GitLabAPIDataSource(
this.configService.get<string>('GITLAB_TOKEN')!,
this.configService.get<string>('GITLAB_URL', 'https://gitlab.com')
);
// Create reviewer service
const service = new ReviewerService(dataSource);
// Get reviewer suggestions
const suggestions = await service.suggestReviewers({
project: event.project.id,
mergeRequestIid: event.object_attributes.iid,
});
// Post comment to merge request
await dataSource.createNote(
event.project.id,
event.object_attributes.iid,
suggestions.comment
);
this.logger.log(
`Posted reviewer suggestions to MR !${event.object_attributes.iid}`
);
} catch (error) {
if (error instanceof MCPError) {
this.logger.error(
`Failed to process webhook [${error.code}]: ${error.message}`,
error.details
);
} else {
this.logger.error('Unexpected error processing webhook', error);
}
throw error;
}
}
}Step 5: Create Controller
// src/libs/b2b-mfe-auto-reviewers/b2b-mfe-auto-reviewers.controller.ts
import { Controller, Post, Body, HttpCode, Logger } from '@nestjs/common';
import { B2BMfeAutoReviewersService } from './b2b-mfe-auto-reviewers.service';
import { isMergeRequestEvent } from './b2b-mfe-auto-reviewers.type-guards';
@Controller('webhooks/b2b-mfe-auto-reviewers')
export class B2BMfeAutoReviewersController {
private readonly logger = new Logger(B2BMfeAutoReviewersController.name);
constructor(
private readonly service: B2BMfeAutoReviewersService
) {}
@Post()
@HttpCode(200)
async handleWebhook(@Body() body: unknown): Promise<{ success: boolean }> {
// Validate webhook event
if (!isMergeRequestEvent(body)) {
this.logger.warn('Invalid webhook event received');
return { success: false };
}
// Only process open/update/reopen actions
const action = body.object_attributes.action;
if (!['open', 'update', 'reopen'].includes(action)) {
this.logger.log(`Ignoring action: ${action}`);
return { success: true };
}
// Process webhook
await this.service.processWebhook(body);
return { success: true };
}
}Step 6: Register Module
// src/app.module.ts
import { Module } from '@nestjs/common';
import { B2BMfeAutoReviewersModule } from './libs/b2b-mfe-auto-reviewers/b2b-mfe-auto-reviewers.module';
@Module({
imports: [
// ... other modules
B2BMfeAutoReviewersModule,
],
})
export class AppModule {}Step 7: Configure Environment
# .env
GITLAB_TOKEN=glpat-xxxxxxxxxxxx
GITLAB_URL=https://gitlab.comStep 8: Configure GitLab Webhook
- Go to your GitLab project: Settings → Webhooks
- Add webhook URL:
https://your-server.com/webhooks/b2b-mfe-auto-reviewers - Select trigger: "Merge request events"
- Select actions: "Opened", "Updated", "Reopened"
- Save webhook
Express.js Integration
import express from 'express';
import {
ReviewerService,
GitLabAPIDataSource
} from 'gitlab-auto-reviewers';
const app = express();
app.use(express.json());
app.post('/webhooks/auto-reviewers', async (req, res) => {
try {
const event = req.body;
// Validate event
if (event.object_kind !== 'merge_request') {
return res.status(200).json({ success: false });
}
// Create data source
const dataSource = new GitLabAPIDataSource(
process.env.GITLAB_TOKEN!,
process.env.GITLAB_URL
);
// Create service
const service = new ReviewerService(dataSource);
// Get suggestions
const suggestions = await service.suggestReviewers({
project: event.project.id,
mergeRequestIid: event.object_attributes.iid,
});
// Post comment
await dataSource.createNote(
event.project.id,
event.object_attributes.iid,
suggestions.comment
);
res.status(200).json({ success: true });
} catch (error) {
console.error('Webhook error:', error);
res.status(500).json({ success: false, error: error.message });
}
});
app.listen(3000, () => {
console.log('Webhook server listening on port 3000');
});Webhook Configuration for New Repositories
To enable auto-reviewer suggestions for a new repository:
Install Package (if using webhook server):
npm install gitlab-auto-reviewersConfigure Environment Variables:
GITLAB_TOKEN=glpat-xxxxxxxxxxxx GITLAB_URL=https://gitlab.comCreate Configuration Files (in repository root):
CONTRIBUTORS (optional):
{ "contributors": [ { "username": "alice", "email": "[email protected]", "teams": [ { "name": "Backend", "fte": 1.0 }, { "name": "API", "fte": 0.5 } ] } ] }CODEOWNERS (optional):
# Backend team owns all backend code /backend/ @backend-team # API section requires 2 approvals [API][2] @api-lead /api/ @alice @bobConfigure GitLab Webhook:
- Go to: Project → Settings → Webhooks
- URL:
https://your-webhook-server.com/webhooks/auto-reviewers - Trigger: "Merge request events"
- Actions: "Opened", "Updated", "Reopened"
- Secret token: (optional, for security)
- SSL verification: Enabled (recommended)
Test Webhook:
- Create a test merge request
- Check webhook logs for successful delivery
- Verify comment appears on merge request
Monitor and Adjust:
- Monitor webhook logs for errors
- Adjust CONTRIBUTORS and CODEOWNERS as needed
- Update team FTE values based on workload
Webhook Security
Verify Webhook Signature (recommended):
import crypto from 'crypto';
function verifyWebhookSignature(
payload: string,
signature: string,
secret: string
): boolean {
const hmac = crypto.createHmac('sha256', secret);
const digest = hmac.update(payload).digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(digest)
);
}
app.post('/webhooks/auto-reviewers', (req, res) => {
const signature = req.headers['x-gitlab-token'];
const payload = JSON.stringify(req.body);
if (!verifyWebhookSignature(payload, signature, process.env.WEBHOOK_SECRET!)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process webhook...
});IP Whitelist (optional):
const GITLAB_IPS = [
'34.74.90.64/28',
'34.74.226.0/24',
// Add your GitLab instance IPs
];
function isGitLabIP(ip: string): boolean {
// Check if IP is in whitelist
return GITLAB_IPS.some(range => ipInRange(ip, range));
}MCP Integration
To use this MCP server with an AI assistant, add it to your MCP configuration:
{
"mcpServers": {
"gitlab-auto-reviewers": {
"command": "npx",
"args": ["-y", "gitlab-auto-reviewers", "mcp"],
"env": {
"GITLAB_TOKEN": "your_token_here",
"GITLAB_URL": "https://gitlab.com"
}
}
}
}For backward compatibility, the old command name is still supported:
{
"mcpServers": {
"auto-reviewers": {
"command": "npx",
"args": ["-y", "auto-reviewers-mcp-server"],
"env": {
"GITLAB_TOKEN": "your_token_here",
"GITLAB_URL": "https://gitlab.com"
}
}
}
}Team Configuration
Create a CONTRIBUTORS file in your repository root with team and FTE data:
{
"contributors": [
{
"username": "developer1",
"email": "[email protected]",
"teams": [
{ "name": "Backend", "fte": 1.0 },
{ "name": "API", "fte": 0.5 }
]
}
]
}Code Owners
Create a CODEOWNERS file in your repository root (or docs/CODEOWNERS or .gitlab/CODEOWNERS):
# Backend team owns all backend code
/backend/ @backend-team
# API section requires 2 approvals
[API][2] @api-lead
/api/ @developer1 @developer2Troubleshooting
For comprehensive troubleshooting information, see TROUBLESHOOTING.md.
Quick Diagnostics
Run these commands to quickly identify issues:
# 1. Check Node.js version (must be 18+)
node --version
# 2. Check if server starts
npm start 2>&1 | head -20
# 3. Check environment variables
env | grep -E 'GITLAB|CACHE|LOG|DEBUG|REPO'
# 4. Test GitLab API access
curl -H "PRIVATE-TOKEN: $GITLAB_TOKEN" $GITLAB_URL/api/v4/user
# 5. Check git repository (if using local mode)
git statusCommon Issues
Server Won't Start
# Check Node.js version (must be 18+)
node --version
# Verify environment variables
echo $GITLAB_TOKEN
cat .env
# Check for configuration errors
npm start 2>&1 | grep ERRORNo Reviewers Suggested
# Check git history
git log --follow path/to/file
# Verify configuration files
cat CONTRIBUTORS | jq .
cat CODEOWNERS
# Enable debug logging
DEBUG=true LOG_LEVEL=debug npm startPerformance Issues
# Enable caching
CACHE_ENABLED=true
CACHE_TTL=300000
# Use local git mode (faster)
REPO_PATH=/path/to/repo
# Monitor performance
DEBUG=true LOG_LEVEL=debug npm start 2>&1 | grep durationAuthentication Errors
# Test token
curl -H "PRIVATE-TOKEN: $GITLAB_TOKEN" $GITLAB_URL/api/v4/user
# Create new token with required scopes:
# - api OR read_api
# - read_repositoryDebug Mode
Enable detailed logging:
DEBUG=true LOG_LEVEL=debug npm startDebug logs include:
- Configuration loading and validation
- Cache hits and misses
- API request/response details
- Git command execution
- Performance timing for all operations
Getting Help
If you encounter issues:
Check Documentation:
- TROUBLESHOOTING.md - Comprehensive troubleshooting guide
- MIGRATION.md - Migration guide for v1.x to v2.0
- ARCHITECTURE.md - Architecture details
Enable Debug Mode:
DEBUG=true LOG_LEVEL=debug npm startReport Issues: Open an issue with:
- Error messages and stack traces
- Configuration (redact sensitive tokens)
- Steps to reproduce
- Server version and environment
- Debug logs
Development
Building from Source
# Clone repository
git clone ssh://git@code.[company-name].com:2222/frank.renfeng/state-of-merge-requests.git
cd state-of-merge-requests/gitlab-auto-reviewers
# Install dependencies
npm install
# Build
npm run build
# Run tests
npm test
# Run in development mode
npm run devProject Structure
mcp-server/
├── src/
│ ├── index.ts # Main entry point
│ ├── types.ts # TypeScript interfaces
│ ├── tools.ts # MCP tool definitions
│ ├── config/
│ │ └── config.service.ts # Configuration management
│ ├── logging/
│ │ └── logger.service.ts # Logging service
│ ├── errors/
│ │ └── error-handler.ts # Error handling
│ ├── cache/
│ │ └── cache.service.ts # Caching service
│ ├── datasources/
│ │ ├── git-data-source.interface.ts
│ │ ├── gitlab-api-data-source.ts
│ │ └── local-git-data-source.ts
│ └── services/
│ ├── reviewer-service.ts
│ ├── contributors.service.ts
│ ├── codeowners.service.ts
│ ├── team-members.service.ts
│ ├── blacklist.service.ts
│ ├── whitelist.service.ts
│ └── comment-builder.service.ts
├── dist/ # Compiled output
├── tests/ # Test files
└── package.jsonRunning Tests
# Run all tests
npm test
# Run tests in watch mode
npm run test:watch
# Run tests with coverage
npm run test:coverageCode Style
The project uses:
- TypeScript with strict mode enabled
- ESLint for linting
- Prettier for code formatting
# Lint code
npm run lint
# Format code
npm run format
# Type check
npm run type-checkContributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Add tests for new functionality
- Ensure all tests pass (
npm test) - Lint and format code (
npm run lint && npm run format) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Contribution Guidelines
- Write clear, descriptive commit messages
- Add JSDoc comments for all public APIs
- Include tests for new features
- Update documentation as needed
- Follow existing code style and patterns
Migration from v1.x
If you're upgrading from version 1.x to 2.0, see MIGRATION.md for detailed instructions.
Quick Migration Steps
Update Package:
npm install [email protected]Update Node.js (if needed):
node --version # Must be 18+Add New Configuration (optional):
# Add to .env CACHE_ENABLED=true CACHE_TTL=300000 MAX_PARALLEL_REQUESTS=5 LOG_LEVEL=infoTest Configuration:
npm start # Should see: [INFO] Configuration loaded successfullyUpdate Integration Code (if needed):
// Update imports for strict types import { MergeRequest, User, ReviewerSuggestion } from 'gitlab-auto-reviewers';
Breaking Changes
- Node.js 18+ required (was 16+)
- Configuration validation now fails fast on startup
- Error response format includes more structured information
- Log format changed to structured JSON
See MIGRATION.md for complete details and troubleshooting.
Known Limitations
Large Merge Request Handling
GitLab API Data Limitations
When using GitLabAPIDataSource (webhook mode or API-based analysis), very large merge requests may encounter GitLab API limitations:
Limitations:
- Diff Size Limits: GitLab API may truncate or limit diff data for merge requests with extensive changes
- File Count Limits: Merge requests with hundreds of changed files may return partial file lists
- API Rate Limits: High-frequency requests may be throttled by GitLab's rate limiting
- Timeout Constraints: Very large merge requests may exceed API timeout thresholds
Impact:
- Reviewer suggestions may be based on partial data
- Some changed files may not be analyzed
- Contributor analysis may be incomplete
- CODEOWNERS matching may miss some files
Mitigation Strategies:
Use LocalGitDataSource for Large MRs:
# CLI mode with local repository (no API limits) npx gitlab-auto-reviewers cli --repo /path/to/repo --mr 123Split Large Merge Requests:
- Break large changes into smaller, focused merge requests
- Each MR should ideally change fewer than 50-100 files
Monitor API Usage:
- Check GitLab API rate limit headers
- Implement request throttling if needed
- Use caching to reduce API calls
Expect Partial Results:
- The system will continue to function with limited data
- Reviewer suggestions will be based on available information
- No errors will be thrown for partial data
When to Use Each Data Source:
| Scenario | Recommended Data Source | Reason | |----------|------------------------|--------| | Large MR (100+ files) | LocalGitDataSource | No API limits, complete data | | Webhook integration | GitLabAPIDataSource | Stateless, no repo clone needed | | CI/CD pipeline | LocalGitDataSource | Repo already cloned, faster | | Development | LocalGitDataSource | Faster, works offline | | Small MR (< 50 files) | Either | Both work well |
Documentation References:
- Requirements 12.4: System allows limited data for large MRs
- Requirements 12.5: Clear messaging about limitations
- Design Document: Performance Considerations section
For more details, see TROUBLESHOOTING.md.
Documentation
- README.md - This file, general documentation
- MIGRATION.md - Migration guide from v1.x to v2.0
- TROUBLESHOOTING.md - Comprehensive troubleshooting guide
- ARCHITECTURE.md - Architecture and design documentation
License
MIT
Support
For issues, questions, or contributions, please visit:
- Issues: GitHub Issues
- Repository: GitHub Repository
- Documentation: Full Documentation
Changelog
v2.0.0 (2024-12-04)
Major Release - Performance & Reliability Improvements
New Features:
- In-memory caching with configurable TTL
- Automatic retry logic with exponential backoff
- Parallel data fetching for improved performance
- Structured logging with multiple log levels
- Configuration validation on startup
- Performance metrics tracking
- Enhanced error messages with context
Breaking Changes:
- Node.js 18+ required (was 16+)
- Configuration validation now fails fast
- Error response format changed
- Log format changed to structured JSON
Improvements:
- Full TypeScript strict mode (zero
anytypes) - Comprehensive type definitions
- Better error handling and recovery
- Improved observability and debugging
- Enhanced documentation
See MIGRATION.md for upgrade instructions.
Documentation
Comprehensive documentation is available in the ../docs/ directory:
For Users
- Usage Examples - Practical examples and common use cases
- CLI Guide - Complete command-line interface documentation
- Troubleshooting - Common issues and solutions
- Migration Guide - Upgrading from v1.x to v2.0
- API Limitations - Known limitations and workarounds
- Large MR Handling - Best practices for large merge requests
For Developers
- Architecture - System architecture and design
- Refactoring Summary - Package refactoring details
- Implementation Progress - Development progress tracking
For Testers
- Cross-Implementation Test Summary - Comprehensive test results validating Requirements 12.1-12.9
- Testing Infrastructure - Testing setup and methodology
- Test Repository Setup - How to set up test environments
For Maintainers
- Publishing Guide - How to publish packages to npm
- Backward Compatibility - Compatibility guarantees
- Roadmap - Project roadmap and future plans
Documentation Index
See docs/README.md for the complete documentation index and organization.
