From 0a261fe8a47b9fb75b01bbad209e303d35fd6f25 Mon Sep 17 00:00:00 2001 From: Andrey Avtomonov Date: Thu, 14 May 2026 01:13:31 +0200 Subject: [PATCH 1/2] ci: add codecov coverage reporting (#82) * ci: add codecov coverage reporting * ci: fix codecov and secret scan checks * ci: fix smoke and artifact checks --- .github/workflows/ci.yml | 64 +++++++ knip.json | 1 + package.json | 3 + packages/cli/package.json | 1 + packages/cli/src/doctor.test.ts | 6 +- packages/cli/src/setup-sources.test.ts | 4 +- packages/cli/src/standalone-smoke.test.ts | 10 +- packages/connector-bigquery/package.json | 1 + packages/connector-clickhouse/package.json | 1 + packages/connector-mysql/package.json | 1 + packages/connector-postgres/package.json | 1 + packages/connector-snowflake/package.json | 1 + packages/connector-sqlite/package.json | 1 + packages/connector-sqlserver/package.json | 1 + packages/context/package.json | 1 + packages/llm/package.json | 1 + pnpm-lock.yaml | 187 +++++++++++++++++++-- pyproject.toml | 1 + scripts/package-artifacts.mjs | 5 +- uv.lock | 2 + 20 files changed, 272 insertions(+), 21 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ff0b7843..de9d056d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -188,6 +188,70 @@ jobs: - name: Run Python checks run: uv run pytest + coverage: + name: Coverage + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Setup pnpm + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 + with: + run_install: false + + - name: Setup Node.js + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: "24" + cache: "pnpm" + cache-dependency-path: "pnpm-lock.yaml" + + - name: Install TypeScript dependencies + run: pnpm install --frozen-lockfile + + - name: Setup Python + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + with: + python-version: "3.13" + + - name: Setup uv + uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 + with: + version: "0.11.11" + enable-cache: true + cache-dependency-glob: "uv.lock" + + - name: Install Python dependencies + run: uv sync --all-packages --all-groups + + - name: Generate TypeScript coverage + run: pnpm run test:coverage:ts + + - name: Upload TypeScript coverage + uses: codecov/codecov-action@75cd11691c0faa626561e295848008c8a7dddffe # v5.5.4 + with: + use_oidc: true + files: ./packages/cli/coverage/lcov.info,./packages/connector-bigquery/coverage/lcov.info,./packages/connector-clickhouse/coverage/lcov.info,./packages/connector-mysql/coverage/lcov.info,./packages/connector-postgres/coverage/lcov.info,./packages/connector-snowflake/coverage/lcov.info,./packages/connector-sqlite/coverage/lcov.info,./packages/connector-sqlserver/coverage/lcov.info,./packages/context/coverage/lcov.info,./packages/llm/coverage/lcov.info + flags: typescript + name: typescript + fail_ci_if_error: false + + - name: Generate Python coverage + run: pnpm run test:coverage:py + + - name: Upload Python coverage + uses: codecov/codecov-action@75cd11691c0faa626561e295848008c8a7dddffe # v5.5.4 + with: + use_oidc: true + files: ./coverage/python.xml + flags: python + name: python + fail_ci_if_error: false + artifact-checks: name: Artifact checks runs-on: ubuntu-latest diff --git a/knip.json b/knip.json index a6bf5d26..83a8fb1d 100644 --- a/knip.json +++ b/knip.json @@ -79,6 +79,7 @@ "**/*.gen.ts", "**/*.generated.ts" ], + "ignoreBinaries": ["uv"], "ignoreIssues": { "packages/cli/src/clack.ts": ["exports"], "packages/cli/src/commands/connection-metabase-setup.ts": ["exports", "types"], diff --git a/package.json b/package.json index b105784b..5fa920ff 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,9 @@ "relationships:verify-orbit": "node scripts/relationship-orbit-verification.mjs", "smoke": "pnpm run build && pnpm --filter @ktx/cli run smoke", "test": "node --test scripts/*.test.mjs && pnpm --filter './packages/*' run test", + "test:coverage": "pnpm run test:coverage:ts && pnpm run test:coverage:py", + "test:coverage:py": "uv run pytest --cov=python/ktx-sl/semantic_layer --cov=python/ktx-daemon/src/ktx_daemon --cov-report=xml:coverage/python.xml --cov-report=term", + "test:coverage:ts": "pnpm --filter './packages/*' run build && pnpm --filter './packages/*' run test --coverage --coverage.reporter=lcov --coverage.exclude='dist/**'", "test:slow": "pnpm --filter @ktx/context run test:slow && pnpm --filter @ktx/cli run test:slow", "type-check": "pnpm --filter './packages/*' run type-check" }, diff --git a/packages/cli/package.json b/packages/cli/package.json index 19bcc64b..65895f89 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -54,6 +54,7 @@ "@types/better-sqlite3": "^7.6.13", "@types/node": "^25.7.0", "@types/react": "^19.2.14", + "@vitest/coverage-v8": "^4.1.6", "better-sqlite3": "^12.10.0", "ink-testing-library": "^4.0.0", "typescript": "^6.0.3", diff --git a/packages/cli/src/doctor.test.ts b/packages/cli/src/doctor.test.ts index d5db8ab6..b96ee04a 100644 --- a/packages/cli/src/doctor.test.ts +++ b/packages/cli/src/doctor.test.ts @@ -281,7 +281,7 @@ describe('runKtxDoctor', () => { }); it('runs project checks against a valid ktx.yaml', async () => { - process.env.ANTHROPIC_API_KEY = 'test-key'; + process.env.ANTHROPIC_API_KEY = 'test-key'; // pragma: allowlist secret await writeFile( join(tempDir, 'ktx.yaml'), [ @@ -306,7 +306,7 @@ describe('runKtxDoctor', () => { ].join('\n'), 'utf-8', ); - process.env.OPENAI_API_KEY = 'test-key'; + process.env.OPENAI_API_KEY = 'test-key'; // pragma: allowlist secret const testIo = makeIo(); await expect( @@ -357,7 +357,7 @@ describe('runKtxDoctor', () => { }); it('warns when semantic-search embeddings are not configured', async () => { - process.env.ANTHROPIC_API_KEY = 'test-key'; + process.env.ANTHROPIC_API_KEY = 'test-key'; // pragma: allowlist secret await writeFile( join(tempDir, 'ktx.yaml'), [ diff --git a/packages/cli/src/setup-sources.test.ts b/packages/cli/src/setup-sources.test.ts index 0a0eab2c..cb21cd20 100644 --- a/packages/cli/src/setup-sources.test.ts +++ b/packages/cli/src/setup-sources.test.ts @@ -1108,13 +1108,13 @@ describe('setup sources step', () => { }); expect(discoverMetabaseDatabases).toHaveBeenCalledWith({ sourceUrl: 'https://metabase-new.example.com', - sourceApiKeyRef: 'env:METABASE_API_KEY', + sourceApiKeyRef: 'env:METABASE_API_KEY', // pragma: allowlist secret sourceConnectionId: 'metabase-main', }); expect((await readConfig()).connections['metabase-main']).toMatchObject({ driver: 'metabase', api_url: 'https://metabase-new.example.com', - api_key_ref: 'env:METABASE_API_KEY', + api_key_ref: 'env:METABASE_API_KEY', // pragma: allowlist secret mappings: { databaseMappings: { '2': 'warehouse' }, syncEnabled: { '2': true }, diff --git a/packages/cli/src/standalone-smoke.test.ts b/packages/cli/src/standalone-smoke.test.ts index 0f53cca0..ee1b0150 100644 --- a/packages/cli/src/standalone-smoke.test.ts +++ b/packages/cli/src/standalone-smoke.test.ts @@ -200,9 +200,13 @@ describe('standalone built ktx CLI smoke', () => { it('runs doctor setup through the built binary', async () => { const result = await runBuiltCli(['status', '--no-input']); - expect(result.stdout).toMatch(/KTX (setup|project) doctor/); - expect(result.stdout).toContain('Node 22+'); - expect(result.stdout).toContain('Workspace-local CLI'); + expect(result.stdout).toMatch(/KTX (setup doctor|project doctor|status)/); + if (result.stdout.includes('No project here yet.')) { + expect(result.stdout).toContain('Before you can run ktx setup'); + } else { + expect(result.stdout).toContain('Node 22+'); + expect(result.stdout).toContain('Workspace-local CLI'); + } expect(result.stderr === '' || result.stderr.startsWith('Project: ')).toBe(true); expect([0, 1]).toContain(result.code); }); diff --git a/packages/connector-bigquery/package.json b/packages/connector-bigquery/package.json index c21c332f..591e5193 100644 --- a/packages/connector-bigquery/package.json +++ b/packages/connector-bigquery/package.json @@ -31,6 +31,7 @@ }, "devDependencies": { "@types/node": "^25.7.0", + "@vitest/coverage-v8": "^4.1.6", "typescript": "^6.0.3", "vitest": "^4.1.6" }, diff --git a/packages/connector-clickhouse/package.json b/packages/connector-clickhouse/package.json index 8cfbb8eb..568ed6b2 100644 --- a/packages/connector-clickhouse/package.json +++ b/packages/connector-clickhouse/package.json @@ -31,6 +31,7 @@ }, "devDependencies": { "@types/node": "^25.7.0", + "@vitest/coverage-v8": "^4.1.6", "typescript": "^6.0.3", "vitest": "^4.1.6" }, diff --git a/packages/connector-mysql/package.json b/packages/connector-mysql/package.json index dc2df809..16bbc782 100644 --- a/packages/connector-mysql/package.json +++ b/packages/connector-mysql/package.json @@ -31,6 +31,7 @@ }, "devDependencies": { "@types/node": "^25.7.0", + "@vitest/coverage-v8": "^4.1.6", "typescript": "^6.0.3", "vitest": "^4.1.6" }, diff --git a/packages/connector-postgres/package.json b/packages/connector-postgres/package.json index 32991ec3..de7c5457 100644 --- a/packages/connector-postgres/package.json +++ b/packages/connector-postgres/package.json @@ -32,6 +32,7 @@ "devDependencies": { "@types/node": "^25.7.0", "@types/pg": "^8.20.0", + "@vitest/coverage-v8": "^4.1.6", "typescript": "^6.0.3", "vitest": "^4.1.6" }, diff --git a/packages/connector-snowflake/package.json b/packages/connector-snowflake/package.json index fb88c6a3..5135a457 100644 --- a/packages/connector-snowflake/package.json +++ b/packages/connector-snowflake/package.json @@ -31,6 +31,7 @@ }, "devDependencies": { "@types/node": "^25.7.0", + "@vitest/coverage-v8": "^4.1.6", "typescript": "^6.0.3", "vitest": "^4.1.6" }, diff --git a/packages/connector-sqlite/package.json b/packages/connector-sqlite/package.json index f83fdf0e..6dc0b725 100644 --- a/packages/connector-sqlite/package.json +++ b/packages/connector-sqlite/package.json @@ -32,6 +32,7 @@ "devDependencies": { "@types/better-sqlite3": "^7.6.13", "@types/node": "^25.7.0", + "@vitest/coverage-v8": "^4.1.6", "typescript": "^6.0.3", "vitest": "^4.1.6" }, diff --git a/packages/connector-sqlserver/package.json b/packages/connector-sqlserver/package.json index f737aeb3..cf8dac83 100644 --- a/packages/connector-sqlserver/package.json +++ b/packages/connector-sqlserver/package.json @@ -32,6 +32,7 @@ "devDependencies": { "@types/mssql": "^12.3.0", "@types/node": "^25.7.0", + "@vitest/coverage-v8": "^4.1.6", "typescript": "^6.0.3", "vitest": "^4.1.6" }, diff --git a/packages/context/package.json b/packages/context/package.json index 843df92d..32423c20 100644 --- a/packages/context/package.json +++ b/packages/context/package.json @@ -152,6 +152,7 @@ "@types/better-sqlite3": "^7.6.13", "@types/node": "^25.7.0", "@types/pg": "^8.20.0", + "@vitest/coverage-v8": "^4.1.6", "typescript": "^6.0.3", "vitest": "^4.1.6" }, diff --git a/packages/llm/package.json b/packages/llm/package.json index 57d89a43..277e0a98 100644 --- a/packages/llm/package.json +++ b/packages/llm/package.json @@ -34,6 +34,7 @@ }, "devDependencies": { "@types/node": "^25.7.0", + "@vitest/coverage-v8": "^4.1.6", "typescript": "^6.0.3", "vitest": "^4.1.6" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6f9f19b1..de92ff9e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -128,6 +128,9 @@ importers: '@types/react': specifier: ^19.2.14 version: 19.2.14 + '@vitest/coverage-v8': + specifier: ^4.1.6 + version: 4.1.6(vitest@4.1.6) better-sqlite3: specifier: ^12.10.0 version: 12.10.0 @@ -139,7 +142,7 @@ importers: version: 6.0.3 vitest: specifier: ^4.1.6 - version: 4.1.6(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(jiti@2.7.0)(yaml@2.9.0)) + version: 4.1.6(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/coverage-v8@4.1.6)(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(jiti@2.7.0)(yaml@2.9.0)) packages/connector-bigquery: dependencies: @@ -153,12 +156,15 @@ importers: '@types/node': specifier: ^24.3.0 version: 24.12.2 + '@vitest/coverage-v8': + specifier: ^4.1.6 + version: 4.1.6(vitest@4.1.6) typescript: specifier: ^6.0.3 version: 6.0.3 vitest: specifier: ^4.1.6 - version: 4.1.6(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(jiti@2.7.0)(yaml@2.9.0)) + version: 4.1.6(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/coverage-v8@4.1.6)(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(jiti@2.7.0)(yaml@2.9.0)) packages/connector-clickhouse: dependencies: @@ -172,12 +178,15 @@ importers: '@types/node': specifier: ^24.3.0 version: 24.12.2 + '@vitest/coverage-v8': + specifier: ^4.1.6 + version: 4.1.6(vitest@4.1.6) typescript: specifier: ^6.0.3 version: 6.0.3 vitest: specifier: ^4.1.6 - version: 4.1.6(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(jiti@2.7.0)(yaml@2.9.0)) + version: 4.1.6(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/coverage-v8@4.1.6)(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(jiti@2.7.0)(yaml@2.9.0)) packages/connector-mysql: dependencies: @@ -191,12 +200,15 @@ importers: '@types/node': specifier: ^24.3.0 version: 24.12.2 + '@vitest/coverage-v8': + specifier: ^4.1.6 + version: 4.1.6(vitest@4.1.6) typescript: specifier: ^6.0.3 version: 6.0.3 vitest: specifier: ^4.1.6 - version: 4.1.6(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(jiti@2.7.0)(yaml@2.9.0)) + version: 4.1.6(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/coverage-v8@4.1.6)(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(jiti@2.7.0)(yaml@2.9.0)) packages/connector-postgres: dependencies: @@ -213,12 +225,15 @@ importers: '@types/pg': specifier: ^8.20.0 version: 8.20.0 + '@vitest/coverage-v8': + specifier: ^4.1.6 + version: 4.1.6(vitest@4.1.6) typescript: specifier: ^6.0.3 version: 6.0.3 vitest: specifier: ^4.1.6 - version: 4.1.6(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(jiti@2.7.0)(yaml@2.9.0)) + version: 4.1.6(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/coverage-v8@4.1.6)(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(jiti@2.7.0)(yaml@2.9.0)) packages/connector-snowflake: dependencies: @@ -232,12 +247,15 @@ importers: '@types/node': specifier: ^24.3.0 version: 24.12.2 + '@vitest/coverage-v8': + specifier: ^4.1.6 + version: 4.1.6(vitest@4.1.6) typescript: specifier: ^6.0.3 version: 6.0.3 vitest: specifier: ^4.1.6 - version: 4.1.6(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(jiti@2.7.0)(yaml@2.9.0)) + version: 4.1.6(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/coverage-v8@4.1.6)(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(jiti@2.7.0)(yaml@2.9.0)) packages/connector-sqlite: dependencies: @@ -254,12 +272,15 @@ importers: '@types/node': specifier: ^24.3.0 version: 24.12.2 + '@vitest/coverage-v8': + specifier: ^4.1.6 + version: 4.1.6(vitest@4.1.6) typescript: specifier: ^6.0.3 version: 6.0.3 vitest: specifier: ^4.1.6 - version: 4.1.6(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(jiti@2.7.0)(yaml@2.9.0)) + version: 4.1.6(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/coverage-v8@4.1.6)(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(jiti@2.7.0)(yaml@2.9.0)) packages/connector-sqlserver: dependencies: @@ -276,12 +297,15 @@ importers: '@types/node': specifier: ^24.3.0 version: 24.12.2 + '@vitest/coverage-v8': + specifier: ^4.1.6 + version: 4.1.6(vitest@4.1.6) typescript: specifier: ^6.0.3 version: 6.0.3 vitest: specifier: ^4.1.6 - version: 4.1.6(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(jiti@2.7.0)(yaml@2.9.0)) + version: 4.1.6(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/coverage-v8@4.1.6)(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(jiti@2.7.0)(yaml@2.9.0)) packages/context: dependencies: @@ -349,12 +373,15 @@ importers: '@types/pg': specifier: ^8.20.0 version: 8.20.0 + '@vitest/coverage-v8': + specifier: ^4.1.6 + version: 4.1.6(vitest@4.1.6) typescript: specifier: ^6.0.3 version: 6.0.3 vitest: specifier: ^4.1.6 - version: 4.1.6(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(jiti@2.7.0)(yaml@2.9.0)) + version: 4.1.6(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/coverage-v8@4.1.6)(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(jiti@2.7.0)(yaml@2.9.0)) packages/llm: dependencies: @@ -377,12 +404,15 @@ importers: '@types/node': specifier: ^24.3.0 version: 24.12.2 + '@vitest/coverage-v8': + specifier: ^4.1.6 + version: 4.1.6(vitest@4.1.6) typescript: specifier: ^6.0.3 version: 6.0.3 vitest: specifier: ^4.1.6 - version: 4.1.6(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(jiti@2.7.0)(yaml@2.9.0)) + version: 4.1.6(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/coverage-v8@4.1.6)(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(jiti@2.7.0)(yaml@2.9.0)) packages: @@ -750,6 +780,27 @@ packages: resolution: {integrity: sha512-SriLPKezypIsiZ+TtlFfE46uuBIap2HeaQVS78e1P7rz5OSbq0rsd52WE1mC5f7vAeLiXqv7I7oRhL3WFZEw3Q==} engines: {node: '>=18.0.0'} + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.3': + resolution: {integrity: sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + engines: {node: '>=6.9.0'} + + '@bcoe/v8-coverage@1.0.2': + resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} + engines: {node: '>=18'} + '@biomejs/biome@2.4.15': resolution: {integrity: sha512-j5VH3a/h/HXTKBM50MDMxRCzkeLv9S2XJcW2WgnZT1+xyisi+0bISrXR82gCX+8S9lvK0skEvHJRN+3Ktr2hlw==} engines: {node: '>=14.21.3'} @@ -2517,6 +2568,15 @@ packages: resolution: {integrity: sha512-UycprH3T6n3jH0k44NHMa7pnFHGu/N05MjojYr+Mc6I7obkoLIJujSWwin1pCvdy/eOxrI/l3uDLQsmcrOb4ug==} engines: {node: '>= 20'} + '@vitest/coverage-v8@4.1.6': + resolution: {integrity: sha512-36l628fQ/9a/8ihy97eOtEnvWQEdqULQOJtcaxtoNq0G1w3Mxd4szSahOaMM9/NGyZ+hyKcMtIW/WIxq0XQViQ==} + peerDependencies: + '@vitest/browser': 4.1.6 + vitest: 4.1.6 + peerDependenciesMeta: + '@vitest/browser': + optional: true + '@vitest/expect@4.1.6': resolution: {integrity: sha512-7EHDquPthALSV0jhhjgEW8FXaviMx7rSqu8W6oqCoAuOhKov814P99QDV1pxMA3QPv21YudvJngIhjrNI4opLg==} @@ -2627,6 +2687,9 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} + ast-v8-to-istanbul@1.0.0: + resolution: {integrity: sha512-1fSfIwuDICFA4LKkCzRPO7F0hzFf0B7+Xqrl27ynQaa+Rh0e1Es0v6kWHPott3lU10AyAr7oKHa65OppjLn3Rg==} + astring@1.9.0: resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==} hasBin: true @@ -3364,6 +3427,10 @@ packages: engines: {node: '>=0.4.7'} hasBin: true + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + has-symbols@1.1.0: resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} engines: {node: '>= 0.4'} @@ -3414,6 +3481,9 @@ packages: html-entities@2.6.0: resolution: {integrity: sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==} + html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + html-void-elements@3.0.0: resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} @@ -3548,6 +3618,18 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + + istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + + istanbul-reports@3.2.0: + resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} + engines: {node: '>=8'} + jiti@2.7.0: resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} hasBin: true @@ -3558,6 +3640,9 @@ packages: js-md4@0.3.2: resolution: {integrity: sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA==} + js-tokens@10.0.0: + resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} + js-yaml@4.1.1: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true @@ -3718,6 +3803,13 @@ packages: magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + magicast@0.5.2: + resolution: {integrity: sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==} + + make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + markdown-extensions@2.0.0: resolution: {integrity: sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==} engines: {node: '>=16'} @@ -4574,6 +4666,10 @@ packages: babel-plugin-macros: optional: true + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + tagged-tag@1.0.0: resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} engines: {node: '>=20'} @@ -5892,6 +5988,21 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/parser@7.29.3': + dependencies: + '@babel/types': 7.29.0 + + '@babel/types@7.29.0': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@bcoe/v8-coverage@1.0.2': {} + '@biomejs/biome@2.4.15': optionalDependencies: '@biomejs/cli-darwin-arm64': 2.4.15 @@ -7607,6 +7718,20 @@ snapshots: '@vercel/oidc@3.2.0': {} + '@vitest/coverage-v8@4.1.6(vitest@4.1.6)': + dependencies: + '@bcoe/v8-coverage': 1.0.2 + '@vitest/utils': 4.1.6 + ast-v8-to-istanbul: 1.0.0 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-report: 3.0.1 + istanbul-reports: 3.2.0 + magicast: 0.5.2 + obug: 2.1.1 + std-env: 4.1.0 + tinyrainbow: 3.1.0 + vitest: 4.1.6(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/coverage-v8@4.1.6)(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(jiti@2.7.0)(yaml@2.9.0)) + '@vitest/expect@4.1.6': dependencies: '@standard-schema/spec': 1.1.0 @@ -7720,6 +7845,12 @@ snapshots: assertion-error@2.0.1: {} + ast-v8-to-istanbul@1.0.0: + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + estree-walker: 3.0.3 + js-tokens: 10.0.0 + astring@1.9.0: {} async@3.2.6: {} @@ -8458,6 +8589,8 @@ snapshots: optionalDependencies: uglify-js: 3.19.3 + has-flag@4.0.0: {} + has-symbols@1.1.0: {} has-tostringtag@1.0.2: @@ -8584,6 +8717,8 @@ snapshots: html-entities@2.6.0: {} + html-escaper@2.0.2: {} + html-void-elements@3.0.0: {} http-errors@2.0.1: @@ -8714,12 +8849,27 @@ snapshots: isexe@2.0.0: {} + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-report@3.0.1: + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + + istanbul-reports@3.2.0: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + jiti@2.7.0: {} jose@6.2.2: {} js-md4@0.3.2: {} + js-tokens@10.0.0: {} + js-yaml@4.1.1: dependencies: argparse: 2.0.1 @@ -8875,6 +9025,16 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + magicast@0.5.2: + dependencies: + '@babel/parser': 7.29.3 + '@babel/types': 7.29.0 + source-map-js: 1.2.1 + + make-dir@4.0.0: + dependencies: + semver: 7.7.4 + markdown-extensions@2.0.0: {} markdown-table@3.0.4: {} @@ -10176,6 +10336,10 @@ snapshots: client-only: 0.0.1 react: 19.2.6 + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + tagged-tag@1.0.0: {} tailwind-merge@3.6.0: {} @@ -10386,7 +10550,7 @@ snapshots: jiti: 2.7.0 yaml: 2.9.0 - vitest@4.1.6(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(jiti@2.7.0)(yaml@2.9.0)): + vitest@4.1.6(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/coverage-v8@4.1.6)(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(jiti@2.7.0)(yaml@2.9.0)): dependencies: '@vitest/expect': 4.1.6 '@vitest/mocker': 4.1.6(vite@8.0.10(@types/node@24.12.2)(esbuild@0.28.0)(jiti@2.7.0)(yaml@2.9.0)) @@ -10411,6 +10575,7 @@ snapshots: optionalDependencies: '@opentelemetry/api': 1.9.0 '@types/node': 24.12.2 + '@vitest/coverage-v8': 4.1.6(vitest@4.1.6) transitivePeerDependencies: - msw diff --git a/pyproject.toml b/pyproject.toml index e6422fb6..67d2acbb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,6 +15,7 @@ Issues = "https://github.com/kaelio/ktx/issues" dev = [ "pre-commit>=4.6.0", "pytest>=9.0.2", + "pytest-cov>=7.1.0", "ruff>=0.8.4", ] diff --git a/scripts/package-artifacts.mjs b/scripts/package-artifacts.mjs index ee785c27..d6d86cd7 100644 --- a/scripts/package-artifacts.mjs +++ b/scripts/package-artifacts.mjs @@ -937,8 +937,9 @@ try { const doctor = await run('pnpm', ['exec', 'ktx', 'status', '--no-input']); assert.ok([0, 1].includes(doctor.code), 'ktx status setup exit code must be 0 or 1'); - requireStdout('ktx status setup', doctor, /KTX setup doctor/); - requireStdout('ktx status setup', doctor, /Node 22\\+/); + requireStdout('ktx status setup', doctor, /KTX status/); + requireStdout('ktx status setup', doctor, /No project here yet\\./); + requireStdout('ktx status setup', doctor, /Before you can run ktx setup/); assert.equal(doctor.stderr, '', 'ktx status setup wrote unexpected stderr'); } finally { await rm(root, { recursive: true, force: true }); diff --git a/uv.lock b/uv.lock index 5531c8e3..f3ffc767 100644 --- a/uv.lock +++ b/uv.lock @@ -548,6 +548,7 @@ source = { virtual = "." } dev = [ { name = "pre-commit" }, { name = "pytest" }, + { name = "pytest-cov" }, { name = "ruff" }, ] @@ -557,6 +558,7 @@ dev = [ dev = [ { name = "pre-commit", specifier = ">=4.6.0" }, { name = "pytest", specifier = ">=9.0.2" }, + { name = "pytest-cov", specifier = ">=7.1.0" }, { name = "ruff", specifier = ">=0.8.4" }, ] From 339bc39de8011ee81171427b964e62b4f5587fe4 Mon Sep 17 00:00:00 2001 From: Andrey Avtomonov Date: Thu, 14 May 2026 01:21:01 +0200 Subject: [PATCH 2/2] docs: add Codecov badge (#85) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 563525e5..b9923b38 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@

npm version + Codecov License GitHub stars