mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-26 09:52:11 +03:00
feat(triage): add args parser with env var fallback
This commit is contained in:
110
scripts/features/lib/args.mjs
Normal file
110
scripts/features/lib/args.mjs
Normal file
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* Args parser for feature-triage CLI.
|
||||
* Precedence: CLI flag > env var > default.
|
||||
*/
|
||||
|
||||
const DEFAULTS = {
|
||||
quarantineDays: 14,
|
||||
overrideThumbs: 5,
|
||||
overrideCommenters: 3,
|
||||
staleNeedsDays: 30,
|
||||
staleDeferDays: 90,
|
||||
ideiaDir: "_ideia",
|
||||
changelog: "CHANGELOG.md",
|
||||
output: null,
|
||||
dryRun: false,
|
||||
verbose: false,
|
||||
onlyIssues: [],
|
||||
};
|
||||
|
||||
const ENV_MAP = {
|
||||
quarantineDays: "FEATURE_QUARANTINE_DAYS",
|
||||
overrideThumbs: "FEATURE_OVERRIDE_THUMBS",
|
||||
overrideCommenters: "FEATURE_OVERRIDE_COMMENTERS",
|
||||
staleNeedsDays: "FEATURE_STALE_NEEDS_DAYS",
|
||||
staleDeferDays: "FEATURE_STALE_DEFER_DAYS",
|
||||
};
|
||||
|
||||
function takeNext(argv, i) {
|
||||
if (i + 1 >= argv.length) {
|
||||
throw new Error(`${argv[i]} requires a value`);
|
||||
}
|
||||
return argv[i + 1];
|
||||
}
|
||||
|
||||
export function parseArgs(argv, env = process.env) {
|
||||
const out = { ...DEFAULTS, owner: null, repo: null };
|
||||
|
||||
for (const [key, envKey] of Object.entries(ENV_MAP)) {
|
||||
if (env[envKey] !== undefined) {
|
||||
const n = Number(env[envKey]);
|
||||
if (Number.isFinite(n)) out[key] = n;
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < argv.length; i++) {
|
||||
const a = argv[i];
|
||||
switch (a) {
|
||||
case "--owner":
|
||||
out.owner = takeNext(argv, i);
|
||||
i++;
|
||||
break;
|
||||
case "--repo":
|
||||
out.repo = takeNext(argv, i);
|
||||
i++;
|
||||
break;
|
||||
case "--quarantine-days":
|
||||
out.quarantineDays = Number(takeNext(argv, i));
|
||||
i++;
|
||||
break;
|
||||
case "--override-thumbs":
|
||||
out.overrideThumbs = Number(takeNext(argv, i));
|
||||
i++;
|
||||
break;
|
||||
case "--override-commenters":
|
||||
out.overrideCommenters = Number(takeNext(argv, i));
|
||||
i++;
|
||||
break;
|
||||
case "--stale-needs-days":
|
||||
out.staleNeedsDays = Number(takeNext(argv, i));
|
||||
i++;
|
||||
break;
|
||||
case "--stale-defer-days":
|
||||
out.staleDeferDays = Number(takeNext(argv, i));
|
||||
i++;
|
||||
break;
|
||||
case "--ideia-dir":
|
||||
out.ideiaDir = takeNext(argv, i);
|
||||
i++;
|
||||
break;
|
||||
case "--changelog":
|
||||
out.changelog = takeNext(argv, i);
|
||||
i++;
|
||||
break;
|
||||
case "--output":
|
||||
out.output = takeNext(argv, i);
|
||||
i++;
|
||||
break;
|
||||
case "--dry-run":
|
||||
out.dryRun = true;
|
||||
break;
|
||||
case "--verbose":
|
||||
out.verbose = true;
|
||||
break;
|
||||
case "--only-issues":
|
||||
out.onlyIssues = takeNext(argv, i)
|
||||
.split(",")
|
||||
.map((s) => Number(s.trim()))
|
||||
.filter(Number.isFinite);
|
||||
i++;
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unknown arg: ${a}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (!out.owner) throw new Error("--owner is required");
|
||||
if (!out.repo) throw new Error("--repo is required");
|
||||
|
||||
return out;
|
||||
}
|
||||
48
tests/unit/feature-triage/args.test.mjs
Normal file
48
tests/unit/feature-triage/args.test.mjs
Normal file
@@ -0,0 +1,48 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { parseArgs } from "../../../scripts/features/lib/args.mjs";
|
||||
|
||||
describe("parseArgs", () => {
|
||||
it("requires --owner and --repo", () => {
|
||||
assert.throws(() => parseArgs([]), /--owner is required/);
|
||||
assert.throws(() => parseArgs(["--owner", "x"]), /--repo is required/);
|
||||
});
|
||||
|
||||
it("applies defaults when args/env missing", () => {
|
||||
const args = parseArgs(["--owner", "diegosouzapw", "--repo", "OmniRoute"], {});
|
||||
assert.equal(args.quarantineDays, 14);
|
||||
assert.equal(args.overrideThumbs, 5);
|
||||
assert.equal(args.overrideCommenters, 3);
|
||||
assert.equal(args.staleNeedsDays, 30);
|
||||
assert.equal(args.staleDeferDays, 90);
|
||||
assert.equal(args.ideiaDir, "_ideia");
|
||||
assert.equal(args.changelog, "CHANGELOG.md");
|
||||
assert.equal(args.output, null);
|
||||
assert.equal(args.dryRun, false);
|
||||
assert.equal(args.verbose, false);
|
||||
assert.deepEqual(args.onlyIssues, []);
|
||||
});
|
||||
|
||||
it("CLI arg takes precedence over env var", () => {
|
||||
const args = parseArgs(["--owner", "x", "--repo", "y", "--quarantine-days", "7"], {
|
||||
FEATURE_QUARANTINE_DAYS: "21",
|
||||
});
|
||||
assert.equal(args.quarantineDays, 7);
|
||||
});
|
||||
|
||||
it("env var used when CLI arg missing", () => {
|
||||
const args = parseArgs(["--owner", "x", "--repo", "y"], { FEATURE_QUARANTINE_DAYS: "21" });
|
||||
assert.equal(args.quarantineDays, 21);
|
||||
});
|
||||
|
||||
it("parses --only-issues as comma-separated numbers", () => {
|
||||
const args = parseArgs(["--owner", "x", "--repo", "y", "--only-issues", "1046,1041,980"], {});
|
||||
assert.deepEqual(args.onlyIssues, [1046, 1041, 980]);
|
||||
});
|
||||
|
||||
it("parses --dry-run and --verbose as booleans", () => {
|
||||
const args = parseArgs(["--owner", "x", "--repo", "y", "--dry-run", "--verbose"], {});
|
||||
assert.equal(args.dryRun, true);
|
||||
assert.equal(args.verbose, true);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user