mirror of
https://github.com/Kaelio/ktx.git
synced 2026-06-10 08:05:14 +02:00
feat(cli): pass managed daemon options to scan
This commit is contained in:
parent
d24415413f
commit
478c06d467
5 changed files with 106 additions and 1 deletions
|
|
@ -1,5 +1,6 @@
|
|||
import { type Command, InvalidArgumentError, Option } from '@commander-js/extra-typings';
|
||||
import { type KtxCliCommandContext, parsePositiveIntegerOption, resolveCommandProjectDir } from '../cli-program.js';
|
||||
import { runtimeInstallPolicyFromFlags } from '../managed-python-command.js';
|
||||
import type { KtxScanArgs } from '../scan.js';
|
||||
import { profileMark } from '../startup-profile.js';
|
||||
|
||||
|
|
@ -102,6 +103,8 @@ export function registerScanCommands(program: Command, context: KtxCliCommandCon
|
|||
)
|
||||
.option('--dry-run', 'Run without writing scan results', false)
|
||||
.option('--database-introspection-url <url>', 'Daemon URL for live-database introspection')
|
||||
.option('--yes', 'Install the managed Python runtime without prompting when required', false)
|
||||
.option('--no-input', 'Disable interactive managed runtime installation')
|
||||
.showHelpAfterError()
|
||||
.addHelpText(
|
||||
'after',
|
||||
|
|
@ -126,6 +129,8 @@ export function registerScanCommands(program: Command, context: KtxCliCommandCon
|
|||
detectRelationships: mode === 'relationships',
|
||||
dryRun: options.dryRun === true,
|
||||
databaseIntrospectionUrl: options.databaseIntrospectionUrl,
|
||||
cliVersion: context.packageInfo.version,
|
||||
runtimeInstallPolicy: runtimeInstallPolicyFromFlags(options),
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -234,6 +234,8 @@ describe('dev Commander tree', () => {
|
|||
detectRelationships: false,
|
||||
dryRun: true,
|
||||
databaseIntrospectionUrl: undefined,
|
||||
cliVersion: '0.0.0-private',
|
||||
runtimeInstallPolicy: 'prompt',
|
||||
},
|
||||
scanIo.io,
|
||||
);
|
||||
|
|
@ -259,6 +261,8 @@ describe('dev Commander tree', () => {
|
|||
detectRelationships: true,
|
||||
dryRun: false,
|
||||
databaseIntrospectionUrl: undefined,
|
||||
cliVersion: '0.0.0-private',
|
||||
runtimeInstallPolicy: 'prompt',
|
||||
},
|
||||
io.io,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2117,11 +2117,48 @@ describe('runKtxCli', () => {
|
|||
detectRelationships: false,
|
||||
dryRun: false,
|
||||
databaseIntrospectionUrl: undefined,
|
||||
cliVersion: '0.0.0-private',
|
||||
runtimeInstallPolicy: 'prompt',
|
||||
},
|
||||
testIo.io,
|
||||
);
|
||||
});
|
||||
|
||||
it('routes scan managed runtime install policies', async () => {
|
||||
const autoIo = makeIo();
|
||||
const neverIo = makeIo();
|
||||
const conflictIo = makeIo();
|
||||
const scan = vi.fn().mockResolvedValue(0);
|
||||
|
||||
await expect(runKtxCli(['--project-dir', tempDir, 'dev', 'scan', 'warehouse', '--yes'], autoIo.io, { scan }))
|
||||
.resolves.toBe(0);
|
||||
await expect(runKtxCli(['--project-dir', tempDir, 'dev', 'scan', 'warehouse', '--no-input'], neverIo.io, { scan }))
|
||||
.resolves.toBe(0);
|
||||
await expect(
|
||||
runKtxCli(['--project-dir', tempDir, 'dev', 'scan', 'warehouse', '--yes', '--no-input'], conflictIo.io, {
|
||||
scan,
|
||||
}),
|
||||
).resolves.toBe(1);
|
||||
|
||||
expect(scan).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
expect.objectContaining({
|
||||
command: 'run',
|
||||
runtimeInstallPolicy: 'auto',
|
||||
}),
|
||||
autoIo.io,
|
||||
);
|
||||
expect(scan).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
expect.objectContaining({
|
||||
command: 'run',
|
||||
runtimeInstallPolicy: 'never',
|
||||
}),
|
||||
neverIo.io,
|
||||
);
|
||||
expect(conflictIo.stderr()).toContain('Choose only one runtime install mode: --yes or --no-input');
|
||||
});
|
||||
|
||||
it('dispatches serve public command options through Commander', async () => {
|
||||
const serveIo = makeIo();
|
||||
const serveStdio = vi.fn(async () => 0);
|
||||
|
|
|
|||
|
|
@ -356,6 +356,49 @@ describe('runKtxScan', () => {
|
|||
expect(io.stdout()).not.toContain('/~');
|
||||
});
|
||||
|
||||
it('passes managed daemon options to local ingest adapters when no explicit daemon URL is set', async () => {
|
||||
await initKtxProject({ projectDir: tempDir, projectName: 'warehouse' });
|
||||
const createLocalIngestAdapters = vi.fn(() => []);
|
||||
const runLocalScan = vi.fn(
|
||||
async (_input: RunLocalScanOptions): Promise<LocalScanRunResult> => ({
|
||||
runId: 'scan-run-1',
|
||||
status: 'done',
|
||||
done: true,
|
||||
connectionId: 'warehouse',
|
||||
mode: 'structural',
|
||||
dryRun: false,
|
||||
syncId: 'sync-1',
|
||||
report,
|
||||
}),
|
||||
);
|
||||
const io = makeIo();
|
||||
|
||||
await expect(
|
||||
runKtxScan(
|
||||
{
|
||||
command: 'run',
|
||||
projectDir: tempDir,
|
||||
connectionId: 'warehouse',
|
||||
mode: 'structural',
|
||||
detectRelationships: false,
|
||||
dryRun: false,
|
||||
cliVersion: '0.2.0',
|
||||
runtimeInstallPolicy: 'auto',
|
||||
},
|
||||
io.io,
|
||||
{ runLocalScan, createLocalIngestAdapters },
|
||||
),
|
||||
).resolves.toBe(0);
|
||||
|
||||
expect(createLocalIngestAdapters).toHaveBeenCalledWith(expect.objectContaining({ projectDir: tempDir }), {
|
||||
managedDaemon: {
|
||||
cliVersion: '0.2.0',
|
||||
installPolicy: 'auto',
|
||||
io: io.io,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('explains warnings, capability gaps, and relationships in human scan summaries', async () => {
|
||||
await initKtxProject({ projectDir: tempDir, projectName: 'warehouse' });
|
||||
const runLocalScan = vi.fn(
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import {
|
|||
import type { KtxCliIo } from './index.js';
|
||||
import { createKtxCliLocalIngestAdapters } from './local-adapters.js';
|
||||
import { createKtxCliScanConnector } from './local-scan-connectors.js';
|
||||
import type { KtxManagedPythonInstallPolicy } from './managed-python-command.js';
|
||||
import { profileMark } from './startup-profile.js';
|
||||
|
||||
profileMark('module:scan');
|
||||
|
|
@ -46,6 +47,8 @@ export type KtxScanArgs =
|
|||
detectRelationships: boolean;
|
||||
dryRun: boolean;
|
||||
databaseIntrospectionUrl?: string;
|
||||
cliVersion?: string;
|
||||
runtimeInstallPolicy?: KtxManagedPythonInstallPolicy;
|
||||
}
|
||||
| { command: 'status'; projectDir: string; runId: string }
|
||||
| { command: 'report'; projectDir: string; runId: string; json: boolean }
|
||||
|
|
@ -220,6 +223,17 @@ function warningLine(warning: KtxScanWarning): string {
|
|||
return `${warning.code}: ${location}${warning.message}`;
|
||||
}
|
||||
|
||||
function managedDaemonOptionsForScanRun(args: Extract<KtxScanArgs, { command: 'run' }>, io: KtxCliIo) {
|
||||
if (args.databaseIntrospectionUrl || !args.cliVersion || !args.runtimeInstallPolicy) {
|
||||
return undefined;
|
||||
}
|
||||
return {
|
||||
cliVersion: args.cliVersion,
|
||||
installPolicy: args.runtimeInstallPolicy,
|
||||
io,
|
||||
};
|
||||
}
|
||||
|
||||
function writeNeedsAttention(report: KtxScanReport, io: KtxCliIo): void {
|
||||
io.stdout.write('\nNeeds attention\n');
|
||||
if (report.warnings.length === 0 && report.capabilityGaps.length === 0) {
|
||||
|
|
@ -704,6 +718,7 @@ export async function runKtxScan(args: KtxScanArgs, io: KtxCliIo = process, deps
|
|||
return 0;
|
||||
}
|
||||
|
||||
const managedDaemon = managedDaemonOptionsForScanRun(args, io);
|
||||
const connector =
|
||||
args.mode !== 'structural' || args.detectRelationships
|
||||
? await createKtxCliScanConnector(project, args.connectionId)
|
||||
|
|
@ -720,7 +735,8 @@ export async function runKtxScan(args: KtxScanArgs, io: KtxCliIo = process, deps
|
|||
databaseIntrospectionUrl: args.databaseIntrospectionUrl,
|
||||
connector,
|
||||
adapters: (deps.createLocalIngestAdapters ?? createKtxCliLocalIngestAdapters)(project, {
|
||||
databaseIntrospectionUrl: args.databaseIntrospectionUrl,
|
||||
...(args.databaseIntrospectionUrl ? { databaseIntrospectionUrl: args.databaseIntrospectionUrl } : {}),
|
||||
...(managedDaemon ? { managedDaemon } : {}),
|
||||
}),
|
||||
progress,
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue