diff --git a/packages/cli/src/ingest-viz.test.ts b/packages/cli/src/ingest-viz.test.ts index a37c1ed8..7d790ab7 100644 --- a/packages/cli/src/ingest-viz.test.ts +++ b/packages/cli/src/ingest-viz.test.ts @@ -514,6 +514,18 @@ describe('runKtxIngest viz and replay', () => { expect(io.stderr()).toContain('Local ingest run or report "missing-run" was not found'); }); + it('suggests public ingest when status has no stored reports', async () => { + const projectDir = join(tempDir, 'project'); + await writeWarehouseConfig(projectDir); + const io = makeIo(); + + await expect(runKtxIngest({ command: 'status', projectDir, outputMode: 'plain' }, io.io)).resolves.toBe(1); + + expect(io.stderr()).toContain('No local ingest reports were found. Run `ktx ingest ` first.'); + expect(io.stderr()).not.toContain('ktx ingest run --connection-id'); + expect(io.stderr()).not.toContain('--adapter'); + }); + it('uses the latest local ingest report when status has no run id', async () => { const projectDir = join(tempDir, 'project'); await writeWarehouseConfig(projectDir); diff --git a/packages/cli/src/ingest.ts b/packages/cli/src/ingest.ts index a60ceaf0..b1321fde 100644 --- a/packages/cli/src/ingest.ts +++ b/packages/cli/src/ingest.ts @@ -738,7 +738,7 @@ export async function runKtxIngest( throw new Error( args.runId ? `Local ingest run or report "${args.runId}" was not found` - : 'No local ingest reports were found. Run `ktx ingest run --connection-id --adapter ` first.', + : 'No local ingest reports were found. Run `ktx ingest ` first.', ); } await writeReportRecord(report, args.outputMode, io, { diff --git a/packages/cli/src/local-adapters.test.ts b/packages/cli/src/local-adapters.test.ts index 62c46c03..d64f9459 100644 --- a/packages/cli/src/local-adapters.test.ts +++ b/packages/cli/src/local-adapters.test.ts @@ -170,4 +170,34 @@ describe('CLI local ingest adapters', () => { 'historic_sql_patterns', ]); }); + + it('uses query-history wording for public BigQuery capability errors', async () => { + await writeProject( + tempDir, + [ + 'project: warehouse', + 'connections:', + ' bq:', + ' driver: bigquery', + ' readonly: true', + ' dataset_id: analytics', + ' credentials_json: "{}"', + ' context:', + ' queryHistory:', + ' enabled: true', + 'ingest:', + ' adapters:', + ' - historic-sql', + '', + ].join('\n'), + ); + const project = await loadKtxProject({ projectDir: tempDir }); + + expect(() => + createKtxCliLocalIngestAdapters(project, { + historicSqlConnectionId: 'bq', + sqlAnalysis: sqlAnalysisStub(), + }), + ).toThrow('Query history BigQuery connection requires credentials_json.project_id'); + }); }); diff --git a/packages/cli/src/local-adapters.ts b/packages/cli/src/local-adapters.ts index a99af7df..7edbc5fc 100644 --- a/packages/cli/src/local-adapters.ts +++ b/packages/cli/src/local-adapters.ts @@ -210,7 +210,7 @@ function createEphemeralPostgresHistoricSqlClient(project: KtxLocalProject, conn const connection = project.config.connections[connectionId] as KtxPostgresConnectionConfig | undefined; if (!isKtxPostgresConnectionConfig(connection)) { throw new Error( - `Historic SQL local ingest requires a Postgres connection, got ${String(connection?.driver ?? 'unknown')}`, + `Query history ingest requires a Postgres connection, got ${String(connection?.driver ?? 'unknown')}`, ); } return { @@ -232,7 +232,7 @@ function createEphemeralBigQueryHistoricSqlClient(project: KtxLocalProject, conn const connection = project.config.connections[connectionId] as KtxBigQueryConnectionConfig | undefined; if (!isKtxBigQueryConnectionConfig(connection)) { throw new Error( - `Historic SQL local ingest requires a BigQuery connection, got ${String(connection?.driver ?? 'unknown')}`, + `Query history ingest requires a BigQuery connection, got ${String(connection?.driver ?? 'unknown')}`, ); } return { @@ -263,7 +263,7 @@ async function createEphemeralSnowflakeHistoricSqlClient( const connection = project.config.connections[connectionId]; if (!connectorModule.isKtxSnowflakeConnectionConfig(connection)) { throw new Error( - `Historic SQL local ingest requires a Snowflake connection, got ${String(connection?.driver ?? 'unknown')}`, + `Query history ingest requires a Snowflake connection, got ${String(connection?.driver ?? 'unknown')}`, ); } return { @@ -291,7 +291,7 @@ function bigQueryProjectId(connection: KtxBigQueryConnectionConfig, env: NodeJS. const resolved = raw.startsWith('env:') ? env[raw.slice('env:'.length)] ?? '' : raw; const parsed = JSON.parse(resolved) as { project_id?: unknown }; if (typeof parsed.project_id !== 'string' || parsed.project_id.trim().length === 0) { - throw new Error('Historic SQL BigQuery connection requires credentials_json.project_id'); + throw new Error('Query history BigQuery connection requires credentials_json.project_id'); } return parsed.project_id; } @@ -328,7 +328,7 @@ function historicSqlOptionsForLocalRun(project: KtxLocalProject, options: KtxCli if (dialect === 'bigquery') { if (!isKtxBigQueryConnectionConfig(connection)) { throw new Error( - `Historic SQL local ingest requires a BigQuery connection, got ${String(connection?.driver ?? 'unknown')}`, + `Query history ingest requires a BigQuery connection, got ${String(connection?.driver ?? 'unknown')}`, ); } return {