@bensandee/forgejo-cli 0.5.3 → 0.5.5
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 +38 -36
- package/package.json +4 -4
package/dist/bin.mjs
CHANGED
|
@@ -162,7 +162,7 @@ function loadEnvFileForBin(rawArgs, bin, io = processIo) {
|
|
|
162
162
|
//#region src/version.ts
|
|
163
163
|
const parsed = z.object({ version: z.string() }).safeParse({
|
|
164
164
|
name: "@bensandee/forgejo-cli",
|
|
165
|
-
version: "0.5.
|
|
165
|
+
version: "0.5.5",
|
|
166
166
|
description: "bst-fj: Forgejo API commands without the rest of bst",
|
|
167
167
|
license: "MIT",
|
|
168
168
|
repository: {
|
|
@@ -192,13 +192,13 @@ const parsed = z.object({ version: z.string() }).safeParse({
|
|
|
192
192
|
dependencies: {
|
|
193
193
|
"@bensandee/common": "0.2.0",
|
|
194
194
|
"citty": "^0.2.2",
|
|
195
|
-
"zod": "^4.6.
|
|
195
|
+
"zod": "^4.6.7"
|
|
196
196
|
},
|
|
197
197
|
devDependencies: {
|
|
198
198
|
"@bensandee/cli-kit": "workspace:*",
|
|
199
199
|
"@bensandee/forgejo": "workspace:*",
|
|
200
|
-
"@types/node": "24.19.
|
|
201
|
-
"tsdown": "0.23.
|
|
200
|
+
"@types/node": "24.19.2",
|
|
201
|
+
"tsdown": "0.23.1"
|
|
202
202
|
}
|
|
203
203
|
});
|
|
204
204
|
if (!parsed.success) throw new UnexpectedError(`@bensandee/forgejo-cli's package.json has no string version.`);
|
|
@@ -896,7 +896,8 @@ function resolveRepoUrlFrom(readOrigin, readPackageUrl) {
|
|
|
896
896
|
const originUrl = normalizeGitUrl(readOrigin() ?? "");
|
|
897
897
|
if (originUrl !== null && parseGitUrl(originUrl) !== null) return originUrl;
|
|
898
898
|
const pkgUrl = readPackageUrl();
|
|
899
|
-
|
|
899
|
+
if (pkgUrl === null || parseGitUrl(pkgUrl) === null) return null;
|
|
900
|
+
return normalizeGitUrl(pkgUrl);
|
|
900
901
|
}
|
|
901
902
|
function resolveForgejoConnection(env, repoUrl) {
|
|
902
903
|
const serverUrl = env["FORGEJO_SERVER_URL"];
|
|
@@ -987,10 +988,11 @@ function resolveIssueTarget(refTarget, repo) {
|
|
|
987
988
|
throw new RepoTargetMismatchError(`${repoTarget.serverUrl}/${repoTarget.repository}`, `${refTarget.serverUrl}/${refTarget.repository}`);
|
|
988
989
|
}
|
|
989
990
|
function normalizeGitUrl(raw) {
|
|
990
|
-
const
|
|
991
|
+
const value = raw.startsWith("git+") ? raw.slice(4) : raw;
|
|
992
|
+
const sshMatch = value.match(/^git@([^:]+):(.+?)(?:\.git)?$/);
|
|
991
993
|
if (sshMatch) return `https://${sshMatch[1]}/${sshMatch[2]}`;
|
|
992
994
|
try {
|
|
993
|
-
const url = new URL(
|
|
995
|
+
const url = new URL(value);
|
|
994
996
|
url.pathname = url.pathname.replace(/\.git$/, "");
|
|
995
997
|
url.username = "";
|
|
996
998
|
url.password = "";
|
|
@@ -2576,10 +2578,9 @@ const releaseCreateCommand = defineCommand({
|
|
|
2576
2578
|
});
|
|
2577
2579
|
//#endregion
|
|
2578
2580
|
//#region ../forgejo/src/secrets.ts
|
|
2579
|
-
const ActionSecretListSchema = z.object({
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
});
|
|
2581
|
+
const ActionSecretListSchema = z.array(z.object({ name: z.string() }));
|
|
2582
|
+
const SECRETS_PAGE_SIZE = 50;
|
|
2583
|
+
const SECRETS_MAX_PAGES = 20;
|
|
2583
2584
|
z.object({ sha1: z.string() });
|
|
2584
2585
|
const NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
2585
2586
|
const FORBIDDEN_PREFIX_PATTERN = /^(FORGEJO_|GITEA_|GITHUB_|[0-9])/i;
|
|
@@ -2605,10 +2606,8 @@ async function setActionSecret(executor, conn, secretName, secretValue) {
|
|
|
2605
2606
|
async function listActionSecrets(executor, conn) {
|
|
2606
2607
|
const [owner, repo] = conn.repository.split("/");
|
|
2607
2608
|
const names = [];
|
|
2608
|
-
let page = 1;
|
|
2609
|
-
|
|
2610
|
-
for (;;) {
|
|
2611
|
-
const url = `${conn.serverUrl}/api/v1/repos/${owner}/${repo}/actions/secrets?page=${String(page)}&limit=${String(limit)}`;
|
|
2609
|
+
for (let page = 1; page <= 21; page++) {
|
|
2610
|
+
const url = `${conn.serverUrl}/api/v1/repos/${owner}/${repo}/actions/secrets?page=${String(page)}&limit=${String(SECRETS_PAGE_SIZE)}`;
|
|
2612
2611
|
const res = await executor.fetch(url, { headers: { Authorization: `token ${conn.token}` } });
|
|
2613
2612
|
if (!res.ok) throw new TransientError(await forgejoErrorMessage(res, {
|
|
2614
2613
|
verb: "list secrets",
|
|
@@ -2616,9 +2615,9 @@ async function listActionSecrets(executor, conn) {
|
|
|
2616
2615
|
}));
|
|
2617
2616
|
const parsed = ActionSecretListSchema.safeParse(await res.json());
|
|
2618
2617
|
if (!parsed.success) throw new UnexpectedError(`Unexpected secrets list response: ${parsed.error.message}`);
|
|
2619
|
-
for (const secret of parsed.data
|
|
2620
|
-
if (
|
|
2621
|
-
page
|
|
2618
|
+
for (const secret of parsed.data) names.push(secret.name);
|
|
2619
|
+
if (parsed.data.length === 0) break;
|
|
2620
|
+
if (page === 21) throw new UnexpectedError(`${owner}/${repo} still lists secrets after ${String(SECRETS_MAX_PAGES)} pages; refusing to report a prefix of them`);
|
|
2622
2621
|
}
|
|
2623
2622
|
return names;
|
|
2624
2623
|
}
|
|
@@ -2795,7 +2794,7 @@ const deleteCommand = defineCommand({
|
|
|
2795
2794
|
const secretsCommand = defineCommand({
|
|
2796
2795
|
meta: {
|
|
2797
2796
|
name: "secrets",
|
|
2798
|
-
description: "Low-level CRUD for individual Forgejo Actions secrets (set, list, delete). Use bst setup:secrets (in @bensandee/tooling) for initial repo onboarding"
|
|
2797
|
+
description: "Low-level CRUD for individual Forgejo Actions secrets (set, list, delete). Use pnpm exec bst setup:secrets (in @bensandee/tooling) for initial repo onboarding"
|
|
2799
2798
|
},
|
|
2800
2799
|
args: { json: {
|
|
2801
2800
|
type: "boolean",
|
|
@@ -2879,11 +2878,11 @@ async function hasAdminAccess(executor, conn) {
|
|
|
2879
2878
|
const OrgSchema = z.object({ username: z.string() });
|
|
2880
2879
|
const OrgListSchema = z.array(OrgSchema);
|
|
2881
2880
|
const PAGE_LIMIT = 50;
|
|
2881
|
+
const MAX_PAGES = 100;
|
|
2882
2882
|
async function paginate(executor, conn, endpoint, verb, extract) {
|
|
2883
2883
|
const all = [];
|
|
2884
|
-
let page = 1;
|
|
2885
2884
|
const separator = endpoint.includes("?") ? "&" : "?";
|
|
2886
|
-
for (
|
|
2885
|
+
for (let page = 1; page <= 101; page++) {
|
|
2887
2886
|
const url = `${conn.serverUrl}/api/v1${endpoint}${separator}page=${String(page)}&limit=${String(PAGE_LIMIT)}`;
|
|
2888
2887
|
const res = await executor.fetch(url, { headers: { Authorization: `token ${conn.token}` } });
|
|
2889
2888
|
if (!res.ok) throw new TransientError(await forgejoErrorMessage(res, {
|
|
@@ -2893,7 +2892,7 @@ async function paginate(executor, conn, endpoint, verb, extract) {
|
|
|
2893
2892
|
const items = extract(await res.json());
|
|
2894
2893
|
all.push(...items);
|
|
2895
2894
|
if (items.length < PAGE_LIMIT) break;
|
|
2896
|
-
page
|
|
2895
|
+
if (page === 101) throw new UnexpectedError(`${endpoint} still returns full pages after ${String(MAX_PAGES)} pages; refusing to report a prefix of it`);
|
|
2897
2896
|
}
|
|
2898
2897
|
return all;
|
|
2899
2898
|
}
|
|
@@ -3516,6 +3515,7 @@ function collectInputArgs(rawArgs) {
|
|
|
3516
3515
|
for (let i = 0; i < rawArgs.length; i += 1) {
|
|
3517
3516
|
const arg = rawArgs[i];
|
|
3518
3517
|
if (arg === void 0) continue;
|
|
3518
|
+
if (arg === "--") break;
|
|
3519
3519
|
if (arg === INPUT_FLAG) {
|
|
3520
3520
|
const next = rawArgs[i + 1];
|
|
3521
3521
|
if (next === void 0) throw new FatalError("Missing value for --input: expected `--input key=value`");
|
|
@@ -4505,7 +4505,7 @@ function formatIssueList(result) {
|
|
|
4505
4505
|
//#endregion
|
|
4506
4506
|
//#region src/issue-transport.ts
|
|
4507
4507
|
function githubRefusal(command) {
|
|
4508
|
-
return `bst-fj is Forgejo-only -- use \`gh\` or \`bst ${command}\` for a github.com repository.`;
|
|
4508
|
+
return `bst-fj is Forgejo-only -- use \`gh\` or \`pnpm exec bst ${command}\` for a github.com repository.`;
|
|
4509
4509
|
}
|
|
4510
4510
|
function forgejoIssueTarget(cwd, target, command) {
|
|
4511
4511
|
const conn = requireForgejoTarget(cwd, target, githubRefusal(command));
|
|
@@ -4580,7 +4580,7 @@ const issueCommentCommand = defineCommand({
|
|
|
4580
4580
|
out.json(result);
|
|
4581
4581
|
out.text(formatIssueComment(result, dryRun));
|
|
4582
4582
|
} catch (error) {
|
|
4583
|
-
if (error instanceof IssueNumberRequiredError) throw new FatalError(describeIssueNumberRequired("bst-fj issue:comment 273"));
|
|
4583
|
+
if (error instanceof IssueNumberRequiredError) throw new FatalError(describeIssueNumberRequired("pnpm exec bst-fj issue:comment 273"));
|
|
4584
4584
|
throw error;
|
|
4585
4585
|
}
|
|
4586
4586
|
}
|
|
@@ -4807,7 +4807,7 @@ const issueDownloadCommand = defineCommand({
|
|
|
4807
4807
|
out.json(result);
|
|
4808
4808
|
out.text(formatDownload(result, dryRun));
|
|
4809
4809
|
} catch (error) {
|
|
4810
|
-
if (error instanceof IssueNumberRequiredError) throw new FatalError(describeIssueNumberRequired("bst-fj issue:download 273"));
|
|
4810
|
+
if (error instanceof IssueNumberRequiredError) throw new FatalError(describeIssueNumberRequired("pnpm exec bst-fj issue:download 273"));
|
|
4811
4811
|
if (error instanceof AttachmentExistsError) throw new FatalError(describeAttachmentExists(error, "--force"));
|
|
4812
4812
|
throw error;
|
|
4813
4813
|
}
|
|
@@ -4987,7 +4987,7 @@ function defineIssueLabelCommand(action) {
|
|
|
4987
4987
|
out.json(result);
|
|
4988
4988
|
out.text(formatIssueLabel(result, dryRun));
|
|
4989
4989
|
} catch (error) {
|
|
4990
|
-
if (error instanceof IssueNumberRequiredError) throw new FatalError(describeIssueNumberRequired(`bst-fj ${name} 273 agent/implement`));
|
|
4990
|
+
if (error instanceof IssueNumberRequiredError) throw new FatalError(describeIssueNumberRequired(`pnpm exec bst-fj ${name} 273 agent/implement`));
|
|
4991
4991
|
throw error;
|
|
4992
4992
|
}
|
|
4993
4993
|
}
|
|
@@ -5050,7 +5050,7 @@ const issueSetLabelsCommand = defineCommand({
|
|
|
5050
5050
|
out.json(result);
|
|
5051
5051
|
out.text(formatIssueSetLabels(result, dryRun));
|
|
5052
5052
|
} catch (error) {
|
|
5053
|
-
if (error instanceof IssueNumberRequiredError) throw new FatalError(describeIssueNumberRequired("bst-fj issue:set-labels 273 agent/plan"));
|
|
5053
|
+
if (error instanceof IssueNumberRequiredError) throw new FatalError(describeIssueNumberRequired("pnpm exec bst-fj issue:set-labels 273 agent/plan"));
|
|
5054
5054
|
if (error instanceof NoLabelsGivenError) throw new FatalError(describeNoLabelsGiven(error, "--clear"));
|
|
5055
5055
|
throw error;
|
|
5056
5056
|
}
|
|
@@ -5214,10 +5214,10 @@ function defineIssueStateCommand(action) {
|
|
|
5214
5214
|
out.text(formatIssueState(result, dryRun));
|
|
5215
5215
|
if (dryRun && comment !== void 0 && result.comment?.posted === true) out.text(`[dry-run] Comment that would be posted:\n${comment}`);
|
|
5216
5216
|
} catch (error) {
|
|
5217
|
-
if (error instanceof IssueNumberRequiredError) throw new FatalError(describeIssueNumberRequired(`bst-fj ${name} 273`));
|
|
5217
|
+
if (error instanceof IssueNumberRequiredError) throw new FatalError(describeIssueNumberRequired(`pnpm exec bst-fj ${name} 273`));
|
|
5218
5218
|
if (error instanceof EmptyCommentError) throw new FatalError(describeEmptyComment(flags));
|
|
5219
5219
|
if (error instanceof PullRequestStateError) {
|
|
5220
|
-
const advice = action === "close" ? `Run \`bst-fj pr:close ${String(error.number)}\` to close it.` : "Use the forge UI to change a pull request's state.";
|
|
5220
|
+
const advice = action === "close" ? `Run \`pnpm exec bst-fj pr:close ${String(error.number)}\` to close it.` : "Use the forge UI to change a pull request's state.";
|
|
5221
5221
|
throw new FatalError(describePullRequestState(error, {
|
|
5222
5222
|
command: `bst-fj ${name}`,
|
|
5223
5223
|
advice
|
|
@@ -5351,7 +5351,7 @@ const issueUpdateCommand = defineCommand({
|
|
|
5351
5351
|
out.text(`[dry-run] Current body:\n${current}`);
|
|
5352
5352
|
}
|
|
5353
5353
|
} catch (error) {
|
|
5354
|
-
if (error instanceof IssueNumberRequiredError) throw new FatalError(describeIssueNumberRequired("bst-fj issue:update 273 --title '...'"));
|
|
5354
|
+
if (error instanceof IssueNumberRequiredError) throw new FatalError(describeIssueNumberRequired("pnpm exec bst-fj issue:update 273 --title '...'"));
|
|
5355
5355
|
if (error instanceof NothingToUpdateError) throw new FatalError(describeNothingToUpdate({
|
|
5356
5356
|
title: "--title",
|
|
5357
5357
|
body: "--body",
|
|
@@ -5399,7 +5399,7 @@ const issueSubCommands = {
|
|
|
5399
5399
|
out.json(view);
|
|
5400
5400
|
out.text(formatIssue(view));
|
|
5401
5401
|
} catch (error) {
|
|
5402
|
-
if (error instanceof IssueNumberRequiredError) throw new FatalError(describeIssueNumberRequired("bst-fj issue:view 273"));
|
|
5402
|
+
if (error instanceof IssueNumberRequiredError) throw new FatalError(describeIssueNumberRequired("pnpm exec bst-fj issue:view 273"));
|
|
5403
5403
|
throw error;
|
|
5404
5404
|
}
|
|
5405
5405
|
}
|
|
@@ -5776,7 +5776,7 @@ const prCloseCommand = defineCommand({
|
|
|
5776
5776
|
if (dryRun && comment !== void 0 && result.comment?.posted === true) out.text(`[dry-run] Comment that would be posted:\n${comment}`);
|
|
5777
5777
|
} catch (error) {
|
|
5778
5778
|
if (error instanceof EmptyCommentError) throw new FatalError(describeEmptyComment(flags));
|
|
5779
|
-
if (error instanceof NotAPullRequestError) throw new FatalError(`#${String(error.number)} is an issue, not a pull request -- pr:close refuses to write issue state. Use \`bst-fj issue:close ${String(error.number)}\` to close it.`);
|
|
5779
|
+
if (error instanceof NotAPullRequestError) throw new FatalError(`#${String(error.number)} is an issue, not a pull request -- pr:close refuses to write issue state. Use \`pnpm exec bst-fj issue:close ${String(error.number)}\` to close it.`);
|
|
5780
5780
|
throw error;
|
|
5781
5781
|
}
|
|
5782
5782
|
}
|
|
@@ -6327,8 +6327,8 @@ function cliGit() {
|
|
|
6327
6327
|
//#endregion
|
|
6328
6328
|
//#region src/pr-run.ts
|
|
6329
6329
|
const COMMANDS = {
|
|
6330
|
-
create: "bst-fj pr:create",
|
|
6331
|
-
update: "bst-fj pr:update"
|
|
6330
|
+
create: "pnpm exec bst-fj pr:create",
|
|
6331
|
+
update: "pnpm exec bst-fj pr:update"
|
|
6332
6332
|
};
|
|
6333
6333
|
const FLAGS = {
|
|
6334
6334
|
body: "--body",
|
|
@@ -6411,7 +6411,7 @@ const prCreateCommand = defineCommand({
|
|
|
6411
6411
|
async run({ args }) {
|
|
6412
6412
|
const out = createCliOutput(args.json === true);
|
|
6413
6413
|
const body = readBodySource(args.body ?? void 0, args["body-file"] ?? void 0);
|
|
6414
|
-
const result = await runForgejoPr("bst-fj pr:create works on Forgejo only. Use `gh pr create` on GitHub, or `bst pr:create`, which covers both.", {
|
|
6414
|
+
const result = await runForgejoPr("bst-fj pr:create works on Forgejo only. Use `gh pr create` on GitHub, or `pnpm exec bst pr:create`, which covers both.", {
|
|
6415
6415
|
mode: args.upsert === true ? "upsert" : "create",
|
|
6416
6416
|
title: args.title ?? void 0,
|
|
6417
6417
|
body,
|
|
@@ -6434,6 +6434,7 @@ const prCreateCommand = defineCommand({
|
|
|
6434
6434
|
const DEFAULT_LIMIT = 100;
|
|
6435
6435
|
const PrFileEntrySchema = z.object({
|
|
6436
6436
|
filename: z.string(),
|
|
6437
|
+
previous_filename: z.string().nullish(),
|
|
6437
6438
|
status: z.string().nullish(),
|
|
6438
6439
|
additions: z.number().default(0),
|
|
6439
6440
|
deletions: z.number().default(0)
|
|
@@ -6466,6 +6467,7 @@ async function readPrFilesPage(executor, conn, prNumber, page, limit) {
|
|
|
6466
6467
|
return {
|
|
6467
6468
|
files: parsed.data.map((file) => ({
|
|
6468
6469
|
filename: file.filename,
|
|
6470
|
+
previousFilename: file.previous_filename ?? null,
|
|
6469
6471
|
status: file.status ?? null,
|
|
6470
6472
|
additions: file.additions,
|
|
6471
6473
|
deletions: file.deletions
|
|
@@ -7144,7 +7146,7 @@ const prSubCommands = {
|
|
|
7144
7146
|
const out = createCliOutput(args.json === true);
|
|
7145
7147
|
const body = readBodySource(args.body ?? void 0, args["body-file"] ?? void 0);
|
|
7146
7148
|
const rewrites = args.title !== void 0 || body !== void 0;
|
|
7147
|
-
const result = await runForgejoPr("bst-fj pr:update works on Forgejo only. Use `gh pr edit` on GitHub, or `bst pr:update`, which covers both.", {
|
|
7149
|
+
const result = await runForgejoPr("bst-fj pr:update works on Forgejo only. Use `gh pr edit` on GitHub, or `pnpm exec bst pr:update`, which covers both.", {
|
|
7148
7150
|
mode: "update",
|
|
7149
7151
|
title: args.title ?? void 0,
|
|
7150
7152
|
body,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bensandee/forgejo-cli",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.5",
|
|
4
4
|
"description": "bst-fj: Forgejo API commands without the rest of bst",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -29,13 +29,13 @@
|
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@bensandee/common": "0.2.0",
|
|
31
31
|
"citty": "^0.2.2",
|
|
32
|
-
"zod": "^4.6.
|
|
32
|
+
"zod": "^4.6.7"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@bensandee/cli-kit": "0.0.0",
|
|
36
36
|
"@bensandee/forgejo": "0.7.0",
|
|
37
|
-
"@types/node": "24.19.
|
|
38
|
-
"tsdown": "0.23.
|
|
37
|
+
"@types/node": "24.19.2",
|
|
38
|
+
"tsdown": "0.23.1"
|
|
39
39
|
},
|
|
40
40
|
"scripts": {
|
|
41
41
|
"build": "tsdown",
|