Ship-step contract for pipelines: uniform exit codes (0/1/2/3/4/7) in cli/lib/ship-step.ts, one final --json line, --result-file (atomic, also on failure), --progress json, --env-file with secret redaction, --version-from; idempotent play upload / apple upload / play release / apple submit re-runs end with exit 7; play upload takes --track production and --version-code
This commit is contained in:
parent
4eac8e8cd8
commit
06a0b424f5
14 changed files with 928 additions and 24 deletions
25
cli/index.ts
25
cli/index.ts
|
|
@ -83,12 +83,35 @@ async function main(): Promise<void> {
|
|||
if (accepted) {
|
||||
const ok = new Set([...FLAGS.global, ...accepted]);
|
||||
const bad = [...new Set(rest.filter(x => /^--[^-]/.test(x)).map(x => x.slice(2).split('=')[0]!).filter(f => !ok.has(f)))];
|
||||
if (bad.length) { console.error(`unknown option${bad.length > 1 ? 's' : ''} for storebound ${key}: ${bad.map(f => '--' + f).join(', ')}\n\n${commandUsage(key)}`); process.exit(2); }
|
||||
if (bad.length) {
|
||||
const why = `unknown option${bad.length > 1 ? 's' : ''} for storebound ${key}: ${bad.map(f => '--' + f).join(', ')}`;
|
||||
console.error(`${why}\n\n${commandUsage(key)}`);
|
||||
// a ship step still answers with its one JSON line / result file (exit 2)
|
||||
const { SHIP_STEPS, usageResult } = await import('./lib/ship-step');
|
||||
if (SHIP_STEPS[key]) usageResult(key, rest, why);
|
||||
process.exit(2);
|
||||
}
|
||||
}
|
||||
// --json: stdout is only the JSON, every log line goes to stderr (lib/log.ts withJsonOutput)
|
||||
|
||||
const json = (f: () => Promise<void>): Promise<void> => (rest.includes('--json') && key !== 'mcp' && key !== 'serve' ? withJsonOutput(f) : f());
|
||||
if (PLAIN[key]) { const plain = PLAIN[key]![0]; return json(async () => (await plain()).run(parseArgs(rest))); }
|
||||
// the ship-step contract (cli/lib/ship-step.ts, docs/ship-step.md): one final JSON line / result file, uniform exit codes
|
||||
const { SHIP_STEPS, runShipStep, shipOptions, usesContract } = await import('./lib/ship-step');
|
||||
if (SHIP_STEPS[key] && (() => { try { return usesContract(shipOptions(parseArgs(rest))); } catch { return true; } })()) {
|
||||
const code = await runShipStep(key, rest, parseArgs, async args => {
|
||||
const go = async (): Promise<void> => {
|
||||
const { loadConfig } = await import('./lib/config');
|
||||
const loaded = await loadConfig(args.get('config'));
|
||||
const { acquireLock, lockKeys } = await import('./lib/lock');
|
||||
for (const k of lockKeys(key, args, loaded.config)) acquireLock(loaded.root, k, argv.filter(x => x !== '--force-unlock').join(' '), { force: args.has('force-unlock') });
|
||||
await (await COMMANDS[key]![0]()).run({ loaded, args });
|
||||
};
|
||||
await (args.has('json') ? withJsonOutput(go) : go());
|
||||
});
|
||||
process.exitCode = code;
|
||||
return;
|
||||
}
|
||||
const args = parseArgs(rest);
|
||||
await json(async () => {
|
||||
const { loadConfig } = await import('./lib/config');
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue