@bensandee/forgejo-cli 0.5.6 → 0.6.1
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/dist/bin.mjs +347 -369
- package/package.json +1 -1
package/dist/bin.mjs
CHANGED
|
@@ -6,7 +6,7 @@ import { FatalError, TransientError, UnexpectedError, describeError, redact, red
|
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
import { defineCommand, renderUsage, runCommand, runMain } from "citty";
|
|
8
8
|
import { execFileSync, spawn } from "node:child_process";
|
|
9
|
-
|
|
9
|
+
// ../cli-kit/src/json.ts
|
|
10
10
|
function resolveJsonMode(rawArgs) {
|
|
11
11
|
if (!rawArgs.some(requestsJson)) return false;
|
|
12
12
|
if (rawArgs.includes("--help") || rawArgs.includes("-h")) return false;
|
|
@@ -100,8 +100,7 @@ function classifyThrown(error, verbose) {
|
|
|
100
100
|
detail
|
|
101
101
|
};
|
|
102
102
|
}
|
|
103
|
-
|
|
104
|
-
//#region ../cli-kit/src/env-file.ts
|
|
103
|
+
// ../cli-kit/src/env-file.ts
|
|
105
104
|
const ENV_FILE_VAR = "BST_ENV_FILE";
|
|
106
105
|
function loadEnvFileFromEnv() {
|
|
107
106
|
const raw = process.env[ENV_FILE_VAR]?.trim();
|
|
@@ -158,11 +157,10 @@ function loadEnvFileForBin(rawArgs, bin, io = processIo) {
|
|
|
158
157
|
return io.exit(1);
|
|
159
158
|
}
|
|
160
159
|
}
|
|
161
|
-
|
|
162
|
-
//#region src/version.ts
|
|
160
|
+
// src/version.ts
|
|
163
161
|
const parsed = z.object({ version: z.string() }).safeParse({
|
|
164
162
|
name: "@bensandee/forgejo-cli",
|
|
165
|
-
version: "0.
|
|
163
|
+
version: "0.6.1",
|
|
166
164
|
description: "bst-fj: Forgejo API commands without the rest of bst",
|
|
167
165
|
license: "MIT",
|
|
168
166
|
repository: {
|
|
@@ -203,14 +201,12 @@ const parsed = z.object({ version: z.string() }).safeParse({
|
|
|
203
201
|
});
|
|
204
202
|
if (!parsed.success) throw new UnexpectedError(`@bensandee/forgejo-cli's package.json has no string version.`);
|
|
205
203
|
const BST_FJ_VERSION = parsed.data.version;
|
|
206
|
-
|
|
207
|
-
//#region src/env-file-preload.ts
|
|
204
|
+
// src/env-file-preload.ts
|
|
208
205
|
const envFileLoad = loadEnvFileForBin(process.argv.slice(2), {
|
|
209
206
|
name: "bst-fj",
|
|
210
207
|
version: BST_FJ_VERSION
|
|
211
208
|
});
|
|
212
|
-
|
|
213
|
-
//#region ../cli-kit/src/logger.ts
|
|
209
|
+
// ../cli-kit/src/logger.ts
|
|
214
210
|
const RANK = {
|
|
215
211
|
error: 0,
|
|
216
212
|
warn: 1,
|
|
@@ -310,8 +306,7 @@ function createLogger(options = {}) {
|
|
|
310
306
|
});
|
|
311
307
|
}
|
|
312
308
|
const rootLogger = createLogger();
|
|
313
|
-
|
|
314
|
-
//#region ../cli-kit/src/flags.ts
|
|
309
|
+
// ../cli-kit/src/flags.ts
|
|
315
310
|
const UNIVERSAL_FLAGS = [
|
|
316
311
|
"--help",
|
|
317
312
|
"-h",
|
|
@@ -643,8 +638,12 @@ function listFlagPresent(rawArgs, flag) {
|
|
|
643
638
|
const long = `--${flag}`;
|
|
644
639
|
return rawArgs.some((token) => token === long || token.startsWith(`${long}=`));
|
|
645
640
|
}
|
|
646
|
-
|
|
647
|
-
|
|
641
|
+
function parseLimitFlag(raw) {
|
|
642
|
+
const value = Number(raw);
|
|
643
|
+
if (!Number.isInteger(value) || value < 1) throw new FatalError(`--limit must be a positive integer, got "${raw}"`);
|
|
644
|
+
return value;
|
|
645
|
+
}
|
|
646
|
+
// ../cli-kit/src/output.ts
|
|
648
647
|
const stdout = (msg) => console.log(msg);
|
|
649
648
|
function initialState() {
|
|
650
649
|
return {
|
|
@@ -707,8 +706,7 @@ function flushJsonOutput() {
|
|
|
707
706
|
function jsonDocumentWritten() {
|
|
708
707
|
return state.wrote;
|
|
709
708
|
}
|
|
710
|
-
|
|
711
|
-
//#region ../cli-kit/src/path-probe.ts
|
|
709
|
+
// ../cli-kit/src/path-probe.ts
|
|
712
710
|
function probeCliPath(value) {
|
|
713
711
|
try {
|
|
714
712
|
const stat = statSync(value, { throwIfNoEntry: false });
|
|
@@ -718,8 +716,7 @@ function probeCliPath(value) {
|
|
|
718
716
|
return "missing";
|
|
719
717
|
}
|
|
720
718
|
}
|
|
721
|
-
|
|
722
|
-
//#region ../cli-kit/src/run.ts
|
|
719
|
+
// ../cli-kit/src/run.ts
|
|
723
720
|
function classifyWithHook(error, verbose, hook) {
|
|
724
721
|
const classified = classifyThrown(error, verbose);
|
|
725
722
|
const worded = hook?.(error);
|
|
@@ -873,8 +870,7 @@ const log = {
|
|
|
873
870
|
current.debug(message);
|
|
874
871
|
}
|
|
875
872
|
};
|
|
876
|
-
|
|
877
|
-
//#region ../forgejo/src/connection.ts
|
|
873
|
+
// ../forgejo/src/connection.ts
|
|
878
874
|
function parseGitUrl(urlStr) {
|
|
879
875
|
try {
|
|
880
876
|
const url = new URL(urlStr);
|
|
@@ -1001,14 +997,12 @@ function normalizeGitUrl(raw) {
|
|
|
1001
997
|
return null;
|
|
1002
998
|
}
|
|
1003
999
|
}
|
|
1004
|
-
|
|
1005
|
-
//#region src/describe-forge-error.ts
|
|
1000
|
+
// src/describe-forge-error.ts
|
|
1006
1001
|
function describeForgeError(error) {
|
|
1007
1002
|
if (error instanceof RepoTargetEmptyError) return "--repo was given with no repository URL (expected e.g. https://host/owner/repo).";
|
|
1008
1003
|
if (error instanceof RepoTargetMismatchError) return `--repo disagrees with the issue URL: --repo names ${error.given}, the issue URL names ${error.fromReference}.`;
|
|
1009
1004
|
}
|
|
1010
|
-
|
|
1011
|
-
//#region ../forgejo/src/fetch-retry.ts
|
|
1005
|
+
// ../forgejo/src/fetch-retry.ts
|
|
1012
1006
|
const DEFAULT_RETRY_POLICY = {
|
|
1013
1007
|
attempts: 5,
|
|
1014
1008
|
baseDelayMs: 250,
|
|
@@ -1065,28 +1059,29 @@ function fetchWithRetry(fetchImpl, policy = DEFAULT_RETRY_POLICY, defaultTimeout
|
|
|
1065
1059
|
function createForgeFetcher(policy = DEFAULT_RETRY_POLICY) {
|
|
1066
1060
|
return { fetch: fetchWithRetry((input, init) => globalThis.fetch(input, init), policy) };
|
|
1067
1061
|
}
|
|
1068
|
-
|
|
1069
|
-
//#region src/fetcher.ts
|
|
1062
|
+
// src/fetcher.ts
|
|
1070
1063
|
function cliFetcher() {
|
|
1071
1064
|
return createForgeFetcher();
|
|
1072
1065
|
}
|
|
1073
|
-
|
|
1074
|
-
//#region ../forgejo/src/errors.ts
|
|
1066
|
+
// ../forgejo/src/errors.ts
|
|
1075
1067
|
var ForgeAccessError = class extends FatalError {};
|
|
1076
|
-
function authHeaders
|
|
1068
|
+
function authHeaders(conn) {
|
|
1077
1069
|
return { Authorization: `token ${conn.token}` };
|
|
1078
1070
|
}
|
|
1079
1071
|
function jsonHeaders(conn) {
|
|
1080
1072
|
return {
|
|
1081
|
-
...authHeaders
|
|
1073
|
+
...authHeaders(conn),
|
|
1082
1074
|
"Content-Type": "application/json"
|
|
1083
1075
|
};
|
|
1084
1076
|
}
|
|
1085
1077
|
function repoNotFoundMessage(conn) {
|
|
1086
1078
|
return `Repository ${conn.repository} not found (or the token cannot see it)`;
|
|
1087
1079
|
}
|
|
1080
|
+
function repoBase(conn) {
|
|
1081
|
+
return `${conn.serverUrl}/api/v1/repos/${conn.repository}`;
|
|
1082
|
+
}
|
|
1088
1083
|
function issuesBase(conn) {
|
|
1089
|
-
return `${conn
|
|
1084
|
+
return `${repoBase(conn)}/issues`;
|
|
1090
1085
|
}
|
|
1091
1086
|
function issueNotFoundMessage(conn, number) {
|
|
1092
1087
|
return `Issue #${String(number)} not found in ${conn.repository}`;
|
|
@@ -1165,8 +1160,7 @@ async function throwForgejoFailure(res, operation, notFoundMessage) {
|
|
|
1165
1160
|
if (res.status === 410) throw new FatalError(`${message}\nForgejo returned 410 Gone -- issues are likely disabled on this repository; retrying will not help.`);
|
|
1166
1161
|
throw new TransientError(message);
|
|
1167
1162
|
}
|
|
1168
|
-
|
|
1169
|
-
//#region ../forgejo/src/commit-status.ts
|
|
1163
|
+
// ../forgejo/src/commit-status.ts
|
|
1170
1164
|
const CombinedStatusSchema = z.object({
|
|
1171
1165
|
state: z.string(),
|
|
1172
1166
|
statuses: z.array(z.unknown())
|
|
@@ -1286,18 +1280,12 @@ z.object({
|
|
|
1286
1280
|
created: z.string()
|
|
1287
1281
|
});
|
|
1288
1282
|
z.array(z.unknown());
|
|
1289
|
-
function repoBase$1(conn) {
|
|
1290
|
-
return `${conn.serverUrl}/api/v1/repos/${conn.repository}`;
|
|
1291
|
-
}
|
|
1292
|
-
function authHeaders$1(conn) {
|
|
1293
|
-
return { Authorization: `token ${conn.token}` };
|
|
1294
|
-
}
|
|
1295
1283
|
function branchNotFoundMessage(conn, branch) {
|
|
1296
1284
|
return `Branch ${branch} not found in ${conn.repository}`;
|
|
1297
1285
|
}
|
|
1298
1286
|
async function getBranchHeadSha(executor, conn, branch) {
|
|
1299
|
-
const url = `${repoBase
|
|
1300
|
-
const res = await executor.fetch(url, { headers: authHeaders
|
|
1287
|
+
const url = `${repoBase(conn)}/branches/${encodeURIComponent(branch)}`;
|
|
1288
|
+
const res = await executor.fetch(url, { headers: authHeaders(conn) });
|
|
1301
1289
|
if (!res.ok) await throwForgejoFailure(res, {
|
|
1302
1290
|
verb: "read branch",
|
|
1303
1291
|
resource: branch
|
|
@@ -1307,8 +1295,8 @@ async function getBranchHeadSha(executor, conn, branch) {
|
|
|
1307
1295
|
return parsed.data.commit.id;
|
|
1308
1296
|
}
|
|
1309
1297
|
async function branchExists(executor, conn, branch) {
|
|
1310
|
-
const url = `${repoBase
|
|
1311
|
-
const res = await executor.fetch(url, { headers: authHeaders
|
|
1298
|
+
const url = `${repoBase(conn)}/branches/${encodeURIComponent(branch)}`;
|
|
1299
|
+
const res = await executor.fetch(url, { headers: authHeaders(conn) });
|
|
1312
1300
|
if (res.status === 404) return false;
|
|
1313
1301
|
if (!res.ok) await throwForgejoFailure(res, {
|
|
1314
1302
|
verb: "check branch",
|
|
@@ -1316,8 +1304,7 @@ async function branchExists(executor, conn, branch) {
|
|
|
1316
1304
|
}, branchNotFoundMessage(conn, branch));
|
|
1317
1305
|
return true;
|
|
1318
1306
|
}
|
|
1319
|
-
|
|
1320
|
-
//#region ../cli-kit/src/git.ts
|
|
1307
|
+
// ../cli-kit/src/git.ts
|
|
1321
1308
|
const BRANCH_REF_PREFIX = "refs/heads/";
|
|
1322
1309
|
const ORIGIN_READ_TIMEOUT_MS = 5e3;
|
|
1323
1310
|
function defaultGitRunner(args, cwd, options) {
|
|
@@ -1380,8 +1367,7 @@ function readPackageRepositoryUrl(cwd) {
|
|
|
1380
1367
|
if (!repo) return null;
|
|
1381
1368
|
return typeof repo === "string" ? repo : repo.url;
|
|
1382
1369
|
}
|
|
1383
|
-
|
|
1384
|
-
//#region src/connection.ts
|
|
1370
|
+
// src/connection.ts
|
|
1385
1371
|
function resolveRepoUrl(cwd) {
|
|
1386
1372
|
return resolveRepoUrlFrom(() => readOriginUrl(cwd), () => readPackageRepositoryUrl(cwd));
|
|
1387
1373
|
}
|
|
@@ -1403,8 +1389,7 @@ function requireForgejoTarget(cwd, target, githubRefusal, env = process.env) {
|
|
|
1403
1389
|
if (conn === null) throw new FatalError(githubRefusal);
|
|
1404
1390
|
return conn;
|
|
1405
1391
|
}
|
|
1406
|
-
|
|
1407
|
-
//#region ../forgejo/src/check-poll.ts
|
|
1392
|
+
// ../forgejo/src/check-poll.ts
|
|
1408
1393
|
function classifyBaseStatus(checks) {
|
|
1409
1394
|
if (!checks.parsed) return "unparseable";
|
|
1410
1395
|
if (checks.contexts.length === 0) return "no-status";
|
|
@@ -1441,17 +1426,67 @@ async function readPollChecks(fetcher, conn, sha) {
|
|
|
1441
1426
|
return { failureDetail: describeError(error) };
|
|
1442
1427
|
}
|
|
1443
1428
|
}
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
const
|
|
1447
|
-
const
|
|
1448
|
-
|
|
1429
|
+
async function settleChecks(fetcher, conn, poll, round) {
|
|
1430
|
+
const { timeoutMs, intervalMs, sleep, now } = poll;
|
|
1431
|
+
const startedAt = now();
|
|
1432
|
+
const elapsed = () => now() - startedAt;
|
|
1433
|
+
let consecutiveFailures = 0;
|
|
1434
|
+
let lastFailureDetail;
|
|
1435
|
+
let lastGoodChecks;
|
|
1436
|
+
let previousSettledContexts = null;
|
|
1437
|
+
for (;;) {
|
|
1438
|
+
const sha = round.sha();
|
|
1439
|
+
const { checks, failureDetail } = await readPollChecks(fetcher, conn, sha);
|
|
1440
|
+
if (failureDetail !== void 0) lastFailureDetail = failureDetail;
|
|
1441
|
+
if (checks === void 0) {
|
|
1442
|
+
consecutiveFailures += 1;
|
|
1443
|
+
if (consecutiveFailures >= 3) return round.report(EMPTY_CHECKS, {
|
|
1444
|
+
exit: "retry-budget",
|
|
1445
|
+
elapsed,
|
|
1446
|
+
failureDetail: lastFailureDetail
|
|
1447
|
+
});
|
|
1448
|
+
} else {
|
|
1449
|
+
consecutiveFailures = 0;
|
|
1450
|
+
lastGoodChecks = checks;
|
|
1451
|
+
pushDisagreementNotice(round.notices, sha, checks);
|
|
1452
|
+
if (isSettled(checks)) {
|
|
1453
|
+
const contexts = new Set(checks.contexts.map((check) => check.context));
|
|
1454
|
+
if (previousSettledContexts !== null && previousSettledContexts.size === contexts.size && [...previousSettledContexts].every((context) => contexts.has(context))) return round.report(checks, {
|
|
1455
|
+
exit: "settled",
|
|
1456
|
+
elapsed
|
|
1457
|
+
});
|
|
1458
|
+
previousSettledContexts = contexts;
|
|
1459
|
+
} else previousSettledContexts = null;
|
|
1460
|
+
}
|
|
1461
|
+
if (elapsed() >= timeoutMs) return round.report(lastGoodChecks ?? EMPTY_CHECKS, {
|
|
1462
|
+
exit: "timeout",
|
|
1463
|
+
elapsed
|
|
1464
|
+
});
|
|
1465
|
+
await sleep(intervalMs);
|
|
1466
|
+
if (round.afterSleep !== void 0) {
|
|
1467
|
+
const after = await round.afterSleep(sha, elapsed);
|
|
1468
|
+
if (after !== "retry" && after !== "next") return after.done;
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
function renderCheckLine(check) {
|
|
1473
|
+
const parts = [check.state, check.context];
|
|
1474
|
+
if (check.description !== null) parts.push(check.description);
|
|
1475
|
+
let line = parts.join(" -- ");
|
|
1476
|
+
if (check.verdict === "red" && check.targetUrl !== null) line += ` (${check.targetUrl})`;
|
|
1477
|
+
return line;
|
|
1478
|
+
}
|
|
1479
|
+
// ../cli-kit/src/env-override.ts
|
|
1449
1480
|
function envMsOverride(raw, productionMs) {
|
|
1450
1481
|
if (raw === void 0) return productionMs;
|
|
1451
1482
|
const parsed = Number(raw.trim());
|
|
1452
1483
|
if (!Number.isSafeInteger(parsed) || parsed <= 0) return productionMs;
|
|
1453
1484
|
return Math.min(parsed, productionMs);
|
|
1454
1485
|
}
|
|
1486
|
+
// src/poll-timings.ts
|
|
1487
|
+
const DEFAULT_TIMEOUT_MS = 12e5;
|
|
1488
|
+
const DEFAULT_INTERVAL_MS = 15e3;
|
|
1489
|
+
const MIN_INTERVAL_MS = 5e3;
|
|
1455
1490
|
function resolvePollTimings(options) {
|
|
1456
1491
|
const timeoutMs = options.timeout !== void 0 ? parseDuration(options.timeout, "--timeout") : DEFAULT_TIMEOUT_MS;
|
|
1457
1492
|
const requestedIntervalMs = options.interval !== void 0 ? parseDuration(options.interval, "--interval") : DEFAULT_INTERVAL_MS;
|
|
@@ -1460,15 +1495,13 @@ function resolvePollTimings(options) {
|
|
|
1460
1495
|
intervalMs: envMsOverride(process.env["BST_TEST_CHECK_POLL_INTERVAL_MS"], Math.max(requestedIntervalMs, MIN_INTERVAL_MS))
|
|
1461
1496
|
};
|
|
1462
1497
|
}
|
|
1463
|
-
|
|
1464
|
-
//#region src/sleep.ts
|
|
1498
|
+
// src/sleep.ts
|
|
1465
1499
|
function sleep(ms) {
|
|
1466
1500
|
return new Promise((resolve) => {
|
|
1467
1501
|
setTimeout(resolve, ms);
|
|
1468
1502
|
});
|
|
1469
1503
|
}
|
|
1470
|
-
|
|
1471
|
-
//#region src/commit-status.ts
|
|
1504
|
+
// src/commit-status.ts
|
|
1472
1505
|
async function resolveCommitStatusTarget(fetcher, options) {
|
|
1473
1506
|
const targetRepo = parseRepoTarget(options.repo);
|
|
1474
1507
|
const conn = requireForgejoTarget(options.cwd, targetRepo, "commit:status is Forgejo-only: GitHub Actions publishes check runs, not commit statuses. Use `gh run list` / `gh run view` instead.");
|
|
@@ -1528,47 +1561,23 @@ function buildReport$1(target, checks, ctx, extras = {}) {
|
|
|
1528
1561
|
return report;
|
|
1529
1562
|
}
|
|
1530
1563
|
async function waitForSettledChecks$1(fetcher, target, notices, poll) {
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
consecutiveFailures += 1;
|
|
1543
|
-
if (consecutiveFailures >= 3) return buildReport$1(target, EMPTY_CHECKS, {
|
|
1564
|
+
return settleChecks(fetcher, target.conn, poll, {
|
|
1565
|
+
sha: () => target.sha,
|
|
1566
|
+
notices,
|
|
1567
|
+
report: (checks, extras) => {
|
|
1568
|
+
const extrasForReport = {};
|
|
1569
|
+
if (extras.exit === "timeout") extrasForReport.statusOverride = "timeout";
|
|
1570
|
+
else if (extras.exit === "retry-budget") {
|
|
1571
|
+
extrasForReport.statusOverride = "unparseable";
|
|
1572
|
+
if (extras.failureDetail !== void 0) extrasForReport.detailOverride = extras.failureDetail;
|
|
1573
|
+
}
|
|
1574
|
+
return buildReport$1(target, checks, {
|
|
1544
1575
|
notices,
|
|
1545
1576
|
waited: true,
|
|
1546
|
-
elapsedMs:
|
|
1547
|
-
},
|
|
1548
|
-
statusOverride: "unparseable",
|
|
1549
|
-
detailOverride: lastFailureDetail
|
|
1550
|
-
});
|
|
1551
|
-
} else {
|
|
1552
|
-
consecutiveFailures = 0;
|
|
1553
|
-
lastGoodChecks = checks;
|
|
1554
|
-
pushDisagreementNotice(notices, sha, checks);
|
|
1555
|
-
if (isSettled(checks)) {
|
|
1556
|
-
const contexts = new Set(checks.contexts.map((check) => check.context));
|
|
1557
|
-
if (previousSettledContexts !== null && previousSettledContexts.size === contexts.size && [...previousSettledContexts].every((context) => contexts.has(context))) return buildReport$1(target, checks, {
|
|
1558
|
-
notices,
|
|
1559
|
-
waited: true,
|
|
1560
|
-
elapsedMs: now() - startedAt
|
|
1561
|
-
});
|
|
1562
|
-
previousSettledContexts = contexts;
|
|
1563
|
-
} else previousSettledContexts = null;
|
|
1577
|
+
elapsedMs: extras.elapsed()
|
|
1578
|
+
}, extrasForReport);
|
|
1564
1579
|
}
|
|
1565
|
-
|
|
1566
|
-
notices,
|
|
1567
|
-
waited: true,
|
|
1568
|
-
elapsedMs: now() - startedAt
|
|
1569
|
-
}, { statusOverride: "timeout" });
|
|
1570
|
-
await sleep(intervalMs);
|
|
1571
|
-
}
|
|
1580
|
+
});
|
|
1572
1581
|
}
|
|
1573
1582
|
async function runCommitStatus(fetcher, options) {
|
|
1574
1583
|
const timings = options.wait === true ? resolvePollTimings(options) : void 0;
|
|
@@ -1588,13 +1597,7 @@ async function runCommitStatus(fetcher, options) {
|
|
|
1588
1597
|
});
|
|
1589
1598
|
}
|
|
1590
1599
|
function renderCommitStatus(report) {
|
|
1591
|
-
const lines = report.checks.map(
|
|
1592
|
-
const parts = [check.state, check.context];
|
|
1593
|
-
if (check.description !== null) parts.push(check.description);
|
|
1594
|
-
let line = parts.join(" -- ");
|
|
1595
|
-
if (check.verdict === "red" && check.targetUrl !== null) line += ` (${check.targetUrl})`;
|
|
1596
|
-
return line;
|
|
1597
|
-
});
|
|
1600
|
+
const lines = report.checks.map(renderCheckLine);
|
|
1598
1601
|
const shortSha = FULL_SHA.test(report.sha) ? report.sha.slice(0, 12) : report.sha;
|
|
1599
1602
|
const redCount = report.checks.filter((c) => c.verdict === "red").length;
|
|
1600
1603
|
const pendingCount = report.checks.filter((c) => c.verdict === "pending").length;
|
|
@@ -1608,8 +1611,7 @@ function renderCommitStatus(report) {
|
|
|
1608
1611
|
lines.push(summaryParts.join(" -- "));
|
|
1609
1612
|
return lines.join("\n");
|
|
1610
1613
|
}
|
|
1611
|
-
|
|
1612
|
-
//#region src/commands/commit-status.ts
|
|
1614
|
+
// src/commands/commit-status.ts
|
|
1613
1615
|
const commitStatusCommand = defineCommand({
|
|
1614
1616
|
meta: {
|
|
1615
1617
|
name: "commit:status",
|
|
@@ -1663,8 +1665,7 @@ const commitStatusCommand = defineCommand({
|
|
|
1663
1665
|
process.exitCode = report.status === "green" ? 0 : 1;
|
|
1664
1666
|
}
|
|
1665
1667
|
});
|
|
1666
|
-
|
|
1667
|
-
//#region ../forgejo/src/fetcher.ts
|
|
1668
|
+
// ../forgejo/src/fetcher.ts
|
|
1668
1669
|
const LONG_FETCH_TIMEOUT_MS = 6e5;
|
|
1669
1670
|
function morePagesFollow(res, pageLength, received, pageSize) {
|
|
1670
1671
|
if (pageLength === 0) return false;
|
|
@@ -1673,8 +1674,7 @@ function morePagesFollow(res, pageLength, received, pageSize) {
|
|
|
1673
1674
|
if (!Number.isSafeInteger(total) || total < 0) return pageLength >= pageSize;
|
|
1674
1675
|
return received < total;
|
|
1675
1676
|
}
|
|
1676
|
-
|
|
1677
|
-
//#region ../forgejo/src/label-provisioning.ts
|
|
1677
|
+
// ../forgejo/src/label-provisioning.ts
|
|
1678
1678
|
const LabelSchema = z.object({
|
|
1679
1679
|
id: z.number(),
|
|
1680
1680
|
name: z.string(),
|
|
@@ -1688,7 +1688,7 @@ const LABELS_MAX_PAGES = 20;
|
|
|
1688
1688
|
async function fetchAllForgejoLabels(executor, conn) {
|
|
1689
1689
|
const labels = [];
|
|
1690
1690
|
for (let page = 1; page <= LABELS_MAX_PAGES; page++) {
|
|
1691
|
-
const res = await executor.fetch(`${conn.serverUrl}/api/v1/repos/${conn.repository}/labels?limit=${String(LABELS_PAGE_SIZE)}&page=${String(page)}`, { headers: authHeaders
|
|
1691
|
+
const res = await executor.fetch(`${conn.serverUrl}/api/v1/repos/${conn.repository}/labels?limit=${String(LABELS_PAGE_SIZE)}&page=${String(page)}`, { headers: authHeaders(conn) });
|
|
1692
1692
|
if (!res.ok) await throwForgejoFailure(res, {
|
|
1693
1693
|
verb: "list labels",
|
|
1694
1694
|
resource: conn.repository
|
|
@@ -1712,6 +1712,17 @@ async function resolveLabelIds(executor, conn, names) {
|
|
|
1712
1712
|
return match.id;
|
|
1713
1713
|
});
|
|
1714
1714
|
}
|
|
1715
|
+
function isRetiringExpired(spec, today) {
|
|
1716
|
+
return today > spec.until;
|
|
1717
|
+
}
|
|
1718
|
+
function retiringAsLabelSpec(spec) {
|
|
1719
|
+
return {
|
|
1720
|
+
name: spec.name,
|
|
1721
|
+
color: spec.color,
|
|
1722
|
+
description: spec.description,
|
|
1723
|
+
exclusive: false
|
|
1724
|
+
};
|
|
1725
|
+
}
|
|
1715
1726
|
const LabelSpecSchema = z.strictObject({
|
|
1716
1727
|
name: z.string().min(1),
|
|
1717
1728
|
color: z.string().regex(/^#[0-9a-fA-F]{6}$/),
|
|
@@ -1761,13 +1772,14 @@ function labelScope(name) {
|
|
|
1761
1772
|
const slash = name.indexOf("/");
|
|
1762
1773
|
return slash === -1 ? null : name.slice(0, slash + 1);
|
|
1763
1774
|
}
|
|
1764
|
-
function staleLabelNames(specs, live) {
|
|
1775
|
+
function staleLabelNames(specs, live, retiring = []) {
|
|
1765
1776
|
const owned = /* @__PURE__ */ new Set();
|
|
1766
1777
|
for (const spec of specs) {
|
|
1767
1778
|
const scope = labelScope(spec.name);
|
|
1768
1779
|
if (scope !== null) owned.add(scope);
|
|
1769
1780
|
}
|
|
1770
1781
|
const wanted = new Set(specs.map((spec) => spec.name));
|
|
1782
|
+
for (const spec of retiring) wanted.add(spec.name);
|
|
1771
1783
|
const stale = [];
|
|
1772
1784
|
for (const name of live) {
|
|
1773
1785
|
if (wanted.has(name)) continue;
|
|
@@ -1828,15 +1840,14 @@ async function ensureForgejoLabels(executor, conn, specs) {
|
|
|
1828
1840
|
async function deleteForgejoLabel(executor, conn, id) {
|
|
1829
1841
|
const res = await executor.fetch(`${conn.serverUrl}/api/v1/repos/${conn.repository}/labels/${String(id)}`, {
|
|
1830
1842
|
method: "DELETE",
|
|
1831
|
-
headers: authHeaders
|
|
1843
|
+
headers: authHeaders(conn)
|
|
1832
1844
|
}, { idempotent: true });
|
|
1833
1845
|
if (!res.ok) await throwForgejoFailure(res, {
|
|
1834
1846
|
verb: "delete label",
|
|
1835
1847
|
resource: String(id)
|
|
1836
1848
|
}, repoNotFoundMessage(conn));
|
|
1837
1849
|
}
|
|
1838
|
-
|
|
1839
|
-
//#region ../forgejo/src/issues.ts
|
|
1850
|
+
// ../forgejo/src/issues.ts
|
|
1840
1851
|
const IssueResponseSchema = z.object({
|
|
1841
1852
|
number: z.number(),
|
|
1842
1853
|
title: z.string(),
|
|
@@ -1881,7 +1892,7 @@ function normalizeIssue(raw) {
|
|
|
1881
1892
|
};
|
|
1882
1893
|
}
|
|
1883
1894
|
async function getForgejoIssue(executor, conn, number) {
|
|
1884
|
-
const res = await executor.fetch(`${issuesBase(conn)}/${String(number)}`, { headers: authHeaders
|
|
1895
|
+
const res = await executor.fetch(`${issuesBase(conn)}/${String(number)}`, { headers: authHeaders(conn) });
|
|
1885
1896
|
if (!res.ok) await throwForgejoFailure(res, {
|
|
1886
1897
|
verb: "get issue",
|
|
1887
1898
|
resource: `#${String(number)}`
|
|
@@ -1895,17 +1906,19 @@ const DependencyResponseSchema = z.object({
|
|
|
1895
1906
|
});
|
|
1896
1907
|
z.array(DependencyResponseSchema);
|
|
1897
1908
|
function issueListParams(type, query) {
|
|
1898
|
-
const
|
|
1909
|
+
const kind = query.type ?? type;
|
|
1910
|
+
const params = new URLSearchParams(kind === "all" ? {} : { type: kind });
|
|
1899
1911
|
params.set("state", query.state);
|
|
1900
1912
|
params.set("limit", String(query.limit));
|
|
1901
1913
|
if (query.label !== void 0) params.set("labels", query.label);
|
|
1902
1914
|
if (query.page !== void 0) params.set("page", String(query.page));
|
|
1903
1915
|
if (query.since !== void 0) params.set("since", query.since);
|
|
1904
1916
|
if (query.sort !== void 0) params.set("sort", query.sort);
|
|
1917
|
+
if (query.q !== void 0) params.set("q", query.q);
|
|
1905
1918
|
return params;
|
|
1906
1919
|
}
|
|
1907
1920
|
async function fetchIssueListPage(executor, conn, params) {
|
|
1908
|
-
const res = await executor.fetch(`${issuesBase(conn)}?${params.toString()}`, { headers: authHeaders
|
|
1921
|
+
const res = await executor.fetch(`${issuesBase(conn)}?${params.toString()}`, { headers: authHeaders(conn) });
|
|
1909
1922
|
if (!res.ok) await throwForgejoFailure(res, {
|
|
1910
1923
|
verb: "list issues",
|
|
1911
1924
|
resource: conn.repository
|
|
@@ -1939,6 +1952,29 @@ async function listForgejoIssuesDetailedPaged(executor, conn, query, options) {
|
|
|
1939
1952
|
}
|
|
1940
1953
|
return issues;
|
|
1941
1954
|
}
|
|
1955
|
+
async function listOpenObjectsWithLabel(executor, conn, label) {
|
|
1956
|
+
const objects = [];
|
|
1957
|
+
for (let page = 1; page <= DETAILED_LIST_MAX_PAGES; page++) {
|
|
1958
|
+
const { raw } = await fetchIssueListPage(executor, conn, issueListParams("all", {
|
|
1959
|
+
state: "open",
|
|
1960
|
+
label,
|
|
1961
|
+
limit: DETAILED_LIST_PAGE_SIZE,
|
|
1962
|
+
page
|
|
1963
|
+
}));
|
|
1964
|
+
for (const issue of raw.map(normalizeIssue)) {
|
|
1965
|
+
if (!issue.labels.includes(label)) continue;
|
|
1966
|
+
objects.push({
|
|
1967
|
+
number: issue.number,
|
|
1968
|
+
kind: issue.isPullRequest ? "pull" : "issue",
|
|
1969
|
+
title: issue.title,
|
|
1970
|
+
url: issue.url
|
|
1971
|
+
});
|
|
1972
|
+
}
|
|
1973
|
+
if (raw.length === 0) break;
|
|
1974
|
+
if (page === DETAILED_LIST_MAX_PAGES) log.warn(`Open-object listing on ${conn.repository} hit the ${String(DETAILED_LIST_MAX_PAGES)}-page cap without an empty page; results may be truncated`);
|
|
1975
|
+
}
|
|
1976
|
+
return objects;
|
|
1977
|
+
}
|
|
1942
1978
|
const USER_REPOS_PAGE_SIZE = 50;
|
|
1943
1979
|
const USER_REPOS_MAX_PAGES = 20;
|
|
1944
1980
|
const UserRepoSchema = z.object({
|
|
@@ -2030,8 +2066,7 @@ async function setForgejoIssueState(executor, conn, number, state) {
|
|
|
2030
2066
|
}, issueNotFoundMessage(conn, number));
|
|
2031
2067
|
return normalizeIssue(parseIssueOrThrow(await res.json()));
|
|
2032
2068
|
}
|
|
2033
|
-
|
|
2034
|
-
//#region ../forgejo/src/label-sync.ts
|
|
2069
|
+
// ../forgejo/src/label-sync.ts
|
|
2035
2070
|
function resolveSyncMode(check, dryRun) {
|
|
2036
2071
|
if (check) return "check";
|
|
2037
2072
|
if (dryRun) return "dry-run";
|
|
@@ -2059,24 +2094,77 @@ function outcomeFromAudit(conn, specs, audit, lists) {
|
|
|
2059
2094
|
...lists
|
|
2060
2095
|
};
|
|
2061
2096
|
}
|
|
2097
|
+
async function checkPruneCandidate(fetcher, conn, name) {
|
|
2098
|
+
let objects;
|
|
2099
|
+
try {
|
|
2100
|
+
objects = await listOpenObjectsWithLabel(fetcher, conn, name);
|
|
2101
|
+
} catch (error) {
|
|
2102
|
+
return {
|
|
2103
|
+
ok: false,
|
|
2104
|
+
reason: `could not check open objects: ${describeError(error)}`,
|
|
2105
|
+
objects: []
|
|
2106
|
+
};
|
|
2107
|
+
}
|
|
2108
|
+
if (objects.length === 0) return { ok: true };
|
|
2109
|
+
return {
|
|
2110
|
+
ok: false,
|
|
2111
|
+
reason: `on ${String(objects.length)} open object(s)`,
|
|
2112
|
+
objects
|
|
2113
|
+
};
|
|
2114
|
+
}
|
|
2062
2115
|
async function syncOneRepo(params) {
|
|
2063
|
-
const { fetcher, conn, specs, mode, prune, allowedPruneNames, resolveTargetSpecs } = params;
|
|
2116
|
+
const { fetcher, conn, specs, mode, prune, allowedPruneNames, resolveTargetSpecs, retiring, today } = params;
|
|
2064
2117
|
const target = resolveTargetSpecs === void 0 ? {
|
|
2065
2118
|
specs,
|
|
2066
2119
|
omitted: [],
|
|
2067
2120
|
aliasNames: []
|
|
2068
2121
|
} : await resolveTargetSpecs(conn, specs);
|
|
2069
|
-
const
|
|
2070
|
-
const
|
|
2071
|
-
const
|
|
2122
|
+
const retiringNames = new Set(retiring.map((spec) => spec.name));
|
|
2123
|
+
const fullAudit = await auditForgejoLabels(fetcher, conn, [...target.specs, ...retiring.map(retiringAsLabelSpec)]);
|
|
2124
|
+
const presentRetiring = retiring.filter((spec) => fullAudit.labelIds.has(spec.name));
|
|
2125
|
+
const audit = {
|
|
2126
|
+
...fullAudit,
|
|
2127
|
+
missing: fullAudit.missing.filter((name) => !retiringNames.has(name))
|
|
2128
|
+
};
|
|
2129
|
+
const stale = staleLabelNames(specs, audit.labelIds.keys(), retiring).filter((name) => !target.aliasNames.includes(name));
|
|
2130
|
+
const expiredRetiring = presentRetiring.filter((spec) => isRetiringExpired(spec, today)).map((spec) => spec.name);
|
|
2131
|
+
const pruneCandidates = prune ? [
|
|
2132
|
+
...target.omitted,
|
|
2133
|
+
...stale,
|
|
2134
|
+
...expiredRetiring
|
|
2135
|
+
].filter((name) => audit.labelIds.has(name) && (allowedPruneNames === void 0 || allowedPruneNames.includes(name))) : [];
|
|
2136
|
+
const pruned = [];
|
|
2137
|
+
const refused = [];
|
|
2138
|
+
for (const name of pruneCandidates) {
|
|
2139
|
+
const verdict = await checkPruneCandidate(fetcher, conn, name);
|
|
2140
|
+
if (verdict.ok) {
|
|
2141
|
+
pruned.push(name);
|
|
2142
|
+
continue;
|
|
2143
|
+
}
|
|
2144
|
+
refused.push({
|
|
2145
|
+
name,
|
|
2146
|
+
reason: verdict.reason,
|
|
2147
|
+
objects: verdict.objects
|
|
2148
|
+
});
|
|
2149
|
+
}
|
|
2150
|
+
const retiringReports = [];
|
|
2151
|
+
for (const spec of presentRetiring) retiringReports.push({
|
|
2152
|
+
name: spec.name,
|
|
2153
|
+
replacement: spec.replacement,
|
|
2154
|
+
until: spec.until,
|
|
2155
|
+
expired: isRetiringExpired(spec, today),
|
|
2156
|
+
openObjects: await listOpenObjectsWithLabel(fetcher, conn, spec.name)
|
|
2157
|
+
});
|
|
2072
2158
|
const outcome = outcomeFromAudit(conn, target.specs, audit, {
|
|
2073
2159
|
omitted: target.omitted,
|
|
2074
|
-
pruned
|
|
2075
|
-
stale: prune ? stale.filter((name) => !pruneCandidates.includes(name)) : stale
|
|
2160
|
+
pruned,
|
|
2161
|
+
stale: prune ? stale.filter((name) => !pruneCandidates.includes(name)) : stale,
|
|
2162
|
+
retiring: retiringReports,
|
|
2163
|
+
refused
|
|
2076
2164
|
});
|
|
2077
2165
|
if (mode === "apply") {
|
|
2078
|
-
if (outcome.created.length > 0 || outcome.updated.length > 0) await ensureForgejoLabels(fetcher, conn, target.specs);
|
|
2079
|
-
for (const name of
|
|
2166
|
+
if (outcome.created.length > 0 || outcome.updated.length > 0) await ensureForgejoLabels(fetcher, conn, [...target.specs, ...presentRetiring.map(retiringAsLabelSpec)]);
|
|
2167
|
+
for (const name of pruned) {
|
|
2080
2168
|
const id = audit.labelIds.get(name);
|
|
2081
2169
|
if (id === void 0) throw new UnexpectedError(`Prune candidate "${name}" had no known id after the audit`);
|
|
2082
2170
|
await deleteForgejoLabel(fetcher, conn, id);
|
|
@@ -2086,6 +2174,9 @@ async function syncOneRepo(params) {
|
|
|
2086
2174
|
}
|
|
2087
2175
|
async function syncLabelSet(params) {
|
|
2088
2176
|
const { fetcher, targets, specs, setName, mode, contained, prune, pruneAllowlist } = params;
|
|
2177
|
+
const retiring = params.retiring ?? [];
|
|
2178
|
+
const today = params.today ?? "";
|
|
2179
|
+
if (retiring.length > 0 && params.today === void 0) throw new UnexpectedError("syncLabelSet was given retiring label specs but no `today` to compare their expiry against: an expired entry is a prune candidate, and a guessed date could delete a name whose retirement window is still open.");
|
|
2089
2180
|
const specList = [...specs];
|
|
2090
2181
|
const repos = [];
|
|
2091
2182
|
const failures = [];
|
|
@@ -2098,7 +2189,9 @@ async function syncLabelSet(params) {
|
|
|
2098
2189
|
mode,
|
|
2099
2190
|
prune: prune === true,
|
|
2100
2191
|
allowedPruneNames,
|
|
2101
|
-
resolveTargetSpecs: params.resolveTargetSpecs
|
|
2192
|
+
resolveTargetSpecs: params.resolveTargetSpecs,
|
|
2193
|
+
retiring,
|
|
2194
|
+
today
|
|
2102
2195
|
};
|
|
2103
2196
|
if (contained !== true) {
|
|
2104
2197
|
repos.push(await syncOneRepo(syncOneRepoParams));
|
|
@@ -2131,6 +2224,11 @@ function syncSummaryLines(result) {
|
|
|
2131
2224
|
if (repo.omitted.length > 0) actions.push(`omitted (repo declares its own priority vocabulary): ${repo.omitted.join(", ")}`);
|
|
2132
2225
|
if (repo.pruned.length > 0) actions.push(`${verb}prune: ${repo.pruned.join(", ")}`);
|
|
2133
2226
|
if (repo.stale.length > 0) actions.push(`stale (present, not in this set): ${repo.stale.join(", ")}`);
|
|
2227
|
+
for (const refusal of repo.refused) {
|
|
2228
|
+
const objects = refusal.objects.map((object) => `#${String(object.number)} (${object.kind}) ${object.title}`).join(", ");
|
|
2229
|
+
actions.push(`refused to prune ${refusal.name}: ${refusal.reason}${objects === "" ? "" : ` (${objects})`}`);
|
|
2230
|
+
}
|
|
2231
|
+
for (const retiring of repo.retiring) actions.push(`retiring ${retiring.name}: replaced by ${retiring.replacement}, prunable after ${retiring.until}${retiring.expired ? " (expired)" : ""}; ${String(retiring.openObjects.length)} open object(s)`);
|
|
2134
2232
|
if (actions.length === 0) {
|
|
2135
2233
|
repoLines.push(`${repo.repository}: up to date (${String(repo.unchanged.length)} unchanged)`);
|
|
2136
2234
|
continue;
|
|
@@ -2142,8 +2240,7 @@ function syncSummaryLines(result) {
|
|
|
2142
2240
|
failureLines: result.failures.map((failure) => `${failure.repository}: failed: ${failure.error}`)
|
|
2143
2241
|
};
|
|
2144
2242
|
}
|
|
2145
|
-
|
|
2146
|
-
//#region src/label-sets-file.ts
|
|
2243
|
+
// src/label-sets-file.ts
|
|
2147
2244
|
function readLabelSet(path, setName) {
|
|
2148
2245
|
let raw;
|
|
2149
2246
|
try {
|
|
@@ -2170,8 +2267,7 @@ function readLabelSet(path, setName) {
|
|
|
2170
2267
|
}
|
|
2171
2268
|
return specs;
|
|
2172
2269
|
}
|
|
2173
|
-
|
|
2174
|
-
//#region src/labels.ts
|
|
2270
|
+
// src/labels.ts
|
|
2175
2271
|
async function runLabelsList(fetcher, conn) {
|
|
2176
2272
|
const labels = await fetchAllForgejoLabels(fetcher, conn);
|
|
2177
2273
|
return {
|
|
@@ -2205,8 +2301,7 @@ function renderSync(result) {
|
|
|
2205
2301
|
for (const line of repoLines) rootLogger.info(line);
|
|
2206
2302
|
for (const line of failureLines) rootLogger.warn(line);
|
|
2207
2303
|
}
|
|
2208
|
-
|
|
2209
|
-
//#region src/commands/labels.ts
|
|
2304
|
+
// src/commands/labels.ts
|
|
2210
2305
|
const GITHUB_REFUSAL = "bst-fj labels requires a Forgejo repository";
|
|
2211
2306
|
const listCommand$1 = defineCommand({
|
|
2212
2307
|
meta: {
|
|
@@ -2270,7 +2365,7 @@ const syncCommand = defineCommand({
|
|
|
2270
2365
|
},
|
|
2271
2366
|
json: {
|
|
2272
2367
|
type: "boolean",
|
|
2273
|
-
description: "Emit one JSON document: set, mode (apply | check | dry-run), repos ([{repository, created, updated, unchanged, omitted, stale}], every field but repository a list of label names), failures ([{repository, error}]; always present, filled only under --fleet), drifted. drifted is true when any label is missing or drifted, and sets the exit code only under --check."
|
|
2368
|
+
description: "Emit one JSON document: set, mode (apply | check | dry-run), repos ([{repository, created, updated, unchanged, omitted, stale, retiring, refused}], every field but repository and those two a list of label names; retiring and refused are always empty here, since this command never prunes), failures ([{repository, error}]; always present, filled only under --fleet), drifted. drifted is true when any label is missing or drifted, and sets the exit code only under --check."
|
|
2274
2369
|
}
|
|
2275
2370
|
},
|
|
2276
2371
|
async run({ args, rawArgs }) {
|
|
@@ -2313,8 +2408,7 @@ const labelsCommand = defineCommand({
|
|
|
2313
2408
|
sync: syncCommand
|
|
2314
2409
|
}
|
|
2315
2410
|
});
|
|
2316
|
-
|
|
2317
|
-
//#region ../forgejo/src/releases.ts
|
|
2411
|
+
// ../forgejo/src/releases.ts
|
|
2318
2412
|
const SETTLE_ATTEMPTS = 4;
|
|
2319
2413
|
const SETTLE_BASE_DELAY_MS = 2e3;
|
|
2320
2414
|
const SETTLE_MAX_DELAY_MS = 16e3;
|
|
@@ -2536,8 +2630,7 @@ z.looseObject({
|
|
|
2536
2630
|
created: z.string().nullish()
|
|
2537
2631
|
})
|
|
2538
2632
|
});
|
|
2539
|
-
|
|
2540
|
-
//#region src/commands/release-create.ts
|
|
2633
|
+
// src/commands/release-create.ts
|
|
2541
2634
|
const releaseCreateCommand = defineCommand({
|
|
2542
2635
|
meta: {
|
|
2543
2636
|
name: "release:create",
|
|
@@ -2586,8 +2679,7 @@ const releaseCreateCommand = defineCommand({
|
|
|
2586
2679
|
else rootLogger.info(`Created Forgejo release for ${args.tag}`);
|
|
2587
2680
|
}
|
|
2588
2681
|
});
|
|
2589
|
-
|
|
2590
|
-
//#region ../forgejo/src/secrets.ts
|
|
2682
|
+
// ../forgejo/src/secrets.ts
|
|
2591
2683
|
const ActionSecretListSchema = z.array(z.object({ name: z.string() }));
|
|
2592
2684
|
const SECRETS_PAGE_SIZE = 50;
|
|
2593
2685
|
const SECRETS_MAX_PAGES = 20;
|
|
@@ -2643,8 +2735,7 @@ async function deleteActionSecret(executor, conn, secretName) {
|
|
|
2643
2735
|
resource: secretName
|
|
2644
2736
|
}));
|
|
2645
2737
|
}
|
|
2646
|
-
|
|
2647
|
-
//#region src/secrets.ts
|
|
2738
|
+
// src/secrets.ts
|
|
2648
2739
|
async function runSecretsSet(fetcher, config) {
|
|
2649
2740
|
if (!isValidSecretName(config.secretName)) throw new FatalError(`Invalid secret name "${config.secretName}". A name must match [A-Za-z_][A-Za-z0-9_]* and must not start with FORGEJO_, GITEA_, GITHUB_, or a digit.`);
|
|
2650
2741
|
if (config.dryRun) {
|
|
@@ -2686,8 +2777,7 @@ async function runSecretsDelete(fetcher, config) {
|
|
|
2686
2777
|
repository: config.conn.repository
|
|
2687
2778
|
};
|
|
2688
2779
|
}
|
|
2689
|
-
|
|
2690
|
-
//#region src/commands/secrets.ts
|
|
2780
|
+
// src/commands/secrets.ts
|
|
2691
2781
|
function readSecretValue(body) {
|
|
2692
2782
|
if (body) return body;
|
|
2693
2783
|
try {
|
|
@@ -2816,15 +2906,14 @@ const secretsCommand = defineCommand({
|
|
|
2816
2906
|
delete: deleteCommand
|
|
2817
2907
|
}
|
|
2818
2908
|
});
|
|
2819
|
-
|
|
2820
|
-
//#region ../forgejo/src/user.ts
|
|
2909
|
+
// ../forgejo/src/user.ts
|
|
2821
2910
|
const AuthenticatedUserSchema = z.object({
|
|
2822
2911
|
login: z.string(),
|
|
2823
2912
|
email: z.string().nullish()
|
|
2824
2913
|
});
|
|
2825
2914
|
async function getAuthenticatedUser(executor, conn, signal = null) {
|
|
2826
2915
|
const res = await executor.fetch(`${conn.serverUrl}/api/v1/user`, {
|
|
2827
|
-
headers: authHeaders
|
|
2916
|
+
headers: authHeaders(conn),
|
|
2828
2917
|
signal
|
|
2829
2918
|
});
|
|
2830
2919
|
if (!res.ok) return {
|
|
@@ -2840,8 +2929,7 @@ async function getAuthenticatedUser(executor, conn, signal = null) {
|
|
|
2840
2929
|
email: parsed.data.email || null
|
|
2841
2930
|
};
|
|
2842
2931
|
}
|
|
2843
|
-
|
|
2844
|
-
//#region ../forgejo/src/webhooks.ts
|
|
2932
|
+
// ../forgejo/src/webhooks.ts
|
|
2845
2933
|
const WebhookSchema = z.object({
|
|
2846
2934
|
id: z.number(),
|
|
2847
2935
|
type: z.string(),
|
|
@@ -2922,8 +3010,7 @@ async function searchRepos(executor, conn) {
|
|
|
2922
3010
|
return parsed.data.data;
|
|
2923
3011
|
})).map((r) => r.full_name);
|
|
2924
3012
|
}
|
|
2925
|
-
|
|
2926
|
-
//#region src/commands/webhooks.ts
|
|
3013
|
+
// src/commands/webhooks.ts
|
|
2927
3014
|
function collectGroup(label, scopeHint, status) {
|
|
2928
3015
|
if (status.status === "ok") return status.hooks.length > 0 ? {
|
|
2929
3016
|
label,
|
|
@@ -2999,8 +3086,7 @@ const webhooksCommand = defineCommand({
|
|
|
2999
3086
|
renderText(inventory, conn.serverUrl);
|
|
3000
3087
|
}
|
|
3001
3088
|
});
|
|
3002
|
-
|
|
3003
|
-
//#region ../forgejo/src/actions.ts
|
|
3089
|
+
// ../forgejo/src/actions.ts
|
|
3004
3090
|
function forgeTimestamp(value) {
|
|
3005
3091
|
if (value === null || value === void 0 || value === "") return null;
|
|
3006
3092
|
const ms = Date.parse(value);
|
|
@@ -3178,8 +3264,7 @@ async function dispatchWorkflow(executor, conn, options) {
|
|
|
3178
3264
|
inputs: options.inputs
|
|
3179
3265
|
};
|
|
3180
3266
|
}
|
|
3181
|
-
|
|
3182
|
-
//#region ../forgejo/src/actions-log.ts
|
|
3267
|
+
// ../forgejo/src/actions-log.ts
|
|
3183
3268
|
const CSI_SEQUENCE = /\u001b\[[0-?]*[ -/]*[@-~]/gu;
|
|
3184
3269
|
const OSC_SEQUENCE = /\u001b\][^\u0007]*(?:\u0007|\u001b\\)/gu;
|
|
3185
3270
|
const LONE_ESCAPE = /\u001b/gu;
|
|
@@ -3221,8 +3306,7 @@ function readActionsJobLog(text) {
|
|
|
3221
3306
|
lines
|
|
3222
3307
|
};
|
|
3223
3308
|
}
|
|
3224
|
-
|
|
3225
|
-
//#region src/ci-log.ts
|
|
3309
|
+
// src/ci-log.ts
|
|
3226
3310
|
const ACTIONS_RUN_URL = /\/actions\/runs\/(\d+)\/?(?:[?#]|$)/u;
|
|
3227
3311
|
function parseCiLogTarget(target) {
|
|
3228
3312
|
if (/^\d+$/.test(target)) return {
|
|
@@ -3313,8 +3397,7 @@ function renderCiLog(result) {
|
|
|
3313
3397
|
for (const line of result.lines) lines.push(line.at === null ? line.text : `${line.at} ${line.text}`);
|
|
3314
3398
|
return lines.join("\n");
|
|
3315
3399
|
}
|
|
3316
|
-
|
|
3317
|
-
//#region src/commands/ci-log.ts
|
|
3400
|
+
// src/commands/ci-log.ts
|
|
3318
3401
|
const ciLogCommand = defineCommand({
|
|
3319
3402
|
meta: {
|
|
3320
3403
|
name: "ci:log",
|
|
@@ -3368,13 +3451,7 @@ const ciLogCommand = defineCommand({
|
|
|
3368
3451
|
out.text(renderCiLog(result));
|
|
3369
3452
|
}
|
|
3370
3453
|
});
|
|
3371
|
-
|
|
3372
|
-
//#region src/ci-runs.ts
|
|
3373
|
-
function parseLimit$2(raw) {
|
|
3374
|
-
const limit = Number(raw);
|
|
3375
|
-
if (!Number.isInteger(limit) || limit < 1) throw new FatalError(`Invalid --limit "${raw}" (expected a positive integer).`);
|
|
3376
|
-
return limit;
|
|
3377
|
-
}
|
|
3454
|
+
// src/ci-runs.ts
|
|
3378
3455
|
function resolveRunsRef(ref, pr) {
|
|
3379
3456
|
if (ref !== void 0 && pr !== void 0) throw new FatalError("--ref and --pr are the same filter -- give one of them (--pr 273 for a pull request's own runs, --ref main for a branch's).");
|
|
3380
3457
|
if (pr !== void 0) {
|
|
@@ -3399,7 +3476,7 @@ function resolveRunsRef(ref, pr) {
|
|
|
3399
3476
|
};
|
|
3400
3477
|
}
|
|
3401
3478
|
async function runCiRuns(fetcher, options) {
|
|
3402
|
-
const limit =
|
|
3479
|
+
const limit = parseLimitFlag(options.limit);
|
|
3403
3480
|
const resolved = resolveRunsRef(options.ref, options.pr);
|
|
3404
3481
|
const conn = requireForgejoTarget(options.cwd, resolveIssueTarget(resolved.target, options.repo), "ci:runs is Forgejo-only -- gh run list already serves GitHub, first-class. Use that instead.");
|
|
3405
3482
|
rootLogger.debug(`ci:runs repository=${conn.repository} limit=${String(limit)}`);
|
|
@@ -3450,8 +3527,7 @@ function renderCiRuns(result) {
|
|
|
3450
3527
|
}
|
|
3451
3528
|
return lines.join("\n");
|
|
3452
3529
|
}
|
|
3453
|
-
|
|
3454
|
-
//#region src/commands/ci-runs.ts
|
|
3530
|
+
// src/commands/ci-runs.ts
|
|
3455
3531
|
const ciRunsCommand = defineCommand({
|
|
3456
3532
|
meta: {
|
|
3457
3533
|
name: "ci:runs",
|
|
@@ -3516,8 +3592,7 @@ const ciRunsCommand = defineCommand({
|
|
|
3516
3592
|
out.text(renderCiRuns(result));
|
|
3517
3593
|
}
|
|
3518
3594
|
});
|
|
3519
|
-
|
|
3520
|
-
//#region ../cli-kit/src/workflow-inputs.ts
|
|
3595
|
+
// ../cli-kit/src/workflow-inputs.ts
|
|
3521
3596
|
const INPUT_FLAG = "--input";
|
|
3522
3597
|
const INPUT_FLAG_EQ = "--input=";
|
|
3523
3598
|
function collectInputArgs(rawArgs) {
|
|
@@ -3544,8 +3619,7 @@ function parseInputs(raw) {
|
|
|
3544
3619
|
}
|
|
3545
3620
|
return inputs;
|
|
3546
3621
|
}
|
|
3547
|
-
|
|
3548
|
-
//#region src/workflow-dispatch.ts
|
|
3622
|
+
// src/workflow-dispatch.ts
|
|
3549
3623
|
async function runWorkflowDispatch(fetcher, options) {
|
|
3550
3624
|
const dispatched = await dispatchWorkflow(fetcher, requireForgejoTarget(options.cwd, void 0, "workflow:dispatch is Forgejo-only -- use gh workflow run on GitHub."), {
|
|
3551
3625
|
...options.repo === void 0 ? {} : { repository: options.repo },
|
|
@@ -3562,8 +3636,7 @@ async function runWorkflowDispatch(fetcher, options) {
|
|
|
3562
3636
|
inputs: dispatched.inputs
|
|
3563
3637
|
};
|
|
3564
3638
|
}
|
|
3565
|
-
|
|
3566
|
-
//#region src/registry-actions.ts
|
|
3639
|
+
// src/registry-actions.ts
|
|
3567
3640
|
const actionsSubCommands = {
|
|
3568
3641
|
"ci:log": ciLogCommand,
|
|
3569
3642
|
"ci:runs": ciRunsCommand,
|
|
@@ -3632,8 +3705,7 @@ const DirEntrySchema = z.looseObject({
|
|
|
3632
3705
|
type: z.string()
|
|
3633
3706
|
});
|
|
3634
3707
|
z.array(DirEntrySchema);
|
|
3635
|
-
|
|
3636
|
-
//#region ../forgejo/src/branches.ts
|
|
3708
|
+
// ../forgejo/src/branches.ts
|
|
3637
3709
|
const BranchEntrySchema = z.object({
|
|
3638
3710
|
name: z.string(),
|
|
3639
3711
|
protected: z.boolean().optional(),
|
|
@@ -3644,12 +3716,6 @@ const BranchEntrySchema = z.object({
|
|
|
3644
3716
|
});
|
|
3645
3717
|
const BRANCHES_PAGE_SIZE = 50;
|
|
3646
3718
|
const DEFAULT_MAX_PAGES = 20;
|
|
3647
|
-
function repoBase(conn) {
|
|
3648
|
-
return `${conn.serverUrl}/api/v1/repos/${conn.repository}`;
|
|
3649
|
-
}
|
|
3650
|
-
function authHeaders(conn) {
|
|
3651
|
-
return { Authorization: `token ${conn.token}` };
|
|
3652
|
-
}
|
|
3653
3719
|
async function listBranches(executor, conn, options = {}) {
|
|
3654
3720
|
const signal = options.signal;
|
|
3655
3721
|
const maxPages = options.maxPages ?? DEFAULT_MAX_PAGES;
|
|
@@ -3718,8 +3784,7 @@ async function deleteBranch(executor, conn, branch) {
|
|
|
3718
3784
|
resource: `${conn.repository}/${branch}`
|
|
3719
3785
|
});
|
|
3720
3786
|
}
|
|
3721
|
-
|
|
3722
|
-
//#region src/branch.ts
|
|
3787
|
+
// src/branch.ts
|
|
3723
3788
|
const REFUSAL_WORDS = {
|
|
3724
3789
|
forbidden: "forbidden",
|
|
3725
3790
|
locked: "locked",
|
|
@@ -3745,8 +3810,7 @@ function renderBranchList(listing) {
|
|
|
3745
3810
|
if (listing.truncated) lines.push("Listing truncated at the page cap; more branches exist.");
|
|
3746
3811
|
return lines.join("\n");
|
|
3747
3812
|
}
|
|
3748
|
-
|
|
3749
|
-
//#region src/registry-branch.ts
|
|
3813
|
+
// src/registry-branch.ts
|
|
3750
3814
|
const branchSubCommands = {
|
|
3751
3815
|
"branch:delete": defineCommand({
|
|
3752
3816
|
meta: {
|
|
@@ -3816,8 +3880,7 @@ const branchSubCommands = {
|
|
|
3816
3880
|
}
|
|
3817
3881
|
})
|
|
3818
3882
|
};
|
|
3819
|
-
|
|
3820
|
-
//#region ../cli-kit/src/body-source.ts
|
|
3883
|
+
// ../cli-kit/src/body-source.ts
|
|
3821
3884
|
function tryRead(read, label) {
|
|
3822
3885
|
try {
|
|
3823
3886
|
return read();
|
|
@@ -3837,8 +3900,7 @@ function readBodySource(body, bodyFile, options = {}) {
|
|
|
3837
3900
|
if (!existsSync(bodyFile)) throw new FatalError(`${flags.file} not found: ${bodyFile}`);
|
|
3838
3901
|
return tryRead(() => readFileSync(bodyFile, "utf-8"), `${flags.file} "${bodyFile}"`);
|
|
3839
3902
|
}
|
|
3840
|
-
|
|
3841
|
-
//#region ../forgejo/src/issue-comments.ts
|
|
3903
|
+
// ../forgejo/src/issue-comments.ts
|
|
3842
3904
|
const CommentResponseSchema = z.object({
|
|
3843
3905
|
id: z.number(),
|
|
3844
3906
|
body: z.string().nullish(),
|
|
@@ -3879,7 +3941,7 @@ async function listForgejoComments(executor, conn, number, options = {}) {
|
|
|
3879
3941
|
limit: String(COMMENTS_PAGE_SIZE),
|
|
3880
3942
|
page: String(page)
|
|
3881
3943
|
});
|
|
3882
|
-
const res = await executor.fetch(`${issuesBase(conn)}/${String(number)}/comments?${params.toString()}`, { headers: authHeaders
|
|
3944
|
+
const res = await executor.fetch(`${issuesBase(conn)}/${String(number)}/comments?${params.toString()}`, { headers: authHeaders(conn) });
|
|
3883
3945
|
if (!res.ok) await throwForgejoFailure(res, {
|
|
3884
3946
|
verb: "list comments",
|
|
3885
3947
|
resource: `#${String(number)}`
|
|
@@ -3912,8 +3974,7 @@ async function addForgejoComment(executor, conn, number, body) {
|
|
|
3912
3974
|
}, issueNotFoundMessage(conn, number));
|
|
3913
3975
|
return normalizeComment(parseCommentOrThrow(await res.json()));
|
|
3914
3976
|
}
|
|
3915
|
-
|
|
3916
|
-
//#region ../forgejo/src/pr-title.ts
|
|
3977
|
+
// ../forgejo/src/pr-title.ts
|
|
3917
3978
|
const WIP_PREFIXES = ["WIP:", "[WIP]"];
|
|
3918
3979
|
function hasWipPrefix(title) {
|
|
3919
3980
|
return matchedWipPrefix(title) !== void 0;
|
|
@@ -3927,8 +3988,7 @@ function stripWipPrefix(title) {
|
|
|
3927
3988
|
if (prefix === void 0) return title;
|
|
3928
3989
|
return title.slice(prefix.length).trimStart();
|
|
3929
3990
|
}
|
|
3930
|
-
|
|
3931
|
-
//#region ../forgejo/src/pr.ts
|
|
3991
|
+
// ../forgejo/src/pr.ts
|
|
3932
3992
|
const CreatedPrSchema = z.object({
|
|
3933
3993
|
number: z.number(),
|
|
3934
3994
|
html_url: z.string().optional()
|
|
@@ -3979,9 +4039,12 @@ function updatedBefore(since) {
|
|
|
3979
4039
|
return (pr) => pr.updatedAt !== null && Date.parse(pr.updatedAt) < since;
|
|
3980
4040
|
}
|
|
3981
4041
|
async function listPulls(executor, conn, options = {}) {
|
|
4042
|
+
const startPage = options.startPage ?? 1;
|
|
4043
|
+
if (!Number.isInteger(startPage) || startPage < 1) throw new FatalError(`Cannot list PRs on ${conn.repository}: startPage must be an integer of at least 1, got ${String(startPage)}`);
|
|
4044
|
+
const lastPage = startPage + PULLS_MAX_PAGES - 1;
|
|
3982
4045
|
const headers = { Authorization: `token ${conn.token}` };
|
|
3983
4046
|
const pulls = [];
|
|
3984
|
-
for (let page =
|
|
4047
|
+
for (let page = startPage; page <= lastPage; page++) {
|
|
3985
4048
|
options.signal?.throwIfAborted();
|
|
3986
4049
|
const params = new URLSearchParams({
|
|
3987
4050
|
state: options.state ?? "all",
|
|
@@ -4021,9 +4084,9 @@ async function listPulls(executor, conn, options = {}) {
|
|
|
4021
4084
|
if (options.stopWhen !== void 0 && items.some(options.stopWhen)) break;
|
|
4022
4085
|
if (options.updatedSince !== void 0 && items.some(updatedBefore(options.updatedSince))) break;
|
|
4023
4086
|
if (options.limit !== void 0 && pulls.length >= options.limit) break;
|
|
4024
|
-
if (page ===
|
|
4087
|
+
if (page === lastPage) {
|
|
4025
4088
|
log.warn(`PR listing on ${conn.repository} hit the ${String(PULLS_MAX_PAGES)}-page cap without an empty page; results may be truncated`);
|
|
4026
|
-
options.onPageCap?.();
|
|
4089
|
+
options.onPageCap?.(lastPage);
|
|
4027
4090
|
}
|
|
4028
4091
|
}
|
|
4029
4092
|
return pulls;
|
|
@@ -4195,8 +4258,7 @@ const PullReviewCommentSchema = z.object({
|
|
|
4195
4258
|
user: z.object({ login: z.string() }).nullish()
|
|
4196
4259
|
});
|
|
4197
4260
|
z.array(PullReviewCommentSchema);
|
|
4198
|
-
|
|
4199
|
-
//#region ../forgejo/src/issue-api.ts
|
|
4261
|
+
// ../forgejo/src/issue-api.ts
|
|
4200
4262
|
var IssueNumberRequiredError = class extends FatalError {
|
|
4201
4263
|
constructor() {
|
|
4202
4264
|
super("An issue number or issue URL is required.");
|
|
@@ -4223,8 +4285,7 @@ function forgejoIssueApi(fetcher, conn) {
|
|
|
4223
4285
|
pullRequest: (number) => getForgejoPrDetail(fetcher, conn, number)
|
|
4224
4286
|
};
|
|
4225
4287
|
}
|
|
4226
|
-
|
|
4227
|
-
//#region ../forgejo/src/issue-messages.ts
|
|
4288
|
+
// ../forgejo/src/issue-messages.ts
|
|
4228
4289
|
const ISSUE_LIST_JSON_HELP = "Emit one JSON document: issues ([{number, title, state, url, author, labels, createdAt, updatedAt, closedAt (null while open), isPullRequest, assignees, attachments ([{id, name, size, createdAt, downloadUrl}])}]), truncated.";
|
|
4229
4290
|
const ISSUE_CREATE_JSON_HELP = "Emit one JSON document: number, url, assignees. A dry run reports number 0 and an empty url.";
|
|
4230
4291
|
const ISSUE_STATE_JSON_HELP = "Emit one JSON document: number, url, action (close | reopen), state ({previous, current}), changed, comment? ({posted}; present only when a comment was given).";
|
|
@@ -4255,8 +4316,7 @@ function describeNoLabelsGiven(error, clearFlag) {
|
|
|
4255
4316
|
function describeAttachmentExists(error, forceFlag) {
|
|
4256
4317
|
return `"${error.filePath}" already exists -- pass ${forceFlag} to overwrite it.`;
|
|
4257
4318
|
}
|
|
4258
|
-
|
|
4259
|
-
//#region ../forgejo/src/issue-run.ts
|
|
4319
|
+
// ../forgejo/src/issue-run.ts
|
|
4260
4320
|
var NothingToUpdateError = class extends FatalError {
|
|
4261
4321
|
constructor() {
|
|
4262
4322
|
super("Nothing to change: neither a title nor a body was given.");
|
|
@@ -4362,7 +4422,7 @@ function parseState$1(state) {
|
|
|
4362
4422
|
if (state === "open" || state === "closed" || state === "all") return state;
|
|
4363
4423
|
throw new InvalidListQueryError("state", state);
|
|
4364
4424
|
}
|
|
4365
|
-
function parseLimit
|
|
4425
|
+
function parseLimit(raw) {
|
|
4366
4426
|
const limit = Number(raw);
|
|
4367
4427
|
if (!Number.isInteger(limit) || limit <= 0) throw new InvalidListQueryError("limit", raw);
|
|
4368
4428
|
return limit;
|
|
@@ -4375,7 +4435,7 @@ async function listIssues(resolve, request) {
|
|
|
4375
4435
|
const label = normalizeLabel(request.label);
|
|
4376
4436
|
const query = {
|
|
4377
4437
|
state: parseState$1(request.state),
|
|
4378
|
-
limit: parseLimit
|
|
4438
|
+
limit: parseLimit(request.limit),
|
|
4379
4439
|
...label === void 0 ? {} : { label }
|
|
4380
4440
|
};
|
|
4381
4441
|
const { api } = resolve(parseRepoTarget(request.repo));
|
|
@@ -4512,8 +4572,7 @@ function formatIssueList(result) {
|
|
|
4512
4572
|
}
|
|
4513
4573
|
return lines.join("\n");
|
|
4514
4574
|
}
|
|
4515
|
-
|
|
4516
|
-
//#region src/issue-transport.ts
|
|
4575
|
+
// src/issue-transport.ts
|
|
4517
4576
|
function githubRefusal(command) {
|
|
4518
4577
|
return `bst-fj is Forgejo-only -- use \`gh\` or \`pnpm exec bst ${command}\` for a github.com repository.`;
|
|
4519
4578
|
}
|
|
@@ -4536,8 +4595,7 @@ function forgejoIssueTransport(cwd, target, command) {
|
|
|
4536
4595
|
target: resolved.target
|
|
4537
4596
|
};
|
|
4538
4597
|
}
|
|
4539
|
-
|
|
4540
|
-
//#region src/commands/issue-comment.ts
|
|
4598
|
+
// src/commands/issue-comment.ts
|
|
4541
4599
|
const issueCommentCommand = defineCommand({
|
|
4542
4600
|
meta: {
|
|
4543
4601
|
name: "issue:comment",
|
|
@@ -4595,8 +4653,7 @@ const issueCommentCommand = defineCommand({
|
|
|
4595
4653
|
}
|
|
4596
4654
|
}
|
|
4597
4655
|
});
|
|
4598
|
-
|
|
4599
|
-
//#region src/commands/issue-create.ts
|
|
4656
|
+
// src/commands/issue-create.ts
|
|
4600
4657
|
const issueCreateCommand = defineCommand({
|
|
4601
4658
|
meta: {
|
|
4602
4659
|
name: "issue:create",
|
|
@@ -4669,8 +4726,7 @@ const issueCreateCommand = defineCommand({
|
|
|
4669
4726
|
}
|
|
4670
4727
|
}
|
|
4671
4728
|
});
|
|
4672
|
-
|
|
4673
|
-
//#region ../forgejo/src/issue-run-download.ts
|
|
4729
|
+
// ../forgejo/src/issue-run-download.ts
|
|
4674
4730
|
function isReadableFile(filePath) {
|
|
4675
4731
|
try {
|
|
4676
4732
|
readFileSync(filePath);
|
|
@@ -4763,8 +4819,7 @@ function formatDownload(result, dryRun) {
|
|
|
4763
4819
|
for (const file of result.files) lines.push(` ${file.name} (${String(file.size)} bytes)`);
|
|
4764
4820
|
return lines.join("\n");
|
|
4765
4821
|
}
|
|
4766
|
-
|
|
4767
|
-
//#region src/commands/issue-download.ts
|
|
4822
|
+
// src/commands/issue-download.ts
|
|
4768
4823
|
const issueDownloadCommand = defineCommand({
|
|
4769
4824
|
meta: {
|
|
4770
4825
|
name: "issue:download",
|
|
@@ -4823,8 +4878,7 @@ const issueDownloadCommand = defineCommand({
|
|
|
4823
4878
|
}
|
|
4824
4879
|
}
|
|
4825
4880
|
});
|
|
4826
|
-
|
|
4827
|
-
//#region ../forgejo/src/issue-labels.ts
|
|
4881
|
+
// ../forgejo/src/issue-labels.ts
|
|
4828
4882
|
const TimelineEntrySchema = z.object({
|
|
4829
4883
|
id: z.number(),
|
|
4830
4884
|
type: z.string(),
|
|
@@ -4857,7 +4911,7 @@ async function removeForgejoIssueLabel(executor, conn, number, name, labelIds) {
|
|
|
4857
4911
|
const id = await resolveLabelId(executor, conn, name, labelIds);
|
|
4858
4912
|
const res = await executor.fetch(`${issuesBase(conn)}/${String(number)}/labels/${String(id)}`, {
|
|
4859
4913
|
method: "DELETE",
|
|
4860
|
-
headers: authHeaders
|
|
4914
|
+
headers: authHeaders(conn)
|
|
4861
4915
|
}, { idempotent: true });
|
|
4862
4916
|
if (!res.ok) await throwForgejoFailure(res, {
|
|
4863
4917
|
verb: "remove label",
|
|
@@ -4875,8 +4929,7 @@ async function replaceForgejoIssueLabels(executor, conn, number, labelIds) {
|
|
|
4875
4929
|
resource: `#${String(number)}`
|
|
4876
4930
|
}, issueNotFoundMessage(conn, number));
|
|
4877
4931
|
}
|
|
4878
|
-
|
|
4879
|
-
//#region ../forgejo/src/issue-run-labels.ts
|
|
4932
|
+
// ../forgejo/src/issue-run-labels.ts
|
|
4880
4933
|
async function labelIssue(resolve, request) {
|
|
4881
4934
|
const ref = parseIssueRef(request.ref);
|
|
4882
4935
|
const number = requireIssueNumber(ref);
|
|
@@ -4945,8 +4998,7 @@ function formatIssueSetLabels(result, dryRun) {
|
|
|
4945
4998
|
if (result.added.length > 0) lines.push(` ${dryRun ? "would add" : "added"}: ${result.added.join(", ")}`);
|
|
4946
4999
|
return lines.join("\n");
|
|
4947
5000
|
}
|
|
4948
|
-
|
|
4949
|
-
//#region src/commands/issue-label.ts
|
|
5001
|
+
// src/commands/issue-label.ts
|
|
4950
5002
|
function defineIssueLabelCommand(action) {
|
|
4951
5003
|
const name = action === "add" ? "issue:label" : "issue:unlabel";
|
|
4952
5004
|
return defineCommand({
|
|
@@ -5005,8 +5057,7 @@ function defineIssueLabelCommand(action) {
|
|
|
5005
5057
|
}
|
|
5006
5058
|
const issueLabelCommand = defineIssueLabelCommand("add");
|
|
5007
5059
|
const issueUnlabelCommand = defineIssueLabelCommand("remove");
|
|
5008
|
-
|
|
5009
|
-
//#region src/commands/issue-set-labels.ts
|
|
5060
|
+
// src/commands/issue-set-labels.ts
|
|
5010
5061
|
const issueSetLabelsCommand = defineCommand({
|
|
5011
5062
|
meta: {
|
|
5012
5063
|
name: "issue:set-labels",
|
|
@@ -5066,8 +5117,7 @@ const issueSetLabelsCommand = defineCommand({
|
|
|
5066
5117
|
}
|
|
5067
5118
|
}
|
|
5068
5119
|
});
|
|
5069
|
-
|
|
5070
|
-
//#region ../forgejo/src/issue-run-state.ts
|
|
5120
|
+
// ../forgejo/src/issue-run-state.ts
|
|
5071
5121
|
var EmptyCommentError = class extends FatalError {
|
|
5072
5122
|
constructor() {
|
|
5073
5123
|
super("The comment resolved to empty text.");
|
|
@@ -5163,8 +5213,7 @@ function formatIssueState(result, dryRun) {
|
|
|
5163
5213
|
}
|
|
5164
5214
|
return lines.join("\n");
|
|
5165
5215
|
}
|
|
5166
|
-
|
|
5167
|
-
//#region src/commands/issue-state.ts
|
|
5216
|
+
// src/commands/issue-state.ts
|
|
5168
5217
|
function defineIssueStateCommand(action) {
|
|
5169
5218
|
const name = action === "close" ? "issue:close" : "issue:reopen";
|
|
5170
5219
|
return defineCommand({
|
|
@@ -5240,8 +5289,7 @@ function defineIssueStateCommand(action) {
|
|
|
5240
5289
|
}
|
|
5241
5290
|
const issueCloseCommand = defineIssueStateCommand("close");
|
|
5242
5291
|
const issueReopenCommand = defineIssueStateCommand("reopen");
|
|
5243
|
-
|
|
5244
|
-
//#region src/commands/issue-list.ts
|
|
5292
|
+
// src/commands/issue-list.ts
|
|
5245
5293
|
const issueListCommand = defineCommand({
|
|
5246
5294
|
meta: {
|
|
5247
5295
|
name: "issue:list",
|
|
@@ -5299,8 +5347,7 @@ const issueListCommand = defineCommand({
|
|
|
5299
5347
|
}
|
|
5300
5348
|
}
|
|
5301
5349
|
});
|
|
5302
|
-
|
|
5303
|
-
//#region src/commands/issue-update.ts
|
|
5350
|
+
// src/commands/issue-update.ts
|
|
5304
5351
|
const issueUpdateCommand = defineCommand({
|
|
5305
5352
|
meta: {
|
|
5306
5353
|
name: "issue:update",
|
|
@@ -5371,8 +5418,7 @@ const issueUpdateCommand = defineCommand({
|
|
|
5371
5418
|
}
|
|
5372
5419
|
}
|
|
5373
5420
|
});
|
|
5374
|
-
|
|
5375
|
-
//#region src/registry-issue.ts
|
|
5421
|
+
// src/registry-issue.ts
|
|
5376
5422
|
const issueSubCommands = {
|
|
5377
5423
|
"issue:view": defineCommand({
|
|
5378
5424
|
meta: {
|
|
@@ -5425,8 +5471,7 @@ const issueSubCommands = {
|
|
|
5425
5471
|
"issue:set-labels": issueSetLabelsCommand,
|
|
5426
5472
|
"issue:download": issueDownloadCommand
|
|
5427
5473
|
};
|
|
5428
|
-
|
|
5429
|
-
//#region src/pr-checks.ts
|
|
5474
|
+
// src/pr-checks.ts
|
|
5430
5475
|
async function resolvePrChecksTarget(fetcher, options) {
|
|
5431
5476
|
const ref = parseIssueRef(options.pr);
|
|
5432
5477
|
if (options.repo !== void 0 && ref.number === void 0 && options.branch === void 0) throw new FatalError("--repo requires --pr or --branch -- the current branch of this checkout means nothing in another repository, and inferring it there would silently answer about the wrong PR.");
|
|
@@ -5521,75 +5566,45 @@ function buildReport(detail, checks, ctx, extras = {}) {
|
|
|
5521
5566
|
return report;
|
|
5522
5567
|
}
|
|
5523
5568
|
async function waitForSettledChecks(fetcher, target, baseline, notices, poll) {
|
|
5524
|
-
const { timeoutMs, intervalMs, sleep, now } = poll;
|
|
5525
|
-
const startedAt = now();
|
|
5526
5569
|
let currentDetail = target.detail;
|
|
5527
|
-
let consecutiveFailures = 0;
|
|
5528
5570
|
let consecutiveDetailFailures = 0;
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
|
|
5533
|
-
|
|
5534
|
-
|
|
5535
|
-
|
|
5536
|
-
|
|
5537
|
-
|
|
5538
|
-
|
|
5539
|
-
|
|
5540
|
-
|
|
5541
|
-
|
|
5542
|
-
|
|
5543
|
-
|
|
5544
|
-
|
|
5545
|
-
|
|
5546
|
-
|
|
5547
|
-
|
|
5548
|
-
|
|
5549
|
-
|
|
5550
|
-
|
|
5551
|
-
|
|
5552
|
-
|
|
5553
|
-
|
|
5554
|
-
|
|
5555
|
-
|
|
5556
|
-
|
|
5557
|
-
|
|
5558
|
-
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
|
|
5563
|
-
|
|
5564
|
-
if (now() - startedAt >= timeoutMs) return buildReport(currentDetail, lastGoodChecks ?? EMPTY_CHECKS, {
|
|
5565
|
-
target,
|
|
5566
|
-
baseline,
|
|
5567
|
-
notices,
|
|
5568
|
-
waited: true,
|
|
5569
|
-
elapsedMs: now() - startedAt
|
|
5570
|
-
}, { statusOverride: "timeout" });
|
|
5571
|
-
await sleep(intervalMs);
|
|
5572
|
-
let nextDetail;
|
|
5573
|
-
try {
|
|
5574
|
-
nextDetail = await getForgejoPrDetail(fetcher, target.conn, target.prNumber);
|
|
5575
|
-
consecutiveDetailFailures = 0;
|
|
5576
|
-
} catch (error) {
|
|
5577
|
-
consecutiveDetailFailures += 1;
|
|
5578
|
-
if (consecutiveDetailFailures >= 3) throw error;
|
|
5579
|
-
continue;
|
|
5571
|
+
const reportFor = (detail, checks, elapsedMs, extras = {}) => buildReport(detail, checks, {
|
|
5572
|
+
target,
|
|
5573
|
+
baseline,
|
|
5574
|
+
notices,
|
|
5575
|
+
waited: true,
|
|
5576
|
+
elapsedMs
|
|
5577
|
+
}, extras);
|
|
5578
|
+
return settleChecks(fetcher, target.conn, poll, {
|
|
5579
|
+
sha: () => currentDetail.head.sha,
|
|
5580
|
+
notices,
|
|
5581
|
+
report: (checks, extras) => {
|
|
5582
|
+
const reportExtras = {};
|
|
5583
|
+
if (extras.exit === "timeout") reportExtras.statusOverride = "timeout";
|
|
5584
|
+
else if (extras.exit === "retry-budget") {
|
|
5585
|
+
reportExtras.statusOverride = "unparseable";
|
|
5586
|
+
if (extras.failureDetail !== void 0) reportExtras.detailOverride = extras.failureDetail;
|
|
5587
|
+
}
|
|
5588
|
+
return reportFor(currentDetail, checks, extras.elapsed(), reportExtras);
|
|
5589
|
+
},
|
|
5590
|
+
afterSleep: async (sha, elapsed) => {
|
|
5591
|
+
let nextDetail;
|
|
5592
|
+
try {
|
|
5593
|
+
nextDetail = await getForgejoPrDetail(fetcher, target.conn, target.prNumber);
|
|
5594
|
+
consecutiveDetailFailures = 0;
|
|
5595
|
+
} catch (error) {
|
|
5596
|
+
consecutiveDetailFailures += 1;
|
|
5597
|
+
if (consecutiveDetailFailures >= 3) throw error;
|
|
5598
|
+
return "retry";
|
|
5599
|
+
}
|
|
5600
|
+
if (nextDetail.head.sha !== sha) return { done: reportFor(nextDetail, EMPTY_CHECKS, elapsed(), {
|
|
5601
|
+
statusOverride: "head-moved",
|
|
5602
|
+
previousHeadSha: sha
|
|
5603
|
+
}) };
|
|
5604
|
+
currentDetail = nextDetail;
|
|
5605
|
+
return "next";
|
|
5580
5606
|
}
|
|
5581
|
-
|
|
5582
|
-
target,
|
|
5583
|
-
baseline,
|
|
5584
|
-
notices,
|
|
5585
|
-
waited: true,
|
|
5586
|
-
elapsedMs: now() - startedAt
|
|
5587
|
-
}, {
|
|
5588
|
-
statusOverride: "head-moved",
|
|
5589
|
-
previousHeadSha: sha
|
|
5590
|
-
});
|
|
5591
|
-
currentDetail = nextDetail;
|
|
5592
|
-
}
|
|
5607
|
+
});
|
|
5593
5608
|
}
|
|
5594
5609
|
async function runPrChecks(fetcher, options) {
|
|
5595
5610
|
const timings = options.wait === true ? resolvePollTimings(options) : void 0;
|
|
@@ -5622,13 +5637,7 @@ function baselineClause(report) {
|
|
|
5622
5637
|
return `${String(redChecks.length)} red, ${String(preexistingCount)} of them already red on ` + report.baseline.ref;
|
|
5623
5638
|
}
|
|
5624
5639
|
function renderPrChecks(report) {
|
|
5625
|
-
const lines = report.checks.map((check) =>
|
|
5626
|
-
const parts = [check.state, check.context];
|
|
5627
|
-
if (check.description !== null) parts.push(check.description);
|
|
5628
|
-
let line = parts.join(" -- ");
|
|
5629
|
-
if (check.verdict === "red" && check.targetUrl !== null) line += ` (${check.targetUrl})`;
|
|
5630
|
-
return line;
|
|
5631
|
-
});
|
|
5640
|
+
const lines = report.checks.map((check) => renderCheckLine(check));
|
|
5632
5641
|
const summaryParts = [`head ${report.headSha.slice(0, 12)}: ${report.status}`];
|
|
5633
5642
|
const clause = baselineClause(report);
|
|
5634
5643
|
if (clause !== null) summaryParts.push(clause);
|
|
@@ -5636,8 +5645,7 @@ function renderPrChecks(report) {
|
|
|
5636
5645
|
lines.push(summaryParts.join(" -- "));
|
|
5637
5646
|
return lines.join("\n");
|
|
5638
5647
|
}
|
|
5639
|
-
|
|
5640
|
-
//#region src/commands/pr-checks.ts
|
|
5648
|
+
// src/commands/pr-checks.ts
|
|
5641
5649
|
const prChecksCommand = defineCommand({
|
|
5642
5650
|
meta: {
|
|
5643
5651
|
name: "pr:checks",
|
|
@@ -5701,8 +5709,7 @@ const prChecksCommand = defineCommand({
|
|
|
5701
5709
|
process.exitCode = report.status === "green" ? 0 : 1;
|
|
5702
5710
|
}
|
|
5703
5711
|
});
|
|
5704
|
-
|
|
5705
|
-
//#region ../forgejo/src/pr-close.ts
|
|
5712
|
+
// ../forgejo/src/pr-close.ts
|
|
5706
5713
|
async function closePullRequest(api, request) {
|
|
5707
5714
|
rejectEmptyComment(request.comment);
|
|
5708
5715
|
return changeState(api, request.number, {
|
|
@@ -5719,15 +5726,13 @@ function formatPrClose(result, dryRun) {
|
|
|
5719
5726
|
return lines.join("\n");
|
|
5720
5727
|
}
|
|
5721
5728
|
const PR_CLOSE_JSON_HELP = "Emit one JSON document: number, url, action (close), state ({previous, current}), changed, merged? (present only when the pull request was already closed), comment? ({posted}; present only when a comment was given).";
|
|
5722
|
-
|
|
5723
|
-
//#region ../forgejo/src/pr-number.ts
|
|
5729
|
+
// ../forgejo/src/pr-number.ts
|
|
5724
5730
|
function parsePrNumber(raw) {
|
|
5725
5731
|
const value = Number(raw);
|
|
5726
5732
|
if (!/^\d+$/.test(raw) || !Number.isSafeInteger(value) || value < 1) throw new FatalError(`Invalid pull request number "${raw}" (expected a positive integer).`);
|
|
5727
5733
|
return value;
|
|
5728
5734
|
}
|
|
5729
|
-
|
|
5730
|
-
//#region src/commands/pr-close.ts
|
|
5735
|
+
// src/commands/pr-close.ts
|
|
5731
5736
|
const prCloseCommand = defineCommand({
|
|
5732
5737
|
meta: {
|
|
5733
5738
|
name: "pr:close",
|
|
@@ -5791,8 +5796,7 @@ const prCloseCommand = defineCommand({
|
|
|
5791
5796
|
}
|
|
5792
5797
|
}
|
|
5793
5798
|
});
|
|
5794
|
-
|
|
5795
|
-
//#region ../forgejo/src/closing-refs.ts
|
|
5799
|
+
// ../forgejo/src/closing-refs.ts
|
|
5796
5800
|
const CLOSING_REF = /(?:^|[\s([])(clos(?:e|es|ed)|fix(?:es|ed)?|resolv(?:e|es|ed))(?::[ \t]*|[ \t]+)((?:[\w.-]+\/[\w.-]+)?#\d+)(?![\w-])/gim;
|
|
5797
5801
|
function capitalize(word) {
|
|
5798
5802
|
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
|
@@ -5822,8 +5826,7 @@ function carryForwardClosingRefs(source, target) {
|
|
|
5822
5826
|
const refLines = missing.map((ref) => ref.text).join("\n");
|
|
5823
5827
|
return target.trim() === "" ? refLines : `${target}\n\n${refLines}`;
|
|
5824
5828
|
}
|
|
5825
|
-
|
|
5826
|
-
//#region ../forgejo/src/git.ts
|
|
5829
|
+
// ../forgejo/src/git.ts
|
|
5827
5830
|
const GIT_LOCAL_TIMEOUT_MS = 6e4;
|
|
5828
5831
|
const GIT_WRITE_TIMEOUT_MS = 3e5;
|
|
5829
5832
|
function pickDefaultBranch(override, originHead) {
|
|
@@ -5934,8 +5937,7 @@ async function pushBranch(git, cwd, branch, env, forceWithLease = false) {
|
|
|
5934
5937
|
});
|
|
5935
5938
|
if (result.exitCode !== 0) throw new FatalError(`Failed to push ${branch}: ${result.stderr || result.stdout}`);
|
|
5936
5939
|
}
|
|
5937
|
-
|
|
5938
|
-
//#region ../forgejo/src/pr-upsert.ts
|
|
5940
|
+
// ../forgejo/src/pr-upsert.ts
|
|
5939
5941
|
const COMMIT_TYPES = /* @__PURE__ */ new Set([
|
|
5940
5942
|
"feat",
|
|
5941
5943
|
"fix",
|
|
@@ -6143,8 +6145,7 @@ async function runPrUpsert(git, host, options) {
|
|
|
6143
6145
|
...shape
|
|
6144
6146
|
};
|
|
6145
6147
|
}
|
|
6146
|
-
|
|
6147
|
-
//#region ../forgejo/src/pr-upsert-messages.ts
|
|
6148
|
+
// ../forgejo/src/pr-upsert-messages.ts
|
|
6148
6149
|
function describePrModeError(error, commands) {
|
|
6149
6150
|
if (error.reason === "already-open") {
|
|
6150
6151
|
const createVerb = commands.create.split(" ").at(-1) ?? commands.create;
|
|
@@ -6223,8 +6224,7 @@ function formatPrUpdate(result, rewrites, flags) {
|
|
|
6223
6224
|
body: null
|
|
6224
6225
|
};
|
|
6225
6226
|
}
|
|
6226
|
-
|
|
6227
|
-
//#region ../forgejo/src/pr-host.ts
|
|
6227
|
+
// ../forgejo/src/pr-host.ts
|
|
6228
6228
|
function forgejoPrHost(fetcher, conn) {
|
|
6229
6229
|
return {
|
|
6230
6230
|
wipTitles: true,
|
|
@@ -6257,8 +6257,7 @@ function forgejoPrEditHost(fetcher, conn) {
|
|
|
6257
6257
|
ready: (number, write) => updatePr(fetcher, conn, number, { title: write.title })
|
|
6258
6258
|
};
|
|
6259
6259
|
}
|
|
6260
|
-
|
|
6261
|
-
//#region src/git.ts
|
|
6260
|
+
// src/git.ts
|
|
6262
6261
|
const TIMED_OUT_EXIT_CODE = 124;
|
|
6263
6262
|
const ABORTED_EXIT_CODE = 143;
|
|
6264
6263
|
function cliGit() {
|
|
@@ -6334,8 +6333,7 @@ function cliGit() {
|
|
|
6334
6333
|
});
|
|
6335
6334
|
}) };
|
|
6336
6335
|
}
|
|
6337
|
-
|
|
6338
|
-
//#region src/pr-run.ts
|
|
6336
|
+
// src/pr-run.ts
|
|
6339
6337
|
const COMMANDS = {
|
|
6340
6338
|
create: "pnpm exec bst-fj pr:create",
|
|
6341
6339
|
update: "pnpm exec bst-fj pr:update"
|
|
@@ -6369,8 +6367,7 @@ async function runForgejoPr(githubRefusal, options) {
|
|
|
6369
6367
|
});
|
|
6370
6368
|
}
|
|
6371
6369
|
}
|
|
6372
|
-
|
|
6373
|
-
//#region src/commands/pr-create.ts
|
|
6370
|
+
// src/commands/pr-create.ts
|
|
6374
6371
|
const prCreateCommand = defineCommand({
|
|
6375
6372
|
meta: {
|
|
6376
6373
|
name: "pr:create",
|
|
@@ -6439,8 +6436,7 @@ const prCreateCommand = defineCommand({
|
|
|
6439
6436
|
if (summary.body !== null) out.text(`${summary.body.heading}\n${summary.body.text}`);
|
|
6440
6437
|
}
|
|
6441
6438
|
});
|
|
6442
|
-
|
|
6443
|
-
//#region ../forgejo/src/pr-files.ts
|
|
6439
|
+
// ../forgejo/src/pr-files.ts
|
|
6444
6440
|
const DEFAULT_LIMIT = 100;
|
|
6445
6441
|
const PrFileEntrySchema = z.object({
|
|
6446
6442
|
filename: z.string(),
|
|
@@ -6485,8 +6481,7 @@ async function readPrFilesPage(executor, conn, prNumber, page, limit) {
|
|
|
6485
6481
|
truncated: res.headers.get("x-hasmore") === "true"
|
|
6486
6482
|
};
|
|
6487
6483
|
}
|
|
6488
|
-
|
|
6489
|
-
//#region src/pr-files.ts
|
|
6484
|
+
// src/pr-files.ts
|
|
6490
6485
|
function runPrFiles(fetcher, options) {
|
|
6491
6486
|
const number = parsePrNumber(options.number);
|
|
6492
6487
|
return listAllPrFiles(fetcher, requireForgejoTarget(options.cwd, parseRepoTarget(options.repo), "pr:files is Forgejo-only -- gh pr diff --name-only already serves GitHub."), number);
|
|
@@ -6497,8 +6492,7 @@ function renderPrFiles(listing) {
|
|
|
6497
6492
|
if (listing.truncated) lines.push("Listing truncated; the pull request changes more files.");
|
|
6498
6493
|
return lines.join("\n");
|
|
6499
6494
|
}
|
|
6500
|
-
|
|
6501
|
-
//#region src/commands/pr-files.ts
|
|
6495
|
+
// src/commands/pr-files.ts
|
|
6502
6496
|
const prFilesCommand = defineCommand({
|
|
6503
6497
|
meta: {
|
|
6504
6498
|
name: "pr:files",
|
|
@@ -6537,20 +6531,14 @@ const prFilesCommand = defineCommand({
|
|
|
6537
6531
|
out.text(renderPrFiles(listing));
|
|
6538
6532
|
}
|
|
6539
6533
|
});
|
|
6540
|
-
|
|
6541
|
-
//#region src/pr-list.ts
|
|
6534
|
+
// src/pr-list.ts
|
|
6542
6535
|
function parseState(state) {
|
|
6543
6536
|
if (state === "open" || state === "closed" || state === "all") return state;
|
|
6544
6537
|
throw new FatalError(`Invalid --state "${state}" (expected open, closed, or all).`);
|
|
6545
6538
|
}
|
|
6546
|
-
function parseLimit(raw) {
|
|
6547
|
-
const limit = Number(raw);
|
|
6548
|
-
if (!Number.isInteger(limit) || limit < 1) throw new FatalError(`Invalid --limit "${raw}" (expected a positive integer).`);
|
|
6549
|
-
return limit;
|
|
6550
|
-
}
|
|
6551
6539
|
async function runPrList(fetcher, options) {
|
|
6552
6540
|
const state = parseState(options.state);
|
|
6553
|
-
const limit =
|
|
6541
|
+
const limit = parseLimitFlag(options.limit);
|
|
6554
6542
|
rootLogger.debug(`pr:list state=${state} limit=${String(limit)}`);
|
|
6555
6543
|
const conn = requireForgejoTarget(options.cwd, parseRepoTarget(options.repo), "pr:list is Forgejo-only -- gh pr list already serves GitHub, first-class. Use that instead.");
|
|
6556
6544
|
const notices = [];
|
|
@@ -6580,8 +6568,7 @@ function renderPrList(result) {
|
|
|
6580
6568
|
return `#${String(pr.number)} ${statusLabel(pr)} ${branches}: ${pr.title ?? "(no title)"}${labels}${url}`;
|
|
6581
6569
|
}).join("\n");
|
|
6582
6570
|
}
|
|
6583
|
-
|
|
6584
|
-
//#region src/commands/pr-list.ts
|
|
6571
|
+
// src/commands/pr-list.ts
|
|
6585
6572
|
const prListCommand = defineCommand({
|
|
6586
6573
|
meta: {
|
|
6587
6574
|
name: "pr:list",
|
|
@@ -6624,8 +6611,7 @@ const prListCommand = defineCommand({
|
|
|
6624
6611
|
out.text(renderPrList(result));
|
|
6625
6612
|
}
|
|
6626
6613
|
});
|
|
6627
|
-
|
|
6628
|
-
//#region ../forgejo/src/pr-merge.ts
|
|
6614
|
+
// ../forgejo/src/pr-merge.ts
|
|
6629
6615
|
async function mergePr(executor, conn, prNumber, options) {
|
|
6630
6616
|
const url = `${conn.serverUrl}/api/v1/repos/${conn.repository}/pulls/${String(prNumber)}/merge`;
|
|
6631
6617
|
const body = {
|
|
@@ -6728,8 +6714,7 @@ z.object({
|
|
|
6728
6714
|
sha: z.string()
|
|
6729
6715
|
})
|
|
6730
6716
|
});
|
|
6731
|
-
|
|
6732
|
-
//#region ../forgejo/src/pr-merge-run.ts
|
|
6717
|
+
// ../forgejo/src/pr-merge-run.ts
|
|
6733
6718
|
const MERGE_METHODS = [
|
|
6734
6719
|
"merge",
|
|
6735
6720
|
"rebase",
|
|
@@ -6800,8 +6785,7 @@ async function runPrMergeCore(fetcher, conn, number, options = {}) {
|
|
|
6800
6785
|
}
|
|
6801
6786
|
};
|
|
6802
6787
|
}
|
|
6803
|
-
|
|
6804
|
-
//#region src/pr-merge.ts
|
|
6788
|
+
// src/pr-merge.ts
|
|
6805
6789
|
function parseMethod(raw) {
|
|
6806
6790
|
if (raw === void 0) return "merge";
|
|
6807
6791
|
const method = MERGE_METHODS.find((candidate) => candidate === raw);
|
|
@@ -6828,8 +6812,7 @@ function renderPrMerge(result) {
|
|
|
6828
6812
|
const what = `PR #${String(result.number)} (${result.method}) at ${result.headSha.slice(0, 12)}, checks ${result.checks}`;
|
|
6829
6813
|
return result.merged ? `Merged ${what}.` : `Dry run: would merge ${what}.`;
|
|
6830
6814
|
}
|
|
6831
|
-
|
|
6832
|
-
//#region src/commands/pr-merge.ts
|
|
6815
|
+
// src/commands/pr-merge.ts
|
|
6833
6816
|
const prMergeCommand = defineCommand({
|
|
6834
6817
|
meta: {
|
|
6835
6818
|
name: "pr:merge",
|
|
@@ -6885,8 +6868,7 @@ const prMergeCommand = defineCommand({
|
|
|
6885
6868
|
out.text(renderPrMerge(result));
|
|
6886
6869
|
}
|
|
6887
6870
|
});
|
|
6888
|
-
|
|
6889
|
-
//#region ../forgejo/src/pr-edit.ts
|
|
6871
|
+
// ../forgejo/src/pr-edit.ts
|
|
6890
6872
|
const MERGEABLE_RECHECK_DELAY_MS = 2e3;
|
|
6891
6873
|
function isOpen(live) {
|
|
6892
6874
|
return live.state === "open" && live.merged === false;
|
|
@@ -7013,8 +6995,7 @@ function renderPrReady(result) {
|
|
|
7013
6995
|
if (result.action === "would-ready") return `Dry run: pull request ${number} would stop being a draft, reading "${result.title}".`;
|
|
7014
6996
|
return `Dry run: pull request ${number} would read "${result.title}".`;
|
|
7015
6997
|
}
|
|
7016
|
-
|
|
7017
|
-
//#region src/registry-pr.ts
|
|
6998
|
+
// src/registry-pr.ts
|
|
7018
6999
|
const prSubCommands = {
|
|
7019
7000
|
"pr:checks": prChecksCommand,
|
|
7020
7001
|
"pr:close": prCloseCommand,
|
|
@@ -7179,8 +7160,7 @@ const prSubCommands = {
|
|
|
7179
7160
|
}
|
|
7180
7161
|
})
|
|
7181
7162
|
};
|
|
7182
|
-
|
|
7183
|
-
//#region src/registry.ts
|
|
7163
|
+
// src/registry.ts
|
|
7184
7164
|
const bstFjSubCommands = {
|
|
7185
7165
|
"commit:status": commitStatusCommand,
|
|
7186
7166
|
labels: labelsCommand,
|
|
@@ -7192,8 +7172,7 @@ const bstFjSubCommands = {
|
|
|
7192
7172
|
webhooks: webhooksCommand,
|
|
7193
7173
|
...issueSubCommands
|
|
7194
7174
|
};
|
|
7195
|
-
|
|
7196
|
-
//#region src/bin.ts
|
|
7175
|
+
// src/bin.ts
|
|
7197
7176
|
applyVerbosityFromArgs(process.argv.slice(2));
|
|
7198
7177
|
rootLogger.debug(describeEnvFileLoad(envFileLoad));
|
|
7199
7178
|
setForgejoLogger(rootLogger);
|
|
@@ -7205,5 +7184,4 @@ await runCli({
|
|
|
7205
7184
|
subCommands: bstFjSubCommands,
|
|
7206
7185
|
describeError: describeForgeError
|
|
7207
7186
|
});
|
|
7208
|
-
//#endregion
|
|
7209
7187
|
export {};
|