@apiclient.xyz/gitlab 2.4.0 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/dist_ts/00_commitinfo_data.js +1 -1
  2. package/dist_ts/gitlab.classes.branch.d.ts +7 -0
  3. package/dist_ts/gitlab.classes.branch.js +13 -0
  4. package/dist_ts/gitlab.classes.gitlabclient.d.ts +117 -32
  5. package/dist_ts/gitlab.classes.gitlabclient.js +278 -96
  6. package/dist_ts/gitlab.classes.group.d.ts +47 -0
  7. package/dist_ts/gitlab.classes.group.js +97 -0
  8. package/dist_ts/gitlab.classes.job.d.ts +29 -0
  9. package/dist_ts/gitlab.classes.job.js +74 -0
  10. package/dist_ts/gitlab.classes.pipeline.d.ts +32 -0
  11. package/dist_ts/gitlab.classes.pipeline.js +87 -0
  12. package/dist_ts/gitlab.classes.project.d.ts +63 -0
  13. package/dist_ts/gitlab.classes.project.js +122 -0
  14. package/dist_ts/gitlab.classes.protectedbranch.d.ts +8 -0
  15. package/dist_ts/gitlab.classes.protectedbranch.js +15 -0
  16. package/dist_ts/gitlab.classes.tag.d.ts +7 -0
  17. package/dist_ts/gitlab.classes.tag.js +13 -0
  18. package/dist_ts/gitlab.classes.testreport.d.ts +34 -0
  19. package/dist_ts/gitlab.classes.testreport.js +67 -0
  20. package/dist_ts/gitlab.classes.variable.d.ts +18 -0
  21. package/dist_ts/gitlab.classes.variable.js +35 -0
  22. package/dist_ts/gitlab.helpers.d.ts +8 -0
  23. package/dist_ts/gitlab.helpers.js +23 -0
  24. package/dist_ts/gitlab.interfaces.d.ts +114 -9
  25. package/dist_ts/gitlab.interfaces.js +4 -1
  26. package/dist_ts/index.d.ts +11 -1
  27. package/dist_ts/index.js +15 -1
  28. package/package.json +1 -1
  29. package/readme.md +468 -163
  30. package/ts/00_commitinfo_data.ts +1 -1
  31. package/ts/gitlab.classes.branch.ts +18 -0
  32. package/ts/gitlab.classes.gitlabclient.ts +354 -114
  33. package/ts/gitlab.classes.group.ts +137 -0
  34. package/ts/gitlab.classes.job.ts +104 -0
  35. package/ts/gitlab.classes.pipeline.ts +122 -0
  36. package/ts/gitlab.classes.project.ts +177 -0
  37. package/ts/gitlab.classes.protectedbranch.ts +21 -0
  38. package/ts/gitlab.classes.tag.ts +18 -0
  39. package/ts/gitlab.classes.testreport.ts +97 -0
  40. package/ts/gitlab.classes.variable.ts +50 -0
  41. package/ts/gitlab.helpers.ts +26 -0
  42. package/ts/gitlab.interfaces.ts +162 -11
  43. package/ts/index.ts +25 -0
@@ -1,5 +1,4 @@
1
1
  import * as plugins from './gitlab.plugins.js';
2
- import { logger } from './gitlab.logging.js';
3
2
  import type {
4
3
  IGitLabUser,
5
4
  IGitLabProject,
@@ -10,26 +9,34 @@ import type {
10
9
  IGitLabBranch,
11
10
  IGitLabTag,
12
11
  IGitLabPipeline,
12
+ IGitLabPipelineVariable,
13
+ IGitLabTestReport,
13
14
  IGitLabJob,
14
15
  ITestConnectionResult,
15
16
  IListOptions,
17
+ IPipelineListOptions,
18
+ IJobListOptions,
16
19
  } from './gitlab.interfaces.js';
20
+ import { GitLabGroup } from './gitlab.classes.group.js';
21
+ import { GitLabProject } from './gitlab.classes.project.js';
22
+ import { GitLabPipeline } from './gitlab.classes.pipeline.js';
23
+ import { autoPaginate } from './gitlab.helpers.js';
17
24
 
18
25
  export class GitLabClient {
19
26
  private baseUrl: string;
20
27
  private token: string;
21
28
 
22
29
  constructor(baseUrl: string, token: string) {
23
- // Remove trailing slash if present
24
30
  this.baseUrl = baseUrl.replace(/\/+$/, '');
25
31
  this.token = token;
26
32
  }
27
33
 
28
- // ---------------------------------------------------------------------------
29
- // HTTP helpers
30
- // ---------------------------------------------------------------------------
34
+ // ===========================================================================
35
+ // HTTP helpers (internal)
36
+ // ===========================================================================
31
37
 
32
- private async request<T = any>(
38
+ /** @internal */
39
+ async request<T = any>(
33
40
  method: 'GET' | 'POST' | 'PUT' | 'DELETE',
34
41
  path: string,
35
42
  data?: any,
@@ -80,7 +87,8 @@ export class GitLabClient {
80
87
  }
81
88
  }
82
89
 
83
- private async requestText(
90
+ /** @internal */
91
+ async requestText(
84
92
  method: 'GET' | 'POST' | 'PUT' | 'DELETE',
85
93
  path: string,
86
94
  ): Promise<string> {
@@ -115,9 +123,45 @@ export class GitLabClient {
115
123
  return response.text();
116
124
  }
117
125
 
118
- // ---------------------------------------------------------------------------
119
- // Connection
120
- // ---------------------------------------------------------------------------
126
+ /** @internal — multipart form upload (for avatars) */
127
+ async requestMultipart<T = any>(
128
+ method: 'PUT' | 'POST',
129
+ path: string,
130
+ formData: FormData,
131
+ ): Promise<T> {
132
+ const url = `${this.baseUrl}${path}`;
133
+ const response = await fetch(url, {
134
+ method,
135
+ headers: { 'PRIVATE-TOKEN': this.token },
136
+ body: formData,
137
+ });
138
+ if (!response.ok) {
139
+ const errorText = await response.text();
140
+ throw new Error(`${method} ${path}: ${response.status} ${response.statusText} - ${errorText}`);
141
+ }
142
+ try {
143
+ return await response.json() as T;
144
+ } catch {
145
+ return undefined as unknown as T;
146
+ }
147
+ }
148
+
149
+ /** @internal — fetch binary data (e.g. avatar images) */
150
+ async requestBinary(url: string): Promise<Uint8Array> {
151
+ const fullUrl = url.startsWith('http') ? url : `${this.baseUrl}${url}`;
152
+ const response = await fetch(fullUrl, {
153
+ headers: { 'PRIVATE-TOKEN': this.token },
154
+ });
155
+ if (!response.ok) {
156
+ throw new Error(`GET ${url}: ${response.status} ${response.statusText}`);
157
+ }
158
+ const buf = await response.arrayBuffer();
159
+ return new Uint8Array(buf);
160
+ }
161
+
162
+ // ===========================================================================
163
+ // Public API — Connection
164
+ // ===========================================================================
121
165
 
122
166
  public async testConnection(): Promise<ITestConnectionResult> {
123
167
  try {
@@ -128,24 +172,95 @@ export class GitLabClient {
128
172
  }
129
173
  }
130
174
 
131
- // ---------------------------------------------------------------------------
132
- // Groupsscoped queries
133
- // ---------------------------------------------------------------------------
175
+ // ===========================================================================
176
+ // Public API Groups (returns rich objects)
177
+ // ===========================================================================
134
178
 
135
179
  /**
136
- * Get a single group by its full path (e.g. "foss.global" or "foss.global/push.rocks")
180
+ * Get all groups (auto-paginated).
137
181
  */
138
- public async getGroupByPath(fullPath: string): Promise<IGitLabGroup> {
139
- return this.request<IGitLabGroup>(
140
- 'GET',
141
- `/api/v4/groups/${encodeURIComponent(fullPath)}`,
142
- );
182
+ public async getGroups(opts?: IListOptions): Promise<GitLabGroup[]> {
183
+ return autoPaginate(
184
+ (page, perPage) => this.requestGetGroups({ ...opts, page, perPage }),
185
+ opts,
186
+ ).then(groups => groups.map(g => new GitLabGroup(this, g)));
143
187
  }
144
188
 
145
189
  /**
146
- * List projects within a group (includes subgroups when include_subgroups=true)
190
+ * Get a single group by full path.
147
191
  */
148
- public async getGroupProjects(groupId: number | string, opts?: IListOptions): Promise<IGitLabProject[]> {
192
+ public async getGroup(fullPath: string): Promise<GitLabGroup> {
193
+ const raw = await this.requestGetGroupByPath(fullPath);
194
+ return new GitLabGroup(this, raw);
195
+ }
196
+
197
+ /**
198
+ * Create a new group.
199
+ */
200
+ public async createGroup(name: string, path: string, parentId?: number): Promise<GitLabGroup> {
201
+ const raw = await this.requestCreateGroup(name, path, parentId);
202
+ return new GitLabGroup(this, raw);
203
+ }
204
+
205
+ // ===========================================================================
206
+ // Public API — Projects (returns rich objects)
207
+ // ===========================================================================
208
+
209
+ /**
210
+ * Get all projects (auto-paginated, membership=true).
211
+ */
212
+ public async getProjects(opts?: IListOptions): Promise<GitLabProject[]> {
213
+ return autoPaginate(
214
+ (page, perPage) => this.requestGetProjects({ ...opts, page, perPage }),
215
+ opts,
216
+ ).then(projects => projects.map(p => new GitLabProject(this, p)));
217
+ }
218
+
219
+ /**
220
+ * Get a single project by ID or path.
221
+ */
222
+ public async getProject(idOrPath: number | string): Promise<GitLabProject> {
223
+ const raw = await this.requestGetProject(idOrPath);
224
+ return new GitLabProject(this, raw);
225
+ }
226
+
227
+ /**
228
+ * Create a new project.
229
+ */
230
+ public async createProject(name: string, opts?: {
231
+ path?: string;
232
+ namespaceId?: number;
233
+ visibility?: string;
234
+ description?: string;
235
+ }): Promise<GitLabProject> {
236
+ const raw = await this.requestCreateProject(name, opts);
237
+ return new GitLabProject(this, raw);
238
+ }
239
+
240
+ // ===========================================================================
241
+ // Internal request methods — called by domain classes
242
+ // ===========================================================================
243
+
244
+ // --- Groups ---
245
+
246
+ /** @internal */
247
+ async requestGetGroups(opts?: IListOptions): Promise<IGitLabGroup[]> {
248
+ const page = opts?.page || 1;
249
+ const perPage = opts?.perPage || 50;
250
+ let url = `/api/v4/groups?order_by=name&sort=asc&page=${page}&per_page=${perPage}`;
251
+ if (opts?.search) {
252
+ url += `&search=${encodeURIComponent(opts.search)}`;
253
+ }
254
+ return this.request<IGitLabGroup[]>('GET', url);
255
+ }
256
+
257
+ /** @internal */
258
+ async requestGetGroupByPath(fullPath: string): Promise<IGitLabGroup> {
259
+ return this.request<IGitLabGroup>('GET', `/api/v4/groups/${encodeURIComponent(fullPath)}`);
260
+ }
261
+
262
+ /** @internal */
263
+ async requestGetGroupProjects(groupId: number | string, opts?: IListOptions): Promise<IGitLabProject[]> {
149
264
  const page = opts?.page || 1;
150
265
  const perPage = opts?.perPage || 50;
151
266
  let url = `/api/v4/groups/${encodeURIComponent(groupId)}/projects?include_subgroups=true&order_by=updated_at&sort=desc&page=${page}&per_page=${perPage}`;
@@ -155,10 +270,8 @@ export class GitLabClient {
155
270
  return this.request<IGitLabProject[]>('GET', url);
156
271
  }
157
272
 
158
- /**
159
- * List all descendant groups (recursive subgroups) within a group
160
- */
161
- public async getDescendantGroups(groupId: number | string, opts?: IListOptions): Promise<IGitLabGroup[]> {
273
+ /** @internal */
274
+ async requestGetDescendantGroups(groupId: number | string, opts?: IListOptions): Promise<IGitLabGroup[]> {
162
275
  const page = opts?.page || 1;
163
276
  const perPage = opts?.perPage || 50;
164
277
  let url = `/api/v4/groups/${encodeURIComponent(groupId)}/descendant_groups?order_by=name&sort=asc&page=${page}&per_page=${perPage}`;
@@ -168,19 +281,58 @@ export class GitLabClient {
168
281
  return this.request<IGitLabGroup[]>('GET', url);
169
282
  }
170
283
 
171
- /**
172
- * Create a new group. Optionally nested under a parent group.
173
- */
174
- public async createGroup(name: string, path: string, parentId?: number): Promise<IGitLabGroup> {
284
+ /** @internal */
285
+ async requestCreateGroup(name: string, path: string, parentId?: number): Promise<IGitLabGroup> {
175
286
  const body: any = { name, path, visibility: 'private' };
176
287
  if (parentId) body.parent_id = parentId;
177
288
  return this.request<IGitLabGroup>('POST', '/api/v4/groups', body);
178
289
  }
179
290
 
180
- /**
181
- * Create a new project (repository).
182
- */
183
- public async createProject(name: string, opts?: {
291
+ /** @internal */
292
+ async requestUpdateGroup(groupId: number | string, data: Record<string, any>): Promise<void> {
293
+ await this.request('PUT', `/api/v4/groups/${encodeURIComponent(groupId)}`, data);
294
+ }
295
+
296
+ /** @internal */
297
+ async requestSetGroupAvatar(groupId: number | string, imageData: Uint8Array, filename: string): Promise<void> {
298
+ const blob = new Blob([imageData.buffer as ArrayBuffer]);
299
+ const formData = new FormData();
300
+ formData.append('avatar', blob, filename);
301
+ await this.requestMultipart('PUT', `/api/v4/groups/${encodeURIComponent(groupId)}`, formData);
302
+ }
303
+
304
+ /** @internal */
305
+ async requestTransferGroup(groupId: number | string, parentGroupId: number): Promise<void> {
306
+ await this.request('POST', `/api/v4/groups/${encodeURIComponent(groupId)}/transfer`, {
307
+ group_id: parentGroupId,
308
+ });
309
+ }
310
+
311
+ /** @internal */
312
+ async requestDeleteGroup(groupId: number | string): Promise<void> {
313
+ await this.request('DELETE', `/api/v4/groups/${encodeURIComponent(groupId)}`);
314
+ }
315
+
316
+ // --- Projects ---
317
+
318
+ /** @internal */
319
+ async requestGetProjects(opts?: IListOptions): Promise<IGitLabProject[]> {
320
+ const page = opts?.page || 1;
321
+ const perPage = opts?.perPage || 50;
322
+ let url = `/api/v4/projects?membership=true&order_by=updated_at&sort=desc&page=${page}&per_page=${perPage}`;
323
+ if (opts?.search) {
324
+ url += `&search=${encodeURIComponent(opts.search)}`;
325
+ }
326
+ return this.request<IGitLabProject[]>('GET', url);
327
+ }
328
+
329
+ /** @internal */
330
+ async requestGetProject(idOrPath: number | string): Promise<IGitLabProject> {
331
+ return this.request<IGitLabProject>('GET', `/api/v4/projects/${encodeURIComponent(idOrPath)}`);
332
+ }
333
+
334
+ /** @internal */
335
+ async requestCreateProject(name: string, opts?: {
184
336
  path?: string;
185
337
  namespaceId?: number;
186
338
  visibility?: string;
@@ -195,46 +347,83 @@ export class GitLabClient {
195
347
  });
196
348
  }
197
349
 
198
- // ---------------------------------------------------------------------------
199
- // Projects
200
- // ---------------------------------------------------------------------------
350
+ /** @internal */
351
+ async requestUpdateProject(projectId: number | string, data: Record<string, any>): Promise<void> {
352
+ await this.request('PUT', `/api/v4/projects/${encodeURIComponent(projectId)}`, data);
353
+ }
354
+
355
+ /** @internal */
356
+ async requestSetProjectAvatar(projectId: number | string, imageData: Uint8Array, filename: string): Promise<void> {
357
+ const blob = new Blob([imageData.buffer as ArrayBuffer]);
358
+ const formData = new FormData();
359
+ formData.append('avatar', blob, filename);
360
+ await this.requestMultipart('PUT', `/api/v4/projects/${encodeURIComponent(projectId)}`, formData);
361
+ }
362
+
363
+ /** @internal */
364
+ async requestTransferProject(projectId: number | string, namespaceId: number): Promise<void> {
365
+ await this.request('PUT', `/api/v4/projects/${encodeURIComponent(projectId)}/transfer`, {
366
+ namespace: namespaceId,
367
+ });
368
+ }
201
369
 
202
- public async getProjects(opts?: IListOptions): Promise<IGitLabProject[]> {
370
+ /** @internal */
371
+ async requestDeleteProject(projectId: number | string): Promise<void> {
372
+ await this.request('DELETE', `/api/v4/projects/${encodeURIComponent(projectId)}`);
373
+ }
374
+
375
+ // --- Repo Branches & Tags ---
376
+
377
+ /** @internal */
378
+ async requestGetRepoBranches(projectId: number | string, opts?: IListOptions): Promise<IGitLabBranch[]> {
203
379
  const page = opts?.page || 1;
204
380
  const perPage = opts?.perPage || 50;
205
- let url = `/api/v4/projects?membership=true&order_by=updated_at&sort=desc&page=${page}&per_page=${perPage}`;
206
- if (opts?.search) {
207
- url += `&search=${encodeURIComponent(opts.search)}`;
208
- }
209
- return this.request<IGitLabProject[]>('GET', url);
381
+ return this.request<IGitLabBranch[]>(
382
+ 'GET',
383
+ `/api/v4/projects/${encodeURIComponent(projectId)}/repository/branches?page=${page}&per_page=${perPage}`,
384
+ );
210
385
  }
211
386
 
212
- // ---------------------------------------------------------------------------
213
- // Groups
214
- // ---------------------------------------------------------------------------
215
-
216
- public async getGroups(opts?: IListOptions): Promise<IGitLabGroup[]> {
387
+ /** @internal */
388
+ async requestGetRepoTags(projectId: number | string, opts?: IListOptions): Promise<IGitLabTag[]> {
217
389
  const page = opts?.page || 1;
218
390
  const perPage = opts?.perPage || 50;
219
- let url = `/api/v4/groups?order_by=name&sort=asc&page=${page}&per_page=${perPage}`;
220
- if (opts?.search) {
221
- url += `&search=${encodeURIComponent(opts.search)}`;
222
- }
223
- return this.request<IGitLabGroup[]>('GET', url);
391
+ return this.request<IGitLabTag[]>(
392
+ 'GET',
393
+ `/api/v4/projects/${encodeURIComponent(projectId)}/repository/tags?page=${page}&per_page=${perPage}`,
394
+ );
224
395
  }
225
396
 
226
- // ---------------------------------------------------------------------------
227
- // Project Variables (CI/CD)
228
- // ---------------------------------------------------------------------------
397
+ // --- Protected Branches ---
229
398
 
230
- public async getProjectVariables(projectId: number | string): Promise<IGitLabVariable[]> {
399
+ /** @internal */
400
+ async requestGetProtectedBranches(projectId: number | string): Promise<IGitLabProtectedBranch[]> {
401
+ return this.request<IGitLabProtectedBranch[]>(
402
+ 'GET',
403
+ `/api/v4/projects/${encodeURIComponent(projectId)}/protected_branches`,
404
+ );
405
+ }
406
+
407
+ /** @internal */
408
+ async requestUnprotectBranch(projectId: number | string, branchName: string): Promise<void> {
409
+ await this.request(
410
+ 'DELETE',
411
+ `/api/v4/projects/${encodeURIComponent(projectId)}/protected_branches/${encodeURIComponent(branchName)}`,
412
+ );
413
+ }
414
+
415
+ // --- Project Variables ---
416
+
417
+ /** @internal */
418
+ async requestGetProjectVariables(projectId: number | string): Promise<IGitLabVariable[]> {
231
419
  return this.request<IGitLabVariable[]>(
232
420
  'GET',
233
421
  `/api/v4/projects/${encodeURIComponent(projectId)}/variables`,
234
422
  );
235
423
  }
236
424
 
237
- public async createProjectVariable(
425
+ /** @internal */
426
+ async requestCreateProjectVariable(
238
427
  projectId: number | string,
239
428
  key: string,
240
429
  value: string,
@@ -253,7 +442,8 @@ export class GitLabClient {
253
442
  );
254
443
  }
255
444
 
256
- public async updateProjectVariable(
445
+ /** @internal */
446
+ async requestUpdateProjectVariable(
257
447
  projectId: number | string,
258
448
  key: string,
259
449
  value: string,
@@ -270,25 +460,26 @@ export class GitLabClient {
270
460
  );
271
461
  }
272
462
 
273
- public async deleteProjectVariable(projectId: number | string, key: string): Promise<void> {
463
+ /** @internal */
464
+ async requestDeleteProjectVariable(projectId: number | string, key: string): Promise<void> {
274
465
  await this.request(
275
466
  'DELETE',
276
467
  `/api/v4/projects/${encodeURIComponent(projectId)}/variables/${encodeURIComponent(key)}`,
277
468
  );
278
469
  }
279
470
 
280
- // ---------------------------------------------------------------------------
281
- // Group Variables (CI/CD)
282
- // ---------------------------------------------------------------------------
471
+ // --- Group Variables ---
283
472
 
284
- public async getGroupVariables(groupId: number | string): Promise<IGitLabVariable[]> {
473
+ /** @internal */
474
+ async requestGetGroupVariables(groupId: number | string): Promise<IGitLabVariable[]> {
285
475
  return this.request<IGitLabVariable[]>(
286
476
  'GET',
287
477
  `/api/v4/groups/${encodeURIComponent(groupId)}/variables`,
288
478
  );
289
479
  }
290
480
 
291
- public async createGroupVariable(
481
+ /** @internal */
482
+ async requestCreateGroupVariable(
292
483
  groupId: number | string,
293
484
  key: string,
294
485
  value: string,
@@ -307,7 +498,8 @@ export class GitLabClient {
307
498
  );
308
499
  }
309
500
 
310
- public async updateGroupVariable(
501
+ /** @internal */
502
+ async requestUpdateGroupVariable(
311
503
  groupId: number | string,
312
504
  key: string,
313
505
  value: string,
@@ -324,102 +516,150 @@ export class GitLabClient {
324
516
  );
325
517
  }
326
518
 
327
- public async deleteGroupVariable(groupId: number | string, key: string): Promise<void> {
519
+ /** @internal */
520
+ async requestDeleteGroupVariable(groupId: number | string, key: string): Promise<void> {
328
521
  await this.request(
329
522
  'DELETE',
330
523
  `/api/v4/groups/${encodeURIComponent(groupId)}/variables/${encodeURIComponent(key)}`,
331
524
  );
332
525
  }
333
526
 
334
- // ---------------------------------------------------------------------------
335
- // Pipelines
336
- // ---------------------------------------------------------------------------
527
+ // --- Pipelines ---
337
528
 
338
- public async getPipelines(projectId: number | string, opts?: IListOptions): Promise<IGitLabPipeline[]> {
529
+ /** @internal */
530
+ async requestGetPipelines(projectId: number | string, opts?: IPipelineListOptions): Promise<IGitLabPipeline[]> {
339
531
  const page = opts?.page || 1;
340
532
  const perPage = opts?.perPage || 30;
341
- return this.request<IGitLabPipeline[]>(
342
- 'GET',
343
- `/api/v4/projects/${encodeURIComponent(projectId)}/pipelines?page=${page}&per_page=${perPage}&order_by=updated_at&sort=desc`,
344
- );
533
+ const orderBy = opts?.orderBy || 'updated_at';
534
+ const sort = opts?.sort || 'desc';
535
+ let url = `/api/v4/projects/${encodeURIComponent(projectId)}/pipelines?page=${page}&per_page=${perPage}&order_by=${orderBy}&sort=${sort}`;
536
+ if (opts?.status) url += `&status=${encodeURIComponent(opts.status)}`;
537
+ if (opts?.ref) url += `&ref=${encodeURIComponent(opts.ref)}`;
538
+ if (opts?.source) url += `&source=${encodeURIComponent(opts.source)}`;
539
+ if (opts?.scope) url += `&scope=${encodeURIComponent(opts.scope)}`;
540
+ if (opts?.username) url += `&username=${encodeURIComponent(opts.username)}`;
541
+ if (opts?.updatedAfter) url += `&updated_after=${encodeURIComponent(opts.updatedAfter)}`;
542
+ if (opts?.updatedBefore) url += `&updated_before=${encodeURIComponent(opts.updatedBefore)}`;
543
+ return this.request<IGitLabPipeline[]>('GET', url);
345
544
  }
346
545
 
347
- public async getPipelineJobs(projectId: number | string, pipelineId: number): Promise<IGitLabJob[]> {
348
- return this.request<IGitLabJob[]>(
546
+ /** @internal */
547
+ async requestGetPipeline(projectId: number | string, pipelineId: number): Promise<IGitLabPipeline> {
548
+ return this.request<IGitLabPipeline>(
349
549
  'GET',
350
- `/api/v4/projects/${encodeURIComponent(projectId)}/pipelines/${pipelineId}/jobs`,
550
+ `/api/v4/projects/${encodeURIComponent(projectId)}/pipelines/${pipelineId}`,
351
551
  );
352
552
  }
353
553
 
354
- public async getJobLog(projectId: number | string, jobId: number): Promise<string> {
355
- return this.requestText(
356
- 'GET',
357
- `/api/v4/projects/${encodeURIComponent(projectId)}/jobs/${jobId}/trace`,
554
+ /** @internal */
555
+ async requestTriggerPipeline(
556
+ projectId: number | string,
557
+ ref: string,
558
+ variables?: { key: string; value: string; variable_type?: string }[],
559
+ ): Promise<IGitLabPipeline> {
560
+ const body: any = { ref };
561
+ if (variables && variables.length > 0) {
562
+ body.variables = variables;
563
+ }
564
+ return this.request<IGitLabPipeline>(
565
+ 'POST',
566
+ `/api/v4/projects/${encodeURIComponent(projectId)}/pipeline`,
567
+ body,
358
568
  );
359
569
  }
360
570
 
361
- public async retryPipeline(projectId: number | string, pipelineId: number): Promise<void> {
362
- await this.request(
571
+ /** @internal */
572
+ async requestRetryPipeline(projectId: number | string, pipelineId: number): Promise<IGitLabPipeline> {
573
+ return this.request<IGitLabPipeline>(
363
574
  'POST',
364
575
  `/api/v4/projects/${encodeURIComponent(projectId)}/pipelines/${pipelineId}/retry`,
365
576
  );
366
577
  }
367
578
 
368
- public async cancelPipeline(projectId: number | string, pipelineId: number): Promise<void> {
369
- await this.request(
579
+ /** @internal */
580
+ async requestCancelPipeline(projectId: number | string, pipelineId: number): Promise<IGitLabPipeline> {
581
+ return this.request<IGitLabPipeline>(
370
582
  'POST',
371
583
  `/api/v4/projects/${encodeURIComponent(projectId)}/pipelines/${pipelineId}/cancel`,
372
584
  );
373
585
  }
374
586
 
375
- // ---------------------------------------------------------------------------
376
- // Repository Branches & Tags
377
- // ---------------------------------------------------------------------------
587
+ /** @internal */
588
+ async requestDeletePipeline(projectId: number | string, pipelineId: number): Promise<void> {
589
+ await this.request(
590
+ 'DELETE',
591
+ `/api/v4/projects/${encodeURIComponent(projectId)}/pipelines/${pipelineId}`,
592
+ );
593
+ }
378
594
 
379
- public async getRepoBranches(projectId: number | string, opts?: IListOptions): Promise<IGitLabBranch[]> {
380
- const page = opts?.page || 1;
381
- const perPage = opts?.perPage || 50;
382
- return this.request<IGitLabBranch[]>(
595
+ /** @internal */
596
+ async requestGetPipelineVariables(projectId: number | string, pipelineId: number): Promise<IGitLabPipelineVariable[]> {
597
+ return this.request<IGitLabPipelineVariable[]>(
383
598
  'GET',
384
- `/api/v4/projects/${encodeURIComponent(projectId)}/repository/branches?page=${page}&per_page=${perPage}`,
599
+ `/api/v4/projects/${encodeURIComponent(projectId)}/pipelines/${pipelineId}/variables`,
385
600
  );
386
601
  }
387
602
 
388
- public async getRepoTags(projectId: number | string, opts?: IListOptions): Promise<IGitLabTag[]> {
389
- const page = opts?.page || 1;
390
- const perPage = opts?.perPage || 50;
391
- return this.request<IGitLabTag[]>(
603
+ /** @internal */
604
+ async requestGetPipelineTestReport(projectId: number | string, pipelineId: number): Promise<IGitLabTestReport> {
605
+ return this.request<IGitLabTestReport>(
392
606
  'GET',
393
- `/api/v4/projects/${encodeURIComponent(projectId)}/repository/tags?page=${page}&per_page=${perPage}`,
607
+ `/api/v4/projects/${encodeURIComponent(projectId)}/pipelines/${pipelineId}/test_report`,
394
608
  );
395
609
  }
396
610
 
397
- // ---------------------------------------------------------------------------
398
- // Protected Branches
399
- // ---------------------------------------------------------------------------
611
+ // --- Jobs ---
400
612
 
401
- public async getProtectedBranches(projectId: number | string): Promise<IGitLabProtectedBranch[]> {
402
- return this.request<IGitLabProtectedBranch[]>(
613
+ /** @internal */
614
+ async requestGetPipelineJobs(projectId: number | string, pipelineId: number, opts?: IJobListOptions): Promise<IGitLabJob[]> {
615
+ const page = opts?.page || 1;
616
+ const perPage = opts?.perPage || 100;
617
+ let url = `/api/v4/projects/${encodeURIComponent(projectId)}/pipelines/${pipelineId}/jobs?page=${page}&per_page=${perPage}`;
618
+ if (opts?.scope && opts.scope.length > 0) {
619
+ for (const s of opts.scope) {
620
+ url += `&scope[]=${encodeURIComponent(s)}`;
621
+ }
622
+ }
623
+ return this.request<IGitLabJob[]>('GET', url);
624
+ }
625
+
626
+ /** @internal */
627
+ async requestGetJobLog(projectId: number | string, jobId: number): Promise<string> {
628
+ return this.requestText(
403
629
  'GET',
404
- `/api/v4/projects/${encodeURIComponent(projectId)}/protected_branches`,
630
+ `/api/v4/projects/${encodeURIComponent(projectId)}/jobs/${jobId}/trace`,
405
631
  );
406
632
  }
407
633
 
408
- public async unprotectBranch(projectId: number | string, branchName: string): Promise<void> {
409
- await this.request(
410
- 'DELETE',
411
- `/api/v4/projects/${encodeURIComponent(projectId)}/protected_branches/${encodeURIComponent(branchName)}`,
634
+ /** @internal */
635
+ async requestRetryJob(projectId: number | string, jobId: number): Promise<IGitLabJob> {
636
+ return this.request<IGitLabJob>(
637
+ 'POST',
638
+ `/api/v4/projects/${encodeURIComponent(projectId)}/jobs/${jobId}/retry`,
639
+ );
640
+ }
641
+
642
+ /** @internal */
643
+ async requestCancelJob(projectId: number | string, jobId: number): Promise<IGitLabJob> {
644
+ return this.request<IGitLabJob>(
645
+ 'POST',
646
+ `/api/v4/projects/${encodeURIComponent(projectId)}/jobs/${jobId}/cancel`,
412
647
  );
413
648
  }
414
649
 
415
- // ---------------------------------------------------------------------------
416
- // Project Deletion
417
- // ---------------------------------------------------------------------------
650
+ /** @internal */
651
+ async requestPlayJob(projectId: number | string, jobId: number): Promise<IGitLabJob> {
652
+ return this.request<IGitLabJob>(
653
+ 'POST',
654
+ `/api/v4/projects/${encodeURIComponent(projectId)}/jobs/${jobId}/play`,
655
+ );
656
+ }
418
657
 
419
- public async deleteProject(projectId: number | string): Promise<void> {
658
+ /** @internal */
659
+ async requestEraseJob(projectId: number | string, jobId: number): Promise<void> {
420
660
  await this.request(
421
- 'DELETE',
422
- `/api/v4/projects/${encodeURIComponent(projectId)}`,
661
+ 'POST',
662
+ `/api/v4/projects/${encodeURIComponent(projectId)}/jobs/${jobId}/erase`,
423
663
  );
424
664
  }
425
665
  }