mirror of
https://github.com/Kaelio/ktx.git
synced 2026-06-07 07:55:13 +02:00
ci: configure Codecov coverage uploads (#150)
This commit is contained in:
parent
75bb4f9497
commit
366c44f224
6 changed files with 222 additions and 9 deletions
27
.github/workflows/ci.yml
vendored
27
.github/workflows/ci.yml
vendored
|
|
@ -191,9 +191,8 @@ jobs:
|
|||
coverage:
|
||||
name: Coverage
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
env:
|
||||
CODECOV_TOKEN_CONFIGURED: ${{ secrets.CODECOV_TOKEN != '' }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
|
@ -232,25 +231,39 @@ jobs:
|
|||
run: pnpm run test:coverage:ts
|
||||
|
||||
- name: Upload TypeScript coverage
|
||||
if: env.CODECOV_TOKEN_CONFIGURED == 'true'
|
||||
uses: codecov/codecov-action@75cd11691c0faa626561e295848008c8a7dddffe # v5.5.4
|
||||
with:
|
||||
use_oidc: true
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
slug: Kaelio/ktx
|
||||
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
|
||||
disable_search: true
|
||||
fail_ci_if_error: true
|
||||
|
||||
- name: Warn when Codecov token is missing for TypeScript
|
||||
if: env.CODECOV_TOKEN_CONFIGURED != 'true'
|
||||
run: echo "::warning::CODECOV_TOKEN is not configured; skipping TypeScript coverage upload"
|
||||
|
||||
- name: Generate Python coverage
|
||||
run: pnpm run test:coverage:py
|
||||
|
||||
- name: Upload Python coverage
|
||||
if: env.CODECOV_TOKEN_CONFIGURED == 'true'
|
||||
uses: codecov/codecov-action@75cd11691c0faa626561e295848008c8a7dddffe # v5.5.4
|
||||
with:
|
||||
use_oidc: true
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
slug: Kaelio/ktx
|
||||
files: ./coverage/python.xml
|
||||
flags: python
|
||||
name: python
|
||||
fail_ci_if_error: false
|
||||
disable_search: true
|
||||
fail_ci_if_error: true
|
||||
|
||||
- name: Warn when Codecov token is missing for Python
|
||||
if: env.CODECOV_TOKEN_CONFIGURED != 'true'
|
||||
run: echo "::warning::CODECOV_TOKEN is not configured; skipping Python coverage upload"
|
||||
|
||||
artifact-checks:
|
||||
name: Artifact checks
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@
|
|||
|
||||
<p align="center">
|
||||
<a href="https://www.npmjs.com/package/@kaelio/ktx"><img src="https://img.shields.io/npm/v/@kaelio/ktx?style=flat-square&color=f97316" alt="npm version" /></a>
|
||||
<a href="https://codecov.io/gh/Kaelio/ktx"><img src="https://codecov.io/gh/Kaelio/ktx/branch/main/graph/badge.svg" alt="Codecov" /></a>
|
||||
<a href="https://codecov.io/gh/Kaelio/ktx"><img src="https://codecov.io/gh/Kaelio/ktx/graph/badge.svg?branch=main" alt="Codecov" /></a>
|
||||
<a href="https://docs.kaelio.com/ktx/docs/"><img src="https://img.shields.io/badge/docs-KTX-f97316?style=flat-square" alt="Documentation" /></a>
|
||||
<a href="https://github.com/Kaelio/ktx/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-blue?style=flat-square" alt="License" /></a>
|
||||
<a href="https://github.com/Kaelio/ktx"><img src="https://img.shields.io/github/stars/Kaelio/ktx?style=flat-square" alt="GitHub stars" /></a>
|
||||
</p>
|
||||
|
|
|
|||
109
codecov.yml
Normal file
109
codecov.yml
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
codecov:
|
||||
branch: main
|
||||
require_ci_to_pass: true
|
||||
notify:
|
||||
after_n_builds: 2
|
||||
|
||||
coverage:
|
||||
precision: 2
|
||||
round: down
|
||||
range: "70...100"
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
target: auto
|
||||
threshold: 1%
|
||||
if_ci_failed: error
|
||||
typescript:
|
||||
target: auto
|
||||
threshold: 1%
|
||||
flags:
|
||||
- typescript
|
||||
if_ci_failed: error
|
||||
python:
|
||||
target: auto
|
||||
threshold: 1%
|
||||
flags:
|
||||
- python
|
||||
if_ci_failed: error
|
||||
patch:
|
||||
default:
|
||||
target: 75%
|
||||
threshold: 5%
|
||||
if_ci_failed: error
|
||||
informational: true
|
||||
|
||||
comment:
|
||||
layout: "header, diff, flags, components, files"
|
||||
behavior: default
|
||||
require_changes: false
|
||||
require_base: false
|
||||
require_head: true
|
||||
|
||||
flags:
|
||||
typescript:
|
||||
paths:
|
||||
- packages/
|
||||
carryforward: false
|
||||
python:
|
||||
paths:
|
||||
- python/
|
||||
carryforward: false
|
||||
|
||||
component_management:
|
||||
individual_components:
|
||||
- component_id: pkg_cli
|
||||
name: CLI
|
||||
paths:
|
||||
- packages/cli/src/**
|
||||
- component_id: pkg_context
|
||||
name: Context engine
|
||||
paths:
|
||||
- packages/context/src/**
|
||||
- component_id: pkg_llm
|
||||
name: LLM
|
||||
paths:
|
||||
- packages/llm/src/**
|
||||
- component_id: connector_bigquery
|
||||
name: BigQuery connector
|
||||
paths:
|
||||
- packages/connector-bigquery/src/**
|
||||
- component_id: connector_clickhouse
|
||||
name: ClickHouse connector
|
||||
paths:
|
||||
- packages/connector-clickhouse/src/**
|
||||
- component_id: connector_mysql
|
||||
name: MySQL connector
|
||||
paths:
|
||||
- packages/connector-mysql/src/**
|
||||
- component_id: connector_postgres
|
||||
name: Postgres connector
|
||||
paths:
|
||||
- packages/connector-postgres/src/**
|
||||
- component_id: connector_snowflake
|
||||
name: Snowflake connector
|
||||
paths:
|
||||
- packages/connector-snowflake/src/**
|
||||
- component_id: connector_sqlite
|
||||
name: SQLite connector
|
||||
paths:
|
||||
- packages/connector-sqlite/src/**
|
||||
- component_id: connector_sqlserver
|
||||
name: SQL Server connector
|
||||
paths:
|
||||
- packages/connector-sqlserver/src/**
|
||||
- component_id: py_semantic_layer
|
||||
name: Python semantic layer
|
||||
paths:
|
||||
- python/ktx-sl/semantic_layer/**
|
||||
- component_id: py_daemon
|
||||
name: Python daemon
|
||||
paths:
|
||||
- python/ktx-daemon/src/ktx_daemon/**
|
||||
|
||||
ignore:
|
||||
- docs-site/**
|
||||
- examples/**
|
||||
- packages/*/coverage/**
|
||||
- packages/*/dist/**
|
||||
- python/ktx-sl/demos/**
|
||||
|
|
@ -42,7 +42,7 @@
|
|||
"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:coverage:ts": "pnpm --filter './packages/*' run build && pnpm --filter './packages/*' run test --coverage --coverage.reporter=lcov --coverage.exclude='dist/**' && node scripts/normalize-lcov-paths.mjs packages/*/coverage/lcov.info",
|
||||
"test:slow": "pnpm --filter @ktx/context run test:slow && pnpm --filter @ktx/cli run test:slow",
|
||||
"type-check": "pnpm --filter './packages/*' run type-check"
|
||||
},
|
||||
|
|
|
|||
59
scripts/normalize-lcov-paths.mjs
Normal file
59
scripts/normalize-lcov-paths.mjs
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
import { readFile, writeFile } from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||
|
||||
function toPosix(filePath) {
|
||||
return filePath.replace(/\\/g, '/');
|
||||
}
|
||||
|
||||
export function normalizeLcovContent(content, packagePath) {
|
||||
const normalizedPackagePath = toPosix(packagePath).replace(/\/$/, '');
|
||||
|
||||
return content.replace(/^SF:(.+)$/gm, (line, sourcePath) => {
|
||||
const normalizedSourcePath = toPosix(sourcePath);
|
||||
|
||||
if (
|
||||
path.isAbsolute(sourcePath) ||
|
||||
normalizedSourcePath.startsWith(`${normalizedPackagePath}/`) ||
|
||||
normalizedSourcePath.startsWith('../')
|
||||
) {
|
||||
return line;
|
||||
}
|
||||
|
||||
return `SF:${normalizedPackagePath}/${normalizedSourcePath}`;
|
||||
});
|
||||
}
|
||||
|
||||
export async function normalizeLcovFile(rootDir, reportPath) {
|
||||
const absoluteReportPath = path.resolve(rootDir, reportPath);
|
||||
const packagePath = toPosix(path.relative(rootDir, path.dirname(path.dirname(absoluteReportPath))));
|
||||
const content = await readFile(absoluteReportPath, 'utf8');
|
||||
const normalizedContent = normalizeLcovContent(content, packagePath);
|
||||
|
||||
if (normalizedContent !== content) {
|
||||
await writeFile(absoluteReportPath, normalizedContent);
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const scriptDir = path.dirname(fileURLToPath(import.meta.url));
|
||||
const rootDir = path.resolve(scriptDir, '..');
|
||||
const reportPaths = process.argv.slice(2);
|
||||
|
||||
if (reportPaths.length === 0) {
|
||||
throw new Error('Usage: normalize-lcov-paths.mjs <coverage/lcov.info> [...]');
|
||||
}
|
||||
|
||||
for (const reportPath of reportPaths) {
|
||||
await normalizeLcovFile(rootDir, reportPath);
|
||||
}
|
||||
}
|
||||
|
||||
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
||||
main().catch((error) => {
|
||||
console.error(error instanceof Error ? error.message : error);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
}
|
||||
31
scripts/normalize-lcov-paths.test.mjs
Normal file
31
scripts/normalize-lcov-paths.test.mjs
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import assert from 'node:assert/strict';
|
||||
import { describe, it } from 'node:test';
|
||||
|
||||
import { normalizeLcovContent } from './normalize-lcov-paths.mjs';
|
||||
|
||||
describe('normalizeLcovContent', () => {
|
||||
it('prefixes relative LCOV source paths with the package path', () => {
|
||||
const input = ['TN:', 'SF:src/index.ts', 'SF:src\\windows.ts', 'DA:1,1', 'end_of_record'].join('\n');
|
||||
|
||||
assert.equal(
|
||||
normalizeLcovContent(input, 'packages/context'),
|
||||
[
|
||||
'TN:',
|
||||
'SF:packages/context/src/index.ts',
|
||||
'SF:packages/context/src/windows.ts',
|
||||
'DA:1,1',
|
||||
'end_of_record',
|
||||
].join('\n'),
|
||||
);
|
||||
});
|
||||
|
||||
it('leaves already-normalized and absolute paths unchanged', () => {
|
||||
const input = [
|
||||
'SF:packages/cli/src/index.ts',
|
||||
'SF:/tmp/repo/packages/cli/src/index.ts',
|
||||
'SF:../shared/source.ts',
|
||||
].join('\n');
|
||||
|
||||
assert.equal(normalizeLcovContent(input, 'packages/cli'), input);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue