Cross Platform implementation of the GitLab API
npx @tessl/cli install tessl/npm-gitbeaker--rest@43.8.0A comprehensive, typed GitLab API client that works universally across browsers, Node.js, and Deno platforms, offering complete coverage of GitLab's REST API with over 195 resource endpoints. The library features extensive TypeScript declarations for type safety, flexible authentication options, advanced pagination support, customizable rate limiting, and comprehensive error handling.
npm install @gitbeaker/rest// Primary client class
import { Gitlab } from '@gitbeaker/rest';
// Individual resource classes (for tree-shaking)
import {
Projects,
Issues,
MergeRequests,
Users,
Groups,
Pipelines,
Jobs,
Branches,
Commits,
RepositoryFiles
} from '@gitbeaker/rest';
// Access level constants
import { AccessLevel } from '@gitbeaker/rest';
// Error types for error handling
import {
GitbeakerRequestError,
GitbeakerTimeoutError,
GitbeakerRetryError
} from '@gitbeaker/rest';import { Gitlab } from '@gitbeaker/rest';
// Standard initialization with personal access token
const api = new Gitlab({
host: 'https://gitlab.com', // Can be self-hosted URL
token: process.env.GITLAB_TOKEN // Personal access token
});
// Self-hosted GitLab instance
const selfHostedApi = new Gitlab({
host: 'https://gitlab.mycompany.com',
token: process.env.GITLAB_TOKEN
});
// CI/CD job context (using job token)
const ciApi = new Gitlab({
host: process.env.CI_SERVER_URL,
jobToken: process.env.CI_JOB_TOKEN
});
// OAuth token authentication
const oauthApi = new Gitlab({
host: 'https://gitlab.com',
oauthToken: process.env.OAUTH_TOKEN
});
// Dynamic token retrieval (async function)
const dynamicApi = new Gitlab({
host: 'https://gitlab.com',
token: async () => await getTokenFromVault()
});// Get all user's projects
const myProjects = await api.Projects.all({ membership: true });
// Get specific project details
const project = await api.Projects.show(projectId);
// List open issues in a project
const issues = await api.Issues.all({
projectId,
state: 'opened'
});
// Create a new issue
const newIssue = await api.Issues.create(
projectId,
'Bug: Login not working',
{
description: 'Users cannot log in with SSO',
labels: 'bug,priority::high',
assigneeIds: [userId]
}
);
// List open merge requests
const mrs = await api.MergeRequests.all({
projectId,
state: 'opened'
});
// Create a merge request
const mr = await api.MergeRequests.create(
projectId,
'feature-branch',
'main',
'Add user authentication',
{
description: 'Implements JWT-based authentication',
assigneeIds: [userId],
removeSourceBranch: true
}
);
// Get file content
const fileContent = await api.RepositoryFiles.showRaw(
projectId,
'src/config.json',
'main'
);
// Create a commit with multiple file operations
await api.Commits.create(
projectId,
'main',
'Update configuration',
[
{
action: 'update',
filePath: 'config/settings.json',
content: JSON.stringify({ key: 'value' })
},
{
action: 'create',
filePath: 'src/new-file.ts',
content: 'export const foo = "bar";'
}
]
);
// List pipeline jobs
const jobs = await api.Jobs.all(projectId, {
pipelineId,
scope: 'failed'
});
// Retry a failed job
await api.Jobs.retry(projectId, jobId);import { Gitlab } from '@gitbeaker/rest';For CommonJS:
const { Gitlab } = require('@gitbeaker/rest');Import specific resources:
import {
Projects,
Issues,
MergeRequests,
Users,
Groups,
AccessLevel
} from '@gitbeaker/rest';Import error types:
import {
GitbeakerRequestError,
GitbeakerTimeoutError,
GitbeakerRetryError
} from '@gitbeaker/rest';The @gitbeaker/rest package is built around several key components:
Initialize and configure the GitLab API client with authentication, host settings, rate limiting, and advanced options.
class Gitlab<C extends boolean = false> {
constructor(options: GitlabOptions<C>);
}
type GitlabOptions<C extends boolean = false> = {
// Host configuration
host?: string; // Default: 'https://gitlab.com'
prefixUrl?: string;
// Authentication (one required)
token?: string | (() => Promise<string>);
oauthToken?: string | (() => Promise<string>);
jobToken?: string | (() => Promise<string>);
// Behavior configuration
camelize?: C;
queryTimeout?: number | null; // Default: 300000 (5 minutes)
sudo?: string | number;
// Rate limiting
rateLimits?: RateLimitOptions;
rateLimitDuration?: number; // Default: 60 seconds
// Advanced options
profileToken?: string;
profileMode?: 'execution' | 'memory';
agent?: Agent; // Node.js HTTP agent
};Comprehensive project management including CRUD operations, repository management, settings, members, and webhooks. The Projects resource is the foundation for most GitLab operations.
class Projects<C extends boolean = false> {
all<E extends boolean = false, P extends PaginationTypes = 'keyset'>(
options?: AllProjectsOptions & PaginationRequestOptions<P> & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<ProjectSchema[], C, E, P>>;
show<E extends boolean = false>(
projectId: string | number,
options?: ShowProjectOptions & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<ProjectSchema, C, E, void>>;
create<E extends boolean = false>(
options: CreateProjectOptions & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<ProjectSchema, C, E, void>>;
edit<E extends boolean = false>(
projectId: string | number,
options?: EditProjectOptions & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<ProjectSchema, C, E, void>>;
remove<E extends boolean = false>(
projectId: string | number,
options?: Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<void, C, E, void>>;
fork<E extends boolean = false>(
projectId: string | number,
options?: ForkProjectOptions & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<ProjectSchema, C, E, void>>;
share<E extends boolean = false>(
projectId: string | number,
groupId: number,
groupAccess: number,
options?: ShareProjectOptions & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<void, C, E, void>>;
star<E extends boolean = false>(
projectId: string | number,
options?: Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<ProjectSchema, C, E, void>>;
unstar<E extends boolean = false>(
projectId: string | number,
options?: Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<ProjectSchema, C, E, void>>;
archive<E extends boolean = false>(
projectId: string | number,
options?: Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<ProjectSchema, C, E, void>>;
unarchive<E extends boolean = false>(
projectId: string | number,
options?: Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<ProjectSchema, C, E, void>>;
}Group management including creation, member management, subgroups, epics (Premium/Ultimate), and group-level settings.
class Groups<C extends boolean = false> {
all<E extends boolean = false, P extends PaginationTypes = 'keyset'>(
options?: AllGroupsOptions & PaginationRequestOptions<P> & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<GroupSchema[], C, E, P>>;
show<E extends boolean = false>(
groupId: string | number,
options?: ShowGroupOptions & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<GroupSchema, C, E, void>>;
create<E extends boolean = false>(
name: string,
path: string,
options?: CreateGroupOptions & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<GroupSchema, C, E, void>>;
edit<E extends boolean = false>(
groupId: string | number,
options?: EditGroupOptions & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<GroupSchema, C, E, void>>;
remove<E extends boolean = false>(
groupId: string | number,
options?: Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<void, C, E, void>>;
}Issue tracking including creation, editing, comments, labels, milestones, time tracking, and relationships.
class Issues<C extends boolean = false> {
all<E extends boolean = false, P extends PaginationTypes = 'offset'>(
options?: AllIssuesOptions & PaginationRequestOptions<P> & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<IssueSchema[], C, E, P>>;
show<E extends boolean = false>(
projectId: string | number,
issueIid: number,
options?: Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<IssueSchema, C, E, void>>;
create<E extends boolean = false>(
projectId: string | number,
title: string,
options?: CreateIssueOptions & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<IssueSchema, C, E, void>>;
edit<E extends boolean = false>(
projectId: string | number,
issueIid: number,
options?: EditIssueOptions & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<IssueSchema, C, E, void>>;
remove<E extends boolean = false>(
projectId: string | number,
issueIid: number,
options?: Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<void, C, E, void>>;
addSpentTime<E extends boolean = false>(
projectId: string | number,
issueIid: number,
duration: string,
options?: { summary?: string } & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<TimeStatsSchema, C, E, void>>;
addTimeEstimate<E extends boolean = false>(
projectId: string | number,
issueIid: number,
duration: string,
options?: Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<TimeStatsSchema, C, E, void>>;
}Merge request management including creation, approval, merging, discussions, and pipeline integration.
class MergeRequests<C extends boolean = false> {
all<E extends boolean = false, P extends PaginationTypes = 'offset'>(
options?: AllMergeRequestsOptions & PaginationRequestOptions<P> & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<MergeRequestSchema[], C, E, P>>;
show<E extends boolean = false>(
projectId: string | number,
mergerequestIid: number,
options?: ShowMergeRequestOptions & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<MergeRequestSchema, C, E, void>>;
create<E extends boolean = false>(
projectId: string | number,
sourceBranch: string,
targetBranch: string,
title: string,
options?: CreateMergeRequestOptions & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<MergeRequestSchema, C, E, void>>;
edit<E extends boolean = false>(
projectId: string | number,
mergerequestIid: number,
options?: EditMergeRequestOptions & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<MergeRequestSchema, C, E, void>>;
merge<E extends boolean = false>(
projectId: string | number,
mergerequestIid: number,
options?: MergeMergeRequestOptions & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<MergeRequestSchema, C, E, void>>;
}Comprehensive CI/CD operations including pipelines, jobs, runners, variables, schedules, and artifacts management.
class Pipelines<C extends boolean = false> {
all<E extends boolean = false>(
projectId: string | number,
options?: AllPipelinesOptions & PaginationRequestOptions<'offset'> & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<PipelineSchema[], C, E, 'offset'>>;
show<E extends boolean = false>(
projectId: string | number,
pipelineId: number,
options?: Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<PipelineSchema, C, E, void>>;
create<E extends boolean = false>(
projectId: string | number,
ref: string,
options?: CreatePipelineOptions & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<PipelineSchema, C, E, void>>;
retry<E extends boolean = false>(
projectId: string | number,
pipelineId: number,
options?: Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<PipelineSchema, C, E, void>>;
cancel<E extends boolean = false>(
projectId: string | number,
pipelineId: number,
options?: Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<PipelineSchema, C, E, void>>;
}
class Jobs<C extends boolean = false> {
all<E extends boolean = false, P extends PaginationTypes = 'offset'>(
projectId: string | number,
options?: AllJobsOptions & PaginationRequestOptions<P> & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<JobSchema[], C, E, P>>;
show<E extends boolean = false>(
projectId: string | number,
jobId: number,
options?: Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<JobSchema, C, E, void>>;
showLog<E extends boolean = false>(
projectId: string | number,
jobId: number,
options?: Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<string, C, E, void>>;
retry<E extends boolean = false>(
projectId: string | number,
jobId: number,
options?: Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<JobSchema, C, E, void>>;
cancel<E extends boolean = false>(
projectId: string | number,
jobId: number,
options?: Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<JobSchema, C, E, void>>;
play<E extends boolean = false>(
projectId: string | number,
jobId: number,
options?: PlayJobOptions & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<JobSchema, C, E, void>>;
erase<E extends boolean = false>(
projectId: string | number,
jobId: number,
options?: Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<JobSchema, C, E, void>>;
}Repository operations including branches, tags, commits, files, and merge operations.
class Branches<C extends boolean = false> {
all<E extends boolean = false, P extends PaginationTypes = 'offset'>(
projectId: string | number,
options?: AllBranchesOptions & PaginationRequestOptions<P> & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<BranchSchema[], C, E, P>>;
show<E extends boolean = false>(
projectId: string | number,
branchName: string,
options?: Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<BranchSchema, C, E, void>>;
create<E extends boolean = false>(
projectId: string | number,
branchName: string,
ref: string,
options?: Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<BranchSchema, C, E, void>>;
remove<E extends boolean = false>(
projectId: string | number,
branchName: string,
options?: Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<void, C, E, void>>;
}
class Commits<C extends boolean = false> {
all<E extends boolean = false, P extends PaginationTypes = 'offset'>(
projectId: string | number,
options?: AllCommitsOptions & PaginationRequestOptions<P> & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<CommitSchema[], C, E, P>>;
show<E extends boolean = false>(
projectId: string | number,
sha: string,
options?: ShowCommitOptions & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<CommitSchema, C, E, void>>;
create<E extends boolean = false>(
projectId: string | number,
branch: string,
commitMessage: string,
actions: CommitAction[],
options?: CreateCommitOptions & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<CommitSchema, C, E, void>>;
}
class RepositoryFiles<C extends boolean = false> {
show<E extends boolean = false>(
projectId: string | number,
filePath: string,
ref: string,
options?: Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<RepositoryFileSchema, C, E, void>>;
showRaw<E extends boolean = false>(
projectId: string | number,
filePath: string,
ref: string,
options?: Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<string, C, E, void>>;
create<E extends boolean = false>(
projectId: string | number,
filePath: string,
branch: string,
content: string,
commitMessage: string,
options?: CreateRepositoryFileOptions & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<RepositoryFileSchema, C, E, void>>;
edit<E extends boolean = false>(
projectId: string | number,
filePath: string,
branch: string,
content: string,
commitMessage: string,
options?: EditRepositoryFileOptions & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<RepositoryFileSchema, C, E, void>>;
remove<E extends boolean = false>(
projectId: string | number,
filePath: string,
branch: string,
commitMessage: string,
options?: RemoveRepositoryFileOptions & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<void, C, E, void>>;
}User management including profile operations, SSH keys, GPG keys, emails, and impersonation tokens.
class Users<C extends boolean = false> {
all<E extends boolean = false, P extends PaginationTypes = 'offset'>(
options?: AllUsersOptions & PaginationRequestOptions<P> & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<UserSchema[], C, E, P>>;
show<E extends boolean = false>(
userId: string | number,
options?: Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<UserSchema, C, E, void>>;
showCurrentUser<E extends boolean = false>(
options?: Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<UserSchema, C, E, void>>;
create<E extends boolean = false>(
options: CreateUserOptions & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<UserSchema, C, E, void>>;
edit<E extends boolean = false>(
userId: number,
options?: EditUserOptions & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<UserSchema, C, E, void>>;
block<E extends boolean = false>(
userId: number,
options?: Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<boolean, C, E, void>>;
unblock<E extends boolean = false>(
userId: number,
options?: Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<boolean, C, E, void>>;
}Support for multiple package registry types including npm, Maven, PyPI, NuGet, Composer, Conan, Helm, Go, RubyGems, and Debian.
class NPM<C extends boolean = false> {
uploadPackageFile<E extends boolean = false>(
projectId: string | number,
packageName: string,
packageVersion: string,
fileName: string,
file: Blob | Buffer,
options?: Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<void, C, E, void>>;
downloadPackageFile<E extends boolean = false>(
projectId: string | number,
packageName: string,
packageVersion: string,
fileName: string,
options?: Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<Blob | Buffer, C, E, void>>;
}
class Maven<C extends boolean = false> {
uploadPackageFile<E extends boolean = false>(
projectId: string | number,
path: string,
file: Blob | Buffer,
options?: Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<void, C, E, void>>;
downloadPackageFile<E extends boolean = false>(
projectId: string | number,
path: string,
options?: Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<Blob | Buffer, C, E, void>>;
}
class Packages<C extends boolean = false> {
all<E extends boolean = false, P extends PaginationTypes = 'offset'>(
projectId: string | number,
options?: AllPackagesOptions & PaginationRequestOptions<P> & Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<PackageSchema[], C, E, P>>;
show<E extends boolean = false>(
projectId: string | number,
packageId: number,
options?: Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<PackageSchema, C, E, void>>;
remove<E extends boolean = false>(
projectId: string | number,
packageId: number,
options?: Sudo & ShowExpanded<E>
): Promise<GitlabAPIResponse<void, C, E, void>>;
}Extensive additional resources covering webhooks, wikis, snippets, labels, milestones, releases, deployments, environments, security, analytics, and administrative operations.
Note on Resource Naming: Many resources have both project-scoped and group-scoped variants with prefixed names:
ProjectLabels, GroupLabelsProjectMilestones, GroupMilestonesProjectWikis, GroupWikisProjectReleases, GroupReleasesIssueNotes, MergeRequestNotes, EpicNotes, ProjectSnippetNotesProjectMembers, GroupMembersProjectHooks, GroupHooksExample usage:
const api = new Gitlab({ token: 'your-token' });
// Project-specific resources
const projectLabels = await api.ProjectLabels.all(projectId);
const projectMilestones = await api.ProjectMilestones.all(projectId);
// Group-specific resources
const groupLabels = await api.GroupLabels.all(groupId);
const groupMilestones = await api.GroupMilestones.all(groupId);Most operations require a projectId. This can be:
// Numeric project ID
const projectId = 12345;
// URL-encoded project path
const projectId = 'mygroup%2Fmyproject';
// Helper for encoding project path
function encodeProjectPath(path: string): string {
return encodeURIComponent(path);
}
const projectId = encodeProjectPath('mygroup/myproject');// Create issue with all common fields
const issue = await api.Issues.create(projectId, 'Bug: Login failure', {
description: '## Problem\n\nUsers cannot log in via SSO\n\n## Steps to Reproduce\n1. Click login\n2. Select SSO',
labels: 'bug,priority::high,backend',
assigneeIds: [456, 789],
milestoneId: 10,
dueDate: '2024-12-31',
weight: 3,
confidential: false
});
// Add time tracking immediately
await api.Issues.addTimeEstimate(projectId, issue.iid, '3h');// 1. Create MR
const mr = await api.MergeRequests.create(
projectId,
'feature/new-auth',
'main',
'Add OAuth authentication',
{
description: '## Changes\n\n- Add OAuth provider\n- Update login flow',
assigneeIds: [userId],
reviewerIds: [reviewerId1, reviewerId2],
labels: 'feature,backend',
removeSourceBranch: true,
squash: true
}
);
// 2. Check pipeline status
const pipelines = await api.MergeRequests.allPipelines(projectId, mr.iid);
const latestPipeline = pipelines[0];
if (latestPipeline.status === 'success') {
// 3. Merge if pipeline passes
await api.MergeRequests.merge(projectId, mr.iid, {
shouldRemoveSourceBranch: true,
squash: true,
mergeCommitMessage: 'feat: add OAuth authentication'
});
}// Update multiple files in a single commit
await api.Commits.create(
projectId,
'main',
'Refactor authentication system',
[
// Update existing file
{
action: 'update',
filePath: 'src/auth/index.ts',
content: newAuthCode
},
// Create new file
{
action: 'create',
filePath: 'src/auth/oauth.ts',
content: oauthCode
},
// Delete old file
{
action: 'delete',
filePath: 'src/auth/legacy.ts'
},
// Move file
{
action: 'move',
filePath: 'src/auth/providers/google.ts',
previousPath: 'src/auth/google.ts'
},
// Change file permissions
{
action: 'chmod',
filePath: 'scripts/deploy.sh',
executeFilemode: true
}
],
{
authorEmail: 'bot@example.com',
authorName: 'Deploy Bot'
}
);// Keyset pagination (recommended for large datasets)
let allProjects: ProjectSchema[] = [];
const options = {
membership: true,
perPage: 100,
pagination: 'keyset' as const
};
const firstPage = await api.Projects.all(options);
allProjects.push(...firstPage.data);
// Handle subsequent pages
while (firstPage.paginationInfo.idAfter) {
const nextPage = await api.Projects.all({
...options,
idAfter: firstPage.paginationInfo.idAfter
});
allProjects.push(...nextPage.data);
if (!nextPage.paginationInfo.idAfter) break;
}
// Offset pagination (simpler but less efficient)
const allIssues: IssueSchema[] = [];
for (let page = 1; page <= 10; page++) {
const issues = await api.Issues.all({
projectId,
state: 'opened',
page,
perPage: 100
});
if (issues.length === 0) break;
allIssues.push(...issues);
}
// Using maxPages for automatic pagination
const issues = await api.Issues.all({
projectId,
state: 'opened',
perPage: 100,
maxPages: 5 // Fetch up to 5 pages automatically
});// Trigger pipeline with variables
const pipeline = await api.Pipelines.create(projectId, 'main', {
variables: [
{ key: 'DEPLOY_ENV', value: 'production' },
{ key: 'SKIP_TESTS', value: 'false' }
]
});
// Monitor pipeline progress
const checkPipelineStatus = async () => {
const p = await api.Pipelines.show(projectId, pipeline.id);
console.log(`Pipeline ${p.id}: ${p.status}`);
if (p.status === 'running' || p.status === 'pending') {
// Get job statuses
const jobs = await api.Jobs.all(projectId, { pipelineId: p.id });
jobs.forEach(job => {
console.log(` Job ${job.name}: ${job.status}`);
});
}
return p.status;
};
// Poll until complete
let status = await checkPipelineStatus();
while (status === 'running' || status === 'pending') {
await new Promise(resolve => setTimeout(resolve, 30000)); // Wait 30s
status = await checkPipelineStatus();
}
// Handle failed jobs
if (status === 'failed') {
const jobs = await api.Jobs.all(projectId, {
pipelineId: pipeline.id,
scope: 'failed'
});
for (const job of jobs) {
// Get job logs
const logs = await api.Jobs.showLog(projectId, job.id);
console.error(`Job ${job.name} failed:\n${logs}`);
// Retry if retriable
if (job.retryable) {
await api.Jobs.retry(projectId, job.id);
}
}
}enum AccessLevel {
NO_ACCESS = 0,
MINIMAL_ACCESS = 5,
GUEST = 10,
REPORTER = 20,
DEVELOPER = 30,
MAINTAINER = 40,
OWNER = 50,
ADMIN = 60
}class GitbeakerRequestError extends Error {
constructor(
message: string,
options?: {
cause: {
description: string;
request: Request;
response: Response;
};
}
);
}
class GitbeakerTimeoutError extends Error {}
class GitbeakerRetryError extends Error {}type PaginationTypes = 'offset' | 'keyset';
interface PaginationRequestOptions<P extends PaginationTypes | void = void> {
pagination?: P;
perPage?: number | string;
maxPages?: number;
orderBy?: string;
sort?: 'asc' | 'desc';
page?: number | string; // For offset pagination
idAfter?: number; // For keyset pagination
}
interface OffsetPagination {
total: number;
next: number | null;
current: number;
previous: number | null;
perPage: number;
totalPages: number;
}
interface KeysetPagination {
idAfter: number;
perPage: number;
orderBy: string;
sort: 'asc' | 'desc';
}interface ExpandedResponse<T> {
data: T;
headers: Record<string, string>;
status: number;
}
type PaginatedResponse<T, P extends PaginationTypes> = {
paginationInfo: P extends 'keyset' ? KeysetPagination : OffsetPagination;
data: T;
};
type GitlabAPIResponse<
T,
C extends boolean,
E extends boolean,
P extends PaginationTypes | void
> =
E extends true
? P extends PaginationTypes
? ExpandedResponse<T> & PaginatedResponse<T, P>
: ExpandedResponse<T>
: P extends PaginationTypes
? PaginatedResponse<T, P>
: C extends true
? Camelize<T>
: T;interface Sudo {
sudo?: string | number;
}
interface ShowExpanded<E extends boolean = false> {
showExpanded?: E;
}
interface AsStream {
asStream?: boolean;
}import { GitbeakerRequestError, GitbeakerTimeoutError, GitbeakerRetryError } from '@gitbeaker/rest';
try {
const issue = await api.Issues.create(projectId, 'Title', options);
} catch (error) {
if (error instanceof GitbeakerRequestError) {
// HTTP error with request/response context
console.error('Request failed:', error.message);
console.error('Status:', error.cause.response.status);
console.error('Description:', error.cause.description);
// Handle specific status codes
if (error.cause.response.status === 404) {
console.error('Resource not found');
} else if (error.cause.response.status === 401) {
console.error('Authentication failed - check token');
} else if (error.cause.response.status === 403) {
console.error('Insufficient permissions');
} else if (error.cause.response.status === 422) {
console.error('Validation error - check parameters');
} else if (error.cause.response.status === 429) {
console.error('Rate limit exceeded');
}
} else if (error instanceof GitbeakerTimeoutError) {
console.error('Request timed out');
} else if (error instanceof GitbeakerRetryError) {
console.error('Request failed after retries');
}
}404 Not Found: Project, issue, or resource doesn't exist
401 Unauthorized: Authentication failed
403 Forbidden: Insufficient permissions
422 Unprocessable Entity: Validation errors
429 Too Many Requests: Rate limit exceeded
// Configure custom rate limits
const api = new Gitlab({
token: process.env.GITLAB_TOKEN,
rateLimits: {
'**': 1000, // 1000 requests per minute for all endpoints
'projects/*/issues': 300, // 300 for issue operations
'projects/*/merge_requests': {
method: 'post',
limit: 100 // 100 POST requests for MRs
}
},
rateLimitDuration: 60 // Check rate limit every 60 seconds
});
// Handle rate limit errors
try {
await api.Issues.create(projectId, 'Title', options);
} catch (error) {
if (error instanceof GitbeakerRequestError && error.cause.response.status === 429) {
const retryAfter = error.cause.response.headers.get('Retry-After');
console.log(`Rate limited. Retry after ${retryAfter} seconds`);
// Wait and retry
await new Promise(resolve => setTimeout(resolve, parseInt(retryAfter) * 1000));
return api.Issues.create(projectId, 'Title', options);
}
}// Test token validity
try {
const currentUser = await api.Users.showCurrentUser();
console.log('Authenticated as:', currentUser.username);
console.log('Token scopes:', currentUser.scopes);
} catch (error) {
console.error('Authentication failed:', error);
}// Verify project exists and you have access
try {
const project = await api.Projects.show(projectId);
console.log('Project found:', project.name);
} catch (error) {
if (error instanceof GitbeakerRequestError && error.cause.response.status === 404) {
console.error('Project not found or no access');
// Try listing projects to see what you have access to
const projects = await api.Projects.all({ membership: true });
console.log('Available projects:', projects.map(p => `${p.id}: ${p.name}`));
}
}// Enable expanded responses to see full HTTP details
const issue = await api.Issues.create(projectId, 'Title', {
description: 'Test',
showExpanded: true
});
console.log('Response status:', issue.status);
console.log('Response headers:', issue.headers);
console.log('Response data:', issue.data);// For self-signed certificates (development only)
import https from 'https';
const api = new Gitlab({
host: 'https://gitlab.mycompany.com',
token: process.env.GITLAB_TOKEN,
agent: new https.Agent({
rejectUnauthorized: false // ONLY for development/testing
})
});