@remogram/provider-gitlab-api 0.1.0-beta.3 → 0.1.0-beta.4
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.
- package/index.js +167 -26
- package/package.json +2 -2
package/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
fetchJson,
|
|
3
|
+
fetchJsonWithMeta,
|
|
3
4
|
sanitizeField,
|
|
4
5
|
sanitizeUrl,
|
|
5
6
|
assertGitRef,
|
|
@@ -9,19 +10,33 @@ import {
|
|
|
9
10
|
gitAheadBehind,
|
|
10
11
|
refsInventory,
|
|
11
12
|
crInventory,
|
|
12
|
-
|
|
13
|
+
buildMergePlanBodyFromFacts,
|
|
13
14
|
ERROR_CODES,
|
|
14
15
|
forgeError,
|
|
15
16
|
forgeIngestCapabilityFacts,
|
|
16
17
|
checkPaginationCapabilityFacts,
|
|
18
|
+
openPullListCapabilityFacts,
|
|
17
19
|
DEFAULT_CHECK_STATUS_PAGE_SIZE,
|
|
18
20
|
MAX_CHECK_STATUS_PAGES,
|
|
21
|
+
DEFAULT_OPEN_PULL_LIST_PAGE_SIZE,
|
|
19
22
|
paginateCheckStatusPages,
|
|
20
23
|
paginateOffsetListPages,
|
|
21
24
|
fetchWithIngestPageBackoff,
|
|
22
25
|
fetchPageWithIngestBackoff,
|
|
23
26
|
withPerPageParam,
|
|
24
27
|
apiProviderCommands,
|
|
28
|
+
normalizeCrInventorySort,
|
|
29
|
+
DEFAULT_CR_INVENTORY_SLICE_SORT,
|
|
30
|
+
parseTotalCountHeader,
|
|
31
|
+
isCrInventoryFastPathEligible,
|
|
32
|
+
validateFastPathPageLength,
|
|
33
|
+
isNumberSortFastPathEligible,
|
|
34
|
+
isNumberSortFullCollectRequired,
|
|
35
|
+
resolveListTruncatedWithTrustedTotal,
|
|
36
|
+
orderOpenPullNumbers,
|
|
37
|
+
buildOpenPullListMeta,
|
|
38
|
+
gitlabOpenPullSortQuery,
|
|
39
|
+
appendSortQuery,
|
|
25
40
|
} from '@remogram/core';
|
|
26
41
|
|
|
27
42
|
const PUBLIC_GITLAB_HOST = 'gitlab.com';
|
|
@@ -129,6 +144,16 @@ export async function gitlabFetch(config, parsed, path, options = {}) {
|
|
|
129
144
|
});
|
|
130
145
|
}
|
|
131
146
|
|
|
147
|
+
export async function gitlabFetchWithMeta(config, parsed, path, options = {}) {
|
|
148
|
+
const base = apiBase(config, parsed);
|
|
149
|
+
const token = requireToken();
|
|
150
|
+
const url = `${base}${path}`;
|
|
151
|
+
return fetchJsonWithMeta(url, {
|
|
152
|
+
...options,
|
|
153
|
+
headers: { ...authHeaders(token), ...(options.headers || {}) },
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
132
157
|
const MAX_CHECK_PAGES = MAX_CHECK_STATUS_PAGES;
|
|
133
158
|
const GITLAB_PAGE_SIZE = 100;
|
|
134
159
|
|
|
@@ -162,6 +187,10 @@ export function providerCapabilities() {
|
|
|
162
187
|
pageSizeParam: 'per_page',
|
|
163
188
|
sourceCount: check_sources.length,
|
|
164
189
|
}),
|
|
190
|
+
...openPullListCapabilityFacts({
|
|
191
|
+
totalCountSource: 'response_header',
|
|
192
|
+
totalCountHeader: 'X-Total',
|
|
193
|
+
}),
|
|
165
194
|
};
|
|
166
195
|
}
|
|
167
196
|
|
|
@@ -314,45 +343,157 @@ export async function prChecks(ctx, opts) {
|
|
|
314
343
|
export async function mergePlan(ctx, opts) {
|
|
315
344
|
const view = await prView(ctx, opts);
|
|
316
345
|
const checks = await prChecks(ctx, { number: view.pr_number });
|
|
317
|
-
|
|
346
|
+
return buildMergePlanBodyFromFacts(ctx, view, checks, opts);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const GITLAB_OPEN_PULL_COMPLIANT_MAX =
|
|
350
|
+
DEFAULT_OPEN_PULL_LIST_PAGE_SIZE * MAX_CHECK_STATUS_PAGES;
|
|
351
|
+
|
|
352
|
+
async function probeGitlabOpenPullPageOne(ctx, retainMax, sliceSort) {
|
|
353
|
+
const maxTrusted = GITLAB_OPEN_PULL_COMPLIANT_MAX * 2;
|
|
354
|
+
let path = `${projectApiPath(ctx.config, 'merge_requests')}?state=opened`;
|
|
355
|
+
path = appendSortQuery(path, gitlabOpenPullSortQuery(sliceSort));
|
|
356
|
+
const separator = path.includes('?') ? '&' : '?';
|
|
357
|
+
const requestLimit = Math.min(retainMax, GITLAB_PAGE_SIZE);
|
|
358
|
+
try {
|
|
359
|
+
const { body, headers } = await gitlabFetchWithMeta(
|
|
360
|
+
ctx.config,
|
|
361
|
+
ctx.parsed,
|
|
362
|
+
`${path}${separator}per_page=${requestLimit}&page=1`,
|
|
363
|
+
);
|
|
364
|
+
if (!Array.isArray(body)) return null;
|
|
365
|
+
const totalCount = parseTotalCountHeader(headers, 'X-Total', { maxTrusted });
|
|
366
|
+
if (totalCount == null) return null;
|
|
367
|
+
const listTruncated = totalCount > GITLAB_OPEN_PULL_COMPLIANT_MAX;
|
|
368
|
+
return { body, totalCount, listTruncated, requestLimit };
|
|
369
|
+
} catch {
|
|
370
|
+
return null;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function buildGitlabOpenPullMetaFromPage(body, retainMax, sliceSort, totalCount, listTruncated) {
|
|
375
|
+
let numbers = orderOpenPullNumbers(body, (mr) => mr?.iid, sliceSort);
|
|
376
|
+
if (numbers.length > retainMax) numbers = numbers.slice(0, retainMax);
|
|
377
|
+
return buildOpenPullListMeta({
|
|
378
|
+
totalCount,
|
|
379
|
+
numbers,
|
|
380
|
+
listTruncated,
|
|
381
|
+
sliceSort,
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function gitlabProbePaginationOpts(probe, extra = {}) {
|
|
386
|
+
const { body, totalCount, requestLimit } = probe;
|
|
318
387
|
return {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
blockers,
|
|
388
|
+
trustedTotalCount: totalCount,
|
|
389
|
+
seededFirstPage: { items: body, usedLimit: requestLimit },
|
|
390
|
+
...extra,
|
|
323
391
|
};
|
|
324
392
|
}
|
|
325
393
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
394
|
+
async function paginateGitlabOpenPullList(ctx, opts, sliceSort, paginationOpts = {}) {
|
|
395
|
+
const {
|
|
396
|
+
trustedTotalCount = null,
|
|
397
|
+
numberSortFullCollect = false,
|
|
398
|
+
seededFirstPage = null,
|
|
399
|
+
startPage = 1,
|
|
400
|
+
maxPages = MAX_CHECK_STATUS_PAGES,
|
|
401
|
+
suppressFinalPageProbe = false,
|
|
402
|
+
} = paginationOpts;
|
|
329
403
|
const listLimit =
|
|
330
404
|
opts.limit != null && Number.isInteger(Number(opts.limit)) && Number(opts.limit) > 0
|
|
331
405
|
? Number(opts.limit)
|
|
332
406
|
: null;
|
|
333
|
-
const
|
|
407
|
+
const retainMax =
|
|
408
|
+
listLimit == null &&
|
|
409
|
+
opts.retain_max != null &&
|
|
410
|
+
Number.isInteger(Number(opts.retain_max)) &&
|
|
411
|
+
Number(opts.retain_max) > 0
|
|
412
|
+
? Number(opts.retain_max)
|
|
413
|
+
: null;
|
|
414
|
+
let path = `${projectApiPath(ctx.config, 'merge_requests')}?state=opened`;
|
|
415
|
+
path = appendSortQuery(path, gitlabOpenPullSortQuery(sliceSort));
|
|
334
416
|
const separator = path.includes('?') ? '&' : '?';
|
|
335
|
-
const
|
|
417
|
+
const effectiveRetainMax = numberSortFullCollect ? null : retainMax;
|
|
418
|
+
const {
|
|
419
|
+
items: all,
|
|
420
|
+
list_truncated: listTruncated,
|
|
421
|
+
entry_count: entryCount,
|
|
422
|
+
walked_count: walkedCount,
|
|
423
|
+
} = await paginateOffsetListPages({
|
|
336
424
|
pageSize: GITLAB_PAGE_SIZE,
|
|
337
425
|
listLimit,
|
|
426
|
+
retainMax: effectiveRetainMax,
|
|
427
|
+
trustedEntryCount: trustedTotalCount,
|
|
428
|
+
seededFirstPage,
|
|
429
|
+
startPage,
|
|
430
|
+
maxPages,
|
|
431
|
+
suppressFinalPageProbe,
|
|
338
432
|
...(listLimit != null ? { maxPagesTruncatesWithLimit: true } : {}),
|
|
339
433
|
fetchPage: async ({ page, limit }) => {
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
let numbers = all
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
.
|
|
352
|
-
|
|
353
|
-
|
|
434
|
+
const body = await gitlabFetch(
|
|
435
|
+
ctx.config,
|
|
436
|
+
ctx.parsed,
|
|
437
|
+
`${path}${separator}per_page=${limit}&page=${page}`,
|
|
438
|
+
);
|
|
439
|
+
return Array.isArray(body) ? body : [];
|
|
440
|
+
},
|
|
441
|
+
});
|
|
442
|
+
let numbers = orderOpenPullNumbers(all, (mr) => mr?.iid, sliceSort);
|
|
443
|
+
const outputCap = listLimit ?? retainMax;
|
|
444
|
+
if (outputCap != null && numbers.length > outputCap) {
|
|
445
|
+
numbers = numbers.slice(0, outputCap);
|
|
446
|
+
}
|
|
447
|
+
return {
|
|
448
|
+
numbers,
|
|
449
|
+
list_truncated: resolveListTruncatedWithTrustedTotal({
|
|
450
|
+
listTruncated,
|
|
451
|
+
trustedTotalCount,
|
|
452
|
+
walkedCount,
|
|
453
|
+
fullCollect: numberSortFullCollect,
|
|
454
|
+
}),
|
|
455
|
+
...(entryCount != null ? { entry_count: entryCount } : {}),
|
|
456
|
+
slice_sort: sliceSort,
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
export async function listOpenPullsWithMeta(ctx, opts = {}) {
|
|
461
|
+
apiBase(ctx.config, ctx.parsed);
|
|
462
|
+
requireToken();
|
|
463
|
+
const sliceSort = normalizeCrInventorySort(opts.sort ?? DEFAULT_CR_INVENTORY_SLICE_SORT);
|
|
464
|
+
if (!isCrInventoryFastPathEligible(opts)) {
|
|
465
|
+
return paginateGitlabOpenPullList(ctx, opts, sliceSort);
|
|
354
466
|
}
|
|
355
|
-
|
|
467
|
+
|
|
468
|
+
const retainMax = Number(opts.retain_max);
|
|
469
|
+
const probe = await probeGitlabOpenPullPageOne(ctx, retainMax, sliceSort);
|
|
470
|
+
if (!probe) {
|
|
471
|
+
return paginateGitlabOpenPullList(ctx, opts, sliceSort);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
const { body, totalCount, listTruncated, requestLimit } = probe;
|
|
475
|
+
|
|
476
|
+
if (listTruncated) {
|
|
477
|
+
if (body.length === 0) {
|
|
478
|
+
return paginateGitlabOpenPullList(ctx, opts, sliceSort, gitlabProbePaginationOpts(probe));
|
|
479
|
+
}
|
|
480
|
+
return buildGitlabOpenPullMetaFromPage(body, retainMax, sliceSort, totalCount, true);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
if (
|
|
484
|
+
isNumberSortFastPathEligible(totalCount, retainMax, sliceSort) &&
|
|
485
|
+
validateFastPathPageLength(totalCount, requestLimit, body.length)
|
|
486
|
+
) {
|
|
487
|
+
return buildGitlabOpenPullMetaFromPage(body, retainMax, sliceSort, totalCount, false);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
const numberSortFullCollect = isNumberSortFullCollectRequired(totalCount, retainMax, sliceSort);
|
|
491
|
+
return paginateGitlabOpenPullList(
|
|
492
|
+
ctx,
|
|
493
|
+
opts,
|
|
494
|
+
sliceSort,
|
|
495
|
+
gitlabProbePaginationOpts(probe, { numberSortFullCollect }),
|
|
496
|
+
);
|
|
356
497
|
}
|
|
357
498
|
|
|
358
499
|
export async function listOpenPulls(ctx, opts = {}) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remogram/provider-gitlab-api",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.4",
|
|
4
4
|
"description": "GitLab API provider for remogram",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -22,6 +22,6 @@
|
|
|
22
22
|
"node": ">=20"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@remogram/core": "0.1.0-beta.
|
|
25
|
+
"@remogram/core": "0.1.0-beta.4"
|
|
26
26
|
}
|
|
27
27
|
}
|