feat(fleet): harden v1 migration preview
Some checks failed
ci/woodpecker/pr/ci Pipeline failed

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Jarvis
2026-07-16 00:57:33 -05:00
parent 0e814324ca
commit 04891422b3
14 changed files with 477 additions and 82 deletions

View File

@@ -17,9 +17,9 @@ export interface FleetMigrationCommandDeps {
}
interface PreviewOptions {
readonly source?: string;
readonly decisions?: string;
readonly observations?: string;
readonly source?: string | boolean;
readonly decisions?: string | boolean;
readonly observations?: string | boolean;
}
/** Registers preview-only v1 migration. This command has no mutation verbs or runners. */
@@ -32,9 +32,9 @@ export function registerFleetMigrationCommand(
.description('Preview a field-complete v1-to-v2 roster migration')
.command('preview')
.description('Compile migration evidence without writing files or changing runtimes')
.option('--source <path>', 'v1 roster YAML or JSON')
.option('--decisions <path>', 'explicit migration decisions JSON')
.option('--observations <path>', 'reviewed lifecycle observations JSON')
.option('--source [path]', 'v1 roster YAML or JSON')
.option('--decisions [path]', 'explicit migration decisions JSON')
.option('--observations [path]', 'reviewed lifecycle observations JSON')
.action(async (options: PreviewOptions): Promise<void> => {
const readText = deps.readText ?? ((path: string): Promise<string> => readFile(path, 'utf8'));
const printJson =
@@ -58,7 +58,24 @@ export function registerFleetMigrationCommand(
setExitCode(1);
return;
}
const emptyOption = requiredOptionNames.find((name) => options[name]?.trim() === '');
const missingValueOption = requiredOptionNames.find((name) => options[name] === true);
if (missingValueOption !== undefined) {
printJson({
status: 'blocked',
blockers: [
{
code: 'missing-migration-preview-option-value',
path: `request.${missingValueOption}`,
detail: 'Required migration preview option value is missing.',
},
],
});
setExitCode(1);
return;
}
const emptyOption = requiredOptionNames.find(
(name) => typeof options[name] === 'string' && options[name].trim() === '',
);
if (emptyOption !== undefined) {
printJson({
status: 'blocked',
@@ -77,9 +94,9 @@ export function registerFleetMigrationCommand(
const decisionsPath = options.decisions;
const observationsPath = options.observations;
if (
sourcePath === undefined ||
decisionsPath === undefined ||
observationsPath === undefined
typeof sourcePath !== 'string' ||
typeof decisionsPath !== 'string' ||
typeof observationsPath !== 'string'
) {
throw new Error('Validated migration preview options became unavailable.');
}