@code-pushup/coverage-plugin
Version:
Code PushUp plugin for tracking code coverage ☂
94 lines • 4.63 kB
JavaScript
import { bold } from 'ansis';
import path from 'node:path';
import { importModule, ui } from '@code-pushup/utils';
/**
* @param targets nx targets to be used for measuring coverage, test by default
* @returns An array of coverage result information for the coverage plugin.
*/
export async function getNxCoveragePaths(targets = ['test'], verbose) {
if (verbose) {
ui().logger.info(bold('💡 Gathering coverage from the following nx projects:'));
}
const { createProjectGraphAsync } = await import('@nx/devkit');
const { nodes } = await createProjectGraphAsync({ exitOnError: false });
const coverageResults = await Promise.all(targets.map(async (target) => {
const relevantNodes = Object.values(nodes).filter(graph => hasNxTarget(graph, target));
return await Promise.all(relevantNodes.map(async ({ name, data }) => {
const coveragePaths = await getCoveragePathsForTarget(data, target);
if (verbose) {
ui().logger.info(`- ${name}: ${target}`);
}
return coveragePaths;
}));
}));
if (verbose) {
ui().logger.info('\n');
}
return coverageResults.flat();
}
function hasNxTarget(project, target) {
return project.data.targets != null && target in project.data.targets;
}
export async function getCoveragePathsForTarget(project, target) {
const targetConfig = project.targets?.[target];
if (!targetConfig) {
throw new Error(`No configuration found for target ${target} in project ${project.name}`);
}
if (targetConfig.executor?.includes('@nx/vite')) {
return getCoveragePathForVitest(targetConfig.options, project, target);
}
if (targetConfig.executor?.includes('@nx/jest')) {
return getCoveragePathForJest(targetConfig.options, project, target);
}
throw new Error(`Unsupported executor ${targetConfig.executor}. Only @nx/vite and @nx/jest are currently supported.`);
}
export async function getCoveragePathForVitest(options, project, target) {
const { default: { normalizeViteConfigFilePathWithTree }, } = await import('@nx/vite');
const config = normalizeViteConfigFilePathWithTree(
// HACK: only tree.exists is called, so injecting existSync from node:fs instead
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
{ exists: (await import('node:fs')).existsSync }, project.root, options.configFile);
if (!config) {
throw new Error(`Could not find Vitest config file for target ${target} in project ${project.name}`);
}
const vitestConfig = await importModule({
filepath: config,
format: 'esm',
});
const reportsDirectory = options.reportsDirectory ?? vitestConfig.test.coverage?.reportsDirectory;
const reporter = vitestConfig.test.coverage?.reporter;
if (reportsDirectory == null) {
throw new Error(`Vitest coverage configuration at ${config} does not include coverage path for target ${target} in project ${project.name}. Add the path under coverage > reportsDirectory.`);
}
if (!reporter?.some(format => format === 'lcov' || format === 'lcovonly')) {
throw new Error(`Vitest coverage configuration at ${config} does not include LCOV report format for target ${target} in project ${project.name}. Add 'lcov' format under coverage > reporter.`);
}
if (path.isAbsolute(reportsDirectory)) {
return path.join(reportsDirectory, 'lcov.info');
}
return {
pathToProject: project.root,
resultsPath: path.join(project.root, reportsDirectory, 'lcov.info'),
};
}
export async function getCoveragePathForJest(options, project, target) {
const { jestConfig } = options;
const testConfig = await importModule({
filepath: jestConfig,
});
const { coverageDirectory, coverageReporters } = {
...testConfig,
...options,
};
if (coverageDirectory == null) {
throw new Error(`Jest coverage configuration at ${jestConfig} does not include coverage path for target ${target} in ${project.name}. Add the path under coverageDirectory.`);
}
if (!coverageReporters?.includes('lcov') && !('preset' in testConfig)) {
throw new Error(`Jest coverage configuration at ${jestConfig} does not include LCOV report format for target ${target} in ${project.name}. Add 'lcov' format under coverageReporters.`);
}
if (path.isAbsolute(coverageDirectory)) {
return path.join(coverageDirectory, 'lcov.info');
}
return path.join(project.root, coverageDirectory, 'lcov.info');
}
//# sourceMappingURL=coverage-paths.js.map