Skip to content

Commit

Permalink
feat(plugin-coverage): add coverage tool run option, convert to runne…
Browse files Browse the repository at this point in the history
…rConfig
  • Loading branch information
Tlacenka committed Feb 13, 2024
1 parent e05a56e commit d259c14
Show file tree
Hide file tree
Showing 18 changed files with 285 additions and 191 deletions.
2 changes: 0 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,6 @@ jobs:
cache: npm
- name: Install dependencies
run: npm ci
- name: Collect unit test coverage (temporary due to coverage plugin)
run: npx nx run-many -t unit-test --coverage
- name: Collect Code PushUp report
run: npx nx run-collect
- name: Upload Code PushUp report to portal
Expand Down
2 changes: 0 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,6 @@ jobs:
run: |
echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" >> .npmrc
npx nx run-many -t=deploy --exclude=plugin-lighthouse,nx-plugin
- name: Collect unit test coverage (temporary due to coverage plugin)
run: npx nx run-many -t unit-test --coverage
- name: Collect and upload Code PushUp report
run: npx nx run-autorun
env:
Expand Down
6 changes: 5 additions & 1 deletion code-pushup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,11 @@ const config: CoreConfig = {

plugins: [
await eslintPlugin(await eslintConfigFromNxProjects()),
coveragePlugin({
await coveragePlugin({
coverageToolCommand: {
command: 'npx',
args: ['nx', 'run-many', '-t', 'unit-test', '--coverage'],
},
reports: [
{
resultsPath: 'coverage/cli/unit-tests/lcov.info',
Expand Down
19 changes: 3 additions & 16 deletions e2e/cli-e2e/mocks/fixtures/code-pushup.config.coverage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,16 @@ export default {
title: 'Code coverage',
refs: [
{
type: 'audit',
type: 'group',
plugin: 'coverage',
slug: 'function-coverage',
weight: 1,
},
{
type: 'audit',
plugin: 'coverage',
slug: 'branch-coverage',
weight: 1,
},
{
type: 'audit',
plugin: 'coverage',
slug: 'line-coverage',
slug: 'coverage',
weight: 1,
},
],
},
],
plugins: [
coveragePlugin({
coverageTypes: ['branch', 'function', 'line'],
await coveragePlugin({
reports: [
{
resultsPath: join('e2e', 'cli-e2e', 'mocks', 'fixtures', 'lcov.info'),
Expand Down
84 changes: 36 additions & 48 deletions e2e/cli-e2e/tests/__snapshots__/collect.e2e.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,8 @@ exports[`CLI collect > should run Code coverage plugin and create report.json 1`
"refs": [
{
"plugin": "coverage",
"slug": "function-coverage",
"type": "audit",
"weight": 1,
},
{
"plugin": "coverage",
"slug": "branch-coverage",
"type": "audit",
"weight": 1,
},
{
"plugin": "coverage",
"slug": "line-coverage",
"type": "audit",
"slug": "coverage",
"type": "group",
"weight": 1,
},
],
Expand All @@ -32,6 +20,38 @@ exports[`CLI collect > should run Code coverage plugin and create report.json 1`
"plugins": [
{
"audits": [
{
"description": "Measures how many functions were called in at least one test.",
"details": {
"issues": [
{
"message": "Function formatReportScore is not called in any test case.",
"severity": "error",
"source": {
"file": "packages/cli/src/lib/partly-covered/utils.ts",
"position": {
"startLine": 2,
},
},
},
{
"message": "Function sortReport is not called in any test case.",
"severity": "error",
"source": {
"file": "packages/cli/src/lib/not-covered/sorting.ts",
"position": {
"startLine": 1,
},
},
},
],
},
"displayValue": "60 %",
"score": 0.6,
"slug": "function-coverage",
"title": "Function coverage",
"value": 60,
},
{
"description": "Measures how many branches were executed after conditional statements in at least one test.",
"details": {
Expand Down Expand Up @@ -84,38 +104,6 @@ exports[`CLI collect > should run Code coverage plugin and create report.json 1`
"title": "Branch coverage",
"value": 76,
},
{
"description": "Measures how many functions were called in at least one test.",
"details": {
"issues": [
{
"message": "Function formatReportScore is not called in any test case.",
"severity": "error",
"source": {
"file": "packages/cli/src/lib/partly-covered/utils.ts",
"position": {
"startLine": 2,
},
},
},
{
"message": "Function sortReport is not called in any test case.",
"severity": "error",
"source": {
"file": "packages/cli/src/lib/not-covered/sorting.ts",
"position": {
"startLine": 1,
},
},
},
],
},
"displayValue": "60 %",
"score": 0.6,
"slug": "function-coverage",
"title": "Function coverage",
"value": 60,
},
{
"description": "Measures how many lines of code were executed in at least one test.",
"details": {
Expand Down Expand Up @@ -158,11 +146,11 @@ exports[`CLI collect > should run Code coverage plugin and create report.json 1`
"description": "Group containing all defined coverage types as audits.",
"refs": [
{
"slug": "branch-coverage",
"slug": "function-coverage",
"weight": 1,
},
{
"slug": "function-coverage",
"slug": "branch-coverage",
"weight": 1,
},
{
Expand Down
1 change: 1 addition & 0 deletions packages/plugin-coverage/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"outputPath": "dist/packages/plugin-coverage",
"main": "packages/plugin-coverage/src/index.ts",
"tsConfig": "packages/plugin-coverage/tsconfig.lib.json",
"additionalEntryPoints": ["packages/plugin-coverage/src/bin.ts"],
"assets": ["packages/plugin-coverage/*.md"],
"esbuildConfig": "esbuild.config.js"
}
Expand Down
3 changes: 3 additions & 0 deletions packages/plugin-coverage/src/bin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { executeRunner } from './lib/runner';

await executeRunner().catch(console.error);
9 changes: 6 additions & 3 deletions packages/plugin-coverage/src/lib/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { z } from 'zod';
export const coverageTypeSchema = z.enum(['function', 'branch', 'line']);
export type CoverageType = z.infer<typeof coverageTypeSchema>;

export const coverageReportSchema = z.object({
export const coverageResultSchema = z.object({
resultsPath: z.string().includes('lcov'),
pathToProject: z
.string({
Expand All @@ -12,7 +12,7 @@ export const coverageReportSchema = z.object({
})
.optional(),
});
export type CoverageReport = z.infer<typeof coverageReportSchema>;
export type CoverageResult = z.infer<typeof coverageResultSchema>;

export const coveragePluginConfigSchema = z.object({
coverageToolCommand: z
Expand All @@ -34,7 +34,7 @@ export const coveragePluginConfigSchema = z.object({
.min(1)
.default(['function', 'branch', 'line']),
reports: z
.array(coverageReportSchema, {
.array(coverageResultSchema, {
description:
'Path to all code coverage report files. Only LCOV format is supported for now.',
})
Expand All @@ -49,3 +49,6 @@ export const coveragePluginConfigSchema = z.object({
.optional(),
});
export type CoveragePluginConfig = z.input<typeof coveragePluginConfigSchema>;
export type FinalCoveragePluginConfig = z.infer<
typeof coveragePluginConfigSchema
>;
56 changes: 16 additions & 40 deletions packages/plugin-coverage/src/lib/coverage-plugin.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,11 @@
import { join } from 'node:path';
import type {
Audit,
Group,
PluginConfig,
RunnerConfig,
RunnerFunction,
} from '@code-pushup/models';
import { capitalize, pluginWorkDir } from '@code-pushup/utils';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import type { Audit, Group, PluginConfig } from '@code-pushup/models';
import { capitalize } from '@code-pushup/utils';
import { name, version } from '../../package.json';
import { CoveragePluginConfig, coveragePluginConfigSchema } from './config';
import { lcovResultsToAuditOutputs } from './runner/lcov/runner';
import { applyMaxScoreAboveThreshold, coverageDescription } from './utils';

export const RUNNER_OUTPUT_PATH = join(
pluginWorkDir('coverage'),
'runner-output.json',
);
import { createRunnerConfig } from './runner';
import { coverageDescription } from './utils';

/**
* Instantiates Code PushUp code coverage plugin for core config.
Expand All @@ -35,11 +25,12 @@ export const RUNNER_OUTPUT_PATH = join(
*
* @returns Plugin configuration.
*/
export function coveragePlugin(config: CoveragePluginConfig): PluginConfig {
const { reports, perfectScoreThreshold, coverageTypes, coverageToolCommand } =
coveragePluginConfigSchema.parse(config);
export async function coveragePlugin(
config: CoveragePluginConfig,
): Promise<PluginConfig> {
const coverageConfig = coveragePluginConfigSchema.parse(config);

const audits = coverageTypes.map(
const audits = coverageConfig.coverageTypes.map(
(type): Audit => ({
slug: `${type}-coverage`,
title: `${capitalize(type)} coverage`,
Expand All @@ -54,25 +45,10 @@ export function coveragePlugin(config: CoveragePluginConfig): PluginConfig {
refs: audits.map(audit => ({ ...audit, weight: 1 })),
};

const getAuditOutputs = async () =>
perfectScoreThreshold
? applyMaxScoreAboveThreshold(
await lcovResultsToAuditOutputs(reports, coverageTypes),
perfectScoreThreshold,
)
: await lcovResultsToAuditOutputs(reports, coverageTypes);

// if coverage results are provided, only convert them to AuditOutputs
// if not, run coverage command and then run result conversion
const runner: RunnerConfig | RunnerFunction =
coverageToolCommand == null
? getAuditOutputs
: {
command: coverageToolCommand.command,
args: coverageToolCommand.args,
outputFile: RUNNER_OUTPUT_PATH,
outputTransform: getAuditOutputs,
};
const runnerScriptPath = join(
fileURLToPath(dirname(import.meta.url)),
'bin.js',
);

return {
slug: 'coverage',
Expand All @@ -84,6 +60,6 @@ export function coveragePlugin(config: CoveragePluginConfig): PluginConfig {
version,
audits,
groups: [group],
runner,
runner: await createRunnerConfig(runnerScriptPath, coverageConfig),
};
}
Loading

0 comments on commit d259c14

Please sign in to comment.