@remogram/provider-gitea-api 0.1.0-beta.8 → 0.1.0-beta.9
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/branch-protection-internal.js +13 -0
- package/index.js +252 -20
- package/package.json +4 -3
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** @type {((ctx: object, opts: { branchRef: string }) => Promise<object>) | null} */
|
|
2
|
+
let branchProtectionImpl = null;
|
|
3
|
+
|
|
4
|
+
export function setBranchProtectionImpl(fn) {
|
|
5
|
+
branchProtectionImpl = fn;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export async function resolveBranchProtection(ctx, opts) {
|
|
9
|
+
if (typeof branchProtectionImpl !== 'function') {
|
|
10
|
+
throw new Error('branch protection impl not registered');
|
|
11
|
+
}
|
|
12
|
+
return branchProtectionImpl(ctx, opts);
|
|
13
|
+
}
|
package/index.js
CHANGED
|
@@ -12,11 +12,15 @@ import {
|
|
|
12
12
|
crInventory,
|
|
13
13
|
buildMergePlanFromProviderFacts,
|
|
14
14
|
buildChangeRequestOpenedBody,
|
|
15
|
+
buildIssueOpenedBody,
|
|
16
|
+
parseIssueOpenArgs,
|
|
15
17
|
buildCommitStatusSetBody,
|
|
18
|
+
idempotencyPacketFields,
|
|
16
19
|
parseStatusSetArgs,
|
|
17
20
|
normalizeStatusSetState,
|
|
18
21
|
buildProviderIdentityFromGiteaUser,
|
|
19
22
|
buildBranchProtectionFromGiteaProtection,
|
|
23
|
+
buildPrChecksBody,
|
|
20
24
|
buildCrFilesBody,
|
|
21
25
|
buildCrFilesFromGiteaFiles,
|
|
22
26
|
buildCrCommentsBody,
|
|
@@ -28,6 +32,7 @@ import {
|
|
|
28
32
|
ERROR_CODES,
|
|
29
33
|
forgeError,
|
|
30
34
|
assertExpectedSha,
|
|
35
|
+
LIVE_REACHABILITY_TIMEOUT_MS,
|
|
31
36
|
forgeIngestCapabilityFacts,
|
|
32
37
|
checkPaginationCapabilityFacts,
|
|
33
38
|
idempotencyScanCapabilityFacts,
|
|
@@ -58,7 +63,14 @@ import {
|
|
|
58
63
|
giteaOpenPullSortQuery,
|
|
59
64
|
appendSortQuery,
|
|
60
65
|
assertWriteCommandConfigured,
|
|
66
|
+
fetchWithTimeout,
|
|
67
|
+
readStreamCapped,
|
|
68
|
+
getEffectiveIngestMaxBytes,
|
|
61
69
|
} from '@remogram/core';
|
|
70
|
+
import {
|
|
71
|
+
resolveBranchProtection,
|
|
72
|
+
setBranchProtectionImpl,
|
|
73
|
+
} from './branch-protection-internal.js';
|
|
62
74
|
const PUBLIC_GITEA_HOST = 'gitea.com';
|
|
63
75
|
const PUBLIC_GITEA_API = 'https://gitea.com/api/v1';
|
|
64
76
|
const AUTH_CAPABILITIES = [
|
|
@@ -81,6 +93,7 @@ const AUTH_CAPABILITIES = [
|
|
|
81
93
|
|
|
82
94
|
const STRUCTURED_COMMANDS = apiProviderCommands({
|
|
83
95
|
writeCommandsImplemented: true,
|
|
96
|
+
issueOpenImplemented: true,
|
|
84
97
|
statusSetImplemented: true,
|
|
85
98
|
branchProtectionImplemented: true,
|
|
86
99
|
crFilesImplemented: true,
|
|
@@ -215,6 +228,22 @@ export async function giteaFetchWithMeta(config, parsed, path, options = {}) {
|
|
|
215
228
|
});
|
|
216
229
|
}
|
|
217
230
|
|
|
231
|
+
export async function apiReachability(ctx) {
|
|
232
|
+
if (!giteaToken()) {
|
|
233
|
+
throw Object.assign(new Error('GITEA_TOKEN not set'), {
|
|
234
|
+
forgeError: forgeError(ERROR_CODES.UNAUTHENTICATED_PROVIDER, 'GITEA_TOKEN not set'),
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
const token = requireToken();
|
|
238
|
+
const url = `${apiBase(ctx.config, ctx.parsed)}${repoApiPath(ctx.config)}`;
|
|
239
|
+
await fetchJson(
|
|
240
|
+
url,
|
|
241
|
+
{ headers: authHeaders(token) },
|
|
242
|
+
LIVE_REACHABILITY_TIMEOUT_MS,
|
|
243
|
+
);
|
|
244
|
+
return { repo_accessible: true };
|
|
245
|
+
}
|
|
246
|
+
|
|
218
247
|
const MAX_CHECK_PAGES = MAX_CHECK_STATUS_PAGES;
|
|
219
248
|
const GITEA_PAGE_SIZE = DEFAULT_OPEN_PULL_LIST_PAGE_SIZE;
|
|
220
249
|
|
|
@@ -281,11 +310,14 @@ export function dedupeGiteaStatusRecords(records) {
|
|
|
281
310
|
return Array.from(latestByContext.values());
|
|
282
311
|
}
|
|
283
312
|
|
|
284
|
-
export function mapGiteaCommitStatuses(records) {
|
|
313
|
+
export function mapGiteaCommitStatuses(records, { headSha } = {}) {
|
|
285
314
|
return dedupeGiteaStatusRecords(records).map((s) => ({
|
|
286
315
|
context: sanitizeField(s.context),
|
|
287
316
|
state: normalizeGiteaStatusState(s.status ?? s.state),
|
|
288
317
|
description: sanitizeField(s.description),
|
|
318
|
+
...(s.target_url ? { target_url: sanitizeField(s.target_url) } : {}),
|
|
319
|
+
...(headSha ? { sha: headSha } : {}),
|
|
320
|
+
source: 'commit_status',
|
|
289
321
|
}));
|
|
290
322
|
}
|
|
291
323
|
|
|
@@ -319,12 +351,19 @@ export async function whoami(ctx) {
|
|
|
319
351
|
|
|
320
352
|
export async function branchProtection(ctx, { branchRef }) {
|
|
321
353
|
requireToken();
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
354
|
+
try {
|
|
355
|
+
const protection = await giteaFetch(
|
|
356
|
+
ctx.config,
|
|
357
|
+
ctx.parsed,
|
|
358
|
+
repoApiPath(ctx.config, 'branch_protections', branchRef),
|
|
359
|
+
);
|
|
360
|
+
return buildBranchProtectionFromGiteaProtection(branchRef, protection);
|
|
361
|
+
} catch (err) {
|
|
362
|
+
if (err?.status === 404) {
|
|
363
|
+
return buildBranchProtectionFromGiteaProtection(branchRef, null);
|
|
364
|
+
}
|
|
365
|
+
throw err;
|
|
366
|
+
}
|
|
328
367
|
}
|
|
329
368
|
|
|
330
369
|
export async function branchHeadSha(ctx, branchRef, { repoId } = {}) {
|
|
@@ -551,7 +590,7 @@ export function providerCapabilities() {
|
|
|
551
590
|
host_binding: 'verified_remote_host',
|
|
552
591
|
pagination: 'supported',
|
|
553
592
|
write_support: true,
|
|
554
|
-
write_commands: ['cr_open', 'status_set', 'merge'],
|
|
593
|
+
write_commands: ['cr_open', 'status_set', 'merge', 'issue_open'],
|
|
555
594
|
...forgeIngestCapabilityFacts(),
|
|
556
595
|
...checkPaginationCapabilityFacts({
|
|
557
596
|
strategy: 'offset_limit',
|
|
@@ -600,7 +639,63 @@ export async function getPull(ctx, { number }) {
|
|
|
600
639
|
forgeError: forgeError(ERROR_CODES.INVALID_ARGS, 'Provide --number for PR lookup'),
|
|
601
640
|
});
|
|
602
641
|
}
|
|
603
|
-
return
|
|
642
|
+
return giteaFetchPullForView(ctx.config, ctx.parsed, number);
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
/** Raw read bound for pull view before stripping bulky fields (#478). */
|
|
646
|
+
const GITEA_PULL_VIEW_RAW_READ_MAX = 256 * 1024;
|
|
647
|
+
|
|
648
|
+
function stripGiteaPullBulkJsonFields(raw) {
|
|
649
|
+
return String(raw)
|
|
650
|
+
.replace(/"body"\s*:\s*"(?:\\.|[^"\\])*"/g, '"body":""')
|
|
651
|
+
.replace(/"body_html"\s*:\s*"(?:\\.|[^"\\])*"/g, '"body_html":""')
|
|
652
|
+
.replace(/"diff"\s*:\s*"(?:\\.|[^"\\])*"/g, '"diff":""')
|
|
653
|
+
.replace(/"patch"\s*:\s*"(?:\\.|[^"\\])*"/g, '"patch":""');
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
async function giteaFetchPullForView(config, parsed, number) {
|
|
657
|
+
const token = requireToken();
|
|
658
|
+
const url = `${apiBase(config, parsed)}${repoApiPath(config, 'pulls', number)}`;
|
|
659
|
+
const res = await fetchWithTimeout(url, { headers: authHeaders(token) });
|
|
660
|
+
if (res.status >= 300 && res.status < 400) {
|
|
661
|
+
const message = 'HTTP redirect rejected';
|
|
662
|
+
throw Object.assign(new Error(message), {
|
|
663
|
+
forgeError: forgeError(ERROR_CODES.API_ERROR, message, res.status),
|
|
664
|
+
status: res.status,
|
|
665
|
+
});
|
|
666
|
+
}
|
|
667
|
+
const capped = await readStreamCapped(res.body, GITEA_PULL_VIEW_RAW_READ_MAX);
|
|
668
|
+
if (capped.truncated) {
|
|
669
|
+
throw Object.assign(new Error('Provider output exceeded cap'), {
|
|
670
|
+
forgeError: forgeError(ERROR_CODES.OVERSIZED_RAW_OUTPUT, 'Provider response exceeded byte cap'),
|
|
671
|
+
status: res.status,
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
const stripped = stripGiteaPullBulkJsonFields(capped.text);
|
|
675
|
+
if (Buffer.byteLength(stripped, 'utf8') > getEffectiveIngestMaxBytes().bytes) {
|
|
676
|
+
throw Object.assign(new Error('Provider output exceeded cap after projection'), {
|
|
677
|
+
forgeError: forgeError(ERROR_CODES.OVERSIZED_RAW_OUTPUT, 'Provider response exceeded byte cap'),
|
|
678
|
+
status: res.status,
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
let body;
|
|
682
|
+
try {
|
|
683
|
+
body = stripped ? JSON.parse(stripped) : null;
|
|
684
|
+
} catch {
|
|
685
|
+
throw Object.assign(new Error('Unparseable JSON from provider'), {
|
|
686
|
+
forgeError: forgeError(ERROR_CODES.UNPARSEABLE_PROVIDER_OUTPUT, 'Provider returned invalid JSON'),
|
|
687
|
+
status: res.status,
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
if (!res.ok) {
|
|
691
|
+
const raw = body?.message || body?.error || res.statusText || 'API error';
|
|
692
|
+
const message = sanitizeField(raw) || 'API error';
|
|
693
|
+
throw Object.assign(new Error(message), {
|
|
694
|
+
forgeError: forgeError(ERROR_CODES.API_ERROR, message, res.status),
|
|
695
|
+
status: res.status,
|
|
696
|
+
});
|
|
697
|
+
}
|
|
698
|
+
return body;
|
|
604
699
|
}
|
|
605
700
|
|
|
606
701
|
/** Paginated open-pull scan for idempotent cr open; fail-closed when scan cap prevents proof of absence. */
|
|
@@ -651,6 +746,68 @@ export async function findOpenPullByHeadBase(ctx, head, base) {
|
|
|
651
746
|
return null;
|
|
652
747
|
}
|
|
653
748
|
|
|
749
|
+
function issueOpenIdempotencyScanIncompleteError(pagesScanned, pageSizeUsed) {
|
|
750
|
+
return forgeError(
|
|
751
|
+
ERROR_CODES.IDEMPOTENCY_SCAN_INCOMPLETE,
|
|
752
|
+
'Cannot prove no open issue exists for title within scan limit; retry or open manually',
|
|
753
|
+
null,
|
|
754
|
+
{
|
|
755
|
+
idempotency_scan: {
|
|
756
|
+
pages: pagesScanned,
|
|
757
|
+
max_pages: MAX_OPEN_PULL_IDEMPOTENCY_PAGES,
|
|
758
|
+
page_size: pageSizeUsed,
|
|
759
|
+
},
|
|
760
|
+
},
|
|
761
|
+
);
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
/** Paginated open-issue scan for idempotent issue open; fail-closed when scan cap prevents proof of absence. */
|
|
765
|
+
export async function findOpenIssueByTitle(ctx, title) {
|
|
766
|
+
requireToken();
|
|
767
|
+
const path = `${repoApiPath(ctx.config, 'issues')}?state=open`;
|
|
768
|
+
const pageSep = path.includes('?') ? '&' : '?';
|
|
769
|
+
let activeLimit = GITEA_PAGE_SIZE;
|
|
770
|
+
|
|
771
|
+
for (let page = 1; page <= MAX_OPEN_PULL_IDEMPOTENCY_PAGES; page += 1) {
|
|
772
|
+
const { items, usedLimit } = await fetchPageWithIngestBackoff(
|
|
773
|
+
async ({ page: pageNum, limit }) => {
|
|
774
|
+
const body = await giteaFetch(
|
|
775
|
+
ctx.config,
|
|
776
|
+
ctx.parsed,
|
|
777
|
+
`${path}${pageSep}limit=${limit}&page=${pageNum}`,
|
|
778
|
+
);
|
|
779
|
+
if (!Array.isArray(body)) {
|
|
780
|
+
throw Object.assign(new Error('Provider returned non-array open issue list'), {
|
|
781
|
+
forgeError: forgeError(
|
|
782
|
+
ERROR_CODES.UNPARSEABLE_PROVIDER_OUTPUT,
|
|
783
|
+
'Provider returned non-array open issue list',
|
|
784
|
+
),
|
|
785
|
+
});
|
|
786
|
+
}
|
|
787
|
+
return body;
|
|
788
|
+
},
|
|
789
|
+
page,
|
|
790
|
+
activeLimit,
|
|
791
|
+
);
|
|
792
|
+
activeLimit = usedLimit;
|
|
793
|
+
|
|
794
|
+
const match =
|
|
795
|
+
items.find(
|
|
796
|
+
(issue) =>
|
|
797
|
+
String(issue?.state ?? '').toLowerCase() === 'open' &&
|
|
798
|
+
sanitizeField(issue?.title ?? '') === title,
|
|
799
|
+
) ?? null;
|
|
800
|
+
if (match) return match;
|
|
801
|
+
if (items.length < usedLimit) return null;
|
|
802
|
+
if (page === MAX_OPEN_PULL_IDEMPOTENCY_PAGES) {
|
|
803
|
+
throw Object.assign(new Error('Open issue idempotency scan incomplete'), {
|
|
804
|
+
forgeError: issueOpenIdempotencyScanIncompleteError(page, usedLimit),
|
|
805
|
+
});
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
return null;
|
|
809
|
+
}
|
|
810
|
+
|
|
654
811
|
function statusSetIdempotencyScanIncompleteError(pagesScanned, pageSizeUsed) {
|
|
655
812
|
return forgeError(
|
|
656
813
|
ERROR_CODES.IDEMPOTENCY_SCAN_INCOMPLETE,
|
|
@@ -716,12 +873,18 @@ export async function findCommitStatusByContext(ctx, sha, context) {
|
|
|
716
873
|
|
|
717
874
|
export async function statusSet(ctx, args) {
|
|
718
875
|
assertWriteCommandConfigured(ctx.config, 'status_set');
|
|
719
|
-
const
|
|
876
|
+
const { idempotencyFingerprint = null, ...rest } = args;
|
|
877
|
+
const parsed = parseStatusSetArgs(rest);
|
|
720
878
|
const existing = await findCommitStatusByContext(ctx, parsed.sha, parsed.context);
|
|
721
879
|
if (existing) {
|
|
722
880
|
const existingState = normalizeStatusSetState(existing.status ?? existing.state);
|
|
723
881
|
if (existingState === parsed.state) {
|
|
724
|
-
return buildCommitStatusSetBody(existing, parsed, {
|
|
882
|
+
return buildCommitStatusSetBody(existing, parsed, {
|
|
883
|
+
reusedExisting: true,
|
|
884
|
+
idempotencyFields: idempotencyFingerprint
|
|
885
|
+
? idempotencyPacketFields(idempotencyFingerprint, { reusedExisting: true })
|
|
886
|
+
: null,
|
|
887
|
+
});
|
|
725
888
|
}
|
|
726
889
|
}
|
|
727
890
|
const payload = {
|
|
@@ -740,10 +903,48 @@ export async function statusSet(ctx, args) {
|
|
|
740
903
|
body: JSON.stringify(payload),
|
|
741
904
|
},
|
|
742
905
|
);
|
|
743
|
-
return buildCommitStatusSetBody(response, parsed
|
|
906
|
+
return buildCommitStatusSetBody(response, parsed, {
|
|
907
|
+
idempotencyFields: idempotencyFingerprint
|
|
908
|
+
? idempotencyPacketFields(idempotencyFingerprint, { reusedExisting: false })
|
|
909
|
+
: null,
|
|
910
|
+
} );
|
|
744
911
|
}
|
|
745
912
|
|
|
746
|
-
export async function
|
|
913
|
+
export async function issueOpen(ctx, { title, body: issueBody, idempotencyFingerprint = null }) {
|
|
914
|
+
assertWriteCommandConfigured(ctx.config, 'issue_open');
|
|
915
|
+
const parsed = parseIssueOpenArgs({ title, body: issueBody });
|
|
916
|
+
const existing = await findOpenIssueByTitle(ctx, parsed.title);
|
|
917
|
+
if (existing) {
|
|
918
|
+
return buildIssueOpenedBody(
|
|
919
|
+
existing,
|
|
920
|
+
{ title: parsed.title },
|
|
921
|
+
{
|
|
922
|
+
reusedExisting: true,
|
|
923
|
+
idempotencyFields: idempotencyFingerprint
|
|
924
|
+
? idempotencyPacketFields(idempotencyFingerprint, { reusedExisting: true })
|
|
925
|
+
: null,
|
|
926
|
+
},
|
|
927
|
+
);
|
|
928
|
+
}
|
|
929
|
+
const payload = { title: parsed.title };
|
|
930
|
+
if (parsed.body != null) payload.body = parsed.body;
|
|
931
|
+
const issue = await giteaFetch(ctx.config, ctx.parsed, repoApiPath(ctx.config, 'issues'), {
|
|
932
|
+
method: 'POST',
|
|
933
|
+
headers: { 'Content-Type': 'application/json' },
|
|
934
|
+
body: JSON.stringify(payload),
|
|
935
|
+
});
|
|
936
|
+
return buildIssueOpenedBody(
|
|
937
|
+
issue,
|
|
938
|
+
{ title: parsed.title },
|
|
939
|
+
{
|
|
940
|
+
idempotencyFields: idempotencyFingerprint
|
|
941
|
+
? idempotencyPacketFields(idempotencyFingerprint, { reusedExisting: false })
|
|
942
|
+
: null,
|
|
943
|
+
},
|
|
944
|
+
);
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
export async function crOpen(ctx, { head, base, title, body: prBody, idempotencyFingerprint = null }) {
|
|
747
948
|
assertWriteCommandConfigured(ctx.config, 'cr_open');
|
|
748
949
|
assertGitRef(head, 'head');
|
|
749
950
|
assertGitRef(base, 'base');
|
|
@@ -762,14 +963,31 @@ export async function crOpen(ctx, { head, base, title, body: prBody }) {
|
|
|
762
963
|
}
|
|
763
964
|
const existing = await findOpenPullByHeadBase(ctx, payload.head, payload.base);
|
|
764
965
|
if (existing) {
|
|
765
|
-
return buildChangeRequestOpenedBody(
|
|
966
|
+
return buildChangeRequestOpenedBody(
|
|
967
|
+
existing,
|
|
968
|
+
{ head, base, title },
|
|
969
|
+
{
|
|
970
|
+
reusedExisting: true,
|
|
971
|
+
idempotencyFields: idempotencyFingerprint
|
|
972
|
+
? idempotencyPacketFields(idempotencyFingerprint, { reusedExisting: true })
|
|
973
|
+
: null,
|
|
974
|
+
},
|
|
975
|
+
);
|
|
766
976
|
}
|
|
767
977
|
const pull = await giteaFetch(ctx.config, ctx.parsed, repoApiPath(ctx.config, 'pulls'), {
|
|
768
978
|
method: 'POST',
|
|
769
979
|
headers: { 'Content-Type': 'application/json' },
|
|
770
980
|
body: JSON.stringify(payload),
|
|
771
981
|
});
|
|
772
|
-
return buildChangeRequestOpenedBody(
|
|
982
|
+
return buildChangeRequestOpenedBody(
|
|
983
|
+
pull,
|
|
984
|
+
{ head, base, title },
|
|
985
|
+
{
|
|
986
|
+
idempotencyFields: idempotencyFingerprint
|
|
987
|
+
? idempotencyPacketFields(idempotencyFingerprint, { reusedExisting: false })
|
|
988
|
+
: null,
|
|
989
|
+
},
|
|
990
|
+
);
|
|
773
991
|
}
|
|
774
992
|
|
|
775
993
|
export async function mergeExecute(ctx, { number, method = 'merge', expectedHeadSha }) {
|
|
@@ -1053,6 +1271,7 @@ export async function prView(ctx, opts) {
|
|
|
1053
1271
|
export async function prChecks(ctx, opts) {
|
|
1054
1272
|
requireToken();
|
|
1055
1273
|
let sha;
|
|
1274
|
+
let requiredContexts = [];
|
|
1056
1275
|
if (opts.ref) {
|
|
1057
1276
|
assertGitRef(opts.ref, 'ref');
|
|
1058
1277
|
sha = gitRevParse(ctx.cwd, opts.ref);
|
|
@@ -1064,6 +1283,15 @@ export async function prChecks(ctx, opts) {
|
|
|
1064
1283
|
} else {
|
|
1065
1284
|
const pr = await getPull(ctx, opts);
|
|
1066
1285
|
sha = pr.head?.sha;
|
|
1286
|
+
const targetBranch = pr.base?.ref;
|
|
1287
|
+
if (targetBranch) {
|
|
1288
|
+
try {
|
|
1289
|
+
const protection = await resolveBranchProtection(ctx, { branchRef: targetBranch });
|
|
1290
|
+
requiredContexts = protection.required_status_contexts ?? [];
|
|
1291
|
+
} catch (err) {
|
|
1292
|
+
if (err?.status !== 404) throw err;
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1067
1295
|
}
|
|
1068
1296
|
if (!sha) {
|
|
1069
1297
|
throw Object.assign(new Error('No SHA'), {
|
|
@@ -1075,14 +1303,14 @@ export async function prChecks(ctx, opts) {
|
|
|
1075
1303
|
ctx.parsed,
|
|
1076
1304
|
repoApiPath(ctx.config, 'commits', sha, 'statuses'),
|
|
1077
1305
|
);
|
|
1078
|
-
const mapped = mapGiteaCommitStatuses(statusRecords);
|
|
1079
|
-
|
|
1080
|
-
return {
|
|
1306
|
+
const mapped = mapGiteaCommitStatuses(statusRecords, { headSha: sha });
|
|
1307
|
+
return buildPrChecksBody({
|
|
1081
1308
|
forge_source_sha: sha,
|
|
1082
|
-
check_conclusion:
|
|
1309
|
+
check_conclusion: summarizeChecks(mapped),
|
|
1083
1310
|
checks_truncated,
|
|
1084
1311
|
statuses: mapped,
|
|
1085
|
-
|
|
1312
|
+
required_contexts: requiredContexts,
|
|
1313
|
+
});
|
|
1086
1314
|
}
|
|
1087
1315
|
|
|
1088
1316
|
export function summarizeChecks(statuses) {
|
|
@@ -1127,6 +1355,7 @@ export async function syncPlan(ctx, remoteName = 'origin') {
|
|
|
1127
1355
|
export const provider = {
|
|
1128
1356
|
id: 'gitea-api',
|
|
1129
1357
|
providerCapabilities,
|
|
1358
|
+
apiReachability,
|
|
1130
1359
|
repoStatus,
|
|
1131
1360
|
refsCompare,
|
|
1132
1361
|
refsInventory,
|
|
@@ -1137,6 +1366,7 @@ export const provider = {
|
|
|
1137
1366
|
mergePlan,
|
|
1138
1367
|
syncPlan,
|
|
1139
1368
|
crOpen,
|
|
1369
|
+
issueOpen,
|
|
1140
1370
|
mergeExecute,
|
|
1141
1371
|
statusSet,
|
|
1142
1372
|
whoami,
|
|
@@ -1146,3 +1376,5 @@ export const provider = {
|
|
|
1146
1376
|
crComments,
|
|
1147
1377
|
forgeChanges,
|
|
1148
1378
|
};
|
|
1379
|
+
|
|
1380
|
+
setBranchProtectionImpl(branchProtection);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remogram/provider-gitea-api",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.9",
|
|
4
4
|
"description": "Gitea REST API forge provider for remogram",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -16,12 +16,13 @@
|
|
|
16
16
|
"*.js"
|
|
17
17
|
],
|
|
18
18
|
"exports": {
|
|
19
|
-
".": "./index.js"
|
|
19
|
+
".": "./index.js",
|
|
20
|
+
"./branch-protection-internal.js": "./branch-protection-internal.js"
|
|
20
21
|
},
|
|
21
22
|
"engines": {
|
|
22
23
|
"node": ">=20"
|
|
23
24
|
},
|
|
24
25
|
"dependencies": {
|
|
25
|
-
"@remogram/core": "0.1.0-beta.
|
|
26
|
+
"@remogram/core": "0.1.0-beta.9"
|
|
26
27
|
}
|
|
27
28
|
}
|