diff --git a/web/scripts/__tests__/check-governance-health.test.ts b/web/scripts/__tests__/check-governance-health.test.ts index 09cbaf55..118b7563 100644 --- a/web/scripts/__tests__/check-governance-health.test.ts +++ b/web/scripts/__tests__/check-governance-health.test.ts @@ -1,4 +1,4 @@ -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, vi, afterEach } from 'vitest'; import type { ActivityData, Comment, @@ -20,6 +20,7 @@ import { extractRole, hadQuorumFailure, inferEligibleVoterCount, + parseArgs, percentile, resolveActivityFile, } from '../check-governance-health'; @@ -962,3 +963,33 @@ describe('resolveActivityFile', () => { expect(result).toContain('public'); }); }); + +describe('parseArgs', () => { + afterEach(() => { + vi.restoreAllMocks(); + }); + + it('returns json: false with no args', () => { + expect(parseArgs([])).toEqual({ json: false }); + }); + + it('returns json: true with --json', () => { + expect(parseArgs(['--json'])).toEqual({ json: true }); + }); + + it('throws on unknown argument', () => { + expect(() => parseArgs(['--unknown'])).toThrow( + 'Unknown argument: --unknown' + ); + }); + + it('prints help and exits on --help', () => { + const log = vi.spyOn(console, 'log').mockImplementation(() => {}); + const exit = vi.spyOn(process, 'exit').mockImplementation((_code) => { + throw new Error('process.exit'); + }); + expect(() => parseArgs(['--help'])).toThrow('process.exit'); + expect(exit).toHaveBeenCalledWith(0); + expect(log).toHaveBeenCalledWith(expect.stringContaining('--json')); + }); +}); diff --git a/web/scripts/check-governance-health.ts b/web/scripts/check-governance-health.ts index 91a32932..9bf38762 100644 --- a/web/scripts/check-governance-health.ts +++ b/web/scripts/check-governance-health.ts @@ -708,6 +708,32 @@ export function resolveActivityFile( return env.ACTIVITY_FILE ?? DEFAULT_ACTIVITY_FILE; } +interface CliOptions { + json: boolean; +} + +export function parseArgs(argv: string[]): CliOptions { + const options: CliOptions = { json: false }; + for (const arg of argv) { + if (arg === '--json') { + options.json = true; + continue; + } + if (arg === '--help') { + console.log( + 'Usage: npm run check-governance-health [--json]\n' + + ' ACTIVITY_FILE=/path/to/activity.json npm run check-governance-health\n\n' + + 'Options:\n' + + ' --json Output report as JSON\n' + + ' --help Show this message' + ); + process.exit(0); + } + throw new Error(`Unknown argument: ${arg}`); + } + return options; +} + function isDirectExecution(): boolean { if (!process.argv[1]) return false; return resolve(process.argv[1]) === resolve(fileURLToPath(import.meta.url)); @@ -715,7 +741,7 @@ function isDirectExecution(): boolean { async function main(): Promise { const activityFile = resolveActivityFile(); - const isJson = process.argv.includes('--json'); + const { json: isJson } = parseArgs(process.argv.slice(2)); if (!existsSync(activityFile)) { console.error(`Activity file not found: ${activityFile}`);