From dae22a9ae3a0fafa95e2711e4308f8e434b8fdbf Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 23 Jul 2025 12:51:10 +0200 Subject: [PATCH 001/111] chore: add local eslint targets --- code-pushup.config.ts | 20 +-- code-pushup.preset.ts | 69 ++++++++-- nx.json | 21 +++ packages/cli/code-pushup.config.ts | 37 ++++++ packages/cli/project.json | 8 ++ packages/core/code-pushup.config.ts | 37 ++++++ packages/core/project.json | 8 ++ packages/models/code-pushup.config.ts | 37 ++++++ packages/models/project.json | 11 ++ .../src/lib/nx/coverage-paths.ts | 22 +++- .../src/lib/nx/coverage-paths.unit.test.ts | 123 ++++++++++++++++-- project.json | 8 +- 12 files changed, 352 insertions(+), 49 deletions(-) create mode 100644 packages/cli/code-pushup.config.ts create mode 100644 packages/core/code-pushup.config.ts create mode 100644 packages/models/code-pushup.config.ts diff --git a/code-pushup.config.ts b/code-pushup.config.ts index 51aa2b33b..18e7ae5db 100644 --- a/code-pushup.config.ts +++ b/code-pushup.config.ts @@ -6,30 +6,14 @@ import { jsDocsCoreConfig, jsPackagesCoreConfig, lighthouseCoreConfig, + loadEnv, typescriptPluginConfig, } from './code-pushup.preset.js'; import type { CoreConfig } from './packages/models/src/index.js'; import { mergeConfigs } from './packages/utils/src/index.js'; -// load upload configuration from environment -const envSchema = z.object({ - CP_SERVER: z.string().url(), - CP_API_KEY: z.string().min(1), - CP_ORGANIZATION: z.string().min(1), - CP_PROJECT: z.string().min(1), -}); -const { data: env } = await envSchema.safeParseAsync(process.env); - const config: CoreConfig = { - ...(env && { - upload: { - server: env.CP_SERVER, - apiKey: env.CP_API_KEY, - organization: env.CP_ORGANIZATION, - project: env.CP_PROJECT, - }, - }), - + ...(await loadEnv()), plugins: [], }; diff --git a/code-pushup.preset.ts b/code-pushup.preset.ts index 15ba02ccc..c5db28546 100644 --- a/code-pushup.preset.ts +++ b/code-pushup.preset.ts @@ -1,4 +1,6 @@ /* eslint-disable @nx/enforce-module-boundaries */ +import 'dotenv/config'; +import { z } from 'zod'; import type { CategoryConfig, CoreConfig, @@ -29,6 +31,46 @@ import typescriptPlugin, { getCategories, } from './packages/plugin-typescript/src/index.js'; +/** + * Helper function to load and validate Code PushUp environment variables for upload configuration + */ +export async function loadEnv() { + const envSchema = z.object({ + CP_SERVER: z.string().url(), + CP_API_KEY: z.string().min(1), + CP_ORGANIZATION: z.string().min(1), + CP_PROJECT: z.string().min(1), + }); + + const { data: env, success } = await envSchema.safeParseAsync(process.env); + + if (!success || !env) { + return {}; + } + const uploadConfig = { + server: env.CP_SERVER, + apiKey: env.CP_API_KEY, + organization: env.CP_ORGANIZATION, + project: env.CP_PROJECT, + }; + return ( + uploadConfig.apiKey && { + upload: uploadConfig, + } + ); +} + +/** + * Common exclusion patterns for JSDoc coverage + */ +export const jsDocsExclusionPatterns = [ + '!packages/**/node_modules', + '!packages/**/{mocks,mock}', + '!**/*.{spec,test}.ts', + '!**/implementation/**', + '!**/internal/**', +]; + export const jsPackagesCategories: CategoryConfig[] = [ { slug: 'security', @@ -131,8 +173,12 @@ export const coverageCategories: CategoryConfig[] = [ }, ]; -export const jsPackagesCoreConfig = async (): Promise => ({ - plugins: [await jsPackagesPlugin()], +export const jsPackagesCoreConfig = async ( + packageJsonPath?: string, +): Promise => ({ + plugins: [ + await jsPackagesPlugin(packageJsonPath ? { packageJsonPath } : undefined), + ], categories: jsPackagesCategories, }); @@ -177,12 +223,12 @@ export const typescriptPluginConfig = async ( categories: getCategories(), }); +/** + * Generates coverage configuration for Nx projects. Supports both single projects and all projects. + */ export const coverageCoreConfigNx = async ( projectName?: string, ): Promise => { - if (projectName) { - throw new Error('coverageCoreConfigNx for single projects not implemented'); - } const targetNames = ['unit-test', 'int-test']; const targetArgs = [ '-t', @@ -195,13 +241,14 @@ export const coverageCoreConfigNx = async ( await coveragePlugin({ coverageToolCommand: { command: 'npx', - args: [ - 'nx', - projectName ? `run --project ${projectName}` : 'run-many', - ...targetArgs, - ], + args: projectName + ? ['nx', 'run-many', '-p', projectName, ...targetArgs] + : ['nx', 'run-many', ...targetArgs], }, - reports: await getNxCoveragePaths(targetNames), + reports: await getNxCoveragePaths( + targetNames, + projectName ? [projectName] : undefined, + ), }), ], categories: coverageCategories, diff --git a/nx.json b/nx.json index 251b8f366..e18e07c32 100644 --- a/nx.json +++ b/nx.json @@ -1,6 +1,27 @@ { "$schema": "./node_modules/nx/schemas/nx-schema.json", "targetDefaults": { + "code-pushup": { + "executor": "nx:run-commands", + "options": { + "command": "node packages/cli/src/index.ts --no-progress --verbose", + "cache": true, + "options": { + "config": "packages/{projectName}/code-pushup.config.ts", + "persist": { + "filename": "{projectName}-report", + "outputDir": "packages/{projectName}/.code-pushup" + }, + "upload": { + "project": "{projectName}" + } + }, + "env": { + "NODE_OPTIONS": "--import tsx", + "TSX_TSCONFIG_PATH": "{workspaceRoot}/tsconfig.base.json" + } + } + }, "build": { "dependsOn": ["^build"], "inputs": ["production", "^production"], diff --git a/packages/cli/code-pushup.config.ts b/packages/cli/code-pushup.config.ts new file mode 100644 index 000000000..35b392440 --- /dev/null +++ b/packages/cli/code-pushup.config.ts @@ -0,0 +1,37 @@ +import 'dotenv/config'; +import { + coverageCoreConfigNx, + eslintCoreConfigNx, + jsDocsCoreConfig, + jsDocsExclusionPatterns, + jsPackagesCoreConfig, + loadEnv, + typescriptPluginConfig, +} from '../../code-pushup.preset.js'; +import type { CoreConfig } from '../../packages/models/src/index.js'; +import { mergeConfigs } from '../../packages/utils/src/index.js'; + +const projectName = process.env.CP_PROJECT_NAME || 'cli'; + +const config: CoreConfig = { + ...(await loadEnv()), + persist: { + filename: `${projectName}-report`, + outputDir: `packages/${projectName}/.code-pushup`, + }, + plugins: [], +}; + +export default mergeConfigs( + config, + await coverageCoreConfigNx(projectName), + await jsPackagesCoreConfig('package.json'), // Use workspace root package.json + await typescriptPluginConfig({ + tsconfig: `packages/${projectName}/tsconfig.lib.json`, + }), + await eslintCoreConfigNx(projectName), + jsDocsCoreConfig([ + `packages/${projectName}/src/**/*.ts`, + ...jsDocsExclusionPatterns, + ]), +); diff --git a/packages/cli/project.json b/packages/cli/project.json index 180ef5c3f..1e993d9a6 100644 --- a/packages/cli/project.json +++ b/packages/cli/project.json @@ -4,6 +4,14 @@ "sourceRoot": "packages/cli/src", "projectType": "library", "targets": { + "code-pushup": { + "options": { + "config": "packages/cli/code-pushup.config.ts" + }, + "env": { + "TSX_TSCONFIG_PATH": "../../tsconfig.base.json" + } + }, "build": { "executor": "@nx/js:tsc", "outputs": ["{options.outputPath}"], diff --git a/packages/core/code-pushup.config.ts b/packages/core/code-pushup.config.ts new file mode 100644 index 000000000..de597af2d --- /dev/null +++ b/packages/core/code-pushup.config.ts @@ -0,0 +1,37 @@ +import 'dotenv/config'; +import { + coverageCoreConfigNx, + eslintCoreConfigNx, + jsDocsCoreConfig, + jsDocsExclusionPatterns, + jsPackagesCoreConfig, + loadEnv, + typescriptPluginConfig, +} from '../../code-pushup.preset.js'; +import type { CoreConfig } from '../../packages/models/src/index.js'; +import { mergeConfigs } from '../../packages/utils/src/index.js'; + +const projectName = process.env.CP_PROJECT_NAME || 'core'; + +const config: CoreConfig = { + ...(await loadEnv()), + persist: { + filename: `${projectName}-report`, + outputDir: `packages/${projectName}/.code-pushup`, + }, + plugins: [], +}; + +export default mergeConfigs( + config, + await coverageCoreConfigNx(projectName), + await jsPackagesCoreConfig('package.json'), // Use workspace root package.json + await typescriptPluginConfig({ + tsconfig: `packages/${projectName}/tsconfig.lib.json`, + }), + await eslintCoreConfigNx(projectName), + jsDocsCoreConfig([ + `packages/${projectName}/src/**/*.ts`, + ...jsDocsExclusionPatterns, + ]), +); diff --git a/packages/core/project.json b/packages/core/project.json index a830a353b..0ff150165 100644 --- a/packages/core/project.json +++ b/packages/core/project.json @@ -4,6 +4,14 @@ "sourceRoot": "packages/core/src", "projectType": "library", "targets": { + "code-pushup": { + "options": { + "config": "packages/core/code-pushup.config.ts" + }, + "env": { + "TSX_TSCONFIG_PATH": "../../tsconfig.base.json" + } + }, "build": { "executor": "@nx/js:tsc", "outputs": ["{options.outputPath}"], diff --git a/packages/models/code-pushup.config.ts b/packages/models/code-pushup.config.ts new file mode 100644 index 000000000..3cabc1092 --- /dev/null +++ b/packages/models/code-pushup.config.ts @@ -0,0 +1,37 @@ +import 'dotenv/config'; +import { + coverageCoreConfigNx, + eslintCoreConfigNx, + jsDocsCoreConfig, + jsDocsExclusionPatterns, + jsPackagesCoreConfig, + loadEnv, + typescriptPluginConfig, +} from '../../code-pushup.preset.js'; +import type { CoreConfig } from '../../packages/models/src/index.js'; +import { mergeConfigs } from '../../packages/utils/src/index.js'; + +const projectName = process.env.CP_PROJECT_NAME || 'models'; + +const config: CoreConfig = { + ...(await loadEnv()), + persist: { + filename: `${projectName}-report`, + outputDir: `packages/${projectName}/.code-pushup`, + }, + plugins: [], +}; + +export default mergeConfigs( + config, + await coverageCoreConfigNx(projectName), + await jsPackagesCoreConfig('package.json'), // Use workspace root package.json + await typescriptPluginConfig({ + tsconfig: `packages/${projectName}/tsconfig.lib.json`, + }), + await eslintCoreConfigNx(projectName), + jsDocsCoreConfig([ + `packages/${projectName}/src/**/*.ts`, + ...jsDocsExclusionPatterns, + ]), +); diff --git a/packages/models/project.json b/packages/models/project.json index 2f2d65e89..b7b07ab32 100644 --- a/packages/models/project.json +++ b/packages/models/project.json @@ -4,6 +4,17 @@ "sourceRoot": "packages/models/src", "projectType": "library", "targets": { + "code-pushup": { + "outputs": ["{options.outputPath}"], + "cache": true, + "options": { + "config": "packages/models/code-pushup.config.ts", + "outputPath": "packages/models/.code-pushup" + }, + "env": { + "TSX_TSCONFIG_PATH": "../../tsconfig.base.json" + } + }, "build": { "dependsOn": [{ "projects": "models-transformers", "target": "build" }], "executor": "@nx/js:tsc", diff --git a/packages/plugin-coverage/src/lib/nx/coverage-paths.ts b/packages/plugin-coverage/src/lib/nx/coverage-paths.ts index a74b0a195..00d17e8fb 100644 --- a/packages/plugin-coverage/src/lib/nx/coverage-paths.ts +++ b/packages/plugin-coverage/src/lib/nx/coverage-paths.ts @@ -12,11 +12,15 @@ import { importModule, ui } from '@code-pushup/utils'; import type { CoverageResult } from '../config.js'; /** + * Gathers coverage paths from Nx projects. Filters by specific projects when provided. * @param targets nx targets to be used for measuring coverage, test by default + * @param projects optional array of project names to filter results for specific projects + * @param verbose optional verbose logging * @returns An array of coverage result information for the coverage plugin. */ export async function getNxCoveragePaths( targets: string[] = ['test'], + projects?: string[], verbose?: boolean, ): Promise { if (verbose) { @@ -30,8 +34,10 @@ export async function getNxCoveragePaths( const coverageResults = await Promise.all( targets.map(async target => { - const relevantNodes = Object.values(nodes).filter(graph => - hasNxTarget(graph, target), + const relevantNodes = Object.values(nodes).filter( + graph => + hasNxTarget(graph, target) && + (projects ? projects.includes(graph.name) : true), ); return await Promise.all( @@ -162,7 +168,7 @@ export async function getCoveragePathForJest( options: JestExecutorOptions, project: ProjectConfiguration, target: string, -) { +): Promise { const { jestConfig } = options; const testConfig = await importModule({ @@ -186,7 +192,13 @@ export async function getCoveragePathForJest( } if (path.isAbsolute(coverageDirectory)) { - return path.join(coverageDirectory, 'lcov.info'); + return { + pathToProject: project.root, + resultsPath: path.join(coverageDirectory, 'lcov.info'), + }; } - return path.join(project.root, coverageDirectory, 'lcov.info'); + return { + pathToProject: project.root, + resultsPath: path.join(project.root, coverageDirectory, 'lcov.info'), + }; } diff --git a/packages/plugin-coverage/src/lib/nx/coverage-paths.unit.test.ts b/packages/plugin-coverage/src/lib/nx/coverage-paths.unit.test.ts index 8d57dba34..35ab06e99 100644 --- a/packages/plugin-coverage/src/lib/nx/coverage-paths.unit.test.ts +++ b/packages/plugin-coverage/src/lib/nx/coverage-paths.unit.test.ts @@ -11,6 +11,7 @@ import { getCoveragePathForJest, getCoveragePathForVitest, getCoveragePathsForTarget, + getNxCoveragePaths, } from './coverage-paths.js'; vi.mock('bundle-require', () => ({ @@ -276,9 +277,16 @@ describe('getCoveragePathForJest', () => { { name: 'cli', root: path.join('packages', 'cli') }, 'unit-test', ), - ).resolves.toBe( - path.join('packages', 'cli', 'coverage', 'core', 'lcov.info'), - ); + ).resolves.toEqual({ + pathToProject: path.join('packages', 'cli'), + resultsPath: path.join( + 'packages', + 'cli', + 'coverage', + 'core', + 'lcov.info', + ), + } satisfies CoverageResult); }); it('should throw when coverageDirectory is not set in Jest config', async () => { @@ -310,9 +318,16 @@ describe('getCoveragePathForJest', () => { { name: 'cli', root: path.join('packages', 'cli') }, 'unit-test', ), - ).resolves.toBe( - path.join('dist', 'packages', 'cli', 'coverage', 'lcov.info'), - ); + ).resolves.toEqual({ + pathToProject: path.join('packages', 'cli'), + resultsPath: path.join( + 'dist', + 'packages', + 'cli', + 'coverage', + 'lcov.info', + ), + } satisfies CoverageResult); }); it('should throw when Jest config does not include lcov reporter', async () => { @@ -335,7 +350,12 @@ describe('getCoveragePathForJest', () => { { name: 'core', root: path.join('packages', 'core') }, 'integration-test', ), - ).resolves.toBeTypeOf('string'); + ).resolves.toEqual( + expect.objectContaining({ + pathToProject: expect.any(String), + resultsPath: expect.any(String), + }), + ); }); it('should throw if lcov reporter from jest config overridden in project.json', async () => { @@ -361,7 +381,12 @@ describe('getCoveragePathForJest', () => { { name: 'core', root: path.join('packages', 'core') }, 'integration-test', ), - ).resolves.toBeTypeOf('string'); + ).resolves.toEqual( + expect.objectContaining({ + pathToProject: expect.any(String), + resultsPath: expect.any(String), + }), + ); }); it('should not throw regarding missing lcov reporter if jest config uses preset', async () => { @@ -371,7 +396,12 @@ describe('getCoveragePathForJest', () => { { name: 'core', root: path.join('packages', 'core') }, 'test', ), - ).resolves.toBeTypeOf('string'); + ).resolves.toEqual( + expect.objectContaining({ + pathToProject: expect.any(String), + resultsPath: expect.any(String), + }), + ); }); it('should handle absolute path in coverageDirectory', async () => { @@ -389,8 +419,79 @@ describe('getCoveragePathForJest', () => { { name: 'cli', root: path.join('packages', 'cli') }, 'unit-test', ), - ).resolves.toBe( - path.join(process.cwd(), 'coverage', 'packages', 'cli', 'lcov.info'), + ).resolves.toEqual({ + pathToProject: path.join('packages', 'cli'), + resultsPath: path.join( + process.cwd(), + 'coverage', + 'packages', + 'cli', + 'lcov.info', + ), + } satisfies CoverageResult); + }); +}); + +describe('getNxCoveragePaths', () => { + beforeEach(() => { + vol.fromJSON( + { + 'vitest-cli.config.ts': '', + 'vitest-core.config.ts': '', + }, + MEMFS_VOLUME, ); + + // Mock createProjectGraphAsync to return a mock project graph + vi.doMock('@nx/devkit', () => ({ + createProjectGraphAsync: vi.fn().mockResolvedValue({ + nodes: { + cli: { + name: 'cli', + type: 'lib', + data: { + name: 'cli', + root: path.join('packages', 'cli'), + targets: { + 'unit-test': { + executor: '@nx/vite:test', + options: { + configFile: 'vitest-cli.config.ts', + } satisfies VitestExecutorOptions, + }, + }, + }, + }, + core: { + name: 'core', + type: 'lib', + data: { + name: 'core', + root: path.join('packages', 'core'), + targets: { + 'unit-test': { + executor: '@nx/vite:test', + options: { + configFile: 'vitest-core.config.ts', + } satisfies VitestExecutorOptions, + }, + }, + }, + }, + }, + }), + })); + }); + + afterEach(() => { + vi.doUnmock('@nx/devkit'); + }); + + it('should filter coverage paths by project names', async () => { + const allResults = await getNxCoveragePaths(['unit-test']); + const filteredResults = await getNxCoveragePaths(['unit-test'], ['cli']); + + expect(allResults).toHaveLength(2); // cli and core + expect(filteredResults).toHaveLength(1); // only cli }); }); diff --git a/project.json b/project.json index a4c550bfb..ef9f7bc9e 100644 --- a/project.json +++ b/project.json @@ -5,10 +5,10 @@ "code-pushup": { "executor": "nx:run-commands", "options": { - "command": "node packages/cli/src/index.ts --no-progress --verbose", - "env": { - "NODE_OPTIONS": "--import tsx", - "TSX_TSCONFIG_PATH": "tsconfig.base.json" + "config": "code-pushup.config.ts", + "persist": { + "filename": "{projectName}-report", + "outputDir": ".code-pushup" } } } From 1c61157e91dfdc63aff5895bd3b5dfe651ba5544 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 23 Jul 2025 20:23:00 +0200 Subject: [PATCH 002/111] chore: add adjust global cp logic --- code-pushup.preset.ts | 2 ++ packages/models/code-pushup.config.ts | 2 +- packages/plugin-eslint/src/bin.ts | 4 ++-- packages/plugin-eslint/src/lib/config.ts | 12 +++++++--- .../plugin-eslint/src/lib/eslint-plugin.ts | 5 +++- .../plugin-eslint/src/lib/runner/index.ts | 22 ++++++++++++------ packages/plugin-eslint/src/lib/runner/lint.ts | 23 +++++++++++-------- 7 files changed, 46 insertions(+), 24 deletions(-) diff --git a/code-pushup.preset.ts b/code-pushup.preset.ts index c5db28546..c8c76b65a 100644 --- a/code-pushup.preset.ts +++ b/code-pushup.preset.ts @@ -205,12 +205,14 @@ export const jsDocsCoreConfig = ( export const eslintCoreConfigNx = async ( projectName?: string, + opt?: { cwd?: string }, ): Promise => ({ plugins: [ await eslintPlugin( await (projectName ? eslintConfigFromNxProject(projectName) : eslintConfigFromAllNxProjects()), + opt, ), ], categories: eslintCategories, diff --git a/packages/models/code-pushup.config.ts b/packages/models/code-pushup.config.ts index 3cabc1092..271ed96b3 100644 --- a/packages/models/code-pushup.config.ts +++ b/packages/models/code-pushup.config.ts @@ -29,7 +29,7 @@ export default mergeConfigs( await typescriptPluginConfig({ tsconfig: `packages/${projectName}/tsconfig.lib.json`, }), - await eslintCoreConfigNx(projectName), + await eslintCoreConfigNx(projectName, { cwd: `./packages/${projectName}` }), jsDocsCoreConfig([ `packages/${projectName}/src/**/*.ts`, ...jsDocsExclusionPatterns, diff --git a/packages/plugin-eslint/src/bin.ts b/packages/plugin-eslint/src/bin.ts index fc625dd73..7171c2e64 100644 --- a/packages/plugin-eslint/src/bin.ts +++ b/packages/plugin-eslint/src/bin.ts @@ -2,6 +2,6 @@ import process from 'node:process'; import { Parser } from 'yargs/helpers'; import { executeRunner } from './lib/runner/index.js'; -const { runnerConfigPath, runnerOutputPath } = Parser(process.argv); +const { runnerConfigPath, runnerOutputPath, cwd } = Parser(process.argv); -await executeRunner({ runnerConfigPath, runnerOutputPath }); +await executeRunner({ runnerConfigPath, runnerOutputPath }, { cwd }); diff --git a/packages/plugin-eslint/src/lib/config.ts b/packages/plugin-eslint/src/lib/config.ts index 4a3133d2c..f3d78b2af 100644 --- a/packages/plugin-eslint/src/lib/config.ts +++ b/packages/plugin-eslint/src/lib/config.ts @@ -6,6 +6,10 @@ const patternsSchema = z.union([z.string(), z.array(z.string()).min(1)], { 'Lint target files. May contain file paths, directory paths or glob patterns', }); +const envSchema = z.object({ + cwd: z.string({ description: 'CWD path' }).optional(), +}); + const eslintrcSchema = z.string({ description: 'Path to ESLint config file' }); const eslintTargetObjectSchema = z.object({ @@ -62,7 +66,9 @@ const customGroupSchema = z.object({ }); export type CustomGroup = z.infer; -export const eslintPluginOptionsSchema = z.object({ - groups: z.array(customGroupSchema).optional(), -}); +export const eslintPluginOptionsSchema = z + .object({ + groups: z.array(customGroupSchema).optional(), + }) + .merge(envSchema); export type ESLintPluginOptions = z.infer; diff --git a/packages/plugin-eslint/src/lib/eslint-plugin.ts b/packages/plugin-eslint/src/lib/eslint-plugin.ts index 285a39e50..7a97ba76a 100644 --- a/packages/plugin-eslint/src/lib/eslint-plugin.ts +++ b/packages/plugin-eslint/src/lib/eslint-plugin.ts @@ -41,6 +41,7 @@ export async function eslintPlugin( schemaType: 'ESLint plugin config', }); + const cwd = options?.cwd || process.cwd(); const customGroups = options ? parseSchema(eslintPluginOptionsSchema, options, { schemaType: 'ESLint plugin options', @@ -71,6 +72,8 @@ export async function eslintPlugin( audits, groups, - runner: await createRunnerConfig(runnerScriptPath, audits, targets), + runner: await createRunnerConfig(runnerScriptPath, audits, targets, { + cwd, + }), }; } diff --git a/packages/plugin-eslint/src/lib/runner/index.ts b/packages/plugin-eslint/src/lib/runner/index.ts index 7e5e8ee9d..b3f9a1901 100644 --- a/packages/plugin-eslint/src/lib/runner/index.ts +++ b/packages/plugin-eslint/src/lib/runner/index.ts @@ -19,16 +19,19 @@ import type { ESLintPluginRunnerConfig, ESLintTarget } from '../config.js'; import { lint } from './lint.js'; import { lintResultsToAudits, mergeLinterOutputs } from './transform.js'; -export async function executeRunner({ - runnerConfigPath, - runnerOutputPath, -}: RunnerFilesPaths): Promise { +export async function executeRunner( + { runnerConfigPath, runnerOutputPath }: RunnerFilesPaths, + opt?: { cwd?: string }, +): Promise { + const { cwd = process.cwd() } = opt || {}; const { slugs, targets } = await readJsonFile(runnerConfigPath); - ui().logger.log(`ESLint plugin executing ${targets.length} lint targets`); + ui().logger.log( + `ESLint plugin executing ${targets.length} lint targets with cwd: ${cwd}`, + ); - const linterOutputs = await asyncSequential(targets, lint); + const linterOutputs = await asyncSequential(targets, cfg => lint(cfg, opt)); const lintResults = mergeLinterOutputs(linterOutputs); const failedAudits = lintResultsToAudits(lintResults); @@ -51,6 +54,7 @@ export async function createRunnerConfig( scriptPath: string, audits: Audit[], targets: ESLintTarget[], + opt?: { cwd?: string }, ): Promise { const config: ESLintPluginRunnerConfig = { targets, @@ -65,7 +69,11 @@ export async function createRunnerConfig( command: 'node', args: [ filePathToCliArg(scriptPath), - ...objectToCliArgs({ runnerConfigPath, runnerOutputPath }), + ...objectToCliArgs({ + runnerConfigPath, + runnerOutputPath, + ...(opt?.cwd ? { cwd: opt.cwd } : {}), + }), ], configFile: runnerConfigPath, outputFile: runnerOutputPath, diff --git a/packages/plugin-eslint/src/lib/runner/lint.ts b/packages/plugin-eslint/src/lib/runner/lint.ts index 80300ded3..19ea8cf4d 100644 --- a/packages/plugin-eslint/src/lib/runner/lint.ts +++ b/packages/plugin-eslint/src/lib/runner/lint.ts @@ -1,5 +1,6 @@ import type { ESLint, Linter } from 'eslint'; import { platform } from 'node:os'; +import { join } from 'node:path'; import { distinct, executeProcess, @@ -10,20 +11,21 @@ import type { ESLintTarget } from '../config.js'; import { setupESLint } from '../setup.js'; import type { LinterOutput, RuleOptionsPerFile } from './types.js'; -export async function lint({ - eslintrc, - patterns, -}: ESLintTarget): Promise { - const results = await executeLint({ eslintrc, patterns }); +export async function lint( + { eslintrc, patterns }: ESLintTarget, + opt?: { cwd?: string }, +): Promise { + const results = await executeLint({ eslintrc, patterns }, opt); const eslint = await setupESLint(eslintrc); const ruleOptionsPerFile = await loadRuleOptionsPerFile(eslint, results); return { results, ruleOptionsPerFile }; } -async function executeLint({ - eslintrc, - patterns, -}: ESLintTarget): Promise { +async function executeLint( + { eslintrc, patterns }: ESLintTarget, + opt?: { cwd?: string }, +): Promise { + const { cwd = process.cwd() } = opt ?? {}; // running as CLI because ESLint#lintFiles() runs out of memory const { stdout } = await executeProcess({ command: 'npx', @@ -33,13 +35,14 @@ async function executeLint({ ...(typeof eslintrc === 'object' ? ['--no-eslintrc'] : []), '--no-error-on-unmatched-pattern', '--format=json', + `--output-file=${join(cwd, '.eslint-results.json')}`, ...toArray(patterns).map(pattern => // globs need to be escaped on Unix platform() === 'win32' ? pattern : `'${pattern}'`, ), ], ignoreExitCode: true, - cwd: process.cwd(), + cwd, }); return JSON.parse(stdout) as ESLint.LintResult[]; From e81aef0fe87baf362f654530d8e4971430b2df40 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 6 Aug 2025 04:11:33 +0200 Subject: [PATCH 003/111] core: add code-pushup.config.ts projects --- nx.json | 20 ++++++++------------ packages/ci/project.json | 3 +++ packages/cli/project.json | 7 +------ packages/core/project.json | 9 +-------- packages/create-cli/project.json | 1 + packages/models/project.json | 10 +--------- packages/nx-plugin/project.json | 1 + packages/plugin-coverage/project.json | 1 + packages/plugin-eslint/project.json | 1 + packages/plugin-js-packages/project.json | 1 + packages/plugin-jsdocs/project.json | 1 + packages/plugin-lighthouse/project.json | 1 + packages/plugin-typescript/project.json | 1 + packages/utils/project.json | 1 + project.json | 9 ++------- 15 files changed, 25 insertions(+), 42 deletions(-) diff --git a/nx.json b/nx.json index e18e07c32..3822d4478 100644 --- a/nx.json +++ b/nx.json @@ -2,23 +2,19 @@ "$schema": "./node_modules/nx/schemas/nx-schema.json", "targetDefaults": { "code-pushup": { + "cache": true, + "outputs": ["{options.outputPath}"], "executor": "nx:run-commands", "options": { "command": "node packages/cli/src/index.ts --no-progress --verbose", - "cache": true, - "options": { - "config": "packages/{projectName}/code-pushup.config.ts", - "persist": { - "filename": "{projectName}-report", - "outputDir": "packages/{projectName}/.code-pushup" - }, - "upload": { - "project": "{projectName}" - } - }, + "config": "{projectRoot}/code-pushup.config.ts", + "persist.filename": "{projectName}-report", + "persist.outputDir": "{projectRoot}/.code-pushup", + "outputPath": "{projectRoot}/.code-pushup", + "upload.project": "cli-{projectName}", "env": { "NODE_OPTIONS": "--import tsx", - "TSX_TSCONFIG_PATH": "{workspaceRoot}/tsconfig.base.json" + "TSX_TSCONFIG_PATH": "tsconfig.base.json" } } }, diff --git a/packages/ci/project.json b/packages/ci/project.json index a74f13988..120ff36ef 100644 --- a/packages/ci/project.json +++ b/packages/ci/project.json @@ -4,6 +4,9 @@ "sourceRoot": "packages/ci/src", "projectType": "library", "targets": { + "code-pushup": { + "dependsOn": ["unit-test", "int-test"] + }, "build": { "executor": "@nx/js:tsc", "outputs": ["{options.outputPath}"], diff --git a/packages/cli/project.json b/packages/cli/project.json index 1e993d9a6..928bf964b 100644 --- a/packages/cli/project.json +++ b/packages/cli/project.json @@ -5,12 +5,7 @@ "projectType": "library", "targets": { "code-pushup": { - "options": { - "config": "packages/cli/code-pushup.config.ts" - }, - "env": { - "TSX_TSCONFIG_PATH": "../../tsconfig.base.json" - } + "dependsOn": ["unit-test", "int-test"] }, "build": { "executor": "@nx/js:tsc", diff --git a/packages/core/project.json b/packages/core/project.json index 0ff150165..8d90e38fa 100644 --- a/packages/core/project.json +++ b/packages/core/project.json @@ -4,14 +4,7 @@ "sourceRoot": "packages/core/src", "projectType": "library", "targets": { - "code-pushup": { - "options": { - "config": "packages/core/code-pushup.config.ts" - }, - "env": { - "TSX_TSCONFIG_PATH": "../../tsconfig.base.json" - } - }, + "code-pushup": {}, "build": { "executor": "@nx/js:tsc", "outputs": ["{options.outputPath}"], diff --git a/packages/create-cli/project.json b/packages/create-cli/project.json index ed0c24c55..6f118d041 100644 --- a/packages/create-cli/project.json +++ b/packages/create-cli/project.json @@ -4,6 +4,7 @@ "sourceRoot": "packages/create-cli/src", "projectType": "library", "targets": { + "code-pushup": {}, "build": { "executor": "@nx/js:tsc", "outputs": ["{options.outputPath}"], diff --git a/packages/models/project.json b/packages/models/project.json index b7b07ab32..b964d8113 100644 --- a/packages/models/project.json +++ b/packages/models/project.json @@ -5,15 +5,7 @@ "projectType": "library", "targets": { "code-pushup": { - "outputs": ["{options.outputPath}"], - "cache": true, - "options": { - "config": "packages/models/code-pushup.config.ts", - "outputPath": "packages/models/.code-pushup" - }, - "env": { - "TSX_TSCONFIG_PATH": "../../tsconfig.base.json" - } + "dependsOn": ["unit-test", "int-test"] }, "build": { "dependsOn": [{ "projects": "models-transformers", "target": "build" }], diff --git a/packages/nx-plugin/project.json b/packages/nx-plugin/project.json index 73ed871d4..b5f80e88f 100644 --- a/packages/nx-plugin/project.json +++ b/packages/nx-plugin/project.json @@ -5,6 +5,7 @@ "projectType": "library", "implicitDependencies": ["cli"], "targets": { + "code-pushup": {}, "build": { "executor": "@nx/js:tsc", "outputs": ["{options.outputPath}"], diff --git a/packages/plugin-coverage/project.json b/packages/plugin-coverage/project.json index dbcc08847..0cebf67c5 100644 --- a/packages/plugin-coverage/project.json +++ b/packages/plugin-coverage/project.json @@ -4,6 +4,7 @@ "sourceRoot": "packages/plugin-coverage/src", "projectType": "library", "targets": { + "code-pushup": {}, "build": { "executor": "@nx/js:tsc", "outputs": ["{options.outputPath}"], diff --git a/packages/plugin-eslint/project.json b/packages/plugin-eslint/project.json index 5d6c7fbe9..716405683 100644 --- a/packages/plugin-eslint/project.json +++ b/packages/plugin-eslint/project.json @@ -4,6 +4,7 @@ "sourceRoot": "packages/plugin-eslint/src", "projectType": "library", "targets": { + "code-pushup": {}, "build": { "executor": "@nx/js:tsc", "outputs": ["{options.outputPath}"], diff --git a/packages/plugin-js-packages/project.json b/packages/plugin-js-packages/project.json index 44de3c7f5..9e6eda9e5 100644 --- a/packages/plugin-js-packages/project.json +++ b/packages/plugin-js-packages/project.json @@ -4,6 +4,7 @@ "sourceRoot": "packages/plugin-js-packages/src", "projectType": "library", "targets": { + "code-pushup": {}, "build": { "executor": "@nx/js:tsc", "outputs": ["{options.outputPath}"], diff --git a/packages/plugin-jsdocs/project.json b/packages/plugin-jsdocs/project.json index 2eb8ef30b..e1f220b4b 100644 --- a/packages/plugin-jsdocs/project.json +++ b/packages/plugin-jsdocs/project.json @@ -5,6 +5,7 @@ "projectType": "library", "tags": ["scope:plugin", "type:feature", "publishable"], "targets": { + "code-pushup": {}, "build": { "executor": "@nx/js:tsc", "outputs": ["{options.outputPath}"], diff --git a/packages/plugin-lighthouse/project.json b/packages/plugin-lighthouse/project.json index fb62179c0..022e1ce95 100644 --- a/packages/plugin-lighthouse/project.json +++ b/packages/plugin-lighthouse/project.json @@ -4,6 +4,7 @@ "sourceRoot": "packages/plugin-lighthouse/src", "projectType": "library", "targets": { + "code-pushup": {}, "build": { "executor": "@nx/js:tsc", "outputs": ["{options.outputPath}"], diff --git a/packages/plugin-typescript/project.json b/packages/plugin-typescript/project.json index 92da1ecdb..da9cfb79a 100644 --- a/packages/plugin-typescript/project.json +++ b/packages/plugin-typescript/project.json @@ -4,6 +4,7 @@ "sourceRoot": "packages/plugin-typescript/src", "projectType": "library", "targets": { + "code-pushup": {}, "build": { "executor": "@nx/js:tsc", "outputs": ["{options.outputPath}"], diff --git a/packages/utils/project.json b/packages/utils/project.json index ccf3c97f3..c77403c34 100644 --- a/packages/utils/project.json +++ b/packages/utils/project.json @@ -4,6 +4,7 @@ "sourceRoot": "packages/utils/src", "projectType": "library", "targets": { + "code-pushup": {}, "build": { "executor": "@nx/js:tsc", "outputs": ["{options.outputPath}"], diff --git a/project.json b/project.json index ef9f7bc9e..d07e3ce85 100644 --- a/project.json +++ b/project.json @@ -1,15 +1,10 @@ { - "name": "@code-pushup/cli-source", + "name": "cli-source", "$schema": "node_modules/nx/schemas/project-schema.json", "targets": { "code-pushup": { - "executor": "nx:run-commands", "options": { - "config": "code-pushup.config.ts", - "persist": { - "filename": "{projectName}-report", - "outputDir": ".code-pushup" - } + "config": "{workspaceRoot}/code-pushup.config.ts" } } } From 1a320c7e4a6c3a1b67745c13b6791483311c7870 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 6 Aug 2025 04:12:55 +0200 Subject: [PATCH 004/111] fix: revert changes --- packages/ci/code-pushup.config.ts | 37 +++++++++++++++++++ packages/cli/code-pushup.config.ts | 2 +- packages/create-cli/code-pushup.config.ts | 37 +++++++++++++++++++ packages/models/code-pushup.config.ts | 2 +- packages/nx-plugin/code-pushup.config.ts | 37 +++++++++++++++++++ .../plugin-coverage/code-pushup.config.ts | 37 +++++++++++++++++++ packages/plugin-eslint/code-pushup.config.ts | 37 +++++++++++++++++++ .../plugin-js-packages/code-pushup.config.ts | 37 +++++++++++++++++++ packages/plugin-jsdocs/code-pushup.config.ts | 37 +++++++++++++++++++ .../plugin-lighthouse/code-pushup.config.ts | 37 +++++++++++++++++++ .../plugin-typescript/code-pushup.config.ts | 37 +++++++++++++++++++ packages/utils/code-pushup.config.ts | 37 +++++++++++++++++++ 12 files changed, 372 insertions(+), 2 deletions(-) create mode 100644 packages/ci/code-pushup.config.ts create mode 100644 packages/create-cli/code-pushup.config.ts create mode 100644 packages/nx-plugin/code-pushup.config.ts create mode 100644 packages/plugin-coverage/code-pushup.config.ts create mode 100644 packages/plugin-eslint/code-pushup.config.ts create mode 100644 packages/plugin-js-packages/code-pushup.config.ts create mode 100644 packages/plugin-jsdocs/code-pushup.config.ts create mode 100644 packages/plugin-lighthouse/code-pushup.config.ts create mode 100644 packages/plugin-typescript/code-pushup.config.ts create mode 100644 packages/utils/code-pushup.config.ts diff --git a/packages/ci/code-pushup.config.ts b/packages/ci/code-pushup.config.ts new file mode 100644 index 000000000..4958c3831 --- /dev/null +++ b/packages/ci/code-pushup.config.ts @@ -0,0 +1,37 @@ +import 'dotenv/config'; +import { + coverageCoreConfigNx, + eslintCoreConfigNx, + jsDocsCoreConfig, + jsDocsExclusionPatterns, + jsPackagesCoreConfig, + loadEnv, + typescriptPluginConfig, +} from '../../code-pushup.preset.js'; +import type { CoreConfig } from '../../packages/models/src/index.js'; +import { mergeConfigs } from '../../packages/utils/src/index.js'; + +const projectName = process.env.CP_PROJECT_NAME || 'cli'; + +const config: CoreConfig = { + ...(await loadEnv()), + persist: { + filename: `${projectName}-report`, + outputDir: `packages/${projectName}/.code-pushup`, + }, + plugins: [], +}; + +export default mergeConfigs( + config, + await eslintCoreConfigNx(projectName), + await coverageCoreConfigNx(projectName), + await jsPackagesCoreConfig('package.json'), // Use workspace root package.json + await typescriptPluginConfig({ + tsconfig: `packages/${projectName}/tsconfig.lib.json`, + }), + jsDocsCoreConfig([ + `packages/${projectName}/src/**/*.ts`, + ...jsDocsExclusionPatterns, + ]), +); diff --git a/packages/cli/code-pushup.config.ts b/packages/cli/code-pushup.config.ts index 35b392440..4958c3831 100644 --- a/packages/cli/code-pushup.config.ts +++ b/packages/cli/code-pushup.config.ts @@ -24,12 +24,12 @@ const config: CoreConfig = { export default mergeConfigs( config, + await eslintCoreConfigNx(projectName), await coverageCoreConfigNx(projectName), await jsPackagesCoreConfig('package.json'), // Use workspace root package.json await typescriptPluginConfig({ tsconfig: `packages/${projectName}/tsconfig.lib.json`, }), - await eslintCoreConfigNx(projectName), jsDocsCoreConfig([ `packages/${projectName}/src/**/*.ts`, ...jsDocsExclusionPatterns, diff --git a/packages/create-cli/code-pushup.config.ts b/packages/create-cli/code-pushup.config.ts new file mode 100644 index 000000000..a4bb1ed22 --- /dev/null +++ b/packages/create-cli/code-pushup.config.ts @@ -0,0 +1,37 @@ +import 'dotenv/config'; +import { + coverageCoreConfigNx, + eslintCoreConfigNx, + jsDocsCoreConfig, + jsDocsExclusionPatterns, + jsPackagesCoreConfig, + loadEnv, + typescriptPluginConfig, +} from '../../code-pushup.preset.js'; +import type { CoreConfig } from '../../packages/models/src/index.js'; +import { mergeConfigs } from '../../packages/utils/src/index.js'; + +const projectName = process.env.CP_PROJECT_NAME || 'create-cli'; + +const config: CoreConfig = { + ...(await loadEnv()), + persist: { + filename: `${projectName}-report`, + outputDir: `packages/${projectName}/.code-pushup`, + }, + plugins: [], +}; + +export default mergeConfigs( + config, + await eslintCoreConfigNx(projectName), + await coverageCoreConfigNx(projectName), + await jsPackagesCoreConfig('package.json'), // Use workspace root package.json + await typescriptPluginConfig({ + tsconfig: `packages/${projectName}/tsconfig.lib.json`, + }), + jsDocsCoreConfig([ + `packages/${projectName}/src/**/*.ts`, + ...jsDocsExclusionPatterns, + ]), +); diff --git a/packages/models/code-pushup.config.ts b/packages/models/code-pushup.config.ts index 271ed96b3..352dfd523 100644 --- a/packages/models/code-pushup.config.ts +++ b/packages/models/code-pushup.config.ts @@ -24,12 +24,12 @@ const config: CoreConfig = { export default mergeConfigs( config, + await eslintCoreConfigNx(projectName), await coverageCoreConfigNx(projectName), await jsPackagesCoreConfig('package.json'), // Use workspace root package.json await typescriptPluginConfig({ tsconfig: `packages/${projectName}/tsconfig.lib.json`, }), - await eslintCoreConfigNx(projectName, { cwd: `./packages/${projectName}` }), jsDocsCoreConfig([ `packages/${projectName}/src/**/*.ts`, ...jsDocsExclusionPatterns, diff --git a/packages/nx-plugin/code-pushup.config.ts b/packages/nx-plugin/code-pushup.config.ts new file mode 100644 index 000000000..2c4af73ce --- /dev/null +++ b/packages/nx-plugin/code-pushup.config.ts @@ -0,0 +1,37 @@ +import 'dotenv/config'; +import { + coverageCoreConfigNx, + eslintCoreConfigNx, + jsDocsCoreConfig, + jsDocsExclusionPatterns, + jsPackagesCoreConfig, + loadEnv, + typescriptPluginConfig, +} from '../../code-pushup.preset.js'; +import type { CoreConfig } from '../../packages/models/src/index.js'; +import { mergeConfigs } from '../../packages/utils/src/index.js'; + +const projectName = process.env.CP_PROJECT_NAME || 'nx-plugin'; + +const config: CoreConfig = { + ...(await loadEnv()), + persist: { + filename: `${projectName}-report`, + outputDir: `packages/${projectName}/.code-pushup`, + }, + plugins: [], +}; + +export default mergeConfigs( + config, + await eslintCoreConfigNx(projectName), + await coverageCoreConfigNx(projectName), + await jsPackagesCoreConfig('package.json'), // Use workspace root package.json + await typescriptPluginConfig({ + tsconfig: `packages/${projectName}/tsconfig.lib.json`, + }), + jsDocsCoreConfig([ + `packages/${projectName}/src/**/*.ts`, + ...jsDocsExclusionPatterns, + ]), +); diff --git a/packages/plugin-coverage/code-pushup.config.ts b/packages/plugin-coverage/code-pushup.config.ts new file mode 100644 index 000000000..dd546f427 --- /dev/null +++ b/packages/plugin-coverage/code-pushup.config.ts @@ -0,0 +1,37 @@ +import 'dotenv/config'; +import { + coverageCoreConfigNx, + eslintCoreConfigNx, + jsDocsCoreConfig, + jsDocsExclusionPatterns, + jsPackagesCoreConfig, + loadEnv, + typescriptPluginConfig, +} from '../../code-pushup.preset.js'; +import type { CoreConfig } from '../../packages/models/src/index.js'; +import { mergeConfigs } from '../../packages/utils/src/index.js'; + +const projectName = process.env.CP_PROJECT_NAME || 'plugin-coverage'; + +const config: CoreConfig = { + ...(await loadEnv()), + persist: { + filename: `${projectName}-report`, + outputDir: `packages/${projectName}/.code-pushup`, + }, + plugins: [], +}; + +export default mergeConfigs( + config, + await eslintCoreConfigNx(projectName), + await coverageCoreConfigNx(projectName), + await jsPackagesCoreConfig('package.json'), // Use workspace root package.json + await typescriptPluginConfig({ + tsconfig: `packages/${projectName}/tsconfig.lib.json`, + }), + jsDocsCoreConfig([ + `packages/${projectName}/src/**/*.ts`, + ...jsDocsExclusionPatterns, + ]), +); diff --git a/packages/plugin-eslint/code-pushup.config.ts b/packages/plugin-eslint/code-pushup.config.ts new file mode 100644 index 000000000..c077677cd --- /dev/null +++ b/packages/plugin-eslint/code-pushup.config.ts @@ -0,0 +1,37 @@ +import 'dotenv/config'; +import { + coverageCoreConfigNx, + eslintCoreConfigNx, + jsDocsCoreConfig, + jsDocsExclusionPatterns, + jsPackagesCoreConfig, + loadEnv, + typescriptPluginConfig, +} from '../../code-pushup.preset.js'; +import type { CoreConfig } from '../../packages/models/src/index.js'; +import { mergeConfigs } from '../../packages/utils/src/index.js'; + +const projectName = process.env.CP_PROJECT_NAME || 'plugin-eslint'; + +const config: CoreConfig = { + ...(await loadEnv()), + persist: { + filename: `${projectName}-report`, + outputDir: `packages/${projectName}/.code-pushup`, + }, + plugins: [], +}; + +export default mergeConfigs( + config, + await eslintCoreConfigNx(projectName), + await coverageCoreConfigNx(projectName), + await jsPackagesCoreConfig('package.json'), // Use workspace root package.json + await typescriptPluginConfig({ + tsconfig: `packages/${projectName}/tsconfig.lib.json`, + }), + jsDocsCoreConfig([ + `packages/${projectName}/src/**/*.ts`, + ...jsDocsExclusionPatterns, + ]), +); diff --git a/packages/plugin-js-packages/code-pushup.config.ts b/packages/plugin-js-packages/code-pushup.config.ts new file mode 100644 index 000000000..9f1f5317f --- /dev/null +++ b/packages/plugin-js-packages/code-pushup.config.ts @@ -0,0 +1,37 @@ +import 'dotenv/config'; +import { + coverageCoreConfigNx, + eslintCoreConfigNx, + jsDocsCoreConfig, + jsDocsExclusionPatterns, + jsPackagesCoreConfig, + loadEnv, + typescriptPluginConfig, +} from '../../code-pushup.preset.js'; +import type { CoreConfig } from '../../packages/models/src/index.js'; +import { mergeConfigs } from '../../packages/utils/src/index.js'; + +const projectName = process.env.CP_PROJECT_NAME || 'plugin-js-packages'; + +const config: CoreConfig = { + ...(await loadEnv()), + persist: { + filename: `${projectName}-report`, + outputDir: `packages/${projectName}/.code-pushup`, + }, + plugins: [], +}; + +export default mergeConfigs( + config, + await eslintCoreConfigNx(projectName), + await coverageCoreConfigNx(projectName), + await jsPackagesCoreConfig('package.json'), // Use workspace root package.json + await typescriptPluginConfig({ + tsconfig: `packages/${projectName}/tsconfig.lib.json`, + }), + jsDocsCoreConfig([ + `packages/${projectName}/src/**/*.ts`, + ...jsDocsExclusionPatterns, + ]), +); diff --git a/packages/plugin-jsdocs/code-pushup.config.ts b/packages/plugin-jsdocs/code-pushup.config.ts new file mode 100644 index 000000000..0f37e7394 --- /dev/null +++ b/packages/plugin-jsdocs/code-pushup.config.ts @@ -0,0 +1,37 @@ +import 'dotenv/config'; +import { + coverageCoreConfigNx, + eslintCoreConfigNx, + jsDocsCoreConfig, + jsDocsExclusionPatterns, + jsPackagesCoreConfig, + loadEnv, + typescriptPluginConfig, +} from '../../code-pushup.preset.js'; +import type { CoreConfig } from '../../packages/models/src/index.js'; +import { mergeConfigs } from '../../packages/utils/src/index.js'; + +const projectName = process.env.CP_PROJECT_NAME || 'plugin-jsdocs'; + +const config: CoreConfig = { + ...(await loadEnv()), + persist: { + filename: `${projectName}-report`, + outputDir: `packages/${projectName}/.code-pushup`, + }, + plugins: [], +}; + +export default mergeConfigs( + config, + await eslintCoreConfigNx(projectName), + await coverageCoreConfigNx(projectName), + await jsPackagesCoreConfig('package.json'), // Use workspace root package.json + await typescriptPluginConfig({ + tsconfig: `packages/${projectName}/tsconfig.lib.json`, + }), + jsDocsCoreConfig([ + `packages/${projectName}/src/**/*.ts`, + ...jsDocsExclusionPatterns, + ]), +); diff --git a/packages/plugin-lighthouse/code-pushup.config.ts b/packages/plugin-lighthouse/code-pushup.config.ts new file mode 100644 index 000000000..9f1f5317f --- /dev/null +++ b/packages/plugin-lighthouse/code-pushup.config.ts @@ -0,0 +1,37 @@ +import 'dotenv/config'; +import { + coverageCoreConfigNx, + eslintCoreConfigNx, + jsDocsCoreConfig, + jsDocsExclusionPatterns, + jsPackagesCoreConfig, + loadEnv, + typescriptPluginConfig, +} from '../../code-pushup.preset.js'; +import type { CoreConfig } from '../../packages/models/src/index.js'; +import { mergeConfigs } from '../../packages/utils/src/index.js'; + +const projectName = process.env.CP_PROJECT_NAME || 'plugin-js-packages'; + +const config: CoreConfig = { + ...(await loadEnv()), + persist: { + filename: `${projectName}-report`, + outputDir: `packages/${projectName}/.code-pushup`, + }, + plugins: [], +}; + +export default mergeConfigs( + config, + await eslintCoreConfigNx(projectName), + await coverageCoreConfigNx(projectName), + await jsPackagesCoreConfig('package.json'), // Use workspace root package.json + await typescriptPluginConfig({ + tsconfig: `packages/${projectName}/tsconfig.lib.json`, + }), + jsDocsCoreConfig([ + `packages/${projectName}/src/**/*.ts`, + ...jsDocsExclusionPatterns, + ]), +); diff --git a/packages/plugin-typescript/code-pushup.config.ts b/packages/plugin-typescript/code-pushup.config.ts new file mode 100644 index 000000000..9f1f5317f --- /dev/null +++ b/packages/plugin-typescript/code-pushup.config.ts @@ -0,0 +1,37 @@ +import 'dotenv/config'; +import { + coverageCoreConfigNx, + eslintCoreConfigNx, + jsDocsCoreConfig, + jsDocsExclusionPatterns, + jsPackagesCoreConfig, + loadEnv, + typescriptPluginConfig, +} from '../../code-pushup.preset.js'; +import type { CoreConfig } from '../../packages/models/src/index.js'; +import { mergeConfigs } from '../../packages/utils/src/index.js'; + +const projectName = process.env.CP_PROJECT_NAME || 'plugin-js-packages'; + +const config: CoreConfig = { + ...(await loadEnv()), + persist: { + filename: `${projectName}-report`, + outputDir: `packages/${projectName}/.code-pushup`, + }, + plugins: [], +}; + +export default mergeConfigs( + config, + await eslintCoreConfigNx(projectName), + await coverageCoreConfigNx(projectName), + await jsPackagesCoreConfig('package.json'), // Use workspace root package.json + await typescriptPluginConfig({ + tsconfig: `packages/${projectName}/tsconfig.lib.json`, + }), + jsDocsCoreConfig([ + `packages/${projectName}/src/**/*.ts`, + ...jsDocsExclusionPatterns, + ]), +); diff --git a/packages/utils/code-pushup.config.ts b/packages/utils/code-pushup.config.ts new file mode 100644 index 000000000..748dca1a9 --- /dev/null +++ b/packages/utils/code-pushup.config.ts @@ -0,0 +1,37 @@ +import 'dotenv/config'; +import { + coverageCoreConfigNx, + eslintCoreConfigNx, + jsDocsCoreConfig, + jsDocsExclusionPatterns, + jsPackagesCoreConfig, + loadEnv, + typescriptPluginConfig, +} from '../../code-pushup.preset.js'; +import type { CoreConfig } from '../../packages/models/src/index.js'; +import { mergeConfigs } from '../../packages/utils/src/index.js'; + +const projectName = process.env.CP_PROJECT_NAME || 'utils'; + +const config: CoreConfig = { + ...(await loadEnv()), + persist: { + filename: `${projectName}-report`, + outputDir: `packages/${projectName}/.code-pushup`, + }, + plugins: [], +}; + +export default mergeConfigs( + config, + await eslintCoreConfigNx(projectName), + await coverageCoreConfigNx(projectName), + await jsPackagesCoreConfig('package.json'), // Use workspace root package.json + await typescriptPluginConfig({ + tsconfig: `packages/${projectName}/tsconfig.lib.json`, + }), + jsDocsCoreConfig([ + `packages/${projectName}/src/**/*.ts`, + ...jsDocsExclusionPatterns, + ]), +); From dfc1171a53dd477c42a71e22bfe68163177197db Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 6 Aug 2025 04:13:00 +0200 Subject: [PATCH 005/111] fix: revert changes --- code-pushup.config.ts | 1 - code-pushup.preset.ts | 2 -- .../src/lib/nx/coverage-paths.unit.test.ts | 13 ++++++++--- packages/plugin-eslint/src/bin.ts | 4 ++-- .../plugin-eslint/src/lib/eslint-plugin.ts | 5 +--- .../plugin-eslint/src/lib/runner/index.ts | 22 ++++++------------ packages/plugin-eslint/src/lib/runner/lint.ts | 23 ++++++++----------- 7 files changed, 30 insertions(+), 40 deletions(-) diff --git a/code-pushup.config.ts b/code-pushup.config.ts index 18e7ae5db..c21859cce 100644 --- a/code-pushup.config.ts +++ b/code-pushup.config.ts @@ -1,5 +1,4 @@ import 'dotenv/config'; -import { z } from 'zod'; import { coverageCoreConfigNx, eslintCoreConfigNx, diff --git a/code-pushup.preset.ts b/code-pushup.preset.ts index c8c76b65a..c5db28546 100644 --- a/code-pushup.preset.ts +++ b/code-pushup.preset.ts @@ -205,14 +205,12 @@ export const jsDocsCoreConfig = ( export const eslintCoreConfigNx = async ( projectName?: string, - opt?: { cwd?: string }, ): Promise => ({ plugins: [ await eslintPlugin( await (projectName ? eslintConfigFromNxProject(projectName) : eslintConfigFromAllNxProjects()), - opt, ), ], categories: eslintCategories, diff --git a/packages/plugin-coverage/src/lib/nx/coverage-paths.unit.test.ts b/packages/plugin-coverage/src/lib/nx/coverage-paths.unit.test.ts index 35ab06e99..9e2bd1fa4 100644 --- a/packages/plugin-coverage/src/lib/nx/coverage-paths.unit.test.ts +++ b/packages/plugin-coverage/src/lib/nx/coverage-paths.unit.test.ts @@ -135,9 +135,16 @@ describe('getCoveragePathForTarget', () => { }, 'test', ), - ).resolves.toBe( - path.join('packages', 'core', 'coverage', 'core', 'lcov.info'), - ); + ).resolves.toStrictEqual({ + pathToProject: path.join('packages', 'core'), + resultsPath: path.join( + 'packages', + 'core', + 'coverage', + 'core', + 'lcov.info', + ), + }); }); it('should throw for unsupported executor (only vitest and jest are supported)', async () => { diff --git a/packages/plugin-eslint/src/bin.ts b/packages/plugin-eslint/src/bin.ts index 7171c2e64..fc625dd73 100644 --- a/packages/plugin-eslint/src/bin.ts +++ b/packages/plugin-eslint/src/bin.ts @@ -2,6 +2,6 @@ import process from 'node:process'; import { Parser } from 'yargs/helpers'; import { executeRunner } from './lib/runner/index.js'; -const { runnerConfigPath, runnerOutputPath, cwd } = Parser(process.argv); +const { runnerConfigPath, runnerOutputPath } = Parser(process.argv); -await executeRunner({ runnerConfigPath, runnerOutputPath }, { cwd }); +await executeRunner({ runnerConfigPath, runnerOutputPath }); diff --git a/packages/plugin-eslint/src/lib/eslint-plugin.ts b/packages/plugin-eslint/src/lib/eslint-plugin.ts index 7a97ba76a..285a39e50 100644 --- a/packages/plugin-eslint/src/lib/eslint-plugin.ts +++ b/packages/plugin-eslint/src/lib/eslint-plugin.ts @@ -41,7 +41,6 @@ export async function eslintPlugin( schemaType: 'ESLint plugin config', }); - const cwd = options?.cwd || process.cwd(); const customGroups = options ? parseSchema(eslintPluginOptionsSchema, options, { schemaType: 'ESLint plugin options', @@ -72,8 +71,6 @@ export async function eslintPlugin( audits, groups, - runner: await createRunnerConfig(runnerScriptPath, audits, targets, { - cwd, - }), + runner: await createRunnerConfig(runnerScriptPath, audits, targets), }; } diff --git a/packages/plugin-eslint/src/lib/runner/index.ts b/packages/plugin-eslint/src/lib/runner/index.ts index b3f9a1901..7e5e8ee9d 100644 --- a/packages/plugin-eslint/src/lib/runner/index.ts +++ b/packages/plugin-eslint/src/lib/runner/index.ts @@ -19,19 +19,16 @@ import type { ESLintPluginRunnerConfig, ESLintTarget } from '../config.js'; import { lint } from './lint.js'; import { lintResultsToAudits, mergeLinterOutputs } from './transform.js'; -export async function executeRunner( - { runnerConfigPath, runnerOutputPath }: RunnerFilesPaths, - opt?: { cwd?: string }, -): Promise { - const { cwd = process.cwd() } = opt || {}; +export async function executeRunner({ + runnerConfigPath, + runnerOutputPath, +}: RunnerFilesPaths): Promise { const { slugs, targets } = await readJsonFile(runnerConfigPath); - ui().logger.log( - `ESLint plugin executing ${targets.length} lint targets with cwd: ${cwd}`, - ); + ui().logger.log(`ESLint plugin executing ${targets.length} lint targets`); - const linterOutputs = await asyncSequential(targets, cfg => lint(cfg, opt)); + const linterOutputs = await asyncSequential(targets, lint); const lintResults = mergeLinterOutputs(linterOutputs); const failedAudits = lintResultsToAudits(lintResults); @@ -54,7 +51,6 @@ export async function createRunnerConfig( scriptPath: string, audits: Audit[], targets: ESLintTarget[], - opt?: { cwd?: string }, ): Promise { const config: ESLintPluginRunnerConfig = { targets, @@ -69,11 +65,7 @@ export async function createRunnerConfig( command: 'node', args: [ filePathToCliArg(scriptPath), - ...objectToCliArgs({ - runnerConfigPath, - runnerOutputPath, - ...(opt?.cwd ? { cwd: opt.cwd } : {}), - }), + ...objectToCliArgs({ runnerConfigPath, runnerOutputPath }), ], configFile: runnerConfigPath, outputFile: runnerOutputPath, diff --git a/packages/plugin-eslint/src/lib/runner/lint.ts b/packages/plugin-eslint/src/lib/runner/lint.ts index 19ea8cf4d..80300ded3 100644 --- a/packages/plugin-eslint/src/lib/runner/lint.ts +++ b/packages/plugin-eslint/src/lib/runner/lint.ts @@ -1,6 +1,5 @@ import type { ESLint, Linter } from 'eslint'; import { platform } from 'node:os'; -import { join } from 'node:path'; import { distinct, executeProcess, @@ -11,21 +10,20 @@ import type { ESLintTarget } from '../config.js'; import { setupESLint } from '../setup.js'; import type { LinterOutput, RuleOptionsPerFile } from './types.js'; -export async function lint( - { eslintrc, patterns }: ESLintTarget, - opt?: { cwd?: string }, -): Promise { - const results = await executeLint({ eslintrc, patterns }, opt); +export async function lint({ + eslintrc, + patterns, +}: ESLintTarget): Promise { + const results = await executeLint({ eslintrc, patterns }); const eslint = await setupESLint(eslintrc); const ruleOptionsPerFile = await loadRuleOptionsPerFile(eslint, results); return { results, ruleOptionsPerFile }; } -async function executeLint( - { eslintrc, patterns }: ESLintTarget, - opt?: { cwd?: string }, -): Promise { - const { cwd = process.cwd() } = opt ?? {}; +async function executeLint({ + eslintrc, + patterns, +}: ESLintTarget): Promise { // running as CLI because ESLint#lintFiles() runs out of memory const { stdout } = await executeProcess({ command: 'npx', @@ -35,14 +33,13 @@ async function executeLint( ...(typeof eslintrc === 'object' ? ['--no-eslintrc'] : []), '--no-error-on-unmatched-pattern', '--format=json', - `--output-file=${join(cwd, '.eslint-results.json')}`, ...toArray(patterns).map(pattern => // globs need to be escaped on Unix platform() === 'win32' ? pattern : `'${pattern}'`, ), ], ignoreExitCode: true, - cwd, + cwd: process.cwd(), }); return JSON.parse(stdout) as ESLint.LintResult[]; From ab758687146b67a52689a0503bbf700c6293cd8d Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 6 Aug 2025 14:02:03 +0200 Subject: [PATCH 006/111] fix: remove tests --- .../src/lib/nx/coverage-paths.ts | 21 ++- .../src/lib/nx/coverage-paths.unit.test.ts | 135 ++---------------- 2 files changed, 22 insertions(+), 134 deletions(-) diff --git a/packages/plugin-coverage/src/lib/nx/coverage-paths.ts b/packages/plugin-coverage/src/lib/nx/coverage-paths.ts index 00d17e8fb..e6b44fe94 100644 --- a/packages/plugin-coverage/src/lib/nx/coverage-paths.ts +++ b/packages/plugin-coverage/src/lib/nx/coverage-paths.ts @@ -18,11 +18,12 @@ import type { CoverageResult } from '../config.js'; * @param verbose optional verbose logging * @returns An array of coverage result information for the coverage plugin. */ -export async function getNxCoveragePaths( - targets: string[] = ['test'], - projects?: string[], - verbose?: boolean, -): Promise { +export async function getNxCoveragePaths(options: { + targets?: string[]; + projects?: string[]; + verbose?: boolean; +}): Promise { + const { targets = ['test'], verbose, projects } = options; if (verbose) { ui().logger.info( bold('💡 Gathering coverage from the following nx projects:'), @@ -192,13 +193,7 @@ export async function getCoveragePathForJest( } if (path.isAbsolute(coverageDirectory)) { - return { - pathToProject: project.root, - resultsPath: path.join(coverageDirectory, 'lcov.info'), - }; + return path.join(coverageDirectory, 'lcov.info'); } - return { - pathToProject: project.root, - resultsPath: path.join(project.root, coverageDirectory, 'lcov.info'), - }; + return path.join(project.root, coverageDirectory, 'lcov.info'); } diff --git a/packages/plugin-coverage/src/lib/nx/coverage-paths.unit.test.ts b/packages/plugin-coverage/src/lib/nx/coverage-paths.unit.test.ts index 9e2bd1fa4..ff7020155 100644 --- a/packages/plugin-coverage/src/lib/nx/coverage-paths.unit.test.ts +++ b/packages/plugin-coverage/src/lib/nx/coverage-paths.unit.test.ts @@ -135,16 +135,9 @@ describe('getCoveragePathForTarget', () => { }, 'test', ), - ).resolves.toStrictEqual({ - pathToProject: path.join('packages', 'core'), - resultsPath: path.join( - 'packages', - 'core', - 'coverage', - 'core', - 'lcov.info', - ), - }); + ).resolves.toBe( + path.join('packages', 'core', 'coverage', 'core', 'lcov.info'), + ); }); it('should throw for unsupported executor (only vitest and jest are supported)', async () => { @@ -284,16 +277,9 @@ describe('getCoveragePathForJest', () => { { name: 'cli', root: path.join('packages', 'cli') }, 'unit-test', ), - ).resolves.toEqual({ - pathToProject: path.join('packages', 'cli'), - resultsPath: path.join( - 'packages', - 'cli', - 'coverage', - 'core', - 'lcov.info', - ), - } satisfies CoverageResult); + ).resolves.toBe( + path.join('packages', 'cli', 'coverage', 'core', 'lcov.info'), + ); }); it('should throw when coverageDirectory is not set in Jest config', async () => { @@ -325,16 +311,9 @@ describe('getCoveragePathForJest', () => { { name: 'cli', root: path.join('packages', 'cli') }, 'unit-test', ), - ).resolves.toEqual({ - pathToProject: path.join('packages', 'cli'), - resultsPath: path.join( - 'dist', - 'packages', - 'cli', - 'coverage', - 'lcov.info', - ), - } satisfies CoverageResult); + ).resolves.toBe( + path.join('dist', 'packages', 'cli', 'coverage', 'lcov.info'), + ); }); it('should throw when Jest config does not include lcov reporter', async () => { @@ -357,12 +336,7 @@ describe('getCoveragePathForJest', () => { { name: 'core', root: path.join('packages', 'core') }, 'integration-test', ), - ).resolves.toEqual( - expect.objectContaining({ - pathToProject: expect.any(String), - resultsPath: expect.any(String), - }), - ); + ).resolves.toBeTypeOf('string'); }); it('should throw if lcov reporter from jest config overridden in project.json', async () => { @@ -388,12 +362,7 @@ describe('getCoveragePathForJest', () => { { name: 'core', root: path.join('packages', 'core') }, 'integration-test', ), - ).resolves.toEqual( - expect.objectContaining({ - pathToProject: expect.any(String), - resultsPath: expect.any(String), - }), - ); + ).resolves.toBeTypeOf('string'); }); it('should not throw regarding missing lcov reporter if jest config uses preset', async () => { @@ -403,12 +372,7 @@ describe('getCoveragePathForJest', () => { { name: 'core', root: path.join('packages', 'core') }, 'test', ), - ).resolves.toEqual( - expect.objectContaining({ - pathToProject: expect.any(String), - resultsPath: expect.any(String), - }), - ); + ).resolves.toBeTypeOf('string'); }); it('should handle absolute path in coverageDirectory', async () => { @@ -426,79 +390,8 @@ describe('getCoveragePathForJest', () => { { name: 'cli', root: path.join('packages', 'cli') }, 'unit-test', ), - ).resolves.toEqual({ - pathToProject: path.join('packages', 'cli'), - resultsPath: path.join( - process.cwd(), - 'coverage', - 'packages', - 'cli', - 'lcov.info', - ), - } satisfies CoverageResult); - }); -}); - -describe('getNxCoveragePaths', () => { - beforeEach(() => { - vol.fromJSON( - { - 'vitest-cli.config.ts': '', - 'vitest-core.config.ts': '', - }, - MEMFS_VOLUME, + ).resolves.toBe( + path.join(process.cwd(), 'coverage', 'packages', 'cli', 'lcov.info'), ); - - // Mock createProjectGraphAsync to return a mock project graph - vi.doMock('@nx/devkit', () => ({ - createProjectGraphAsync: vi.fn().mockResolvedValue({ - nodes: { - cli: { - name: 'cli', - type: 'lib', - data: { - name: 'cli', - root: path.join('packages', 'cli'), - targets: { - 'unit-test': { - executor: '@nx/vite:test', - options: { - configFile: 'vitest-cli.config.ts', - } satisfies VitestExecutorOptions, - }, - }, - }, - }, - core: { - name: 'core', - type: 'lib', - data: { - name: 'core', - root: path.join('packages', 'core'), - targets: { - 'unit-test': { - executor: '@nx/vite:test', - options: { - configFile: 'vitest-core.config.ts', - } satisfies VitestExecutorOptions, - }, - }, - }, - }, - }, - }), - })); - }); - - afterEach(() => { - vi.doUnmock('@nx/devkit'); - }); - - it('should filter coverage paths by project names', async () => { - const allResults = await getNxCoveragePaths(['unit-test']); - const filteredResults = await getNxCoveragePaths(['unit-test'], ['cli']); - - expect(allResults).toHaveLength(2); // cli and core - expect(filteredResults).toHaveLength(1); // only cli }); }); From d72a81dc4e43cadbc23029129ae9cc085d842513 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 6 Aug 2025 14:17:42 +0200 Subject: [PATCH 007/111] core: adjust gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 4284058f4..de9074007 100644 --- a/.gitignore +++ b/.gitignore @@ -44,7 +44,7 @@ testem.log Thumbs.db # generated Code PushUp reports -/.code-pushup +.code-pushup # Nx workspace cache .nx From 0fb00582144b02e76e01b8727192f0fe5ba3897c Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 6 Aug 2025 14:24:12 +0200 Subject: [PATCH 008/111] core: fix main cp config --- code-pushup.preset.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/code-pushup.preset.ts b/code-pushup.preset.ts index c5db28546..758e4ed1e 100644 --- a/code-pushup.preset.ts +++ b/code-pushup.preset.ts @@ -245,10 +245,10 @@ export const coverageCoreConfigNx = async ( ? ['nx', 'run-many', '-p', projectName, ...targetArgs] : ['nx', 'run-many', ...targetArgs], }, - reports: await getNxCoveragePaths( - targetNames, - projectName ? [projectName] : undefined, - ), + reports: await getNxCoveragePaths({ + targets: targetNames, + projects: projectName ? [projectName] : undefined, + }), }), ], categories: coverageCategories, From e2cfbe8e11662156f820ee6e5fa2bab337ad63e6 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 6 Aug 2025 15:30:46 +0200 Subject: [PATCH 009/111] fix: remove tests --- packages/plugin-coverage/src/lib/nx/coverage-paths.unit.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/plugin-coverage/src/lib/nx/coverage-paths.unit.test.ts b/packages/plugin-coverage/src/lib/nx/coverage-paths.unit.test.ts index ff7020155..8d57dba34 100644 --- a/packages/plugin-coverage/src/lib/nx/coverage-paths.unit.test.ts +++ b/packages/plugin-coverage/src/lib/nx/coverage-paths.unit.test.ts @@ -11,7 +11,6 @@ import { getCoveragePathForJest, getCoveragePathForVitest, getCoveragePathsForTarget, - getNxCoveragePaths, } from './coverage-paths.js'; vi.mock('bundle-require', () => ({ From 973d1e191486503c259f4ab8e943cb1237696e1c Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 6 Aug 2025 17:48:42 +0200 Subject: [PATCH 010/111] fix: avoid cyclic --- packages/models/code-pushup.config.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/models/code-pushup.config.ts b/packages/models/code-pushup.config.ts index 352dfd523..6f11a6703 100644 --- a/packages/models/code-pushup.config.ts +++ b/packages/models/code-pushup.config.ts @@ -9,7 +9,6 @@ import { typescriptPluginConfig, } from '../../code-pushup.preset.js'; import type { CoreConfig } from '../../packages/models/src/index.js'; -import { mergeConfigs } from '../../packages/utils/src/index.js'; const projectName = process.env.CP_PROJECT_NAME || 'models'; @@ -22,7 +21,7 @@ const config: CoreConfig = { plugins: [], }; -export default mergeConfigs( +const configs = [ config, await eslintCoreConfigNx(projectName), await coverageCoreConfigNx(projectName), @@ -34,4 +33,19 @@ export default mergeConfigs( `packages/${projectName}/src/**/*.ts`, ...jsDocsExclusionPatterns, ]), +]; + +const mergedConfig = configs.reduce( + (result, currentConfig) => ({ + ...result, + ...currentConfig, + plugins: [...(result.plugins || []), ...(currentConfig.plugins || [])], + categories: [ + ...(result.categories || []), + ...(currentConfig.categories || []), + ], + }), + {} as CoreConfig, ); + +export default mergedConfig; From 14d438a1ada2fa79ddf302b80af5a98da9414b98 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 6 Aug 2025 17:55:09 +0200 Subject: [PATCH 011/111] fix: wip --- packages/models/code-pushup.config.ts | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/packages/models/code-pushup.config.ts b/packages/models/code-pushup.config.ts index 6f11a6703..352dfd523 100644 --- a/packages/models/code-pushup.config.ts +++ b/packages/models/code-pushup.config.ts @@ -9,6 +9,7 @@ import { typescriptPluginConfig, } from '../../code-pushup.preset.js'; import type { CoreConfig } from '../../packages/models/src/index.js'; +import { mergeConfigs } from '../../packages/utils/src/index.js'; const projectName = process.env.CP_PROJECT_NAME || 'models'; @@ -21,7 +22,7 @@ const config: CoreConfig = { plugins: [], }; -const configs = [ +export default mergeConfigs( config, await eslintCoreConfigNx(projectName), await coverageCoreConfigNx(projectName), @@ -33,19 +34,4 @@ const configs = [ `packages/${projectName}/src/**/*.ts`, ...jsDocsExclusionPatterns, ]), -]; - -const mergedConfig = configs.reduce( - (result, currentConfig) => ({ - ...result, - ...currentConfig, - plugins: [...(result.plugins || []), ...(currentConfig.plugins || [])], - categories: [ - ...(result.categories || []), - ...(currentConfig.categories || []), - ], - }), - {} as CoreConfig, ); - -export default mergedConfig; From 0aa32b19b8c100e5dba3c3b68e57928073aaede0 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 6 Aug 2025 18:42:18 +0200 Subject: [PATCH 012/111] fix: wip --- eslint.config.js | 9 ++++++++- project.json | 3 ++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/eslint.config.js b/eslint.config.js index bc9dd841b..d060e1a57 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -119,11 +119,18 @@ export default tseslint.config( { ignores: [ '**/*.mock.*', - '**/code-pushup.config.ts', '**/mocks/fixtures/**', '**/__snapshots__/**', '**/dist', '**/*.md', + '**/code-pushup.config.ts', + 'packages/*/code-pushup.config.ts', + 'examples/*/code-pushup.config.ts', + 'testing/test-utils/src/lib/fixtures/**', + 'testing/test-utils/src/lib/utils/omit-report-data.ts', + 'testing/test-utils/src/lib/utils/os-agnostic-paths.ts', + 'packages/utils/perf/**', + 'packages/utils/src/**', ], }, ); diff --git a/project.json b/project.json index d07e3ce85..3363bc29c 100644 --- a/project.json +++ b/project.json @@ -4,7 +4,8 @@ "targets": { "code-pushup": { "options": { - "config": "{workspaceRoot}/code-pushup.config.ts" + "config": "{workspaceRoot}/code-pushup.config.ts", + "upload.project": "cli" } } } From 0e7708170393e93d0280c495b9d3cf4c5310a7b3 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 7 Aug 2025 01:04:34 +0200 Subject: [PATCH 013/111] fix: wip 2 --- packages/models/eslint.config.js | 2 +- packages/models/tsconfig.test.json | 2 +- packages/models/tsconfig.tools.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/models/eslint.config.js b/packages/models/eslint.config.js index 26af011ea..a0aea4708 100644 --- a/packages/models/eslint.config.js +++ b/packages/models/eslint.config.js @@ -19,6 +19,6 @@ export default tseslint.config( }, }, { - ignores: ['packages/models/transformers/**/*.ts'], + ignores: ['packages/models/transformers/**/*.ts', 'code-pushup.config.ts'], }, ); diff --git a/packages/models/tsconfig.test.json b/packages/models/tsconfig.test.json index 67645f7d5..477efb329 100644 --- a/packages/models/tsconfig.test.json +++ b/packages/models/tsconfig.test.json @@ -4,7 +4,7 @@ "outDir": "../../dist/out-tsc", "types": ["vitest/globals", "vitest/importMeta", "vite/client", "node"] }, - "exclude": ["**/code-pushup.config.ts"], + "exclude": ["code-pushup.config.ts"], "include": [ "vitest.unit.config.ts", "vitest.int.config.ts", diff --git a/packages/models/tsconfig.tools.json b/packages/models/tsconfig.tools.json index 18f62770b..4a9dfeae3 100644 --- a/packages/models/tsconfig.tools.json +++ b/packages/models/tsconfig.tools.json @@ -4,5 +4,5 @@ "outDir": "../../dist/out-tsc", "types": ["nodenext"] }, - "include": ["zod2md.config.ts"] + "include": ["zod2md.config.ts", "code-pushup.config.ts"] } From 7e722f0ebc9e33700f8a991dc2c36ecdb14d0da3 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 7 Aug 2025 01:06:33 +0200 Subject: [PATCH 014/111] fix: wip 3 --- eslint.config.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/eslint.config.js b/eslint.config.js index d060e1a57..bc9dd841b 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -119,18 +119,11 @@ export default tseslint.config( { ignores: [ '**/*.mock.*', + '**/code-pushup.config.ts', '**/mocks/fixtures/**', '**/__snapshots__/**', '**/dist', '**/*.md', - '**/code-pushup.config.ts', - 'packages/*/code-pushup.config.ts', - 'examples/*/code-pushup.config.ts', - 'testing/test-utils/src/lib/fixtures/**', - 'testing/test-utils/src/lib/utils/omit-report-data.ts', - 'testing/test-utils/src/lib/utils/os-agnostic-paths.ts', - 'packages/utils/perf/**', - 'packages/utils/src/**', ], }, ); From 34909f90fb19f4f108f5d7f61e7e2d7ee93770ff Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 7 Aug 2025 01:11:20 +0200 Subject: [PATCH 015/111] fix: add task deps to cp targets --- packages/core/project.json | 4 +++- packages/create-cli/project.json | 4 +++- packages/nx-plugin/project.json | 4 +++- packages/plugin-coverage/project.json | 4 +++- packages/plugin-eslint/project.json | 4 +++- packages/plugin-js-packages/project.json | 4 +++- packages/plugin-jsdocs/project.json | 4 +++- packages/plugin-lighthouse/project.json | 4 +++- packages/plugin-typescript/project.json | 4 +++- packages/utils/project.json | 4 +++- 10 files changed, 30 insertions(+), 10 deletions(-) diff --git a/packages/core/project.json b/packages/core/project.json index 8d90e38fa..a08990714 100644 --- a/packages/core/project.json +++ b/packages/core/project.json @@ -4,7 +4,9 @@ "sourceRoot": "packages/core/src", "projectType": "library", "targets": { - "code-pushup": {}, + "code-pushup": { + "dependsOn": ["unit-test", "int-test"] + }, "build": { "executor": "@nx/js:tsc", "outputs": ["{options.outputPath}"], diff --git a/packages/create-cli/project.json b/packages/create-cli/project.json index 6f118d041..b712f5175 100644 --- a/packages/create-cli/project.json +++ b/packages/create-cli/project.json @@ -4,7 +4,9 @@ "sourceRoot": "packages/create-cli/src", "projectType": "library", "targets": { - "code-pushup": {}, + "code-pushup": { + "dependsOn": ["unit-test", "int-test"] + }, "build": { "executor": "@nx/js:tsc", "outputs": ["{options.outputPath}"], diff --git a/packages/nx-plugin/project.json b/packages/nx-plugin/project.json index b5f80e88f..6e74f0e1f 100644 --- a/packages/nx-plugin/project.json +++ b/packages/nx-plugin/project.json @@ -5,7 +5,9 @@ "projectType": "library", "implicitDependencies": ["cli"], "targets": { - "code-pushup": {}, + "code-pushup": { + "dependsOn": ["unit-test", "int-test"] + }, "build": { "executor": "@nx/js:tsc", "outputs": ["{options.outputPath}"], diff --git a/packages/plugin-coverage/project.json b/packages/plugin-coverage/project.json index 0cebf67c5..577315f70 100644 --- a/packages/plugin-coverage/project.json +++ b/packages/plugin-coverage/project.json @@ -4,7 +4,9 @@ "sourceRoot": "packages/plugin-coverage/src", "projectType": "library", "targets": { - "code-pushup": {}, + "code-pushup": { + "dependsOn": ["unit-test", "int-test"] + }, "build": { "executor": "@nx/js:tsc", "outputs": ["{options.outputPath}"], diff --git a/packages/plugin-eslint/project.json b/packages/plugin-eslint/project.json index 716405683..ed35d1007 100644 --- a/packages/plugin-eslint/project.json +++ b/packages/plugin-eslint/project.json @@ -4,7 +4,9 @@ "sourceRoot": "packages/plugin-eslint/src", "projectType": "library", "targets": { - "code-pushup": {}, + "code-pushup": { + "dependsOn": ["unit-test", "int-test"] + }, "build": { "executor": "@nx/js:tsc", "outputs": ["{options.outputPath}"], diff --git a/packages/plugin-js-packages/project.json b/packages/plugin-js-packages/project.json index 9e6eda9e5..b00751904 100644 --- a/packages/plugin-js-packages/project.json +++ b/packages/plugin-js-packages/project.json @@ -4,7 +4,9 @@ "sourceRoot": "packages/plugin-js-packages/src", "projectType": "library", "targets": { - "code-pushup": {}, + "code-pushup": { + "dependsOn": ["unit-test", "int-test"] + }, "build": { "executor": "@nx/js:tsc", "outputs": ["{options.outputPath}"], diff --git a/packages/plugin-jsdocs/project.json b/packages/plugin-jsdocs/project.json index e1f220b4b..ed386a6d0 100644 --- a/packages/plugin-jsdocs/project.json +++ b/packages/plugin-jsdocs/project.json @@ -5,7 +5,9 @@ "projectType": "library", "tags": ["scope:plugin", "type:feature", "publishable"], "targets": { - "code-pushup": {}, + "code-pushup": { + "dependsOn": ["unit-test", "int-test"] + }, "build": { "executor": "@nx/js:tsc", "outputs": ["{options.outputPath}"], diff --git a/packages/plugin-lighthouse/project.json b/packages/plugin-lighthouse/project.json index 022e1ce95..84fe2cca7 100644 --- a/packages/plugin-lighthouse/project.json +++ b/packages/plugin-lighthouse/project.json @@ -4,7 +4,9 @@ "sourceRoot": "packages/plugin-lighthouse/src", "projectType": "library", "targets": { - "code-pushup": {}, + "code-pushup": { + "dependsOn": ["unit-test", "int-test"] + }, "build": { "executor": "@nx/js:tsc", "outputs": ["{options.outputPath}"], diff --git a/packages/plugin-typescript/project.json b/packages/plugin-typescript/project.json index da9cfb79a..dd9db8fff 100644 --- a/packages/plugin-typescript/project.json +++ b/packages/plugin-typescript/project.json @@ -4,7 +4,9 @@ "sourceRoot": "packages/plugin-typescript/src", "projectType": "library", "targets": { - "code-pushup": {}, + "code-pushup": { + "dependsOn": ["unit-test", "int-test"] + }, "build": { "executor": "@nx/js:tsc", "outputs": ["{options.outputPath}"], diff --git a/packages/utils/project.json b/packages/utils/project.json index c77403c34..bcb925e51 100644 --- a/packages/utils/project.json +++ b/packages/utils/project.json @@ -4,7 +4,9 @@ "sourceRoot": "packages/utils/src", "projectType": "library", "targets": { - "code-pushup": {}, + "code-pushup": { + "dependsOn": ["unit-test", "int-test"] + }, "build": { "executor": "@nx/js:tsc", "outputs": ["{options.outputPath}"], From ec2433228e2fe87a3b563e695cd7649efa01b10a Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 7 Aug 2025 15:25:55 +0200 Subject: [PATCH 016/111] fix: revert --- packages/models/code-pushup.config.ts | 27 +++++++++++++++++++++++++-- packages/models/eslint.config.js | 2 +- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/packages/models/code-pushup.config.ts b/packages/models/code-pushup.config.ts index 352dfd523..f7629f13f 100644 --- a/packages/models/code-pushup.config.ts +++ b/packages/models/code-pushup.config.ts @@ -9,7 +9,6 @@ import { typescriptPluginConfig, } from '../../code-pushup.preset.js'; import type { CoreConfig } from '../../packages/models/src/index.js'; -import { mergeConfigs } from '../../packages/utils/src/index.js'; const projectName = process.env.CP_PROJECT_NAME || 'models'; @@ -22,6 +21,29 @@ const config: CoreConfig = { plugins: [], }; +export default [ + await eslintCoreConfigNx(projectName), + await coverageCoreConfigNx(projectName), + await jsPackagesCoreConfig('package.json'), // Use workspace root package.json + await typescriptPluginConfig({ + tsconfig: `packages/${projectName}/tsconfig.lib.json`, + }), + jsDocsCoreConfig([ + `packages/${projectName}/src/**\/*.ts`, + ...jsDocsExclusionPatterns, + ]), +].reduce((acc, curr) => { + curr.plugins.forEach(plugin => { + acc.plugins.push(plugin); + }); + curr.categories?.forEach(category => { + acc.categories?.push(category); + }); + return acc; +}, config); +/* +//import { mergeConfigs } from '../../packages/utils/src/index.js'; + export default mergeConfigs( config, await eslintCoreConfigNx(projectName), @@ -31,7 +53,8 @@ export default mergeConfigs( tsconfig: `packages/${projectName}/tsconfig.lib.json`, }), jsDocsCoreConfig([ - `packages/${projectName}/src/**/*.ts`, + `packages/${projectName}/src/**\/*.ts`, ...jsDocsExclusionPatterns, ]), ); +*/ diff --git a/packages/models/eslint.config.js b/packages/models/eslint.config.js index a0aea4708..26af011ea 100644 --- a/packages/models/eslint.config.js +++ b/packages/models/eslint.config.js @@ -19,6 +19,6 @@ export default tseslint.config( }, }, { - ignores: ['packages/models/transformers/**/*.ts', 'code-pushup.config.ts'], + ignores: ['packages/models/transformers/**/*.ts'], }, ); From 8dc3fba031930542bd8606f74b49c07b6565c1e1 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 12 Aug 2025 13:50:41 +0200 Subject: [PATCH 017/111] fix: adjust nx.json --- nx.json | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/nx.json b/nx.json index 4c6230774..cdf0447cb 100644 --- a/nx.json +++ b/nx.json @@ -8,10 +8,14 @@ "options": { "command": "node packages/cli/src/index.ts --no-progress --verbose", "config": "{projectRoot}/code-pushup.config.ts", - "persist.filename": "{projectName}-report", - "persist.outputDir": "{projectRoot}/.code-pushup", + "persist": { + "filename": "{projectName}-report", + "outputDir": "{projectRoot}/.code-pushup" + }, + "upload": { + "project": "cli-{projectName}" + }, "outputPath": "{projectRoot}/.code-pushup", - "upload.project": "cli-{projectName}", "env": { "NODE_OPTIONS": "--import tsx", "TSX_TSCONFIG_PATH": "tsconfig.base.json" From da5de155ceb81615f048ab1624fbde1f7c8d70c0 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 12 Aug 2025 16:06:02 +0200 Subject: [PATCH 018/111] chore: add code-pushup to testing targets --- testing/test-nx-utils/code-pushup.config.ts | 35 +++++++++++++++++++++ testing/test-nx-utils/project.json | 6 ++++ testing/test-setup/code-pushup.config.ts | 35 +++++++++++++++++++++ testing/test-setup/project.json | 6 ++++ testing/test-utils/code-pushup.config.ts | 35 +++++++++++++++++++++ testing/test-utils/project.json | 6 ++++ 6 files changed, 123 insertions(+) create mode 100644 testing/test-nx-utils/code-pushup.config.ts create mode 100644 testing/test-setup/code-pushup.config.ts create mode 100644 testing/test-utils/code-pushup.config.ts diff --git a/testing/test-nx-utils/code-pushup.config.ts b/testing/test-nx-utils/code-pushup.config.ts new file mode 100644 index 000000000..95fa44fd7 --- /dev/null +++ b/testing/test-nx-utils/code-pushup.config.ts @@ -0,0 +1,35 @@ +import 'dotenv/config'; +import { + coverageCoreConfigNx, + eslintCoreConfigNx, + jsDocsCoreConfig, + jsDocsExclusionPatterns, + jsPackagesCoreConfig, + loadEnv, + typescriptPluginConfig, +} from '../../code-pushup.preset.js'; +import type { CoreConfig } from '../../packages/models/src/index.js'; +import { mergeConfigs } from '../../packages/utils/src/index.js'; + +const projectName = process.env.CP_PROJECT_NAME || 'test-nx-utils'; + +const config: CoreConfig = { + ...(await loadEnv()), + persist: { + filename: `${projectName}-report`, + outputDir: `testing/${projectName}/.code-pushup`, + }, + plugins: [], +}; + +export default mergeConfigs( + config, + await eslintCoreConfigNx(projectName), + await typescriptPluginConfig({ + tsconfig: `testing/${projectName}/tsconfig.lib.json`, + }), + jsDocsCoreConfig([ + `testing/${projectName}/src/**/*.ts`, + ...jsDocsExclusionPatterns, + ]), +); diff --git a/testing/test-nx-utils/project.json b/testing/test-nx-utils/project.json index 9fc33df87..7f9886230 100644 --- a/testing/test-nx-utils/project.json +++ b/testing/test-nx-utils/project.json @@ -4,6 +4,12 @@ "sourceRoot": "testing/test-nx-utils/src", "projectType": "library", "targets": { + "code-pushup": { + "dependsOn": ["code-pushup-coverage"] + }, + "code-pushup-coverage": { + "dependsOn": ["unit-test"] + }, "build": {}, "lint": {}, "unit-test": { diff --git a/testing/test-setup/code-pushup.config.ts b/testing/test-setup/code-pushup.config.ts new file mode 100644 index 000000000..9699cedb9 --- /dev/null +++ b/testing/test-setup/code-pushup.config.ts @@ -0,0 +1,35 @@ +import 'dotenv/config'; +import { + coverageCoreConfigNx, + eslintCoreConfigNx, + jsDocsCoreConfig, + jsDocsExclusionPatterns, + jsPackagesCoreConfig, + loadEnv, + typescriptPluginConfig, +} from '../../code-pushup.preset.js'; +import type { CoreConfig } from '../../packages/models/src/index.js'; +import { mergeConfigs } from '../../packages/utils/src/index.js'; + +const projectName = process.env.CP_PROJECT_NAME || 'test-setup'; + +const config: CoreConfig = { + ...(await loadEnv()), + persist: { + filename: `${projectName}-report`, + outputDir: `testing/${projectName}/.code-pushup`, + }, + plugins: [], +}; + +export default mergeConfigs( + config, + await eslintCoreConfigNx(projectName), + await typescriptPluginConfig({ + tsconfig: `testing/${projectName}/tsconfig.lib.json`, + }), + jsDocsCoreConfig([ + `testing/${projectName}/src/**/*.ts`, + ...jsDocsExclusionPatterns, + ]), +); diff --git a/testing/test-setup/project.json b/testing/test-setup/project.json index 6320cfaab..b112b6eed 100644 --- a/testing/test-setup/project.json +++ b/testing/test-setup/project.json @@ -4,6 +4,12 @@ "sourceRoot": "testing/test-setup/src", "projectType": "library", "targets": { + "code-pushup": { + "dependsOn": ["code-pushup-coverage"] + }, + "code-pushup-coverage": { + "dependsOn": ["unit-test"] + }, "build": {}, "lint": {}, "unit-test": { diff --git a/testing/test-utils/code-pushup.config.ts b/testing/test-utils/code-pushup.config.ts new file mode 100644 index 000000000..9fd5c3e16 --- /dev/null +++ b/testing/test-utils/code-pushup.config.ts @@ -0,0 +1,35 @@ +import 'dotenv/config'; +import { + coverageCoreConfigNx, + eslintCoreConfigNx, + jsDocsCoreConfig, + jsDocsExclusionPatterns, + jsPackagesCoreConfig, + loadEnv, + typescriptPluginConfig, +} from '../../code-pushup.preset.js'; +import type { CoreConfig } from '../../packages/models/src/index.js'; +import { mergeConfigs } from '../../packages/utils/src/index.js'; + +const projectName = process.env.CP_PROJECT_NAME || 'test-utils'; + +const config: CoreConfig = { + ...(await loadEnv()), + persist: { + filename: `${projectName}-report`, + outputDir: `testing/${projectName}/.code-pushup`, + }, + plugins: [], +}; + +export default mergeConfigs( + config, + await eslintCoreConfigNx(projectName), + await typescriptPluginConfig({ + tsconfig: `testing/${projectName}/tsconfig.lib.json`, + }), + jsDocsCoreConfig([ + `testing/${projectName}/src/**/*.ts`, + ...jsDocsExclusionPatterns, + ]), +); diff --git a/testing/test-utils/project.json b/testing/test-utils/project.json index ccc11d50c..0f8e90f6e 100644 --- a/testing/test-utils/project.json +++ b/testing/test-utils/project.json @@ -4,6 +4,12 @@ "sourceRoot": "testing/test-utils/src", "projectType": "library", "targets": { + "code-pushup": { + "dependsOn": ["code-pushup-coverage"] + }, + "code-pushup-coverage": { + "dependsOn": ["unit-test"] + }, "build": {}, "lint": {}, "unit-test": { From 07ace2f76215d80e153aa82cdd2ea996084c6a02 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 12 Aug 2025 16:06:17 +0200 Subject: [PATCH 019/111] chore: update code-pushup targets --- CONTRIBUTING.md | 35 +++++++++++++++ e2e/create-cli-e2e/project.json | 2 +- examples/plugins/project.json | 6 +++ nx.json | 55 ++++++++++++++++++----- package-lock.json | 34 ++++++++++++++ package.json | 2 + packages/ci/project.json | 6 +++ packages/cli/project.json | 5 ++- packages/core/project.json | 3 ++ packages/create-cli/project.json | 3 ++ packages/models/code-pushup.config.ts | 18 +------- packages/models/project.json | 3 ++ packages/models/transformers/project.json | 4 ++ packages/nx-plugin/project.json | 3 ++ packages/plugin-coverage/project.json | 3 ++ packages/plugin-eslint/project.json | 3 ++ packages/plugin-js-packages/project.json | 3 ++ packages/plugin-jsdocs/project.json | 3 ++ packages/plugin-lighthouse/project.json | 3 ++ packages/plugin-typescript/project.json | 3 ++ packages/utils/project.json | 3 ++ project.json | 4 +- 22 files changed, 174 insertions(+), 30 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e8c8e23a5..b0b9cc487 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -69,6 +69,41 @@ You can control the execution of long-running tests over the `INCLUDE_SLOW_TESTS To change this setup, open (or create) the `.env` file in the root folder. Edit or add the environment variable there as follows: `INCLUDE_SLOW_TESTS=true`. +### Testing with pkg-new + +You can test the CLI using published packages from pull requests via [pkg-new](https://pkg.pr.new/). This is useful for testing changes before they are merged. + +To test a specific PR (replace `` with the actual PR number): + +```bash +# Install required dependencies first +npm install \ + https://pkg.pr.new/code-pushup/cli/@code-pushup/utils@ \ + https://pkg.pr.new/code-pushup/cli/@code-pushup/models@ \ + https://pkg.pr.new/code-pushup/cli/@code-pushup/core@ \ + https://pkg.pr.new/code-pushup/cli/@code-pushup/cli@ +``` + +Update nx.json to use pkg-new: + +```jsonc +{ + "targetDefaults": { + "code-pushup": { + "executor": "nx:run-commands", + "options": { + "command": "npx https://pkg.pr.new/code-pushup/cli/@code-pushup/cli@", // instead of "command": "node packages/cli/src/index.ts" + "args": [ + // ... + ], + }, + }, + }, +} +``` + +**Note:** The `@code-pushup/portal-client` package may not be available via pkg-new, but it's an optional peer dependency and won't affect collect functionality. Only the upload command is not working. + ## Git Commit messages must follow [conventional commits](https://conventionalcommits.org/) format. diff --git a/e2e/create-cli-e2e/project.json b/e2e/create-cli-e2e/project.json index beeb09874..b187959ac 100644 --- a/e2e/create-cli-e2e/project.json +++ b/e2e/create-cli-e2e/project.json @@ -1,7 +1,7 @@ { "name": "create-cli-e2e", "$schema": "../../node_modules/nx/schemas/project-schema.json", - "sourceRoot": "examples/create-cli-e2e/src", + "sourceRoot": "e2e/create-cli-e2e/src", "projectType": "application", "targets": { "lint": {}, diff --git a/examples/plugins/project.json b/examples/plugins/project.json index f64b7c7b7..7fd16c013 100644 --- a/examples/plugins/project.json +++ b/examples/plugins/project.json @@ -4,6 +4,12 @@ "sourceRoot": "examples/plugins/src", "projectType": "library", "targets": { + "code-pushup": { + "dependsOn": ["code-pushup-coverage"] + }, + "code-pushup-coverage": { + "dependsOn": ["unit-test", "int-test"] + }, "build": { "executor": "@nx/js:tsc", "outputs": ["{options.outputPath}"], diff --git a/nx.json b/nx.json index cdf0447cb..de3326b7c 100644 --- a/nx.json +++ b/nx.json @@ -3,18 +3,25 @@ "targetDefaults": { "code-pushup": { "cache": true, - "outputs": ["{options.outputPath}"], + "outputs": [ + "{projectRoot}/.code-pushup/*.md", + "{projectRoot}/.code-pushup/*.json" + ], "executor": "nx:run-commands", "options": { - "command": "node packages/cli/src/index.ts --no-progress --verbose", - "config": "{projectRoot}/code-pushup.config.ts", - "persist": { - "filename": "{projectName}-report", - "outputDir": "{projectRoot}/.code-pushup" - }, - "upload": { - "project": "cli-{projectName}" - }, + "command": "npx https://pkg.pr.new/code-pushup/cli/@code-pushup/cli@1059", + "args": [ + "--no-progress", + "--verbose", + "--config", + "{projectRoot}/code-pushup.config.ts", + "--persist.filename", + "{projectName}-report", + "--persist.outputDir", + "{projectRoot}/.code-pushup", + "--upload.project", + "cli-{projectName}" + ], "outputPath": "{projectRoot}/.code-pushup", "env": { "NODE_OPTIONS": "--import tsx", @@ -22,6 +29,34 @@ } } }, + "code-pushup-coverage": { + "cache": true, + "outputs": ["{projectRoot}/.code-pushup/coverage"], + "executor": "nx:run-commands", + "options": { + "command": "npm install https://pkg.pr.new/code-pushup/cli/@code-pushup/utils@1059 https://pkg.pr.new/code-pushup/cli/@code-pushup/models@1059 && npx --yes https://pkg.pr.new/code-pushup/cli/@code-pushup/cli@1059", + "args": [ + "--no-progress", + "--verbose", + "--config", + "{projectRoot}/code-pushup.config.ts", + "--cache.write", + "true", + "--onlyPlugins", + "coverage", + "--persist.skipReports", + "true", + "--persist.outputDir", + "{projectRoot}/.code-pushup", + "--upload.project", + "{projectName}" + ], + "env": { + "NODE_OPTIONS": "--import tsx", + "TSX_TSCONFIG_PATH": "tsconfig.base.json" + } + } + }, "build": { "dependsOn": ["^build"], "inputs": ["production", "^production"], diff --git a/package-lock.json b/package-lock.json index 120439704..3f0850b23 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,9 @@ "version": "0.0.0", "license": "MIT", "dependencies": { + "@code-pushup/models": "https://pkg.pr.new/code-pushup/cli/@code-pushup/models@1059", "@code-pushup/portal-client": "^0.15.0", + "@code-pushup/utils": "https://pkg.pr.new/code-pushup/cli/@code-pushup/utils@1059", "@isaacs/cliui": "^8.0.2", "@nx/devkit": "19.8.13", "@poppinss/cliui": "6.4.1", @@ -2336,6 +2338,16 @@ } } }, + "node_modules/@code-pushup/models": { + "version": "0.73.0", + "resolved": "https://pkg.pr.new/code-pushup/cli/@code-pushup/models@1059", + "integrity": "sha512-TNhAJd7xMSqTsWrZz9LEHZKIrCCG9qHLRmKYgboXhd1s0NoaVgZdva8vHNffveArJ0id56ngUaA76K7n4mWPww==", + "license": "MIT", + "dependencies": { + "vscode-material-icons": "^0.1.0", + "zod": "^4.0.5" + } + }, "node_modules/@code-pushup/portal-client": { "version": "0.15.0", "resolved": "https://registry.npmjs.org/@code-pushup/portal-client/-/portal-client-0.15.0.tgz", @@ -2348,6 +2360,28 @@ "vscode-material-icons": "^0.1.0" } }, + "node_modules/@code-pushup/utils": { + "version": "0.73.0", + "resolved": "https://pkg.pr.new/code-pushup/cli/@code-pushup/utils@1059", + "integrity": "sha512-AT+mkzTs1l4WAbCTChDmXScZ6eenmjRKkG3c6OKQvlnCeHwNnZYc8idNbM3DWEM5VhzA2HaHWjqI9Bz+58vOnw==", + "license": "MIT", + "dependencies": { + "@code-pushup/models": "https://pkg.pr.new/code-pushup/cli/@code-pushup/models@98dedef5b1b2751fceb082065d7898454887af53", + "@isaacs/cliui": "^8.0.2", + "@poppinss/cliui": "^6.4.0", + "ansis": "^3.3.0", + "build-md": "^0.4.2", + "bundle-require": "^5.1.0", + "esbuild": "^0.25.2", + "multi-progress-bars": "^5.0.3", + "semver": "^7.6.0", + "simple-git": "^3.20.0", + "zod": "^4.0.5" + }, + "engines": { + "node": ">=17.0.0" + } + }, "node_modules/@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", diff --git a/package.json b/package.json index 1c6ddc846..943a81208 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,9 @@ "node": ">=22.14" }, "dependencies": { + "@code-pushup/models": "https://pkg.pr.new/code-pushup/cli/@code-pushup/models@1059", "@code-pushup/portal-client": "^0.15.0", + "@code-pushup/utils": "https://pkg.pr.new/code-pushup/cli/@code-pushup/utils@1059", "@isaacs/cliui": "^8.0.2", "@nx/devkit": "19.8.13", "@poppinss/cliui": "6.4.1", diff --git a/packages/ci/project.json b/packages/ci/project.json index 433089f77..1ac3c6663 100644 --- a/packages/ci/project.json +++ b/packages/ci/project.json @@ -4,6 +4,12 @@ "sourceRoot": "packages/ci/src", "projectType": "library", "targets": { + "code-pushup": { + "dependsOn": ["code-pushup-coverage"] + }, + "code-pushup-coverage": { + "dependsOn": ["unit-test", "int-test"] + }, "build": {}, "lint": {}, "unit-test": { diff --git a/packages/cli/project.json b/packages/cli/project.json index 9c78c5851..2bb54d0ee 100644 --- a/packages/cli/project.json +++ b/packages/cli/project.json @@ -5,7 +5,10 @@ "projectType": "library", "targets": { "code-pushup": { - "dependsOn": ["unit-test", "int-test"] + "dependsOn": ["code-pushup-coverage"] + }, + "code-pushup-coverage": { + "dependsOn": ["unit-test", "int-test", "e2e-test"] }, "build": {}, "lint": {}, diff --git a/packages/core/project.json b/packages/core/project.json index a7b933d06..60adf08a4 100644 --- a/packages/core/project.json +++ b/packages/core/project.json @@ -5,6 +5,9 @@ "projectType": "library", "targets": { "code-pushup": { + "dependsOn": ["code-pushup-coverage"] + }, + "code-pushup-coverage": { "dependsOn": ["unit-test", "int-test"] }, "build": {}, diff --git a/packages/create-cli/project.json b/packages/create-cli/project.json index 7c9bd7ef9..ddfebc2ea 100644 --- a/packages/create-cli/project.json +++ b/packages/create-cli/project.json @@ -5,6 +5,9 @@ "projectType": "library", "targets": { "code-pushup": { + "dependsOn": ["code-pushup-coverage"] + }, + "code-pushup-coverage": { "dependsOn": ["unit-test", "int-test"] }, "build": {}, diff --git a/packages/models/code-pushup.config.ts b/packages/models/code-pushup.config.ts index f7629f13f..a8be5d14c 100644 --- a/packages/models/code-pushup.config.ts +++ b/packages/models/code-pushup.config.ts @@ -21,6 +21,7 @@ const config: CoreConfig = { plugins: [], }; +// This part should use mergeConfig in a normal setup, but here we are manually merging to avoid circular dependencies export default [ await eslintCoreConfigNx(projectName), await coverageCoreConfigNx(projectName), @@ -41,20 +42,3 @@ export default [ }); return acc; }, config); -/* -//import { mergeConfigs } from '../../packages/utils/src/index.js'; - -export default mergeConfigs( - config, - await eslintCoreConfigNx(projectName), - await coverageCoreConfigNx(projectName), - await jsPackagesCoreConfig('package.json'), // Use workspace root package.json - await typescriptPluginConfig({ - tsconfig: `packages/${projectName}/tsconfig.lib.json`, - }), - jsDocsCoreConfig([ - `packages/${projectName}/src/**\/*.ts`, - ...jsDocsExclusionPatterns, - ]), -); -*/ diff --git a/packages/models/project.json b/packages/models/project.json index 63f54aac7..d35181a85 100644 --- a/packages/models/project.json +++ b/packages/models/project.json @@ -11,6 +11,9 @@ "outputs": ["{projectRoot}/docs/models-reference.md"] }, "code-pushup": { + "dependsOn": ["code-pushup-coverage"] + }, + "code-pushup-coverage": { "dependsOn": ["unit-test", "int-test"] }, "build": { diff --git a/packages/models/transformers/project.json b/packages/models/transformers/project.json index fdd783682..1e489cc52 100644 --- a/packages/models/transformers/project.json +++ b/packages/models/transformers/project.json @@ -4,6 +4,10 @@ "sourceRoot": "packages/models/transformers/src", "projectType": "library", "targets": { + "code-pushup": { + "dependsOn": ["code-pushup-coverage"] + }, + "code-pushup-coverage": {}, "build": { "executor": "@nx/js:tsc", "outputs": ["{options.outputPath}"], diff --git a/packages/nx-plugin/project.json b/packages/nx-plugin/project.json index dca4e797d..4886ebf30 100644 --- a/packages/nx-plugin/project.json +++ b/packages/nx-plugin/project.json @@ -6,6 +6,9 @@ "implicitDependencies": ["cli"], "targets": { "code-pushup": { + "dependsOn": ["code-pushup-coverage"] + }, + "code-pushup-coverage": { "dependsOn": ["unit-test", "int-test"] }, "build": { diff --git a/packages/plugin-coverage/project.json b/packages/plugin-coverage/project.json index f1cc4ccd1..ac9193ddc 100644 --- a/packages/plugin-coverage/project.json +++ b/packages/plugin-coverage/project.json @@ -5,6 +5,9 @@ "projectType": "library", "targets": { "code-pushup": { + "dependsOn": ["code-pushup-coverage"] + }, + "code-pushup-coverage": { "dependsOn": ["unit-test", "int-test"] }, "build": {}, diff --git a/packages/plugin-eslint/project.json b/packages/plugin-eslint/project.json index aefe1683b..c30c88c9a 100644 --- a/packages/plugin-eslint/project.json +++ b/packages/plugin-eslint/project.json @@ -5,6 +5,9 @@ "projectType": "library", "targets": { "code-pushup": { + "dependsOn": ["code-pushup-coverage"] + }, + "code-pushup-coverage": { "dependsOn": ["unit-test", "int-test"] }, "build": {}, diff --git a/packages/plugin-js-packages/project.json b/packages/plugin-js-packages/project.json index 1d049be6f..f77f88e05 100644 --- a/packages/plugin-js-packages/project.json +++ b/packages/plugin-js-packages/project.json @@ -5,6 +5,9 @@ "projectType": "library", "targets": { "code-pushup": { + "dependsOn": ["code-pushup-coverage"] + }, + "code-pushup-coverage": { "dependsOn": ["unit-test", "int-test"] }, "build": {}, diff --git a/packages/plugin-jsdocs/project.json b/packages/plugin-jsdocs/project.json index 5719cda07..f6931c112 100644 --- a/packages/plugin-jsdocs/project.json +++ b/packages/plugin-jsdocs/project.json @@ -6,6 +6,9 @@ "tags": ["scope:plugin", "type:feature", "publishable"], "targets": { "code-pushup": { + "dependsOn": ["code-pushup-coverage"] + }, + "code-pushup-coverage": { "dependsOn": ["unit-test", "int-test"] }, "build": {}, diff --git a/packages/plugin-lighthouse/project.json b/packages/plugin-lighthouse/project.json index 448418f9d..cf1204f61 100644 --- a/packages/plugin-lighthouse/project.json +++ b/packages/plugin-lighthouse/project.json @@ -5,6 +5,9 @@ "projectType": "library", "targets": { "code-pushup": { + "dependsOn": ["code-pushup-coverage"] + }, + "code-pushup-coverage": { "dependsOn": ["unit-test", "int-test"] }, "build": {}, diff --git a/packages/plugin-typescript/project.json b/packages/plugin-typescript/project.json index ee45a2ac8..7e114d7ca 100644 --- a/packages/plugin-typescript/project.json +++ b/packages/plugin-typescript/project.json @@ -5,6 +5,9 @@ "projectType": "library", "targets": { "code-pushup": { + "dependsOn": ["code-pushup-coverage"] + }, + "code-pushup-coverage": { "dependsOn": ["unit-test", "int-test"] }, "build": {}, diff --git a/packages/utils/project.json b/packages/utils/project.json index 502f7d5c6..040a94034 100644 --- a/packages/utils/project.json +++ b/packages/utils/project.json @@ -5,6 +5,9 @@ "projectType": "library", "targets": { "code-pushup": { + "dependsOn": ["code-pushup-coverage"] + }, + "code-pushup-coverage": { "dependsOn": ["unit-test", "int-test"] }, "build": {}, diff --git a/project.json b/project.json index 3363bc29c..a3ec91600 100644 --- a/project.json +++ b/project.json @@ -3,10 +3,12 @@ "$schema": "node_modules/nx/schemas/project-schema.json", "targets": { "code-pushup": { + "dependsOn": ["code-pushup-coverage"], "options": { "config": "{workspaceRoot}/code-pushup.config.ts", "upload.project": "cli" } - } + }, + "code-pushup-coverage": {} } } From e72b00fa71442f48f622888aeb4780582bdffce9 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 12 Aug 2025 18:04:35 +0200 Subject: [PATCH 020/111] chore: wip caching --- code-pushup.config.ts | 19 +-- code-pushup.preset.ts | 12 +- examples/plugins/project.json | 8 +- nx.json | 146 ++++++++++++++++++---- package-lock.json | 4 +- packages/ci/project.json | 4 + packages/cli/project.json | 4 + packages/core/project.json | 4 + packages/create-cli/project.json | 4 + packages/models/project.json | 8 +- packages/models/transformers/project.json | 4 - packages/nx-plugin/project.json | 4 + packages/plugin-coverage/project.json | 4 + packages/plugin-eslint/project.json | 4 + packages/plugin-js-packages/project.json | 4 + packages/plugin-jsdocs/project.json | 4 + packages/plugin-lighthouse/project.json | 4 + packages/plugin-typescript/project.json | 4 + packages/utils/project.json | 4 + project.json | 16 ++- testing/test-nx-utils/project.json | 12 +- testing/test-setup/project.json | 12 +- testing/test-utils/project.json | 12 +- 23 files changed, 231 insertions(+), 70 deletions(-) diff --git a/code-pushup.config.ts b/code-pushup.config.ts index c21859cce..803e0acad 100644 --- a/code-pushup.config.ts +++ b/code-pushup.config.ts @@ -1,12 +1,8 @@ import 'dotenv/config'; import { - coverageCoreConfigNx, - eslintCoreConfigNx, - jsDocsCoreConfig, jsPackagesCoreConfig, lighthouseCoreConfig, loadEnv, - typescriptPluginConfig, } from './code-pushup.preset.js'; import type { CoreConfig } from './packages/models/src/index.js'; import { mergeConfigs } from './packages/utils/src/index.js'; @@ -18,21 +14,8 @@ const config: CoreConfig = { export default mergeConfigs( config, - await coverageCoreConfigNx(), - await jsPackagesCoreConfig(), + /* await jsPackagesCoreConfig(),*/ await lighthouseCoreConfig( 'https://github.com/code-pushup/cli?tab=readme-ov-file#code-pushup-cli/', ), - await typescriptPluginConfig({ - tsconfig: 'packages/cli/tsconfig.lib.json', - }), - await eslintCoreConfigNx(), - jsDocsCoreConfig([ - 'packages/**/src/**/*.ts', - '!packages/**/node_modules', - '!packages/**/{mocks,mock}', - '!**/*.{spec,test}.ts', - '!**/implementation/**', - '!**/internal/**', - ]), ); diff --git a/code-pushup.preset.ts b/code-pushup.preset.ts index 758e4ed1e..994564763 100644 --- a/code-pushup.preset.ts +++ b/code-pushup.preset.ts @@ -39,7 +39,7 @@ export async function loadEnv() { CP_SERVER: z.string().url(), CP_API_KEY: z.string().min(1), CP_ORGANIZATION: z.string().min(1), - CP_PROJECT: z.string().min(1), + CP_PROJECT: z.string().optional(), }); const { data: env, success } = await envSchema.safeParseAsync(process.env); @@ -48,10 +48,12 @@ export async function loadEnv() { return {}; } const uploadConfig = { - server: env.CP_SERVER, apiKey: env.CP_API_KEY, + server: env.CP_SERVER, organization: env.CP_ORGANIZATION, - project: env.CP_PROJECT, + ...(env.CP_PROJECT + ? { project: env.CP_PROJECT } + : { project: 'missing-project-name' }), }; return ( uploadConfig.apiKey && { @@ -185,7 +187,9 @@ export const jsPackagesCoreConfig = async ( export const lighthouseCoreConfig = async ( urls: LighthouseUrls, ): Promise => { - const lhPlugin = await lighthousePlugin(urls); + const lhPlugin = await lighthousePlugin(urls, { + onlyAudits: ['largest-contentful-paint'], + }); return { plugins: [lhPlugin], categories: mergeLighthouseCategories(lhPlugin, lighthouseCategories), diff --git a/examples/plugins/project.json b/examples/plugins/project.json index 7fd16c013..b11efba5e 100644 --- a/examples/plugins/project.json +++ b/examples/plugins/project.json @@ -5,11 +5,17 @@ "projectType": "library", "targets": { "code-pushup": { - "dependsOn": ["code-pushup-coverage"] + "dependsOn": [ + "code-pushup-coverage", + "code-pushup-eslint", + "code-pushup-typescript" + ] }, "code-pushup-coverage": { "dependsOn": ["unit-test", "int-test"] }, + "code-pushup-eslint": {}, + "code-pushup-typescript": {}, "build": { "executor": "@nx/js:tsc", "outputs": ["{options.outputPath}"], diff --git a/nx.json b/nx.json index de3326b7c..20beedae4 100644 --- a/nx.json +++ b/nx.json @@ -2,27 +2,30 @@ "$schema": "./node_modules/nx/schemas/nx-schema.json", "targetDefaults": { "code-pushup": { - "cache": true, + "dependsOn": [ + "code-pushup-coverage", + "code-pushup-eslint", + "code-pushup-js-packages", + "code-pushup-lighthouse", + "code-pushup-jsdocs", + "code-pushup-typescript" + ], + "cache": false, "outputs": [ "{projectRoot}/.code-pushup/*.md", "{projectRoot}/.code-pushup/*.json" ], "executor": "nx:run-commands", "options": { - "command": "npx https://pkg.pr.new/code-pushup/cli/@code-pushup/cli@1059", + "command": "node packages/cli/src/index.ts", "args": [ "--no-progress", "--verbose", - "--config", - "{projectRoot}/code-pushup.config.ts", - "--persist.filename", - "{projectName}-report", - "--persist.outputDir", - "{projectRoot}/.code-pushup", - "--upload.project", - "cli-{projectName}" + "--config={projectRoot}/code-pushup.config.ts", + "--cache.read", + "--persist.outputDir={projectRoot}/.code-pushup", + "--upload.project=cli-{projectName}" ], - "outputPath": "{projectRoot}/.code-pushup", "env": { "NODE_OPTIONS": "--import tsx", "TSX_TSCONFIG_PATH": "tsconfig.base.json" @@ -33,23 +36,122 @@ "cache": true, "outputs": ["{projectRoot}/.code-pushup/coverage"], "executor": "nx:run-commands", + "dependsOn": ["unit-test", "int-test"], + "options": { + "command": "node packages/cli/src/index.ts collect", + "args": [ + "--no-progress", + "--verbose", + "--config={projectRoot}/code-pushup.config.ts", + "--cache.write", + "--onlyPlugins=coverage", + "--persist.skipReports=true", + "--persist.outputDir={projectRoot}/.code-pushup" + ], + "env": { + "NODE_OPTIONS": "--import tsx", + "TSX_TSCONFIG_PATH": "tsconfig.base.json" + } + } + }, + "code-pushup-eslint": { + "cache": true, + "outputs": ["{projectRoot}/.code-pushup/eslint"], + "executor": "nx:run-commands", + "options": { + "command": "node packages/cli/src/index.ts collect", + "args": [ + "--no-progress", + "--verbose", + "--config={projectRoot}/code-pushup.config.ts", + "--cache.write", + "--onlyPlugins=eslint", + "--persist.skipReports", + "--persist.outputDir={projectRoot}/.code-pushup" + ], + "env": { + "NODE_OPTIONS": "--import tsx", + "TSX_TSCONFIG_PATH": "tsconfig.base.json" + } + } + }, + "code-pushup-js-packages": { + "cache": false, + "outputs": ["{projectRoot}/.code-pushup/js-packages"], + "executor": "nx:run-commands", + "options": { + "command": "node packages/cli/src/index.ts collect", + "args": [ + "--no-progress", + "--verbose", + "--config={projectRoot}/code-pushup.config.ts", + "--cache.write", + "--onlyPlugins=js-packages", + "--persist.skipReports", + "--persist.outputDir={projectRoot}/.code-pushup" + ], + "env": { + "NODE_OPTIONS": "--import tsx", + "TSX_TSCONFIG_PATH": "tsconfig.base.json" + } + } + }, + "code-pushup-lighthouse": { + "cache": true, + "outputs": ["{projectRoot}/.code-pushup/lighthouse"], + "executor": "nx:run-commands", + "options": { + "command": "node packages/cli/src/index.ts", + "args": [ + "--no-progress", + "--verbose", + "--config={projectRoot}/code-pushup.config.ts", + "--cache.write", + "--onlyPlugins=lighthouse", + "--persist.skipReports", + "--persist.outputDir={projectRoot}/.code-pushup" + ], + "env": { + "NODE_OPTIONS": "--import tsx", + "TSX_TSCONFIG_PATH": "tsconfig.base.json" + } + } + }, + "code-pushup-jsdocs": { + "cache": true, + "outputs": ["{projectRoot}/.code-pushup/jsdocs"], + "executor": "nx:run-commands", + "options": { + "command": "node packages/cli/src/index.ts collect", + "args": [ + "--no-progress", + "--verbose", + "--config={projectRoot}/code-pushup.config.ts", + "--cache.write", + "--onlyPlugins=jsdocs", + "--persist.skipReports", + "--persist.outputDir={projectRoot}/.code-pushup" + ], + "env": { + "NODE_OPTIONS": "--import tsx", + "TSX_TSCONFIG_PATH": "tsconfig.base.json" + } + } + }, + "code-pushup-typescript": { + "cache": true, + "outputs": ["{projectRoot}/.code-pushup/typescript"], + "executor": "nx:run-commands", "options": { - "command": "npm install https://pkg.pr.new/code-pushup/cli/@code-pushup/utils@1059 https://pkg.pr.new/code-pushup/cli/@code-pushup/models@1059 && npx --yes https://pkg.pr.new/code-pushup/cli/@code-pushup/cli@1059", + "command": "node packages/cli/src/index.ts collect", "args": [ "--no-progress", "--verbose", - "--config", - "{projectRoot}/code-pushup.config.ts", + "--config={projectRoot}/code-pushup.config.ts", "--cache.write", - "true", - "--onlyPlugins", - "coverage", + "--onlyPlugins=typescript", "--persist.skipReports", - "true", - "--persist.outputDir", - "{projectRoot}/.code-pushup", - "--upload.project", - "{projectName}" + "--persist.outputDir={projectRoot}/.code-pushup" ], "env": { "NODE_OPTIONS": "--import tsx", diff --git a/package-lock.json b/package-lock.json index 3f0850b23..acfabdf72 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2363,10 +2363,10 @@ "node_modules/@code-pushup/utils": { "version": "0.73.0", "resolved": "https://pkg.pr.new/code-pushup/cli/@code-pushup/utils@1059", - "integrity": "sha512-AT+mkzTs1l4WAbCTChDmXScZ6eenmjRKkG3c6OKQvlnCeHwNnZYc8idNbM3DWEM5VhzA2HaHWjqI9Bz+58vOnw==", + "integrity": "sha512-VRXkc2MSEb1N/Z9bl+h82hvLE0/f8HfGMmcGb6teHHyEhMCPU0/XVe02RI0XI+4KIcIPxPc68sxgnuCnSc73Vg==", "license": "MIT", "dependencies": { - "@code-pushup/models": "https://pkg.pr.new/code-pushup/cli/@code-pushup/models@98dedef5b1b2751fceb082065d7898454887af53", + "@code-pushup/models": "https://pkg.pr.new/code-pushup/cli/@code-pushup/models@612dcb8110ed5c8d004a2b10b2d10aaff2e5ec85", "@isaacs/cliui": "^8.0.2", "@poppinss/cliui": "^6.4.0", "ansis": "^3.3.0", diff --git a/packages/ci/project.json b/packages/ci/project.json index 1ac3c6663..88d93b963 100644 --- a/packages/ci/project.json +++ b/packages/ci/project.json @@ -10,6 +10,10 @@ "code-pushup-coverage": { "dependsOn": ["unit-test", "int-test"] }, + "code-pushup-eslint": {}, + "code-pushup-js-packages": {}, + "code-pushup-jsdocs": {}, + "code-pushup-typescript": {}, "build": {}, "lint": {}, "unit-test": { diff --git a/packages/cli/project.json b/packages/cli/project.json index 2bb54d0ee..ac6f2077d 100644 --- a/packages/cli/project.json +++ b/packages/cli/project.json @@ -10,6 +10,10 @@ "code-pushup-coverage": { "dependsOn": ["unit-test", "int-test", "e2e-test"] }, + "code-pushup-eslint": {}, + "code-pushup-js-packages": {}, + "code-pushup-lighthouse": {}, + "code-pushup-typescript": {}, "build": {}, "lint": {}, "unit-test": { diff --git a/packages/core/project.json b/packages/core/project.json index 60adf08a4..300e2793e 100644 --- a/packages/core/project.json +++ b/packages/core/project.json @@ -10,6 +10,10 @@ "code-pushup-coverage": { "dependsOn": ["unit-test", "int-test"] }, + "code-pushup-eslint": {}, + "code-pushup-js-packages": {}, + "code-pushup-lighthouse": {}, + "code-pushup-typescript": {}, "build": {}, "lint": {}, "unit-test": { diff --git a/packages/create-cli/project.json b/packages/create-cli/project.json index ddfebc2ea..d3d19e2ad 100644 --- a/packages/create-cli/project.json +++ b/packages/create-cli/project.json @@ -10,6 +10,10 @@ "code-pushup-coverage": { "dependsOn": ["unit-test", "int-test"] }, + "code-pushup-eslint": {}, + "code-pushup-js-packages": {}, + "code-pushup-lighthouse": {}, + "code-pushup-typescript": {}, "build": {}, "lint": {}, "unit-test": { diff --git a/packages/models/project.json b/packages/models/project.json index d35181a85..d402a89a6 100644 --- a/packages/models/project.json +++ b/packages/models/project.json @@ -10,12 +10,14 @@ "inputs": ["production", "^production", "{projectRoot}/zod2md.config.ts"], "outputs": ["{projectRoot}/docs/models-reference.md"] }, - "code-pushup": { - "dependsOn": ["code-pushup-coverage"] - }, + "code-pushup": {}, "code-pushup-coverage": { "dependsOn": ["unit-test", "int-test"] }, + "code-pushup-eslint": {}, + "code-pushup-js-packages": {}, + "code-pushup-jsdocs": {}, + "code-pushup-typescript": {}, "build": { "dependsOn": [ "^build", diff --git a/packages/models/transformers/project.json b/packages/models/transformers/project.json index 1e489cc52..fdd783682 100644 --- a/packages/models/transformers/project.json +++ b/packages/models/transformers/project.json @@ -4,10 +4,6 @@ "sourceRoot": "packages/models/transformers/src", "projectType": "library", "targets": { - "code-pushup": { - "dependsOn": ["code-pushup-coverage"] - }, - "code-pushup-coverage": {}, "build": { "executor": "@nx/js:tsc", "outputs": ["{options.outputPath}"], diff --git a/packages/nx-plugin/project.json b/packages/nx-plugin/project.json index 4886ebf30..929fe7fb6 100644 --- a/packages/nx-plugin/project.json +++ b/packages/nx-plugin/project.json @@ -11,6 +11,10 @@ "code-pushup-coverage": { "dependsOn": ["unit-test", "int-test"] }, + "code-pushup-eslint": {}, + "code-pushup-js-packages": {}, + "code-pushup-jsdocs": {}, + "code-pushup-typescript": {}, "build": { "options": { "assets": [ diff --git a/packages/plugin-coverage/project.json b/packages/plugin-coverage/project.json index ac9193ddc..018e8e1a3 100644 --- a/packages/plugin-coverage/project.json +++ b/packages/plugin-coverage/project.json @@ -10,6 +10,10 @@ "code-pushup-coverage": { "dependsOn": ["unit-test", "int-test"] }, + "code-pushup-eslint": {}, + "code-pushup-js-packages": {}, + "code-pushup-jsdocs": {}, + "code-pushup-typescript": {}, "build": {}, "lint": {}, "unit-test": { diff --git a/packages/plugin-eslint/project.json b/packages/plugin-eslint/project.json index c30c88c9a..87809c3fb 100644 --- a/packages/plugin-eslint/project.json +++ b/packages/plugin-eslint/project.json @@ -10,6 +10,10 @@ "code-pushup-coverage": { "dependsOn": ["unit-test", "int-test"] }, + "code-pushup-eslint": {}, + "code-pushup-js-packages": {}, + "code-pushup-jsdocs": {}, + "code-pushup-typescript": {}, "build": {}, "lint": {}, "unit-test": { diff --git a/packages/plugin-js-packages/project.json b/packages/plugin-js-packages/project.json index f77f88e05..7a8ba2e79 100644 --- a/packages/plugin-js-packages/project.json +++ b/packages/plugin-js-packages/project.json @@ -10,6 +10,10 @@ "code-pushup-coverage": { "dependsOn": ["unit-test", "int-test"] }, + "code-pushup-eslint": {}, + "code-pushup-js-packages": {}, + "code-pushup-jsdocs": {}, + "code-pushup-typescript": {}, "build": {}, "lint": {}, "unit-test": { diff --git a/packages/plugin-jsdocs/project.json b/packages/plugin-jsdocs/project.json index f6931c112..2be83f65f 100644 --- a/packages/plugin-jsdocs/project.json +++ b/packages/plugin-jsdocs/project.json @@ -11,6 +11,10 @@ "code-pushup-coverage": { "dependsOn": ["unit-test", "int-test"] }, + "code-pushup-eslint": {}, + "code-pushup-js-packages": {}, + "code-pushup-jsdocs": {}, + "code-pushup-typescript": {}, "build": {}, "lint": {}, "unit-test": { diff --git a/packages/plugin-lighthouse/project.json b/packages/plugin-lighthouse/project.json index cf1204f61..f9b99b136 100644 --- a/packages/plugin-lighthouse/project.json +++ b/packages/plugin-lighthouse/project.json @@ -10,6 +10,10 @@ "code-pushup-coverage": { "dependsOn": ["unit-test", "int-test"] }, + "code-pushup-eslint": {}, + "code-pushup-js-packages": {}, + "code-pushup-jsdocs": {}, + "code-pushup-typescript": {}, "build": {}, "lint": {}, "unit-test": { diff --git a/packages/plugin-typescript/project.json b/packages/plugin-typescript/project.json index 7e114d7ca..b6055db8d 100644 --- a/packages/plugin-typescript/project.json +++ b/packages/plugin-typescript/project.json @@ -10,6 +10,10 @@ "code-pushup-coverage": { "dependsOn": ["unit-test", "int-test"] }, + "code-pushup-eslint": {}, + "code-pushup-js-packages": {}, + "code-pushup-jsdocs": {}, + "code-pushup-typescript": {}, "build": {}, "lint": {}, "unit-test": { diff --git a/packages/utils/project.json b/packages/utils/project.json index 040a94034..92eb6112f 100644 --- a/packages/utils/project.json +++ b/packages/utils/project.json @@ -10,6 +10,10 @@ "code-pushup-coverage": { "dependsOn": ["unit-test", "int-test"] }, + "code-pushup-eslint": {}, + "code-pushup-js-packages": {}, + "code-pushup-jsdocs": {}, + "code-pushup-typescript": {}, "build": {}, "lint": {}, "perf": { diff --git a/project.json b/project.json index a3ec91600..4fd01156a 100644 --- a/project.json +++ b/project.json @@ -3,12 +3,20 @@ "$schema": "node_modules/nx/schemas/project-schema.json", "targets": { "code-pushup": { - "dependsOn": ["code-pushup-coverage"], + "executor": "nx:run-commands", "options": { - "config": "{workspaceRoot}/code-pushup.config.ts", - "upload.project": "cli" + "command": "node packages/cli/src/index.ts", + "args": [ + "--no-progress", + "--verbose", + "--config={projectRoot}/code-pushup.config.ts", + "--cache.read", + "--persist.outputDir={projectRoot}/.code-pushup", + "--upload.project=cli" + ] } }, - "code-pushup-coverage": {} + + "code-pushup-lighthouse": {} } } diff --git a/testing/test-nx-utils/project.json b/testing/test-nx-utils/project.json index 7f9886230..ca3eb586c 100644 --- a/testing/test-nx-utils/project.json +++ b/testing/test-nx-utils/project.json @@ -5,11 +5,15 @@ "projectType": "library", "targets": { "code-pushup": { - "dependsOn": ["code-pushup-coverage"] - }, - "code-pushup-coverage": { - "dependsOn": ["unit-test"] + "dependsOn": [ + "code-pushup-coverage", + "code-pushup-eslint", + "code-pushup-typescript" + ] }, + "code-pushup-coverage": {}, + "code-pushup-eslint": {}, + "code-pushup-typescript": {}, "build": {}, "lint": {}, "unit-test": { diff --git a/testing/test-setup/project.json b/testing/test-setup/project.json index b112b6eed..31990d367 100644 --- a/testing/test-setup/project.json +++ b/testing/test-setup/project.json @@ -5,11 +5,15 @@ "projectType": "library", "targets": { "code-pushup": { - "dependsOn": ["code-pushup-coverage"] - }, - "code-pushup-coverage": { - "dependsOn": ["unit-test"] + "dependsOn": [ + "code-pushup-coverage", + "code-pushup-eslint", + "code-pushup-typescript" + ] }, + "code-pushup-coverage": {}, + "code-pushup-eslint": {}, + "code-pushup-typescript": {}, "build": {}, "lint": {}, "unit-test": { diff --git a/testing/test-utils/project.json b/testing/test-utils/project.json index 0f8e90f6e..1479b13ed 100644 --- a/testing/test-utils/project.json +++ b/testing/test-utils/project.json @@ -5,11 +5,15 @@ "projectType": "library", "targets": { "code-pushup": { - "dependsOn": ["code-pushup-coverage"] - }, - "code-pushup-coverage": { - "dependsOn": ["unit-test"] + "dependsOn": [ + "code-pushup-coverage", + "code-pushup-eslint", + "code-pushup-typescript" + ] }, + "code-pushup-coverage": {}, + "code-pushup-eslint": {}, + "code-pushup-typescript": {}, "build": {}, "lint": {}, "unit-test": { From b17323f28909fc143a329eb861666a4c64f1e045 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 12 Aug 2025 18:34:03 +0200 Subject: [PATCH 021/111] chore: wip caching cp configs --- .../mocks/fixtures/npm-repo/code-pushup.config.ts | 8 -------- nx.json | 12 ++++++++---- packages/ci/code-pushup.config.ts | 4 ---- packages/cli/code-pushup.config.ts | 4 ---- packages/core/code-pushup.config.ts | 4 ---- packages/create-cli/code-pushup.config.ts | 4 ---- packages/models/code-pushup.config.ts | 4 ---- packages/nx-plugin/code-pushup.config.ts | 4 ---- packages/plugin-coverage/code-pushup.config.ts | 4 ---- packages/plugin-eslint/code-pushup.config.ts | 4 ---- packages/plugin-js-packages/code-pushup.config.ts | 4 ---- packages/plugin-jsdocs/code-pushup.config.ts | 4 ---- packages/plugin-lighthouse/code-pushup.config.ts | 4 ---- packages/plugin-typescript/code-pushup.config.ts | 4 ---- packages/utils/code-pushup.config.ts | 4 ---- testing/test-nx-utils/code-pushup.config.ts | 4 ---- testing/test-setup/code-pushup.config.ts | 4 ---- testing/test-utils/code-pushup.config.ts | 4 ---- 18 files changed, 8 insertions(+), 76 deletions(-) diff --git a/e2e/plugin-js-packages-e2e/mocks/fixtures/npm-repo/code-pushup.config.ts b/e2e/plugin-js-packages-e2e/mocks/fixtures/npm-repo/code-pushup.config.ts index aba57ced5..f200abcd6 100644 --- a/e2e/plugin-js-packages-e2e/mocks/fixtures/npm-repo/code-pushup.config.ts +++ b/e2e/plugin-js-packages-e2e/mocks/fixtures/npm-repo/code-pushup.config.ts @@ -6,11 +6,3 @@ import type { CoreConfig } from '@code-pushup/models'; const thisConfigFolder = fileURLToPath(dirname(import.meta.url)); export default { - persist: { outputDir: thisConfigFolder, format: ['json'] }, - plugins: [ - await jsPackagesPlugin({ - packageManager: 'npm', - packageJsonPath: join(thisConfigFolder, 'package.json'), - }), - ], -} satisfies CoreConfig; diff --git a/nx.json b/nx.json index 20beedae4..1107d7080 100644 --- a/nx.json +++ b/nx.json @@ -10,10 +10,10 @@ "code-pushup-jsdocs", "code-pushup-typescript" ], - "cache": false, + "cache": true, "outputs": [ - "{projectRoot}/.code-pushup/*.md", - "{projectRoot}/.code-pushup/*.json" + "{projectRoot}/.code-pushup/report.md", + "{projectRoot}/.code-pushup/report.json" ], "executor": "nx:run-commands", "options": { @@ -56,6 +56,7 @@ }, "code-pushup-eslint": { "cache": true, + "inputs": ["default", "^default", "{projectRoot}/eslint.config.?(c)js"], "outputs": ["{projectRoot}/.code-pushup/eslint"], "executor": "nx:run-commands", "options": { @@ -77,6 +78,7 @@ }, "code-pushup-js-packages": { "cache": false, + "inputs": ["default", "^default", "{projectRoot}/package.json"], "outputs": ["{projectRoot}/.code-pushup/js-packages"], "executor": "nx:run-commands", "options": { @@ -97,7 +99,7 @@ } }, "code-pushup-lighthouse": { - "cache": true, + "cache": false, "outputs": ["{projectRoot}/.code-pushup/lighthouse"], "executor": "nx:run-commands", "options": { @@ -119,6 +121,7 @@ }, "code-pushup-jsdocs": { "cache": true, + "inputs": ["default", "^default", "{projectRoot}/tsconfig.lib.json"], "outputs": ["{projectRoot}/.code-pushup/jsdocs"], "executor": "nx:run-commands", "options": { @@ -140,6 +143,7 @@ }, "code-pushup-typescript": { "cache": true, + "inputs": ["default", "^default", "{projectRoot}/tsconfig.lib.json"], "outputs": ["{projectRoot}/.code-pushup/typescript"], "executor": "nx:run-commands", "options": { diff --git a/packages/ci/code-pushup.config.ts b/packages/ci/code-pushup.config.ts index 4958c3831..25e0c8e51 100644 --- a/packages/ci/code-pushup.config.ts +++ b/packages/ci/code-pushup.config.ts @@ -15,10 +15,6 @@ const projectName = process.env.CP_PROJECT_NAME || 'cli'; const config: CoreConfig = { ...(await loadEnv()), - persist: { - filename: `${projectName}-report`, - outputDir: `packages/${projectName}/.code-pushup`, - }, plugins: [], }; diff --git a/packages/cli/code-pushup.config.ts b/packages/cli/code-pushup.config.ts index 4958c3831..25e0c8e51 100644 --- a/packages/cli/code-pushup.config.ts +++ b/packages/cli/code-pushup.config.ts @@ -15,10 +15,6 @@ const projectName = process.env.CP_PROJECT_NAME || 'cli'; const config: CoreConfig = { ...(await loadEnv()), - persist: { - filename: `${projectName}-report`, - outputDir: `packages/${projectName}/.code-pushup`, - }, plugins: [], }; diff --git a/packages/core/code-pushup.config.ts b/packages/core/code-pushup.config.ts index de597af2d..add3f2c0d 100644 --- a/packages/core/code-pushup.config.ts +++ b/packages/core/code-pushup.config.ts @@ -15,10 +15,6 @@ const projectName = process.env.CP_PROJECT_NAME || 'core'; const config: CoreConfig = { ...(await loadEnv()), - persist: { - filename: `${projectName}-report`, - outputDir: `packages/${projectName}/.code-pushup`, - }, plugins: [], }; diff --git a/packages/create-cli/code-pushup.config.ts b/packages/create-cli/code-pushup.config.ts index a4bb1ed22..6b895dcc7 100644 --- a/packages/create-cli/code-pushup.config.ts +++ b/packages/create-cli/code-pushup.config.ts @@ -15,10 +15,6 @@ const projectName = process.env.CP_PROJECT_NAME || 'create-cli'; const config: CoreConfig = { ...(await loadEnv()), - persist: { - filename: `${projectName}-report`, - outputDir: `packages/${projectName}/.code-pushup`, - }, plugins: [], }; diff --git a/packages/models/code-pushup.config.ts b/packages/models/code-pushup.config.ts index a8be5d14c..b05a67f89 100644 --- a/packages/models/code-pushup.config.ts +++ b/packages/models/code-pushup.config.ts @@ -14,10 +14,6 @@ const projectName = process.env.CP_PROJECT_NAME || 'models'; const config: CoreConfig = { ...(await loadEnv()), - persist: { - filename: `${projectName}-report`, - outputDir: `packages/${projectName}/.code-pushup`, - }, plugins: [], }; diff --git a/packages/nx-plugin/code-pushup.config.ts b/packages/nx-plugin/code-pushup.config.ts index 2c4af73ce..00f01dc6a 100644 --- a/packages/nx-plugin/code-pushup.config.ts +++ b/packages/nx-plugin/code-pushup.config.ts @@ -15,10 +15,6 @@ const projectName = process.env.CP_PROJECT_NAME || 'nx-plugin'; const config: CoreConfig = { ...(await loadEnv()), - persist: { - filename: `${projectName}-report`, - outputDir: `packages/${projectName}/.code-pushup`, - }, plugins: [], }; diff --git a/packages/plugin-coverage/code-pushup.config.ts b/packages/plugin-coverage/code-pushup.config.ts index dd546f427..be7a310c8 100644 --- a/packages/plugin-coverage/code-pushup.config.ts +++ b/packages/plugin-coverage/code-pushup.config.ts @@ -15,10 +15,6 @@ const projectName = process.env.CP_PROJECT_NAME || 'plugin-coverage'; const config: CoreConfig = { ...(await loadEnv()), - persist: { - filename: `${projectName}-report`, - outputDir: `packages/${projectName}/.code-pushup`, - }, plugins: [], }; diff --git a/packages/plugin-eslint/code-pushup.config.ts b/packages/plugin-eslint/code-pushup.config.ts index c077677cd..a79ca8ad2 100644 --- a/packages/plugin-eslint/code-pushup.config.ts +++ b/packages/plugin-eslint/code-pushup.config.ts @@ -15,10 +15,6 @@ const projectName = process.env.CP_PROJECT_NAME || 'plugin-eslint'; const config: CoreConfig = { ...(await loadEnv()), - persist: { - filename: `${projectName}-report`, - outputDir: `packages/${projectName}/.code-pushup`, - }, plugins: [], }; diff --git a/packages/plugin-js-packages/code-pushup.config.ts b/packages/plugin-js-packages/code-pushup.config.ts index 9f1f5317f..642b553aa 100644 --- a/packages/plugin-js-packages/code-pushup.config.ts +++ b/packages/plugin-js-packages/code-pushup.config.ts @@ -15,10 +15,6 @@ const projectName = process.env.CP_PROJECT_NAME || 'plugin-js-packages'; const config: CoreConfig = { ...(await loadEnv()), - persist: { - filename: `${projectName}-report`, - outputDir: `packages/${projectName}/.code-pushup`, - }, plugins: [], }; diff --git a/packages/plugin-jsdocs/code-pushup.config.ts b/packages/plugin-jsdocs/code-pushup.config.ts index 0f37e7394..b4f872164 100644 --- a/packages/plugin-jsdocs/code-pushup.config.ts +++ b/packages/plugin-jsdocs/code-pushup.config.ts @@ -15,10 +15,6 @@ const projectName = process.env.CP_PROJECT_NAME || 'plugin-jsdocs'; const config: CoreConfig = { ...(await loadEnv()), - persist: { - filename: `${projectName}-report`, - outputDir: `packages/${projectName}/.code-pushup`, - }, plugins: [], }; diff --git a/packages/plugin-lighthouse/code-pushup.config.ts b/packages/plugin-lighthouse/code-pushup.config.ts index 9f1f5317f..642b553aa 100644 --- a/packages/plugin-lighthouse/code-pushup.config.ts +++ b/packages/plugin-lighthouse/code-pushup.config.ts @@ -15,10 +15,6 @@ const projectName = process.env.CP_PROJECT_NAME || 'plugin-js-packages'; const config: CoreConfig = { ...(await loadEnv()), - persist: { - filename: `${projectName}-report`, - outputDir: `packages/${projectName}/.code-pushup`, - }, plugins: [], }; diff --git a/packages/plugin-typescript/code-pushup.config.ts b/packages/plugin-typescript/code-pushup.config.ts index 9f1f5317f..642b553aa 100644 --- a/packages/plugin-typescript/code-pushup.config.ts +++ b/packages/plugin-typescript/code-pushup.config.ts @@ -15,10 +15,6 @@ const projectName = process.env.CP_PROJECT_NAME || 'plugin-js-packages'; const config: CoreConfig = { ...(await loadEnv()), - persist: { - filename: `${projectName}-report`, - outputDir: `packages/${projectName}/.code-pushup`, - }, plugins: [], }; diff --git a/packages/utils/code-pushup.config.ts b/packages/utils/code-pushup.config.ts index 748dca1a9..b3c514d96 100644 --- a/packages/utils/code-pushup.config.ts +++ b/packages/utils/code-pushup.config.ts @@ -15,10 +15,6 @@ const projectName = process.env.CP_PROJECT_NAME || 'utils'; const config: CoreConfig = { ...(await loadEnv()), - persist: { - filename: `${projectName}-report`, - outputDir: `packages/${projectName}/.code-pushup`, - }, plugins: [], }; diff --git a/testing/test-nx-utils/code-pushup.config.ts b/testing/test-nx-utils/code-pushup.config.ts index 95fa44fd7..631a58b5f 100644 --- a/testing/test-nx-utils/code-pushup.config.ts +++ b/testing/test-nx-utils/code-pushup.config.ts @@ -15,10 +15,6 @@ const projectName = process.env.CP_PROJECT_NAME || 'test-nx-utils'; const config: CoreConfig = { ...(await loadEnv()), - persist: { - filename: `${projectName}-report`, - outputDir: `testing/${projectName}/.code-pushup`, - }, plugins: [], }; diff --git a/testing/test-setup/code-pushup.config.ts b/testing/test-setup/code-pushup.config.ts index 9699cedb9..4c29d6754 100644 --- a/testing/test-setup/code-pushup.config.ts +++ b/testing/test-setup/code-pushup.config.ts @@ -15,10 +15,6 @@ const projectName = process.env.CP_PROJECT_NAME || 'test-setup'; const config: CoreConfig = { ...(await loadEnv()), - persist: { - filename: `${projectName}-report`, - outputDir: `testing/${projectName}/.code-pushup`, - }, plugins: [], }; diff --git a/testing/test-utils/code-pushup.config.ts b/testing/test-utils/code-pushup.config.ts index 9fd5c3e16..bcfa93811 100644 --- a/testing/test-utils/code-pushup.config.ts +++ b/testing/test-utils/code-pushup.config.ts @@ -15,10 +15,6 @@ const projectName = process.env.CP_PROJECT_NAME || 'test-utils'; const config: CoreConfig = { ...(await loadEnv()), - persist: { - filename: `${projectName}-report`, - outputDir: `testing/${projectName}/.code-pushup`, - }, plugins: [], }; From 5f438c5567eeb07c6ebd8d5030e011bf1191f591 Mon Sep 17 00:00:00 2001 From: John Doe Date: Tue, 12 Aug 2025 21:23:20 +0200 Subject: [PATCH 022/111] chore: wip caching cp configs 2 --- code-pushup.config.ts | 6 +- code-pushup.preset.ts | 11 ++- examples/plugins/project.json | 46 ++---------- nx.json | 29 +++++--- packages/ci/code-pushup.config.ts | 2 +- packages/ci/project.json | 33 ++++----- packages/cli/code-pushup.config.ts | 2 +- packages/cli/project.json | 33 ++++----- packages/core/code-pushup.config.ts | 2 +- packages/core/project.json | 33 ++++----- packages/create-cli/code-pushup.config.ts | 2 +- packages/create-cli/project.json | 41 ++++------- packages/models/code-pushup.config.ts | 2 +- packages/models/project.json | 34 ++++----- packages/nx-plugin/code-pushup.config.ts | 2 +- packages/nx-plugin/project.json | 72 +++++-------------- .../plugin-coverage/code-pushup.config.ts | 2 +- packages/plugin-coverage/project.json | 33 ++++----- packages/plugin-eslint/code-pushup.config.ts | 2 +- packages/plugin-eslint/project.json | 33 ++++----- .../plugin-js-packages/code-pushup.config.ts | 2 +- packages/plugin-js-packages/project.json | 33 ++++----- packages/plugin-jsdocs/code-pushup.config.ts | 2 +- packages/plugin-jsdocs/project.json | 37 +++++----- .../plugin-lighthouse/code-pushup.config.ts | 2 +- packages/plugin-lighthouse/project.json | 33 ++++----- .../plugin-typescript/code-pushup.config.ts | 2 +- packages/plugin-typescript/project.json | 33 ++++----- packages/utils/code-pushup.config.ts | 2 +- packages/utils/project.json | 45 ++++-------- project.json | 14 ++-- testing/test-nx-utils/code-pushup.config.ts | 31 -------- testing/test-nx-utils/project.json | 19 +---- testing/test-setup/code-pushup.config.ts | 31 -------- testing/test-setup/project.json | 22 +----- testing/test-utils/code-pushup.config.ts | 31 -------- testing/test-utils/project.json | 19 +---- 37 files changed, 264 insertions(+), 514 deletions(-) delete mode 100644 testing/test-nx-utils/code-pushup.config.ts delete mode 100644 testing/test-setup/code-pushup.config.ts delete mode 100644 testing/test-utils/code-pushup.config.ts diff --git a/code-pushup.config.ts b/code-pushup.config.ts index 803e0acad..08fd11946 100644 --- a/code-pushup.config.ts +++ b/code-pushup.config.ts @@ -7,14 +7,16 @@ import { import type { CoreConfig } from './packages/models/src/index.js'; import { mergeConfigs } from './packages/utils/src/index.js'; +const projectName = 'cli'; + const config: CoreConfig = { - ...(await loadEnv()), + ...(await loadEnv(projectName)), plugins: [], }; export default mergeConfigs( config, - /* await jsPackagesCoreConfig(),*/ + await jsPackagesCoreConfig(), await lighthouseCoreConfig( 'https://github.com/code-pushup/cli?tab=readme-ov-file#code-pushup-cli/', ), diff --git a/code-pushup.preset.ts b/code-pushup.preset.ts index 994564763..d184179ba 100644 --- a/code-pushup.preset.ts +++ b/code-pushup.preset.ts @@ -34,7 +34,14 @@ import typescriptPlugin, { /** * Helper function to load and validate Code PushUp environment variables for upload configuration */ -export async function loadEnv() { +export async function loadEnv( + projectName: string | undefined = process.env.NX_TASK_TARGET_PROJECT, +): Promise> { + if (projectName == null || projectName === '') { + throw new Error( + 'loadEnv failed! Project name is not defined. Please run code pushup fit Nx or provide a projectName.', + ); + } const envSchema = z.object({ CP_SERVER: z.string().url(), CP_API_KEY: z.string().min(1), @@ -53,7 +60,7 @@ export async function loadEnv() { organization: env.CP_ORGANIZATION, ...(env.CP_PROJECT ? { project: env.CP_PROJECT } - : { project: 'missing-project-name' }), + : { project: projectName }), }; return ( uploadConfig.apiKey && { diff --git a/examples/plugins/project.json b/examples/plugins/project.json index b11efba5e..06335f3dd 100644 --- a/examples/plugins/project.json +++ b/examples/plugins/project.json @@ -1,52 +1,16 @@ { "name": "examples-plugins", - "$schema": "../../node_modules/nx/schemas/project-schema.json", + "$schema": "../node_modules/nx/schemas/project-schema.json", "sourceRoot": "examples/plugins/src", "projectType": "library", "targets": { - "code-pushup": { - "dependsOn": [ - "code-pushup-coverage", - "code-pushup-eslint", - "code-pushup-typescript" - ] - }, - "code-pushup-coverage": { - "dependsOn": ["unit-test", "int-test"] - }, - "code-pushup-eslint": {}, - "code-pushup-typescript": {}, - "build": { - "executor": "@nx/js:tsc", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/examples/plugins", - "main": "examples/plugins/src/index.ts", - "tsConfig": "examples/plugins/tsconfig.lib.json", - "assets": ["examples/plugins/*.md"] - } - }, - "lint": { - "executor": "@nx/linter:eslint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": ["examples/plugins/**/*.ts"] - } - }, - "unit-test": { - "executor": "@nx/vite:test", - "outputs": ["{options.reportsDirectory}"], - "options": { - "configFile": "examples/plugins/vitest.unit.config.ts", - "reportsDirectory": "../../coverage/examples-plugins/unit-tests" - } - }, + "build": {}, + "lint": {}, + "unit-test": {}, "int-test": { "executor": "@nx/vite:test", - "outputs": ["{options.reportsDirectory}"], "options": { - "configFile": "examples/plugins/vitest.int.config.ts", - "reportsDirectory": "../../coverage/examples-plugins/int-tests" + "configFile": "examples/plugins/vitest.int.config.ts" } }, "run-collect": { diff --git a/nx.json b/nx.json index 1107d7080..86ea772c2 100644 --- a/nx.json +++ b/nx.json @@ -2,14 +2,6 @@ "$schema": "./node_modules/nx/schemas/nx-schema.json", "targetDefaults": { "code-pushup": { - "dependsOn": [ - "code-pushup-coverage", - "code-pushup-eslint", - "code-pushup-js-packages", - "code-pushup-lighthouse", - "code-pushup-jsdocs", - "code-pushup-typescript" - ], "cache": true, "outputs": [ "{projectRoot}/.code-pushup/report.md", @@ -78,7 +70,12 @@ }, "code-pushup-js-packages": { "cache": false, - "inputs": ["default", "^default", "{projectRoot}/package.json"], + "inputs": [ + "default", + "^default", + "{projectRoot}/package.json", + { "runtime": "echo $(($(date +%s) / 6))" } + ], "outputs": ["{projectRoot}/.code-pushup/js-packages"], "executor": "nx:run-commands", "options": { @@ -99,7 +96,7 @@ } }, "code-pushup-lighthouse": { - "cache": false, + "cache": true, "outputs": ["{projectRoot}/.code-pushup/lighthouse"], "executor": "nx:run-commands", "options": { @@ -189,6 +186,18 @@ ] } }, + "unit-test": { + "executor": "@nx/vite:test", + "options": { + "configFile": "{projectRoot}/vitest.unit.config.ts" + } + }, + "int-test": { + "executor": "@nx/vite:test", + "options": { + "configFile": "{projectRoot}/vitest.int.config.ts" + } + }, "e2e": { "dependsOn": ["^build"] }, diff --git a/packages/ci/code-pushup.config.ts b/packages/ci/code-pushup.config.ts index 25e0c8e51..19912fefa 100644 --- a/packages/ci/code-pushup.config.ts +++ b/packages/ci/code-pushup.config.ts @@ -11,7 +11,7 @@ import { import type { CoreConfig } from '../../packages/models/src/index.js'; import { mergeConfigs } from '../../packages/utils/src/index.js'; -const projectName = process.env.CP_PROJECT_NAME || 'cli'; +const projectName = process.env.NX_TASK_TARGET_PROJECT; const config: CoreConfig = { ...(await loadEnv()), diff --git a/packages/ci/project.json b/packages/ci/project.json index 88d93b963..150b872f1 100644 --- a/packages/ci/project.json +++ b/packages/ci/project.json @@ -4,30 +4,27 @@ "sourceRoot": "packages/ci/src", "projectType": "library", "targets": { - "code-pushup": { - "dependsOn": ["code-pushup-coverage"] - }, - "code-pushup-coverage": { - "dependsOn": ["unit-test", "int-test"] - }, - "code-pushup-eslint": {}, - "code-pushup-js-packages": {}, - "code-pushup-jsdocs": {}, - "code-pushup-typescript": {}, "build": {}, "lint": {}, - "unit-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "packages/ci/vitest.unit.config.ts" - } - }, "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "packages/ci/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts" } - } + }, + "unit-test": {}, + "code-pushup": { + "dependsOn": [ + "code-pushup-coverage", + "code-pushup-jsdocs", + "code-pushup-js-packages", + "code-pushup-typescript" + ] + }, + "code-pushup-coverage": {}, + "code-pushup-jsdocs": {}, + "code-pushup-js-packages": {}, + "code-pushup-typescript": {} }, "tags": ["scope:tooling", "type:feature", "publishable"] } diff --git a/packages/cli/code-pushup.config.ts b/packages/cli/code-pushup.config.ts index 25e0c8e51..19912fefa 100644 --- a/packages/cli/code-pushup.config.ts +++ b/packages/cli/code-pushup.config.ts @@ -11,7 +11,7 @@ import { import type { CoreConfig } from '../../packages/models/src/index.js'; import { mergeConfigs } from '../../packages/utils/src/index.js'; -const projectName = process.env.CP_PROJECT_NAME || 'cli'; +const projectName = process.env.NX_TASK_TARGET_PROJECT; const config: CoreConfig = { ...(await loadEnv()), diff --git a/packages/cli/project.json b/packages/cli/project.json index ac6f2077d..f33990af6 100644 --- a/packages/cli/project.json +++ b/packages/cli/project.json @@ -4,28 +4,13 @@ "sourceRoot": "packages/cli/src", "projectType": "library", "targets": { - "code-pushup": { - "dependsOn": ["code-pushup-coverage"] - }, - "code-pushup-coverage": { - "dependsOn": ["unit-test", "int-test", "e2e-test"] - }, - "code-pushup-eslint": {}, - "code-pushup-js-packages": {}, - "code-pushup-lighthouse": {}, - "code-pushup-typescript": {}, "build": {}, "lint": {}, - "unit-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "packages/cli/vitest.unit.config.ts" - } - }, + "unit-test": {}, "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "packages/cli/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts" } }, "run-help": { @@ -45,7 +30,19 @@ "cwd": "examples/react-todos-app" }, "dependsOn": ["build"] - } + }, + "code-pushup": { + "dependsOn": [ + "code-pushup-coverage", + "code-pushup-jsdocs", + "code-pushup-js-packages", + "code-pushup-typescript" + ] + }, + "code-pushup-coverage": {}, + "code-pushup-jsdocs": {}, + "code-pushup-js-packages": {}, + "code-pushup-typescript": {} }, "tags": ["scope:core", "type:app", "publishable"] } diff --git a/packages/core/code-pushup.config.ts b/packages/core/code-pushup.config.ts index add3f2c0d..8dac3b7d6 100644 --- a/packages/core/code-pushup.config.ts +++ b/packages/core/code-pushup.config.ts @@ -11,7 +11,7 @@ import { import type { CoreConfig } from '../../packages/models/src/index.js'; import { mergeConfigs } from '../../packages/utils/src/index.js'; -const projectName = process.env.CP_PROJECT_NAME || 'core'; +const projectName = process.env.NX_TASK_TARGET_PROJECT; const config: CoreConfig = { ...(await loadEnv()), diff --git a/packages/core/project.json b/packages/core/project.json index 300e2793e..3597956bb 100644 --- a/packages/core/project.json +++ b/packages/core/project.json @@ -4,30 +4,27 @@ "sourceRoot": "packages/core/src", "projectType": "library", "targets": { - "code-pushup": { - "dependsOn": ["code-pushup-coverage"] - }, - "code-pushup-coverage": { - "dependsOn": ["unit-test", "int-test"] - }, - "code-pushup-eslint": {}, - "code-pushup-js-packages": {}, - "code-pushup-lighthouse": {}, - "code-pushup-typescript": {}, "build": {}, "lint": {}, - "unit-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "packages/core/vitest.unit.config.ts" - } - }, + "unit-test": {}, "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "packages/core/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts" } - } + }, + "code-pushup": { + "dependsOn": [ + "code-pushup-coverage", + "code-pushup-jsdocs", + "code-pushup-js-packages", + "code-pushup-typescript" + ] + }, + "code-pushup-coverage": {}, + "code-pushup-jsdocs": {}, + "code-pushup-js-packages": {}, + "code-pushup-typescript": {} }, "tags": ["scope:core", "type:feature", "publishable"] } diff --git a/packages/create-cli/code-pushup.config.ts b/packages/create-cli/code-pushup.config.ts index 6b895dcc7..19912fefa 100644 --- a/packages/create-cli/code-pushup.config.ts +++ b/packages/create-cli/code-pushup.config.ts @@ -11,7 +11,7 @@ import { import type { CoreConfig } from '../../packages/models/src/index.js'; import { mergeConfigs } from '../../packages/utils/src/index.js'; -const projectName = process.env.CP_PROJECT_NAME || 'create-cli'; +const projectName = process.env.NX_TASK_TARGET_PROJECT; const config: CoreConfig = { ...(await loadEnv()), diff --git a/packages/create-cli/project.json b/packages/create-cli/project.json index d3d19e2ad..8e641b679 100644 --- a/packages/create-cli/project.json +++ b/packages/create-cli/project.json @@ -4,40 +4,27 @@ "sourceRoot": "packages/create-cli/src", "projectType": "library", "targets": { - "code-pushup": { - "dependsOn": ["code-pushup-coverage"] - }, - "code-pushup-coverage": { - "dependsOn": ["unit-test", "int-test"] - }, - "code-pushup-eslint": {}, - "code-pushup-js-packages": {}, - "code-pushup-lighthouse": {}, - "code-pushup-typescript": {}, "build": {}, "lint": {}, - "unit-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "packages/create-cli/vitest.unit.config.ts" - } - }, + "unit-test": {}, "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "packages/create-cli/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts" } }, - "exec-node": { - "dependsOn": ["build"], - "command": "node ./dist/packages/create-cli/src/index.js", - "options": {} + "code-pushup": { + "dependsOn": [ + "code-pushup-coverage", + "code-pushup-jsdocs", + "code-pushup-js-packages", + "code-pushup-typescript" + ] }, - "exec-npm": { - "dependsOn": ["^build"], - "command": "npm exec ./dist/packages/create-cli", - "options": {} - } + "code-pushup-coverage": {}, + "code-pushup-jsdocs": {}, + "code-pushup-js-packages": {}, + "code-pushup-typescript": {} }, - "tags": ["scope:tooling", "type:app", "publishable"] + "tags": ["scope:shared", "type:util", "publishable"] } diff --git a/packages/models/code-pushup.config.ts b/packages/models/code-pushup.config.ts index b05a67f89..d2b9780e7 100644 --- a/packages/models/code-pushup.config.ts +++ b/packages/models/code-pushup.config.ts @@ -10,7 +10,7 @@ import { } from '../../code-pushup.preset.js'; import type { CoreConfig } from '../../packages/models/src/index.js'; -const projectName = process.env.CP_PROJECT_NAME || 'models'; +const projectName = process.env.NX_TASK_TARGET_PROJECT; const config: CoreConfig = { ...(await loadEnv()), diff --git a/packages/models/project.json b/packages/models/project.json index d402a89a6..e075ca0b0 100644 --- a/packages/models/project.json +++ b/packages/models/project.json @@ -4,38 +4,40 @@ "sourceRoot": "packages/models/src", "projectType": "library", "targets": { + "code-pushup": { + "dependsOn": [ + "code-pushup-coverage", + "code-pushup-jsdocs", + "code-pushup-js-packages", + "code-pushup-typescript" + ] + }, + "code-pushup-eslint": {}, + "code-pushup-js-packages": {}, + "code-pushup-jsdocs": {}, + "code-pushup-typescript": {}, "generate-docs": { "command": "npx zod2md --config packages/models/zod2md.config.ts", "cache": true, "inputs": ["production", "^production", "{projectRoot}/zod2md.config.ts"], "outputs": ["{projectRoot}/docs/models-reference.md"] }, - "code-pushup": {}, - "code-pushup-coverage": { - "dependsOn": ["unit-test", "int-test"] - }, - "code-pushup-eslint": {}, - "code-pushup-js-packages": {}, - "code-pushup-jsdocs": {}, - "code-pushup-typescript": {}, "build": { "dependsOn": [ "^build", "generate-docs", - { "projects": "models-transformers", "target": "build" } + { + "projects": "models-transformers", + "target": "build" + } ] }, "lint": {}, - "unit-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "packages/models/vitest.unit.config.ts" - } - }, + "unit-test": {}, "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "packages/models/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts" } } }, diff --git a/packages/nx-plugin/code-pushup.config.ts b/packages/nx-plugin/code-pushup.config.ts index 00f01dc6a..19912fefa 100644 --- a/packages/nx-plugin/code-pushup.config.ts +++ b/packages/nx-plugin/code-pushup.config.ts @@ -11,7 +11,7 @@ import { import type { CoreConfig } from '../../packages/models/src/index.js'; import { mergeConfigs } from '../../packages/utils/src/index.js'; -const projectName = process.env.CP_PROJECT_NAME || 'nx-plugin'; +const projectName = process.env.NX_TASK_TARGET_PROJECT; const config: CoreConfig = { ...(await loadEnv()), diff --git a/packages/nx-plugin/project.json b/packages/nx-plugin/project.json index 929fe7fb6..b6f6e5a7c 100644 --- a/packages/nx-plugin/project.json +++ b/packages/nx-plugin/project.json @@ -3,66 +3,28 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "packages/nx-plugin/src", "projectType": "library", - "implicitDependencies": ["cli"], "targets": { - "code-pushup": { - "dependsOn": ["code-pushup-coverage"] - }, - "code-pushup-coverage": { - "dependsOn": ["unit-test", "int-test"] - }, - "code-pushup-eslint": {}, - "code-pushup-js-packages": {}, - "code-pushup-jsdocs": {}, - "code-pushup-typescript": {}, - "build": { - "options": { - "assets": [ - "{projectRoot}/*.md", - { - "input": "./packages/nx-plugin/src", - "glob": "**/!(*.ts)", - "output": "./src" - }, - { - "input": "./packages/nx-plugin/src", - "glob": "**/*.d.ts", - "output": "./src" - }, - { - "input": "./packages/nx-plugin", - "glob": "generators.json", - "output": "." - }, - { - "input": "./packages/nx-plugin", - "glob": "executors.json", - "output": "." - } - ] - } - }, - "lint": { - "options": { - "lintFilePatterns": [ - "packages/nx-plugin/**/*.ts", - "packages/nx-plugin/package.json", - "packages/nx-plugin/generators.json" - ] - } - }, - "unit-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "packages/nx-plugin/vitest.unit.config.ts" - } - }, + "build": {}, + "lint": {}, + "unit-test": {}, "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "packages/nx-plugin/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts" } - } + }, + "code-pushup": { + "dependsOn": [ + "code-pushup-coverage", + "code-pushup-jsdocs", + "code-pushup-js-packages", + "code-pushup-typescript" + ] + }, + "code-pushup-coverage": {}, + "code-pushup-jsdocs": {}, + "code-pushup-js-packages": {}, + "code-pushup-typescript": {} }, "tags": ["scope:tooling", "type:feature", "publishable"] } diff --git a/packages/plugin-coverage/code-pushup.config.ts b/packages/plugin-coverage/code-pushup.config.ts index be7a310c8..19912fefa 100644 --- a/packages/plugin-coverage/code-pushup.config.ts +++ b/packages/plugin-coverage/code-pushup.config.ts @@ -11,7 +11,7 @@ import { import type { CoreConfig } from '../../packages/models/src/index.js'; import { mergeConfigs } from '../../packages/utils/src/index.js'; -const projectName = process.env.CP_PROJECT_NAME || 'plugin-coverage'; +const projectName = process.env.NX_TASK_TARGET_PROJECT; const config: CoreConfig = { ...(await loadEnv()), diff --git a/packages/plugin-coverage/project.json b/packages/plugin-coverage/project.json index 018e8e1a3..c666e33da 100644 --- a/packages/plugin-coverage/project.json +++ b/packages/plugin-coverage/project.json @@ -4,30 +4,27 @@ "sourceRoot": "packages/plugin-coverage/src", "projectType": "library", "targets": { - "code-pushup": { - "dependsOn": ["code-pushup-coverage"] - }, - "code-pushup-coverage": { - "dependsOn": ["unit-test", "int-test"] - }, - "code-pushup-eslint": {}, - "code-pushup-js-packages": {}, - "code-pushup-jsdocs": {}, - "code-pushup-typescript": {}, "build": {}, "lint": {}, - "unit-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "packages/plugin-coverage/vitest.unit.config.ts" - } - }, + "unit-test": {}, "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "packages/plugin-coverage/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts" } - } + }, + "code-pushup": { + "dependsOn": [ + "code-pushup-coverage", + "code-pushup-jsdocs", + "code-pushup-js-packages", + "code-pushup-typescript" + ] + }, + "code-pushup-coverage": {}, + "code-pushup-jsdocs": {}, + "code-pushup-js-packages": {}, + "code-pushup-typescript": {} }, "tags": ["scope:plugin", "type:feature", "publishable"] } diff --git a/packages/plugin-eslint/code-pushup.config.ts b/packages/plugin-eslint/code-pushup.config.ts index a79ca8ad2..19912fefa 100644 --- a/packages/plugin-eslint/code-pushup.config.ts +++ b/packages/plugin-eslint/code-pushup.config.ts @@ -11,7 +11,7 @@ import { import type { CoreConfig } from '../../packages/models/src/index.js'; import { mergeConfigs } from '../../packages/utils/src/index.js'; -const projectName = process.env.CP_PROJECT_NAME || 'plugin-eslint'; +const projectName = process.env.NX_TASK_TARGET_PROJECT; const config: CoreConfig = { ...(await loadEnv()), diff --git a/packages/plugin-eslint/project.json b/packages/plugin-eslint/project.json index 87809c3fb..46c800ad7 100644 --- a/packages/plugin-eslint/project.json +++ b/packages/plugin-eslint/project.json @@ -4,30 +4,27 @@ "sourceRoot": "packages/plugin-eslint/src", "projectType": "library", "targets": { - "code-pushup": { - "dependsOn": ["code-pushup-coverage"] - }, - "code-pushup-coverage": { - "dependsOn": ["unit-test", "int-test"] - }, - "code-pushup-eslint": {}, - "code-pushup-js-packages": {}, - "code-pushup-jsdocs": {}, - "code-pushup-typescript": {}, "build": {}, "lint": {}, - "unit-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "packages/plugin-eslint/vitest.unit.config.ts" - } - }, + "unit-test": {}, "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "packages/plugin-eslint/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts" } - } + }, + "code-pushup": { + "dependsOn": [ + "code-pushup-coverage", + "code-pushup-jsdocs", + "code-pushup-js-packages", + "code-pushup-typescript" + ] + }, + "code-pushup-coverage": {}, + "code-pushup-jsdocs": {}, + "code-pushup-js-packages": {}, + "code-pushup-typescript": {} }, "tags": ["scope:plugin", "type:feature", "publishable"] } diff --git a/packages/plugin-js-packages/code-pushup.config.ts b/packages/plugin-js-packages/code-pushup.config.ts index 642b553aa..19912fefa 100644 --- a/packages/plugin-js-packages/code-pushup.config.ts +++ b/packages/plugin-js-packages/code-pushup.config.ts @@ -11,7 +11,7 @@ import { import type { CoreConfig } from '../../packages/models/src/index.js'; import { mergeConfigs } from '../../packages/utils/src/index.js'; -const projectName = process.env.CP_PROJECT_NAME || 'plugin-js-packages'; +const projectName = process.env.NX_TASK_TARGET_PROJECT; const config: CoreConfig = { ...(await loadEnv()), diff --git a/packages/plugin-js-packages/project.json b/packages/plugin-js-packages/project.json index 7a8ba2e79..0d8b802e3 100644 --- a/packages/plugin-js-packages/project.json +++ b/packages/plugin-js-packages/project.json @@ -4,30 +4,27 @@ "sourceRoot": "packages/plugin-js-packages/src", "projectType": "library", "targets": { - "code-pushup": { - "dependsOn": ["code-pushup-coverage"] - }, - "code-pushup-coverage": { - "dependsOn": ["unit-test", "int-test"] - }, - "code-pushup-eslint": {}, - "code-pushup-js-packages": {}, - "code-pushup-jsdocs": {}, - "code-pushup-typescript": {}, "build": {}, "lint": {}, - "unit-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "packages/plugin-js-packages/vitest.unit.config.ts" - } - }, + "unit-test": {}, "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "packages/plugin-js-packages/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts" } - } + }, + "code-pushup": { + "dependsOn": [ + "code-pushup-coverage", + "code-pushup-jsdocs", + "code-pushup-js-packages", + "code-pushup-typescript" + ] + }, + "code-pushup-coverage": {}, + "code-pushup-jsdocs": {}, + "code-pushup-js-packages": {}, + "code-pushup-typescript": {} }, "tags": ["scope:plugin", "type:feature", "publishable"], "description": "A plugin for JavaScript packages." diff --git a/packages/plugin-jsdocs/code-pushup.config.ts b/packages/plugin-jsdocs/code-pushup.config.ts index b4f872164..19912fefa 100644 --- a/packages/plugin-jsdocs/code-pushup.config.ts +++ b/packages/plugin-jsdocs/code-pushup.config.ts @@ -11,7 +11,7 @@ import { import type { CoreConfig } from '../../packages/models/src/index.js'; import { mergeConfigs } from '../../packages/utils/src/index.js'; -const projectName = process.env.CP_PROJECT_NAME || 'plugin-jsdocs'; +const projectName = process.env.NX_TASK_TARGET_PROJECT; const config: CoreConfig = { ...(await loadEnv()), diff --git a/packages/plugin-jsdocs/project.json b/packages/plugin-jsdocs/project.json index 2be83f65f..515a385f9 100644 --- a/packages/plugin-jsdocs/project.json +++ b/packages/plugin-jsdocs/project.json @@ -3,31 +3,28 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "packages/plugin-jsdocs/src", "projectType": "library", - "tags": ["scope:plugin", "type:feature", "publishable"], "targets": { - "code-pushup": { - "dependsOn": ["code-pushup-coverage"] - }, - "code-pushup-coverage": { - "dependsOn": ["unit-test", "int-test"] - }, - "code-pushup-eslint": {}, - "code-pushup-js-packages": {}, - "code-pushup-jsdocs": {}, - "code-pushup-typescript": {}, "build": {}, "lint": {}, - "unit-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "packages/plugin-jsdocs/vitest.unit.config.ts" - } - }, + "unit-test": {}, "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "packages/plugin-jsdocs/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts" } - } - } + }, + "code-pushup": { + "dependsOn": [ + "code-pushup-coverage", + "code-pushup-jsdocs", + "code-pushup-js-packages", + "code-pushup-typescript" + ] + }, + "code-pushup-coverage": {}, + "code-pushup-jsdocs": {}, + "code-pushup-js-packages": {}, + "code-pushup-typescript": {} + }, + "tags": ["scope:plugin", "type:feature", "publishable"] } diff --git a/packages/plugin-lighthouse/code-pushup.config.ts b/packages/plugin-lighthouse/code-pushup.config.ts index 642b553aa..19912fefa 100644 --- a/packages/plugin-lighthouse/code-pushup.config.ts +++ b/packages/plugin-lighthouse/code-pushup.config.ts @@ -11,7 +11,7 @@ import { import type { CoreConfig } from '../../packages/models/src/index.js'; import { mergeConfigs } from '../../packages/utils/src/index.js'; -const projectName = process.env.CP_PROJECT_NAME || 'plugin-js-packages'; +const projectName = process.env.NX_TASK_TARGET_PROJECT; const config: CoreConfig = { ...(await loadEnv()), diff --git a/packages/plugin-lighthouse/project.json b/packages/plugin-lighthouse/project.json index f9b99b136..91426270c 100644 --- a/packages/plugin-lighthouse/project.json +++ b/packages/plugin-lighthouse/project.json @@ -4,30 +4,27 @@ "sourceRoot": "packages/plugin-lighthouse/src", "projectType": "library", "targets": { - "code-pushup": { - "dependsOn": ["code-pushup-coverage"] - }, - "code-pushup-coverage": { - "dependsOn": ["unit-test", "int-test"] - }, - "code-pushup-eslint": {}, - "code-pushup-js-packages": {}, - "code-pushup-jsdocs": {}, - "code-pushup-typescript": {}, "build": {}, "lint": {}, - "unit-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "packages/plugin-lighthouse/vitest.unit.config.ts" - } - }, + "unit-test": {}, "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "packages/plugin-lighthouse/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts" } - } + }, + "code-pushup": { + "dependsOn": [ + "code-pushup-coverage", + "code-pushup-jsdocs", + "code-pushup-js-packages", + "code-pushup-typescript" + ] + }, + "code-pushup-coverage": {}, + "code-pushup-jsdocs": {}, + "code-pushup-js-packages": {}, + "code-pushup-typescript": {} }, "tags": ["scope:plugin", "type:feature", "publishable"] } diff --git a/packages/plugin-typescript/code-pushup.config.ts b/packages/plugin-typescript/code-pushup.config.ts index 642b553aa..19912fefa 100644 --- a/packages/plugin-typescript/code-pushup.config.ts +++ b/packages/plugin-typescript/code-pushup.config.ts @@ -11,7 +11,7 @@ import { import type { CoreConfig } from '../../packages/models/src/index.js'; import { mergeConfigs } from '../../packages/utils/src/index.js'; -const projectName = process.env.CP_PROJECT_NAME || 'plugin-js-packages'; +const projectName = process.env.NX_TASK_TARGET_PROJECT; const config: CoreConfig = { ...(await loadEnv()), diff --git a/packages/plugin-typescript/project.json b/packages/plugin-typescript/project.json index b6055db8d..50285ecf8 100644 --- a/packages/plugin-typescript/project.json +++ b/packages/plugin-typescript/project.json @@ -4,30 +4,27 @@ "sourceRoot": "packages/plugin-typescript/src", "projectType": "library", "targets": { - "code-pushup": { - "dependsOn": ["code-pushup-coverage"] - }, - "code-pushup-coverage": { - "dependsOn": ["unit-test", "int-test"] - }, - "code-pushup-eslint": {}, - "code-pushup-js-packages": {}, - "code-pushup-jsdocs": {}, - "code-pushup-typescript": {}, "build": {}, "lint": {}, - "unit-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "packages/plugin-typescript/vitest.unit.config.ts" - } - }, + "unit-test": {}, "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "packages/plugin-typescript/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts" } - } + }, + "code-pushup": { + "dependsOn": [ + "code-pushup-coverage", + "code-pushup-jsdocs", + "code-pushup-js-packages", + "code-pushup-typescript" + ] + }, + "code-pushup-coverage": {}, + "code-pushup-jsdocs": {}, + "code-pushup-js-packages": {}, + "code-pushup-typescript": {} }, "tags": ["scope:plugin", "type:feature", "publishable"] } diff --git a/packages/utils/code-pushup.config.ts b/packages/utils/code-pushup.config.ts index b3c514d96..19912fefa 100644 --- a/packages/utils/code-pushup.config.ts +++ b/packages/utils/code-pushup.config.ts @@ -11,7 +11,7 @@ import { import type { CoreConfig } from '../../packages/models/src/index.js'; import { mergeConfigs } from '../../packages/utils/src/index.js'; -const projectName = process.env.CP_PROJECT_NAME || 'utils'; +const projectName = process.env.NX_TASK_TARGET_PROJECT; const config: CoreConfig = { ...(await loadEnv()), diff --git a/packages/utils/project.json b/packages/utils/project.json index 92eb6112f..17384891c 100644 --- a/packages/utils/project.json +++ b/packages/utils/project.json @@ -4,42 +4,27 @@ "sourceRoot": "packages/utils/src", "projectType": "library", "targets": { - "code-pushup": { - "dependsOn": ["code-pushup-coverage"] - }, - "code-pushup-coverage": { - "dependsOn": ["unit-test", "int-test"] - }, - "code-pushup-eslint": {}, - "code-pushup-js-packages": {}, - "code-pushup-jsdocs": {}, - "code-pushup-typescript": {}, "build": {}, "lint": {}, - "perf": { - "command": "npx tsx --tsconfig=../tsconfig.perf.json", - "options": { - "cwd": "./packages/utils/perf" - } - }, - "perf:list": { - "command": "ls -l | grep \"^d\" | awk '{print $9}'", - "options": { - "cwd": "./packages/utils/perf" - } - }, - "unit-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "packages/utils/vitest.unit.config.ts" - } - }, + "unit-test": {}, "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "packages/utils/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts" } - } + }, + "code-pushup": { + "dependsOn": [ + "code-pushup-coverage", + "code-pushup-jsdocs", + "code-pushup-js-packages", + "code-pushup-typescript" + ] + }, + "code-pushup-coverage": {}, + "code-pushup-jsdocs": {}, + "code-pushup-js-packages": {}, + "code-pushup-typescript": {} }, "tags": ["scope:shared", "type:util", "publishable"] } diff --git a/project.json b/project.json index 4fd01156a..c70768052 100644 --- a/project.json +++ b/project.json @@ -3,20 +3,24 @@ "$schema": "node_modules/nx/schemas/project-schema.json", "targets": { "code-pushup": { + "dependsOn": ["code-pushup-js-packages", "code-pushup-lighthouse"], "executor": "nx:run-commands", "options": { - "command": "node packages/cli/src/index.ts", "args": [ "--no-progress", "--verbose", "--config={projectRoot}/code-pushup.config.ts", "--cache.read", - "--persist.outputDir={projectRoot}/.code-pushup", - "--upload.project=cli" + "--persist.outputDir={projectRoot}/.code-pushup" ] } }, - - "code-pushup-lighthouse": {} + "code-pushup-js-packages": {}, + "code-pushup-lighthouse": {}, + "nx-cache-epoch": { + "cache": true, + "inputs": [{ "runtime": "echo $(($(date +%s) / 6))" }], + "command": "bash -c 'date && sleep 2'" + } } } diff --git a/testing/test-nx-utils/code-pushup.config.ts b/testing/test-nx-utils/code-pushup.config.ts deleted file mode 100644 index 631a58b5f..000000000 --- a/testing/test-nx-utils/code-pushup.config.ts +++ /dev/null @@ -1,31 +0,0 @@ -import 'dotenv/config'; -import { - coverageCoreConfigNx, - eslintCoreConfigNx, - jsDocsCoreConfig, - jsDocsExclusionPatterns, - jsPackagesCoreConfig, - loadEnv, - typescriptPluginConfig, -} from '../../code-pushup.preset.js'; -import type { CoreConfig } from '../../packages/models/src/index.js'; -import { mergeConfigs } from '../../packages/utils/src/index.js'; - -const projectName = process.env.CP_PROJECT_NAME || 'test-nx-utils'; - -const config: CoreConfig = { - ...(await loadEnv()), - plugins: [], -}; - -export default mergeConfigs( - config, - await eslintCoreConfigNx(projectName), - await typescriptPluginConfig({ - tsconfig: `testing/${projectName}/tsconfig.lib.json`, - }), - jsDocsCoreConfig([ - `testing/${projectName}/src/**/*.ts`, - ...jsDocsExclusionPatterns, - ]), -); diff --git a/testing/test-nx-utils/project.json b/testing/test-nx-utils/project.json index ca3eb586c..5aad9c4f0 100644 --- a/testing/test-nx-utils/project.json +++ b/testing/test-nx-utils/project.json @@ -4,24 +4,7 @@ "sourceRoot": "testing/test-nx-utils/src", "projectType": "library", "targets": { - "code-pushup": { - "dependsOn": [ - "code-pushup-coverage", - "code-pushup-eslint", - "code-pushup-typescript" - ] - }, - "code-pushup-coverage": {}, - "code-pushup-eslint": {}, - "code-pushup-typescript": {}, - "build": {}, - "lint": {}, - "unit-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "testing/test-nx-utils/vitest.unit.config.ts" - } - } + "unit-test": {} }, "tags": ["scope:shared", "type:testing"] } diff --git a/testing/test-setup/code-pushup.config.ts b/testing/test-setup/code-pushup.config.ts deleted file mode 100644 index 4c29d6754..000000000 --- a/testing/test-setup/code-pushup.config.ts +++ /dev/null @@ -1,31 +0,0 @@ -import 'dotenv/config'; -import { - coverageCoreConfigNx, - eslintCoreConfigNx, - jsDocsCoreConfig, - jsDocsExclusionPatterns, - jsPackagesCoreConfig, - loadEnv, - typescriptPluginConfig, -} from '../../code-pushup.preset.js'; -import type { CoreConfig } from '../../packages/models/src/index.js'; -import { mergeConfigs } from '../../packages/utils/src/index.js'; - -const projectName = process.env.CP_PROJECT_NAME || 'test-setup'; - -const config: CoreConfig = { - ...(await loadEnv()), - plugins: [], -}; - -export default mergeConfigs( - config, - await eslintCoreConfigNx(projectName), - await typescriptPluginConfig({ - tsconfig: `testing/${projectName}/tsconfig.lib.json`, - }), - jsDocsCoreConfig([ - `testing/${projectName}/src/**/*.ts`, - ...jsDocsExclusionPatterns, - ]), -); diff --git a/testing/test-setup/project.json b/testing/test-setup/project.json index 31990d367..69a55091e 100644 --- a/testing/test-setup/project.json +++ b/testing/test-setup/project.json @@ -3,25 +3,7 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "testing/test-setup/src", "projectType": "library", - "targets": { - "code-pushup": { - "dependsOn": [ - "code-pushup-coverage", - "code-pushup-eslint", - "code-pushup-typescript" - ] - }, - "code-pushup-coverage": {}, - "code-pushup-eslint": {}, - "code-pushup-typescript": {}, - "build": {}, - "lint": {}, - "unit-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "testing/test-setup/vitest.unit.config.ts" - } - } - }, + "targets": {}, + "unit-test": {}, "tags": ["scope:shared", "type:testing"] } diff --git a/testing/test-utils/code-pushup.config.ts b/testing/test-utils/code-pushup.config.ts deleted file mode 100644 index bcfa93811..000000000 --- a/testing/test-utils/code-pushup.config.ts +++ /dev/null @@ -1,31 +0,0 @@ -import 'dotenv/config'; -import { - coverageCoreConfigNx, - eslintCoreConfigNx, - jsDocsCoreConfig, - jsDocsExclusionPatterns, - jsPackagesCoreConfig, - loadEnv, - typescriptPluginConfig, -} from '../../code-pushup.preset.js'; -import type { CoreConfig } from '../../packages/models/src/index.js'; -import { mergeConfigs } from '../../packages/utils/src/index.js'; - -const projectName = process.env.CP_PROJECT_NAME || 'test-utils'; - -const config: CoreConfig = { - ...(await loadEnv()), - plugins: [], -}; - -export default mergeConfigs( - config, - await eslintCoreConfigNx(projectName), - await typescriptPluginConfig({ - tsconfig: `testing/${projectName}/tsconfig.lib.json`, - }), - jsDocsCoreConfig([ - `testing/${projectName}/src/**/*.ts`, - ...jsDocsExclusionPatterns, - ]), -); diff --git a/testing/test-utils/project.json b/testing/test-utils/project.json index 1479b13ed..f77ae7728 100644 --- a/testing/test-utils/project.json +++ b/testing/test-utils/project.json @@ -4,24 +4,7 @@ "sourceRoot": "testing/test-utils/src", "projectType": "library", "targets": { - "code-pushup": { - "dependsOn": [ - "code-pushup-coverage", - "code-pushup-eslint", - "code-pushup-typescript" - ] - }, - "code-pushup-coverage": {}, - "code-pushup-eslint": {}, - "code-pushup-typescript": {}, - "build": {}, - "lint": {}, - "unit-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "testing/test-utils/vitest.unit.config.ts" - } - }, + "unit-test": {}, "nx-release-publish": { "executor": "nx:noop" } From 650d300e37c7b08b9e8b3c7a252087962f33b8e6 Mon Sep 17 00:00:00 2001 From: John Doe Date: Tue, 12 Aug 2025 22:31:03 +0200 Subject: [PATCH 023/111] fix: fix lint issues --- code-pushup.config.ts | 2 +- code-pushup.preset.ts | 148 ++++++++++++++++++ eslint.config.js | 2 + examples/plugins/tsconfig.lib.json | 3 +- packages/ci/tsconfig.lib.json | 3 +- packages/ci/tsconfig.tools.json | 8 + packages/cli/code-pushup.config.ts | 2 +- packages/cli/tsconfig.lib.json | 3 +- packages/cli/tsconfig.tools.json | 8 + packages/core/code-pushup.config.ts | 33 ---- packages/core/tsconfig.json | 3 + packages/core/tsconfig.lib.json | 3 +- packages/core/tsconfig.tools.json | 8 + packages/create-cli/tsconfig.lib.json | 3 +- packages/create-cli/tsconfig.tools.json | 8 + packages/models/code-pushup.config.ts | 16 +- packages/models/tsconfig.tools.json | 6 +- packages/nx-plugin/tsconfig.lib.json | 3 +- packages/nx-plugin/tsconfig.tools.json | 8 + .../plugin-coverage/code-pushup.config.ts | 2 +- packages/plugin-coverage/tsconfig.lib.json | 3 +- packages/plugin-coverage/tsconfig.tools.json | 8 + packages/plugin-eslint/code-pushup.config.ts | 2 +- packages/plugin-eslint/tsconfig.lib.json | 3 +- packages/plugin-eslint/tsconfig.tools.json | 8 + .../plugin-js-packages/code-pushup.config.ts | 2 +- packages/plugin-js-packages/tsconfig.lib.json | 3 +- .../plugin-js-packages/tsconfig.tools.json | 8 + packages/plugin-jsdocs/tsconfig.lib.json | 3 +- packages/plugin-jsdocs/tsconfig.tools.json | 8 + .../plugin-lighthouse/code-pushup.config.ts | 2 +- packages/plugin-lighthouse/tsconfig.lib.json | 3 +- .../plugin-lighthouse/tsconfig.tools.json | 8 + .../plugin-typescript/code-pushup.config.ts | 2 +- packages/plugin-typescript/tsconfig.lib.json | 3 +- .../plugin-typescript/tsconfig.tools.json | 8 + packages/utils/code-pushup.config.ts | 2 +- packages/utils/tsconfig.lib.json | 3 +- packages/utils/tsconfig.tools.json | 8 + project.json | 7 +- .../lib/fixtures/configs/tsconfig.tools.json | 8 + tsconfig.tools.json | 8 + 42 files changed, 308 insertions(+), 74 deletions(-) create mode 100644 packages/ci/tsconfig.tools.json create mode 100644 packages/cli/tsconfig.tools.json create mode 100644 packages/core/tsconfig.tools.json create mode 100644 packages/create-cli/tsconfig.tools.json create mode 100644 packages/nx-plugin/tsconfig.tools.json create mode 100644 packages/plugin-coverage/tsconfig.tools.json create mode 100644 packages/plugin-eslint/tsconfig.tools.json create mode 100644 packages/plugin-js-packages/tsconfig.tools.json create mode 100644 packages/plugin-jsdocs/tsconfig.tools.json create mode 100644 packages/plugin-lighthouse/tsconfig.tools.json create mode 100644 packages/plugin-typescript/tsconfig.tools.json create mode 100644 packages/utils/tsconfig.tools.json create mode 100644 testing/test-utils/src/lib/fixtures/configs/tsconfig.tools.json create mode 100644 tsconfig.tools.json diff --git a/code-pushup.config.ts b/code-pushup.config.ts index 08fd11946..78559dab5 100644 --- a/code-pushup.config.ts +++ b/code-pushup.config.ts @@ -3,9 +3,9 @@ import { jsPackagesCoreConfig, lighthouseCoreConfig, loadEnv, + mergeConfigs, } from './code-pushup.preset.js'; import type { CoreConfig } from './packages/models/src/index.js'; -import { mergeConfigs } from './packages/utils/src/index.js'; const projectName = 'cli'; diff --git a/code-pushup.preset.ts b/code-pushup.preset.ts index d184179ba..e0d6ab2bc 100644 --- a/code-pushup.preset.ts +++ b/code-pushup.preset.ts @@ -4,6 +4,9 @@ import { z } from 'zod'; import type { CategoryConfig, CoreConfig, + PersistConfig, + PluginConfig, + UploadConfig, } from './packages/models/src/index.js'; import coveragePlugin, { getNxCoveragePaths, @@ -265,3 +268,148 @@ export const coverageCoreConfigNx = async ( categories: coverageCategories, }; }; + +export function mergeConfigs( + config: CoreConfig, + ...configs: Partial[] +): CoreConfig { + return configs.reduce( + (acc, obj) => ({ + ...acc, + ...mergeCategories(acc.categories, obj.categories), + ...mergePlugins(acc.plugins, obj.plugins), + ...mergePersist(acc.persist, obj.persist), + ...mergeUpload(acc.upload, obj.upload), + }), + config, + ); +} + +function mergeCategories( + a: CategoryConfig[] | undefined, + b: CategoryConfig[] | undefined, +): Pick { + if (!a && !b) { + return {}; + } + + const mergedMap = new Map(); + + const addToMap = (categories: CategoryConfig[]) => { + categories.forEach(newObject => { + if (mergedMap.has(newObject.slug)) { + const existingObject: CategoryConfig | undefined = mergedMap.get( + newObject.slug, + ); + + mergedMap.set(newObject.slug, { + ...existingObject, + ...newObject, + + refs: mergeByUniqueCategoryRefCombination( + existingObject?.refs, + newObject.refs, + ), + }); + } else { + mergedMap.set(newObject.slug, newObject); + } + }); + }; + + if (a) { + addToMap(a); + } + if (b) { + addToMap(b); + } + + // Convert the map back to an array + return { categories: [...mergedMap.values()] }; +} + +function mergePlugins( + a: PluginConfig[] | undefined, + b: PluginConfig[] | undefined, +): Pick { + if (!a && !b) { + return { plugins: [] }; + } + + const mergedMap = new Map(); + + const addToMap = (plugins: PluginConfig[]) => { + plugins.forEach(newObject => { + mergedMap.set(newObject.slug, newObject); + }); + }; + + if (a) { + addToMap(a); + } + if (b) { + addToMap(b); + } + + return { plugins: [...mergedMap.values()] }; +} + +function mergePersist( + a: PersistConfig | undefined, + b: PersistConfig | undefined, +): Pick { + if (!a && !b) { + return {}; + } + + if (a) { + return b ? { persist: { ...a, ...b } } : {}; + } else { + return { persist: b }; + } +} + +function mergeByUniqueCategoryRefCombination< + T extends { slug: string; type: string; plugin: string }, +>(a: T[] | undefined, b: T[] | undefined) { + const map = new Map(); + + const addToMap = (refs: T[]) => { + refs.forEach(ref => { + const uniqueIdentification = `${ref.type}:${ref.plugin}:${ref.slug}`; + if (map.has(uniqueIdentification)) { + map.set(uniqueIdentification, { + ...map.get(uniqueIdentification), + ...ref, + }); + } else { + map.set(uniqueIdentification, ref); + } + }); + }; + + // Add objects from both arrays to the map + if (a) { + addToMap(a); + } + if (b) { + addToMap(b); + } + + return [...map.values()]; +} + +function mergeUpload( + a: UploadConfig | undefined, + b: UploadConfig | undefined, +): Pick { + if (!a && !b) { + return {}; + } + + if (a) { + return b ? { upload: { ...a, ...b } } : {}; + } else { + return { upload: b }; + } +} diff --git a/eslint.config.js b/eslint.config.js index 5830ca0f7..456cfea4f 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -27,6 +27,8 @@ export default tseslint.config( String.raw`^.*/eslint(\.base)?\.config\.[cm]?js$`, String.raw`^.*/code-pushup\.(config|preset)(\.m?[jt]s)?$`, '^[./]+/tools/.*$', + '^@code-pushup/test-utils(|/.*)$', + '^@code-pushup/test-nx-utils(|/.*)$', ], depConstraints: [ { diff --git a/examples/plugins/tsconfig.lib.json b/examples/plugins/tsconfig.lib.json index 76a3dbec1..8f9e8a92a 100644 --- a/examples/plugins/tsconfig.lib.json +++ b/examples/plugins/tsconfig.lib.json @@ -11,6 +11,7 @@ "vitest.int.config.ts", "src/**/*.test.ts", "src/**/*.mock.ts", - "mocks/**/*.ts" + "mocks/**/*.ts", + "code-pushup.config.ts" ] } diff --git a/packages/ci/tsconfig.lib.json b/packages/ci/tsconfig.lib.json index 76a3dbec1..8f9e8a92a 100644 --- a/packages/ci/tsconfig.lib.json +++ b/packages/ci/tsconfig.lib.json @@ -11,6 +11,7 @@ "vitest.int.config.ts", "src/**/*.test.ts", "src/**/*.mock.ts", - "mocks/**/*.ts" + "mocks/**/*.ts", + "code-pushup.config.ts" ] } diff --git a/packages/ci/tsconfig.tools.json b/packages/ci/tsconfig.tools.json new file mode 100644 index 000000000..8fd1f320d --- /dev/null +++ b/packages/ci/tsconfig.tools.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc-tools", + "types": ["node"] + }, + "include": ["code-pushup.config.ts"] +} diff --git a/packages/cli/code-pushup.config.ts b/packages/cli/code-pushup.config.ts index 19912fefa..c2fbffb1c 100644 --- a/packages/cli/code-pushup.config.ts +++ b/packages/cli/code-pushup.config.ts @@ -6,10 +6,10 @@ import { jsDocsExclusionPatterns, jsPackagesCoreConfig, loadEnv, + mergeConfigs, typescriptPluginConfig, } from '../../code-pushup.preset.js'; import type { CoreConfig } from '../../packages/models/src/index.js'; -import { mergeConfigs } from '../../packages/utils/src/index.js'; const projectName = process.env.NX_TASK_TARGET_PROJECT; diff --git a/packages/cli/tsconfig.lib.json b/packages/cli/tsconfig.lib.json index 76a3dbec1..8f9e8a92a 100644 --- a/packages/cli/tsconfig.lib.json +++ b/packages/cli/tsconfig.lib.json @@ -11,6 +11,7 @@ "vitest.int.config.ts", "src/**/*.test.ts", "src/**/*.mock.ts", - "mocks/**/*.ts" + "mocks/**/*.ts", + "code-pushup.config.ts" ] } diff --git a/packages/cli/tsconfig.tools.json b/packages/cli/tsconfig.tools.json new file mode 100644 index 000000000..8fd1f320d --- /dev/null +++ b/packages/cli/tsconfig.tools.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc-tools", + "types": ["node"] + }, + "include": ["code-pushup.config.ts"] +} diff --git a/packages/core/code-pushup.config.ts b/packages/core/code-pushup.config.ts index 8dac3b7d6..e69de29bb 100644 --- a/packages/core/code-pushup.config.ts +++ b/packages/core/code-pushup.config.ts @@ -1,33 +0,0 @@ -import 'dotenv/config'; -import { - coverageCoreConfigNx, - eslintCoreConfigNx, - jsDocsCoreConfig, - jsDocsExclusionPatterns, - jsPackagesCoreConfig, - loadEnv, - typescriptPluginConfig, -} from '../../code-pushup.preset.js'; -import type { CoreConfig } from '../../packages/models/src/index.js'; -import { mergeConfigs } from '../../packages/utils/src/index.js'; - -const projectName = process.env.NX_TASK_TARGET_PROJECT; - -const config: CoreConfig = { - ...(await loadEnv()), - plugins: [], -}; - -export default mergeConfigs( - config, - await coverageCoreConfigNx(projectName), - await jsPackagesCoreConfig('package.json'), // Use workspace root package.json - await typescriptPluginConfig({ - tsconfig: `packages/${projectName}/tsconfig.lib.json`, - }), - await eslintCoreConfigNx(projectName), - jsDocsCoreConfig([ - `packages/${projectName}/src/**/*.ts`, - ...jsDocsExclusionPatterns, - ]), -); diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json index 893f9a925..042f549ac 100644 --- a/packages/core/tsconfig.json +++ b/packages/core/tsconfig.json @@ -18,6 +18,9 @@ }, { "path": "./tsconfig.test.json" + }, + { + "path": "./tsconfig.tools.json" } ] } diff --git a/packages/core/tsconfig.lib.json b/packages/core/tsconfig.lib.json index 76a3dbec1..8f9e8a92a 100644 --- a/packages/core/tsconfig.lib.json +++ b/packages/core/tsconfig.lib.json @@ -11,6 +11,7 @@ "vitest.int.config.ts", "src/**/*.test.ts", "src/**/*.mock.ts", - "mocks/**/*.ts" + "mocks/**/*.ts", + "code-pushup.config.ts" ] } diff --git a/packages/core/tsconfig.tools.json b/packages/core/tsconfig.tools.json new file mode 100644 index 000000000..8fd1f320d --- /dev/null +++ b/packages/core/tsconfig.tools.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc-tools", + "types": ["node"] + }, + "include": ["code-pushup.config.ts"] +} diff --git a/packages/create-cli/tsconfig.lib.json b/packages/create-cli/tsconfig.lib.json index d96298230..c38419f5e 100644 --- a/packages/create-cli/tsconfig.lib.json +++ b/packages/create-cli/tsconfig.lib.json @@ -10,6 +10,7 @@ "vitest.unit.config.ts", "vitest.int.config.ts", "src/**/*.test.ts", - "test/**/*.ts" + "test/**/*.ts", + "code-pushup.config.ts" ] } diff --git a/packages/create-cli/tsconfig.tools.json b/packages/create-cli/tsconfig.tools.json new file mode 100644 index 000000000..8fd1f320d --- /dev/null +++ b/packages/create-cli/tsconfig.tools.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc-tools", + "types": ["node"] + }, + "include": ["code-pushup.config.ts"] +} diff --git a/packages/models/code-pushup.config.ts b/packages/models/code-pushup.config.ts index d2b9780e7..0c7853be6 100644 --- a/packages/models/code-pushup.config.ts +++ b/packages/models/code-pushup.config.ts @@ -6,6 +6,7 @@ import { jsDocsExclusionPatterns, jsPackagesCoreConfig, loadEnv, + mergeConfigs, typescriptPluginConfig, } from '../../code-pushup.preset.js'; import type { CoreConfig } from '../../packages/models/src/index.js'; @@ -18,7 +19,8 @@ const config: CoreConfig = { }; // This part should use mergeConfig in a normal setup, but here we are manually merging to avoid circular dependencies -export default [ +export default mergeConfigs( + config, await eslintCoreConfigNx(projectName), await coverageCoreConfigNx(projectName), await jsPackagesCoreConfig('package.json'), // Use workspace root package.json @@ -26,15 +28,7 @@ export default [ tsconfig: `packages/${projectName}/tsconfig.lib.json`, }), jsDocsCoreConfig([ - `packages/${projectName}/src/**\/*.ts`, + `packages/${projectName}/src/**/*.ts`, ...jsDocsExclusionPatterns, ]), -].reduce((acc, curr) => { - curr.plugins.forEach(plugin => { - acc.plugins.push(plugin); - }); - curr.categories?.forEach(category => { - acc.categories?.push(category); - }); - return acc; -}, config); +); diff --git a/packages/models/tsconfig.tools.json b/packages/models/tsconfig.tools.json index 4a9dfeae3..8fd1f320d 100644 --- a/packages/models/tsconfig.tools.json +++ b/packages/models/tsconfig.tools.json @@ -1,8 +1,8 @@ { "extends": "./tsconfig.json", "compilerOptions": { - "outDir": "../../dist/out-tsc", - "types": ["nodenext"] + "outDir": "../../dist/out-tsc-tools", + "types": ["node"] }, - "include": ["zod2md.config.ts", "code-pushup.config.ts"] + "include": ["code-pushup.config.ts"] } diff --git a/packages/nx-plugin/tsconfig.lib.json b/packages/nx-plugin/tsconfig.lib.json index 71aabc78b..20ece2831 100644 --- a/packages/nx-plugin/tsconfig.lib.json +++ b/packages/nx-plugin/tsconfig.lib.json @@ -12,6 +12,7 @@ "src/**/__snapshots__/*.ts", "src/**/*.test.ts", "src/**/*.mock.ts", - "test/**/*.ts" + "test/**/*.ts", + "code-pushup.config.ts" ] } diff --git a/packages/nx-plugin/tsconfig.tools.json b/packages/nx-plugin/tsconfig.tools.json new file mode 100644 index 000000000..8fd1f320d --- /dev/null +++ b/packages/nx-plugin/tsconfig.tools.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc-tools", + "types": ["node"] + }, + "include": ["code-pushup.config.ts"] +} diff --git a/packages/plugin-coverage/code-pushup.config.ts b/packages/plugin-coverage/code-pushup.config.ts index 19912fefa..c2fbffb1c 100644 --- a/packages/plugin-coverage/code-pushup.config.ts +++ b/packages/plugin-coverage/code-pushup.config.ts @@ -6,10 +6,10 @@ import { jsDocsExclusionPatterns, jsPackagesCoreConfig, loadEnv, + mergeConfigs, typescriptPluginConfig, } from '../../code-pushup.preset.js'; import type { CoreConfig } from '../../packages/models/src/index.js'; -import { mergeConfigs } from '../../packages/utils/src/index.js'; const projectName = process.env.NX_TASK_TARGET_PROJECT; diff --git a/packages/plugin-coverage/tsconfig.lib.json b/packages/plugin-coverage/tsconfig.lib.json index 76a3dbec1..8f9e8a92a 100644 --- a/packages/plugin-coverage/tsconfig.lib.json +++ b/packages/plugin-coverage/tsconfig.lib.json @@ -11,6 +11,7 @@ "vitest.int.config.ts", "src/**/*.test.ts", "src/**/*.mock.ts", - "mocks/**/*.ts" + "mocks/**/*.ts", + "code-pushup.config.ts" ] } diff --git a/packages/plugin-coverage/tsconfig.tools.json b/packages/plugin-coverage/tsconfig.tools.json new file mode 100644 index 000000000..8fd1f320d --- /dev/null +++ b/packages/plugin-coverage/tsconfig.tools.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc-tools", + "types": ["node"] + }, + "include": ["code-pushup.config.ts"] +} diff --git a/packages/plugin-eslint/code-pushup.config.ts b/packages/plugin-eslint/code-pushup.config.ts index 19912fefa..c2fbffb1c 100644 --- a/packages/plugin-eslint/code-pushup.config.ts +++ b/packages/plugin-eslint/code-pushup.config.ts @@ -6,10 +6,10 @@ import { jsDocsExclusionPatterns, jsPackagesCoreConfig, loadEnv, + mergeConfigs, typescriptPluginConfig, } from '../../code-pushup.preset.js'; import type { CoreConfig } from '../../packages/models/src/index.js'; -import { mergeConfigs } from '../../packages/utils/src/index.js'; const projectName = process.env.NX_TASK_TARGET_PROJECT; diff --git a/packages/plugin-eslint/tsconfig.lib.json b/packages/plugin-eslint/tsconfig.lib.json index 76a3dbec1..8f9e8a92a 100644 --- a/packages/plugin-eslint/tsconfig.lib.json +++ b/packages/plugin-eslint/tsconfig.lib.json @@ -11,6 +11,7 @@ "vitest.int.config.ts", "src/**/*.test.ts", "src/**/*.mock.ts", - "mocks/**/*.ts" + "mocks/**/*.ts", + "code-pushup.config.ts" ] } diff --git a/packages/plugin-eslint/tsconfig.tools.json b/packages/plugin-eslint/tsconfig.tools.json new file mode 100644 index 000000000..8fd1f320d --- /dev/null +++ b/packages/plugin-eslint/tsconfig.tools.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc-tools", + "types": ["node"] + }, + "include": ["code-pushup.config.ts"] +} diff --git a/packages/plugin-js-packages/code-pushup.config.ts b/packages/plugin-js-packages/code-pushup.config.ts index 19912fefa..c2fbffb1c 100644 --- a/packages/plugin-js-packages/code-pushup.config.ts +++ b/packages/plugin-js-packages/code-pushup.config.ts @@ -6,10 +6,10 @@ import { jsDocsExclusionPatterns, jsPackagesCoreConfig, loadEnv, + mergeConfigs, typescriptPluginConfig, } from '../../code-pushup.preset.js'; import type { CoreConfig } from '../../packages/models/src/index.js'; -import { mergeConfigs } from '../../packages/utils/src/index.js'; const projectName = process.env.NX_TASK_TARGET_PROJECT; diff --git a/packages/plugin-js-packages/tsconfig.lib.json b/packages/plugin-js-packages/tsconfig.lib.json index 76a3dbec1..8f9e8a92a 100644 --- a/packages/plugin-js-packages/tsconfig.lib.json +++ b/packages/plugin-js-packages/tsconfig.lib.json @@ -11,6 +11,7 @@ "vitest.int.config.ts", "src/**/*.test.ts", "src/**/*.mock.ts", - "mocks/**/*.ts" + "mocks/**/*.ts", + "code-pushup.config.ts" ] } diff --git a/packages/plugin-js-packages/tsconfig.tools.json b/packages/plugin-js-packages/tsconfig.tools.json new file mode 100644 index 000000000..8fd1f320d --- /dev/null +++ b/packages/plugin-js-packages/tsconfig.tools.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc-tools", + "types": ["node"] + }, + "include": ["code-pushup.config.ts"] +} diff --git a/packages/plugin-jsdocs/tsconfig.lib.json b/packages/plugin-jsdocs/tsconfig.lib.json index 76a3dbec1..8f9e8a92a 100644 --- a/packages/plugin-jsdocs/tsconfig.lib.json +++ b/packages/plugin-jsdocs/tsconfig.lib.json @@ -11,6 +11,7 @@ "vitest.int.config.ts", "src/**/*.test.ts", "src/**/*.mock.ts", - "mocks/**/*.ts" + "mocks/**/*.ts", + "code-pushup.config.ts" ] } diff --git a/packages/plugin-jsdocs/tsconfig.tools.json b/packages/plugin-jsdocs/tsconfig.tools.json new file mode 100644 index 000000000..8fd1f320d --- /dev/null +++ b/packages/plugin-jsdocs/tsconfig.tools.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc-tools", + "types": ["node"] + }, + "include": ["code-pushup.config.ts"] +} diff --git a/packages/plugin-lighthouse/code-pushup.config.ts b/packages/plugin-lighthouse/code-pushup.config.ts index 19912fefa..c2fbffb1c 100644 --- a/packages/plugin-lighthouse/code-pushup.config.ts +++ b/packages/plugin-lighthouse/code-pushup.config.ts @@ -6,10 +6,10 @@ import { jsDocsExclusionPatterns, jsPackagesCoreConfig, loadEnv, + mergeConfigs, typescriptPluginConfig, } from '../../code-pushup.preset.js'; import type { CoreConfig } from '../../packages/models/src/index.js'; -import { mergeConfigs } from '../../packages/utils/src/index.js'; const projectName = process.env.NX_TASK_TARGET_PROJECT; diff --git a/packages/plugin-lighthouse/tsconfig.lib.json b/packages/plugin-lighthouse/tsconfig.lib.json index 76a3dbec1..8f9e8a92a 100644 --- a/packages/plugin-lighthouse/tsconfig.lib.json +++ b/packages/plugin-lighthouse/tsconfig.lib.json @@ -11,6 +11,7 @@ "vitest.int.config.ts", "src/**/*.test.ts", "src/**/*.mock.ts", - "mocks/**/*.ts" + "mocks/**/*.ts", + "code-pushup.config.ts" ] } diff --git a/packages/plugin-lighthouse/tsconfig.tools.json b/packages/plugin-lighthouse/tsconfig.tools.json new file mode 100644 index 000000000..8fd1f320d --- /dev/null +++ b/packages/plugin-lighthouse/tsconfig.tools.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc-tools", + "types": ["node"] + }, + "include": ["code-pushup.config.ts"] +} diff --git a/packages/plugin-typescript/code-pushup.config.ts b/packages/plugin-typescript/code-pushup.config.ts index 19912fefa..c2fbffb1c 100644 --- a/packages/plugin-typescript/code-pushup.config.ts +++ b/packages/plugin-typescript/code-pushup.config.ts @@ -6,10 +6,10 @@ import { jsDocsExclusionPatterns, jsPackagesCoreConfig, loadEnv, + mergeConfigs, typescriptPluginConfig, } from '../../code-pushup.preset.js'; import type { CoreConfig } from '../../packages/models/src/index.js'; -import { mergeConfigs } from '../../packages/utils/src/index.js'; const projectName = process.env.NX_TASK_TARGET_PROJECT; diff --git a/packages/plugin-typescript/tsconfig.lib.json b/packages/plugin-typescript/tsconfig.lib.json index 76a3dbec1..8f9e8a92a 100644 --- a/packages/plugin-typescript/tsconfig.lib.json +++ b/packages/plugin-typescript/tsconfig.lib.json @@ -11,6 +11,7 @@ "vitest.int.config.ts", "src/**/*.test.ts", "src/**/*.mock.ts", - "mocks/**/*.ts" + "mocks/**/*.ts", + "code-pushup.config.ts" ] } diff --git a/packages/plugin-typescript/tsconfig.tools.json b/packages/plugin-typescript/tsconfig.tools.json new file mode 100644 index 000000000..8fd1f320d --- /dev/null +++ b/packages/plugin-typescript/tsconfig.tools.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc-tools", + "types": ["node"] + }, + "include": ["code-pushup.config.ts"] +} diff --git a/packages/utils/code-pushup.config.ts b/packages/utils/code-pushup.config.ts index 19912fefa..c2fbffb1c 100644 --- a/packages/utils/code-pushup.config.ts +++ b/packages/utils/code-pushup.config.ts @@ -6,10 +6,10 @@ import { jsDocsExclusionPatterns, jsPackagesCoreConfig, loadEnv, + mergeConfigs, typescriptPluginConfig, } from '../../code-pushup.preset.js'; import type { CoreConfig } from '../../packages/models/src/index.js'; -import { mergeConfigs } from '../../packages/utils/src/index.js'; const projectName = process.env.NX_TASK_TARGET_PROJECT; diff --git a/packages/utils/tsconfig.lib.json b/packages/utils/tsconfig.lib.json index 17dadcedf..0ac87fe0b 100644 --- a/packages/utils/tsconfig.lib.json +++ b/packages/utils/tsconfig.lib.json @@ -12,6 +12,7 @@ "src/**/*.test.ts", "src/**/*.mock.ts", "mocks/**/*.ts", - "perf/**/*.ts" + "perf/**/*.ts", + "code-pushup.config.ts" ] } diff --git a/packages/utils/tsconfig.tools.json b/packages/utils/tsconfig.tools.json new file mode 100644 index 000000000..8fd1f320d --- /dev/null +++ b/packages/utils/tsconfig.tools.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc-tools", + "types": ["node"] + }, + "include": ["code-pushup.config.ts"] +} diff --git a/project.json b/project.json index c70768052..a1f347ba6 100644 --- a/project.json +++ b/project.json @@ -16,11 +16,6 @@ } }, "code-pushup-js-packages": {}, - "code-pushup-lighthouse": {}, - "nx-cache-epoch": { - "cache": true, - "inputs": [{ "runtime": "echo $(($(date +%s) / 6))" }], - "command": "bash -c 'date && sleep 2'" - } + "code-pushup-lighthouse": {} } } diff --git a/testing/test-utils/src/lib/fixtures/configs/tsconfig.tools.json b/testing/test-utils/src/lib/fixtures/configs/tsconfig.tools.json new file mode 100644 index 000000000..8fd1f320d --- /dev/null +++ b/testing/test-utils/src/lib/fixtures/configs/tsconfig.tools.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc-tools", + "types": ["node"] + }, + "include": ["code-pushup.config.ts"] +} diff --git a/tsconfig.tools.json b/tsconfig.tools.json new file mode 100644 index 000000000..8fd1f320d --- /dev/null +++ b/tsconfig.tools.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc-tools", + "types": ["node"] + }, + "include": ["code-pushup.config.ts"] +} From 0a6467ec614b6d7d7607b5fd28975d924115e1d2 Mon Sep 17 00:00:00 2001 From: John Doe Date: Tue, 12 Aug 2025 22:35:14 +0200 Subject: [PATCH 024/111] fix: revert changed --- packages/models/tsconfig.tools.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/models/tsconfig.tools.json b/packages/models/tsconfig.tools.json index 8fd1f320d..4a9dfeae3 100644 --- a/packages/models/tsconfig.tools.json +++ b/packages/models/tsconfig.tools.json @@ -1,8 +1,8 @@ { "extends": "./tsconfig.json", "compilerOptions": { - "outDir": "../../dist/out-tsc-tools", - "types": ["node"] + "outDir": "../../dist/out-tsc", + "types": ["nodenext"] }, - "include": ["code-pushup.config.ts"] + "include": ["zod2md.config.ts", "code-pushup.config.ts"] } From c7704551fd9b5e3937a7ddcad7dd42e299ad4403 Mon Sep 17 00:00:00 2001 From: John Doe Date: Tue, 12 Aug 2025 22:56:40 +0200 Subject: [PATCH 025/111] fix: wip --- code-pushup.config.ts | 40 +++++++++++++++++-- code-pushup.new.config.ts | 23 +++++++++++ .../fixtures/npm-repo/code-pushup.config.ts | 8 ++++ project.json | 10 +++++ testing/test-nx-utils/project.json | 2 + testing/test-setup/project.json | 7 +++- .../lib/fixtures/configs/tsconfig.tools.json | 8 ---- tsconfig.tools.json | 8 ---- 8 files changed, 84 insertions(+), 22 deletions(-) create mode 100644 code-pushup.new.config.ts delete mode 100644 testing/test-utils/src/lib/fixtures/configs/tsconfig.tools.json delete mode 100644 tsconfig.tools.json diff --git a/code-pushup.config.ts b/code-pushup.config.ts index 78559dab5..51aa2b33b 100644 --- a/code-pushup.config.ts +++ b/code-pushup.config.ts @@ -1,23 +1,55 @@ import 'dotenv/config'; +import { z } from 'zod'; import { + coverageCoreConfigNx, + eslintCoreConfigNx, + jsDocsCoreConfig, jsPackagesCoreConfig, lighthouseCoreConfig, - loadEnv, - mergeConfigs, + typescriptPluginConfig, } from './code-pushup.preset.js'; import type { CoreConfig } from './packages/models/src/index.js'; +import { mergeConfigs } from './packages/utils/src/index.js'; -const projectName = 'cli'; +// load upload configuration from environment +const envSchema = z.object({ + CP_SERVER: z.string().url(), + CP_API_KEY: z.string().min(1), + CP_ORGANIZATION: z.string().min(1), + CP_PROJECT: z.string().min(1), +}); +const { data: env } = await envSchema.safeParseAsync(process.env); const config: CoreConfig = { - ...(await loadEnv(projectName)), + ...(env && { + upload: { + server: env.CP_SERVER, + apiKey: env.CP_API_KEY, + organization: env.CP_ORGANIZATION, + project: env.CP_PROJECT, + }, + }), + plugins: [], }; export default mergeConfigs( config, + await coverageCoreConfigNx(), await jsPackagesCoreConfig(), await lighthouseCoreConfig( 'https://github.com/code-pushup/cli?tab=readme-ov-file#code-pushup-cli/', ), + await typescriptPluginConfig({ + tsconfig: 'packages/cli/tsconfig.lib.json', + }), + await eslintCoreConfigNx(), + jsDocsCoreConfig([ + 'packages/**/src/**/*.ts', + '!packages/**/node_modules', + '!packages/**/{mocks,mock}', + '!**/*.{spec,test}.ts', + '!**/implementation/**', + '!**/internal/**', + ]), ); diff --git a/code-pushup.new.config.ts b/code-pushup.new.config.ts new file mode 100644 index 000000000..78559dab5 --- /dev/null +++ b/code-pushup.new.config.ts @@ -0,0 +1,23 @@ +import 'dotenv/config'; +import { + jsPackagesCoreConfig, + lighthouseCoreConfig, + loadEnv, + mergeConfigs, +} from './code-pushup.preset.js'; +import type { CoreConfig } from './packages/models/src/index.js'; + +const projectName = 'cli'; + +const config: CoreConfig = { + ...(await loadEnv(projectName)), + plugins: [], +}; + +export default mergeConfigs( + config, + await jsPackagesCoreConfig(), + await lighthouseCoreConfig( + 'https://github.com/code-pushup/cli?tab=readme-ov-file#code-pushup-cli/', + ), +); diff --git a/e2e/plugin-js-packages-e2e/mocks/fixtures/npm-repo/code-pushup.config.ts b/e2e/plugin-js-packages-e2e/mocks/fixtures/npm-repo/code-pushup.config.ts index f200abcd6..aba57ced5 100644 --- a/e2e/plugin-js-packages-e2e/mocks/fixtures/npm-repo/code-pushup.config.ts +++ b/e2e/plugin-js-packages-e2e/mocks/fixtures/npm-repo/code-pushup.config.ts @@ -6,3 +6,11 @@ import type { CoreConfig } from '@code-pushup/models'; const thisConfigFolder = fileURLToPath(dirname(import.meta.url)); export default { + persist: { outputDir: thisConfigFolder, format: ['json'] }, + plugins: [ + await jsPackagesPlugin({ + packageManager: 'npm', + packageJsonPath: join(thisConfigFolder, 'package.json'), + }), + ], +} satisfies CoreConfig; diff --git a/project.json b/project.json index a1f347ba6..1a520cec8 100644 --- a/project.json +++ b/project.json @@ -2,6 +2,16 @@ "name": "cli-source", "$schema": "node_modules/nx/schemas/project-schema.json", "targets": { + "code-pushup-old": { + "executor": "nx:run-commands", + "options": { + "command": "node packages/cli/src/index.ts --no-progress --verbose", + "env": { + "NODE_OPTIONS": "--import tsx", + "TSX_TSCONFIG_PATH": "tsconfig.base.json" + } + } + }, "code-pushup": { "dependsOn": ["code-pushup-js-packages", "code-pushup-lighthouse"], "executor": "nx:run-commands", diff --git a/testing/test-nx-utils/project.json b/testing/test-nx-utils/project.json index 5aad9c4f0..d76cad67e 100644 --- a/testing/test-nx-utils/project.json +++ b/testing/test-nx-utils/project.json @@ -4,6 +4,8 @@ "sourceRoot": "testing/test-nx-utils/src", "projectType": "library", "targets": { + "build": {}, + "lint": {}, "unit-test": {} }, "tags": ["scope:shared", "type:testing"] diff --git a/testing/test-setup/project.json b/testing/test-setup/project.json index 69a55091e..0657658a2 100644 --- a/testing/test-setup/project.json +++ b/testing/test-setup/project.json @@ -3,7 +3,10 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "testing/test-setup/src", "projectType": "library", - "targets": {}, - "unit-test": {}, + "targets": { + "build": {}, + "lint": {}, + "unit-test": {} + }, "tags": ["scope:shared", "type:testing"] } diff --git a/testing/test-utils/src/lib/fixtures/configs/tsconfig.tools.json b/testing/test-utils/src/lib/fixtures/configs/tsconfig.tools.json deleted file mode 100644 index 8fd1f320d..000000000 --- a/testing/test-utils/src/lib/fixtures/configs/tsconfig.tools.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../dist/out-tsc-tools", - "types": ["node"] - }, - "include": ["code-pushup.config.ts"] -} diff --git a/tsconfig.tools.json b/tsconfig.tools.json deleted file mode 100644 index 8fd1f320d..000000000 --- a/tsconfig.tools.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../dist/out-tsc-tools", - "types": ["node"] - }, - "include": ["code-pushup.config.ts"] -} From 21a4f04e388d810926cf0951927a15c7337fe071 Mon Sep 17 00:00:00 2001 From: John Doe Date: Tue, 12 Aug 2025 23:00:21 +0200 Subject: [PATCH 026/111] chore: add new cp action --- .github/workflows/code-pushup-fork-old.yml | 38 +++++++++++++++++++++ .github/workflows/code-pushup-old.yml | 39 ++++++++++++++++++++++ .github/workflows/code-pushup.yml | 2 +- 3 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/code-pushup-fork-old.yml create mode 100644 .github/workflows/code-pushup-old.yml diff --git a/.github/workflows/code-pushup-fork-old.yml b/.github/workflows/code-pushup-fork-old.yml new file mode 100644 index 000000000..5ecfdddf0 --- /dev/null +++ b/.github/workflows/code-pushup-fork-old.yml @@ -0,0 +1,38 @@ +name: Code PushUp (fork) + +# separated from code-pushup.yml for security reasons +# => requires permissions to create PR comment +# => for PRs from forks, needs to run on `pull_request_target`, not `pull_request` +# => `pull_request_target` is a security risk when secrets are being used +# => secrets needed for code-pushup upload +# => code-pushup for forks runs in separate workflow with no secrets access + +on: + pull_request_target: + branches: [main] + +env: + NX_NON_NATIVE_HASHER: true + +permissions: + pull-requests: write + +jobs: + code-pushup: + runs-on: ubuntu-latest + name: Code PushUp + if: github.event.pull_request.head.repo.fork + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version-file: .nvmrc + cache: npm + - name: Install dependencies + run: npm ci + - name: Run Code PushUp action + uses: code-pushup/github-action@v0 + with: + bin: npx nx code-pushup-old -- diff --git a/.github/workflows/code-pushup-old.yml b/.github/workflows/code-pushup-old.yml new file mode 100644 index 000000000..cc1351476 --- /dev/null +++ b/.github/workflows/code-pushup-old.yml @@ -0,0 +1,39 @@ +name: Code PushUp + +on: + push: + branches: [main] + pull_request: + branches: [main] + +env: + NX_NON_NATIVE_HASHER: true + +permissions: + pull-requests: write + +jobs: + code-pushup: + runs-on: ubuntu-latest + name: Code PushUp + # ignore PRs from forks, handled by code-pushup-fork.yml + if: ${{ !github.event.pull_request.head.repo.fork }} + env: + CP_SERVER: ${{ secrets.CP_SERVER }} + CP_API_KEY: ${{ secrets.CP_API_KEY }} + CP_ORGANIZATION: code-pushup + CP_PROJECT: cli + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version-file: .nvmrc + cache: npm + - name: Install dependencies + run: npm ci + - name: Run Code PushUp action + uses: code-pushup/github-action@v0 + with: + bin: npx nx code-pushup -- diff --git a/.github/workflows/code-pushup.yml b/.github/workflows/code-pushup.yml index cc1351476..ed135e5a5 100644 --- a/.github/workflows/code-pushup.yml +++ b/.github/workflows/code-pushup.yml @@ -36,4 +36,4 @@ jobs: - name: Run Code PushUp action uses: code-pushup/github-action@v0 with: - bin: npx nx code-pushup -- + bin: npx nx affected -t code-pushup From 4ee6001b6b82bea30ae0a183348189be6e8318f4 Mon Sep 17 00:00:00 2001 From: John Doe Date: Tue, 12 Aug 2025 23:13:45 +0200 Subject: [PATCH 027/111] chore: wip gh action 2 --- .github/workflows/code-pushup-fork.yml | 10 ++++++++-- .github/workflows/code-pushup.yml | 6 +++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/.github/workflows/code-pushup-fork.yml b/.github/workflows/code-pushup-fork.yml index 27d9c04e0..06de8f75b 100644 --- a/.github/workflows/code-pushup-fork.yml +++ b/.github/workflows/code-pushup-fork.yml @@ -23,8 +23,14 @@ jobs: name: Code PushUp if: github.event.pull_request.head.repo.fork steps: - - name: Checkout repository + - name: Checkout PR head uses: actions/checkout@v4 + with: + repository: ${{ github.event.pull_request.head.repo.full_name }} + ref: ${{ github.event.pull_request.head.ref }} + fetch-depth: 0 + - name: Derive Nx SHAs + uses: nrwl/nx-set-shas@v4 - name: Set up Node.js uses: actions/setup-node@v4 with: @@ -35,4 +41,4 @@ jobs: - name: Run Code PushUp action uses: code-pushup/github-action@v0 with: - bin: npx nx code-pushup -- + bin: npx nx affected -t code-pushup --base=${{ env.NX_BASE }} --head=${{ env.NX_HEAD }} diff --git a/.github/workflows/code-pushup.yml b/.github/workflows/code-pushup.yml index ed135e5a5..c94abe2bd 100644 --- a/.github/workflows/code-pushup.yml +++ b/.github/workflows/code-pushup.yml @@ -26,6 +26,10 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Derive Nx SHAs + uses: nrwl/nx-set-shas@v4 - name: Set up Node.js uses: actions/setup-node@v4 with: @@ -36,4 +40,4 @@ jobs: - name: Run Code PushUp action uses: code-pushup/github-action@v0 with: - bin: npx nx affected -t code-pushup + bin: npx nx affected -t code-pushup --base=${{ env.NX_BASE }} --head=${{ env.NX_HEAD }} From 3261c0eb04d2c5ab1f5c2301a4ccaebf9668e3f1 Mon Sep 17 00:00:00 2001 From: John Doe Date: Tue, 12 Aug 2025 23:28:29 +0200 Subject: [PATCH 028/111] chore: refactor unit and int test targets --- nx.json | 14 ++++++++++++++ packages/ci/project.json | 9 ++------- packages/cli/project.json | 9 ++------- packages/core/project.json | 9 ++------- packages/create-cli/project.json | 9 ++------- packages/models/project.json | 9 ++------- packages/nx-plugin/project.json | 9 ++------- packages/plugin-coverage/project.json | 9 ++------- packages/plugin-eslint/project.json | 9 ++------- packages/plugin-js-packages/project.json | 9 ++------- packages/plugin-jsdocs/project.json | 9 ++------- packages/plugin-lighthouse/project.json | 9 ++------- packages/plugin-typescript/project.json | 9 ++------- packages/utils/project.json | 9 ++------- 14 files changed, 40 insertions(+), 91 deletions(-) diff --git a/nx.json b/nx.json index a6f3b45a0..53b7fe496 100644 --- a/nx.json +++ b/nx.json @@ -14,6 +14,20 @@ "assets": ["{projectRoot}/*.md"] } }, + "unit-test": { + "cache": true, + "executor": "@nx/vite:test", + "options": { + "configFile": "{projectRoot}/vitest.unit.config.ts" + } + }, + "int-test": { + "cache": true, + "executor": "@nx/vite:test", + "options": { + "configFile": "{projectRoot}/vitest.int.config.ts" + } + }, "lint": { "inputs": ["default", "{workspaceRoot}/eslint.config.?(c)js"], "executor": "@nx/linter:eslint", diff --git a/packages/ci/project.json b/packages/ci/project.json index 433089f77..ee895fca5 100644 --- a/packages/ci/project.json +++ b/packages/ci/project.json @@ -6,16 +6,11 @@ "targets": { "build": {}, "lint": {}, - "unit-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "packages/ci/vitest.unit.config.ts" - } - }, + "unit-test": {}, "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "packages/ci/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts" } } }, diff --git a/packages/cli/project.json b/packages/cli/project.json index f25d2cccf..c7c0a59b4 100644 --- a/packages/cli/project.json +++ b/packages/cli/project.json @@ -6,16 +6,11 @@ "targets": { "build": {}, "lint": {}, - "unit-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "packages/cli/vitest.unit.config.ts" - } - }, + "unit-test": {}, "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "packages/cli/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts" } }, "run-help": { diff --git a/packages/core/project.json b/packages/core/project.json index fe36dba07..4379a3c1e 100644 --- a/packages/core/project.json +++ b/packages/core/project.json @@ -6,16 +6,11 @@ "targets": { "build": {}, "lint": {}, - "unit-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "packages/core/vitest.unit.config.ts" - } - }, + "unit-test": {}, "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "packages/core/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts" } } }, diff --git a/packages/create-cli/project.json b/packages/create-cli/project.json index 11e1ef907..11193d2cf 100644 --- a/packages/create-cli/project.json +++ b/packages/create-cli/project.json @@ -6,16 +6,11 @@ "targets": { "build": {}, "lint": {}, - "unit-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "packages/create-cli/vitest.unit.config.ts" - } - }, + "unit-test": {}, "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "packages/create-cli/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts" } }, "exec-node": { diff --git a/packages/models/project.json b/packages/models/project.json index d80e38793..22243ac11 100644 --- a/packages/models/project.json +++ b/packages/models/project.json @@ -18,16 +18,11 @@ ] }, "lint": {}, - "unit-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "packages/models/vitest.unit.config.ts" - } - }, + "unit-test": {}, "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "packages/models/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts" } } }, diff --git a/packages/nx-plugin/project.json b/packages/nx-plugin/project.json index df20084e3..d214b726b 100644 --- a/packages/nx-plugin/project.json +++ b/packages/nx-plugin/project.json @@ -41,16 +41,11 @@ ] } }, - "unit-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "packages/nx-plugin/vitest.unit.config.ts" - } - }, + "unit-test": {}, "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "packages/nx-plugin/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts" } } }, diff --git a/packages/plugin-coverage/project.json b/packages/plugin-coverage/project.json index ddef42a9d..56488ba8c 100644 --- a/packages/plugin-coverage/project.json +++ b/packages/plugin-coverage/project.json @@ -6,16 +6,11 @@ "targets": { "build": {}, "lint": {}, - "unit-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "packages/plugin-coverage/vitest.unit.config.ts" - } - }, + "unit-test": {}, "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "packages/plugin-coverage/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts" } } }, diff --git a/packages/plugin-eslint/project.json b/packages/plugin-eslint/project.json index 0f23cf33d..7347d86b2 100644 --- a/packages/plugin-eslint/project.json +++ b/packages/plugin-eslint/project.json @@ -6,16 +6,11 @@ "targets": { "build": {}, "lint": {}, - "unit-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "packages/plugin-eslint/vitest.unit.config.ts" - } - }, + "unit-test": {}, "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "packages/plugin-eslint/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts" } } }, diff --git a/packages/plugin-js-packages/project.json b/packages/plugin-js-packages/project.json index d664a3817..6c36a0948 100644 --- a/packages/plugin-js-packages/project.json +++ b/packages/plugin-js-packages/project.json @@ -6,16 +6,11 @@ "targets": { "build": {}, "lint": {}, - "unit-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "packages/plugin-js-packages/vitest.unit.config.ts" - } - }, + "unit-test": {}, "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "packages/plugin-js-packages/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts" } } }, diff --git a/packages/plugin-jsdocs/project.json b/packages/plugin-jsdocs/project.json index ebe839f44..5217e993f 100644 --- a/packages/plugin-jsdocs/project.json +++ b/packages/plugin-jsdocs/project.json @@ -7,16 +7,11 @@ "targets": { "build": {}, "lint": {}, - "unit-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "packages/plugin-jsdocs/vitest.unit.config.ts" - } - }, + "unit-test": {}, "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "packages/plugin-jsdocs/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts" } } } diff --git a/packages/plugin-lighthouse/project.json b/packages/plugin-lighthouse/project.json index 9442227f4..bf55f2e95 100644 --- a/packages/plugin-lighthouse/project.json +++ b/packages/plugin-lighthouse/project.json @@ -6,16 +6,11 @@ "targets": { "build": {}, "lint": {}, - "unit-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "packages/plugin-lighthouse/vitest.unit.config.ts" - } - }, + "unit-test": {}, "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "packages/plugin-lighthouse/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts" } } }, diff --git a/packages/plugin-typescript/project.json b/packages/plugin-typescript/project.json index 9b2265b73..27bf5d835 100644 --- a/packages/plugin-typescript/project.json +++ b/packages/plugin-typescript/project.json @@ -6,16 +6,11 @@ "targets": { "build": {}, "lint": {}, - "unit-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "packages/plugin-typescript/vitest.unit.config.ts" - } - }, + "unit-test": {}, "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "packages/plugin-typescript/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts" } } }, diff --git a/packages/utils/project.json b/packages/utils/project.json index 30e7fa046..5d0755f4a 100644 --- a/packages/utils/project.json +++ b/packages/utils/project.json @@ -18,16 +18,11 @@ "cwd": "./packages/utils/perf" } }, - "unit-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "packages/utils/vitest.unit.config.ts" - } - }, + "unit-test": {}, "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "packages/utils/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts" } } }, From ad988ab00b9bc1fe0a53cac65dee9135474e8bc0 Mon Sep 17 00:00:00 2001 From: John Doe Date: Tue, 12 Aug 2025 23:34:36 +0200 Subject: [PATCH 029/111] chore: refactor unit and int test targets 2 --- testing/test-nx-utils/project.json | 7 +------ testing/test-setup/project.json | 7 +------ testing/test-utils/project.json | 7 +------ 3 files changed, 3 insertions(+), 18 deletions(-) diff --git a/testing/test-nx-utils/project.json b/testing/test-nx-utils/project.json index 9fc33df87..d76cad67e 100644 --- a/testing/test-nx-utils/project.json +++ b/testing/test-nx-utils/project.json @@ -6,12 +6,7 @@ "targets": { "build": {}, "lint": {}, - "unit-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "testing/test-nx-utils/vitest.unit.config.ts" - } - } + "unit-test": {} }, "tags": ["scope:shared", "type:testing"] } diff --git a/testing/test-setup/project.json b/testing/test-setup/project.json index 6320cfaab..0657658a2 100644 --- a/testing/test-setup/project.json +++ b/testing/test-setup/project.json @@ -6,12 +6,7 @@ "targets": { "build": {}, "lint": {}, - "unit-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "testing/test-setup/vitest.unit.config.ts" - } - } + "unit-test": {} }, "tags": ["scope:shared", "type:testing"] } diff --git a/testing/test-utils/project.json b/testing/test-utils/project.json index ccc11d50c..a23396a9e 100644 --- a/testing/test-utils/project.json +++ b/testing/test-utils/project.json @@ -6,12 +6,7 @@ "targets": { "build": {}, "lint": {}, - "unit-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "testing/test-utils/vitest.unit.config.ts" - } - }, + "unit-test": {}, "nx-release-publish": { "executor": "nx:noop" } From 709bb88a2aa699eed4deb87256b2a6d5d2a756ae Mon Sep 17 00:00:00 2001 From: John Doe Date: Tue, 12 Aug 2025 23:55:33 +0200 Subject: [PATCH 030/111] chore: add env var helper --- code-pushup.config.ts | 13 +++---------- code-pushup.preset.ts | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/code-pushup.config.ts b/code-pushup.config.ts index 51aa2b33b..c590b3cd2 100644 --- a/code-pushup.config.ts +++ b/code-pushup.config.ts @@ -6,6 +6,7 @@ import { jsDocsCoreConfig, jsPackagesCoreConfig, lighthouseCoreConfig, + loadEnv, typescriptPluginConfig, } from './code-pushup.preset.js'; import type { CoreConfig } from './packages/models/src/index.js'; @@ -18,18 +19,10 @@ const envSchema = z.object({ CP_ORGANIZATION: z.string().min(1), CP_PROJECT: z.string().min(1), }); -const { data: env } = await envSchema.safeParseAsync(process.env); +const projectName = 'cli'; const config: CoreConfig = { - ...(env && { - upload: { - server: env.CP_SERVER, - apiKey: env.CP_API_KEY, - organization: env.CP_ORGANIZATION, - project: env.CP_PROJECT, - }, - }), - + ...(await loadEnv(projectName)), plugins: [], }; diff --git a/code-pushup.preset.ts b/code-pushup.preset.ts index 15ba02ccc..e66b76eef 100644 --- a/code-pushup.preset.ts +++ b/code-pushup.preset.ts @@ -1,4 +1,5 @@ /* eslint-disable @nx/enforce-module-boundaries */ +import { z } from 'zod'; import type { CategoryConfig, CoreConfig, @@ -29,6 +30,44 @@ import typescriptPlugin, { getCategories, } from './packages/plugin-typescript/src/index.js'; +/** + * Helper function to load and validate Code PushUp environment variables for upload configuration + */ +export async function loadEnv( + projectName: string | undefined = process.env.NX_TASK_TARGET_PROJECT, +): Promise> { + if (projectName == null || projectName === '') { + throw new Error( + 'loadEnv failed! Project name is not defined. Please run code pushup fit Nx or provide a projectName.', + ); + } + const envSchema = z.object({ + CP_SERVER: z.string().url(), + CP_API_KEY: z.string().min(1), + CP_ORGANIZATION: z.string().min(1), + CP_PROJECT: z.string().optional(), + }); + + const { data: env, success } = await envSchema.safeParseAsync(process.env); + + if (!success || !env) { + return {}; + } + const uploadConfig = { + apiKey: env.CP_API_KEY, + server: env.CP_SERVER, + organization: env.CP_ORGANIZATION, + ...(env.CP_PROJECT + ? { project: env.CP_PROJECT } + : { project: projectName }), + }; + return ( + uploadConfig.apiKey && { + upload: uploadConfig, + } + ); +} + export const jsPackagesCategories: CategoryConfig[] = [ { slug: 'security', From 0958ad09306be62007fb0b3e49498112501a2c28 Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 13 Aug 2025 00:16:19 +0200 Subject: [PATCH 031/111] chore: add default targets --- nx.json | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++ project.json | 22 +++++++- 2 files changed, 172 insertions(+), 1 deletion(-) diff --git a/nx.json b/nx.json index a6f3b45a0..d96efaa7c 100644 --- a/nx.json +++ b/nx.json @@ -41,6 +41,157 @@ "watch": false } }, + "code-pushup": { + "cache": true, + "outputs": [ + "{projectRoot}/.code-pushup/report.md", + "{projectRoot}/.code-pushup/report.json" + ], + "executor": "nx:run-commands", + "options": { + "command": "node packages/cli/src/index.ts", + "args": [ + "--no-progress", + "--verbose", + "--config={projectRoot}/code-pushup.config.ts", + "--cache.read", + "--persist.outputDir={projectRoot}/.code-pushup", + "--upload.project=cli-{projectName}" + ], + "env": { + "NODE_OPTIONS": "--import tsx", + "TSX_TSCONFIG_PATH": "tsconfig.base.json" + } + } + }, + "code-pushup-coverage": { + "cache": true, + "outputs": ["{projectRoot}/.code-pushup/coverage"], + "executor": "nx:run-commands", + "dependsOn": ["unit-test", "int-test"], + "options": { + "command": "node packages/cli/src/index.ts collect", + "args": [ + "--no-progress", + "--verbose", + "--config={projectRoot}/code-pushup.config.ts", + "--cache.write", + "--onlyPlugins=coverage", + "--persist.skipReports=true", + "--persist.outputDir={projectRoot}/.code-pushup" + ], + "env": { + "NODE_OPTIONS": "--import tsx", + "TSX_TSCONFIG_PATH": "tsconfig.base.json" + } + } + }, + "code-pushup-eslint": { + "cache": true, + "outputs": ["{projectRoot}/.code-pushup/eslint"], + "executor": "nx:run-commands", + "options": { + "command": "node packages/cli/src/index.ts collect", + "args": [ + "--no-progress", + "--verbose", + "--config={projectRoot}/code-pushup.config.ts", + "--cache.write", + "--onlyPlugins=eslint", + "--persist.skipReports", + "--persist.outputDir={projectRoot}/.code-pushup" + ], + "env": { + "NODE_OPTIONS": "--import tsx", + "TSX_TSCONFIG_PATH": "tsconfig.base.json" + } + } + }, + "code-pushup-js-packages": { + "cache": false, + "outputs": ["{projectRoot}/.code-pushup/js-packages"], + "executor": "nx:run-commands", + "options": { + "command": "node packages/cli/src/index.ts collect", + "args": [ + "--no-progress", + "--verbose", + "--config={projectRoot}/code-pushup.config.ts", + "--cache.write", + "--onlyPlugins=js-packages", + "--persist.skipReports", + "--persist.outputDir={projectRoot}/.code-pushup" + ], + "env": { + "NODE_OPTIONS": "--import tsx", + "TSX_TSCONFIG_PATH": "tsconfig.base.json" + } + } + }, + "code-pushup-lighthouse": { + "cache": true, + "outputs": ["{projectRoot}/.code-pushup/lighthouse"], + "executor": "nx:run-commands", + "options": { + "command": "node packages/cli/src/index.ts", + "args": [ + "--no-progress", + "--verbose", + "--config={projectRoot}/code-pushup.config.ts", + "--cache.write", + "--onlyPlugins=lighthouse", + "--persist.skipReports", + "--persist.outputDir={projectRoot}/.code-pushup" + ], + "env": { + "NODE_OPTIONS": "--import tsx", + "TSX_TSCONFIG_PATH": "tsconfig.base.json" + } + } + }, + "code-pushup-jsdocs": { + "cache": true, + "outputs": ["{projectRoot}/.code-pushup/jsdocs"], + "executor": "nx:run-commands", + "options": { + "command": "node packages/cli/src/index.ts collect", + "args": [ + "--no-progress", + "--verbose", + "--config={projectRoot}/code-pushup.config.ts", + "--cache.write", + "--onlyPlugins=jsdocs", + "--persist.skipReports", + "--persist.outputDir={projectRoot}/.code-pushup" + ], + "env": { + "NODE_OPTIONS": "--import tsx", + "TSX_TSCONFIG_PATH": "tsconfig.base.json" + } + } + }, + "code-pushup-typescript": { + "cache": true, + "inputs": ["default", "^default", "{projectRoot}/tsconfig.lib.json"], + "outputs": ["{projectRoot}/.code-pushup/typescript"], + "executor": "nx:run-commands", + "options": { + "command": "node packages/cli/src/index.ts collect", + "args": [ + "--no-progress", + "--verbose", + "--config={projectRoot}/code-pushup.config.ts", + "--cache.write", + "--onlyPlugins=typescript", + "--persist.skipReports", + "--persist.outputDir={projectRoot}/.code-pushup" + ], + "env": { + "NODE_OPTIONS": "--import tsx", + "TSX_TSCONFIG_PATH": "tsconfig.base.json" + } + } + }, "nx-release-publish": { "dependsOn": ["build"], "executor": "@nx/js:release-publish", diff --git a/project.json b/project.json index a4c550bfb..b18c89e17 100644 --- a/project.json +++ b/project.json @@ -2,10 +2,30 @@ "name": "@code-pushup/cli-source", "$schema": "node_modules/nx/schemas/project-schema.json", "targets": { + "code-pushup-js-packages": {}, + "code-pushup-lighthouse": {}, + "code-pushup-coverage": {}, + "code-pushup-eslint": {}, + "code-pushup-jsdocs": {}, + "code-pushup-typescript": {}, "code-pushup": { + "dependsOn": [ + "code-pushup-js-packages", + "code-pushup-lighthouse", + "code-pushup-coverage", + "code-pushup-eslint", + "code-pushup-jsdocs", + "code-pushup-typescript" + ], "executor": "nx:run-commands", "options": { - "command": "node packages/cli/src/index.ts --no-progress --verbose", + "args": [ + "--no-progress", + "--verbose", + "--config={projectRoot}/code-pushup.config.ts", + "--cache.read", + "--persist.outputDir={projectRoot}/.code-pushup" + ], "env": { "NODE_OPTIONS": "--import tsx", "TSX_TSCONFIG_PATH": "tsconfig.base.json" From 30fa5b3d17d894890fa88a3a0acf4f871722766a Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 13 Aug 2025 00:23:16 +0200 Subject: [PATCH 032/111] chore: adjust gh actions --- .github/workflows/code-pushup-fork.yml | 4 +++- .github/workflows/code-pushup.yml | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/code-pushup-fork.yml b/.github/workflows/code-pushup-fork.yml index 27d9c04e0..4dd08dbb1 100644 --- a/.github/workflows/code-pushup-fork.yml +++ b/.github/workflows/code-pushup-fork.yml @@ -30,9 +30,11 @@ jobs: with: node-version-file: .nvmrc cache: npm + - name: Set base and head for Nx affected commands + uses: nrwl/nx-set-shas@v4 - name: Install dependencies run: npm ci - name: Run Code PushUp action uses: code-pushup/github-action@v0 with: - bin: npx nx code-pushup -- + bin: npx nx affected -t code-pushup --parallel=3 -- diff --git a/.github/workflows/code-pushup.yml b/.github/workflows/code-pushup.yml index cc1351476..a5136b1ff 100644 --- a/.github/workflows/code-pushup.yml +++ b/.github/workflows/code-pushup.yml @@ -31,9 +31,11 @@ jobs: with: node-version-file: .nvmrc cache: npm + - name: Set base and head for Nx affected commands + uses: nrwl/nx-set-shas@v4 - name: Install dependencies run: npm ci - name: Run Code PushUp action uses: code-pushup/github-action@v0 with: - bin: npx nx code-pushup -- + bin: npx nx affected -t code-pushup --parallel=3 -- From 822a3235aeb188f82f25e73f9e1e58d3cf343fec Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 13 Aug 2025 00:39:27 +0200 Subject: [PATCH 033/111] chore: add coverage to existing test targets --- code-pushup.preset.ts | 7 +------ nx.json | 10 ++++++++-- packages/ci/project.json | 5 ++++- packages/cli/project.json | 5 ++++- packages/core/project.json | 5 ++++- packages/create-cli/project.json | 5 ++++- packages/models/project.json | 5 ++++- packages/nx-plugin/project.json | 5 ++++- packages/plugin-coverage/project.json | 5 ++++- packages/plugin-eslint/project.json | 5 ++++- packages/plugin-js-packages/project.json | 5 ++++- packages/plugin-jsdocs/project.json | 5 ++++- packages/plugin-lighthouse/project.json | 5 ++++- packages/plugin-typescript/project.json | 5 ++++- packages/utils/project.json | 5 ++++- 15 files changed, 61 insertions(+), 21 deletions(-) diff --git a/code-pushup.preset.ts b/code-pushup.preset.ts index 15ba02ccc..c6d5652f1 100644 --- a/code-pushup.preset.ts +++ b/code-pushup.preset.ts @@ -184,12 +184,7 @@ export const coverageCoreConfigNx = async ( throw new Error('coverageCoreConfigNx for single projects not implemented'); } const targetNames = ['unit-test', 'int-test']; - const targetArgs = [ - '-t', - ...targetNames, - '--coverage.enabled', - '--skipNxCache', - ]; + const targetArgs = ['-t', ...targetNames]; return { plugins: [ await coveragePlugin({ diff --git a/nx.json b/nx.json index 53b7fe496..088d1d11d 100644 --- a/nx.json +++ b/nx.json @@ -18,14 +18,20 @@ "cache": true, "executor": "@nx/vite:test", "options": { - "configFile": "{projectRoot}/vitest.unit.config.ts" + "configFile": "{projectRoot}/vitest.unit.config.ts", + "coverage": { + "enabled": true + } } }, "int-test": { "cache": true, "executor": "@nx/vite:test", "options": { - "configFile": "{projectRoot}/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts", + "coverage": { + "enabled": true + } } }, "lint": { diff --git a/packages/ci/project.json b/packages/ci/project.json index ee895fca5..dbe33d05f 100644 --- a/packages/ci/project.json +++ b/packages/ci/project.json @@ -10,7 +10,10 @@ "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "{projectRoot}/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts", + "coverage": { + "enabled": true + } } } }, diff --git a/packages/cli/project.json b/packages/cli/project.json index c7c0a59b4..9157b25ad 100644 --- a/packages/cli/project.json +++ b/packages/cli/project.json @@ -10,7 +10,10 @@ "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "{projectRoot}/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts", + "coverage": { + "enabled": true + } } }, "run-help": { diff --git a/packages/core/project.json b/packages/core/project.json index 4379a3c1e..4dbbe86c7 100644 --- a/packages/core/project.json +++ b/packages/core/project.json @@ -10,7 +10,10 @@ "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "{projectRoot}/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts", + "coverage": { + "enabled": true + } } } }, diff --git a/packages/create-cli/project.json b/packages/create-cli/project.json index 11193d2cf..8e4b13b58 100644 --- a/packages/create-cli/project.json +++ b/packages/create-cli/project.json @@ -10,7 +10,10 @@ "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "{projectRoot}/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts", + "coverage": { + "enabled": true + } } }, "exec-node": { diff --git a/packages/models/project.json b/packages/models/project.json index 22243ac11..9e8ff7b11 100644 --- a/packages/models/project.json +++ b/packages/models/project.json @@ -22,7 +22,10 @@ "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "{projectRoot}/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts", + "coverage": { + "enabled": true + } } } }, diff --git a/packages/nx-plugin/project.json b/packages/nx-plugin/project.json index d214b726b..1ec43129e 100644 --- a/packages/nx-plugin/project.json +++ b/packages/nx-plugin/project.json @@ -45,7 +45,10 @@ "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "{projectRoot}/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts", + "coverage": { + "enabled": true + } } } }, diff --git a/packages/plugin-coverage/project.json b/packages/plugin-coverage/project.json index 56488ba8c..670030ce1 100644 --- a/packages/plugin-coverage/project.json +++ b/packages/plugin-coverage/project.json @@ -10,7 +10,10 @@ "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "{projectRoot}/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts", + "coverage": { + "enabled": true + } } } }, diff --git a/packages/plugin-eslint/project.json b/packages/plugin-eslint/project.json index 7347d86b2..49fc49313 100644 --- a/packages/plugin-eslint/project.json +++ b/packages/plugin-eslint/project.json @@ -10,7 +10,10 @@ "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "{projectRoot}/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts", + "coverage": { + "enabled": true + } } } }, diff --git a/packages/plugin-js-packages/project.json b/packages/plugin-js-packages/project.json index 6c36a0948..9164982fc 100644 --- a/packages/plugin-js-packages/project.json +++ b/packages/plugin-js-packages/project.json @@ -10,7 +10,10 @@ "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "{projectRoot}/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts", + "coverage": { + "enabled": true + } } } }, diff --git a/packages/plugin-jsdocs/project.json b/packages/plugin-jsdocs/project.json index 5217e993f..b08eaec07 100644 --- a/packages/plugin-jsdocs/project.json +++ b/packages/plugin-jsdocs/project.json @@ -11,7 +11,10 @@ "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "{projectRoot}/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts", + "coverage": { + "enabled": true + } } } } diff --git a/packages/plugin-lighthouse/project.json b/packages/plugin-lighthouse/project.json index bf55f2e95..f45bcf0c1 100644 --- a/packages/plugin-lighthouse/project.json +++ b/packages/plugin-lighthouse/project.json @@ -10,7 +10,10 @@ "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "{projectRoot}/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts", + "coverage": { + "enabled": true + } } } }, diff --git a/packages/plugin-typescript/project.json b/packages/plugin-typescript/project.json index 27bf5d835..94698b289 100644 --- a/packages/plugin-typescript/project.json +++ b/packages/plugin-typescript/project.json @@ -10,7 +10,10 @@ "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "{projectRoot}/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts", + "coverage": { + "enabled": true + } } } }, diff --git a/packages/utils/project.json b/packages/utils/project.json index 5d0755f4a..32b23aeb1 100644 --- a/packages/utils/project.json +++ b/packages/utils/project.json @@ -22,7 +22,10 @@ "int-test": { "executor": "@nx/vite:test", "options": { - "configFile": "{projectRoot}/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts", + "coverage": { + "enabled": true + } } } }, From 31666454798b86337f546f85b00ed056ea962c33 Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 13 Aug 2025 01:44:12 +0200 Subject: [PATCH 034/111] chore: refine e2e and int test targets --- code-pushup.preset.ts | 45 ++++++++++++++++--- e2e/ci-e2e/project.json | 7 +-- e2e/cli-e2e/project.json | 13 ++---- e2e/create-cli-e2e/project.json | 14 ++---- e2e/nx-plugin-e2e/project.json | 13 ++---- e2e/plugin-coverage-e2e/project.json | 13 ++---- e2e/plugin-eslint-e2e/project.json | 13 ++---- e2e/plugin-js-packages-e2e/project.json | 11 ++--- examples/plugins/project.json | 37 ++++----------- nx.json | 14 ++++-- packages/ci/project.json | 2 + packages/cli/project.json | 2 + packages/core/project.json | 2 + packages/create-cli/project.json | 2 + packages/nx-plugin/project.json | 2 + packages/plugin-coverage/project.json | 2 + .../src/lib/nx/coverage-paths.ts | 7 ++- packages/plugin-eslint/project.json | 2 + packages/plugin-js-packages/project.json | 2 + packages/plugin-jsdocs/project.json | 2 + packages/plugin-lighthouse/project.json | 2 + packages/plugin-typescript/project.json | 2 + packages/utils/project.json | 2 + 23 files changed, 114 insertions(+), 97 deletions(-) diff --git a/code-pushup.preset.ts b/code-pushup.preset.ts index c6d5652f1..55d20548c 100644 --- a/code-pushup.preset.ts +++ b/code-pushup.preset.ts @@ -100,12 +100,16 @@ export const eslintCategories: CategoryConfig[] = [ export function getJsDocsCategories( config: JsDocsPluginConfig, ): CategoryConfig[] { + const filterOptions = + typeof config === 'string' || Array.isArray(config) + ? {} + : { onlyAudits: config.onlyAudits, skipAudits: config.skipAudits }; return [ { slug: 'docs', title: 'Documentation', description: 'Measures how much of your code is **documented**.', - refs: filterGroupsByOnlyAudits(groups, config).map(group => ({ + refs: filterGroupsByOnlyAudits(groups, filterOptions).map(group => ({ weight: 1, type: 'group', plugin: PLUGIN_SLUG, @@ -159,12 +163,13 @@ export const jsDocsCoreConfig = ( export const eslintCoreConfigNx = async ( projectName?: string, + options?: { exclude?: string[] }, ): Promise => ({ plugins: [ await eslintPlugin( await (projectName ? eslintConfigFromNxProject(projectName) - : eslintConfigFromAllNxProjects()), + : eslintConfigFromAllNxProjects(options)), ), ], categories: eslintCategories, @@ -178,13 +183,42 @@ export const typescriptPluginConfig = async ( }); export const coverageCoreConfigNx = async ( - projectName?: string, + projectOrConfig?: + | string + | { + projectName: string; + targetNames: string[]; + }, + options?: { exclude?: string[] }, ): Promise => { + const projectName = + typeof projectOrConfig === 'string' + ? projectOrConfig + : projectOrConfig?.projectName; + const targetNames = + typeof projectOrConfig === 'object' && projectOrConfig?.targetNames?.length + ? projectOrConfig.targetNames + : ['unit-test', 'int-test']; + if (projectName) { throw new Error('coverageCoreConfigNx for single projects not implemented'); } - const targetNames = ['unit-test', 'int-test']; + const targetArgs = ['-t', ...targetNames]; + + // Compute projects list and apply exclude for efficient run-many execution + const { createProjectGraphAsync } = await import('@nx/devkit'); + const { nodes } = await createProjectGraphAsync({ exitOnError: false }); + const projectsWithTargets = Object.values(nodes).filter(node => + targetNames.some(t => node.data.targets && t in node.data.targets), + ); + const filteredProjects = options?.exclude?.length + ? projectsWithTargets.filter(node => !options.exclude!.includes(node.name)) + : projectsWithTargets; + const projectsArg = `--projects=${filteredProjects + .map(p => p.name) + .join(',')}`; + return { plugins: [ await coveragePlugin({ @@ -194,9 +228,10 @@ export const coverageCoreConfigNx = async ( 'nx', projectName ? `run --project ${projectName}` : 'run-many', ...targetArgs, + projectsArg, ], }, - reports: await getNxCoveragePaths(targetNames), + reports: await getNxCoveragePaths(targetNames, false, options?.exclude), }), ], categories: coverageCategories, diff --git a/e2e/ci-e2e/project.json b/e2e/ci-e2e/project.json index 29a33f65d..704b13730 100644 --- a/e2e/ci-e2e/project.json +++ b/e2e/ci-e2e/project.json @@ -5,12 +5,7 @@ "projectType": "application", "targets": { "lint": {}, - "e2e": { - "executor": "@nx/vite:test", - "options": { - "configFile": "e2e/ci-e2e/vitest.e2e.config.ts" - } - } + "e2e": {} }, "implicitDependencies": ["cli", "ci"], "tags": ["scope:tooling", "type:e2e"] diff --git a/e2e/cli-e2e/project.json b/e2e/cli-e2e/project.json index ba2f90352..181dd4854 100644 --- a/e2e/cli-e2e/project.json +++ b/e2e/cli-e2e/project.json @@ -3,15 +3,10 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "e2e/cli-e2e/src", "projectType": "application", + "tags": ["scope:core", "scope:plugin", "type:e2e"], + "implicitDependencies": ["cli"], "targets": { "lint": {}, - "e2e": { - "executor": "@nx/vite:test", - "options": { - "configFile": "e2e/cli-e2e/vitest.e2e.config.ts" - } - } - }, - "implicitDependencies": ["cli"], - "tags": ["scope:core", "scope:plugin", "type:e2e"] + "e2e": {} + } } diff --git a/e2e/create-cli-e2e/project.json b/e2e/create-cli-e2e/project.json index beeb09874..aad7d6f5f 100644 --- a/e2e/create-cli-e2e/project.json +++ b/e2e/create-cli-e2e/project.json @@ -3,16 +3,10 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "examples/create-cli-e2e/src", "projectType": "application", + "tags": ["scope:tooling", "type:e2e"], + "implicitDependencies": ["create-cli"], "targets": { "lint": {}, - "e2e": { - "executor": "@nx/vite:test", - "options": { - "keepServerRunning": true, - "configFile": "e2e/create-cli-e2e/vitest.e2e.config.ts" - } - } - }, - "implicitDependencies": ["create-cli"], - "tags": ["scope:tooling", "type:e2e"] + "e2e": {} + } } diff --git a/e2e/nx-plugin-e2e/project.json b/e2e/nx-plugin-e2e/project.json index 9c7a190fc..1c7d2a00f 100644 --- a/e2e/nx-plugin-e2e/project.json +++ b/e2e/nx-plugin-e2e/project.json @@ -3,15 +3,10 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "e2e/nx-plugin-e2e/src", "projectType": "application", + "tags": ["scope:tooling", "type:e2e"], + "implicitDependencies": ["test-utils", "nx-plugin"], "targets": { "lint": {}, - "e2e": { - "executor": "@nx/vite:test", - "options": { - "configFile": "e2e/nx-plugin-e2e/vitest.e2e.config.ts" - } - } - }, - "implicitDependencies": ["test-utils", "nx-plugin"], - "tags": ["scope:tooling", "type:e2e"] + "e2e": {} + } } diff --git a/e2e/plugin-coverage-e2e/project.json b/e2e/plugin-coverage-e2e/project.json index 7b127aa13..f8a9e46e9 100644 --- a/e2e/plugin-coverage-e2e/project.json +++ b/e2e/plugin-coverage-e2e/project.json @@ -3,15 +3,10 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "e2e/plugin-coverage-e2e/src", "projectType": "application", + "tags": ["scope:plugin", "type:e2e"], + "implicitDependencies": ["cli", "plugin-coverage"], "targets": { "lint": {}, - "e2e": { - "executor": "@nx/vite:test", - "options": { - "configFile": "e2e/plugin-coverage-e2e/vitest.e2e.config.ts" - } - } - }, - "implicitDependencies": ["cli", "plugin-coverage"], - "tags": ["scope:plugin", "type:e2e"] + "e2e": {} + } } diff --git a/e2e/plugin-eslint-e2e/project.json b/e2e/plugin-eslint-e2e/project.json index 544d6a8ef..82e3ff70b 100644 --- a/e2e/plugin-eslint-e2e/project.json +++ b/e2e/plugin-eslint-e2e/project.json @@ -3,15 +3,10 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "e2e/plugin-eslint-e2e/src", "projectType": "application", + "tags": ["scope:plugin", "type:e2e"], + "implicitDependencies": ["cli", "plugin-eslint"], "targets": { "lint": {}, - "e2e": { - "executor": "@nx/vite:test", - "options": { - "configFile": "e2e/plugin-eslint-e2e/vitest.e2e.config.ts" - } - } - }, - "implicitDependencies": ["cli", "plugin-eslint"], - "tags": ["scope:plugin", "type:e2e"] + "e2e": {} + } } diff --git a/e2e/plugin-js-packages-e2e/project.json b/e2e/plugin-js-packages-e2e/project.json index 901c92dd4..d1aaaaf01 100644 --- a/e2e/plugin-js-packages-e2e/project.json +++ b/e2e/plugin-js-packages-e2e/project.json @@ -3,15 +3,10 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "projectType": "application", "sourceRoot": "e2e/plugin-js-packages-e2e/src", + "tags": ["scope:plugin", "type:e2e"], "implicitDependencies": ["cli", "plugin-js-packages"], "targets": { "lint": {}, - "e2e": { - "executor": "@nx/vite:test", - "options": { - "configFile": "e2e/plugin-eslint-e2e/vitest.e2e.config.ts" - } - } - }, - "tags": ["scope:plugin", "type:e2e"] + "e2e": {} + } } diff --git a/examples/plugins/project.json b/examples/plugins/project.json index f64b7c7b7..8f784340b 100644 --- a/examples/plugins/project.json +++ b/examples/plugins/project.json @@ -4,37 +4,18 @@ "sourceRoot": "examples/plugins/src", "projectType": "library", "targets": { - "build": { - "executor": "@nx/js:tsc", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/examples/plugins", - "main": "examples/plugins/src/index.ts", - "tsConfig": "examples/plugins/tsconfig.lib.json", - "assets": ["examples/plugins/*.md"] - } - }, - "lint": { - "executor": "@nx/linter:eslint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": ["examples/plugins/**/*.ts"] - } - }, - "unit-test": { - "executor": "@nx/vite:test", - "outputs": ["{options.reportsDirectory}"], - "options": { - "configFile": "examples/plugins/vitest.unit.config.ts", - "reportsDirectory": "../../coverage/examples-plugins/unit-tests" - } - }, + "build": {}, + "lint": {}, + "unit-test": {}, "int-test": { + "cache": true, + "outputs": ["{workspaceRoot}/coverage/{projectName}/int-tests/lcov.info"], "executor": "@nx/vite:test", - "outputs": ["{options.reportsDirectory}"], "options": { - "configFile": "examples/plugins/vitest.int.config.ts", - "reportsDirectory": "../../coverage/examples-plugins/int-tests" + "configFile": "{projectRoot}/vitest.int.config.ts", + "coverage": { + "enabled": true + } } }, "run-collect": { diff --git a/nx.json b/nx.json index 088d1d11d..816ba1b5a 100644 --- a/nx.json +++ b/nx.json @@ -16,6 +16,9 @@ }, "unit-test": { "cache": true, + "outputs": [ + "{workspaceRoot}/coverage/{projectName}/unit-tests/lcov.info" + ], "executor": "@nx/vite:test", "options": { "configFile": "{projectRoot}/vitest.unit.config.ts", @@ -26,6 +29,7 @@ }, "int-test": { "cache": true, + "outputs": ["{workspaceRoot}/coverage/{projectName}/int-tests/lcov.info"], "executor": "@nx/vite:test", "options": { "configFile": "{projectRoot}/vitest.int.config.ts", @@ -34,6 +38,13 @@ } } }, + "e2e": { + "dependsOn": ["^build"], + "executor": "@nx/vite:test", + "options": { + "configFile": "{projectRoot}/vitest.e2e.config.ts" + } + }, "lint": { "inputs": ["default", "{workspaceRoot}/eslint.config.?(c)js"], "executor": "@nx/linter:eslint", @@ -47,9 +58,6 @@ ] } }, - "e2e": { - "dependsOn": ["^build"] - }, "nxv-pkg-install": { "parallelism": false }, diff --git a/packages/ci/project.json b/packages/ci/project.json index dbe33d05f..0b514dee8 100644 --- a/packages/ci/project.json +++ b/packages/ci/project.json @@ -8,6 +8,8 @@ "lint": {}, "unit-test": {}, "int-test": { + "cache": true, + "outputs": ["{workspaceRoot}/coverage/{projectName}/int-tests/lcov.info"], "executor": "@nx/vite:test", "options": { "configFile": "{projectRoot}/vitest.int.config.ts", diff --git a/packages/cli/project.json b/packages/cli/project.json index 9157b25ad..1de7d070f 100644 --- a/packages/cli/project.json +++ b/packages/cli/project.json @@ -8,6 +8,8 @@ "lint": {}, "unit-test": {}, "int-test": { + "cache": true, + "outputs": ["{workspaceRoot}/coverage/{projectName}/int-tests/lcov.info"], "executor": "@nx/vite:test", "options": { "configFile": "{projectRoot}/vitest.int.config.ts", diff --git a/packages/core/project.json b/packages/core/project.json index 4dbbe86c7..f543a6579 100644 --- a/packages/core/project.json +++ b/packages/core/project.json @@ -8,6 +8,8 @@ "lint": {}, "unit-test": {}, "int-test": { + "cache": true, + "outputs": ["{workspaceRoot}/coverage/{projectName}/int-tests/lcov.info"], "executor": "@nx/vite:test", "options": { "configFile": "{projectRoot}/vitest.int.config.ts", diff --git a/packages/create-cli/project.json b/packages/create-cli/project.json index 8e4b13b58..77c2af03d 100644 --- a/packages/create-cli/project.json +++ b/packages/create-cli/project.json @@ -8,6 +8,8 @@ "lint": {}, "unit-test": {}, "int-test": { + "cache": true, + "outputs": ["{workspaceRoot}/coverage/{projectName}/int-tests/lcov.info"], "executor": "@nx/vite:test", "options": { "configFile": "{projectRoot}/vitest.int.config.ts", diff --git a/packages/nx-plugin/project.json b/packages/nx-plugin/project.json index 1ec43129e..4d3763b49 100644 --- a/packages/nx-plugin/project.json +++ b/packages/nx-plugin/project.json @@ -43,6 +43,8 @@ }, "unit-test": {}, "int-test": { + "cache": true, + "outputs": ["{workspaceRoot}/coverage/{projectName}/int-tests/lcov.info"], "executor": "@nx/vite:test", "options": { "configFile": "{projectRoot}/vitest.int.config.ts", diff --git a/packages/plugin-coverage/project.json b/packages/plugin-coverage/project.json index 670030ce1..f2188a633 100644 --- a/packages/plugin-coverage/project.json +++ b/packages/plugin-coverage/project.json @@ -8,6 +8,8 @@ "lint": {}, "unit-test": {}, "int-test": { + "cache": true, + "outputs": ["{workspaceRoot}/coverage/{projectName}/int-tests/lcov.info"], "executor": "@nx/vite:test", "options": { "configFile": "{projectRoot}/vitest.int.config.ts", diff --git a/packages/plugin-coverage/src/lib/nx/coverage-paths.ts b/packages/plugin-coverage/src/lib/nx/coverage-paths.ts index a74b0a195..fdf734ae2 100644 --- a/packages/plugin-coverage/src/lib/nx/coverage-paths.ts +++ b/packages/plugin-coverage/src/lib/nx/coverage-paths.ts @@ -18,6 +18,7 @@ import type { CoverageResult } from '../config.js'; export async function getNxCoveragePaths( targets: string[] = ['test'], verbose?: boolean, + exclude?: string[], ): Promise { if (verbose) { ui().logger.info( @@ -34,8 +35,12 @@ export async function getNxCoveragePaths( hasNxTarget(graph, target), ); + const filteredNodes = exclude?.length + ? relevantNodes.filter(node => !exclude.includes(node.name)) + : relevantNodes; + return await Promise.all( - relevantNodes.map>(async ({ name, data }) => { + filteredNodes.map>(async ({ name, data }) => { const coveragePaths = await getCoveragePathsForTarget(data, target); if (verbose) { ui().logger.info(`- ${name}: ${target}`); diff --git a/packages/plugin-eslint/project.json b/packages/plugin-eslint/project.json index 49fc49313..3d8cb9a6c 100644 --- a/packages/plugin-eslint/project.json +++ b/packages/plugin-eslint/project.json @@ -8,6 +8,8 @@ "lint": {}, "unit-test": {}, "int-test": { + "cache": true, + "outputs": ["{workspaceRoot}/coverage/{projectName}/int-tests/lcov.info"], "executor": "@nx/vite:test", "options": { "configFile": "{projectRoot}/vitest.int.config.ts", diff --git a/packages/plugin-js-packages/project.json b/packages/plugin-js-packages/project.json index 9164982fc..0c084d3ca 100644 --- a/packages/plugin-js-packages/project.json +++ b/packages/plugin-js-packages/project.json @@ -8,6 +8,8 @@ "lint": {}, "unit-test": {}, "int-test": { + "cache": true, + "outputs": ["{workspaceRoot}/coverage/{projectName}/int-tests/lcov.info"], "executor": "@nx/vite:test", "options": { "configFile": "{projectRoot}/vitest.int.config.ts", diff --git a/packages/plugin-jsdocs/project.json b/packages/plugin-jsdocs/project.json index b08eaec07..fbb7ea361 100644 --- a/packages/plugin-jsdocs/project.json +++ b/packages/plugin-jsdocs/project.json @@ -9,6 +9,8 @@ "lint": {}, "unit-test": {}, "int-test": { + "cache": true, + "outputs": ["{workspaceRoot}/coverage/{projectName}/int-tests/lcov.info"], "executor": "@nx/vite:test", "options": { "configFile": "{projectRoot}/vitest.int.config.ts", diff --git a/packages/plugin-lighthouse/project.json b/packages/plugin-lighthouse/project.json index f45bcf0c1..f664a4ce1 100644 --- a/packages/plugin-lighthouse/project.json +++ b/packages/plugin-lighthouse/project.json @@ -8,6 +8,8 @@ "lint": {}, "unit-test": {}, "int-test": { + "cache": true, + "outputs": ["{workspaceRoot}/coverage/{projectName}/int-tests/lcov.info"], "executor": "@nx/vite:test", "options": { "configFile": "{projectRoot}/vitest.int.config.ts", diff --git a/packages/plugin-typescript/project.json b/packages/plugin-typescript/project.json index 94698b289..10549bd1a 100644 --- a/packages/plugin-typescript/project.json +++ b/packages/plugin-typescript/project.json @@ -8,6 +8,8 @@ "lint": {}, "unit-test": {}, "int-test": { + "cache": true, + "outputs": ["{workspaceRoot}/coverage/{projectName}/int-tests/lcov.info"], "executor": "@nx/vite:test", "options": { "configFile": "{projectRoot}/vitest.int.config.ts", diff --git a/packages/utils/project.json b/packages/utils/project.json index 32b23aeb1..ebcfe1c4a 100644 --- a/packages/utils/project.json +++ b/packages/utils/project.json @@ -20,6 +20,8 @@ }, "unit-test": {}, "int-test": { + "cache": true, + "outputs": ["{workspaceRoot}/coverage/{projectName}/int-tests/lcov.info"], "executor": "@nx/vite:test", "options": { "configFile": "{projectRoot}/vitest.int.config.ts", From 28213f0b23794b7529825e8663d63da3e2a9830e Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 13 Aug 2025 01:54:37 +0200 Subject: [PATCH 035/111] chore: refine preset --- code-pushup.preset.ts | 52 ++++--------------- .../src/lib/nx/coverage-paths.ts | 7 +-- 2 files changed, 12 insertions(+), 47 deletions(-) diff --git a/code-pushup.preset.ts b/code-pushup.preset.ts index 55d20548c..15ba02ccc 100644 --- a/code-pushup.preset.ts +++ b/code-pushup.preset.ts @@ -100,16 +100,12 @@ export const eslintCategories: CategoryConfig[] = [ export function getJsDocsCategories( config: JsDocsPluginConfig, ): CategoryConfig[] { - const filterOptions = - typeof config === 'string' || Array.isArray(config) - ? {} - : { onlyAudits: config.onlyAudits, skipAudits: config.skipAudits }; return [ { slug: 'docs', title: 'Documentation', description: 'Measures how much of your code is **documented**.', - refs: filterGroupsByOnlyAudits(groups, filterOptions).map(group => ({ + refs: filterGroupsByOnlyAudits(groups, config).map(group => ({ weight: 1, type: 'group', plugin: PLUGIN_SLUG, @@ -163,13 +159,12 @@ export const jsDocsCoreConfig = ( export const eslintCoreConfigNx = async ( projectName?: string, - options?: { exclude?: string[] }, ): Promise => ({ plugins: [ await eslintPlugin( await (projectName ? eslintConfigFromNxProject(projectName) - : eslintConfigFromAllNxProjects(options)), + : eslintConfigFromAllNxProjects()), ), ], categories: eslintCategories, @@ -183,42 +178,18 @@ export const typescriptPluginConfig = async ( }); export const coverageCoreConfigNx = async ( - projectOrConfig?: - | string - | { - projectName: string; - targetNames: string[]; - }, - options?: { exclude?: string[] }, + projectName?: string, ): Promise => { - const projectName = - typeof projectOrConfig === 'string' - ? projectOrConfig - : projectOrConfig?.projectName; - const targetNames = - typeof projectOrConfig === 'object' && projectOrConfig?.targetNames?.length - ? projectOrConfig.targetNames - : ['unit-test', 'int-test']; - if (projectName) { throw new Error('coverageCoreConfigNx for single projects not implemented'); } - - const targetArgs = ['-t', ...targetNames]; - - // Compute projects list and apply exclude for efficient run-many execution - const { createProjectGraphAsync } = await import('@nx/devkit'); - const { nodes } = await createProjectGraphAsync({ exitOnError: false }); - const projectsWithTargets = Object.values(nodes).filter(node => - targetNames.some(t => node.data.targets && t in node.data.targets), - ); - const filteredProjects = options?.exclude?.length - ? projectsWithTargets.filter(node => !options.exclude!.includes(node.name)) - : projectsWithTargets; - const projectsArg = `--projects=${filteredProjects - .map(p => p.name) - .join(',')}`; - + const targetNames = ['unit-test', 'int-test']; + const targetArgs = [ + '-t', + ...targetNames, + '--coverage.enabled', + '--skipNxCache', + ]; return { plugins: [ await coveragePlugin({ @@ -228,10 +199,9 @@ export const coverageCoreConfigNx = async ( 'nx', projectName ? `run --project ${projectName}` : 'run-many', ...targetArgs, - projectsArg, ], }, - reports: await getNxCoveragePaths(targetNames, false, options?.exclude), + reports: await getNxCoveragePaths(targetNames), }), ], categories: coverageCategories, diff --git a/packages/plugin-coverage/src/lib/nx/coverage-paths.ts b/packages/plugin-coverage/src/lib/nx/coverage-paths.ts index fdf734ae2..a74b0a195 100644 --- a/packages/plugin-coverage/src/lib/nx/coverage-paths.ts +++ b/packages/plugin-coverage/src/lib/nx/coverage-paths.ts @@ -18,7 +18,6 @@ import type { CoverageResult } from '../config.js'; export async function getNxCoveragePaths( targets: string[] = ['test'], verbose?: boolean, - exclude?: string[], ): Promise { if (verbose) { ui().logger.info( @@ -35,12 +34,8 @@ export async function getNxCoveragePaths( hasNxTarget(graph, target), ); - const filteredNodes = exclude?.length - ? relevantNodes.filter(node => !exclude.includes(node.name)) - : relevantNodes; - return await Promise.all( - filteredNodes.map>(async ({ name, data }) => { + relevantNodes.map>(async ({ name, data }) => { const coveragePaths = await getCoveragePathsForTarget(data, target); if (verbose) { ui().logger.info(`- ${name}: ${target}`); From 139b9418179df5eec58825c7f6369a00835ea404 Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 13 Aug 2025 02:11:24 +0200 Subject: [PATCH 036/111] chore: refine targets --- e2e/plugin-lighthouse-e2e/project.json | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/e2e/plugin-lighthouse-e2e/project.json b/e2e/plugin-lighthouse-e2e/project.json index f8f4c9cb4..9aafc3cdc 100644 --- a/e2e/plugin-lighthouse-e2e/project.json +++ b/e2e/plugin-lighthouse-e2e/project.json @@ -5,12 +5,7 @@ "projectType": "application", "targets": { "lint": {}, - "e2e": { - "executor": "@nx/vite:test", - "options": { - "configFile": "e2e/plugin-lighthouse-e2e/vitest.e2e.config.ts" - } - } + "e2e": {} }, "implicitDependencies": ["cli", "plugin-lighthouse"], "tags": ["scope:plugin", "type:e2e"] From 454f9866e6563dcf37cfb37acaa653a8f6ddfd65 Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 13 Aug 2025 02:43:02 +0200 Subject: [PATCH 037/111] chore: refine targets 2 --- e2e/plugin-lighthouse-e2e/project.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/e2e/plugin-lighthouse-e2e/project.json b/e2e/plugin-lighthouse-e2e/project.json index 9aafc3cdc..a29950ee3 100644 --- a/e2e/plugin-lighthouse-e2e/project.json +++ b/e2e/plugin-lighthouse-e2e/project.json @@ -5,7 +5,12 @@ "projectType": "application", "targets": { "lint": {}, - "e2e": {} + "e2e": { + "executor": "@nx/vite:test", + "options": { + "configFile": "{projectRoot}/vitest.e2e.config.ts" + } + } }, "implicitDependencies": ["cli", "plugin-lighthouse"], "tags": ["scope:plugin", "type:e2e"] From 55bc6282ad4fb0338292a82eb7c4b374112768ca Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 13 Aug 2025 02:49:15 +0200 Subject: [PATCH 038/111] chore: refine targets 3 --- e2e/ci-e2e/project.json | 7 ++++++- e2e/cli-e2e/project.json | 13 +++++++++---- e2e/create-cli-e2e/project.json | 14 ++++++++++---- e2e/nx-plugin-e2e/project.json | 13 +++++++++---- e2e/plugin-coverage-e2e/project.json | 13 +++++++++---- e2e/plugin-eslint-e2e/project.json | 13 +++++++++---- e2e/plugin-js-packages-e2e/project.json | 11 ++++++++--- nx.json | 6 +----- 8 files changed, 61 insertions(+), 29 deletions(-) diff --git a/e2e/ci-e2e/project.json b/e2e/ci-e2e/project.json index 704b13730..f458d8d9d 100644 --- a/e2e/ci-e2e/project.json +++ b/e2e/ci-e2e/project.json @@ -5,7 +5,12 @@ "projectType": "application", "targets": { "lint": {}, - "e2e": {} + "e2e": { + "executor": "@nx/vite:test", + "options": { + "configFile": "{projectRoot}/vitest.e2e.config.ts" + } + } }, "implicitDependencies": ["cli", "ci"], "tags": ["scope:tooling", "type:e2e"] diff --git a/e2e/cli-e2e/project.json b/e2e/cli-e2e/project.json index 181dd4854..6cdabf9ae 100644 --- a/e2e/cli-e2e/project.json +++ b/e2e/cli-e2e/project.json @@ -3,10 +3,15 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "e2e/cli-e2e/src", "projectType": "application", - "tags": ["scope:core", "scope:plugin", "type:e2e"], - "implicitDependencies": ["cli"], "targets": { "lint": {}, - "e2e": {} - } + "e2e": { + "executor": "@nx/vite:test", + "options": { + "configFile": "{projectRoot}/vitest.e2e.config.ts" + } + } + }, + "implicitDependencies": ["cli"], + "tags": ["scope:core", "scope:plugin", "type:e2e"] } diff --git a/e2e/create-cli-e2e/project.json b/e2e/create-cli-e2e/project.json index aad7d6f5f..bf0b88071 100644 --- a/e2e/create-cli-e2e/project.json +++ b/e2e/create-cli-e2e/project.json @@ -3,10 +3,16 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "examples/create-cli-e2e/src", "projectType": "application", - "tags": ["scope:tooling", "type:e2e"], - "implicitDependencies": ["create-cli"], "targets": { "lint": {}, - "e2e": {} - } + "e2e": { + "executor": "@nx/vite:test", + "options": { + "keepServerRunning": true, + "configFile": "{projectRoot}/vitest.e2e.config.ts" + } + } + }, + "implicitDependencies": ["create-cli"], + "tags": ["scope:tooling", "type:e2e"] } diff --git a/e2e/nx-plugin-e2e/project.json b/e2e/nx-plugin-e2e/project.json index 1c7d2a00f..f569a465f 100644 --- a/e2e/nx-plugin-e2e/project.json +++ b/e2e/nx-plugin-e2e/project.json @@ -3,10 +3,15 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "e2e/nx-plugin-e2e/src", "projectType": "application", - "tags": ["scope:tooling", "type:e2e"], - "implicitDependencies": ["test-utils", "nx-plugin"], "targets": { "lint": {}, - "e2e": {} - } + "e2e": { + "executor": "@nx/vite:test", + "options": { + "configFile": "{projectRoot}/vitest.e2e.config.ts" + } + } + }, + "implicitDependencies": ["test-utils", "nx-plugin"], + "tags": ["scope:tooling", "type:e2e"] } diff --git a/e2e/plugin-coverage-e2e/project.json b/e2e/plugin-coverage-e2e/project.json index f8a9e46e9..ca5b5b3fd 100644 --- a/e2e/plugin-coverage-e2e/project.json +++ b/e2e/plugin-coverage-e2e/project.json @@ -3,10 +3,15 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "e2e/plugin-coverage-e2e/src", "projectType": "application", - "tags": ["scope:plugin", "type:e2e"], - "implicitDependencies": ["cli", "plugin-coverage"], "targets": { "lint": {}, - "e2e": {} - } + "e2e": { + "executor": "@nx/vite:test", + "options": { + "configFile": "{projectRoot}/vitest.e2e.config.ts" + } + } + }, + "implicitDependencies": ["cli", "plugin-coverage"], + "tags": ["scope:plugin", "type:e2e"] } diff --git a/e2e/plugin-eslint-e2e/project.json b/e2e/plugin-eslint-e2e/project.json index 82e3ff70b..c4000be23 100644 --- a/e2e/plugin-eslint-e2e/project.json +++ b/e2e/plugin-eslint-e2e/project.json @@ -3,10 +3,15 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "e2e/plugin-eslint-e2e/src", "projectType": "application", - "tags": ["scope:plugin", "type:e2e"], - "implicitDependencies": ["cli", "plugin-eslint"], "targets": { "lint": {}, - "e2e": {} - } + "e2e": { + "executor": "@nx/vite:test", + "options": { + "configFile": "{projectRoot}/vitest.e2e.config.ts" + } + } + }, + "implicitDependencies": ["cli", "plugin-eslint"], + "tags": ["scope:plugin", "type:e2e"] } diff --git a/e2e/plugin-js-packages-e2e/project.json b/e2e/plugin-js-packages-e2e/project.json index d1aaaaf01..5c6382c06 100644 --- a/e2e/plugin-js-packages-e2e/project.json +++ b/e2e/plugin-js-packages-e2e/project.json @@ -3,10 +3,15 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "projectType": "application", "sourceRoot": "e2e/plugin-js-packages-e2e/src", - "tags": ["scope:plugin", "type:e2e"], "implicitDependencies": ["cli", "plugin-js-packages"], "targets": { "lint": {}, - "e2e": {} - } + "e2e": { + "executor": "@nx/vite:test", + "options": { + "configFile": "{projectRoot}/vitest.e2e.config.ts" + } + } + }, + "tags": ["scope:plugin", "type:e2e"] } diff --git a/nx.json b/nx.json index 816ba1b5a..9fa2bacf6 100644 --- a/nx.json +++ b/nx.json @@ -39,11 +39,7 @@ } }, "e2e": { - "dependsOn": ["^build"], - "executor": "@nx/vite:test", - "options": { - "configFile": "{projectRoot}/vitest.e2e.config.ts" - } + "dependsOn": ["^build"] }, "lint": { "inputs": ["default", "{workspaceRoot}/eslint.config.?(c)js"], From 622a5acbfff9d296d5c9c41ca8494902a596100e Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 13 Aug 2025 03:04:09 +0200 Subject: [PATCH 039/111] chore: refine targets 4 --- .github/workflows/code-pushup.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/code-pushup.yml b/.github/workflows/code-pushup.yml index a5136b1ff..26e217d10 100644 --- a/.github/workflows/code-pushup.yml +++ b/.github/workflows/code-pushup.yml @@ -26,16 +26,19 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Set up Node.js uses: actions/setup-node@v4 with: node-version-file: .nvmrc cache: npm - name: Set base and head for Nx affected commands + id: nx-set-shas uses: nrwl/nx-set-shas@v4 - name: Install dependencies run: npm ci - name: Run Code PushUp action uses: code-pushup/github-action@v0 with: - bin: npx nx affected -t code-pushup --parallel=3 -- + bin: npx nx affected -t code-pushup --parallel=3 --base=${{ steps.nx-set-shas.outputs.base }} --head=${{ steps.nx-set-shas.outputs.head }} -- From 503be8f8f104be10b88c2929280ad3ecb7d8cacb Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 13 Aug 2025 03:23:37 +0200 Subject: [PATCH 040/111] chore: refine targets 5 --- nx.json | 14 +++++++------- packages/cli/docs/nx-caching.md | 26 ++++++++++++++++++-------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/nx.json b/nx.json index d96efaa7c..c02287c90 100644 --- a/nx.json +++ b/nx.json @@ -66,7 +66,7 @@ }, "code-pushup-coverage": { "cache": true, - "outputs": ["{projectRoot}/.code-pushup/coverage"], + "outputs": ["{projectRoot}/.code-pushup/coverage/runner-output.json"], "executor": "nx:run-commands", "dependsOn": ["unit-test", "int-test"], "options": { @@ -88,7 +88,7 @@ }, "code-pushup-eslint": { "cache": true, - "outputs": ["{projectRoot}/.code-pushup/eslint"], + "outputs": ["{projectRoot}/.code-pushup/eslint/runner-output.json"], "executor": "nx:run-commands", "options": { "command": "node packages/cli/src/index.ts collect", @@ -109,7 +109,7 @@ }, "code-pushup-js-packages": { "cache": false, - "outputs": ["{projectRoot}/.code-pushup/js-packages"], + "outputs": ["{projectRoot}/.code-pushup/js-packages/runner-output.json"], "executor": "nx:run-commands", "options": { "command": "node packages/cli/src/index.ts collect", @@ -130,10 +130,10 @@ }, "code-pushup-lighthouse": { "cache": true, - "outputs": ["{projectRoot}/.code-pushup/lighthouse"], + "outputs": ["{projectRoot}/.code-pushup/lighthouse/runner-output.json"], "executor": "nx:run-commands", "options": { - "command": "node packages/cli/src/index.ts", + "command": "node packages/cli/src/index.ts collect", "args": [ "--no-progress", "--verbose", @@ -151,7 +151,7 @@ }, "code-pushup-jsdocs": { "cache": true, - "outputs": ["{projectRoot}/.code-pushup/jsdocs"], + "outputs": ["{projectRoot}/.code-pushup/jsdocs/runner-output.json"], "executor": "nx:run-commands", "options": { "command": "node packages/cli/src/index.ts collect", @@ -173,7 +173,7 @@ "code-pushup-typescript": { "cache": true, "inputs": ["default", "^default", "{projectRoot}/tsconfig.lib.json"], - "outputs": ["{projectRoot}/.code-pushup/typescript"], + "outputs": ["{projectRoot}/.code-pushup/typescript/runner-output.json"], "executor": "nx:run-commands", "options": { "command": "node packages/cli/src/index.ts collect", diff --git a/packages/cli/docs/nx-caching.md b/packages/cli/docs/nx-caching.md index ce3f95f52..f2257c1f2 100644 --- a/packages/cli/docs/nx-caching.md +++ b/packages/cli/docs/nx-caching.md @@ -49,9 +49,17 @@ export default { "coverage.reportsDirectory": "{projectRoot}/coverage/unit-test" } }, + "code-pushup-js-packages": { + "cache": false, + "executor": "nx:run-commands", + "options": { + "command": "npx @code-pushup/cli collect", + "args": ["--config={projectRoot}/code-pushup.config.ts", "--cache.write=true", "--persist.skipReports=true", "--persist.outputDir={projectRoot}/.code-pushup", "--upload.project={projectName}"] + } + }, "code-pushup-coverage": { "cache": true, - "outputs": ["{projectRoot}/.code-pushup/coverage"], + "outputs": ["{projectRoot}/.code-pushup/coverage/runner-output.json"], "executor": "nx:run-commands", "options": { "command": "npx @code-pushup/cli collect", @@ -61,13 +69,13 @@ export default { }, "code-pushup": { "cache": true, - "outputs": ["{projectRoot}/.code-pushup"], + "outputs": ["{projectRoot}/.code-pushup/report.*"], "executor": "nx:run-commands", "options": { "command": "npx @code-pushup/cli", "args": ["--config={projectRoot}/code-pushup.config.ts", "--cache.read=true", "--persist.outputDir={projectRoot}/.code-pushup", "--upload.project={projectName}"] }, - "dependsOn": ["code-pushup-coverage"] + "dependsOn": ["code-pushup-coverage", "code-pushup-js-packages"] } } } @@ -80,12 +88,14 @@ This configuration creates the following task dependency graph: **Legend:** - 🐳 = Cached target +- 💾 = Parallel execution ```mermaid graph TD - A[lib-a:code-pushup 🐳] --> B[lib-a:code-pushup-coverage 🐳] - B --> C[lib-a:unit-test 🐳] - B --> D[lib-a:int-test 🐳] + A[lib-a:code-pushup 🐳] --> B[lib-a:code-pushup-coverage 💾🐳] + A --> C[lib-a:code-pushup-js-packages 💾] + B --> C[lib-a:unit-test 💾🐳] + B --> D[lib-a:int-test 💾🐳] ``` ## Command Line Example @@ -100,7 +110,7 @@ nx affected --target=code-pushup This approach has the following benefits: -1. **Parallel Execution**: Plugins can run in parallel -2. **Fine-grained Caching**: Code level cache invalidation enables usage of [affected](https://nx.dev/recipes/affected-tasks) command +1. **💾 Parallel Execution**: Plugins can run in parallel +2. **🐳 Fine-grained Caching**: Code level cache invalidation enables usage of [affected](https://nx.dev/recipes/affected-tasks) command 3. **Dependency Management**: Leverage Nx task dependencies and its caching strategy 4. **Clear Separation**: Each plugin has its own target for better debugging and maintainability From 503b076b5d06f8406368d6c16bf6c800b01ad9e1 Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 13 Aug 2025 03:23:51 +0200 Subject: [PATCH 041/111] chore: refine targets 6 --- .github/workflows/code-pushup.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/code-pushup.yml b/.github/workflows/code-pushup.yml index 26e217d10..56a8fd2fa 100644 --- a/.github/workflows/code-pushup.yml +++ b/.github/workflows/code-pushup.yml @@ -34,11 +34,10 @@ jobs: node-version-file: .nvmrc cache: npm - name: Set base and head for Nx affected commands - id: nx-set-shas uses: nrwl/nx-set-shas@v4 - name: Install dependencies run: npm ci - name: Run Code PushUp action uses: code-pushup/github-action@v0 with: - bin: npx nx affected -t code-pushup --parallel=3 --base=${{ steps.nx-set-shas.outputs.base }} --head=${{ steps.nx-set-shas.outputs.head }} -- + bin: npx nx affected -t code-pushup --parallel=3 -- From 1d5bb72625ee772b1a045b7a25f1dcee83ceb428 Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 13 Aug 2025 03:41:28 +0200 Subject: [PATCH 042/111] chore: refine gh action --- .github/workflows/code-pushup-fork.yml | 2 +- .github/workflows/code-pushup.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/code-pushup-fork.yml b/.github/workflows/code-pushup-fork.yml index 4dd08dbb1..ff9eaad97 100644 --- a/.github/workflows/code-pushup-fork.yml +++ b/.github/workflows/code-pushup-fork.yml @@ -37,4 +37,4 @@ jobs: - name: Run Code PushUp action uses: code-pushup/github-action@v0 with: - bin: npx nx affected -t code-pushup --parallel=3 -- + bin: npx nx affected -t code-pushup --parallel=1 -- diff --git a/.github/workflows/code-pushup.yml b/.github/workflows/code-pushup.yml index 56a8fd2fa..9fdf2e333 100644 --- a/.github/workflows/code-pushup.yml +++ b/.github/workflows/code-pushup.yml @@ -40,4 +40,4 @@ jobs: - name: Run Code PushUp action uses: code-pushup/github-action@v0 with: - bin: npx nx affected -t code-pushup --parallel=3 -- + bin: npx nx affected -t code-pushup --parallel=1 -- From 5c247087f0fb08a6f04b9f93f477f393f61a8217 Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 13 Aug 2025 04:05:53 +0200 Subject: [PATCH 043/111] chore: refine preset --- code-pushup.preset.ts | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/code-pushup.preset.ts b/code-pushup.preset.ts index e0d6ab2bc..5ccb7964d 100644 --- a/code-pushup.preset.ts +++ b/code-pushup.preset.ts @@ -16,9 +16,8 @@ import eslintPlugin, { eslintConfigFromNxProject, } from './packages/plugin-eslint/src/index.js'; import jsPackagesPlugin from './packages/plugin-js-packages/src/index.js'; -import jsDocsPlugin, { - JsDocsPluginConfig, -} from './packages/plugin-jsdocs/src/index.js'; +import jsDocsPlugin from './packages/plugin-jsdocs/src/index.js'; +import type { JsDocsPluginConfig } from './packages/plugin-jsdocs/src/index.js'; import { PLUGIN_SLUG, groups, @@ -65,11 +64,7 @@ export async function loadEnv( ? { project: env.CP_PROJECT } : { project: projectName }), }; - return ( - uploadConfig.apiKey && { - upload: uploadConfig, - } - ); + return uploadConfig.apiKey ? { upload: uploadConfig } : {}; } /** @@ -221,11 +216,12 @@ export const eslintCoreConfigNx = async ( projectName?: string, ): Promise => ({ plugins: [ - await eslintPlugin( - await (projectName - ? eslintConfigFromNxProject(projectName) - : eslintConfigFromAllNxProjects()), - ), + projectName + ? await eslintPlugin({ + eslintrc: `packages/${projectName}/eslint.config.js`, + patterns: ['.'], + }) + : await eslintPlugin(await eslintConfigFromAllNxProjects()), ], categories: eslintCategories, }); @@ -259,10 +255,14 @@ export const coverageCoreConfigNx = async ( ? ['nx', 'run-many', '-p', projectName, ...targetArgs] : ['nx', 'run-many', ...targetArgs], }, - reports: await getNxCoveragePaths({ - targets: targetNames, - projects: projectName ? [projectName] : undefined, - }), + reports: projectName + ? [ + // Prefer Jest default dir; adjust if your project uses Vitest + `packages/${projectName}/coverage/lcov.info`, + ] + : await getNxCoveragePaths({ + targets: targetNames, + }), }), ], categories: coverageCategories, From 3541c80eb3e8e3e5906d4301184183da5d7865da Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 13 Aug 2025 04:13:12 +0200 Subject: [PATCH 044/111] chore: refine preset 2 --- code-pushup.preset.ts | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/code-pushup.preset.ts b/code-pushup.preset.ts index 15ba02ccc..a1551a4b9 100644 --- a/code-pushup.preset.ts +++ b/code-pushup.preset.ts @@ -11,9 +11,8 @@ import eslintPlugin, { eslintConfigFromNxProject, } from './packages/plugin-eslint/src/index.js'; import jsPackagesPlugin from './packages/plugin-js-packages/src/index.js'; -import jsDocsPlugin, { - JsDocsPluginConfig, -} from './packages/plugin-jsdocs/src/index.js'; +import jsDocsPlugin from './packages/plugin-jsdocs/src/index.js'; +import type { JsDocsPluginTransformedConfig } from './packages/plugin-jsdocs/src/lib/config.js'; import { PLUGIN_SLUG, groups, @@ -98,7 +97,7 @@ export const eslintCategories: CategoryConfig[] = [ ]; export function getJsDocsCategories( - config: JsDocsPluginConfig, + config: JsDocsPluginTransformedConfig, ): CategoryConfig[] { return [ { @@ -147,7 +146,7 @@ export const lighthouseCoreConfig = async ( }; export const jsDocsCoreConfig = ( - config: JsDocsPluginConfig | string[], + config: JsDocsPluginTransformedConfig | string[], ): CoreConfig => ({ plugins: [ jsDocsPlugin(Array.isArray(config) ? { patterns: config } : config), @@ -180,9 +179,6 @@ export const typescriptPluginConfig = async ( export const coverageCoreConfigNx = async ( projectName?: string, ): Promise => { - if (projectName) { - throw new Error('coverageCoreConfigNx for single projects not implemented'); - } const targetNames = ['unit-test', 'int-test']; const targetArgs = [ '-t', @@ -195,13 +191,18 @@ export const coverageCoreConfigNx = async ( await coveragePlugin({ coverageToolCommand: { command: 'npx', - args: [ - 'nx', - projectName ? `run --project ${projectName}` : 'run-many', - ...targetArgs, - ], + args: projectName + ? ['nx', 'run-many', '-p', projectName, ...targetArgs] + : ['nx', 'run-many', ...targetArgs], }, - reports: await getNxCoveragePaths(targetNames), + reports: projectName + ? [ + { + pathToProject: `packages/${projectName}`, + resultsPath: `packages/${projectName}/coverage/lcov.info`, + }, + ] + : await getNxCoveragePaths(targetNames), }), ], categories: coverageCategories, From 52612d77926658abd551d5fb8ea51a1c86be62ea Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 13 Aug 2025 04:14:51 +0200 Subject: [PATCH 045/111] fix: avoid graph generation if possible --- .github/workflows/code-pushup.yml | 2 +- code-pushup.preset.ts | 42 +++++++++++++++---------------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/.github/workflows/code-pushup.yml b/.github/workflows/code-pushup.yml index 9fdf2e333..56a8fd2fa 100644 --- a/.github/workflows/code-pushup.yml +++ b/.github/workflows/code-pushup.yml @@ -40,4 +40,4 @@ jobs: - name: Run Code PushUp action uses: code-pushup/github-action@v0 with: - bin: npx nx affected -t code-pushup --parallel=1 -- + bin: npx nx affected -t code-pushup --parallel=3 -- diff --git a/code-pushup.preset.ts b/code-pushup.preset.ts index e66b76eef..5b192e0b8 100644 --- a/code-pushup.preset.ts +++ b/code-pushup.preset.ts @@ -1,5 +1,4 @@ /* eslint-disable @nx/enforce-module-boundaries */ -import { z } from 'zod'; import type { CategoryConfig, CoreConfig, @@ -9,12 +8,10 @@ import coveragePlugin, { } from './packages/plugin-coverage/src/index.js'; import eslintPlugin, { eslintConfigFromAllNxProjects, - eslintConfigFromNxProject, } from './packages/plugin-eslint/src/index.js'; import jsPackagesPlugin from './packages/plugin-js-packages/src/index.js'; -import jsDocsPlugin, { - JsDocsPluginConfig, -} from './packages/plugin-jsdocs/src/index.js'; +import jsDocsPlugin from './packages/plugin-jsdocs/src/index.js'; +import type { JsDocsPluginTransformedConfig } from './packages/plugin-jsdocs/src/lib/config.js'; import { PLUGIN_SLUG, groups, @@ -137,7 +134,7 @@ export const eslintCategories: CategoryConfig[] = [ ]; export function getJsDocsCategories( - config: JsDocsPluginConfig, + config: JsDocsPluginTransformedConfig, ): CategoryConfig[] { return [ { @@ -186,7 +183,7 @@ export const lighthouseCoreConfig = async ( }; export const jsDocsCoreConfig = ( - config: JsDocsPluginConfig | string[], + config: JsDocsPluginTransformedConfig | string[], ): CoreConfig => ({ plugins: [ jsDocsPlugin(Array.isArray(config) ? { patterns: config } : config), @@ -200,11 +197,12 @@ export const eslintCoreConfigNx = async ( projectName?: string, ): Promise => ({ plugins: [ - await eslintPlugin( - await (projectName - ? eslintConfigFromNxProject(projectName) - : eslintConfigFromAllNxProjects()), - ), + projectName + ? await eslintPlugin({ + eslintrc: `packages/${projectName}/eslint.config.js`, + patterns: ['.'], + }) + : await eslintPlugin(await eslintConfigFromAllNxProjects()), ], categories: eslintCategories, }); @@ -219,9 +217,6 @@ export const typescriptPluginConfig = async ( export const coverageCoreConfigNx = async ( projectName?: string, ): Promise => { - if (projectName) { - throw new Error('coverageCoreConfigNx for single projects not implemented'); - } const targetNames = ['unit-test', 'int-test']; const targetArgs = [ '-t', @@ -234,13 +229,18 @@ export const coverageCoreConfigNx = async ( await coveragePlugin({ coverageToolCommand: { command: 'npx', - args: [ - 'nx', - projectName ? `run --project ${projectName}` : 'run-many', - ...targetArgs, - ], + args: projectName + ? ['nx', 'run-many', '-p', projectName, ...targetArgs] + : ['nx', 'run-many', ...targetArgs], }, - reports: await getNxCoveragePaths(targetNames), + reports: projectName + ? [ + { + pathToProject: `packages/${projectName}`, + resultsPath: `packages/${projectName}/coverage/lcov.info`, + }, + ] + : await getNxCoveragePaths(targetNames), }), ], categories: coverageCategories, From a9c3afaf8b1a10a61e5295ca84eecd7cac012fec Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 13 Aug 2025 04:19:10 +0200 Subject: [PATCH 046/111] fix: imports --- code-pushup.preset.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code-pushup.preset.ts b/code-pushup.preset.ts index 5b192e0b8..94ea8306c 100644 --- a/code-pushup.preset.ts +++ b/code-pushup.preset.ts @@ -1,4 +1,6 @@ /* eslint-disable @nx/enforce-module-boundaries */ +import 'dotenv/config'; +import { z } from 'zod'; import type { CategoryConfig, CoreConfig, From 6234d00ee682a631dd5c39c9231710f430a1c09a Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 13 Aug 2025 04:53:22 +0200 Subject: [PATCH 047/111] merge --- packages/nx-plugin/project.json | 3 +++ testing/test-nx-utils/tsconfig.json | 6 +++++- testing/test-nx-utils/tsconfig.lib.json | 1 + testing/test-setup/tsconfig.json | 6 +++++- testing/test-setup/tsconfig.lib.json | 1 + testing/test-utils/tsconfig.lib.json | 1 + 6 files changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/nx-plugin/project.json b/packages/nx-plugin/project.json index e39dfcaad..f1b646e4f 100644 --- a/packages/nx-plugin/project.json +++ b/packages/nx-plugin/project.json @@ -41,6 +41,9 @@ } }, "unit-test": {}, + "build": {}, + "lint": {}, + "unit-test": {}, "int-test": { "cache": true, "outputs": ["{workspaceRoot}/coverage/{projectName}/int-tests/lcov.info"], diff --git a/testing/test-nx-utils/tsconfig.json b/testing/test-nx-utils/tsconfig.json index c370491f9..aab1b622a 100644 --- a/testing/test-nx-utils/tsconfig.json +++ b/testing/test-nx-utils/tsconfig.json @@ -8,7 +8,8 @@ "noPropertyAccessFromIndexSignature": true, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, - "types": ["vitest"] + "types": ["vitest"], + "rootDir": ".." }, "files": [], "include": [], @@ -18,6 +19,9 @@ }, { "path": "./tsconfig.test.json" + }, + { + "path": "../test-utils/tsconfig.lib.json" } ] } diff --git a/testing/test-nx-utils/tsconfig.lib.json b/testing/test-nx-utils/tsconfig.lib.json index 09cc715cc..3750702ca 100644 --- a/testing/test-nx-utils/tsconfig.lib.json +++ b/testing/test-nx-utils/tsconfig.lib.json @@ -2,6 +2,7 @@ "extends": "./tsconfig.json", "compilerOptions": { "outDir": "../dist/out-tsc", + "rootDir": "../../", "declaration": true, "types": ["node"] }, diff --git a/testing/test-setup/tsconfig.json b/testing/test-setup/tsconfig.json index 465306e46..1a2fbb2f5 100644 --- a/testing/test-setup/tsconfig.json +++ b/testing/test-setup/tsconfig.json @@ -7,7 +7,8 @@ "noImplicitOverride": true, "noPropertyAccessFromIndexSignature": true, "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true + "noFallthroughCasesInSwitch": true, + "rootDir": ".." }, "files": [], "include": [], @@ -17,6 +18,9 @@ }, { "path": "./tsconfig.test.json" + }, + { + "path": "../test-utils/tsconfig.lib.json" } ] } diff --git a/testing/test-setup/tsconfig.lib.json b/testing/test-setup/tsconfig.lib.json index 3cc313086..fec0e233c 100644 --- a/testing/test-setup/tsconfig.lib.json +++ b/testing/test-setup/tsconfig.lib.json @@ -2,6 +2,7 @@ "extends": "./tsconfig.json", "compilerOptions": { "outDir": "../dist/out-tsc", + "rootDir": "../../", "declaration": true, "types": ["node"] }, diff --git a/testing/test-utils/tsconfig.lib.json b/testing/test-utils/tsconfig.lib.json index 3975fe4ed..eeb3208f4 100644 --- a/testing/test-utils/tsconfig.lib.json +++ b/testing/test-utils/tsconfig.lib.json @@ -3,6 +3,7 @@ "compilerOptions": { "outDir": "../dist/out-tsc", "declaration": true, + "composite": true, "types": ["node"] }, "include": ["src/**/*.ts"], From 61eb942f940658ef9b5a37729161cc788d93dab1 Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 13 Aug 2025 17:10:36 +0200 Subject: [PATCH 048/111] chore: adjust int-test targets --- packages/ci/project.json | 12 +----------- packages/cli/project.json | 12 +----------- packages/core/project.json | 12 +----------- packages/create-cli/project.json | 12 +----------- packages/models/project.json | 8 +------- packages/nx-plugin/project.json | 12 +----------- packages/plugin-coverage/project.json | 12 +----------- packages/plugin-eslint/project.json | 12 +----------- packages/plugin-js-packages/project.json | 12 +----------- packages/plugin-jsdocs/project.json | 12 +----------- packages/plugin-lighthouse/project.json | 12 +----------- packages/plugin-typescript/project.json | 12 +----------- packages/utils/project.json | 12 +----------- 13 files changed, 13 insertions(+), 139 deletions(-) diff --git a/packages/ci/project.json b/packages/ci/project.json index 0b514dee8..9215f87b3 100644 --- a/packages/ci/project.json +++ b/packages/ci/project.json @@ -7,17 +7,7 @@ "build": {}, "lint": {}, "unit-test": {}, - "int-test": { - "cache": true, - "outputs": ["{workspaceRoot}/coverage/{projectName}/int-tests/lcov.info"], - "executor": "@nx/vite:test", - "options": { - "configFile": "{projectRoot}/vitest.int.config.ts", - "coverage": { - "enabled": true - } - } - } + "int-test": {} }, "tags": ["scope:tooling", "type:feature", "publishable"] } diff --git a/packages/cli/project.json b/packages/cli/project.json index 1de7d070f..bc3b384a7 100644 --- a/packages/cli/project.json +++ b/packages/cli/project.json @@ -7,17 +7,7 @@ "build": {}, "lint": {}, "unit-test": {}, - "int-test": { - "cache": true, - "outputs": ["{workspaceRoot}/coverage/{projectName}/int-tests/lcov.info"], - "executor": "@nx/vite:test", - "options": { - "configFile": "{projectRoot}/vitest.int.config.ts", - "coverage": { - "enabled": true - } - } - }, + "int-test": {}, "run-help": { "command": "npx dist/packages/cli --help", "dependsOn": ["build"] diff --git a/packages/core/project.json b/packages/core/project.json index f543a6579..4924717c5 100644 --- a/packages/core/project.json +++ b/packages/core/project.json @@ -7,17 +7,7 @@ "build": {}, "lint": {}, "unit-test": {}, - "int-test": { - "cache": true, - "outputs": ["{workspaceRoot}/coverage/{projectName}/int-tests/lcov.info"], - "executor": "@nx/vite:test", - "options": { - "configFile": "{projectRoot}/vitest.int.config.ts", - "coverage": { - "enabled": true - } - } - } + "int-test": {} }, "tags": ["scope:core", "type:feature", "publishable"] } diff --git a/packages/create-cli/project.json b/packages/create-cli/project.json index 77c2af03d..2e7544e59 100644 --- a/packages/create-cli/project.json +++ b/packages/create-cli/project.json @@ -7,17 +7,7 @@ "build": {}, "lint": {}, "unit-test": {}, - "int-test": { - "cache": true, - "outputs": ["{workspaceRoot}/coverage/{projectName}/int-tests/lcov.info"], - "executor": "@nx/vite:test", - "options": { - "configFile": "{projectRoot}/vitest.int.config.ts", - "coverage": { - "enabled": true - } - } - }, + "int-test": {}, "exec-node": { "dependsOn": ["build"], "command": "node ./dist/packages/create-cli/src/index.js", diff --git a/packages/models/project.json b/packages/models/project.json index 9e8ff7b11..1d4453151 100644 --- a/packages/models/project.json +++ b/packages/models/project.json @@ -20,13 +20,7 @@ "lint": {}, "unit-test": {}, "int-test": { - "executor": "@nx/vite:test", - "options": { - "configFile": "{projectRoot}/vitest.int.config.ts", - "coverage": { - "enabled": true - } - } + "options": {} } }, "tags": ["scope:shared", "type:util", "publishable"] diff --git a/packages/nx-plugin/project.json b/packages/nx-plugin/project.json index 4d3763b49..52c8f2290 100644 --- a/packages/nx-plugin/project.json +++ b/packages/nx-plugin/project.json @@ -42,17 +42,7 @@ } }, "unit-test": {}, - "int-test": { - "cache": true, - "outputs": ["{workspaceRoot}/coverage/{projectName}/int-tests/lcov.info"], - "executor": "@nx/vite:test", - "options": { - "configFile": "{projectRoot}/vitest.int.config.ts", - "coverage": { - "enabled": true - } - } - } + "int-test": {} }, "tags": ["scope:tooling", "type:feature", "publishable"] } diff --git a/packages/plugin-coverage/project.json b/packages/plugin-coverage/project.json index f2188a633..edb62346f 100644 --- a/packages/plugin-coverage/project.json +++ b/packages/plugin-coverage/project.json @@ -7,17 +7,7 @@ "build": {}, "lint": {}, "unit-test": {}, - "int-test": { - "cache": true, - "outputs": ["{workspaceRoot}/coverage/{projectName}/int-tests/lcov.info"], - "executor": "@nx/vite:test", - "options": { - "configFile": "{projectRoot}/vitest.int.config.ts", - "coverage": { - "enabled": true - } - } - } + "int-test": {} }, "tags": ["scope:plugin", "type:feature", "publishable"] } diff --git a/packages/plugin-eslint/project.json b/packages/plugin-eslint/project.json index 3d8cb9a6c..241101850 100644 --- a/packages/plugin-eslint/project.json +++ b/packages/plugin-eslint/project.json @@ -7,17 +7,7 @@ "build": {}, "lint": {}, "unit-test": {}, - "int-test": { - "cache": true, - "outputs": ["{workspaceRoot}/coverage/{projectName}/int-tests/lcov.info"], - "executor": "@nx/vite:test", - "options": { - "configFile": "{projectRoot}/vitest.int.config.ts", - "coverage": { - "enabled": true - } - } - } + "int-test": {} }, "tags": ["scope:plugin", "type:feature", "publishable"] } diff --git a/packages/plugin-js-packages/project.json b/packages/plugin-js-packages/project.json index 0c084d3ca..9f0dc7789 100644 --- a/packages/plugin-js-packages/project.json +++ b/packages/plugin-js-packages/project.json @@ -7,17 +7,7 @@ "build": {}, "lint": {}, "unit-test": {}, - "int-test": { - "cache": true, - "outputs": ["{workspaceRoot}/coverage/{projectName}/int-tests/lcov.info"], - "executor": "@nx/vite:test", - "options": { - "configFile": "{projectRoot}/vitest.int.config.ts", - "coverage": { - "enabled": true - } - } - } + "int-test": {} }, "tags": ["scope:plugin", "type:feature", "publishable"], "description": "A plugin for JavaScript packages." diff --git a/packages/plugin-jsdocs/project.json b/packages/plugin-jsdocs/project.json index fbb7ea361..745540438 100644 --- a/packages/plugin-jsdocs/project.json +++ b/packages/plugin-jsdocs/project.json @@ -8,16 +8,6 @@ "build": {}, "lint": {}, "unit-test": {}, - "int-test": { - "cache": true, - "outputs": ["{workspaceRoot}/coverage/{projectName}/int-tests/lcov.info"], - "executor": "@nx/vite:test", - "options": { - "configFile": "{projectRoot}/vitest.int.config.ts", - "coverage": { - "enabled": true - } - } - } + "int-test": {} } } diff --git a/packages/plugin-lighthouse/project.json b/packages/plugin-lighthouse/project.json index f664a4ce1..5c639347b 100644 --- a/packages/plugin-lighthouse/project.json +++ b/packages/plugin-lighthouse/project.json @@ -7,17 +7,7 @@ "build": {}, "lint": {}, "unit-test": {}, - "int-test": { - "cache": true, - "outputs": ["{workspaceRoot}/coverage/{projectName}/int-tests/lcov.info"], - "executor": "@nx/vite:test", - "options": { - "configFile": "{projectRoot}/vitest.int.config.ts", - "coverage": { - "enabled": true - } - } - } + "int-test": {} }, "tags": ["scope:plugin", "type:feature", "publishable"] } diff --git a/packages/plugin-typescript/project.json b/packages/plugin-typescript/project.json index 10549bd1a..645259554 100644 --- a/packages/plugin-typescript/project.json +++ b/packages/plugin-typescript/project.json @@ -7,17 +7,7 @@ "build": {}, "lint": {}, "unit-test": {}, - "int-test": { - "cache": true, - "outputs": ["{workspaceRoot}/coverage/{projectName}/int-tests/lcov.info"], - "executor": "@nx/vite:test", - "options": { - "configFile": "{projectRoot}/vitest.int.config.ts", - "coverage": { - "enabled": true - } - } - } + "int-test": {} }, "tags": ["scope:plugin", "type:feature", "publishable"] } diff --git a/packages/utils/project.json b/packages/utils/project.json index ebcfe1c4a..021205deb 100644 --- a/packages/utils/project.json +++ b/packages/utils/project.json @@ -19,17 +19,7 @@ } }, "unit-test": {}, - "int-test": { - "cache": true, - "outputs": ["{workspaceRoot}/coverage/{projectName}/int-tests/lcov.info"], - "executor": "@nx/vite:test", - "options": { - "configFile": "{projectRoot}/vitest.int.config.ts", - "coverage": { - "enabled": true - } - } - } + "int-test": {} }, "tags": ["scope:shared", "type:util", "publishable"] } From 5b75d06fd6e34a8dc5322161a66a4355075c0de1 Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 13 Aug 2025 17:14:32 +0200 Subject: [PATCH 049/111] chore: adjust int-test target --- examples/plugins/project.json | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/examples/plugins/project.json b/examples/plugins/project.json index 8f784340b..1370e0782 100644 --- a/examples/plugins/project.json +++ b/examples/plugins/project.json @@ -7,17 +7,7 @@ "build": {}, "lint": {}, "unit-test": {}, - "int-test": { - "cache": true, - "outputs": ["{workspaceRoot}/coverage/{projectName}/int-tests/lcov.info"], - "executor": "@nx/vite:test", - "options": { - "configFile": "{projectRoot}/vitest.int.config.ts", - "coverage": { - "enabled": true - } - } - }, + "int-test": {}, "run-collect": { "command": "npx dist/packages/cli collect --config=examples/plugins/code-pushup.config.ts --persist.format=md", "dependsOn": [ From 867b3c690b774020eba00f749489b2528acb15bc Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 13 Aug 2025 17:43:25 +0200 Subject: [PATCH 050/111] chore: remove int-target as no int tests available --- packages/create-cli/project.json | 1 - packages/create-cli/vitest.int.config.ts | 29 ------------------------ 2 files changed, 30 deletions(-) delete mode 100644 packages/create-cli/vitest.int.config.ts diff --git a/packages/create-cli/project.json b/packages/create-cli/project.json index 2e7544e59..c2bc6ef60 100644 --- a/packages/create-cli/project.json +++ b/packages/create-cli/project.json @@ -7,7 +7,6 @@ "build": {}, "lint": {}, "unit-test": {}, - "int-test": {}, "exec-node": { "dependsOn": ["build"], "command": "node ./dist/packages/create-cli/src/index.js", diff --git a/packages/create-cli/vitest.int.config.ts b/packages/create-cli/vitest.int.config.ts deleted file mode 100644 index 2495fbe9c..000000000 --- a/packages/create-cli/vitest.int.config.ts +++ /dev/null @@ -1,29 +0,0 @@ -/// -import { defineConfig } from 'vite'; -import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js'; - -export default defineConfig({ - cacheDir: '../../node_modules/.vite/create-cli', - test: { - reporters: ['basic'], - globals: true, - cache: { - dir: '../../node_modules/.vitest', - }, - alias: tsconfigPathAliases(), - pool: 'threads', - poolOptions: { threads: { singleThread: true } }, - coverage: { - reporter: ['text', 'lcov'], - reportsDirectory: '../../coverage/create-cli/int-tests', - exclude: ['mocks/**', '**/types.ts'], - }, - environment: 'node', - include: ['src/**/*.int.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], - globalSetup: ['../../global-setup.ts'], - setupFiles: [ - '../../testing/test-setup/src/lib/console.mock.ts', - '../../testing/test-setup/src/lib/reset.mocks.ts', - ], - }, -}); From 88e43d59d63dd7e7f5ec9a298d56d502b69ed9b4 Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 13 Aug 2025 17:47:24 +0200 Subject: [PATCH 051/111] chore: add passWithNoTests:true to all test configs --- nx.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nx.json b/nx.json index e998706a8..99e48af53 100644 --- a/nx.json +++ b/nx.json @@ -22,6 +22,7 @@ "executor": "@nx/vite:test", "options": { "configFile": "{projectRoot}/vitest.unit.config.ts", + "passWithNoTests": true, "coverage": { "enabled": true } @@ -33,6 +34,7 @@ "executor": "@nx/vite:test", "options": { "configFile": "{projectRoot}/vitest.int.config.ts", + "passWithNoTests": true, "coverage": { "enabled": true } From bdb7f021695d27568f52491bf75a4abe4dea5352 Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 13 Aug 2025 17:52:42 +0200 Subject: [PATCH 052/111] chore: remove unused int test config from models and plugin-lighthouse --- packages/models/project.json | 5 +--- packages/models/vitest.int.config.ts | 29 ------------------ packages/plugin-lighthouse/project.json | 3 +- .../plugin-lighthouse/vitest.int.config.ts | 30 ------------------- 4 files changed, 2 insertions(+), 65 deletions(-) delete mode 100644 packages/models/vitest.int.config.ts delete mode 100644 packages/plugin-lighthouse/vitest.int.config.ts diff --git a/packages/models/project.json b/packages/models/project.json index 1d4453151..15981781f 100644 --- a/packages/models/project.json +++ b/packages/models/project.json @@ -18,10 +18,7 @@ ] }, "lint": {}, - "unit-test": {}, - "int-test": { - "options": {} - } + "unit-test": {} }, "tags": ["scope:shared", "type:util", "publishable"] } diff --git a/packages/models/vitest.int.config.ts b/packages/models/vitest.int.config.ts deleted file mode 100644 index fc651cceb..000000000 --- a/packages/models/vitest.int.config.ts +++ /dev/null @@ -1,29 +0,0 @@ -/// -import { defineConfig } from 'vite'; -import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js'; - -export default defineConfig({ - cacheDir: '../../node_modules/.vite/models', - test: { - reporters: ['basic'], - globals: true, - cache: { - dir: '../../node_modules/.vitest', - }, - alias: tsconfigPathAliases(), - pool: 'threads', - poolOptions: { threads: { singleThread: true } }, - coverage: { - reporter: ['text', 'lcov'], - reportsDirectory: '../../coverage/models/int-tests', - exclude: ['mocks/**', '**/types.ts', 'zod2md.config.ts'], - }, - environment: 'node', - include: ['src/**/*.int.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], - globalSetup: ['../../global-setup.ts'], - setupFiles: [ - '../../testing/test-setup/src/lib/console.mock.ts', - '../../testing/test-setup/src/lib/reset.mocks.ts', - ], - }, -}); diff --git a/packages/plugin-lighthouse/project.json b/packages/plugin-lighthouse/project.json index 5c639347b..b93152ffb 100644 --- a/packages/plugin-lighthouse/project.json +++ b/packages/plugin-lighthouse/project.json @@ -6,8 +6,7 @@ "targets": { "build": {}, "lint": {}, - "unit-test": {}, - "int-test": {} + "unit-test": {} }, "tags": ["scope:plugin", "type:feature", "publishable"] } diff --git a/packages/plugin-lighthouse/vitest.int.config.ts b/packages/plugin-lighthouse/vitest.int.config.ts deleted file mode 100644 index 6d7eae79b..000000000 --- a/packages/plugin-lighthouse/vitest.int.config.ts +++ /dev/null @@ -1,30 +0,0 @@ -/// -import { defineConfig } from 'vite'; -import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js'; - -export default defineConfig({ - cacheDir: '../../node_modules/.vite/plugin-lighthouse', - test: { - reporters: ['basic'], - globals: true, - cache: { - dir: '../../node_modules/.vitest', - }, - alias: tsconfigPathAliases(), - pool: 'threads', - poolOptions: { threads: { singleThread: true } }, - coverage: { - reporter: ['text', 'lcov'], - reportsDirectory: '../../coverage/plugin-lighthouse/int-tests', - exclude: ['mocks/**', '**/types.ts'], - }, - environment: 'node', - include: ['src/**/*.int.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], - globalSetup: ['../../global-setup.ts'], - setupFiles: [ - '../../testing/test-setup/src/lib/cliui.mock.ts', - '../../testing/test-setup/src/lib/reset.mocks.ts', - '../../testing/test-setup/src/lib/chrome-path.mock.ts', - ], - }, -}); From 95651288da4eb54eeb82734e2d00d404718942b6 Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 13 Aug 2025 18:21:47 +0200 Subject: [PATCH 053/111] chore: adjust preset --- code-pushup.preset.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/code-pushup.preset.ts b/code-pushup.preset.ts index a1551a4b9..af7633ea9 100644 --- a/code-pushup.preset.ts +++ b/code-pushup.preset.ts @@ -180,12 +180,7 @@ export const coverageCoreConfigNx = async ( projectName?: string, ): Promise => { const targetNames = ['unit-test', 'int-test']; - const targetArgs = [ - '-t', - ...targetNames, - '--coverage.enabled', - '--skipNxCache', - ]; + const targetArgs = ['-t', ...targetNames]; return { plugins: [ await coveragePlugin({ From b0df7cdc65aad06156977d5f0bc23c9a7fb83cb4 Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 13 Aug 2025 18:34:41 +0200 Subject: [PATCH 054/111] chore: adjust preset --- code-pushup.preset.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/code-pushup.preset.ts b/code-pushup.preset.ts index fed4d97ad..56c58517e 100644 --- a/code-pushup.preset.ts +++ b/code-pushup.preset.ts @@ -251,13 +251,11 @@ export const coverageCoreConfigNx = async ( : ['nx', 'run-many', ...targetArgs], }, reports: projectName - ? [ - { - pathToProject: `packages/${projectName}`, - resultsPath: `packages/${projectName}/coverage/lcov.info`, - }, - ] - : await getNxCoveragePaths(targetNames), + ? targetNames.map(target => ({ + pathToProject: `packages/${projectName}`, + resultsPath: `coverage/${projectName}/${target}s/lcov.info`, + })) + : await getNxCoveragePaths({ targets: targetNames }), }), ], categories: coverageCategories, From be9551221100ec5cd10163b9db515e20a0dfa57e Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 13 Aug 2025 18:57:23 +0200 Subject: [PATCH 055/111] chore: remove js-package config from all but root --- packages/ci/code-pushup.config.ts | 4 +-- packages/ci/project.json | 2 -- packages/cli/code-pushup.config.ts | 4 +-- packages/cli/project.json | 2 -- packages/core/code-pushup.config.ts | 31 +++++++++++++++++++ packages/core/project.json | 2 -- packages/create-cli/code-pushup.config.ts | 4 +-- packages/create-cli/project.json | 2 -- packages/models/code-pushup.config.ts | 4 +-- packages/models/project.json | 2 -- packages/nx-plugin/code-pushup.config.ts | 4 +-- packages/nx-plugin/project.json | 2 -- .../plugin-coverage/code-pushup.config.ts | 4 +-- packages/plugin-coverage/project.json | 2 -- packages/plugin-eslint/code-pushup.config.ts | 4 +-- packages/plugin-eslint/project.json | 2 -- .../plugin-js-packages/code-pushup.config.ts | 4 +-- packages/plugin-js-packages/project.json | 2 -- packages/plugin-jsdocs/code-pushup.config.ts | 4 +-- packages/plugin-jsdocs/project.json | 2 -- .../plugin-lighthouse/code-pushup.config.ts | 4 +-- packages/plugin-lighthouse/project.json | 6 ++-- .../plugin-typescript/code-pushup.config.ts | 4 +-- packages/plugin-typescript/project.json | 2 -- packages/utils/code-pushup.config.ts | 4 +-- packages/utils/project.json | 2 -- 26 files changed, 46 insertions(+), 63 deletions(-) diff --git a/packages/ci/code-pushup.config.ts b/packages/ci/code-pushup.config.ts index 19912fefa..9bf27088f 100644 --- a/packages/ci/code-pushup.config.ts +++ b/packages/ci/code-pushup.config.ts @@ -4,14 +4,13 @@ import { eslintCoreConfigNx, jsDocsCoreConfig, jsDocsExclusionPatterns, - jsPackagesCoreConfig, loadEnv, typescriptPluginConfig, } from '../../code-pushup.preset.js'; import type { CoreConfig } from '../../packages/models/src/index.js'; import { mergeConfigs } from '../../packages/utils/src/index.js'; -const projectName = process.env.NX_TASK_TARGET_PROJECT; +const projectName = process.env['NX_TASK_TARGET_PROJECT']; const config: CoreConfig = { ...(await loadEnv()), @@ -22,7 +21,6 @@ export default mergeConfigs( config, await eslintCoreConfigNx(projectName), await coverageCoreConfigNx(projectName), - await jsPackagesCoreConfig('package.json'), // Use workspace root package.json await typescriptPluginConfig({ tsconfig: `packages/${projectName}/tsconfig.lib.json`, }), diff --git a/packages/ci/project.json b/packages/ci/project.json index 45082bc19..4c7215ee6 100644 --- a/packages/ci/project.json +++ b/packages/ci/project.json @@ -12,13 +12,11 @@ "dependsOn": [ "code-pushup-coverage", "code-pushup-jsdocs", - "code-pushup-js-packages", "code-pushup-typescript" ] }, "code-pushup-coverage": {}, "code-pushup-jsdocs": {}, - "code-pushup-js-packages": {}, "code-pushup-typescript": {} }, "tags": ["scope:tooling", "type:feature", "publishable"] diff --git a/packages/cli/code-pushup.config.ts b/packages/cli/code-pushup.config.ts index c2fbffb1c..25e6a399d 100644 --- a/packages/cli/code-pushup.config.ts +++ b/packages/cli/code-pushup.config.ts @@ -4,14 +4,13 @@ import { eslintCoreConfigNx, jsDocsCoreConfig, jsDocsExclusionPatterns, - jsPackagesCoreConfig, loadEnv, mergeConfigs, typescriptPluginConfig, } from '../../code-pushup.preset.js'; import type { CoreConfig } from '../../packages/models/src/index.js'; -const projectName = process.env.NX_TASK_TARGET_PROJECT; +const projectName = process.env['NX_TASK_TARGET_PROJECT']; const config: CoreConfig = { ...(await loadEnv()), @@ -22,7 +21,6 @@ export default mergeConfigs( config, await eslintCoreConfigNx(projectName), await coverageCoreConfigNx(projectName), - await jsPackagesCoreConfig('package.json'), // Use workspace root package.json await typescriptPluginConfig({ tsconfig: `packages/${projectName}/tsconfig.lib.json`, }), diff --git a/packages/cli/project.json b/packages/cli/project.json index 3b165da36..7a36aa701 100644 --- a/packages/cli/project.json +++ b/packages/cli/project.json @@ -30,13 +30,11 @@ "dependsOn": [ "code-pushup-coverage", "code-pushup-jsdocs", - "code-pushup-js-packages", "code-pushup-typescript" ] }, "code-pushup-coverage": {}, "code-pushup-jsdocs": {}, - "code-pushup-js-packages": {}, "code-pushup-typescript": {} }, "tags": ["scope:core", "type:app", "publishable"] diff --git a/packages/core/code-pushup.config.ts b/packages/core/code-pushup.config.ts index e69de29bb..25e6a399d 100644 --- a/packages/core/code-pushup.config.ts +++ b/packages/core/code-pushup.config.ts @@ -0,0 +1,31 @@ +import 'dotenv/config'; +import { + coverageCoreConfigNx, + eslintCoreConfigNx, + jsDocsCoreConfig, + jsDocsExclusionPatterns, + loadEnv, + mergeConfigs, + typescriptPluginConfig, +} from '../../code-pushup.preset.js'; +import type { CoreConfig } from '../../packages/models/src/index.js'; + +const projectName = process.env['NX_TASK_TARGET_PROJECT']; + +const config: CoreConfig = { + ...(await loadEnv()), + plugins: [], +}; + +export default mergeConfigs( + config, + await eslintCoreConfigNx(projectName), + await coverageCoreConfigNx(projectName), + await typescriptPluginConfig({ + tsconfig: `packages/${projectName}/tsconfig.lib.json`, + }), + jsDocsCoreConfig([ + `packages/${projectName}/src/**/*.ts`, + ...jsDocsExclusionPatterns, + ]), +); diff --git a/packages/core/project.json b/packages/core/project.json index bffef0ba4..53c6b8a75 100644 --- a/packages/core/project.json +++ b/packages/core/project.json @@ -12,13 +12,11 @@ "dependsOn": [ "code-pushup-coverage", "code-pushup-jsdocs", - "code-pushup-js-packages", "code-pushup-typescript" ] }, "code-pushup-coverage": {}, "code-pushup-jsdocs": {}, - "code-pushup-js-packages": {}, "code-pushup-typescript": {} }, "tags": ["scope:core", "type:feature", "publishable"] diff --git a/packages/create-cli/code-pushup.config.ts b/packages/create-cli/code-pushup.config.ts index 19912fefa..9bf27088f 100644 --- a/packages/create-cli/code-pushup.config.ts +++ b/packages/create-cli/code-pushup.config.ts @@ -4,14 +4,13 @@ import { eslintCoreConfigNx, jsDocsCoreConfig, jsDocsExclusionPatterns, - jsPackagesCoreConfig, loadEnv, typescriptPluginConfig, } from '../../code-pushup.preset.js'; import type { CoreConfig } from '../../packages/models/src/index.js'; import { mergeConfigs } from '../../packages/utils/src/index.js'; -const projectName = process.env.NX_TASK_TARGET_PROJECT; +const projectName = process.env['NX_TASK_TARGET_PROJECT']; const config: CoreConfig = { ...(await loadEnv()), @@ -22,7 +21,6 @@ export default mergeConfigs( config, await eslintCoreConfigNx(projectName), await coverageCoreConfigNx(projectName), - await jsPackagesCoreConfig('package.json'), // Use workspace root package.json await typescriptPluginConfig({ tsconfig: `packages/${projectName}/tsconfig.lib.json`, }), diff --git a/packages/create-cli/project.json b/packages/create-cli/project.json index d61687275..01235ed57 100644 --- a/packages/create-cli/project.json +++ b/packages/create-cli/project.json @@ -11,7 +11,6 @@ "dependsOn": [ "code-pushup-coverage", "code-pushup-jsdocs", - "code-pushup-js-packages", "code-pushup-typescript" ] }, @@ -22,7 +21,6 @@ }, "code-pushup-coverage": {}, "code-pushup-jsdocs": {}, - "code-pushup-js-packages": {}, "code-pushup-typescript": {} }, "tags": ["scope:shared", "type:util", "publishable"] diff --git a/packages/models/code-pushup.config.ts b/packages/models/code-pushup.config.ts index 0c7853be6..430900c2c 100644 --- a/packages/models/code-pushup.config.ts +++ b/packages/models/code-pushup.config.ts @@ -4,14 +4,13 @@ import { eslintCoreConfigNx, jsDocsCoreConfig, jsDocsExclusionPatterns, - jsPackagesCoreConfig, loadEnv, mergeConfigs, typescriptPluginConfig, } from '../../code-pushup.preset.js'; import type { CoreConfig } from '../../packages/models/src/index.js'; -const projectName = process.env.NX_TASK_TARGET_PROJECT; +const projectName = process.env['NX_TASK_TARGET_PROJECT']; const config: CoreConfig = { ...(await loadEnv()), @@ -23,7 +22,6 @@ export default mergeConfigs( config, await eslintCoreConfigNx(projectName), await coverageCoreConfigNx(projectName), - await jsPackagesCoreConfig('package.json'), // Use workspace root package.json await typescriptPluginConfig({ tsconfig: `packages/${projectName}/tsconfig.lib.json`, }), diff --git a/packages/models/project.json b/packages/models/project.json index 8d02a45f4..e20e78dc6 100644 --- a/packages/models/project.json +++ b/packages/models/project.json @@ -8,12 +8,10 @@ "dependsOn": [ "code-pushup-coverage", "code-pushup-jsdocs", - "code-pushup-js-packages", "code-pushup-typescript" ] }, "code-pushup-eslint": {}, - "code-pushup-js-packages": {}, "code-pushup-jsdocs": {}, "code-pushup-typescript": {}, "generate-docs": { diff --git a/packages/nx-plugin/code-pushup.config.ts b/packages/nx-plugin/code-pushup.config.ts index 19912fefa..9bf27088f 100644 --- a/packages/nx-plugin/code-pushup.config.ts +++ b/packages/nx-plugin/code-pushup.config.ts @@ -4,14 +4,13 @@ import { eslintCoreConfigNx, jsDocsCoreConfig, jsDocsExclusionPatterns, - jsPackagesCoreConfig, loadEnv, typescriptPluginConfig, } from '../../code-pushup.preset.js'; import type { CoreConfig } from '../../packages/models/src/index.js'; import { mergeConfigs } from '../../packages/utils/src/index.js'; -const projectName = process.env.NX_TASK_TARGET_PROJECT; +const projectName = process.env['NX_TASK_TARGET_PROJECT']; const config: CoreConfig = { ...(await loadEnv()), @@ -22,7 +21,6 @@ export default mergeConfigs( config, await eslintCoreConfigNx(projectName), await coverageCoreConfigNx(projectName), - await jsPackagesCoreConfig('package.json'), // Use workspace root package.json await typescriptPluginConfig({ tsconfig: `packages/${projectName}/tsconfig.lib.json`, }), diff --git a/packages/nx-plugin/project.json b/packages/nx-plugin/project.json index 663560e39..35f474f93 100644 --- a/packages/nx-plugin/project.json +++ b/packages/nx-plugin/project.json @@ -46,13 +46,11 @@ "dependsOn": [ "code-pushup-coverage", "code-pushup-jsdocs", - "code-pushup-js-packages", "code-pushup-typescript" ] }, "code-pushup-coverage": {}, "code-pushup-jsdocs": {}, - "code-pushup-js-packages": {}, "code-pushup-typescript": {} }, "tags": ["scope:tooling", "type:feature", "publishable"] diff --git a/packages/plugin-coverage/code-pushup.config.ts b/packages/plugin-coverage/code-pushup.config.ts index c2fbffb1c..25e6a399d 100644 --- a/packages/plugin-coverage/code-pushup.config.ts +++ b/packages/plugin-coverage/code-pushup.config.ts @@ -4,14 +4,13 @@ import { eslintCoreConfigNx, jsDocsCoreConfig, jsDocsExclusionPatterns, - jsPackagesCoreConfig, loadEnv, mergeConfigs, typescriptPluginConfig, } from '../../code-pushup.preset.js'; import type { CoreConfig } from '../../packages/models/src/index.js'; -const projectName = process.env.NX_TASK_TARGET_PROJECT; +const projectName = process.env['NX_TASK_TARGET_PROJECT']; const config: CoreConfig = { ...(await loadEnv()), @@ -22,7 +21,6 @@ export default mergeConfigs( config, await eslintCoreConfigNx(projectName), await coverageCoreConfigNx(projectName), - await jsPackagesCoreConfig('package.json'), // Use workspace root package.json await typescriptPluginConfig({ tsconfig: `packages/${projectName}/tsconfig.lib.json`, }), diff --git a/packages/plugin-coverage/project.json b/packages/plugin-coverage/project.json index e82a42793..1ed9a179a 100644 --- a/packages/plugin-coverage/project.json +++ b/packages/plugin-coverage/project.json @@ -12,13 +12,11 @@ "dependsOn": [ "code-pushup-coverage", "code-pushup-jsdocs", - "code-pushup-js-packages", "code-pushup-typescript" ] }, "code-pushup-coverage": {}, "code-pushup-jsdocs": {}, - "code-pushup-js-packages": {}, "code-pushup-typescript": {} }, "tags": ["scope:plugin", "type:feature", "publishable"] diff --git a/packages/plugin-eslint/code-pushup.config.ts b/packages/plugin-eslint/code-pushup.config.ts index c2fbffb1c..25e6a399d 100644 --- a/packages/plugin-eslint/code-pushup.config.ts +++ b/packages/plugin-eslint/code-pushup.config.ts @@ -4,14 +4,13 @@ import { eslintCoreConfigNx, jsDocsCoreConfig, jsDocsExclusionPatterns, - jsPackagesCoreConfig, loadEnv, mergeConfigs, typescriptPluginConfig, } from '../../code-pushup.preset.js'; import type { CoreConfig } from '../../packages/models/src/index.js'; -const projectName = process.env.NX_TASK_TARGET_PROJECT; +const projectName = process.env['NX_TASK_TARGET_PROJECT']; const config: CoreConfig = { ...(await loadEnv()), @@ -22,7 +21,6 @@ export default mergeConfigs( config, await eslintCoreConfigNx(projectName), await coverageCoreConfigNx(projectName), - await jsPackagesCoreConfig('package.json'), // Use workspace root package.json await typescriptPluginConfig({ tsconfig: `packages/${projectName}/tsconfig.lib.json`, }), diff --git a/packages/plugin-eslint/project.json b/packages/plugin-eslint/project.json index 2f511347f..7d22cefd4 100644 --- a/packages/plugin-eslint/project.json +++ b/packages/plugin-eslint/project.json @@ -12,13 +12,11 @@ "dependsOn": [ "code-pushup-coverage", "code-pushup-jsdocs", - "code-pushup-js-packages", "code-pushup-typescript" ] }, "code-pushup-coverage": {}, "code-pushup-jsdocs": {}, - "code-pushup-js-packages": {}, "code-pushup-typescript": {} }, "tags": ["scope:plugin", "type:feature", "publishable"] diff --git a/packages/plugin-js-packages/code-pushup.config.ts b/packages/plugin-js-packages/code-pushup.config.ts index c2fbffb1c..25e6a399d 100644 --- a/packages/plugin-js-packages/code-pushup.config.ts +++ b/packages/plugin-js-packages/code-pushup.config.ts @@ -4,14 +4,13 @@ import { eslintCoreConfigNx, jsDocsCoreConfig, jsDocsExclusionPatterns, - jsPackagesCoreConfig, loadEnv, mergeConfigs, typescriptPluginConfig, } from '../../code-pushup.preset.js'; import type { CoreConfig } from '../../packages/models/src/index.js'; -const projectName = process.env.NX_TASK_TARGET_PROJECT; +const projectName = process.env['NX_TASK_TARGET_PROJECT']; const config: CoreConfig = { ...(await loadEnv()), @@ -22,7 +21,6 @@ export default mergeConfigs( config, await eslintCoreConfigNx(projectName), await coverageCoreConfigNx(projectName), - await jsPackagesCoreConfig('package.json'), // Use workspace root package.json await typescriptPluginConfig({ tsconfig: `packages/${projectName}/tsconfig.lib.json`, }), diff --git a/packages/plugin-js-packages/project.json b/packages/plugin-js-packages/project.json index 26c0f503f..b6f05cb2f 100644 --- a/packages/plugin-js-packages/project.json +++ b/packages/plugin-js-packages/project.json @@ -12,13 +12,11 @@ "dependsOn": [ "code-pushup-coverage", "code-pushup-jsdocs", - "code-pushup-js-packages", "code-pushup-typescript" ] }, "code-pushup-coverage": {}, "code-pushup-jsdocs": {}, - "code-pushup-js-packages": {}, "code-pushup-typescript": {} }, "tags": ["scope:plugin", "type:feature", "publishable"], diff --git a/packages/plugin-jsdocs/code-pushup.config.ts b/packages/plugin-jsdocs/code-pushup.config.ts index 19912fefa..9bf27088f 100644 --- a/packages/plugin-jsdocs/code-pushup.config.ts +++ b/packages/plugin-jsdocs/code-pushup.config.ts @@ -4,14 +4,13 @@ import { eslintCoreConfigNx, jsDocsCoreConfig, jsDocsExclusionPatterns, - jsPackagesCoreConfig, loadEnv, typescriptPluginConfig, } from '../../code-pushup.preset.js'; import type { CoreConfig } from '../../packages/models/src/index.js'; import { mergeConfigs } from '../../packages/utils/src/index.js'; -const projectName = process.env.NX_TASK_TARGET_PROJECT; +const projectName = process.env['NX_TASK_TARGET_PROJECT']; const config: CoreConfig = { ...(await loadEnv()), @@ -22,7 +21,6 @@ export default mergeConfigs( config, await eslintCoreConfigNx(projectName), await coverageCoreConfigNx(projectName), - await jsPackagesCoreConfig('package.json'), // Use workspace root package.json await typescriptPluginConfig({ tsconfig: `packages/${projectName}/tsconfig.lib.json`, }), diff --git a/packages/plugin-jsdocs/project.json b/packages/plugin-jsdocs/project.json index a3bb00b02..c7a258748 100644 --- a/packages/plugin-jsdocs/project.json +++ b/packages/plugin-jsdocs/project.json @@ -12,13 +12,11 @@ "dependsOn": [ "code-pushup-coverage", "code-pushup-jsdocs", - "code-pushup-js-packages", "code-pushup-typescript" ] }, "code-pushup-coverage": {}, "code-pushup-jsdocs": {}, - "code-pushup-js-packages": {}, "code-pushup-typescript": {} }, "tags": ["scope:plugin", "type:feature", "publishable"] diff --git a/packages/plugin-lighthouse/code-pushup.config.ts b/packages/plugin-lighthouse/code-pushup.config.ts index c2fbffb1c..25e6a399d 100644 --- a/packages/plugin-lighthouse/code-pushup.config.ts +++ b/packages/plugin-lighthouse/code-pushup.config.ts @@ -4,14 +4,13 @@ import { eslintCoreConfigNx, jsDocsCoreConfig, jsDocsExclusionPatterns, - jsPackagesCoreConfig, loadEnv, mergeConfigs, typescriptPluginConfig, } from '../../code-pushup.preset.js'; import type { CoreConfig } from '../../packages/models/src/index.js'; -const projectName = process.env.NX_TASK_TARGET_PROJECT; +const projectName = process.env['NX_TASK_TARGET_PROJECT']; const config: CoreConfig = { ...(await loadEnv()), @@ -22,7 +21,6 @@ export default mergeConfigs( config, await eslintCoreConfigNx(projectName), await coverageCoreConfigNx(projectName), - await jsPackagesCoreConfig('package.json'), // Use workspace root package.json await typescriptPluginConfig({ tsconfig: `packages/${projectName}/tsconfig.lib.json`, }), diff --git a/packages/plugin-lighthouse/project.json b/packages/plugin-lighthouse/project.json index 9374db84b..7413e75e8 100644 --- a/packages/plugin-lighthouse/project.json +++ b/packages/plugin-lighthouse/project.json @@ -12,13 +12,13 @@ "dependsOn": [ "code-pushup-coverage", "code-pushup-jsdocs", - "code-pushup-js-packages", "code-pushup-typescript" ] }, - "code-pushup-coverage": {}, + "code-pushup-coverage": { + "dependsOn": ["unit-test"] + }, "code-pushup-jsdocs": {}, - "code-pushup-js-packages": {}, "code-pushup-typescript": {} }, "tags": ["scope:plugin", "type:feature", "publishable"] diff --git a/packages/plugin-typescript/code-pushup.config.ts b/packages/plugin-typescript/code-pushup.config.ts index c2fbffb1c..25e6a399d 100644 --- a/packages/plugin-typescript/code-pushup.config.ts +++ b/packages/plugin-typescript/code-pushup.config.ts @@ -4,14 +4,13 @@ import { eslintCoreConfigNx, jsDocsCoreConfig, jsDocsExclusionPatterns, - jsPackagesCoreConfig, loadEnv, mergeConfigs, typescriptPluginConfig, } from '../../code-pushup.preset.js'; import type { CoreConfig } from '../../packages/models/src/index.js'; -const projectName = process.env.NX_TASK_TARGET_PROJECT; +const projectName = process.env['NX_TASK_TARGET_PROJECT']; const config: CoreConfig = { ...(await loadEnv()), @@ -22,7 +21,6 @@ export default mergeConfigs( config, await eslintCoreConfigNx(projectName), await coverageCoreConfigNx(projectName), - await jsPackagesCoreConfig('package.json'), // Use workspace root package.json await typescriptPluginConfig({ tsconfig: `packages/${projectName}/tsconfig.lib.json`, }), diff --git a/packages/plugin-typescript/project.json b/packages/plugin-typescript/project.json index 55eb805dc..bab722975 100644 --- a/packages/plugin-typescript/project.json +++ b/packages/plugin-typescript/project.json @@ -12,13 +12,11 @@ "dependsOn": [ "code-pushup-coverage", "code-pushup-jsdocs", - "code-pushup-js-packages", "code-pushup-typescript" ] }, "code-pushup-coverage": {}, "code-pushup-jsdocs": {}, - "code-pushup-js-packages": {}, "code-pushup-typescript": {} }, "tags": ["scope:plugin", "type:feature", "publishable"] diff --git a/packages/utils/code-pushup.config.ts b/packages/utils/code-pushup.config.ts index c2fbffb1c..25e6a399d 100644 --- a/packages/utils/code-pushup.config.ts +++ b/packages/utils/code-pushup.config.ts @@ -4,14 +4,13 @@ import { eslintCoreConfigNx, jsDocsCoreConfig, jsDocsExclusionPatterns, - jsPackagesCoreConfig, loadEnv, mergeConfigs, typescriptPluginConfig, } from '../../code-pushup.preset.js'; import type { CoreConfig } from '../../packages/models/src/index.js'; -const projectName = process.env.NX_TASK_TARGET_PROJECT; +const projectName = process.env['NX_TASK_TARGET_PROJECT']; const config: CoreConfig = { ...(await loadEnv()), @@ -22,7 +21,6 @@ export default mergeConfigs( config, await eslintCoreConfigNx(projectName), await coverageCoreConfigNx(projectName), - await jsPackagesCoreConfig('package.json'), // Use workspace root package.json await typescriptPluginConfig({ tsconfig: `packages/${projectName}/tsconfig.lib.json`, }), diff --git a/packages/utils/project.json b/packages/utils/project.json index 706a81c87..9d576ff21 100644 --- a/packages/utils/project.json +++ b/packages/utils/project.json @@ -24,13 +24,11 @@ "dependsOn": [ "code-pushup-coverage", "code-pushup-jsdocs", - "code-pushup-js-packages", "code-pushup-typescript" ] }, "code-pushup-coverage": {}, "code-pushup-jsdocs": {}, - "code-pushup-js-packages": {}, "code-pushup-typescript": {} }, "tags": ["scope:shared", "type:util", "publishable"] From 8e66b4f2722b14cc3c862a634cd72637d0d81750 Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 13 Aug 2025 19:54:36 +0200 Subject: [PATCH 056/111] chore: adjust old targets --- .prettierignore | 3 ++ code-pushup.config.ts | 42 +++++------------ code-pushup.new.config.ts | 23 ---------- code-pushup.old.config.ts | 45 +++++++++++++++++++ code-pushup.preset.ts | 27 ++++++++--- .../plugin-lighthouse/code-pushup.config.ts | 2 +- project.json | 21 ++++++++- 7 files changed, 101 insertions(+), 62 deletions(-) delete mode 100644 code-pushup.new.config.ts create mode 100644 code-pushup.old.config.ts diff --git a/.prettierignore b/.prettierignore index 4ee7dc0ac..c2e007510 100644 --- a/.prettierignore +++ b/.prettierignore @@ -3,3 +3,6 @@ /coverage /.nx __snapshots__ + +/.nx/cache +/.nx/workspace-data \ No newline at end of file diff --git a/code-pushup.config.ts b/code-pushup.config.ts index 51aa2b33b..0b000476b 100644 --- a/code-pushup.config.ts +++ b/code-pushup.config.ts @@ -1,55 +1,37 @@ import 'dotenv/config'; -import { z } from 'zod'; import { coverageCoreConfigNx, eslintCoreConfigNx, jsDocsCoreConfig, + jsDocsExclusionPatterns, jsPackagesCoreConfig, lighthouseCoreConfig, + loadEnv, + mergeConfigs, typescriptPluginConfig, } from './code-pushup.preset.js'; import type { CoreConfig } from './packages/models/src/index.js'; -import { mergeConfigs } from './packages/utils/src/index.js'; -// load upload configuration from environment -const envSchema = z.object({ - CP_SERVER: z.string().url(), - CP_API_KEY: z.string().min(1), - CP_ORGANIZATION: z.string().min(1), - CP_PROJECT: z.string().min(1), -}); -const { data: env } = await envSchema.safeParseAsync(process.env); +const projectName = 'cli'; const config: CoreConfig = { - ...(env && { - upload: { - server: env.CP_SERVER, - apiKey: env.CP_API_KEY, - organization: env.CP_ORGANIZATION, - project: env.CP_PROJECT, - }, - }), - + ...(await loadEnv(projectName)), plugins: [], }; export default mergeConfigs( config, - await coverageCoreConfigNx(), await jsPackagesCoreConfig(), + await coverageCoreConfigNx(projectName), await lighthouseCoreConfig( 'https://github.com/code-pushup/cli?tab=readme-ov-file#code-pushup-cli/', ), - await typescriptPluginConfig({ - tsconfig: 'packages/cli/tsconfig.lib.json', - }), - await eslintCoreConfigNx(), + await eslintCoreConfigNx(projectName), jsDocsCoreConfig([ - 'packages/**/src/**/*.ts', - '!packages/**/node_modules', - '!packages/**/{mocks,mock}', - '!**/*.{spec,test}.ts', - '!**/implementation/**', - '!**/internal/**', + `packages/${projectName}/src/**/*.ts`, + ...jsDocsExclusionPatterns, ]), + await typescriptPluginConfig({ + tsconfig: `packages/${projectName}/tsconfig.lib.json`, + }), ); diff --git a/code-pushup.new.config.ts b/code-pushup.new.config.ts deleted file mode 100644 index 78559dab5..000000000 --- a/code-pushup.new.config.ts +++ /dev/null @@ -1,23 +0,0 @@ -import 'dotenv/config'; -import { - jsPackagesCoreConfig, - lighthouseCoreConfig, - loadEnv, - mergeConfigs, -} from './code-pushup.preset.js'; -import type { CoreConfig } from './packages/models/src/index.js'; - -const projectName = 'cli'; - -const config: CoreConfig = { - ...(await loadEnv(projectName)), - plugins: [], -}; - -export default mergeConfigs( - config, - await jsPackagesCoreConfig(), - await lighthouseCoreConfig( - 'https://github.com/code-pushup/cli?tab=readme-ov-file#code-pushup-cli/', - ), -); diff --git a/code-pushup.old.config.ts b/code-pushup.old.config.ts new file mode 100644 index 000000000..29768098a --- /dev/null +++ b/code-pushup.old.config.ts @@ -0,0 +1,45 @@ +import 'dotenv/config'; +import { + coverageCoreConfigNx, + eslintCoreConfigNx, + jsDocsCoreConfig, + jsPackagesCoreConfig, + lighthouseCoreConfig, + loadEnv, + typescriptPluginConfig, +} from './code-pushup.preset.js'; +import type { CoreConfig } from './packages/models/src/index.js'; +import { mergeConfigs } from './packages/utils/src/index.js'; + +const config: CoreConfig = { + ...(await loadEnv()), + plugins: [], +}; + +const merged = mergeConfigs( + config, + await coverageCoreConfigNx('cli'), + await jsPackagesCoreConfig(), + await lighthouseCoreConfig( + 'https://github.com/code-pushup/cli?tab=readme-ov-file#code-pushup-cli/', + ), + await typescriptPluginConfig({ + tsconfig: 'packages/cli/tsconfig.lib.json', + }), + await eslintCoreConfigNx(), + jsDocsCoreConfig([ + 'packages/**/src/**/*.ts', + '!packages/**/node_modules', + '!packages/**/{mocks,mock}', + '!**/*.{spec,test}.ts', + '!**/implementation/**', + '!**/internal/**', + ]), +); + +export default { + ...merged, + categories: merged.categories?.filter( + c => c.slug !== 'bug-prevention' && c.slug !== 'code-style', + ), +} satisfies CoreConfig; diff --git a/code-pushup.preset.ts b/code-pushup.preset.ts index 56c58517e..8e5f78559 100644 --- a/code-pushup.preset.ts +++ b/code-pushup.preset.ts @@ -237,10 +237,23 @@ export const typescriptPluginConfig = async ( * Generates coverage configuration for Nx projects. Supports both single projects and all projects. */ export const coverageCoreConfigNx = async ( - projectName?: string, + projectArg?: + | string + | { + projectName?: string; + targetNames?: string | string[]; + }, ): Promise => { - const targetNames = ['unit-test', 'int-test']; - const targetArgs = ['-t', ...targetNames]; + const { projectName, targetNames } = + typeof projectArg === 'string' + ? { projectName: projectArg } + : (projectArg ?? {}); + const parsedTargetNames = Array.isArray(targetNames) + ? targetNames + : targetNames != null + ? [targetNames] + : ['unit-test', 'int-test']; + const targetArgs = ['-t', parsedTargetNames.join(',')]; return { plugins: [ await coveragePlugin({ @@ -251,11 +264,11 @@ export const coverageCoreConfigNx = async ( : ['nx', 'run-many', ...targetArgs], }, reports: projectName - ? targetNames.map(target => ({ + ? parsedTargetNames.map(target => ({ pathToProject: `packages/${projectName}`, resultsPath: `coverage/${projectName}/${target}s/lcov.info`, })) - : await getNxCoveragePaths({ targets: targetNames }), + : await getNxCoveragePaths({ targets: parsedTargetNames }), }), ], categories: coverageCategories, @@ -356,7 +369,7 @@ function mergePersist( } if (a) { - return b ? { persist: { ...a, ...b } } : {}; + return b ? { persist: { ...a, ...b } } : { persist: a }; } else { return { persist: b }; } @@ -401,7 +414,7 @@ function mergeUpload( } if (a) { - return b ? { upload: { ...a, ...b } } : {}; + return b ? { upload: { ...a, ...b } } : { upload: a }; } else { return { upload: b }; } diff --git a/packages/plugin-lighthouse/code-pushup.config.ts b/packages/plugin-lighthouse/code-pushup.config.ts index 25e6a399d..6588febce 100644 --- a/packages/plugin-lighthouse/code-pushup.config.ts +++ b/packages/plugin-lighthouse/code-pushup.config.ts @@ -20,7 +20,7 @@ const config: CoreConfig = { export default mergeConfigs( config, await eslintCoreConfigNx(projectName), - await coverageCoreConfigNx(projectName), + await coverageCoreConfigNx({ projectName, targetNames: ['unit-test'] }), await typescriptPluginConfig({ tsconfig: `packages/${projectName}/tsconfig.lib.json`, }), diff --git a/project.json b/project.json index 1a520cec8..b5e17af9a 100644 --- a/project.json +++ b/project.json @@ -3,9 +3,24 @@ "$schema": "node_modules/nx/schemas/project-schema.json", "targets": { "code-pushup-old": { + "dependsOn": [ + "code-pushup-eslint", + "code-pushup-coverage", + "code-pushup-typescript", + "code-pushup-jsdocs", + "code-pushup-js-packages", + "code-pushup-lighthouse" + ], "executor": "nx:run-commands", "options": { - "command": "node packages/cli/src/index.ts --no-progress --verbose", + "command": "node packages/cli/src/index.ts", + "args": [ + "--no-progress", + "--verbose", + "--config={projectRoot}/code-pushup.old.config.ts", + "--cache.read", + "--persist.outputDir={projectRoot}/.code-pushup" + ], "env": { "NODE_OPTIONS": "--import tsx", "TSX_TSCONFIG_PATH": "tsconfig.base.json" @@ -25,6 +40,10 @@ ] } }, + "code-pushup-eslint": {}, + "code-pushup-coverage": {}, + "code-pushup-jsdocs": {}, + "code-pushup-typescript": {}, "code-pushup-js-packages": {}, "code-pushup-lighthouse": {} } From ac1d5c88809f5dadefa244d3aece9ef0b908b4ca Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 13 Aug 2025 19:55:29 +0200 Subject: [PATCH 057/111] chore: adjust gh actions --- .github/workflows/code-pushup-fork.yml | 2 +- .github/workflows/code-pushup-old.yml | 2 +- .github/workflows/code-pushup.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/code-pushup-fork.yml b/.github/workflows/code-pushup-fork.yml index 06de8f75b..68a3eeecf 100644 --- a/.github/workflows/code-pushup-fork.yml +++ b/.github/workflows/code-pushup-fork.yml @@ -41,4 +41,4 @@ jobs: - name: Run Code PushUp action uses: code-pushup/github-action@v0 with: - bin: npx nx affected -t code-pushup --base=${{ env.NX_BASE }} --head=${{ env.NX_HEAD }} + bin: npx nx affected -t code-pushup -- diff --git a/.github/workflows/code-pushup-old.yml b/.github/workflows/code-pushup-old.yml index cc1351476..fcc65fb9a 100644 --- a/.github/workflows/code-pushup-old.yml +++ b/.github/workflows/code-pushup-old.yml @@ -36,4 +36,4 @@ jobs: - name: Run Code PushUp action uses: code-pushup/github-action@v0 with: - bin: npx nx code-pushup -- + bin: npx nx code-pushup-old -- diff --git a/.github/workflows/code-pushup.yml b/.github/workflows/code-pushup.yml index c94abe2bd..f846739ab 100644 --- a/.github/workflows/code-pushup.yml +++ b/.github/workflows/code-pushup.yml @@ -40,4 +40,4 @@ jobs: - name: Run Code PushUp action uses: code-pushup/github-action@v0 with: - bin: npx nx affected -t code-pushup --base=${{ env.NX_BASE }} --head=${{ env.NX_HEAD }} + bin: npx nx affected -t code-pushup -- From 541ed9a6c317c1840047ad2e3bc0ed0602004ade Mon Sep 17 00:00:00 2001 From: John Doe Date: Thu, 14 Aug 2025 01:49:06 +0200 Subject: [PATCH 058/111] wip --- packages/plugin-lighthouse/project.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/plugin-lighthouse/project.json b/packages/plugin-lighthouse/project.json index 7413e75e8..cb5e1e524 100644 --- a/packages/plugin-lighthouse/project.json +++ b/packages/plugin-lighthouse/project.json @@ -7,7 +7,6 @@ "build": {}, "lint": {}, "unit-test": {}, - "int-test": {}, "code-pushup": { "dependsOn": [ "code-pushup-coverage", From 1c8b7194ccc7840ce45d3b3b2e98587ccaa53f45 Mon Sep 17 00:00:00 2001 From: John Doe Date: Thu, 14 Aug 2025 03:15:26 +0200 Subject: [PATCH 059/111] fix: make all targets pass, title GH actions --- ...d.yml => code-pushup-fork.centralized.yml} | 6 +++--- ...fork.yml => code-pushup-fork.monorepo.yml} | 4 ++-- ...up-old.yml => code-pushup.centralized.yml} | 6 +++--- ...de-pushup.yml => code-pushup.monorepo.yml} | 4 ++-- ...config.ts => code-pushup.central.config.ts | 1 + code-pushup.config.ts | 14 ------------- code-pushup.preset.ts | 5 +---- packages/ci/project.json | 4 +++- packages/cli/project.json | 4 +++- packages/core/project.json | 4 +++- packages/create-cli/project.json | 9 +++------ packages/models/project.json | 6 +++++- packages/nx-plugin/project.json | 4 +++- packages/plugin-coverage/project.json | 4 +++- packages/plugin-eslint/project.json | 4 +++- packages/plugin-js-packages/project.json | 4 +++- packages/plugin-jsdocs/project.json | 4 +++- packages/plugin-lighthouse/project.json | 4 +++- packages/plugin-typescript/project.json | 4 +++- packages/utils/project.json | 9 ++++++--- project.json | 20 ++++--------------- 21 files changed, 60 insertions(+), 64 deletions(-) rename .github/workflows/{code-pushup-fork-old.yml => code-pushup-fork.centralized.yml} (87%) rename .github/workflows/{code-pushup-fork.yml => code-pushup-fork.monorepo.yml} (93%) rename .github/workflows/{code-pushup-old.yml => code-pushup.centralized.yml} (86%) rename .github/workflows/{code-pushup.yml => code-pushup.monorepo.yml} (92%) rename code-pushup.old.config.ts => code-pushup.central.config.ts (99%) diff --git a/.github/workflows/code-pushup-fork-old.yml b/.github/workflows/code-pushup-fork.centralized.yml similarity index 87% rename from .github/workflows/code-pushup-fork-old.yml rename to .github/workflows/code-pushup-fork.centralized.yml index 5ecfdddf0..823365fe1 100644 --- a/.github/workflows/code-pushup-fork-old.yml +++ b/.github/workflows/code-pushup-fork.centralized.yml @@ -1,4 +1,4 @@ -name: Code PushUp (fork) +name: Code PushUp - Centralized Style (fork) # separated from code-pushup.yml for security reasons # => requires permissions to create PR comment @@ -20,7 +20,7 @@ permissions: jobs: code-pushup: runs-on: ubuntu-latest - name: Code PushUp + name: Code PushUp - Centralized Style if: github.event.pull_request.head.repo.fork steps: - name: Checkout repository @@ -35,4 +35,4 @@ jobs: - name: Run Code PushUp action uses: code-pushup/github-action@v0 with: - bin: npx nx code-pushup-old -- + bin: npx nx code-pushup-central -- diff --git a/.github/workflows/code-pushup-fork.yml b/.github/workflows/code-pushup-fork.monorepo.yml similarity index 93% rename from .github/workflows/code-pushup-fork.yml rename to .github/workflows/code-pushup-fork.monorepo.yml index 68a3eeecf..d937bed55 100644 --- a/.github/workflows/code-pushup-fork.yml +++ b/.github/workflows/code-pushup-fork.monorepo.yml @@ -1,4 +1,4 @@ -name: Code PushUp (fork) +name: Code PushUp - Monorepo Style (fork) # separated from code-pushup.yml for security reasons # => requires permissions to create PR comment @@ -20,7 +20,7 @@ permissions: jobs: code-pushup: runs-on: ubuntu-latest - name: Code PushUp + name: Code PushUp - Monorepo Style if: github.event.pull_request.head.repo.fork steps: - name: Checkout PR head diff --git a/.github/workflows/code-pushup-old.yml b/.github/workflows/code-pushup.centralized.yml similarity index 86% rename from .github/workflows/code-pushup-old.yml rename to .github/workflows/code-pushup.centralized.yml index fcc65fb9a..133a7aec4 100644 --- a/.github/workflows/code-pushup-old.yml +++ b/.github/workflows/code-pushup.centralized.yml @@ -1,4 +1,4 @@ -name: Code PushUp +name: Code PushUp - Centralized Style on: push: @@ -15,7 +15,7 @@ permissions: jobs: code-pushup: runs-on: ubuntu-latest - name: Code PushUp + name: Code PushUp - Centralized Style # ignore PRs from forks, handled by code-pushup-fork.yml if: ${{ !github.event.pull_request.head.repo.fork }} env: @@ -36,4 +36,4 @@ jobs: - name: Run Code PushUp action uses: code-pushup/github-action@v0 with: - bin: npx nx code-pushup-old -- + bin: npx nx code-pushup-central -- diff --git a/.github/workflows/code-pushup.yml b/.github/workflows/code-pushup.monorepo.yml similarity index 92% rename from .github/workflows/code-pushup.yml rename to .github/workflows/code-pushup.monorepo.yml index f846739ab..16bd8e1d7 100644 --- a/.github/workflows/code-pushup.yml +++ b/.github/workflows/code-pushup.monorepo.yml @@ -1,4 +1,4 @@ -name: Code PushUp +name: Code PushUp - Monorepo Style on: push: @@ -15,7 +15,7 @@ permissions: jobs: code-pushup: runs-on: ubuntu-latest - name: Code PushUp + name: Code PushUp - Monorepo Style # ignore PRs from forks, handled by code-pushup-fork.yml if: ${{ !github.event.pull_request.head.repo.fork }} env: diff --git a/code-pushup.old.config.ts b/code-pushup.central.config.ts similarity index 99% rename from code-pushup.old.config.ts rename to code-pushup.central.config.ts index 29768098a..955767acf 100644 --- a/code-pushup.old.config.ts +++ b/code-pushup.central.config.ts @@ -26,6 +26,7 @@ const merged = mergeConfigs( await typescriptPluginConfig({ tsconfig: 'packages/cli/tsconfig.lib.json', }), + await eslintCoreConfigNx(), jsDocsCoreConfig([ 'packages/**/src/**/*.ts', diff --git a/code-pushup.config.ts b/code-pushup.config.ts index 0b000476b..78559dab5 100644 --- a/code-pushup.config.ts +++ b/code-pushup.config.ts @@ -1,14 +1,9 @@ import 'dotenv/config'; import { - coverageCoreConfigNx, - eslintCoreConfigNx, - jsDocsCoreConfig, - jsDocsExclusionPatterns, jsPackagesCoreConfig, lighthouseCoreConfig, loadEnv, mergeConfigs, - typescriptPluginConfig, } from './code-pushup.preset.js'; import type { CoreConfig } from './packages/models/src/index.js'; @@ -22,16 +17,7 @@ const config: CoreConfig = { export default mergeConfigs( config, await jsPackagesCoreConfig(), - await coverageCoreConfigNx(projectName), await lighthouseCoreConfig( 'https://github.com/code-pushup/cli?tab=readme-ov-file#code-pushup-cli/', ), - await eslintCoreConfigNx(projectName), - jsDocsCoreConfig([ - `packages/${projectName}/src/**/*.ts`, - ...jsDocsExclusionPatterns, - ]), - await typescriptPluginConfig({ - tsconfig: `packages/${projectName}/tsconfig.lib.json`, - }), ); diff --git a/code-pushup.preset.ts b/code-pushup.preset.ts index 8e5f78559..55fe331f6 100644 --- a/code-pushup.preset.ts +++ b/code-pushup.preset.ts @@ -217,10 +217,7 @@ export const eslintCoreConfigNx = async ( ): Promise => ({ plugins: [ projectName - ? await eslintPlugin({ - eslintrc: `packages/${projectName}/eslint.config.js`, - patterns: ['.'], - }) + ? await eslintPlugin(`packages/${projectName}/eslint.config.js`) : await eslintPlugin(await eslintConfigFromAllNxProjects()), ], categories: eslintCategories, diff --git a/packages/ci/project.json b/packages/ci/project.json index 4c7215ee6..e43ab5b28 100644 --- a/packages/ci/project.json +++ b/packages/ci/project.json @@ -12,9 +12,11 @@ "dependsOn": [ "code-pushup-coverage", "code-pushup-jsdocs", - "code-pushup-typescript" + "code-pushup-typescript", + "code-pushup-eslint" ] }, + "code-pushup-eslint": {}, "code-pushup-coverage": {}, "code-pushup-jsdocs": {}, "code-pushup-typescript": {} diff --git a/packages/cli/project.json b/packages/cli/project.json index 7a36aa701..f2a171500 100644 --- a/packages/cli/project.json +++ b/packages/cli/project.json @@ -30,9 +30,11 @@ "dependsOn": [ "code-pushup-coverage", "code-pushup-jsdocs", - "code-pushup-typescript" + "code-pushup-typescript", + "code-pushup-eslint" ] }, + "code-pushup-eslint": {}, "code-pushup-coverage": {}, "code-pushup-jsdocs": {}, "code-pushup-typescript": {} diff --git a/packages/core/project.json b/packages/core/project.json index 53c6b8a75..5f56713f1 100644 --- a/packages/core/project.json +++ b/packages/core/project.json @@ -12,9 +12,11 @@ "dependsOn": [ "code-pushup-coverage", "code-pushup-jsdocs", - "code-pushup-typescript" + "code-pushup-typescript", + "code-pushup-eslint" ] }, + "code-pushup-eslint": {}, "code-pushup-coverage": {}, "code-pushup-jsdocs": {}, "code-pushup-typescript": {} diff --git a/packages/create-cli/project.json b/packages/create-cli/project.json index 01235ed57..4ceba8aac 100644 --- a/packages/create-cli/project.json +++ b/packages/create-cli/project.json @@ -11,14 +11,11 @@ "dependsOn": [ "code-pushup-coverage", "code-pushup-jsdocs", - "code-pushup-typescript" + "code-pushup-typescript", + "code-pushup-eslint" ] }, - "exec-node": { - "dependsOn": ["build"], - "command": "node ./dist/packages/create-cli/src/index.js", - "options": {} - }, + "code-pushup-eslint": {}, "code-pushup-coverage": {}, "code-pushup-jsdocs": {}, "code-pushup-typescript": {} diff --git a/packages/models/project.json b/packages/models/project.json index e20e78dc6..3eb00c27e 100644 --- a/packages/models/project.json +++ b/packages/models/project.json @@ -8,11 +8,15 @@ "dependsOn": [ "code-pushup-coverage", "code-pushup-jsdocs", - "code-pushup-typescript" + "code-pushup-typescript", + "code-pushup-eslint" ] }, "code-pushup-eslint": {}, "code-pushup-jsdocs": {}, + "code-pushup-coverage": { + "dependsOn": ["unit-test"] + }, "code-pushup-typescript": {}, "generate-docs": { "command": "npx zod2md --config packages/models/zod2md.config.ts", diff --git a/packages/nx-plugin/project.json b/packages/nx-plugin/project.json index 35f474f93..a04836632 100644 --- a/packages/nx-plugin/project.json +++ b/packages/nx-plugin/project.json @@ -46,9 +46,11 @@ "dependsOn": [ "code-pushup-coverage", "code-pushup-jsdocs", - "code-pushup-typescript" + "code-pushup-typescript", + "code-pushup-eslint" ] }, + "code-pushup-eslint": {}, "code-pushup-coverage": {}, "code-pushup-jsdocs": {}, "code-pushup-typescript": {} diff --git a/packages/plugin-coverage/project.json b/packages/plugin-coverage/project.json index 1ed9a179a..022612267 100644 --- a/packages/plugin-coverage/project.json +++ b/packages/plugin-coverage/project.json @@ -12,9 +12,11 @@ "dependsOn": [ "code-pushup-coverage", "code-pushup-jsdocs", - "code-pushup-typescript" + "code-pushup-typescript", + "code-pushup-eslint" ] }, + "code-pushup-eslint": {}, "code-pushup-coverage": {}, "code-pushup-jsdocs": {}, "code-pushup-typescript": {} diff --git a/packages/plugin-eslint/project.json b/packages/plugin-eslint/project.json index 7d22cefd4..462834834 100644 --- a/packages/plugin-eslint/project.json +++ b/packages/plugin-eslint/project.json @@ -12,9 +12,11 @@ "dependsOn": [ "code-pushup-coverage", "code-pushup-jsdocs", - "code-pushup-typescript" + "code-pushup-typescript", + "code-pushup-eslint" ] }, + "code-pushup-eslint": {}, "code-pushup-coverage": {}, "code-pushup-jsdocs": {}, "code-pushup-typescript": {} diff --git a/packages/plugin-js-packages/project.json b/packages/plugin-js-packages/project.json index b6f05cb2f..52b0fd3d2 100644 --- a/packages/plugin-js-packages/project.json +++ b/packages/plugin-js-packages/project.json @@ -12,9 +12,11 @@ "dependsOn": [ "code-pushup-coverage", "code-pushup-jsdocs", - "code-pushup-typescript" + "code-pushup-typescript", + "code-pushup-eslint" ] }, + "code-pushup-eslint": {}, "code-pushup-coverage": {}, "code-pushup-jsdocs": {}, "code-pushup-typescript": {} diff --git a/packages/plugin-jsdocs/project.json b/packages/plugin-jsdocs/project.json index c7a258748..22c336cbf 100644 --- a/packages/plugin-jsdocs/project.json +++ b/packages/plugin-jsdocs/project.json @@ -12,9 +12,11 @@ "dependsOn": [ "code-pushup-coverage", "code-pushup-jsdocs", - "code-pushup-typescript" + "code-pushup-typescript", + "code-pushup-eslint" ] }, + "code-pushup-eslint": {}, "code-pushup-coverage": {}, "code-pushup-jsdocs": {}, "code-pushup-typescript": {} diff --git a/packages/plugin-lighthouse/project.json b/packages/plugin-lighthouse/project.json index cb5e1e524..650aa664d 100644 --- a/packages/plugin-lighthouse/project.json +++ b/packages/plugin-lighthouse/project.json @@ -11,9 +11,11 @@ "dependsOn": [ "code-pushup-coverage", "code-pushup-jsdocs", - "code-pushup-typescript" + "code-pushup-typescript", + "code-pushup-eslint" ] }, + "code-pushup-eslint": {}, "code-pushup-coverage": { "dependsOn": ["unit-test"] }, diff --git a/packages/plugin-typescript/project.json b/packages/plugin-typescript/project.json index bab722975..807d3b72d 100644 --- a/packages/plugin-typescript/project.json +++ b/packages/plugin-typescript/project.json @@ -12,9 +12,11 @@ "dependsOn": [ "code-pushup-coverage", "code-pushup-jsdocs", - "code-pushup-typescript" + "code-pushup-typescript", + "code-pushup-eslint" ] }, + "code-pushup-eslint": {}, "code-pushup-coverage": {}, "code-pushup-jsdocs": {}, "code-pushup-typescript": {} diff --git a/packages/utils/project.json b/packages/utils/project.json index 9d576ff21..0a21c6067 100644 --- a/packages/utils/project.json +++ b/packages/utils/project.json @@ -24,12 +24,15 @@ "dependsOn": [ "code-pushup-coverage", "code-pushup-jsdocs", - "code-pushup-typescript" + "code-pushup-typescript", + "code-pushup-eslint" ] }, - "code-pushup-coverage": {}, + "code-pushup-eslint": {}, "code-pushup-jsdocs": {}, - "code-pushup-typescript": {} + "code-pushup-coverage": { + "dependsOn": ["unit-test", "int-test"] + } }, "tags": ["scope:shared", "type:util", "publishable"] } diff --git a/project.json b/project.json index b5e17af9a..a903efccb 100644 --- a/project.json +++ b/project.json @@ -2,24 +2,16 @@ "name": "cli-source", "$schema": "node_modules/nx/schemas/project-schema.json", "targets": { - "code-pushup-old": { - "dependsOn": [ - "code-pushup-eslint", - "code-pushup-coverage", - "code-pushup-typescript", - "code-pushup-jsdocs", - "code-pushup-js-packages", - "code-pushup-lighthouse" - ], + "code-pushup-central": { "executor": "nx:run-commands", "options": { "command": "node packages/cli/src/index.ts", "args": [ "--no-progress", "--verbose", - "--config={projectRoot}/code-pushup.old.config.ts", - "--cache.read", - "--persist.outputDir={projectRoot}/.code-pushup" + "--config={projectRoot}/code-pushup.central.config.ts", + "--persist.outputDir={projectRoot}/.code-pushup", + "--upload.project=cli" ], "env": { "NODE_OPTIONS": "--import tsx", @@ -40,10 +32,6 @@ ] } }, - "code-pushup-eslint": {}, - "code-pushup-coverage": {}, - "code-pushup-jsdocs": {}, - "code-pushup-typescript": {}, "code-pushup-js-packages": {}, "code-pushup-lighthouse": {} } From f964825e03c4d5e8c8f6b1145e5d4736ffc2877b Mon Sep 17 00:00:00 2001 From: John Doe Date: Thu, 14 Aug 2025 03:26:40 +0200 Subject: [PATCH 060/111] wip gh action --- .github/workflows/code-pushup-fork.centralized.yml | 4 ++-- .github/workflows/code-pushup-fork.monorepo.yml | 4 ++-- .github/workflows/code-pushup.centralized.yml | 4 ++-- .github/workflows/code-pushup.monorepo.yml | 6 ++++-- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/workflows/code-pushup-fork.centralized.yml b/.github/workflows/code-pushup-fork.centralized.yml index 823365fe1..90a6dfffd 100644 --- a/.github/workflows/code-pushup-fork.centralized.yml +++ b/.github/workflows/code-pushup-fork.centralized.yml @@ -1,4 +1,4 @@ -name: Code PushUp - Centralized Style (fork) +name: Code PushUp - Centralized/No Cache (fork) # separated from code-pushup.yml for security reasons # => requires permissions to create PR comment @@ -20,7 +20,7 @@ permissions: jobs: code-pushup: runs-on: ubuntu-latest - name: Code PushUp - Centralized Style + name: Run central layout no cache if: github.event.pull_request.head.repo.fork steps: - name: Checkout repository diff --git a/.github/workflows/code-pushup-fork.monorepo.yml b/.github/workflows/code-pushup-fork.monorepo.yml index d937bed55..13ecc69c2 100644 --- a/.github/workflows/code-pushup-fork.monorepo.yml +++ b/.github/workflows/code-pushup-fork.monorepo.yml @@ -1,4 +1,4 @@ -name: Code PushUp - Monorepo Style (fork) +name: Code PushUp - Monorepo/Cache (fork) # separated from code-pushup.yml for security reasons # => requires permissions to create PR comment @@ -20,7 +20,7 @@ permissions: jobs: code-pushup: runs-on: ubuntu-latest - name: Code PushUp - Monorepo Style + name: Run monorepo layout with caching if: github.event.pull_request.head.repo.fork steps: - name: Checkout PR head diff --git a/.github/workflows/code-pushup.centralized.yml b/.github/workflows/code-pushup.centralized.yml index 133a7aec4..caba6a9cd 100644 --- a/.github/workflows/code-pushup.centralized.yml +++ b/.github/workflows/code-pushup.centralized.yml @@ -1,4 +1,4 @@ -name: Code PushUp - Centralized Style +name: Code PushUp - Centralized/No Cache on: push: @@ -15,7 +15,7 @@ permissions: jobs: code-pushup: runs-on: ubuntu-latest - name: Code PushUp - Centralized Style + name: Run central layout no cache # ignore PRs from forks, handled by code-pushup-fork.yml if: ${{ !github.event.pull_request.head.repo.fork }} env: diff --git a/.github/workflows/code-pushup.monorepo.yml b/.github/workflows/code-pushup.monorepo.yml index 16bd8e1d7..dc85ca3a4 100644 --- a/.github/workflows/code-pushup.monorepo.yml +++ b/.github/workflows/code-pushup.monorepo.yml @@ -1,4 +1,4 @@ -name: Code PushUp - Monorepo Style +name: Code PushUp - Monorepo/Cache on: push: @@ -15,7 +15,7 @@ permissions: jobs: code-pushup: runs-on: ubuntu-latest - name: Code PushUp - Monorepo Style + name: Run monorepo layout with caching # ignore PRs from forks, handled by code-pushup-fork.yml if: ${{ !github.event.pull_request.head.repo.fork }} env: @@ -41,3 +41,5 @@ jobs: uses: code-pushup/github-action@v0 with: bin: npx nx affected -t code-pushup -- + monorepo: nx + parallel: 3 From a9b0b6cf05a0d8b3360a37ffffc18f87f0f9de2a Mon Sep 17 00:00:00 2001 From: John Doe Date: Thu, 14 Aug 2025 03:34:06 +0200 Subject: [PATCH 061/111] fix: adjust action logic --- packages/create-cli/project.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/create-cli/project.json b/packages/create-cli/project.json index 4ceba8aac..9cb31f1b8 100644 --- a/packages/create-cli/project.json +++ b/packages/create-cli/project.json @@ -16,7 +16,9 @@ ] }, "code-pushup-eslint": {}, - "code-pushup-coverage": {}, + "code-pushup-coverage": { + "dependsOn": ["unit-test"] + }, "code-pushup-jsdocs": {}, "code-pushup-typescript": {} }, From 62d0a684d1c1c787956f74b15965a97729388079 Mon Sep 17 00:00:00 2001 From: John Doe Date: Thu, 14 Aug 2025 03:37:14 +0200 Subject: [PATCH 062/111] fix: adjust action logic 2 --- packages/models/code-pushup.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/models/code-pushup.config.ts b/packages/models/code-pushup.config.ts index 430900c2c..cc85175a6 100644 --- a/packages/models/code-pushup.config.ts +++ b/packages/models/code-pushup.config.ts @@ -21,7 +21,7 @@ const config: CoreConfig = { export default mergeConfigs( config, await eslintCoreConfigNx(projectName), - await coverageCoreConfigNx(projectName), + await coverageCoreConfigNx({ projectName, targetNames: ['unit-test'] }), await typescriptPluginConfig({ tsconfig: `packages/${projectName}/tsconfig.lib.json`, }), From 33ca07373c852547a51b2086adae3715e37fa3bc Mon Sep 17 00:00:00 2001 From: John Doe Date: Thu, 14 Aug 2025 04:02:09 +0200 Subject: [PATCH 063/111] fix: adjust action logic 3 --- packages/create-cli/code-pushup.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/create-cli/code-pushup.config.ts b/packages/create-cli/code-pushup.config.ts index 9bf27088f..c661594be 100644 --- a/packages/create-cli/code-pushup.config.ts +++ b/packages/create-cli/code-pushup.config.ts @@ -20,7 +20,7 @@ const config: CoreConfig = { export default mergeConfigs( config, await eslintCoreConfigNx(projectName), - await coverageCoreConfigNx(projectName), + await coverageCoreConfigNx({ projectName, targetNames: ['unit-test'] }), await typescriptPluginConfig({ tsconfig: `packages/${projectName}/tsconfig.lib.json`, }), From 0bcba8f8aa24c496499732c6dba084e9a24dc70b Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Sat, 16 Aug 2025 16:35:46 +0200 Subject: [PATCH 064/111] fix: revert code --- packages/nx-plugin/.env.lint.local | 1 - packages/nx-plugin/README.md | 68 --- ...nx-plugin-dynamic-target-configuration.png | Bin 48819 -> 0 bytes packages/nx-plugin/eslint.config.js | 51 --- packages/nx-plugin/executors.json | 9 - packages/nx-plugin/generators.json | 14 - packages/nx-plugin/mock/fixtures/env.ts | 7 - packages/nx-plugin/mock/utils/executor.ts | 16 - packages/nx-plugin/package.json | 48 --- packages/nx-plugin/project.json | 48 --- .../nx-plugin/src/executors/cli/README.md | 77 ---- .../src/executors/cli/executor.int.test.ts | 48 --- .../nx-plugin/src/executors/cli/executor.ts | 56 --- .../src/executors/cli/executor.unit.test.ts | 142 ------- .../nx-plugin/src/executors/cli/schema.json | 98 ----- .../nx-plugin/src/executors/cli/schema.ts | 19 - .../src/executors/cli/utils.int.test.ts | 51 --- packages/nx-plugin/src/executors/cli/utils.ts | 82 ---- .../src/executors/cli/utils.unit.test.ts | 179 -------- .../nx-plugin/src/executors/internal/cli.ts | 65 --- .../src/executors/internal/cli.unit.test.ts | 99 ----- .../src/executors/internal/config.int.test.ts | 28 -- .../src/executors/internal/config.ts | 69 --- .../executors/internal/config.unit.test.ts | 395 ------------------ .../src/executors/internal/context.ts | 21 - .../executors/internal/context.unit.test.ts | 28 -- .../nx-plugin/src/executors/internal/env.ts | 37 -- .../src/executors/internal/env.unit.test.ts | 40 -- .../nx-plugin/src/executors/internal/types.ts | 51 --- .../src/generators/configuration/README.md | 36 -- .../__snapshots__/root-code-pushup.config.ts | 15 - .../code-pushup-config.int.test.ts | 45 -- .../configuration/code-pushup-config.ts | 66 --- .../code-pushup-config.unit.test.ts | 289 ------------- .../files/code-pushup.config.ts.template | 9 - .../configuration/generator.int.test.ts | 145 ------- .../src/generators/configuration/generator.ts | 61 --- .../src/generators/configuration/schema.d.ts | 9 - .../src/generators/configuration/schema.json | 45 -- .../src/generators/configuration/types.ts | 6 - .../src/generators/configuration/utils.ts | 66 --- .../configuration/utils.unit.test.ts | 98 ----- .../nx-plugin/src/generators/init/README.md | 32 -- .../src/generators/init/generator.int.test.ts | 89 ---- .../src/generators/init/generator.ts | 101 ----- .../nx-plugin/src/generators/init/schema.d.ts | 5 - .../nx-plugin/src/generators/init/schema.json | 23 - packages/nx-plugin/src/index.ts | 18 - packages/nx-plugin/src/internal/constants.ts | 4 - .../nx-plugin/src/internal/execute-process.ts | 186 --------- .../src/internal/execute-process.unit.test.ts | 92 ---- packages/nx-plugin/src/internal/types.ts | 4 - packages/nx-plugin/src/internal/versions.ts | 25 -- packages/nx-plugin/src/plugin/README.md | 107 ----- packages/nx-plugin/src/plugin/constants.ts | 1 - packages/nx-plugin/src/plugin/index.ts | 2 - packages/nx-plugin/src/plugin/plugin.ts | 34 -- .../nx-plugin/src/plugin/plugin.unit.test.ts | 139 ------ .../src/plugin/target/configuration-target.ts | 24 -- .../target/configuration.target.unit.test.ts | 19 - .../nx-plugin/src/plugin/target/constants.ts | 2 - .../src/plugin/target/executor-target.ts | 20 - .../target/executor.target.unit.test.ts | 25 -- .../nx-plugin/src/plugin/target/targets.ts | 36 -- .../src/plugin/target/targets.unit.test.ts | 189 --------- packages/nx-plugin/src/plugin/types.ts | 25 -- packages/nx-plugin/src/plugin/utils.ts | 65 --- .../nx-plugin/src/plugin/utils.unit.test.ts | 160 ------- packages/nx-plugin/tsconfig.json | 17 - packages/nx-plugin/tsconfig.lib.json | 17 - packages/nx-plugin/tsconfig.test.json | 17 - packages/nx-plugin/vitest.int.config.ts | 28 -- packages/nx-plugin/vitest.unit.config.ts | 29 -- 73 files changed, 4272 deletions(-) delete mode 100644 packages/nx-plugin/.env.lint.local delete mode 100644 packages/nx-plugin/README.md delete mode 100644 packages/nx-plugin/docs/images/nx-plugin-dynamic-target-configuration.png delete mode 100644 packages/nx-plugin/eslint.config.js delete mode 100644 packages/nx-plugin/executors.json delete mode 100644 packages/nx-plugin/generators.json delete mode 100644 packages/nx-plugin/mock/fixtures/env.ts delete mode 100644 packages/nx-plugin/mock/utils/executor.ts delete mode 100644 packages/nx-plugin/package.json delete mode 100644 packages/nx-plugin/project.json delete mode 100644 packages/nx-plugin/src/executors/cli/README.md delete mode 100644 packages/nx-plugin/src/executors/cli/executor.int.test.ts delete mode 100644 packages/nx-plugin/src/executors/cli/executor.ts delete mode 100644 packages/nx-plugin/src/executors/cli/executor.unit.test.ts delete mode 100644 packages/nx-plugin/src/executors/cli/schema.json delete mode 100644 packages/nx-plugin/src/executors/cli/schema.ts delete mode 100644 packages/nx-plugin/src/executors/cli/utils.int.test.ts delete mode 100644 packages/nx-plugin/src/executors/cli/utils.ts delete mode 100644 packages/nx-plugin/src/executors/cli/utils.unit.test.ts delete mode 100644 packages/nx-plugin/src/executors/internal/cli.ts delete mode 100644 packages/nx-plugin/src/executors/internal/cli.unit.test.ts delete mode 100644 packages/nx-plugin/src/executors/internal/config.int.test.ts delete mode 100644 packages/nx-plugin/src/executors/internal/config.ts delete mode 100644 packages/nx-plugin/src/executors/internal/config.unit.test.ts delete mode 100644 packages/nx-plugin/src/executors/internal/context.ts delete mode 100644 packages/nx-plugin/src/executors/internal/context.unit.test.ts delete mode 100644 packages/nx-plugin/src/executors/internal/env.ts delete mode 100644 packages/nx-plugin/src/executors/internal/env.unit.test.ts delete mode 100644 packages/nx-plugin/src/executors/internal/types.ts delete mode 100644 packages/nx-plugin/src/generators/configuration/README.md delete mode 100644 packages/nx-plugin/src/generators/configuration/__snapshots__/root-code-pushup.config.ts delete mode 100644 packages/nx-plugin/src/generators/configuration/code-pushup-config.int.test.ts delete mode 100644 packages/nx-plugin/src/generators/configuration/code-pushup-config.ts delete mode 100644 packages/nx-plugin/src/generators/configuration/code-pushup-config.unit.test.ts delete mode 100644 packages/nx-plugin/src/generators/configuration/files/code-pushup.config.ts.template delete mode 100644 packages/nx-plugin/src/generators/configuration/generator.int.test.ts delete mode 100644 packages/nx-plugin/src/generators/configuration/generator.ts delete mode 100644 packages/nx-plugin/src/generators/configuration/schema.d.ts delete mode 100644 packages/nx-plugin/src/generators/configuration/schema.json delete mode 100644 packages/nx-plugin/src/generators/configuration/types.ts delete mode 100644 packages/nx-plugin/src/generators/configuration/utils.ts delete mode 100644 packages/nx-plugin/src/generators/configuration/utils.unit.test.ts delete mode 100644 packages/nx-plugin/src/generators/init/README.md delete mode 100644 packages/nx-plugin/src/generators/init/generator.int.test.ts delete mode 100644 packages/nx-plugin/src/generators/init/generator.ts delete mode 100644 packages/nx-plugin/src/generators/init/schema.d.ts delete mode 100644 packages/nx-plugin/src/generators/init/schema.json delete mode 100644 packages/nx-plugin/src/index.ts delete mode 100644 packages/nx-plugin/src/internal/constants.ts delete mode 100644 packages/nx-plugin/src/internal/execute-process.ts delete mode 100644 packages/nx-plugin/src/internal/execute-process.unit.test.ts delete mode 100644 packages/nx-plugin/src/internal/types.ts delete mode 100644 packages/nx-plugin/src/internal/versions.ts delete mode 100644 packages/nx-plugin/src/plugin/README.md delete mode 100644 packages/nx-plugin/src/plugin/constants.ts delete mode 100644 packages/nx-plugin/src/plugin/index.ts delete mode 100644 packages/nx-plugin/src/plugin/plugin.ts delete mode 100644 packages/nx-plugin/src/plugin/plugin.unit.test.ts delete mode 100644 packages/nx-plugin/src/plugin/target/configuration-target.ts delete mode 100644 packages/nx-plugin/src/plugin/target/configuration.target.unit.test.ts delete mode 100644 packages/nx-plugin/src/plugin/target/constants.ts delete mode 100644 packages/nx-plugin/src/plugin/target/executor-target.ts delete mode 100644 packages/nx-plugin/src/plugin/target/executor.target.unit.test.ts delete mode 100644 packages/nx-plugin/src/plugin/target/targets.ts delete mode 100644 packages/nx-plugin/src/plugin/target/targets.unit.test.ts delete mode 100644 packages/nx-plugin/src/plugin/types.ts delete mode 100644 packages/nx-plugin/src/plugin/utils.ts delete mode 100644 packages/nx-plugin/src/plugin/utils.unit.test.ts delete mode 100644 packages/nx-plugin/tsconfig.json delete mode 100644 packages/nx-plugin/tsconfig.lib.json delete mode 100644 packages/nx-plugin/tsconfig.test.json delete mode 100644 packages/nx-plugin/vitest.int.config.ts delete mode 100644 packages/nx-plugin/vitest.unit.config.ts diff --git a/packages/nx-plugin/.env.lint.local b/packages/nx-plugin/.env.lint.local deleted file mode 100644 index ae6151bc4..000000000 --- a/packages/nx-plugin/.env.lint.local +++ /dev/null @@ -1 +0,0 @@ -NODE_OPTIONS=--experimental-require-module \ No newline at end of file diff --git a/packages/nx-plugin/README.md b/packages/nx-plugin/README.md deleted file mode 100644 index a1fc57551..000000000 --- a/packages/nx-plugin/README.md +++ /dev/null @@ -1,68 +0,0 @@ -# @code-pushup/nx-plugin - -### Plugin - -Register this plugin in your `nx.json` to leverage a set of generators and executors to integrate Code PushUp into a Nx workspace. - -#### Registration - -```jsonc -// nx.json -{ - //... - "plugins": ["@code-pushup/nx-plugin"], -} -``` - -Resulting targets: - -- `nx run :code-pushup--configuration` (no config file present) -- `nx run :code-pushup` (`code-pushup.config.{ts,mjs,js}` is present) - -### Generators - -#### Init - -Install JS packages and register plugin. -See [init generator docs](./src/generators/init/README.md) for details - -Examples: - -- `nx g @code-pushup/nx-plugin:init` - setup code-pushup in the workspace -- `nx g @code-pushup/nx-plugin:init --skipPackageJson` - skip `package.json` update - -#### Configuration - -Adds a `code-pushup` target to your `project.json`. -See [configuration generator docs](./src/generators/configuration/README.md) for details - -Examples: - -- `nx g @code-pushup/nx-plugin:configuration --project=` -- `nx g @code-pushup/nx-plugin:configuration --project= --targetName=cp` - -### Executor - -#### CLI - -Install JS packages configure a target in your project json. -See [CLI executor docs](./src/executors/cli/README.md) for details - -Examples: - -```json -{ - "name": "my-project", - "targets": { - "code-pushup": { - "executor": "@code-pushup/nx-plugin:cli", - "options": { - "projectPrefix": "workspace-name" - } - } - } -} -``` - -- `nx run :code-pushup` -- `nx run :code-pushup print-config --persist.filename=custom-report` diff --git a/packages/nx-plugin/docs/images/nx-plugin-dynamic-target-configuration.png b/packages/nx-plugin/docs/images/nx-plugin-dynamic-target-configuration.png deleted file mode 100644 index 6184f2e39cd47a6b546202d25ffc83164bc8faee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 48819 zcmc$FcTiJZ_pSv+K$@sX7ZFe?5$Rp2B1*B)2_n)7p|=oFq$y3L_m?ixTPT4=W6wBIqN-DVWN8S&m|-Mb?45%PXxJS-o~o`^D7e-R^dr& z#D9qh3TFNHb*5lE6%F8@0Vp>(nrpy6?p{_S+Zr#{SoJRqa{KTQCeeg!aK z;$1arFWcKGobJ}H@f!w|;BEX`28zb8p65ocVkrb@A7s zkfh~;aqqLeu=UL>GSMVW!P8)6nf0o}ILLv=-(=dL44CBm^iOGmi>5hU5ci(!mBu!Q1?>70(fwqtoWPI;f5ubZfbzDysiBJmJ80t`Pkn{gw9!BR#!*ep ztl#z+VbXECTFBYIo9~6+Ay2BD?P7rlVM+UVb2diXqz`7k2_t6JDxYpL6u&_>@K_+; z)k0q{3Bk#OU8?Md)AYWX6+dd(r^3ZpHVfccRbSq$=Z{{v7#dk6XyK13t6$|E!Y4wq zDyuN#FfMtoJ8CDdSD`mz3}@`E1fL(^CrW1D zPR{NIlU92b2w{EO6=)ux!A!^|A2HiD5M5(kthm#@PBU}83?HiTaWr(gV z=*A5qhGI<6Q{$A^nTmdlH5dyoIEf6dLkn$Rhj}ZV%%~@v9U{wMlXCzE;vr9kzLnrq z@%GKiVlY%9-8)Q?W6w{KlS9$DY7-pxeoCuH>LE!C=6+L>b<4Ho$WlkhAvb0{|5>R9LH7(Ab%R({6$peof133l8Y94! zF?Jo=hA@!5_NNDL&gRAji5v2=b6>~d7(L=xg78v2(-CchlQ_0}Z4GDlo-(*vW5^`J&MRWiwmw&3lRX_7AaE0=`QFXr7z8(8KY*OJ+V=7&GtbNLlV! z_sKTE^fzmvSC~(wrgiAS47j_$;2%zfX_sOHAM)k-G;}LYUQC-D_j;BX6+I)Ia%7>9 z7H$y$whLDPYH>`~Ro>gXQEpSuldM&wmwIq#gH({JJUYMuM_pwgX)Ma?Fc)B4wD+sz z{nU@am&-qvLmD=b07gwI}+&u0zsohTGd!X^>XC-}_ z(@F=v?YGx)O8&8W*0gT`Ux9V`XC<0$Lpm?TJjX6)3u3x=L+>CoJsOVZ3PFnnrA6C( z;VxLuVSOJ<8kSX{-z*gI1aSNlU3J##tt1@V%O{P!DPO4Hu_Bb0<6bp*2l(Wl*G;Hf|} zw+Kn_Y)1!ej-KB>+Y+Skc5?dXovODZkN&qO`8zxy-!(oN^D?M(P-HcK8n&OiqoUTg zIE2LEZk|=SJ@w8_`oyn$Mf$7@X=Y<#SQPgx&G4za^K59T|Crew%W01d=d;Oe(L)b| z60=2IrIrh+vy?Q$Iwx!w#)!M_`NzDNe)=*4L!)mwp5c(>fw^vh5>f5r5Zy>a%EPX&88pxw38aDoA4ZaDUw@yiW@@U(hbYk7FO)F zsEGHZUB!R-9W>QSmn`9#IO}1EaG9$WMa_`9wg2|tc&G``uUId-PFT`$b_(OMk4c)f zkzVPsg;GaXWWc@9LQ~p#;S-kPbMid?b9`3L2;6-R`G99@et+y|utz#8)|${1LfAuR zotTC^67xab653f!A{^njr}5>1?>FK5RqEPFM1eZVHHlq!7zkq-qFnx#5~36Q7WD*< z0!~VNr5yUz(vU8n1ErmoWH4rRzgcg%r^Ed_9E8q5T&zCafs_FHlF8U>doFIV=^{0Q zNnBzE#fwB7Rq-X>I^UjEP%7see>G?*0vzz}#*c{u>!*L1`xU`9%IXeMg$1narAM1X z(8UzTEvk63e3Ur=p}Qf3(@tNLbVyhU5Q z&W;Z!kI6!3yOX9HJxP1$BdsxUUDiL}c(aps9e6Hnt}3bj18;80_D`%7bj1u^clLP2 z{@)4RzJg>AsQz!%6~gd8p{zj@A6dWs@1>^59n{!s{QcimwEd(yOQ(J)u`GH-9HJSn4 zWSw@#;Y52j*9a{RT)RD z_1Fr?pxhP0A>&jM2yF1n_~ne6=zRWkPE;ar-CfnW~6`HR=BH7rhgMml-*5S%zgMIBPa}F}M?5k};@PN*?Yc?snfa zchP!1%N$l(>7>j6D*(b2$;N*=axPnurVUEG)`&`br=3{3Hv~U?KeaOw=X5YlPfq#% z)iPJ0@yZ1$=Q(yI-6}45?_=B>#|d=!NE~P=vzhF>Ta}PGN8XUWK9GTI@6=7jj@(yE z>`!j~S@1k-U0={;uSQnNaqy0^*UmgIhqP-b-GkeSpw+5hk;K)i?$+)3MN>f4nRS$k`iKg_DT-I(sbAh^ob{{*T3zhnCUdjhSpH-ORH ziZ&1ecZG<2l~dcqY|gze|6EAf9LK-Ff4QfN45sY3?F=)c>p?LfLMvBI2{cSi|GN5r zu0VISNmP?!pC`k9bae~mK)}GGwDx7VtmLBC&JHtR{QQ3&q`c9AxjiB|EIlkcEI+Im zAUa5i4xTt58UaDFKB%tvXKcz1Qa#80FYmt~r)KH3J8nna`i#v}fjc`im;N1CUH?>s zrTOCQMbaW}z9b~+;`O)d-0JY~f5rHWF#qv8iJAd@nFjFh&-Z}AYTJ(wAD26c8!K{C* zHGn+_uz{)`S^=1Y;fLHFv3K$5?oUR|n=RoYrq##6Rv;u0j2@Mz7XsPm*H)%VjpcK|p)I7&grZ9lAx<}%x>nBxb zTx8$TCtlgR!?9L_{oDU&54gOL#vAH18|!JJ9JM%aG>^^wT<&rAxVKeVS4KImsL3l+ zfg%O>naIdp3C(sUy2}zw=gFVKD61c#`K_fZwPh9};uu&3bXiV~f^I|+f1fj)|=IqRs}|BqNI|Sn=1xo4ywfl$Xd@$#qkvp z6HB{?h1cHRZ909Xz|Owh^^tEAi`z3j%eEr9ugJ1KaP6#f##nDdO(v8?4oWu}GMH=? z@lAoRbNm_DBzxvgmbBr57}JRobMG`U+t}HZLr){H0t35w}c#eZxQM9GKrPE~_%RI6CLuI1mQ&yL{wOjiD+OMl&=EP|Wuz$bYA^TF6_)vr1=QxD@Is@eB z_%u82Mr8*4@WG=yY2nw`rJO4@fk!``19td@@E|CMv~R&cIvlm-yC-r+Id?ZO!YsbU zdv>hR8~k|3(1SrvrDsLMQ8?JH8R7 zV_u4&ffEtL0w0$#kzxAies#&)o(F_|4t3CU$)$!90&DY5(3nrvmkgSQn{CWeY7*zp z1|xN{^&iVfdg|CD>pu^3uhOj}%$`gw*C|<=2Xdx6q;uMHy_oo#QS|*IJ1hRL$cJ?j z3*M_4)-iH2voFGiA+0W8!x;^|O9iPE4hIpVwAT!!C>O zLLU2P%mlNNo6mkeDL#gpLN?n*VRpx+UYsSZ!>=t4iF5J{lCbDH2cDm(ufvCJLz7Ip0hKdv3{g zBWQ82zmK4DZ_9aXgOe~`WE#Q}HlwA-oYi=;tw zfDnhIWuvs$^7KH7M}8x36k=T)TlV>+tHT7aW&i(;?xXvXF+AI+a$ z>(bzADc-=|mt_tY*QX&B=x72l^x`)ktMOE|o& zhVi)b_{3!fo^7dADckH{-!aoR{pRm;J9Vqei>3FvzdA!hQJKxuFI8HG_zynvb-kdM zvUlKDk)Ht1jTH2!C$Tf3EDa|D)km6Yd#~tx0XZ#j}?0JbFnOuyh%LDW1^R z$6H+F*>d-okJ;vpsKib9OM>aO69bBLs4R+i6Lpqv~ZFHX#EET3ASMibU&%D>>eH^jQ3Eyy(s(o`bK7|0_YJczK zHt#som?Hd|iSB|+o|QC!w;OpWgqJP>$fBus!j|$*TzgVIqh{1e>BbKQ-6_h);^=E} z(p}cD&ej)q=*gkr7Q}J$$ztxpjSX;}l5?Hn>6cmJI2w!5MezZySJ+pxHhzL{|Kw#g zE34n6fv;@YZbWNZ;H~eKL-j_-RDI5)gH%s@a2S+z-AXM4-)w!TOe!lRdbN~0y>dCR zx~}F-)zAX#;Ns_Z;TN1f7s`Tf?#QWZ$Evx*nVQt~%i zD($8m;P>NKOM@)@Qe06M0mxu;t~GM2d{#rZ+mwiJ>D!)OGQ-{g+G}dD+<&7lN+wZo zo5KrdRgTV=R<=2gNIVRu8TDOX9QB%Q9`Zd|QYDA$B!%FaL>|L=PAJ~iuOHZB(dz8` z+Zw)DIXRejLvDrb}1j{q${G}mof1(EBV;2VsaW`(YhKKv1f*CGkvqsV;~ z=d~({vH=)57|tE%K}~*C6{-h>AWN>5L1)U4+rG$9yoDdKzA)_ZMY~UF+&(?jq6^g4 zTw-2dNC%yo=2tHc$nSf=mGL%~+qz3pJC#nq|1P6LV+d@`>BEx=p&@Y`dIEinGOA{=Msgpj(VfZwj>_^6g4u zEuB29<#vWMnSjWKcV0qPyr}3V9-kFO){47`|9~-{?1vOa1!?muHA=K(pG~2YB!cJy zbIS&#Dv~sq*XO*G=^2%#3=@!y2*0WLa-E;&{YLc5n;$6_J3x*ESei@e#^$Gw# za3$W8$q+Iqucqv|5y^&YbK6_Ne*1>#y3T!lD#K;pY3Wh*tJC$qX`0Zj z^;LVaqJO4@mGd(n<0k(o`7??!;oap3x85er?SFq$Jb6c^UlW9mp5gc zMHmcs1g{;KOeN}pbNrcfzZ2W--4(c|=V6+_1IL^ll_jbJfghJVXnkWDa_E>JrKvP% z>ZW4}D)-nFT^p0crQb46ufO-gLZo2o&l|Rjyq%s`C~wLL`U%_0^ZJ1C7`ty2 z^ic020UcCf75$P>y0yGEVf!7|#VuPiQXqm>99`|C2JY-nxv;$jtCdpRN?tH)P7u@M z-yDB=;^yWuuLxe$j6AFjbMl#~KDz?J&JLLcPc_K*5d|*Hyzy4z>aFf(2z84}ljsBC zEq7@}?_9I2QAFV?S(UHEz0i*tSNZuw?a8g2Gw>{849)5qi;(g?Q2A1(eLMx-$Sh};*%Qq zqdWHLRfA$n4)17JvyXsZG=l&g;s?t`g&!9+Ge`=QNS&OK)PVn@`a+_;>diXTn0~cp z>(t6ij@-rNp7WLo7#;cuv8#Wd)z4*S(iz3c`FntS_Hp~gW4$wDeA3ae%+}XHmQ|Hz zW+3IXIT|2peLg;+`TdvpvbC%sH6Lu0cGBgr1%wTQ4x2qtMn zZT8}mpnG9k(6AGn_zj@TpcU2g8pc>o|DkW(KfeJIeAsZyygZ_py{^nr!b*y!Ycez;I0cd)9*{J>^75N6kI?SOejN z#e`*He$zV3h&Mlejd#Qbs9rlr|L|Rn=g8i8(fMWczI?Pf>dC?FEb5SI2L`;Lfib;PE!J%gR}#fVg}%_XaQ#7k-7&v z#_H=cLNuxK3NTJz{xjAVZ;qsEz@4HUeG3u22eoT_nn2c1JFPE6FKHVXeau;Ym7`s9 zcR_noW3$9$HW3SNbN<=CKK2=#^YD@LUP(N!WhCO~ur6}9D1uRqZN8?{kq)XqC5jZu z(lo6Iqh=Poa!ZWs!|e}GM@kQwED-n&(-6v<(9n&r?QHFU5p6UY!$k(jeA01f7)j2j zCn{zdzkSnF?DMc7=ML>Jj{G$p?v*8JCtXt!DA{O!0UQ zHq`sNj^>pOglklKG72oYK#ZQHJ{m2!W$rG}N;e{TMWa-Xzx8#^kV|l$Dfc1C;ODDy z)+%jhKZ!S#+|*9^cGQIj6L#rsqJa&&%#i$_IG`wjt%ZC=uc4NYbdfkm=oUhR0vH&g zlZq#Pk^?lAI3xoa0mvLhqh}qiWs96KF0`xFIGVpQiZF%=aVN*~eM~^3OfOFv+li+9 z00lzYwy6i9iu@WIB3F&nF5&6jprD{lxWJ~uqg8TY9J&44?VQ&+JC7Xau2HNkl*~RU zP(TOR*Uo9Q<01H;uY`UFU;<-Be%x+iI%Ywq`n|}I#o&dEv%S_#{{5!Y{{E)LoLF|3 z97908{g-4$&t$i=;C@=_u4|o+5Efo&E^x^Bf z(s2XsIc?nJs{U|mWwmFoOGdiKc)#%%TwIe_oySx+g?3ZrymtvQc6;Q}e|IR!G5meX zBS%EB(?-GwKxX-3Sd9C^UomviN;;xxU3Z#p-|F!HPOWq1>8)(L&3Ye~#Vo``E1;tr z%-RcgS$%*(Qei_*&Xb2i>x50;9bbXORw#sh=SXB<7HIPLJ)s=7qmn7i`(;q(aq{gS zeC9q{F{p6DlY3aA4|iY9cW{Zk*W=eJ50l|8Q#4*r=ChsE-s=_c1aN+PmPLq&)jdr! z6y#%SAMnWCL_NKUwQe1k6}$mllib{i3t_$UxL$x(c=v_2)2Vjw)5aYYxEl7-@Ss`R z{iX^rmyN@8?O<9=HC1>%C_aWBT;7B)VhLuw1GLL}jt!}MSiAa7ZCt{c^vQw+9cIUS z$FkQzYmF@=>HEgZnfw3pBu(d1(snKwN4?DUV-Y%1zhSW)1YRVcWkL<=>;);IVS%t= z+TqVKE5_n}+3+g6SkE59Y}jVdJl*eSCSQ5P6Q9pFSiZ(V}zdXcb4?0^E;9-Agzl_HxSAzt9-$Xp^{jSo?orvnN%H(RUjCz{-N@MemE zQ(*~XX?Q2lD4^CFEm}uE!lCA^R-r06^4y8NA8A-N*EcDRE%@z8(Q z6J*$mYP%4YD$VuFaiV3~Yjcr72x2krFh0>Yw3k544Cs<}=s0g(&YF(m*n%i^nMN_` zgg>y18!rICiKEO?s@7UBN<(G6)d$}-@RIYjNruG|(YhSbkz zSP_T=UL^gRPnwILR61^YS*6*Z9)b{Lyh8;c?xfj7RewC7_{M36LXt#Zj!gL1?Us7o2o_pY-i>Om@qvfUBy+g^XrfB%5u4g02vS)C+7g%9 zO!!TANg6k`17ljvEbHwXO6p3pmbhD(nGN|-V{$lr|x?<0y-mY|?=VtluRSj&2 zw2pZk&L{7hcDi%@wycn$AbjF>3ZEWo1{$qkvi*f z79o4+lT!N=GuL6$db=9*FY!oEVemd4eMqa@+Ba0?`*FKf!g+Q8T8p(RFzM52{$w#b zo*7sd+)T8W<&d{ew1_h`xdzlxz1roNw<2t|b?2(K4g=?NPSfaWEdYan{*8^WN4}j+ z8tb>i1Kaj&;xBlF?DDxZxQ-si&#ZFOwu0 z=wD!NMS2Gxo%8SFR=Z-j!9SJWyW}#q} zoO4QS$F3sww!k=`!9TjweLQ+lNXa(r+MmPi{>%u&DCAu}swspkB_stWVWjMx?l2oM zj5k4tUi|>EURy;%!y+r2vS&8rTXFsFq8fJ`o~J5xDLvSYQasuqdabLLAFa0=&(*r( z2`p4s|1*mE?hNz!_dP$NVAk>`s$1`#3M{s596eURANBlh?dzq7fdqvZ-H z5NzpV;rl%bUc7ONwnhtWn0_l(apn{~E#tYiDsHL!0^jb6kE;EX!cnMGJ7-)QkXAa? z4ZG41!HfH1Ok|u2TIO&vocI{G!jD~+R@uP6N~ojzsH`d0WOQpi8g(t{=I4JhR=A|2 zcfus&3a92xMVF(d=#f%%?bsX|0-f!+r#$~w$Z<5{ltmJRceN{ z9Z;kj5xlNfL>x~gMre_oyb`{K>igaq${GKktDr^Dn zn{a}0!4ETH6aTLSQleTOQ|Y(b?Y}lr0n3GeG`pBFA3J%2zNaH&V|DIfFPek7v*Nx==%eR8_g+g$^vJGL+d9hk zKH-r~vThvq`5_j_`?W!$^6Yb0zOWgTU0))3{gzTaMcb-zpDLtdTIt(Hbh3m9l*-URKLUilND!e(R&UkkZ0?Ap(o=O@Xf-pi-WEG|k85V=eWrK8X&5Weg|h)Wb4wtY!rGy~Ejv0< zNHV1BkiwzaHw}4HT(FyNiqd4k5ODsW+jqn6H>wzPx|D+3e`Au@7bR@}u22!ecy#FR zjR1ew3S5~{2jcJ&!N_B}kMW-yJeKP3 z!_o>(kwK&$cVKegY7*oyOw1?II$XICsbL;)pPPZ@s4>bEG+tknSi3z>(>0X1AHk2c zaU0%oC8xQhJAK5HR(m??Wx_QA#bg43$o(QnB;haZSDf$D8zjKB+ zXOFSvOsyTdgHn5O5+P^AD(`w5H(=ouh}iR5AA!uqK8>yx|RcTv(GXcM+hSVc{2C+NDHwZTnoP-brIo3}in7UZ3 z0=mO1CyGqB;}TEO_I?W|3~HN5LIu{p zA(a&+kP4#Td_QUa1s)yLh|XA3X)AIL9!ea~eb>EB6xbYEkDIEtd|3SpG(PcT!g&pP zVun(b=2nQ$GbO=oCIp^e){M?jhG#|Y%c^Bv2tia)(m@#s7p_*mA$4wUM7T*hp$8R} zn*o;~RuMrR4~!ZfhBD{d#jp$#>D|FcuEZQCdPnrCW|p#e%-Qt&xooFj>k@R)+q$en zgO^sNOXc@#TC)PJOzXC3rG1oP1^0fJ&sdfT`D-FzgniX>9^=oNE8`NZvto97 zU7(NpoBxq_O;_y0FsvRn_y~PRc7V~W+ixA>AmI<7!k$8vfF5OD;FikJO#0B<;xr>iQ zd1lYbO4qFy(Iq2YibzV4q0TE3s&1fbCP3vwO`J`JGxOS&@Ce zstDY=g3a4{3@02ID{rb$N_lb|J?Ep*b!H0YWAOeuHhoXrf?Uw6rF_Qbsrah1N!MoV zRa7l1%*waO(dO*0vUB>&p$aj77ubSKZ^f+Y+o5D;=Fsz&RwX*0ZU$@wBUo^{JmS>u z`-|haeSFH$qqSDqE?j~UrhP>)vNqC{d0qdznlXGGYujvoPuq$3nj70Vi}g~4)3f4b?V+YN>6{=$(3{Y zeM^W{?p?D62xRzszLI6(oO+u6dpWo0(;U#dDYqVRZk%6^(6hu+=TD(g+Eaql5lGv$ z@9qd3+nJ3S#J{NBmB_;wr>leqm&HWlctaD4jxszqWq&^I7fSH*N*Nm)><3H>H*cjt zKPuSv8^7mAP%7(UM2ec+P~t>(a;HShq~M{)7+YTgFmb{ds{aEBvWBSx+w%~{4$VQcSHs6lsHlvyd-w!VVXC@QW@Cp zo-?~B^DKeCOY-yBz-i6d+dcCVU7NuDM_j#AHmgw1=jn22CDE6IQs7x%6;ta+iWx`J znn1zTxQEqcr^|4em_6C*4KcSz)4cA$9tCCTZ+{3uiM)fFN4VTfYv+MKz#Py+f%Om1a^&ZUsm*0>$-sEY6l+zp~sNIbPuUdUV zrauT;5vCjts@ z3oFWD|u_t{f+*tqLB(fF!Dm73#b^efi2r%Hg}PN-eJmrL;Oo zF*L;2K5ep%Z8~~SiXKYW;;=hI`f^I!X_)AS;@SX2DNB4Y=}e!Y018NhP!n7 z>@8he{WIOg*O69t2}mg}xG_3f(W#@icCPSgAevyV6q;E2G_mDzuk5>iDl~$REdm8n zt>?)%i>#c;<{Yyf)c$oIyBsKr>^Na$-vVjE_oU^9@?<6Vb=95(2jyjW`(UyGdWn>N zoDjE2Z;01Pw)b~O!z|TD8K>3!gqceBn8RY3!4*-X^an!j%%1#f-(A0V{mjk{;__;s zm$6k%HvHWd$*;z;CTF8yrAT{+T1C+o^`V7tvnXkenmw|i?koIeEJ=C9Roi$f`Ez%+ip`RnC_yv<5` zPQiWN6~SPw_P<85HwMriFpZX*s;bJj71tiK6+TbfJn&g9joFMQW>q0Bh8~+K*{?lU z)=}!mS+$x;yL8{HYug*H8^v88eW%l9KryNVr5fk9mDli>+hU7tGMPx3{vo;&`@ZM^ z2GZj5_N1&kO*?3v0QF~vwYWJ^hZw}pN2q=_td^1NLF73xj)To^WZUA=j+dTIF9HIW zF!>ni%;>XhBl$3Um9b)I{dYn$jErn zBTbrJ<=OUmz7o|*B`L3kt9`Ve1e8jbHNNU?0!g9AyS`XWzv=#CAUOeRlepL3hz*|q z>jtCr=tb2OYDOMgE|stp8Ee=k9idZCBF@5p->g7g5a4GZn63WzbU0{0QuCYQQ;JTvCm3uC;iyJNyE( zofv|>6_{EDs5xE&rr&ml@6J)*XVHH~>E_Zpc;eLOcJE}aKtxOS(Pq2%dK)9fwymH& zCRuO!+FR{gY_!NU#lceG@us*#ixWmGeo@e(46|5V;lPVE_C58P4dza+#UQ+4Sen}2 zPyIROUU`qD;0?irE~ouqdnrkjZ)?2qgjkJO*U?C~htJV-3+I`fIOyxVl3GToT##0r z0NhcM;5>BDhZ5VB92-p#H7$QQ7Wz2SMR)a zUZ8{e9R1c3RftS^I6G8`*|?%Cx9dNc-L#)2YPmI!soZ|W(EB1-9sbpO2%!o+=EH~& z3cSd$x)cH3T(~|DV73#MUgDfi7E?#$Ju#^)C4?w2G23Nd|GFVkX)~Qsy1HZ^=08a^pmgqRIg{i=F+Nr zMtqjr0S(?FU2wsOlXKMJjJ*UueZ`I&oWz1ugEp8e^^sR3tLs?KoCwPoChmNN(|5kXPFjzjN%9 zQ_`=CqJJ5OTiL9nt-U`dA4$JcYwH0{Ee|AV|bjp2GW-tW)hOLuC)b*9Y z`!cLEPX?0}F=dE@kMrY(y0gQ!1sPf=8gcW<7Vc@2A>dfIC&{{k04RzVyy2>yO z;Yo6Vm-NPvNW|5Ls-fk~K2}2FjX_19U%y$Hjc{PjPDu*DEqE|Ew6l{RX~T z*5rksje)zziK@+CUGe>G3>O=+!ZsOhfG1}``Mrh%Wtw|S99@_s4Jr<$z5R9PK1L-{ z>zHPw??#IB24VgKY59lzM$6aBS(xJ;aqk_SNt-L2bgY1CZPn(z<{jANVj?87LK*1l zSkL%-`Oak|SGdZ46h-Y8ZhGtb(@;n&32TV0vrM9UJ%mWbkOLN>z@a`>;>#pQXXvmq zLl!e51Etf1;Wrnf!e*a5xBs0Y#}u#w>f=LOfKko3@))-o`)&VWh7^6{nOweyr#K66 z1)Rrs5G_rTS?-WUiq`yk;f<@+R6*v<3cV@E!R`*QXKw-;P6k~_cxUeu+;`VFGnvnX z0&f36@b~TJ7{psjKWXB_Ec%_}_*2UH*DjE5^<6o7J8-m&5qC!~-C4L(Zr;hN5Y7`Y zvDHV+G55q@oau^cJ|qb z{pa_Ky_Fu=c!yMO0wI5t#VX8;c#F!di>L3q-iI>t38uK+aPfvSJW}@%ti|Rxf$%m4UU@c z>7Q`$sHT9Ddnj08{#6v?VQ=^Y;S3&*fWtmR$K-bnKQN|5m$S?pPLm=tXZ}Vd3tBwq zmOBHVQpl8toS@7d=9^h*EiQXWVH}#A%h&RYLm75!-;_-JTnkQnRo3xjzO&pfW5uA< zOPrOee)X=1^W$RZWWN$Ir%KXpVuaGeDu3E-;D*c4SklPEf9ABmm2Ti%QW(Z@F7th$ zc|HR0#a`4fT+L;SLm)tF*8Xz=5+@KX&~9TZnykas=itX7;5ni_vH=O@#~Lx>=Vs z`$E$BdR|#2idIlXrMa}yw$UmAv zEk-Wn>0RFFWU812ThkPzKbxC&(iX(rxXrQp)SKG4Nnv$84?gor<34)XAj9gEg;!x6DFw&?qxuqgt{JLo z&TuQ}<>;NpSfzJNzKyv&dm?WT1+@;Cwiv$K`Wl_gBl>22FJ%(@^rIVEEc1sJZXbV3 z9iGSv0FL~a1aS+j8aPjSWd!z*O!B!tUj^hDOYe7$EEb-;+C2?<2G2myLqiaait!EB z@U6Lknpx>=;YfA0%TAvvRM{gX_f8+|D|gC5v+MvT50>q2b$YHK*PFc3mvB_MK zjv3nLa{AeJJ`1ACW65b{vB$;gtTIQekDtV&^)v$t!-XwRS?N|Ku7F<3jniib=(|wG zaBH7jhFLP)rdPA?)yCwP?MqIl%Epo>8oJJbSyoPaEu-JgSw_CH*|Um_r9RM@+2g0O zKe!VUKtVC6C$CdjRx##k`CYTFPaogwpm3g+It3+> zSr;sUt4FF?J*a|S)`COZ=@Rj%0W4cOd0FK&`NA+^a zoES&RMQvJ~;eI?MuZJkXG18;$Y(m5rFY0V5+-RhW+4SYGNWZUJ^;%=6>EEmoo|PSZ zmsMoZUTZdIyGiSx#-=AJ4ok(Ob*rRVbpLj8yCTr%+E5%wEz;IPWL|gUI0M%sdAxg_ z!}ObA^u593riauc&N7;T;=w2c2*})vVccZR`o36!ze_@X;?wY5mEVt}FvFB1r*%v8@`GP{g{PEC zrwb#nnq5kV@B1_taa^pw}3Y07kVgS!g%!D{vTZ_V$j+bN0(P- z{&n9d?@rox7JI9*W+F9GpH5^OZ0Is)%g+)f50ikBI|*^s;M-Opm+X=V8T_xm3@2q! z`1CDGVfKUw(MjE~gZEcBd7)iQ@SJ~xYF_%t4$5C>Nc@UGV=$c@?qEK^wY9xv%=YQa zHxCuBmc_hMVzkcR>XOKpqmiy7B?eGp-mnDWT^15x-YJ=F7Dsce{L2TA(UNJ6+7IK~ z@142T996wM!xpgCs@}L4_|FJh0fN^=!`FII_Op*KQQ`qRbG<>7axV$*!qO9C;J zH0|)rH^hI|BD;w-U|?S0&7*q}?ez=TCboN!r@=0*i+N=b`%^jS#?aucM=)Il*pqi~hu6#&8R5r~Iandnie9Cuk7zNs)I(XQ zo!O4cWxo<}QOLc5Ogkl9r1PHT88(wf^N!WxbCSg(XK!I{&HVMm9%9&T6g4i~Ip837 zhE^W);Q_<0{5(0%(Ih@)py!l^AO0ScvE{0(ZtK2=;*Hd;Jq3lMb*`Cc%M6t zVKz-gltKbB%P#V(p=U*vLu>ZW2}?vlOZ?07N3)U;S%q7ZjsA6!bdsvGy5QD|aMzWnOkrSX($UrRkF}adL!j{ApP%WMK)- z_aj#-PSMJ^WYdbwPk@nyedQejA=o+hN5B1*Poq3oq!8ES(iDxM82|!g1%ejyejx7! z#Vd{eZC!ZB<;Q+QDL*=#G)aR)eUTZGedS+I(Fw>y$W*L7bn+=wD_Q_qh&bHjV-j!e zS@cVL4h`(30oBs}@s#1{oLVGhw)xgLLgsQKlq~<6sMFL`tnSqc|Bklv%-R(7$GZ-k z;Wz%ccIqF|Gv5j33h0(_nqQ2$-%9a^;)9|7-M#|pftv%=RvcN2&04R$uUhzXgveh? zZm~{%5(V_S1OoK04FIW0FD#wwIa<6kizRck)mtfYV?ePBCdwS2&;4nBbvvj8in=tq z2DnsbO@7f0sp_vcEq_$OqrqJ4XvZA+H{|W1yHI;r{7ib-@#`cVsZw*=evK_>~7gzKYMs%G`O%zH}Kv7 z%SCuN!*tkwuwqPAq-4u*gO-|}3!&*7-5HlA!^IH6t)8B{_r~JwnY`qn=M{0hH+UV} zP$IPpo6miX+4-~?I*slw@zLKOyBl$a-VTL|$tH5du;dZ_Qmi=4@I+_UH z;XsJ%$IZwbitsFpVmik*zb}W+h0c$~X;vNQDw3uD?j*LPeUlqfBbsK? zyd=_RX2Wv*Vw@TWuj6gv49GloD~Toxr~F=a3|=Y@?R_-^GiL7s*`qkVn!y)wDXPy(?yK< z(yZoO{K-HX<#+r-0cBtK-_f|Ik#7`J0~xCryh)gs;{y6js^0Ivb|zb6ShGE2#B`q< z@l7Tca5`vAA8~+MA803~T*=D}zVT`}M)+k47Tr==E5Ny?-A`)@QA;93i&FOncJ%EG zkY#wRCwG&z_G={vJhyD81kelEzxP@0%&1Nw;|*qV$ap{uuLM=?B}fs29l^9#3JA&T z!EN+4FFw6m%iu^^LBz>Yh5zQL47^~beOq6b=`b1C(Cp&^qW$oWQ$gw!_2f;#huUii ztJECS%v$sOYM*}24&7O8ooX4nEbmSR1KTND_pos z#r%4!-E3z-%o+M_H2o!Kb)F_Hov!^|#ur-U9ECF-+EQ+vAW>HnJKf%0U-Db2E@`Vw zIX%|x)%?e~at5Vo5&p#gaUBAo9=L?q2hHT<4WW&j#nCEEKz6|RD~gW?Bucu8(@J}!Vdh)hdO z8Lxew*&eb1*VW1MZPgMzd&Ns6`^TVX4SNUq_9X^l2G{zd8^7-JxYh7ADcTe)r<~9SCg^Zl8jeD)|6d|~9oi>{2UHR(j zZr?q|3l2Pa8W@iCDx&LSGko0DSs&g?1k36egHNI>X4QJPU_mC`r~k8T0vvJ93d=Jr}Y*`=iTKWe4uu%HHPVsOOKwno@Y8mBNsg9dW%--r>0(9 zvuqIgcyF05??nU_6^l&Rb9?@b&qb#m&<#3gFuC;@X3_uv|(R z?=HJPPZxZ9mFp#kC?=!1wG$v#r!AROeDWMeAZphjgoyOx>rYA6>GH|fL-G^$m0=r< zS$AE=nQAt6H17-v$y9XOy{i^&=;3ihC$FYr&q>pIBD+b`05O*GJK#!ncTdpE_#{&k z@6lDcld0H1?b~yBoCMz^R%MuL4;B!1_=*He9fI!@c)~H(?E#`79Munvy3A z6cR5^v*p>_KS$_VH$WP0bIUcw(kUHU;f+`mTS+>=3`aw;frltv<22V^^_A;d2Nm?7 zPZnqrX6klw1XuH9*gK&Y^6UIh0Z%3CLF_|LQM@Gi??U-U)*DJD$atgn^(C2Omp9%> zekmZ`dO7ojr{uXY=B#Aa1N7*wfWDle!uNF60S0OY?|f!)>?)-o#q@!((pwy+2Oaz$@ND>{4UUs?(DgUeBzm0e8;9E8zFLM@0s9%k zpH;Kj6(9H;K5nwS^T1ia^v`|{YsgZo0;LepJg=g2Lrqg}QA!h&u9>{fV{)C%=x#WV&zY{a@8{Lx5 zI@S)suLAixT|smQmZe-i1*gex{V#9H-2J5vmlCR_Sm*rs%-NED`j8+T%14jULcia& zQlMLP9%4CzFhl^a`8K_mxtV&CMPlsSAI;8`HaJI8bUu(qEA{suRH5msN7f$i|ziN;aR5Lx;viD~kq zWh(4{#3d0R@@SYSk#VR0x#Cs`d*EJWcXl9M>aq*n(98BVN@qW>8xgM_%6m6rQv%4xX2j(4AhOn@X@GQ(&m9Ftv*00GFq#WmG6RyJ78;=u(oN=wAc~VhvCYS zjw>yf52dyqrrD9O4Szn;=#8=6JFcrSb!j?SBXc;K>~Ru_8S1=bau=17m>a0sk~roo zwR$q1!@T=y2k(f&DoV>N`J(<(yW+_QL^!Xt-n#*4jY0Q?z{5Eeekgcxm?gEd!{L{g z`QX@zdBK&qd!Uehv-);4C+MzjUNg+Mt$LbaRS~R{-PyQMbtu_gKn4=^lr$2w#k-Dd?GjY%@wd$-!-3Y{U^F)gaRl~X0Zd{ z5B{O}9CRj(00^wCOGsXZ-blXHfz-14-67dD!7;0v~UhXIUgZ zmkLS#i`!_Mq<<-;j5&JmM><1{1-dnqt#f?F|Mby!$h61Su4Qzk$T&EFV97v_R5KO= zF-H3B*H8je0@bKz9NRsJIWm(lt4QsgOei4NW4jp-_v`Nv=u^;(bmu+@#eZx~VB}4Y z6&b>&@HE*R4Miua`=f98X@(fv^rRY01-H=W0kQpk$_1IBM7rIZtI$&9LC? zcd;Cd7V46O<)dcXZ?=DVES7qTdKBFo%{QQ@{vI5(~baeu_W%D;He3oZ!Z) zg?6QO`IzctRYcf`6fI^7cu;ZmJZDjt42cfFP0n&P20 z>pA%w>on#hTY=k}6n_HbNys9Yd`V~yx)pBmeq^7NkZa+QPvdslaSaVGWq%yp{B|~g z!!?7Jeo@$4d1<4ZB)Iu?mSZ=J_m8Au(fA`ZelI#Tw$@8p-p||`L*SJ@9abVZ?6%?5 zDQB=?T_WGq^#mc6TNpE`<0gY_*|XC847H66T|N>$qqo(jW)yL)=1+w3Xr$wuh%w(w zQA=;C0pjWus3E!3WScrc7PqKFFfxRJr@1Tv4aC%wM%VyRLIMpt@C>8H8mjZy>gYPPSsA0B^kvN zuPk(O;k&LbCzDnMsdrl{=+=31S`fgM+A=8odQy$>z)NNbtNGpO2TWY!<;8tnI@8R- z*ZO~ufGYR>OXe@0Qc0e2 z*&9@ru~L!b%0$I*EQvX$_s@MJm+h3ZQYzs2{v_thJN<)Jar*oL*SHC2Qx!q?Ofu?F z$TET)_=3$G?x)-QC33C5s^7KWU@`%pa^@n77rhM;UjKGq+Xp1|EWh2GOgp}S;oyQB zYZ@RTgVNaR2~HlEgWLw@h)DN0*UcW*V;Nd>9kZ04r3dLgB~Id~7TEJBX=kJ2Sru+* z{pG(YaW0c0m$=uO_s5144*E{2mG7Mu!==XJ`qdB-F93PzW%t2=G%WFz#n!;Zb*(SX zlmk!9Pxu#Cce_gTn|XGN+m8zA`^qMlzvMoh48wW^?+0_~mA^}2PHkHwW;VuZTk?>q z?B4f`0tC1OSW55V-WObjzro3a1B!r{h%AyA{l<|WLU4BGwEoQg=mdHjX#++)i^bcVz-`_4j9`#El zL|jmNeS8=__#vpO2lbI;g2RK>V(@@6i3jj~Q0%img_qkVAvRdla0`HIUg-RhUlD#= zk_8~CxUb49kw^Y;$oy6~z2r`CuI|aZy0)(GF8(Kp3(PO1>h0R&R+TfTqq$lx?}5B? zkld>z#)g%8fz5z=sfAEBz%`Y~0@|%!w`&<`0eE)}re|(&=`S)vX>~5%kD*S%0AX8a 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/project.json -{ - "name": "my-project", - "targets": { - "code-pushup": { - "executor": "@code-pushup/nx-plugin:cli", - }, - }, -} -``` - -Run -`nx run :code-pushup` - -```text -Root/ -├── .code-pushup/ -│ ├── report.json 👈 generated -│ └── report.md 👈 generated -├── project-name/ -│ ├── project.json -│ ├── code-pushup.config.ts 👈 executed -│ └── ... -└── ... -``` - -By default, the Nx plugin will derive the options from the executor config. - -The following things happen: - -- the output directory defaults to `${workspaceRoot}/.code-pushup/${projectName}` -- the config file defaults to `${projectRoot}/code-pushup.config.ts` -- parses terminal arguments and forwards them to the CLI command (they override the executor config) -- the CLI command is executed - -```jsonc -{ - "name": "my-project", - "targets": { - "code-pushup": { - "executor": "@code-pushup/nx-plugin:autorun", - "options": { - "projectPrefix": "cli", // upload.project = cli-my-project - "verbose": true, - "progress": false, - // persist and upload options as defined in CoreConfig - }, - }, - }, -} -``` - -Show what will be executed without actually executing it: - -`nx run my-project:code-pushup --dryRun` - -## Options - -| Name | type | description | -| ----------------- | --------- | ------------------------------------------------------------------ | -| **projectPrefix** | `string` | prefix for upload.project on non root projects | -| **dryRun** | `boolean` | To debug the executor, dry run the command without real execution. | -| **bin** | `string` | Path to Code PushUp CLI | - -For all other options see the [CLI autorun documentation](../../../../cli/README.md#autorun-command). diff --git a/packages/nx-plugin/src/executors/cli/executor.int.test.ts b/packages/nx-plugin/src/executors/cli/executor.int.test.ts deleted file mode 100644 index a68c9d78f..000000000 --- a/packages/nx-plugin/src/executors/cli/executor.int.test.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { execSync } from 'node:child_process'; -import { afterEach, expect, vi } from 'vitest'; -import { executorContext } from '@code-pushup/test-nx-utils'; -import runAutorunExecutor from './executor.js'; -import * as utils from './utils.js'; - -vi.mock('node:child_process', async () => { - const actual = await vi.importActual('node:child_process'); - return { - ...actual, - execSync: vi.fn(), - }; -}); - -describe('runAutorunExecutor', () => { - const parseAutorunExecutorOptionsSpy = vi.spyOn( - utils, - 'parseAutorunExecutorOptions', - ); - - afterEach(() => { - parseAutorunExecutorOptionsSpy.mockReset(); - }); - - it('should normalize context, parse CLI options and execute command', async () => { - const output = await runAutorunExecutor( - { verbose: true }, - executorContext('utils'), - ); - expect(output.success).toBe(true); - - expect(parseAutorunExecutorOptionsSpy).toHaveBeenCalledTimes(1); - - //is context normalized - expect(parseAutorunExecutorOptionsSpy).toHaveBeenCalledWith( - { verbose: true }, - expect.objectContaining({ - projectConfig: expect.objectContaining({ name: 'utils' }), - }), - ); - // eslint-disable-next-line n/no-sync - expect(execSync).toHaveBeenCalledTimes(1); - // eslint-disable-next-line n/no-sync - expect(execSync).toHaveBeenCalledWith(expect.stringContaining('utils'), { - cwd: process.cwd(), - }); - }); -}); diff --git a/packages/nx-plugin/src/executors/cli/executor.ts b/packages/nx-plugin/src/executors/cli/executor.ts deleted file mode 100644 index 2ff27ed74..000000000 --- a/packages/nx-plugin/src/executors/cli/executor.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { type ExecutorContext, logger } from '@nx/devkit'; -import { execSync } from 'node:child_process'; -import { createCliCommand } from '../internal/cli.js'; -import { normalizeContext } from '../internal/context.js'; -import type { AutorunCommandExecutorOptions } from './schema.js'; -import { mergeExecutorOptions, parseAutorunExecutorOptions } from './utils.js'; - -export type ExecutorOutput = { - success: boolean; - command?: string; - error?: Error; -}; - -export default function runAutorunExecutor( - terminalAndExecutorOptions: AutorunCommandExecutorOptions, - context: ExecutorContext, -): Promise { - const normalizedContext = normalizeContext(context); - const mergedOptions = mergeExecutorOptions( - context.target?.options, - terminalAndExecutorOptions, - ); - const cliArgumentObject = parseAutorunExecutorOptions( - mergedOptions, - normalizedContext, - ); - const { dryRun, verbose, command } = mergedOptions; - - const commandString = createCliCommand({ command, args: cliArgumentObject }); - const commandStringOptions = context.cwd ? { cwd: context.cwd } : {}; - if (verbose) { - logger.info(`Run CLI executor ${command ?? ''}`); - logger.info(`Command: ${commandString}`); - } - if (dryRun) { - logger.warn(`DryRun execution of: ${commandString}`); - } else { - try { - // @TODO use executeProcess instead of execSync -> non blocking, logs #761 - // eslint-disable-next-line n/no-sync - execSync(commandString, commandStringOptions); - } catch (error) { - logger.error(error); - return Promise.resolve({ - success: false, - command: commandString, - error: error as Error, - }); - } - } - - return Promise.resolve({ - success: true, - command: commandString, - }); -} diff --git a/packages/nx-plugin/src/executors/cli/executor.unit.test.ts b/packages/nx-plugin/src/executors/cli/executor.unit.test.ts deleted file mode 100644 index 9af4f1b6b..000000000 --- a/packages/nx-plugin/src/executors/cli/executor.unit.test.ts +++ /dev/null @@ -1,142 +0,0 @@ -import { logger } from '@nx/devkit'; -import { execSync } from 'node:child_process'; -import { afterAll, afterEach, beforeEach, expect, vi } from 'vitest'; -import { executorContext } from '@code-pushup/test-nx-utils'; -import { MEMFS_VOLUME } from '@code-pushup/test-utils'; -import runAutorunExecutor from './executor.js'; - -vi.mock('node:child_process', async () => { - const actual = await vi.importActual('node:child_process'); - - return { - ...actual, - execSync: vi.fn((command: string) => { - if (command.includes('THROW_ERROR')) { - throw new Error(command); - } - }), - }; -}); - -describe('runAutorunExecutor', () => { - const processEnvCP = Object.fromEntries( - Object.entries(process.env).filter(([k]) => k.startsWith('CP_')), - ); - const loggerInfoSpy = vi.spyOn(logger, 'info'); - const loggerWarnSpy = vi.spyOn(logger, 'warn'); - - /* eslint-disable functional/immutable-data, @typescript-eslint/no-dynamic-delete */ - beforeAll(() => { - Object.entries(process.env) - .filter(([k]) => k.startsWith('CP_')) - .forEach(([k]) => delete process.env[k]); - }); - - beforeEach(() => { - vi.unstubAllEnvs(); - }); - - afterEach(() => { - loggerWarnSpy.mockReset(); - loggerInfoSpy.mockReset(); - }); - - afterAll(() => { - Object.entries(processEnvCP).forEach(([k, v]) => (process.env[k] = v)); - }); - /* eslint-enable functional/immutable-data, @typescript-eslint/no-dynamic-delete */ - - it('should call execSync with return result', async () => { - const output = await runAutorunExecutor({}, executorContext('utils')); - expect(output.success).toBe(true); - expect(output.command).toMatch('npx @code-pushup/cli'); - // eslint-disable-next-line n/no-sync - expect(execSync).toHaveBeenCalledWith( - expect.stringContaining('npx @code-pushup/cli'), - { cwd: MEMFS_VOLUME }, - ); - }); - - it('should normalize context', async () => { - const output = await runAutorunExecutor( - {}, - { - ...executorContext('utils'), - cwd: 'cwd-form-context', - }, - ); - expect(output.success).toBe(true); - expect(output.command).toMatch('utils'); - // eslint-disable-next-line n/no-sync - expect(execSync).toHaveBeenCalledWith(expect.stringContaining('utils'), { - cwd: 'cwd-form-context', - }); - }); - - it('should process executorOptions', async () => { - const output = await runAutorunExecutor( - { persist: { filename: 'REPORT' } }, - executorContext('testing-utils'), - ); - expect(output.success).toBe(true); - expect(output.command).toMatch('--persist.filename="REPORT"'); - }); - - it('should create command from context and options if no api key is set', async () => { - vi.stubEnv('CP_PROJECT', 'CLI'); - const output = await runAutorunExecutor( - { persist: { filename: 'REPORT', format: ['md', 'json'] } }, - executorContext('core'), - ); - expect(output.command).toMatch('--persist.filename="REPORT"'); - expect(output.command).toMatch( - '--persist.format="md" --persist.format="json"', - ); - }); - - it('should create command from context, options and arguments if api key is set', async () => { - vi.stubEnv('CP_API_KEY', 'cp_1234567'); - vi.stubEnv('CP_PROJECT', 'CLI'); - const output = await runAutorunExecutor( - { persist: { filename: 'REPORT', format: ['md', 'json'] } }, - executorContext('core'), - ); - expect(output.command).toMatch('--persist.filename="REPORT"'); - expect(output.command).toMatch( - '--persist.format="md" --persist.format="json"', - ); - expect(output.command).toMatch('--upload.apiKey="cp_1234567"'); - expect(output.command).toMatch('--upload.project="CLI"'); - }); - - it('should log information if verbose is set', async () => { - const output = await runAutorunExecutor( - { verbose: true }, - { ...executorContext('github-action'), cwd: '' }, - ); - // eslint-disable-next-line n/no-sync - expect(execSync).toHaveBeenCalledTimes(1); - - expect(output.command).toMatch('--verbose'); - expect(loggerWarnSpy).toHaveBeenCalledTimes(0); - expect(loggerInfoSpy).toHaveBeenCalledTimes(2); - expect(loggerInfoSpy).toHaveBeenCalledWith( - expect.stringContaining(`Run CLI executor`), - ); - expect(loggerInfoSpy).toHaveBeenCalledWith( - expect.stringContaining('Command: npx @code-pushup/cli'), - ); - }); - - it('should log command if dryRun is set', async () => { - await runAutorunExecutor({ dryRun: true }, executorContext('utils')); - - expect(loggerInfoSpy).toHaveBeenCalledTimes(0); - expect(loggerWarnSpy).toHaveBeenCalledTimes(1); - expect(loggerWarnSpy).toHaveBeenCalledWith( - expect.stringContaining( - 'DryRun execution of: npx @code-pushup/cli --dryRun', - ), - ); - }); -}); diff --git a/packages/nx-plugin/src/executors/cli/schema.json b/packages/nx-plugin/src/executors/cli/schema.json deleted file mode 100644 index e494c4cc0..000000000 --- a/packages/nx-plugin/src/executors/cli/schema.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "$schema": "http://json-schema.org/schema", - "$id": "AutorunExecutorOptions", - "title": "CodePushup CLI autorun executor", - "description": "Executes the @code-pushup/cli autorun command See: https://github.com/code-pushup/cli/blob/main/packages/cli/README.md#autorun-command", - "type": "object", - "properties": { - "command": { - "type": "string", - "description": "The command to run.", - "$default": { - "$source": "argv", - "index": 0 - } - }, - "dryRun": { - "type": "boolean", - "description": "Print the commands that would be run, but don't actually run them" - }, - "bin": { - "type": "string", - "description": "Path to Code PushUp CLI" - }, - "verbose": { - "type": "boolean", - "description": "Print additional logs" - }, - "progress": { - "type": "boolean", - "description": "Print additional logs" - }, - "onlyPlugins": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Only run the specified plugins" - }, - "config": { - "type": "string", - "description": "Path to the configuration file" - }, - "projectPrefix": { - "type": "string", - "description": "Prefix for project name" - }, - "persist": { - "type": "object", - "properties": { - "filename": { - "type": "string", - "description": "Filename to save the configuration" - }, - "outputDir": { - "type": "string", - "description": "Directory to save the configuration" - }, - "format": { - "type": "array", - "enum": ["json", "md"], - "description": "Format to save the report in" - } - } - }, - "upload": { - "type": "object", - "properties": { - "server": { - "type": "string", - "format": "uri", - "description": "URL of deployed portal API" - }, - "apiKey": { - "type": "string", - "description": "API key with write access to portal (use `process.env` for security)" - }, - "organization": { - "type": "string", - "pattern": "^[a-z\\d]+(?:-[a-z\\d]+)*$", - "maxLength": 128, - "description": "Organization slug from Code PushUp portal" - }, - "project": { - "type": "string", - "pattern": "^[a-z\\d]+(?:-[a-z\\d]+)*$", - "maxLength": 128, - "description": "Project slug from Code PushUp portal" - }, - "timeout": { - "type": "integer", - "exclusiveMinimum": 0, - "description": "Request timeout in minutes" - } - } - } - }, - "additionalProperties": true -} diff --git a/packages/nx-plugin/src/executors/cli/schema.ts b/packages/nx-plugin/src/executors/cli/schema.ts deleted file mode 100644 index d73a394b6..000000000 --- a/packages/nx-plugin/src/executors/cli/schema.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { PersistConfig, UploadConfig } from '@code-pushup/models'; -import type { - CollectExecutorOnlyOptions, - GeneralExecutorOnlyOptions, - GlobalExecutorOptions, - ProjectExecutorOnlyOptions, -} from '../internal/types.js'; - -export type AutorunCommandExecutorOnlyOptions = ProjectExecutorOnlyOptions & - CollectExecutorOnlyOptions & - GeneralExecutorOnlyOptions; - -export type AutorunCommandExecutorOptions = Partial< - { - upload: Partial; - persist: Partial; - } & AutorunCommandExecutorOnlyOptions & - GlobalExecutorOptions ->; diff --git a/packages/nx-plugin/src/executors/cli/utils.int.test.ts b/packages/nx-plugin/src/executors/cli/utils.int.test.ts deleted file mode 100644 index 180f22af1..000000000 --- a/packages/nx-plugin/src/executors/cli/utils.int.test.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { expect, vi } from 'vitest'; -import type { UploadConfig } from '@code-pushup/models'; -import { normalizedExecutorContext } from '../../../mock/utils/executor.js'; -import * as config from '../internal/config.js'; -import { parseAutorunExecutorOptions } from './utils.js'; - -describe('parseAutorunExecutorOptions', () => { - const persistConfigSpy = vi.spyOn(config, 'persistConfig'); - const uploadConfigSpy = vi.spyOn(config, 'uploadConfig'); - const globalConfigSpy = vi.spyOn(config, 'globalConfig'); - const normalizedContext = normalizedExecutorContext('portal'); - - afterEach(() => { - persistConfigSpy.mockReset(); - uploadConfigSpy.mockReset(); - globalConfigSpy.mockReset(); - }); - - it('should call child config functions with options', () => { - parseAutorunExecutorOptions( - { - verbose: true, - persist: { filename: 'my-name' }, - upload: { - server: 'https://new-portal.code-pushup.dev', - } as UploadConfig, - }, - normalizedContext, - ); - expect(persistConfigSpy).toHaveBeenCalledWith( - { filename: 'my-name' }, - normalizedContext, - ); - expect(uploadConfigSpy).toHaveBeenCalledWith( - { - server: 'https://new-portal.code-pushup.dev', - }, - normalizedContext, - ); - expect(globalConfigSpy).toHaveBeenCalledWith( - { - verbose: true, - persist: { filename: 'my-name' }, - upload: { - server: 'https://new-portal.code-pushup.dev', - } as UploadConfig, - }, - normalizedContext, - ); - }); -}); diff --git a/packages/nx-plugin/src/executors/cli/utils.ts b/packages/nx-plugin/src/executors/cli/utils.ts deleted file mode 100644 index afcca4542..000000000 --- a/packages/nx-plugin/src/executors/cli/utils.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { - globalConfig, - persistConfig, - uploadConfig, -} from '../internal/config.js'; -import type { NormalizedExecutorContext } from '../internal/context.js'; -import type { - AutorunCommandExecutorOnlyOptions, - AutorunCommandExecutorOptions, -} from './schema.js'; - -export function parseAutorunExecutorOnlyOptions( - options: Partial, -): AutorunCommandExecutorOnlyOptions { - const { projectPrefix, dryRun, onlyPlugins } = options; - return { - ...(projectPrefix && { projectPrefix }), - ...(dryRun != null && { dryRun }), - ...(onlyPlugins && { onlyPlugins }), - }; -} - -export function parseAutorunExecutorOptions( - options: Partial, - normalizedContext: NormalizedExecutorContext, -): AutorunCommandExecutorOptions { - const { projectPrefix, persist, upload, command } = options; - const needsUploadParams = - command === 'upload' || command === 'autorun' || command === undefined; - const uploadCfg = uploadConfig( - { projectPrefix, ...upload }, - normalizedContext, - ); - const hasApiToken = uploadCfg?.apiKey != null; - return { - ...parseAutorunExecutorOnlyOptions(options), - ...globalConfig(options, normalizedContext), - persist: persistConfig({ projectPrefix, ...persist }, normalizedContext), - // @TODO This is a hack to avoid validation errors of upload config for commands that dont need it. - // Fix: use utils and execute the core logic directly - // Blocked by Nx plugins can't compile to es6 - ...(needsUploadParams && hasApiToken ? { upload: uploadCfg } : {}), - }; -} - -/** - * Deeply merges executor options. - * - * @param targetOptions - The original options from the target configuration. - * @param cliOptions - The options from Nx, combining target options and CLI arguments. - * @returns A new object with deeply merged properties. - * - * Nx performs a shallow merge by default, where command-line arguments can override entire objects - * (e.g., `--persist.filename` replaces the entire `persist` object). - * This function ensures that nested properties are deeply merged, - * preserving the original target options where CLI arguments are not provided. - */ -export function mergeExecutorOptions( - targetOptions: Partial, - cliOptions: Partial, -): AutorunCommandExecutorOptions { - return { - ...targetOptions, - ...cliOptions, - ...(targetOptions?.persist || cliOptions?.persist - ? { - persist: { - ...targetOptions?.persist, - ...cliOptions?.persist, - }, - } - : {}), - ...(targetOptions?.upload || cliOptions?.upload - ? { - upload: { - ...targetOptions?.upload, - ...cliOptions?.upload, - }, - } - : {}), - }; -} diff --git a/packages/nx-plugin/src/executors/cli/utils.unit.test.ts b/packages/nx-plugin/src/executors/cli/utils.unit.test.ts deleted file mode 100644 index 7a4141eff..000000000 --- a/packages/nx-plugin/src/executors/cli/utils.unit.test.ts +++ /dev/null @@ -1,179 +0,0 @@ -import { type MockInstance, expect, vi } from 'vitest'; -import { osAgnosticPath } from '@code-pushup/test-utils'; -import type { Command } from '../internal/types.js'; -import { - mergeExecutorOptions, - parseAutorunExecutorOnlyOptions, - parseAutorunExecutorOptions, -} from './utils.js'; - -describe('parseAutorunExecutorOnlyOptions', () => { - it('should provide NO default projectPrefix', () => { - expect(parseAutorunExecutorOnlyOptions({})).toStrictEqual( - expect.not.objectContaining({ projectPrefix: expect.anything() }), - ); - }); - - it('should process given projectPrefix', () => { - expect( - parseAutorunExecutorOnlyOptions({ projectPrefix: 'cli' }), - ).toStrictEqual(expect.objectContaining({ projectPrefix: 'cli' })); - }); - - it('should provide NO default dryRun', () => { - expect(parseAutorunExecutorOnlyOptions({})).toStrictEqual( - expect.not.objectContaining({ dryRun: expect.anything() }), - ); - }); - - it('should process given dryRun', () => { - expect(parseAutorunExecutorOnlyOptions({ dryRun: false })).toStrictEqual( - expect.objectContaining({ dryRun: false }), - ); - }); - - it('should provide default onlyPlugins', () => { - expect(parseAutorunExecutorOnlyOptions({})).toStrictEqual( - expect.not.objectContaining({ onlyPlugins: ['json'] }), - ); - }); - - it('should process given onlyPlugins', () => { - expect( - parseAutorunExecutorOnlyOptions({ onlyPlugins: ['md', 'json'] }), - ).toStrictEqual(expect.objectContaining({ onlyPlugins: ['md', 'json'] })); - }); -}); - -describe('parseAutorunExecutorOptions', () => { - let processEnvSpy: MockInstance<[], NodeJS.ProcessEnv>; - - beforeAll(() => { - processEnvSpy = vi.spyOn(process, 'env', 'get').mockReturnValue({}); - }); - - afterAll(() => { - processEnvSpy.mockRestore(); - }); - - it('should leverage other config helper to assemble the executor config', () => { - const projectName = 'my-app'; - const executorOptions = parseAutorunExecutorOptions( - { - persist: { - filename: 'from-options', - }, - }, - { - projectName, - workspaceRoot: 'workspaceRoot', - projectConfig: { - name: 'my-app', - root: 'root', - }, - }, - ); - expect(osAgnosticPath(executorOptions.config ?? '')).toBe( - osAgnosticPath('root/code-pushup.config.ts'), - ); - expect(executorOptions).toEqual( - expect.objectContaining({ - progress: false, - verbose: false, - }), - ); - - expect(processEnvSpy.mock.calls.length).toBeGreaterThanOrEqual(1); - - expect(executorOptions.persist).toEqual( - expect.objectContaining({ - filename: 'from-options', - }), - ); - - expect(osAgnosticPath(executorOptions.persist?.outputDir ?? '')).toBe( - osAgnosticPath('workspaceRoot/.code-pushup/my-app'), - ); - }); - - it.each(['upload', 'autorun', undefined])( - 'should include upload config for command %s if API key is provided', - command => { - const projectName = 'my-app'; - const executorOptions = parseAutorunExecutorOptions( - { - command, - upload: { - apiKey: '123456789', - }, - }, - { - projectName, - workspaceRoot: 'workspaceRoot', - projectConfig: { - name: 'my-app', - root: 'root', - }, - }, - ); - - expect(executorOptions).toEqual( - expect.objectContaining({ - upload: expect.any(Object), - }), - ); - }, - ); - - it.each(['collect'])( - 'should not include upload config for command %s', - command => { - const projectName = 'my-app'; - const executorOptions = parseAutorunExecutorOptions( - { - command, - upload: { - organization: 'code-pushup', - }, - }, - { - projectName, - workspaceRoot: 'workspaceRoot', - projectConfig: { - name: 'my-app', - root: 'root', - }, - }, - ); - - expect(executorOptions).toEqual( - expect.not.objectContaining({ - upload: expect.any(Object), - }), - ); - }, - ); -}); - -describe('mergeExecutorOptions', () => { - it('should deeply merge target and CLI options', () => { - const targetOptions = { - persist: { - outputDir: '.reports', - filename: 'report', - }, - }; - const cliOptions = { - persist: { - filename: 'report-file', - }, - }; - const expected = { - persist: { - outputDir: '.reports', - filename: 'report-file', - }, - }; - expect(mergeExecutorOptions(targetOptions, cliOptions)).toEqual(expected); - }); -}); diff --git a/packages/nx-plugin/src/executors/internal/cli.ts b/packages/nx-plugin/src/executors/internal/cli.ts deleted file mode 100644 index b733eec84..000000000 --- a/packages/nx-plugin/src/executors/internal/cli.ts +++ /dev/null @@ -1,65 +0,0 @@ -export function createCliCommand(options?: { - args?: Record; - command?: string; - bin?: string; -}): string { - const { bin = '@code-pushup/cli', command, args } = options ?? {}; - return `npx ${bin} ${objectToCliArgs({ _: command ?? [], ...args }).join( - ' ', - )}`; -} - -type ArgumentValue = number | string | boolean | string[]; -export type CliArgsObject> = - T extends never - ? Record | { _: string } - : T; - -// @TODO import from @code-pushup/utils => get rid of poppins for cjs support -export function objectToCliArgs< - T extends object = Record, ->(params?: CliArgsObject): string[] { - if (!params) { - return []; - } - - return Object.entries(params).flatMap(([key, value]) => { - // process/file/script - if (key === '_') { - return (Array.isArray(value) ? value : [`${value}`]).filter( - v => v != null, - ); - } - - const prefix = key.length === 1 ? '-' : '--'; - // "-*" arguments (shorthands) - if (Array.isArray(value)) { - return value.map(v => `${prefix}${key}="${v}"`); - } - - if (typeof value === 'object') { - return Object.entries(value as Record).flatMap( - // transform nested objects to the dot notation `key.subkey` - ([k, v]) => objectToCliArgs({ [`${key}.${k}`]: v }), - ); - } - - if (typeof value === 'string') { - return [`${prefix}${key}="${value}"`]; - } - - if (typeof value === 'number') { - return [`${prefix}${key}=${value}`]; - } - - if (typeof value === 'boolean') { - return [`${prefix}${value ? '' : 'no-'}${key}`]; - } - - if (value === undefined) { - return []; - } - - throw new Error(`Unsupported type ${typeof value} for key ${key}`); - }); -} diff --git a/packages/nx-plugin/src/executors/internal/cli.unit.test.ts b/packages/nx-plugin/src/executors/internal/cli.unit.test.ts deleted file mode 100644 index e65cb0ec0..000000000 --- a/packages/nx-plugin/src/executors/internal/cli.unit.test.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { describe, expect, it } from 'vitest'; -import { createCliCommand, objectToCliArgs } from './cli.js'; - -describe('objectToCliArgs', () => { - it('should empty params', () => { - const result = objectToCliArgs(); - expect(result).toEqual([]); - }); - - it('should handle the "_" argument as script', () => { - const params = { _: 'bin.js' }; - const result = objectToCliArgs(params); - expect(result).toEqual(['bin.js']); - }); - - it('should handle the "_" argument with multiple values', () => { - const params = { _: ['bin.js', '--help'] }; - const result = objectToCliArgs(params); - expect(result).toEqual(['bin.js', '--help']); - }); - - it('should handle shorthands arguments', () => { - const params = { - e: `test`, - }; - const result = objectToCliArgs(params); - expect(result).toEqual([`-e="${params.e}"`]); - }); - - it('should handle string arguments', () => { - const params = { name: 'Juanita' }; - const result = objectToCliArgs(params); - expect(result).toEqual(['--name="Juanita"']); - }); - - it('should handle number arguments', () => { - const params = { parallel: 5 }; - const result = objectToCliArgs(params); - expect(result).toEqual(['--parallel=5']); - }); - - it('should handle boolean arguments', () => { - const params = { progress: true }; - const result = objectToCliArgs(params); - expect(result).toEqual(['--progress']); - }); - - it('should handle negated boolean arguments', () => { - const params = { progress: false }; - const result = objectToCliArgs(params); - expect(result).toEqual(['--no-progress']); - }); - - it('should handle array of string arguments', () => { - const params = { format: ['json', 'md'] }; - const result = objectToCliArgs(params); - expect(result).toEqual(['--format="json"', '--format="md"']); - }); - - it('should handle objects', () => { - const params = { format: { json: 'simple' } }; - const result = objectToCliArgs(params); - expect(result).toStrictEqual(['--format.json="simple"']); - }); - - it('should handle nested objects', () => { - const params = { persist: { format: ['json', 'md'], verbose: false } }; - const result = objectToCliArgs(params); - expect(result).toEqual([ - '--persist.format="json"', - '--persist.format="md"', - '--no-persist.verbose', - ]); - }); - - it('should handle objects with undefined', () => { - const params = { format: undefined }; - const result = objectToCliArgs(params); - expect(result).toStrictEqual([]); - }); - - it('should throw error for unsupported type', () => { - expect(() => objectToCliArgs({ param: Symbol('') })).toThrow( - 'Unsupported type', - ); - }); -}); - -describe('createCliCommand', () => { - it('should create command out of object for arguments', () => { - const result = createCliCommand({ args: { verbose: true } }); - expect(result).toBe('npx @code-pushup/cli --verbose'); - }); - - it('should create command out of object for arguments with positional', () => { - const result = createCliCommand({ args: { _: 'autorun', verbose: true } }); - expect(result).toBe('npx @code-pushup/cli autorun --verbose'); - }); -}); diff --git a/packages/nx-plugin/src/executors/internal/config.int.test.ts b/packages/nx-plugin/src/executors/internal/config.int.test.ts deleted file mode 100644 index 54b2e32dc..000000000 --- a/packages/nx-plugin/src/executors/internal/config.int.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { describe, expect } from 'vitest'; -import { ENV } from '../../../mock/fixtures/env.js'; -import { uploadConfig } from './config.js'; -import * as env from './env.js'; - -describe('uploadConfig', () => { - const processEnvSpy = vi.spyOn(process, 'env', 'get').mockReturnValue({}); - const parseEnvSpy = vi.spyOn(env, 'parseEnv'); - - it('should call parseEnv function with values from process.env', () => { - processEnvSpy.mockReturnValue(ENV); - expect( - uploadConfig( - {}, - { - workspaceRoot: 'workspaceRoot', - projectConfig: { - name: 'my-app', - root: 'root', - }, - }, - ), - ).toBeDefined(); - - expect(parseEnvSpy).toHaveBeenCalledTimes(1); - expect(parseEnvSpy).toHaveBeenCalledWith(ENV); - }); -}); diff --git a/packages/nx-plugin/src/executors/internal/config.ts b/packages/nx-plugin/src/executors/internal/config.ts deleted file mode 100644 index 0eb13f8a8..000000000 --- a/packages/nx-plugin/src/executors/internal/config.ts +++ /dev/null @@ -1,69 +0,0 @@ -import * as path from 'node:path'; -import type { PersistConfig, UploadConfig } from '@code-pushup/models'; -import { parseEnv } from './env.js'; -import type { - BaseNormalizedExecutorContext, - GlobalExecutorOptions, - ProjectExecutorOnlyOptions, -} from './types.js'; - -export function globalConfig( - options: Partial>, - context: BaseNormalizedExecutorContext, -): GlobalExecutorOptions { - const { projectConfig } = context; - const { root: projectRoot = '' } = projectConfig ?? {}; - // For better debugging use `--verbose --no-progress` as default - const { verbose, progress, config } = options; - return { - verbose: !!verbose, - progress: !!progress, - config: config ?? path.join(projectRoot, 'code-pushup.config.ts'), - }; -} - -export function persistConfig( - options: Partial, - context: BaseNormalizedExecutorContext, -): Partial { - const { projectConfig, workspaceRoot } = context; - - const { name: projectName = '' } = projectConfig ?? {}; - const { - format, - outputDir = path.join(workspaceRoot, '.code-pushup', projectName), // always in /.code-pushup/, - filename, - } = options; - - return { - outputDir, - ...(format ? { format } : {}), - ...(filename ? { filename } : {}), - }; -} - -export function uploadConfig( - options: Partial, - context: BaseNormalizedExecutorContext, -): Partial { - const { projectConfig, workspaceRoot } = context; - - const { name: projectName } = projectConfig ?? {}; - const { projectPrefix, server, apiKey, organization, project, timeout } = - options; - const applyPrefix = workspaceRoot === '.'; - const prefix = projectPrefix ? `${projectPrefix}-` : ''; - return { - ...(projectName - ? { - project: applyPrefix ? `${prefix}${projectName}` : projectName, - } - : {}), - ...parseEnv(process.env), - ...Object.fromEntries( - Object.entries({ server, apiKey, organization, project, timeout }).filter( - ([_, v]) => v !== undefined, - ), - ), - }; -} diff --git a/packages/nx-plugin/src/executors/internal/config.unit.test.ts b/packages/nx-plugin/src/executors/internal/config.unit.test.ts deleted file mode 100644 index c38554459..000000000 --- a/packages/nx-plugin/src/executors/internal/config.unit.test.ts +++ /dev/null @@ -1,395 +0,0 @@ -import { type MockInstance, describe, expect } from 'vitest'; -import { osAgnosticPath } from '@code-pushup/test-utils'; -import { ENV } from '../../../mock/fixtures/env.js'; -import { globalConfig, persistConfig, uploadConfig } from './config.js'; - -describe('globalConfig', () => { - it('should provide default global verbose options', () => { - expect( - globalConfig( - {}, - { - workspaceRoot: '/test/root/workspace-root', - projectConfig: { - name: 'my-app', - root: 'packages/project-root', - }, - }, - ), - ).toEqual(expect.objectContaining({ verbose: false })); - }); - - it('should parse global verbose options', () => { - expect( - globalConfig( - { verbose: true }, - { - workspaceRoot: '/test/root/workspace-root', - projectConfig: { - name: 'my-app', - root: 'packages/project-root', - }, - }, - ), - ).toEqual(expect.objectContaining({ verbose: true })); - }); - - it('should provide default global progress options', () => { - expect( - globalConfig( - {}, - { - workspaceRoot: '/test/root/workspace-root', - projectConfig: { - name: 'my-app', - root: 'packages/project-root', - }, - }, - ), - ).toEqual(expect.objectContaining({ progress: false })); - }); - - it('should parse global progress options', () => { - expect( - globalConfig( - { progress: true }, - { - workspaceRoot: '/test/root/workspace-root', - projectConfig: { - name: 'my-app', - root: 'packages/project-root', - }, - }, - ), - ).toEqual(expect.objectContaining({ progress: true })); - }); - - it('should provide default global config options', () => { - const { config } = globalConfig( - {}, - { - workspaceRoot: '/test/root/workspace-root', - projectConfig: { - name: 'my-app', - root: 'packages/project-root', - }, - }, - ); - expect(osAgnosticPath(String(config))).toStrictEqual( - expect.stringContaining( - osAgnosticPath('project-root/code-pushup.config.ts'), - ), - ); - }); - - it('should parse global config options', () => { - expect( - globalConfig( - { config: 'my.config.ts' }, - { - workspaceRoot: '/test/root/workspace-root', - projectConfig: { - name: 'my-app', - root: 'packages/project-root', - }, - }, - ), - ).toEqual(expect.objectContaining({ config: 'my.config.ts' })); - }); - - it('should work with empty projectConfig', () => { - expect( - globalConfig( - {}, - { - workspaceRoot: '/test/root/workspace-root', - }, - ), - ).toEqual(expect.objectContaining({ config: 'code-pushup.config.ts' })); - }); - - it('should exclude other options', () => { - expect( - globalConfig( - { test: 42, verbose: true }, - { - workspaceRoot: '/test/root/workspace-root', - projectConfig: { - name: 'my-app', - root: 'packages/project-root', - }, - }, - ), - ).toEqual(expect.not.objectContaining({ test: expect.anything() })); - }); -}); - -describe('persistConfig', () => { - it('should NOT provide default persist format options', () => { - expect( - persistConfig( - {}, - { - workspaceRoot: 'workspaceRoot', - projectConfig: { - name: 'my-app', - root: 'root', - }, - }, - ), - ).toEqual(expect.not.objectContaining({ format: expect.anything() })); - }); - - it('should parse given persist format option', () => { - expect( - persistConfig( - { - format: ['md'], - }, - { - workspaceRoot: 'workspaceRoot', - projectConfig: { - name: 'name', - root: 'root', - }, - }, - ), - ).toEqual( - expect.objectContaining({ - format: ['md'], - }), - ); - }); - - it('should provide default outputDir options', () => { - const projectName = 'my-app'; - const { outputDir } = persistConfig( - {}, - { - workspaceRoot: '/test/root/workspace-root', - projectConfig: { - name: projectName, - root: 'packages/project-root', - }, - }, - ); - expect(osAgnosticPath(String(outputDir))).toBe( - osAgnosticPath(`/test/root/workspace-root/.code-pushup/${projectName}`), - ); - }); - - it('should parse given outputDir options', () => { - const outputDir = '../dist/packages/test-folder'; - const { outputDir: resultingOutDir } = persistConfig( - { - outputDir, - }, - { - workspaceRoot: 'workspaceRoot', - projectConfig: { - name: 'my-app', - root: 'root', - }, - }, - ); - expect(osAgnosticPath(String(resultingOutDir))).toEqual( - expect.stringContaining(osAgnosticPath('../dist/packages/test-folder')), - ); - }); - - it('should work with empty projectConfig', () => { - const { outputDir } = persistConfig( - {}, - { - workspaceRoot: '/test/root/workspace-root', - }, - ); - - expect(osAgnosticPath(String(outputDir))).toEqual( - expect.stringContaining(osAgnosticPath('.code-pushup')), - ); - }); - - it('should provide NO default persist filename', () => { - const projectName = 'my-app'; - expect( - persistConfig( - {}, - { - workspaceRoot: 'workspaceRoot', - projectConfig: { - name: projectName, - root: 'root', - }, - }, - ), - ).toEqual(expect.not.objectContaining({ filename: expect.anything() })); - }); - - it('should parse given persist filename', () => { - const projectName = 'my-app'; - expect( - persistConfig( - { - filename: 'my-name', - }, - { - workspaceRoot: 'workspaceRoot', - projectConfig: { - name: projectName, - root: 'root', - }, - }, - ), - ).toEqual(expect.objectContaining({ filename: 'my-name' })); - }); -}); - -describe('uploadConfig', () => { - const baseUploadConfig = { - server: 'https://base-portal.code.pushup.dev', - apiKey: 'apiKey', - organization: 'organization', - }; - - let processEnvSpy: MockInstance<[], NodeJS.ProcessEnv>; - - beforeAll(() => { - processEnvSpy = vi.spyOn(process, 'env', 'get').mockReturnValue({}); - }); - - afterAll(() => { - processEnvSpy.mockRestore(); - }); - - it('should provide default upload project options as project name', () => { - const projectName = 'my-app'; - expect( - uploadConfig(baseUploadConfig, { - workspaceRoot: 'workspace-root', - projectConfig: { - name: projectName, - root: 'root', - }, - }), - ).toEqual(expect.objectContaining({ project: projectName })); - }); - - it('should parse upload project options', () => { - const projectName = 'utils'; - expect( - uploadConfig( - { - ...baseUploadConfig, - project: 'cli-utils', - }, - { - workspaceRoot: 'workspace-root', - projectConfig: { - name: projectName, - root: 'root', - }, - }, - ), - ).toEqual(expect.objectContaining({ project: 'cli-utils' })); - }); - - it('should parse upload server options', () => { - expect( - uploadConfig( - { - ...baseUploadConfig, - server: 'https://new1-portal.code.pushup.dev', - }, - { - workspaceRoot: 'workspace-root', - projectConfig: { - name: 'utils', - root: 'root', - }, - }, - ), - ).toEqual( - expect.objectContaining({ - server: 'https://new1-portal.code.pushup.dev', - }), - ); - }); - - it('should parse upload organization options', () => { - expect( - uploadConfig( - { - ...baseUploadConfig, - organization: 'code-pushup-v2', - }, - { - workspaceRoot: 'workspace-root', - projectConfig: { - name: 'utils', - root: 'root', - }, - }, - ), - ).toEqual(expect.objectContaining({ organization: 'code-pushup-v2' })); - }); - - it('should parse upload apiKey options', () => { - expect( - uploadConfig( - { - ...baseUploadConfig, - apiKey: '123456789', - }, - { - workspaceRoot: 'workspace-root', - projectConfig: { - name: 'utils', - root: 'root', - }, - }, - ), - ).toEqual(expect.objectContaining({ apiKey: '123456789' })); - }); - - it('should parse process.env options', () => { - processEnvSpy.mockReturnValue(ENV); - expect( - uploadConfig( - {}, - { - workspaceRoot: 'workspaceRoot', - projectConfig: { - name: 'my-app', - root: 'root', - }, - }, - ), - ).toEqual( - expect.objectContaining({ - server: ENV.CP_SERVER, - apiKey: ENV.CP_API_KEY, - organization: ENV.CP_ORGANIZATION, - project: ENV.CP_PROJECT, - timeout: Number(ENV.CP_TIMEOUT), - }), - ); - }); - - it('should options overwrite process.env vars', () => { - expect( - uploadConfig( - { - project: 'my-app2', - }, - { - workspaceRoot: 'workspaceRoot', - projectConfig: { - name: 'my-app', - root: 'root', - }, - }, - ), - ).toEqual(expect.objectContaining({ project: 'my-app2' })); - }); -}); diff --git a/packages/nx-plugin/src/executors/internal/context.ts b/packages/nx-plugin/src/executors/internal/context.ts deleted file mode 100644 index 38ca33416..000000000 --- a/packages/nx-plugin/src/executors/internal/context.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { ExecutorContext } from 'nx/src/config/misc-interfaces'; -import type { BaseNormalizedExecutorContext } from './types.js'; - -export type NormalizedExecutorContext = BaseNormalizedExecutorContext & { - projectName: string; -}; - -export function normalizeContext( - context: ExecutorContext, -): NormalizedExecutorContext { - const { - projectName = '', - root: workspaceRoot, - projectsConfigurations, - } = context; - return { - projectName, - projectConfig: projectsConfigurations?.projects[projectName], - workspaceRoot, - }; -} diff --git a/packages/nx-plugin/src/executors/internal/context.unit.test.ts b/packages/nx-plugin/src/executors/internal/context.unit.test.ts deleted file mode 100644 index 9be17d2a9..000000000 --- a/packages/nx-plugin/src/executors/internal/context.unit.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { describe, expect, it } from 'vitest'; -import { normalizeContext } from './context.js'; - -describe('normalizeContext', () => { - it('should normalizeContext', () => { - const normalizedContext = normalizeContext({ - root: './', - projectName: 'my-app', - cwd: 'string', - projectsConfigurations: { - projects: { - 'my-app': { - root: './my-app', - }, - }, - version: 0, - }, - isVerbose: false, - }); - expect(normalizedContext).toEqual({ - projectName: 'my-app', - projectConfig: { - root: './my-app', - }, - workspaceRoot: './', - }); - }); -}); diff --git a/packages/nx-plugin/src/executors/internal/env.ts b/packages/nx-plugin/src/executors/internal/env.ts deleted file mode 100644 index 16806a09e..000000000 --- a/packages/nx-plugin/src/executors/internal/env.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { z } from 'zod'; -import type { UploadConfig } from '@code-pushup/models'; - -// load upload configuration from environment -const envSchema = z - .object({ - CP_SERVER: z.string().url().optional(), - CP_API_KEY: z.string().min(1).optional(), - CP_ORGANIZATION: z.string().min(1).optional(), - CP_PROJECT: z.string().min(1).optional(), - CP_TIMEOUT: z.string().regex(/^\d+$/).optional(), - }) - .partial(); - -type UploadEnvVars = z.infer; - -export function parseEnv(env: unknown = {}): Partial { - const upload: UploadEnvVars = envSchema.parse(env); - return Object.fromEntries( - Object.entries(upload).map(([envKey, value]) => { - switch (envKey) { - case 'CP_SERVER': - return ['server', value]; - case 'CP_API_KEY': - return ['apiKey', value]; - case 'CP_ORGANIZATION': - return ['organization', value]; - case 'CP_PROJECT': - return ['project', value]; - case 'CP_TIMEOUT': - return Number(value) >= 0 ? ['timeout', Number(value)] : []; - default: - return []; - } - }), - ); -} diff --git a/packages/nx-plugin/src/executors/internal/env.unit.test.ts b/packages/nx-plugin/src/executors/internal/env.unit.test.ts deleted file mode 100644 index 4f5af94ab..000000000 --- a/packages/nx-plugin/src/executors/internal/env.unit.test.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { describe, expect } from 'vitest'; -import { parseEnv } from './env.js'; - -describe('parseEnv', () => { - it('should parse empty env vars', () => { - expect(parseEnv({})).toEqual({}); - }); - - it('should parse process.env.CP_SERVER option', () => { - expect(parseEnv({ CP_SERVER: 'https://portal.code.pushup.dev' })).toEqual( - expect.objectContaining({ server: 'https://portal.code.pushup.dev' }), - ); - }); - - it('should parse process.env.CP_ORGANIZATION option', () => { - expect(parseEnv({ CP_ORGANIZATION: 'code-pushup' })).toEqual( - expect.objectContaining({ organization: 'code-pushup' }), - ); - }); - - it('should parse process.env.CP_PROJECT option', () => { - expect(parseEnv({ CP_PROJECT: 'cli-utils' })).toEqual( - expect.objectContaining({ project: 'cli-utils' }), - ); - }); - - it('should parse process.env.CP_TIMEOUT option', () => { - expect(parseEnv({ CP_TIMEOUT: '3' })).toEqual( - expect.objectContaining({ timeout: 3 }), - ); - }); - - it('should throw for process.env.CP_TIMEOUT option < 0', () => { - expect(() => parseEnv({ CP_TIMEOUT: '-1' })).toThrow('Invalid string'); - }); - - it('should throw for invalid URL in process.env.CP_SERVER option', () => { - expect(() => parseEnv({ CP_SERVER: 'httptpt' })).toThrow('Invalid URL'); - }); -}); diff --git a/packages/nx-plugin/src/executors/internal/types.ts b/packages/nx-plugin/src/executors/internal/types.ts deleted file mode 100644 index 2f529038a..000000000 --- a/packages/nx-plugin/src/executors/internal/types.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { ProjectConfiguration } from 'nx/src/config/workspace-json-project-json'; - -/** - * Types used in the executor only - */ -export type GeneralExecutorOnlyOptions = { - dryRun?: boolean; -}; - -/** - * executor types that apply for a subset of exector's. - * In this case the project related options - * - */ -export type ProjectExecutorOnlyOptions = { - projectPrefix?: string; -}; - -/** - * CLI types that apply globally for all commands. - */ -export type Command = - | 'collect' - | 'upload' - | 'autorun' - | 'print-config' - | 'compare' - | 'merge-diffs' - | 'history'; -export type GlobalExecutorOptions = { - command?: Command; - bin?: string; - verbose?: boolean; - progress?: boolean; - config?: string; -}; - -/** - * CLI types that apply for a subset of commands. - * In this case the collection of data (collect, autorun, history) - */ -export type CollectExecutorOnlyOptions = { - onlyPlugins?: string[]; -}; - -/** - * context that is normalized for all executor's - */ -export type BaseNormalizedExecutorContext = { - projectConfig?: ProjectConfiguration; -} & { workspaceRoot: string }; diff --git a/packages/nx-plugin/src/generators/configuration/README.md b/packages/nx-plugin/src/generators/configuration/README.md deleted file mode 100644 index 79ab3ec39..000000000 --- a/packages/nx-plugin/src/generators/configuration/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# Configuration Generator - -#### @code-pushup/nx-plugin:configuration - -## Usage - -`nx generate @code-pushup/nx-plugin:configuration` - -By default, the Nx plugin will search for existing configuration files. If they are not present it creates a `code-pushup.config.ts` and adds a target to your `project.json` file. - -You can specify the project explicitly as follows: - -`nx g @code-pushup/nx-plugin:configuration ` - -```text -Root/ -├── project-name/ -│ ├── project.json 👈 updated -│ ├── code-pushup.config.ts 👈 generated -│ └── ... -└── ... -``` - -Show what will be generated without writing to disk: - -`nx g configuration ... --dry-run` - -## Options - -| Name | type | description | -| ----------------- | -------------------------------- | -------------------------------------------------------- | -| **--project** | `string` (REQUIRED) | The name of the project. | -| **--targetName** | `string` (DEFAULT 'code-pushup') | The id used to identify a target in your project.json. | -| **--bin** | `string` | Path to Code PushUp CLI | -| **--skipProject** | `boolean` (DEFAULT false) | Skip adding the target to `project.json`. | -| **--skipConfig** | `boolean` (DEFAULT false) | Skip adding the `code-pushup.config.ts` to project root. | diff --git a/packages/nx-plugin/src/generators/configuration/__snapshots__/root-code-pushup.config.ts b/packages/nx-plugin/src/generators/configuration/__snapshots__/root-code-pushup.config.ts deleted file mode 100644 index eae33ec78..000000000 --- a/packages/nx-plugin/src/generators/configuration/__snapshots__/root-code-pushup.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { CoreConfig } from '../dist/packages/models'; -import * as myPlugin from 'my-plugin'; -import { myPluginCategory } from 'my-plugin'; - -// see: https://github.com/code-pushup/cli/blob/main/packages/models/docs/models-reference.md#coreconfig -export default { - persist: { - filename: 'report-123', - }, - upload: { - apiKey: '123', - }, - plugins: [myPlugin({ timeout: 42 })], - categories: [myPluginCategory()], -} satisfies CoreConfig; diff --git a/packages/nx-plugin/src/generators/configuration/code-pushup-config.int.test.ts b/packages/nx-plugin/src/generators/configuration/code-pushup-config.int.test.ts deleted file mode 100644 index 38238ff50..000000000 --- a/packages/nx-plugin/src/generators/configuration/code-pushup-config.int.test.ts +++ /dev/null @@ -1,45 +0,0 @@ -import * as devKit from '@nx/devkit'; -import { formatFiles } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import * as path from 'node:path'; -import { describe, expect, it } from 'vitest'; -import { generateCodePushupConfig } from './code-pushup-config.js'; - -describe('generateCodePushupConfig options', () => { - let tree: devKit.Tree; - const project = 'test-app'; - const projectRoot = path.join('libs', project); - - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - devKit.addProjectConfiguration(tree, project, { - root: 'test-app', - }); - }); - - it('should create code-pushup.config.ts with options in tree', async () => { - generateCodePushupConfig(tree, projectRoot, { - fileImports: 'import type { CoreConfig } from "../dist/packages/models";', - persist: { filename: 'report-123' }, - upload: { apiKey: '123' }, - plugins: [ - { - fileImports: 'import * as myPlugin from "my-plugin";', - codeStrings: 'myPlugin({ timeout: 42})', - }, - ], - categories: [ - { - fileImports: 'import {myPluginCategory} from "my-plugin";', - codeStrings: 'myPluginCategory()', - }, - ], - }); - - await formatFiles(tree); - - expect( - tree.read(path.join(projectRoot, 'code-pushup.config.ts'))?.toString(), - ).toMatchFileSnapshot('__snapshots__/root-code-pushup.config.ts'); - }); -}); diff --git a/packages/nx-plugin/src/generators/configuration/code-pushup-config.ts b/packages/nx-plugin/src/generators/configuration/code-pushup-config.ts deleted file mode 100644 index 6854797fb..000000000 --- a/packages/nx-plugin/src/generators/configuration/code-pushup-config.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { type Tree, generateFiles, logger } from '@nx/devkit'; -import * as path from 'node:path'; -import type { PersistConfig, UploadConfig } from '@code-pushup/models'; -import type { ItemOrArray } from '@code-pushup/utils'; -import type { ExecutableCode } from './types.js'; -import { - formatArrayToLinesOfJsString, - formatObjectToFormattedJsString, - normalizeExecutableCode, - normalizeItemOrArray, -} from './utils.js'; - -export const DEFAULT_IMPORTS = [ - "import type { CoreConfig } from '@code-pushup/models';", -]; - -export type GenerateCodePushupConfigOptions = { - fileImports?: ItemOrArray; - persist?: Partial; - upload?: Partial; - plugins?: ExecutableCode[]; - categories?: ExecutableCode[]; -}; - -export function generateCodePushupConfig( - tree: Tree, - root: string, - options?: GenerateCodePushupConfigOptions, -) { - const supportedFormats = ['ts', 'mjs', 'js']; - const firstExistingFormat = supportedFormats.find(ext => - tree.exists(path.join(root, `code-pushup.config.${ext}`)), - ); - if (firstExistingFormat) { - logger.warn( - `NOTE: No config file created as code-pushup.config.${firstExistingFormat} file already exists.`, - ); - } else { - const { - fileImports: rawImports, - persist, - upload, - plugins: rawPlugins = [], // plugins are required - categories: rawCategories, - } = options ?? {}; - - const plugins = rawPlugins.map(normalizeExecutableCode); - const categories = rawCategories?.map(normalizeExecutableCode); - const configFileImports = [ - ...(rawImports ? normalizeItemOrArray(rawImports) : DEFAULT_IMPORTS), - ...plugins.flatMap(({ fileImports }) => fileImports), - ...(categories ?? []).flatMap(({ fileImports }) => fileImports), - ]; - - generateFiles(tree, path.join(__dirname, 'files'), root, { - ...options, - fileImports: formatArrayToLinesOfJsString(configFileImports), - persist: formatObjectToFormattedJsString(persist), - upload: formatObjectToFormattedJsString(upload), - plugins: `[${plugins.map(({ codeStrings }) => codeStrings).join(',')}]`, - categories: - categories && - `[${categories.map(({ codeStrings }) => codeStrings).join(',')}]`, - }); - } -} diff --git a/packages/nx-plugin/src/generators/configuration/code-pushup-config.unit.test.ts b/packages/nx-plugin/src/generators/configuration/code-pushup-config.unit.test.ts deleted file mode 100644 index 4cd74d681..000000000 --- a/packages/nx-plugin/src/generators/configuration/code-pushup-config.unit.test.ts +++ /dev/null @@ -1,289 +0,0 @@ -import * as devKit from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import * as path from 'node:path'; -import { afterEach, describe, expect, it } from 'vitest'; -import { removeColorCodes } from '@code-pushup/test-utils'; -import { - DEFAULT_IMPORTS, - generateCodePushupConfig, -} from './code-pushup-config.js'; -import { - formatArrayToJSArray, - formatArrayToLinesOfJsString, - formatObjectToFormattedJsString, - normalizeExecutableCode, -} from './utils.js'; - -describe('generateCodePushupConfig options', () => { - let tree: devKit.Tree; - const testProjectName = 'test-app'; - const generateFilesSpy = vi.spyOn(devKit, 'generateFiles'); - const loggerWarnSpy = vi.spyOn(devKit.logger, 'warn'); - - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - devKit.addProjectConfiguration(tree, testProjectName, { - root: 'test-app', - }); - }); - - afterEach(() => { - generateFilesSpy.mockReset(); - }); - - it('should create code-pushup.config.ts with options', () => { - generateCodePushupConfig(tree, testProjectName, { - fileImports: ["import type { CoreConfig } from 'dist/packages/models';"], - persist: { filename: 'report-123' }, - upload: { apiKey: '123' }, - plugins: [ - { - fileImports: "import * as myPlugin from 'my-plugin';", - codeStrings: 'myPlugin({ timeout: 42})', - }, - ], - categories: [ - { - fileImports: "import {myPluginCategory} from 'my-plugin';", - codeStrings: 'myPluginCategory()', - }, - ], - }); - - expect(generateFilesSpy).toHaveBeenCalledWith( - expect.anything(), - expect.any(String), - expect.any(String), - expect.objectContaining({ - fileImports: formatArrayToLinesOfJsString([ - 'import type { CoreConfig } from "dist/packages/models";', - 'import * as myPlugin from "my-plugin";', - 'import {myPluginCategory} from "my-plugin";', - ]), - persist: formatObjectToFormattedJsString({ filename: 'report-123' }), - upload: formatObjectToFormattedJsString({ apiKey: '123' }), - plugins: formatArrayToJSArray(['myPlugin({ timeout: 42})']), - categories: formatArrayToJSArray(['myPluginCategory()']), - }), - ); - }); - - it('should call generateFilesSpy', () => { - generateCodePushupConfig(tree, testProjectName); - expect(generateFilesSpy).toHaveBeenCalledTimes(1); - }); - - it('should skip creation if config already exists', () => { - tree.write(path.join(testProjectName, 'code-pushup.config.js'), ''); - generateCodePushupConfig(tree, testProjectName); - expect(generateFilesSpy).toHaveBeenCalledTimes(0); - expect(loggerWarnSpy).toHaveBeenCalledTimes(1); - expect(loggerWarnSpy).toHaveBeenCalledWith( - removeColorCodes( - 'NOTE: No config file created as code-pushup.config.js file already exists.', - ), - ); - }); - - it('should use correct templates', () => { - generateCodePushupConfig(tree, testProjectName); - expect(generateFilesSpy).toHaveBeenCalledWith( - expect.anything(), - expect.stringContaining( - path.join('nx-plugin', 'src', 'generators', 'configuration', 'files'), - ), - expect.any(String), - expect.any(Object), - ); - }); - - it('should use correct testProjectName', () => { - generateCodePushupConfig(tree, testProjectName); - expect(generateFilesSpy).toHaveBeenCalledWith( - expect.anything(), - expect.any(String), - testProjectName, - expect.any(Object), - ); - }); - - it('should use default options', () => { - generateCodePushupConfig(tree, testProjectName); - expect(generateFilesSpy).toHaveBeenCalledWith( - expect.anything(), - expect.any(String), - expect.any(String), - { - categories: undefined, - fileImports: formatArrayToLinesOfJsString(DEFAULT_IMPORTS), - persist: undefined, - plugins: formatArrayToJSArray([]), - upload: undefined, - }, - ); - }); - - it('should use fileImports options', () => { - generateCodePushupConfig(tree, testProjectName, { - fileImports: [ - "import type { CoreConfig } from '../../dist/packages/models.js';", - ], - }); - expect(generateFilesSpy).toHaveBeenCalledWith( - expect.anything(), - expect.any(String), - expect.any(String), - expect.objectContaining({ - fileImports: formatArrayToLinesOfJsString([ - 'import type { CoreConfig } from "../../dist/packages/models.js";', - ]), - }), - ); - }); - - it('should use persist options', () => { - generateCodePushupConfig(tree, testProjectName, { - persist: { - filename: 'test-report', - outputDir: 'tmp/results', - format: ['md'], - }, - }); - expect(generateFilesSpy).toHaveBeenCalledWith( - expect.anything(), - expect.any(String), - expect.any(String), - expect.objectContaining({ - persist: formatObjectToFormattedJsString({ - filename: 'test-report', - outputDir: 'tmp/results', - format: ['md'], - }), - }), - ); - }); - - it('should use upload options', () => { - generateCodePushupConfig(tree, testProjectName, { - upload: { - organization: 'code-pushup', - project: 'cli', - server: 'https://api.staging.code-pushup.dev/graphql', - apiKey: 'cp_12345678', - }, - }); - expect(generateFilesSpy).toHaveBeenCalledWith( - expect.anything(), - expect.any(String), - expect.any(String), - expect.objectContaining({ - upload: formatObjectToFormattedJsString({ - organization: 'code-pushup', - project: 'cli', - server: 'https://api.staging.code-pushup.dev/graphql', - apiKey: 'cp_12345678', - }), - }), - ); - }); - - it('should use plugins options', () => { - generateCodePushupConfig(tree, testProjectName, { - plugins: [ - { - fileImports: 'import * as myPlugin from "my-import";', - codeStrings: 'myPlugin({ timeout: 42})', - }, - ], - }); - expect(generateFilesSpy).toHaveBeenCalledWith( - expect.anything(), - expect.any(String), - expect.any(String), - expect.objectContaining({ - fileImports: formatArrayToLinesOfJsString([ - ...DEFAULT_IMPORTS, - 'import * as myPlugin from "my-import";', - ]), - plugins: formatArrayToJSArray(['myPlugin({ timeout: 42})']), - }), - ); - }); - - it('should use categories options', () => { - generateCodePushupConfig(tree, testProjectName, { - categories: [ - { - fileImports: 'import {defaultCategory} from "my-plugin";', - codeStrings: 'defaultCategory()', - }, - ], - }); - expect(generateFilesSpy).toHaveBeenCalledWith( - expect.anything(), - expect.any(String), - expect.any(String), - expect.objectContaining({ - fileImports: formatArrayToLinesOfJsString([ - ...DEFAULT_IMPORTS, - 'import {defaultCategory} from "my-plugin";', - ]), - categories: formatArrayToJSArray(['defaultCategory()']), - }), - ); - }); -}); - -describe('normalizeExecutableCode', () => { - it('should normalize fileImports as string', () => { - expect( - normalizeExecutableCode({ - fileImports: 'import * as test from "test"', - codeStrings: 'plugin()', - }), - ).toStrictEqual( - expect.objectContaining({ - fileImports: ['import * as test from "test"'], - }), - ); - }); - - it('should normalize fileImports as array', () => { - expect( - normalizeExecutableCode({ - fileImports: ['import * as test from "test"'], - codeStrings: 'plugin()', - }), - ).toStrictEqual( - expect.objectContaining({ - fileImports: ['import * as test from "test"'], - }), - ); - }); - - it('should normalize codeStrings as string', () => { - expect( - normalizeExecutableCode({ - fileImports: 'import * as test from "test"', - codeStrings: 'plugin()', - }), - ).toStrictEqual( - expect.objectContaining({ - codeStrings: ['plugin()'], - }), - ); - }); - - it('should normalize codeStrings as array', () => { - expect( - normalizeExecutableCode({ - fileImports: 'import * as test from "test"', - codeStrings: ['plugin()'], - }), - ).toStrictEqual( - expect.objectContaining({ - codeStrings: ['plugin()'], - }), - ); - }); -}); diff --git a/packages/nx-plugin/src/generators/configuration/files/code-pushup.config.ts.template b/packages/nx-plugin/src/generators/configuration/files/code-pushup.config.ts.template deleted file mode 100644 index b354d3764..000000000 --- a/packages/nx-plugin/src/generators/configuration/files/code-pushup.config.ts.template +++ /dev/null @@ -1,9 +0,0 @@ -<%- fileImports %> - -// see: https://github.com/code-pushup/cli/blob/main/packages/models/docs/models-reference.md#coreconfig -export default { - <% if (persist) { %>persist: <%- persist %>,<% } %> - <% if (upload) { %>upload: <%- upload %>,<% } %> - <% if (plugins) { %>plugins: <%- plugins %>,<% } %> - <% if (categories) { %>categories: <%- categories %><% } %> -} satisfies CoreConfig; diff --git a/packages/nx-plugin/src/generators/configuration/generator.int.test.ts b/packages/nx-plugin/src/generators/configuration/generator.int.test.ts deleted file mode 100644 index c98d60064..000000000 --- a/packages/nx-plugin/src/generators/configuration/generator.int.test.ts +++ /dev/null @@ -1,145 +0,0 @@ -import { - type Tree, - addProjectConfiguration, - logger, - readProjectConfiguration, -} from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import * as path from 'node:path'; -import { afterEach, describe, expect, it, vi } from 'vitest'; -import { DEFAULT_TARGET_NAME, PACKAGE_NAME } from '../../internal/constants.js'; -import { addTargetToProject, configurationGenerator } from './generator.js'; - -describe('addTargetToProject', () => { - let tree: Tree; - const testProjectName = 'test-app'; - - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - addProjectConfiguration(tree, 'test-app', { - root: 'test-app', - }); - }); - - afterEach(() => { - //reset tree - tree.delete(testProjectName); - }); - - it('should generate a project target', () => { - addTargetToProject( - tree, - { - root: testProjectName, - projectType: 'library', - sourceRoot: `${testProjectName}/src`, - targets: {}, - }, - { - project: testProjectName, - }, - ); - - const projectConfiguration = readProjectConfiguration( - tree, - testProjectName, - ); - - expect(projectConfiguration.targets?.[DEFAULT_TARGET_NAME]).toEqual({ - executor: `${PACKAGE_NAME}:cli`, - }); - }); - - it('should use targetName to generate a project target', () => { - addTargetToProject( - tree, - { - root: testProjectName, - projectType: 'library', - sourceRoot: `${testProjectName}/src`, - targets: {}, - }, - { - project: testProjectName, - targetName: 'cp', - }, - ); - - const projectConfiguration = readProjectConfiguration( - tree, - testProjectName, - ); - - expect(projectConfiguration.targets?.['cp']).toEqual({ - executor: `${PACKAGE_NAME}:cli`, - }); - }); -}); - -describe('configurationGenerator', () => { - let tree: Tree; - const testProjectName = 'test-app'; - const loggerInfoSpy = vi.spyOn(logger, 'info'); - - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - addProjectConfiguration(tree, 'test-app', { - root: 'test-app', - }); - }); - - afterEach(() => { - tree.delete(testProjectName); - }); - - it('should generate a project target and config file', async () => { - await configurationGenerator(tree, { - project: testProjectName, - }); - - const projectConfiguration = readProjectConfiguration( - tree, - testProjectName, - ); - - expect(projectConfiguration.targets?.[DEFAULT_TARGET_NAME]).toEqual({ - executor: `${PACKAGE_NAME}:cli`, - }); - }); - - it('should skip config creation if skipConfig is used', async () => { - await configurationGenerator(tree, { - project: testProjectName, - skipConfig: true, - }); - - readProjectConfiguration(tree, testProjectName); - - expect( - tree.read(path.join('libs', testProjectName, 'code-pushup.config.ts')), - ).toBeNull(); - expect(loggerInfoSpy).toHaveBeenCalledWith('Skip config file creation'); - }); - - it('should skip target creation if skipTarget is used', async () => { - await configurationGenerator(tree, { - project: testProjectName, - skipTarget: true, - }); - - const projectConfiguration = readProjectConfiguration( - tree, - testProjectName, - ); - expect(projectConfiguration.targets).toBeUndefined(); - expect(loggerInfoSpy).toHaveBeenCalledWith('Skip adding target to project'); - }); - - it('should skip formatting', async () => { - await configurationGenerator(tree, { - project: testProjectName, - skipFormat: true, - }); - expect(loggerInfoSpy).toHaveBeenCalledWith('Skip formatting files'); - }); -}); diff --git a/packages/nx-plugin/src/generators/configuration/generator.ts b/packages/nx-plugin/src/generators/configuration/generator.ts deleted file mode 100644 index 4b71b60a2..000000000 --- a/packages/nx-plugin/src/generators/configuration/generator.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { - type Tree, - formatFiles, - logger, - readProjectConfiguration, - updateProjectConfiguration, -} from '@nx/devkit'; -import type { ProjectConfiguration } from 'nx/src/config/workspace-json-project-json'; -import { DEFAULT_TARGET_NAME, PACKAGE_NAME } from '../../internal/constants.js'; -import { generateCodePushupConfig } from './code-pushup-config.js'; -import type { ConfigurationGeneratorOptions } from './schema.js'; - -export async function configurationGenerator( - tree: Tree, - options: ConfigurationGeneratorOptions, -) { - const projectConfiguration = readProjectConfiguration(tree, options.project); - - const { skipConfig, skipTarget, skipFormat } = options; - - if (skipConfig === true) { - logger.info('Skip config file creation'); - } else { - generateCodePushupConfig(tree, projectConfiguration.root); - } - - if (skipTarget === true) { - logger.info('Skip adding target to project'); - } else { - addTargetToProject(tree, projectConfiguration, options); - } - - if (skipFormat === true) { - logger.info('Skip formatting files'); - } else { - await formatFiles(tree); - } -} - -export function addTargetToProject( - tree: Tree, - projectConfiguration: ProjectConfiguration, - options: ConfigurationGeneratorOptions, -) { - const { targets } = projectConfiguration; - const { targetName, project } = options; - - const codePushupTargetConfig = { - executor: `${PACKAGE_NAME}:cli`, - }; - - updateProjectConfiguration(tree, project, { - ...projectConfiguration, - targets: { - ...targets, - [targetName ?? DEFAULT_TARGET_NAME]: codePushupTargetConfig, - }, - }); -} - -export default configurationGenerator; diff --git a/packages/nx-plugin/src/generators/configuration/schema.d.ts b/packages/nx-plugin/src/generators/configuration/schema.d.ts deleted file mode 100644 index b105270c6..000000000 --- a/packages/nx-plugin/src/generators/configuration/schema.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { DynamicTargetOptions } from '../../internal/types.js'; - -export type ConfigurationGeneratorOptions = { - project: string; - bin?: string; - skipTarget?: boolean; - skipConfig?: boolean; - skipFormat?: boolean; -} & DynamicTargetOptions; diff --git a/packages/nx-plugin/src/generators/configuration/schema.json b/packages/nx-plugin/src/generators/configuration/schema.json deleted file mode 100644 index 7098daca2..000000000 --- a/packages/nx-plugin/src/generators/configuration/schema.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "$schema": "http://json-schema.org/schema", - "$id": "AddConfigurationToProject", - "title": "Add CodePushup configuration to a project", - "description": "Add CodePushup configuration to a project", - "type": "object", - "properties": { - "project": { - "type": "string", - "description": "The name of the project.", - "x-prompt": "Which project should configure Code Pushup?", - "x-dropdown": "projects", - "$default": { - "$source": "argv", - "index": 0 - } - }, - "targetName": { - "type": "string", - "description": "The name of the target.", - "x-prompt": "Which name should the target get? default is code-pushup.", - "default": "code-pushup" - }, - "bin": { - "type": "string", - "description": "Path to Code PushUp CLI" - }, - "skipTarget": { - "type": "boolean", - "description": "Skip adding the target to project.json.", - "$default": "false" - }, - "skipConfig": { - "type": "boolean", - "description": "Skip adding the code-pushup.config.ts to the project root.", - "$default": "false" - }, - "skipFormat": { - "type": "boolean", - "description": "Skip formatting of changed files", - "$default": "false" - } - }, - "required": ["project"] -} diff --git a/packages/nx-plugin/src/generators/configuration/types.ts b/packages/nx-plugin/src/generators/configuration/types.ts deleted file mode 100644 index 99451ced8..000000000 --- a/packages/nx-plugin/src/generators/configuration/types.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { ItemOrArray } from '@code-pushup/utils'; - -export type ExecutableCode = { - fileImports: ItemOrArray; - codeStrings: ItemOrArray; -}; diff --git a/packages/nx-plugin/src/generators/configuration/utils.ts b/packages/nx-plugin/src/generators/configuration/utils.ts deleted file mode 100644 index 36464358a..000000000 --- a/packages/nx-plugin/src/generators/configuration/utils.ts +++ /dev/null @@ -1,66 +0,0 @@ -import type { ExtractArrays } from '@code-pushup/utils'; -import type { ExecutableCode } from './types.js'; - -export function normalizeExecutableCode( - executableCode: ExecutableCode, -): ExtractArrays { - const { fileImports: rawFileImports, codeStrings: rawCodeStrings } = - executableCode; - - return { - fileImports: normalizeItemOrArray(rawFileImports), - codeStrings: normalizeItemOrArray(rawCodeStrings), - }; -} - -export function normalizeItemOrArray(itemOrArray: T | T[]): T[]; -export function normalizeItemOrArray( - itemOrArray: T | T[] | undefined, -): T[] | undefined { - if (itemOrArray == null) { - return undefined; - } - if (Array.isArray(itemOrArray)) { - return itemOrArray; - } - return [itemOrArray]; -} - -// Return a formatted JSON in TS object with the same keys as the input object but remove the " for the properties -export function formatObjectToFormattedJsString( - jsonObj?: - | { - [key: string]: unknown; - } - | unknown[], -): string | undefined { - if (!jsonObj) { - return; - } - // Convert JSON object to a string with indentation - const jsonString = JSON.stringify(jsonObj, null, 2); - - // Remove double quotes around property names - return jsonString.replace(/"(\w+)":/g, '$1:'); -} - -export function formatArrayToLinesOfJsString( - lines?: string[], - separator = '\n', -) { - if (lines == null || lines.length === 0) { - return; - } - return lines.join(separator).replace(/'/g, '"'); -} - -export function formatArrayToJSArray(lines?: string[]) { - if (!Array.isArray(lines)) { - return; - } - - return `[${formatArrayToLinesOfJsString(lines, ',\n') ?? ''}]`.replace( - /"/g, - '', - ); -} diff --git a/packages/nx-plugin/src/generators/configuration/utils.unit.test.ts b/packages/nx-plugin/src/generators/configuration/utils.unit.test.ts deleted file mode 100644 index 3a140c8ff..000000000 --- a/packages/nx-plugin/src/generators/configuration/utils.unit.test.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { describe, expect, it } from 'vitest'; -import { - formatArrayToJSArray, - formatArrayToLinesOfJsString, - normalizeExecutableCode, - normalizeItemOrArray, -} from './utils.js'; - -describe('formatArrayToJSArray', () => { - it('should return array as JS', () => { - expect( - formatArrayToJSArray(['plugin1()', 'plugin2()']), - ).toMatchInlineSnapshot( - ` - "[plugin1(), - plugin2()]" - `, - ); - }); - - it('should return empty array as JS for empty items', () => { - expect(formatArrayToJSArray([])).toMatchInlineSnapshot('"[]"'); - }); - - it('should return undefined for undefined values', () => { - expect(formatArrayToJSArray(undefined)).toBeUndefined(); - }); -}); - -describe('formatArrayToLinesOfJsString', () => { - it('should return lines as JS', () => { - expect( - formatArrayToLinesOfJsString([`import plugin from "../mx-plugin";`]), - ).toMatchInlineSnapshot( - ` - "import plugin from "../mx-plugin";" - `, - ); - }); - - it('should return lines as JS with normalized quotes', () => { - expect( - formatArrayToLinesOfJsString([ - `import { CoreConfig } from '@code-pushup/models';`, - `import plugin from "../mx-plugin";`, - ]), - ).toMatchInlineSnapshot( - ` - "import { CoreConfig } from "@code-pushup/models"; - import plugin from "../mx-plugin";" - `, - ); - }); - - it('should return undefined for empty items', () => { - expect(formatArrayToLinesOfJsString([])).toBeUndefined(); - }); - - it('should return undefined for nullish values', () => { - expect(formatArrayToLinesOfJsString()).toBeUndefined(); - }); -}); - -describe('normalizeExecutableCode', () => { - it('should turn strings into arrays', () => { - expect( - normalizeExecutableCode({ - fileImports: 'import { CoreConfig } from "@code-pushup/models";', - codeStrings: 'myPlugin()', - }), - ).toStrictEqual({ - fileImports: ['import { CoreConfig } from "@code-pushup/models";'], - codeStrings: ['myPlugin()'], - }); - }); - - it('should keep arrays', () => { - expect( - normalizeExecutableCode({ - fileImports: ['import { CoreConfig } from "@code-pushup/models";'], - codeStrings: ['myPlugin()'], - }), - ).toStrictEqual({ - fileImports: ['import { CoreConfig } from "@code-pushup/models";'], - codeStrings: ['myPlugin()'], - }); - }); -}); - -describe('normalizeItemOrArray', () => { - it('should turn string into string array', () => { - expect(normalizeItemOrArray('myPlugin()')).toStrictEqual(['myPlugin()']); - }); - - it('should keep string array', () => { - expect(normalizeItemOrArray('myPlugin()')).toStrictEqual(['myPlugin()']); - }); -}); diff --git a/packages/nx-plugin/src/generators/init/README.md b/packages/nx-plugin/src/generators/init/README.md deleted file mode 100644 index c4bfa4573..000000000 --- a/packages/nx-plugin/src/generators/init/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Init Generator - -#### @code-pushup/nx-plugin:init - -## Usage - -`nx generate @code-pushup/nx-plugin:init` - -By default, the Nx plugin will update your `package.json` with needed dependencies and register the plugin in your `nx.json` configuration. - -You can specify the collection explicitly as follows: - -`nx g @code-pushup/nx-plugin:init` - -```text -Root/ -├── ... -├── nx.json 👈 updated -├── package.json 👈 updated -└── ... -``` - -Show what will be generated without writing to disk: - -`nx g @code-pushup/nx-plugin:init --dry-run` - -## Options - -| Name | type | description | -| --------------------- | --------------------------- | ------------------------------------------- | -| **--skipPackageJson** | `boolean` (DEFAULT `false`) | Skip adding `package.json` dependencies. | -| **--skipNxJson** | `boolean` (DEFAULT `false`) | Skip updating `nx.json` with configuration. | diff --git a/packages/nx-plugin/src/generators/init/generator.int.test.ts b/packages/nx-plugin/src/generators/init/generator.int.test.ts deleted file mode 100644 index 5ab890bd1..000000000 --- a/packages/nx-plugin/src/generators/init/generator.int.test.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { type Tree, logger, readJson, readNxJson } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import { describe, expect, it, vi } from 'vitest'; -import { initGenerator } from './generator.js'; - -type PackageJson = { - devDependencies: Record; -}; - -const cpTargetName = 'code-pushup'; - -const devDependencyNames = [ - '@code-pushup/cli', - '@code-pushup/models', - '@code-pushup/nx-plugin', - '@code-pushup/utils', -]; - -describe('init generator', () => { - let tree: Tree; - const loggerInfoSpy = vi.spyOn(logger, 'info'); - - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - }); - - it('should run successfully', () => { - initGenerator(tree, {}); - // nx.json - const targetDefaults = readNxJson(tree)!.targetDefaults!; - expect(targetDefaults).toHaveProperty(cpTargetName); - expect(targetDefaults[cpTargetName]).toEqual({ - inputs: ['default', '^production'], - cache: true, - }); - // package.json - const pkgJson = readJson(tree, 'package.json'); - expect( - Object.keys(pkgJson.devDependencies).filter(dep => - devDependencyNames.includes(dep), - ), - ).toHaveLength(devDependencyNames.length); - }); - - it('should skip package.json', () => { - initGenerator(tree, { skipPackageJson: true }); - // nx.json - const targetDefaults = readNxJson(tree)!.targetDefaults!; - expect(targetDefaults).toHaveProperty(cpTargetName); - expect(targetDefaults[cpTargetName]).toEqual({ - inputs: ['default', '^production'], - cache: true, - }); - // package.json - const pkgJson = readJson(tree, 'package.json'); - expect( - Object.keys(pkgJson.devDependencies).filter(dep => - devDependencyNames.includes(dep), - ), - ).toHaveLength(0); - expect(loggerInfoSpy).toHaveBeenCalledWith('Skip updating package.json'); - }); - - it('should skip package installation', () => { - initGenerator(tree, { skipInstall: true }); - // nx.json - const targetDefaults = readNxJson(tree)!.targetDefaults!; - expect(targetDefaults).toHaveProperty(cpTargetName); - expect(targetDefaults[cpTargetName]).toEqual({ - inputs: ['default', '^production'], - cache: true, - }); - // package.json - const pkgJson = readJson(tree, 'package.json'); - expect( - Object.keys(pkgJson.devDependencies).filter(dep => - devDependencyNames.includes(dep), - ), - ).toHaveLength(4); - expect(loggerInfoSpy).toHaveBeenCalledWith('Skip installing packages'); - }); - - it('should skip nx.json', () => { - initGenerator(tree, { skipNxJson: true }); - // nx.json - const targetDefaults = readNxJson(tree)!.targetDefaults!; - expect(targetDefaults).not.toHaveProperty(cpTargetName); - }); -}); diff --git a/packages/nx-plugin/src/generators/init/generator.ts b/packages/nx-plugin/src/generators/init/generator.ts deleted file mode 100644 index 265298fb0..000000000 --- a/packages/nx-plugin/src/generators/init/generator.ts +++ /dev/null @@ -1,101 +0,0 @@ -/* eslint-disable functional/immutable-data */ -import { - type NxJsonConfiguration, - type Tree, - addDependenciesToPackageJson, - convertNxGenerator, - logger, - readJson, - readNxJson, - runTasksInSerial, - updateJson, - updateNxJson, -} from '@nx/devkit'; -import type { PackageJson } from 'nx/src/utils/package-json'; -import { PACKAGE_NAME } from '../../internal/constants.js'; -import { - cpCliVersion, - cpModelVersion, - cpNxPluginVersion, - cpUtilsVersion, -} from '../../internal/versions.js'; -import type { InitGeneratorSchema } from './schema.js'; - -function checkDependenciesInstalled(host: Tree) { - const packageJson = readJson(host, 'package.json'); - const devDependencies: Record = {}; - const dependencies = {}; - packageJson.dependencies = packageJson.dependencies ?? {}; - packageJson.devDependencies = packageJson.devDependencies ?? {}; - - // base deps - devDependencies[PACKAGE_NAME] = cpNxPluginVersion; - devDependencies['@code-pushup/models'] = cpModelVersion; - devDependencies['@code-pushup/utils'] = cpUtilsVersion; - devDependencies['@code-pushup/cli'] = cpCliVersion; - - return addDependenciesToPackageJson(host, dependencies, devDependencies); -} - -function moveToDevDependencies(tree: Tree) { - updateJson(tree, 'package.json', (packageJson: PackageJson) => { - const newPackageJson: PackageJson = { - dependencies: {}, - devDependencies: {}, - ...packageJson, - }; - - if (newPackageJson.dependencies?.[PACKAGE_NAME] !== undefined) { - const { [PACKAGE_NAME]: version, ...dependencies } = - newPackageJson.dependencies; - return { - ...newPackageJson, - dependencies, - devDependencies: { - ...newPackageJson.devDependencies, - [PACKAGE_NAME]: version, - }, - }; - } - return newPackageJson; - }); -} - -function updateNxJsonConfig(tree: Tree) { - const nxJson: NxJsonConfiguration = readNxJson(tree) as NxJsonConfiguration; - - const targetName = 'code-pushup'; - - nxJson.targetDefaults ??= {}; - nxJson.targetDefaults[targetName] = { - inputs: ['default', '^production'], - cache: true, - }; - - updateNxJson(tree, nxJson); -} - -export function initGenerator(tree: Tree, schema: InitGeneratorSchema) { - if (schema.skipNxJson) { - logger.info(`Skip updating nx.json`); - } else { - updateNxJsonConfig(tree); - } - - const tasks = []; - if (schema.skipPackageJson) { - logger.info(`Skip updating package.json`); - } else { - moveToDevDependencies(tree); - const installDependencies = checkDependenciesInstalled(tree); - if (schema.skipInstall) { - logger.info(`Skip installing packages`); - } else { - tasks.push(installDependencies); - } - } - return runTasksInSerial(...tasks); -} - -export default initGenerator; -export const initSchematic = convertNxGenerator(initGenerator); diff --git a/packages/nx-plugin/src/generators/init/schema.d.ts b/packages/nx-plugin/src/generators/init/schema.d.ts deleted file mode 100644 index 40650a8d5..000000000 --- a/packages/nx-plugin/src/generators/init/schema.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -export type InitGeneratorSchema = { - skipPackageJson?: boolean; - skipInstall?: boolean; - skipNxJson?: boolean; -}; diff --git a/packages/nx-plugin/src/generators/init/schema.json b/packages/nx-plugin/src/generators/init/schema.json deleted file mode 100644 index 8f7dbc0d0..000000000 --- a/packages/nx-plugin/src/generators/init/schema.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "cli": "nx", - "title": "Initialize Code Pushup in the workspace.", - "description": "Initialize Code Pushup in the workspace.", - "$id": "init-code-pushup-plugin", - "type": "object", - "properties": { - "skipPackageJson": { - "type": "boolean", - "description": "Skip adding package.json dependencies", - "x-priority": "internal" - }, - "skipInstall": { - "type": "boolean", - "description": "Skip package installation", - "x-priority": "internal" - }, - "skipNxJson": { - "type": "boolean", - "description": "Skip updating nx.json with configuration" - } - } -} diff --git a/packages/nx-plugin/src/index.ts b/packages/nx-plugin/src/index.ts deleted file mode 100644 index e516b18ce..000000000 --- a/packages/nx-plugin/src/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { createNodes } from './plugin/index.js'; - -// default export for nx.json#plugins -export default createNodes; - -export type { AutorunCommandExecutorOptions } from './executors/cli/schema.js'; -export { objectToCliArgs } from './executors/internal/cli.js'; -export { generateCodePushupConfig } from './generators/configuration/code-pushup-config.js'; -export { configurationGenerator } from './generators/configuration/generator.js'; -export type { ConfigurationGeneratorOptions } from './generators/configuration/schema.js'; -export { initGenerator, initSchematic } from './generators/init/generator.js'; -export { type InitGeneratorSchema } from './generators/init/schema.js'; -export { - executeProcess, - type ProcessConfig, -} from './internal/execute-process.js'; -export * from './internal/versions.js'; -export { createNodes } from './plugin/index.js'; diff --git a/packages/nx-plugin/src/internal/constants.ts b/packages/nx-plugin/src/internal/constants.ts deleted file mode 100644 index f69356ea3..000000000 --- a/packages/nx-plugin/src/internal/constants.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const PROJECT_JSON_FILE_NAME = 'project.json'; -export const CODE_PUSHUP_CONFIG_REGEX = /^code-pushup(?:\.[\w-]+)?\.ts$/; -export const PACKAGE_NAME = '@code-pushup/nx-plugin'; -export const DEFAULT_TARGET_NAME = 'code-pushup'; diff --git a/packages/nx-plugin/src/internal/execute-process.ts b/packages/nx-plugin/src/internal/execute-process.ts deleted file mode 100644 index cf61f3e84..000000000 --- a/packages/nx-plugin/src/internal/execute-process.ts +++ /dev/null @@ -1,186 +0,0 @@ -import { gray } from 'ansis'; -import { spawn } from 'node:child_process'; -import { ui } from '@code-pushup/utils'; - -export function calcDuration(start: number, stop?: number): number { - return Math.round((stop ?? performance.now()) - start); -} - -/** - * Represents the process result. - * @category Types - * @public - * @property {string} stdout - The stdout of the process. - * @property {string} stderr - The stderr of the process. - * @property {number | null} code - The exit code of the process. - */ -export type ProcessResult = { - stdout: string; - stderr: string; - code: number | null; - date: string; - duration: number; -}; - -/** - * Error class for process errors. - * Contains additional information about the process result. - * @category Error - * @public - * @class - * @extends Error - * @example - * const result = await executeProcess({}) - * .catch((error) => { - * if (error instanceof ProcessError) { - * console.error(error.code); - * console.error(error.stderr); - * console.error(error.stdout); - * } - * }); - * - */ -export class ProcessError extends Error { - code: number | null; - stderr: string; - stdout: string; - - constructor(result: ProcessResult) { - super(result.stderr); - this.code = result.code; - this.stderr = result.stderr; - this.stdout = result.stdout; - } -} - -/** - * Process config object. Contains the command, args and observer. - * @param cfg - process config object with command, args and observer (optional) - * @category Types - * @public - * @property {string} command - The command to execute. - * @property {string[]} args - The arguments for the command. - * @property {ProcessObserver} observer - The observer for the process. - * - * @example - * - * // bash command - * const cfg = { - * command: 'bash', - * args: ['-c', 'echo "hello world"'] - * }; - * - * // node command - * const cfg = { - * command: 'node', - * args: ['--version'] - * }; - * - * // npx command - * const cfg = { - * command: 'npx', - * args: ['--version'] - * - */ -export type ProcessConfig = { - command: string; - args?: string[]; - cwd?: string; - observer?: ProcessObserver; - ignoreExitCode?: boolean; -}; - -/** - * Process observer object. Contains the onStdout, error and complete function. - * @category Types - * @public - * @property {function} onStdout - The onStdout function of the observer (optional). - * @property {function} onError - The error function of the observer (optional). - * @property {function} onComplete - The complete function of the observer (optional). - * - * @example - * const observer = { - * onStdout: (stdout) => console.info(stdout) - * } - */ -export type ProcessObserver = { - onStdout?: (stdout: string) => void; - onError?: (error: ProcessError) => void; - onComplete?: () => void; -}; - -/** - * Executes a process and returns a promise with the result as `ProcessResult`. - * - * @example - * - * // sync process execution - * const result = await executeProcess({ - * command: 'node', - * args: ['--version'] - * }); - * - * console.info(result); - * - * // async process execution - * const result = await executeProcess({ - * command: 'node', - * args: ['download-data'], - * observer: { - * onStdout: updateProgress, - * error: handleError, - * complete: cleanLogs, - * } - * }); - * - * console.info(result); - * - * @param cfg - see {@link ProcessConfig} - */ -export function executeProcess(cfg: ProcessConfig): Promise { - const { observer, cwd, command, args, ignoreExitCode = false } = cfg; - const { onStdout, onError, onComplete } = observer ?? {}; - const date = new Date().toISOString(); - const start = performance.now(); - - const logCommand = [command, ...(args || [])].join(' '); - ui().logger.log( - gray( - `Executing command:\n${logCommand}\nIn working directory:\n${cfg.cwd ?? process.cwd()}`, - ), - ); - - return new Promise((resolve, reject) => { - // shell:true tells Windows to use shell command for spawning a child process - const process = spawn(command, args, { cwd, shell: true }); - // eslint-disable-next-line functional/no-let - let stdout = ''; - // eslint-disable-next-line functional/no-let - let stderr = ''; - - process.stdout.on('data', data => { - stdout += String(data); - onStdout?.(String(data)); - }); - - process.stderr.on('data', data => { - stderr += String(data); - }); - - process.on('error', err => { - stderr += err.toString(); - }); - - process.on('close', code => { - const timings = { date, duration: calcDuration(start) }; - if (code === 0 || ignoreExitCode) { - onComplete?.(); - resolve({ code, stdout, stderr, ...timings }); - } else { - const errorMsg = new ProcessError({ code, stdout, stderr, ...timings }); - onError?.(errorMsg); - reject(errorMsg); - } - }); - }); -} diff --git a/packages/nx-plugin/src/internal/execute-process.unit.test.ts b/packages/nx-plugin/src/internal/execute-process.unit.test.ts deleted file mode 100644 index 5893b867f..000000000 --- a/packages/nx-plugin/src/internal/execute-process.unit.test.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { describe, expect, it, vi } from 'vitest'; -import { getAsyncProcessRunnerConfig } from '@code-pushup/test-utils'; -import { type ProcessObserver, executeProcess } from './execute-process.js'; - -describe('executeProcess', () => { - const spyObserver: ProcessObserver = { - onStdout: vi.fn(), - onError: vi.fn(), - onComplete: vi.fn(), - }; - const errorSpy = vi.fn(); - - beforeEach(() => { - vi.clearAllMocks(); - }); - - it('should work with node command `node -v`', async () => { - const processResult = await executeProcess({ - command: `node`, - args: ['-v'], - observer: spyObserver, - }); - - // Note: called once or twice depending on environment (2nd time for a new line) - expect(spyObserver.onStdout).toHaveBeenCalled(); - expect(spyObserver.onComplete).toHaveBeenCalledOnce(); - expect(spyObserver.onError).not.toHaveBeenCalled(); - expect(processResult.stdout).toMatch(/v\d{1,2}(\.\d{1,2}){0,2}/); - }); - - it('should work with npx command `npx --help`', async () => { - const processResult = await executeProcess({ - command: `npx`, - args: ['--help'], - observer: spyObserver, - }); - expect(spyObserver.onStdout).toHaveBeenCalledOnce(); - expect(spyObserver.onComplete).toHaveBeenCalledOnce(); - expect(spyObserver.onError).not.toHaveBeenCalled(); - expect(processResult.stdout).toContain('npm exec'); - }); - - it('should work with script `node custom-script.js`', async () => { - const processResult = await executeProcess({ - ...getAsyncProcessRunnerConfig({ interval: 10, runs: 4 }), - observer: spyObserver, - }).catch(errorSpy); - - expect(errorSpy).not.toHaveBeenCalled(); - expect(processResult.stdout).toContain('process:complete'); - expect(spyObserver.onStdout).toHaveBeenCalledTimes(6); // intro + 4 runs + complete - expect(spyObserver.onError).not.toHaveBeenCalled(); - expect(spyObserver.onComplete).toHaveBeenCalledOnce(); - }); - - it('should work with async script `node custom-script.js` that throws an error', async () => { - const processResult = await executeProcess({ - ...getAsyncProcessRunnerConfig({ - interval: 10, - runs: 1, - throwError: true, - }), - observer: spyObserver, - }).catch(errorSpy); - - expect(errorSpy).toHaveBeenCalledOnce(); - expect(processResult).toBeUndefined(); - expect(spyObserver.onStdout).toHaveBeenCalledTimes(2); // intro + 1 run before error - expect(spyObserver.onError).toHaveBeenCalledOnce(); - expect(spyObserver.onComplete).not.toHaveBeenCalled(); - }); - - it('should successfully exit process after an error is thrown when ignoreExitCode is set', async () => { - const processResult = await executeProcess({ - ...getAsyncProcessRunnerConfig({ - interval: 10, - runs: 1, - throwError: true, - }), - observer: spyObserver, - ignoreExitCode: true, - }).catch(errorSpy); - - expect(errorSpy).not.toHaveBeenCalled(); - expect(processResult.code).toBe(1); - expect(processResult.stdout).toContain('process:update'); - expect(processResult.stderr).toContain('dummy-error'); - expect(spyObserver.onStdout).toHaveBeenCalledTimes(2); // intro + 1 run before error - expect(spyObserver.onError).not.toHaveBeenCalled(); - expect(spyObserver.onComplete).toHaveBeenCalledOnce(); - }); -}); diff --git a/packages/nx-plugin/src/internal/types.ts b/packages/nx-plugin/src/internal/types.ts deleted file mode 100644 index bf3a2d047..000000000 --- a/packages/nx-plugin/src/internal/types.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type DynamicTargetOptions = { - targetName?: string; - bin?: string; -}; diff --git a/packages/nx-plugin/src/internal/versions.ts b/packages/nx-plugin/src/internal/versions.ts deleted file mode 100644 index b7e24f64a..000000000 --- a/packages/nx-plugin/src/internal/versions.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { readJsonFile } from '@nx/devkit'; -import * as path from 'node:path'; -import type { PackageJson } from 'nx/src/utils/package-json'; - -const workspaceRoot = path.join(__dirname, '../../'); -const projectsFolder = path.join(__dirname, '../../../'); - -export const cpNxPluginVersion = loadPackageJson(workspaceRoot).version; -export const cpModelVersion = loadPackageJson( - path.join(projectsFolder, 'cli'), -).version; -export const cpUtilsVersion = loadPackageJson( - path.join(projectsFolder, 'utils'), -).version; -export const cpCliVersion = loadPackageJson( - path.join(projectsFolder, 'models'), -).version; - -/** - * Load the package.json file from the given folder path. - * @param folderPath - */ -function loadPackageJson(folderPath: string): PackageJson { - return readJsonFile(path.join(folderPath, 'package.json')); -} diff --git a/packages/nx-plugin/src/plugin/README.md b/packages/nx-plugin/src/plugin/README.md deleted file mode 100644 index 80216bd58..000000000 --- a/packages/nx-plugin/src/plugin/README.md +++ /dev/null @@ -1,107 +0,0 @@ -# @code-pushup/nx-plugin - -The Nx Plugin for [Code PushUp](https://github.com/code-pushup/cli#readme), an open source code quality and conformance tool. - -Why should you use this plugin? - -- Zero setup cost. Just run the `init` generator and you're good to go. -- Smoother CI integration -- Minimal configuration -- Automated setup, migration and maintenance - -## Usage - -```jsonc -// nx.json -{ - //... - "plugins": ["@code-pushup/nx-plugin"], -} -``` - -or with options: - -```jsonc -// nx.json -{ - //... - "plugins": [ - { - "plugin": "@code-pushup/nx-plugin", - "options": { - "projectPrefix": "cli", - }, - }, - ], -} -``` - -Now every project will have `code-pushup--configuration` target if no `code-pushup.{ts,mjs,js}` is present. - -- `nx run :code-pushup--configuration` -- `nx run :code-pushup--configuration --skipFormat` - -Run it and the project will get automatically configured. - -```text -Root/ -├── project-name/ -│ ├── code-pushup.config.ts 👈 generated -│ └── ... -└── ... -``` - -For details visit the [configuration generator docs](../generators/configuration/README.md). - -With the configuration from above a `code-pushup` target is now present. - -- `nx run :code-pushup` - -Run it and the project will get automatically collect the report. - -```text -Root/ -├── .code-pushup/ -│ └── project-name -│ ├── report.md 👈 generated -│ └── report.json 👈 generated -├── project-name/ -│ ├── code-pushup.config.ts -│ └── ... -└── ... -``` - -Pass positional arguments to execute a specific command, use named arguments to overwrite defaults. - -- `nx run :code-pushup --onlyPlugins=eslint` -- `nx run :code-pushup collect` -- `nx run :code-pushup upload --upload.server=https://staging.code-pushup.dev` - -For a full list of command visit the [Code PushUp CLI documentation](../../../cli/README.md#commands). - -## Options - -| Name | type | description | -| ----------------- | -------------------------------- | ------------------------------------------------------ | -| **projectPrefix** | `string` | prefix for upload.project on non root projects | -| **targetName** | `string` (DEFAULT 'code-pushup') | The id used to identify a target in your project.json. | -| **bin** | `string` | Path to Code PushUp CLI | - -All options are optional and provided in the `nx.json` file. - -```jsonc -// nx.json -{ - //... - "plugins": [ - { - "plugin": "@code-pushup/nx-plugin", - "options": { - "projectPrefix": "cli" - "targetName": "cp" - "bin": "dist/package/code-pushup-custom-build" - } - } - ] -} -``` diff --git a/packages/nx-plugin/src/plugin/constants.ts b/packages/nx-plugin/src/plugin/constants.ts deleted file mode 100644 index bf2e81d9f..000000000 --- a/packages/nx-plugin/src/plugin/constants.ts +++ /dev/null @@ -1 +0,0 @@ -export const CP_TARGET_NAME = 'code-pushup'; diff --git a/packages/nx-plugin/src/plugin/index.ts b/packages/nx-plugin/src/plugin/index.ts deleted file mode 100644 index 648d0b4aa..000000000 --- a/packages/nx-plugin/src/plugin/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { createNodes } from './plugin.js'; -export type { CreateNodesOptions } from './types.js'; diff --git a/packages/nx-plugin/src/plugin/plugin.ts b/packages/nx-plugin/src/plugin/plugin.ts deleted file mode 100644 index 1f125f5a8..000000000 --- a/packages/nx-plugin/src/plugin/plugin.ts +++ /dev/null @@ -1,34 +0,0 @@ -import type { - CreateNodes, - CreateNodesContext, - CreateNodesResult, -} from '@nx/devkit'; -import { PROJECT_JSON_FILE_NAME } from '../internal/constants.js'; -import { createTargets } from './target/targets.js'; -import type { CreateNodesOptions } from './types.js'; -import { normalizedCreateNodesContext } from './utils.js'; - -// name has to be "createNodes" to get picked up by Nx => { - const parsedCreateNodesOptions = createNodesOptions as CreateNodesOptions; - const normalizedContext = await normalizedCreateNodesContext( - context, - projectConfigurationFile, - parsedCreateNodesOptions, - ); - - return { - projects: { - [normalizedContext.projectRoot]: { - targets: await createTargets(normalizedContext), - }, - }, - }; - }, -]; diff --git a/packages/nx-plugin/src/plugin/plugin.unit.test.ts b/packages/nx-plugin/src/plugin/plugin.unit.test.ts deleted file mode 100644 index 62b3c0b2f..000000000 --- a/packages/nx-plugin/src/plugin/plugin.unit.test.ts +++ /dev/null @@ -1,139 +0,0 @@ -import type { CreateNodesContext } from '@nx/devkit'; -import { vol } from 'memfs'; -import { describe, expect } from 'vitest'; -import { invokeCreateNodesOnVirtualFiles } from '@code-pushup/test-nx-utils'; -import { PACKAGE_NAME, PROJECT_JSON_FILE_NAME } from '../internal/constants.js'; -import { CP_TARGET_NAME } from './constants.js'; -import { createNodes } from './plugin.js'; - -describe('@code-pushup/nx-plugin/plugin', () => { - let context: CreateNodesContext; - - beforeEach(() => { - context = { - nxJsonConfiguration: {}, - workspaceRoot: '', - configFiles: [], - }; - }); - - afterEach(() => { - vol.reset(); - }); - - it('should normalize context and use it to create the configuration target on ROOT project', async () => { - const projectRoot = '.'; - const matchingFilesData = { - [`${projectRoot}/${PROJECT_JSON_FILE_NAME}`]: `${JSON.stringify({ - name: '@org/empty-root', - })}`, - }; - - await expect( - invokeCreateNodesOnVirtualFiles( - createNodes, - context, - {}, - { matchingFilesData }, - ), - ).resolves.toStrictEqual({ - [projectRoot]: { - targets: { - [`${CP_TARGET_NAME}--configuration`]: { - command: `nx g ${PACKAGE_NAME}:configuration --skipTarget --targetName="code-pushup" --project="@org/empty-root"`, - }, - }, - }, - }); - }); - - it('should normalize context and use it to create the configuration target on PACKAGE project', async () => { - const projectRoot = 'apps/my-app'; - const matchingFilesData = { - [`${projectRoot}/${PROJECT_JSON_FILE_NAME}`]: `${JSON.stringify({ - name: '@org/empty-root', - })}`, - }; - - await expect( - invokeCreateNodesOnVirtualFiles( - createNodes, - context, - {}, - { matchingFilesData }, - ), - ).resolves.toStrictEqual({ - [projectRoot]: { - targets: { - [`${CP_TARGET_NAME}--configuration`]: { - command: `nx g ${PACKAGE_NAME}:configuration --skipTarget --targetName="code-pushup" --project="@org/empty-root"`, - }, - }, - }, - }); - }); - - it('should create the executor target on ROOT project if configured', async () => { - const projectRoot = '.'; - const matchingFilesData = { - [`${projectRoot}/${PROJECT_JSON_FILE_NAME}`]: `${JSON.stringify({ - name: '@org/empty-root', - })}`, - [`${projectRoot}/code-pushup.config.ts`]: '{}', - }; - - await expect( - invokeCreateNodesOnVirtualFiles( - createNodes, - context, - { - projectPrefix: 'cli', - }, - { matchingFilesData }, - ), - ).resolves.toStrictEqual({ - [projectRoot]: { - targets: { - [CP_TARGET_NAME]: { - executor: `${PACKAGE_NAME}:cli`, - options: { - projectPrefix: 'cli', - }, - }, - }, - }, - }); - }); - - it('should create the executor target on PACKAGE project if configured', async () => { - const projectRoot = 'apps/my-app'; - const matchingFilesData = { - [`${projectRoot}/${PROJECT_JSON_FILE_NAME}`]: `${JSON.stringify({ - name: '@org/empty-root', - })}`, - [`${projectRoot}/code-pushup.config.ts`]: '{}', - }; - - await expect( - invokeCreateNodesOnVirtualFiles( - createNodes, - context, - { - projectPrefix: 'cli', - }, - { matchingFilesData }, - ), - ).resolves.toStrictEqual({ - [projectRoot]: { - targets: { - [CP_TARGET_NAME]: { - executor: `${PACKAGE_NAME}:cli`, - options: { - projectPrefix: 'cli', - }, - }, - }, - }, - }); - }); -}); diff --git a/packages/nx-plugin/src/plugin/target/configuration-target.ts b/packages/nx-plugin/src/plugin/target/configuration-target.ts deleted file mode 100644 index d19b9325b..000000000 --- a/packages/nx-plugin/src/plugin/target/configuration-target.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { TargetConfiguration } from '@nx/devkit'; -import type { RunCommandsOptions } from 'nx/src/executors/run-commands/run-commands.impl'; -import { objectToCliArgs } from '../../executors/internal/cli.js'; -import { PACKAGE_NAME } from '../../internal/constants.js'; -import { CP_TARGET_NAME } from '../constants.js'; - -export function createConfigurationTarget(options?: { - targetName?: string; - projectName?: string; - bin?: string; -}): TargetConfiguration { - const { - projectName, - bin = PACKAGE_NAME, - targetName = CP_TARGET_NAME, - } = options ?? {}; - return { - command: `nx g ${bin}:configuration ${objectToCliArgs({ - skipTarget: true, - targetName, - ...(projectName ? { project: projectName } : {}), - }).join(' ')}`, - }; -} diff --git a/packages/nx-plugin/src/plugin/target/configuration.target.unit.test.ts b/packages/nx-plugin/src/plugin/target/configuration.target.unit.test.ts deleted file mode 100644 index 87f4418c9..000000000 --- a/packages/nx-plugin/src/plugin/target/configuration.target.unit.test.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { expect } from 'vitest'; -import { PACKAGE_NAME } from '../../internal/constants.js'; -import { createConfigurationTarget } from './configuration-target.js'; - -describe('createConfigurationTarget', () => { - it('should return code-pushup--configuration target for given project', () => { - expect( - createConfigurationTarget({ projectName: 'my-project' }), - ).toStrictEqual({ - command: `nx g ${PACKAGE_NAME}:configuration --skipTarget --targetName="code-pushup" --project="my-project"`, - }); - }); - - it('should return code-pushup--configuration target without project name', () => { - expect(createConfigurationTarget()).toStrictEqual({ - command: `nx g ${PACKAGE_NAME}:configuration --skipTarget --targetName="code-pushup"`, - }); - }); -}); diff --git a/packages/nx-plugin/src/plugin/target/constants.ts b/packages/nx-plugin/src/plugin/target/constants.ts deleted file mode 100644 index 79e804e40..000000000 --- a/packages/nx-plugin/src/plugin/target/constants.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const CODE_PUSHUP_CONFIG_REGEX = - /^code-pushup\.config\.(\w*\.)*(ts|js|mjs)$/; diff --git a/packages/nx-plugin/src/plugin/target/executor-target.ts b/packages/nx-plugin/src/plugin/target/executor-target.ts deleted file mode 100644 index e8b52eb8f..000000000 --- a/packages/nx-plugin/src/plugin/target/executor-target.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { TargetConfiguration } from '@nx/devkit'; -import { PACKAGE_NAME } from '../../internal/constants.js'; -import type { ProjectPrefixOptions } from '../types.js'; - -export function createExecutorTarget(options?: { - bin?: string; - projectPrefix?: string; -}): TargetConfiguration { - const { bin = PACKAGE_NAME, projectPrefix } = options ?? {}; - return { - executor: `${bin}:cli`, - ...(projectPrefix - ? { - options: { - projectPrefix, - }, - } - : {}), - }; -} diff --git a/packages/nx-plugin/src/plugin/target/executor.target.unit.test.ts b/packages/nx-plugin/src/plugin/target/executor.target.unit.test.ts deleted file mode 100644 index 610b44bd7..000000000 --- a/packages/nx-plugin/src/plugin/target/executor.target.unit.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { expect } from 'vitest'; -import { createExecutorTarget } from './executor-target.js'; - -describe('createExecutorTarget', () => { - it('should return executor target without project name', () => { - expect(createExecutorTarget()).toStrictEqual({ - executor: '@code-pushup/nx-plugin:cli', - }); - }); - - it('should use bin if provides', () => { - expect(createExecutorTarget({ bin: 'xyz' })).toStrictEqual({ - executor: 'xyz:cli', - }); - }); - - it('should use projectPrefix if provided', () => { - expect(createExecutorTarget({ projectPrefix: 'cli' })).toStrictEqual({ - executor: '@code-pushup/nx-plugin:cli', - options: { - projectPrefix: 'cli', - }, - }); - }); -}); diff --git a/packages/nx-plugin/src/plugin/target/targets.ts b/packages/nx-plugin/src/plugin/target/targets.ts deleted file mode 100644 index eb68740ef..000000000 --- a/packages/nx-plugin/src/plugin/target/targets.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { readdir } from 'node:fs/promises'; -import { CP_TARGET_NAME } from '../constants.js'; -import type { - CreateNodesOptions, - ProjectConfigurationWithName, -} from '../types.js'; -import { createConfigurationTarget } from './configuration-target.js'; -import { CODE_PUSHUP_CONFIG_REGEX } from './constants.js'; -import { createExecutorTarget } from './executor-target.js'; - -export type CreateTargetsOptions = { - projectJson: ProjectConfigurationWithName; - projectRoot: string; - createOptions: CreateNodesOptions; -}; - -export async function createTargets(normalizedContext: CreateTargetsOptions) { - const { - targetName = CP_TARGET_NAME, - bin, - projectPrefix, - } = normalizedContext.createOptions; - const rootFiles = await readdir(normalizedContext.projectRoot); - return rootFiles.some(filename => filename.match(CODE_PUSHUP_CONFIG_REGEX)) - ? { - [targetName]: createExecutorTarget({ bin, projectPrefix }), - } - : // if NO code-pushup.config.*.(ts|js|mjs) is present return configuration target - { - [`${targetName}--configuration`]: createConfigurationTarget({ - targetName, - projectName: normalizedContext.projectJson.name, - bin, - }), - }; -} diff --git a/packages/nx-plugin/src/plugin/target/targets.unit.test.ts b/packages/nx-plugin/src/plugin/target/targets.unit.test.ts deleted file mode 100644 index 9b730f726..000000000 --- a/packages/nx-plugin/src/plugin/target/targets.unit.test.ts +++ /dev/null @@ -1,189 +0,0 @@ -import { vol } from 'memfs'; -import { rm } from 'node:fs/promises'; -import { afterEach, beforeEach, expect } from 'vitest'; -import { MEMFS_VOLUME } from '@code-pushup/test-utils'; -import { DEFAULT_TARGET_NAME, PACKAGE_NAME } from '../../internal/constants.js'; -import { CP_TARGET_NAME } from '../constants.js'; -import type { NormalizedCreateNodesContext } from '../types.js'; -import { createTargets } from './targets.js'; - -describe('createTargets', () => { - beforeEach(async () => { - // needed to have the folder present. readdir otherwise it fails - vol.fromJSON( - { - x: '', - }, - MEMFS_VOLUME, - ); - await rm('x'); - }); - - afterEach(() => { - vol.reset(); - }); - - it('should return configuration targets for project without code-pushup config', async () => { - const projectName = 'plugin-my-plugin'; - await expect( - createTargets({ - projectRoot: '.', - projectJson: { - name: projectName, - }, - createOptions: {}, - } as NormalizedCreateNodesContext), - ).resolves.toStrictEqual({ - [`${CP_TARGET_NAME}--configuration`]: { - command: `nx g ${PACKAGE_NAME}:configuration --skipTarget --targetName="code-pushup" --project="${projectName}"`, - }, - }); - }); - - it('should return configuration targets for empty project without code-pushup config and consider targetName', async () => { - const projectName = 'plugin-my-plugin'; - const targetName = 'cp'; - await expect( - createTargets({ - projectRoot: '.', - projectJson: { - name: projectName, - }, - createOptions: { - targetName, - }, - } as NormalizedCreateNodesContext), - ).resolves.toStrictEqual({ - [`${targetName}--configuration`]: { - command: `nx g ${PACKAGE_NAME}:configuration --skipTarget --targetName="cp" --project="${projectName}"`, - }, - }); - }); - - it('should NOT return configuration target if code-pushup config is given', async () => { - const projectName = 'plugin-my-plugin'; - vol.fromJSON( - { - [`code-pushup.config.ts`]: `{}`, - }, - MEMFS_VOLUME, - ); - const targetName = 'cp'; - await expect( - createTargets({ - projectRoot: '.', - projectJson: { - name: projectName, - }, - createOptions: { - targetName, - }, - } as NormalizedCreateNodesContext), - ).resolves.toStrictEqual( - expect.not.objectContaining({ - [`${targetName}--configuration`]: expect.any(Object), - }), - ); - }); - - it('should return executor target if code-pushup config is given', async () => { - const projectName = 'plugin-my-plugin'; - vol.fromJSON( - { - [`code-pushup.config.ts`]: `{}`, - }, - MEMFS_VOLUME, - ); - const targetName = 'cp'; - await expect( - createTargets({ - projectRoot: '.', - projectJson: { - name: projectName, - }, - createOptions: { - targetName, - }, - } as NormalizedCreateNodesContext), - ).resolves.toStrictEqual( - expect.objectContaining({ - [targetName]: { - executor: `${PACKAGE_NAME}:cli`, - }, - }), - ); - }); - - it('should return executor targets for project if configured', async () => { - const projectName = 'plugin-my-plugin'; - vol.fromJSON( - { - [`code-pushup.config.ts`]: `{}`, - }, - MEMFS_VOLUME, - ); - await expect( - createTargets({ - projectRoot: '.', - projectJson: { - name: projectName, - }, - createOptions: {}, - } as NormalizedCreateNodesContext), - ).resolves.toStrictEqual({ - [DEFAULT_TARGET_NAME]: { - executor: '@code-pushup/nx-plugin:cli', - }, - }); - }); - - it('should return executor targets for configured project and use given targetName', async () => { - const projectName = 'plugin-my-plugin'; - vol.fromJSON( - { - [`code-pushup.config.ts`]: `{}`, - }, - MEMFS_VOLUME, - ); - await expect( - createTargets({ - projectRoot: '.', - projectJson: { - name: projectName, - }, - createOptions: { - targetName: 'cp', - }, - } as NormalizedCreateNodesContext), - ).resolves.toStrictEqual({ - cp: { - executor: '@code-pushup/nx-plugin:cli', - }, - }); - }); - - it('should include projectPrefix options in executor targets if given', async () => { - const projectName = 'plugin-my-plugin'; - vol.fromJSON( - { - [`code-pushup.config.ts`]: `{}`, - }, - MEMFS_VOLUME, - ); - await expect( - createTargets({ - projectRoot: '.', - projectJson: { - name: projectName, - }, - createOptions: { - projectPrefix: 'cli', - }, - } as NormalizedCreateNodesContext), - ).resolves.toStrictEqual({ - [DEFAULT_TARGET_NAME]: expect.objectContaining({ - options: { projectPrefix: 'cli' }, - }), - }); - }); -}); diff --git a/packages/nx-plugin/src/plugin/types.ts b/packages/nx-plugin/src/plugin/types.ts deleted file mode 100644 index 4fd57ed95..000000000 --- a/packages/nx-plugin/src/plugin/types.ts +++ /dev/null @@ -1,25 +0,0 @@ -import type { - CreateNodesContext, - CreateNodesContextV2, - ProjectConfiguration, -} from '@nx/devkit'; -import type { WithRequired } from '@code-pushup/utils'; -import type { DynamicTargetOptions } from '../internal/types.js'; -import type { CreateTargetsOptions } from './target/targets.js'; - -export type ProjectPrefixOptions = { - projectPrefix?: string; -}; - -export type CreateNodesOptions = DynamicTargetOptions & ProjectPrefixOptions; - -export type ProjectConfigurationWithName = WithRequired< - ProjectConfiguration, - 'name' ->; - -export type NormalizedCreateNodesContext = CreateNodesContext & - CreateTargetsOptions; - -export type NormalizedCreateNodesV2Context = CreateNodesContextV2 & - CreateTargetsOptions; diff --git a/packages/nx-plugin/src/plugin/utils.ts b/packages/nx-plugin/src/plugin/utils.ts deleted file mode 100644 index 8d551f682..000000000 --- a/packages/nx-plugin/src/plugin/utils.ts +++ /dev/null @@ -1,65 +0,0 @@ -import type { CreateNodesContext, CreateNodesContextV2 } from '@nx/devkit'; -import { readFile } from 'node:fs/promises'; -import * as path from 'node:path'; -import { CP_TARGET_NAME } from './constants.js'; -import type { - CreateNodesOptions, - NormalizedCreateNodesContext, - NormalizedCreateNodesV2Context, - ProjectConfigurationWithName, -} from './types.js'; - -export async function normalizedCreateNodesContext( - context: CreateNodesContext, - projectConfigurationFile: string, - createOptions: CreateNodesOptions = {}, -): Promise { - const projectRoot = path.dirname(projectConfigurationFile); - - try { - const projectJson = JSON.parse( - (await readFile(projectConfigurationFile)).toString(), - ) as ProjectConfigurationWithName; - - const { targetName = CP_TARGET_NAME } = createOptions; - return { - ...context, - projectJson, - projectRoot, - createOptions: { - ...createOptions, - targetName, - }, - }; - } catch { - throw new Error( - `Error parsing project.json file ${projectConfigurationFile}.`, - ); - } -} - -export async function normalizedCreateNodesV2Context( - context: CreateNodesContextV2, - projectConfigurationFile: string, - createOptions: CreateNodesOptions = {}, -): Promise { - const projectRoot = path.dirname(projectConfigurationFile); - - try { - const projectJson = JSON.parse( - (await readFile(projectConfigurationFile)).toString(), - ) as ProjectConfigurationWithName; - - const { targetName = CP_TARGET_NAME } = createOptions; - return { - ...context, - projectJson, - projectRoot, - createOptions: { ...createOptions, targetName }, - }; - } catch { - throw new Error( - `Error parsing project.json file ${projectConfigurationFile}.`, - ); - } -} diff --git a/packages/nx-plugin/src/plugin/utils.unit.test.ts b/packages/nx-plugin/src/plugin/utils.unit.test.ts deleted file mode 100644 index edf2bf1cb..000000000 --- a/packages/nx-plugin/src/plugin/utils.unit.test.ts +++ /dev/null @@ -1,160 +0,0 @@ -import { vol } from 'memfs'; -import { describe, expect } from 'vitest'; -import { createNodesContext } from '@code-pushup/test-nx-utils'; -import { MEMFS_VOLUME } from '@code-pushup/test-utils'; -import { normalizedCreateNodesContext } from './utils.js'; - -describe('normalizedCreateNodesContext', () => { - it('should provide workspaceRoot', async () => { - vol.fromJSON( - { - 'project.json': JSON.stringify({ name: 'my-project' }), - }, - MEMFS_VOLUME, - ); - - await expect( - normalizedCreateNodesContext( - createNodesContext({ workspaceRoot: MEMFS_VOLUME }), - 'project.json', - ), - ).resolves.toStrictEqual( - expect.objectContaining({ - workspaceRoot: MEMFS_VOLUME, - }), - ); - }); - - it('should provide projectRoot', async () => { - vol.fromJSON( - { - 'packages/utils/project.json': JSON.stringify({ - name: 'my-project', - }), - }, - MEMFS_VOLUME, - ); - - await expect( - normalizedCreateNodesContext( - createNodesContext(), - 'packages/utils/project.json', - ), - ).resolves.toStrictEqual( - expect.objectContaining({ - projectRoot: 'packages/utils', - }), - ); - }); - - it('should provide nxJsonConfiguration', async () => { - vol.fromJSON( - { - 'project.json': JSON.stringify({ - name: 'my-project', - }), - }, - MEMFS_VOLUME, - ); - - await expect( - normalizedCreateNodesContext( - createNodesContext({ - nxJsonConfiguration: { - workspaceLayout: { - libsDir: 'libs', - }, - }, - }), - 'project.json', - ), - ).resolves.toStrictEqual( - expect.objectContaining({ - nxJsonConfiguration: { - workspaceLayout: { - libsDir: 'libs', - }, - }, - }), - ); - }); - - it('should provide projectJson', async () => { - vol.fromJSON( - { - 'project.json': JSON.stringify({ - name: 'my-project', - }), - }, - MEMFS_VOLUME, - ); - - await expect( - normalizedCreateNodesContext(createNodesContext(), 'project.json'), - ).resolves.toStrictEqual( - expect.objectContaining({ - projectJson: { - name: 'my-project', - }, - }), - ); - }); - - it('should throw for empty project.json', async () => { - vol.fromJSON( - { - 'project.json': '', - }, - MEMFS_VOLUME, - ); - - await expect( - normalizedCreateNodesContext(createNodesContext(), 'project.json'), - ).rejects.toThrow('Error parsing project.json file project.json.'); - }); - - it('should provide default targetName in createOptions', async () => { - vol.fromJSON( - { - 'project.json': JSON.stringify({ - name: 'my-project', - }), - }, - MEMFS_VOLUME, - ); - - await expect( - normalizedCreateNodesContext(createNodesContext(), 'project.json'), - ).resolves.toStrictEqual( - expect.objectContaining({ - createOptions: { - targetName: 'code-pushup', - }, - }), - ); - }); - - it('should provide createOptions', async () => { - vol.fromJSON( - { - 'project.json': JSON.stringify({ - name: 'my-project', - }), - }, - MEMFS_VOLUME, - ); - - await expect( - normalizedCreateNodesContext(createNodesContext(), 'project.json', { - projectPrefix: 'cli', - }), - ).resolves.toStrictEqual( - expect.objectContaining({ - createOptions: { - targetName: 'code-pushup', - projectPrefix: 'cli', - }, - }), - ); - }); -}); diff --git a/packages/nx-plugin/tsconfig.json b/packages/nx-plugin/tsconfig.json deleted file mode 100644 index cf0aecd4f..000000000 --- a/packages/nx-plugin/tsconfig.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "module": "CommonJS", - "verbatimModuleSyntax": false - }, - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.lib.json" - }, - { - "path": "./tsconfig.test.json" - } - ] -} diff --git a/packages/nx-plugin/tsconfig.lib.json b/packages/nx-plugin/tsconfig.lib.json deleted file mode 100644 index 71aabc78b..000000000 --- a/packages/nx-plugin/tsconfig.lib.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../dist/out-tsc", - "declaration": true, - "types": ["node"] - }, - "include": ["src/**/*.ts"], - "exclude": [ - "vitest.unit.config.ts", - "vitest.int.config.ts", - "src/**/__snapshots__/*.ts", - "src/**/*.test.ts", - "src/**/*.mock.ts", - "test/**/*.ts" - ] -} diff --git a/packages/nx-plugin/tsconfig.test.json b/packages/nx-plugin/tsconfig.test.json deleted file mode 100644 index e7914d68f..000000000 --- a/packages/nx-plugin/tsconfig.test.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../dist/out-tsc", - "types": ["vitest/globals", "vitest/importMeta", "vite/client", "node"] - }, - "include": [ - "vitest.unit.config.ts", - "vitest.int.config.ts", - "mock/**/*.ts", - "src/**/*.test.ts", - "src/**/*.test.tsx", - "src/**/*.test.js", - "src/**/*.test.jsx", - "src/**/*.d.ts" - ] -} diff --git a/packages/nx-plugin/vitest.int.config.ts b/packages/nx-plugin/vitest.int.config.ts deleted file mode 100644 index 25d5530d1..000000000 --- a/packages/nx-plugin/vitest.int.config.ts +++ /dev/null @@ -1,28 +0,0 @@ -/// -import { defineConfig } from 'vite'; -import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js'; - -export default defineConfig({ - cacheDir: '../../node_modules/.vite/nx-plugin', - test: { - reporters: ['basic'], - globals: true, - cache: { - dir: '../../node_modules/.vitest', - }, - alias: tsconfigPathAliases(), - pool: 'threads', - poolOptions: { threads: { singleThread: true } }, - coverage: { - reporter: ['text', 'lcov'], - reportsDirectory: '../../coverage/nx-plugin/int-tests', - exclude: ['mocks/**', '**/types.ts', '**/__snapshots__/**'], - }, - environment: 'node', - include: ['src/**/*.int.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], - setupFiles: [ - '../../testing/test-setup/src/lib/console.mock.ts', - '../../testing/test-setup/src/lib/reset.mocks.ts', - ], - }, -}); diff --git a/packages/nx-plugin/vitest.unit.config.ts b/packages/nx-plugin/vitest.unit.config.ts deleted file mode 100644 index db557f696..000000000 --- a/packages/nx-plugin/vitest.unit.config.ts +++ /dev/null @@ -1,29 +0,0 @@ -/// -import { defineConfig } from 'vite'; -import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js'; - -export default defineConfig({ - cacheDir: '../../node_modules/.vite/nx-plugin', - test: { - reporters: ['basic'], - globals: true, - cache: { - dir: '../../node_modules/.vitest', - }, - alias: tsconfigPathAliases(), - pool: 'threads', - poolOptions: { threads: { singleThread: true } }, - coverage: { - reporter: ['text', 'lcov'], - reportsDirectory: '../../coverage/nx-plugin/unit-tests', - exclude: ['mocks/**', '**/types.ts', '**/__snapshots__/**'], - }, - environment: 'node', - include: ['src/**/*.unit.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], - setupFiles: [ - '../../testing/test-setup/src/lib/fs.mock.ts', - '../../testing/test-setup/src/lib/console.mock.ts', - '../../testing/test-setup/src/lib/reset.mocks.ts', - ], - }, -}); From 53cb65828bab0ea9b8fb88f47dd98c7a55bbba40 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Sat, 16 Aug 2025 16:53:46 +0200 Subject: [PATCH 065/111] revert --- packages/cli/docs/nx-caching.md | 26 +- packages/nx-plugin/.env.lint.local | 1 + packages/nx-plugin/README.md | 68 +++ ...nx-plugin-dynamic-target-configuration.png | Bin 0 -> 48819 bytes packages/nx-plugin/eslint.config.js | 51 +++ packages/nx-plugin/executors.json | 9 + packages/nx-plugin/generators.json | 14 + packages/nx-plugin/mock/fixtures/env.ts | 7 + packages/nx-plugin/mock/utils/executor.ts | 16 + packages/nx-plugin/package.json | 48 +++ packages/nx-plugin/project.json | 48 +++ .../nx-plugin/src/executors/cli/README.md | 77 ++++ .../src/executors/cli/executor.int.test.ts | 48 +++ .../nx-plugin/src/executors/cli/executor.ts | 56 +++ .../src/executors/cli/executor.unit.test.ts | 142 +++++++ .../nx-plugin/src/executors/cli/schema.json | 98 +++++ .../nx-plugin/src/executors/cli/schema.ts | 19 + .../src/executors/cli/utils.int.test.ts | 51 +++ packages/nx-plugin/src/executors/cli/utils.ts | 82 ++++ .../src/executors/cli/utils.unit.test.ts | 179 ++++++++ .../nx-plugin/src/executors/internal/cli.ts | 65 +++ .../src/executors/internal/cli.unit.test.ts | 99 +++++ .../src/executors/internal/config.int.test.ts | 28 ++ .../src/executors/internal/config.ts | 69 +++ .../executors/internal/config.unit.test.ts | 395 ++++++++++++++++++ .../src/executors/internal/context.ts | 21 + .../executors/internal/context.unit.test.ts | 28 ++ .../nx-plugin/src/executors/internal/env.ts | 37 ++ .../src/executors/internal/env.unit.test.ts | 40 ++ .../nx-plugin/src/executors/internal/types.ts | 51 +++ .../src/generators/configuration/README.md | 36 ++ .../__snapshots__/root-code-pushup.config.ts | 15 + .../code-pushup-config.int.test.ts | 45 ++ .../configuration/code-pushup-config.ts | 66 +++ .../code-pushup-config.unit.test.ts | 289 +++++++++++++ .../files/code-pushup.config.ts.template | 9 + .../configuration/generator.int.test.ts | 145 +++++++ .../src/generators/configuration/generator.ts | 61 +++ .../src/generators/configuration/schema.d.ts | 9 + .../src/generators/configuration/schema.json | 45 ++ .../src/generators/configuration/types.ts | 6 + .../src/generators/configuration/utils.ts | 66 +++ .../configuration/utils.unit.test.ts | 98 +++++ .../nx-plugin/src/generators/init/README.md | 32 ++ .../src/generators/init/generator.int.test.ts | 89 ++++ .../src/generators/init/generator.ts | 101 +++++ .../nx-plugin/src/generators/init/schema.d.ts | 5 + .../nx-plugin/src/generators/init/schema.json | 23 + packages/nx-plugin/src/index.ts | 18 + packages/nx-plugin/src/internal/constants.ts | 4 + .../nx-plugin/src/internal/execute-process.ts | 186 +++++++++ .../src/internal/execute-process.unit.test.ts | 92 ++++ packages/nx-plugin/src/internal/types.ts | 4 + packages/nx-plugin/src/internal/versions.ts | 25 ++ packages/nx-plugin/src/plugin/README.md | 107 +++++ packages/nx-plugin/src/plugin/constants.ts | 1 + packages/nx-plugin/src/plugin/index.ts | 2 + packages/nx-plugin/src/plugin/plugin.ts | 34 ++ .../nx-plugin/src/plugin/plugin.unit.test.ts | 139 ++++++ .../src/plugin/target/configuration-target.ts | 24 ++ .../target/configuration.target.unit.test.ts | 19 + .../nx-plugin/src/plugin/target/constants.ts | 2 + .../src/plugin/target/executor-target.ts | 20 + .../target/executor.target.unit.test.ts | 25 ++ .../nx-plugin/src/plugin/target/targets.ts | 36 ++ .../src/plugin/target/targets.unit.test.ts | 189 +++++++++ packages/nx-plugin/src/plugin/types.ts | 25 ++ packages/nx-plugin/src/plugin/utils.ts | 65 +++ .../nx-plugin/src/plugin/utils.unit.test.ts | 160 +++++++ packages/nx-plugin/tsconfig.json | 17 + packages/nx-plugin/tsconfig.lib.json | 17 + packages/nx-plugin/tsconfig.test.json | 17 + packages/nx-plugin/vitest.int.config.ts | 28 ++ packages/nx-plugin/vitest.unit.config.ts | 29 ++ 74 files changed, 4280 insertions(+), 18 deletions(-) create mode 100644 packages/nx-plugin/.env.lint.local create mode 100644 packages/nx-plugin/README.md create mode 100644 packages/nx-plugin/docs/images/nx-plugin-dynamic-target-configuration.png create mode 100644 packages/nx-plugin/eslint.config.js create mode 100644 packages/nx-plugin/executors.json create mode 100644 packages/nx-plugin/generators.json create mode 100644 packages/nx-plugin/mock/fixtures/env.ts create mode 100644 packages/nx-plugin/mock/utils/executor.ts create mode 100644 packages/nx-plugin/package.json create mode 100644 packages/nx-plugin/project.json create mode 100644 packages/nx-plugin/src/executors/cli/README.md create mode 100644 packages/nx-plugin/src/executors/cli/executor.int.test.ts create mode 100644 packages/nx-plugin/src/executors/cli/executor.ts create mode 100644 packages/nx-plugin/src/executors/cli/executor.unit.test.ts create mode 100644 packages/nx-plugin/src/executors/cli/schema.json create mode 100644 packages/nx-plugin/src/executors/cli/schema.ts create mode 100644 packages/nx-plugin/src/executors/cli/utils.int.test.ts create mode 100644 packages/nx-plugin/src/executors/cli/utils.ts create mode 100644 packages/nx-plugin/src/executors/cli/utils.unit.test.ts create mode 100644 packages/nx-plugin/src/executors/internal/cli.ts create mode 100644 packages/nx-plugin/src/executors/internal/cli.unit.test.ts create mode 100644 packages/nx-plugin/src/executors/internal/config.int.test.ts create mode 100644 packages/nx-plugin/src/executors/internal/config.ts create mode 100644 packages/nx-plugin/src/executors/internal/config.unit.test.ts create mode 100644 packages/nx-plugin/src/executors/internal/context.ts create mode 100644 packages/nx-plugin/src/executors/internal/context.unit.test.ts create mode 100644 packages/nx-plugin/src/executors/internal/env.ts create mode 100644 packages/nx-plugin/src/executors/internal/env.unit.test.ts create mode 100644 packages/nx-plugin/src/executors/internal/types.ts create mode 100644 packages/nx-plugin/src/generators/configuration/README.md create mode 100644 packages/nx-plugin/src/generators/configuration/__snapshots__/root-code-pushup.config.ts create mode 100644 packages/nx-plugin/src/generators/configuration/code-pushup-config.int.test.ts create mode 100644 packages/nx-plugin/src/generators/configuration/code-pushup-config.ts create mode 100644 packages/nx-plugin/src/generators/configuration/code-pushup-config.unit.test.ts create mode 100644 packages/nx-plugin/src/generators/configuration/files/code-pushup.config.ts.template create mode 100644 packages/nx-plugin/src/generators/configuration/generator.int.test.ts create mode 100644 packages/nx-plugin/src/generators/configuration/generator.ts create mode 100644 packages/nx-plugin/src/generators/configuration/schema.d.ts create mode 100644 packages/nx-plugin/src/generators/configuration/schema.json create mode 100644 packages/nx-plugin/src/generators/configuration/types.ts create mode 100644 packages/nx-plugin/src/generators/configuration/utils.ts create mode 100644 packages/nx-plugin/src/generators/configuration/utils.unit.test.ts create mode 100644 packages/nx-plugin/src/generators/init/README.md create mode 100644 packages/nx-plugin/src/generators/init/generator.int.test.ts create mode 100644 packages/nx-plugin/src/generators/init/generator.ts create mode 100644 packages/nx-plugin/src/generators/init/schema.d.ts create mode 100644 packages/nx-plugin/src/generators/init/schema.json create mode 100644 packages/nx-plugin/src/index.ts create mode 100644 packages/nx-plugin/src/internal/constants.ts create mode 100644 packages/nx-plugin/src/internal/execute-process.ts create mode 100644 packages/nx-plugin/src/internal/execute-process.unit.test.ts create mode 100644 packages/nx-plugin/src/internal/types.ts create mode 100644 packages/nx-plugin/src/internal/versions.ts create mode 100644 packages/nx-plugin/src/plugin/README.md create mode 100644 packages/nx-plugin/src/plugin/constants.ts create mode 100644 packages/nx-plugin/src/plugin/index.ts create mode 100644 packages/nx-plugin/src/plugin/plugin.ts create mode 100644 packages/nx-plugin/src/plugin/plugin.unit.test.ts create mode 100644 packages/nx-plugin/src/plugin/target/configuration-target.ts create mode 100644 packages/nx-plugin/src/plugin/target/configuration.target.unit.test.ts create mode 100644 packages/nx-plugin/src/plugin/target/constants.ts create mode 100644 packages/nx-plugin/src/plugin/target/executor-target.ts create mode 100644 packages/nx-plugin/src/plugin/target/executor.target.unit.test.ts create mode 100644 packages/nx-plugin/src/plugin/target/targets.ts create mode 100644 packages/nx-plugin/src/plugin/target/targets.unit.test.ts create mode 100644 packages/nx-plugin/src/plugin/types.ts create mode 100644 packages/nx-plugin/src/plugin/utils.ts create mode 100644 packages/nx-plugin/src/plugin/utils.unit.test.ts create mode 100644 packages/nx-plugin/tsconfig.json create mode 100644 packages/nx-plugin/tsconfig.lib.json create mode 100644 packages/nx-plugin/tsconfig.test.json create mode 100644 packages/nx-plugin/vitest.int.config.ts create mode 100644 packages/nx-plugin/vitest.unit.config.ts diff --git a/packages/cli/docs/nx-caching.md b/packages/cli/docs/nx-caching.md index f2257c1f2..ce3f95f52 100644 --- a/packages/cli/docs/nx-caching.md +++ b/packages/cli/docs/nx-caching.md @@ -49,17 +49,9 @@ export default { "coverage.reportsDirectory": "{projectRoot}/coverage/unit-test" } }, - "code-pushup-js-packages": { - "cache": false, - "executor": "nx:run-commands", - "options": { - "command": "npx @code-pushup/cli collect", - "args": ["--config={projectRoot}/code-pushup.config.ts", "--cache.write=true", "--persist.skipReports=true", "--persist.outputDir={projectRoot}/.code-pushup", "--upload.project={projectName}"] - } - }, "code-pushup-coverage": { "cache": true, - "outputs": ["{projectRoot}/.code-pushup/coverage/runner-output.json"], + "outputs": ["{projectRoot}/.code-pushup/coverage"], "executor": "nx:run-commands", "options": { "command": "npx @code-pushup/cli collect", @@ -69,13 +61,13 @@ export default { }, "code-pushup": { "cache": true, - "outputs": ["{projectRoot}/.code-pushup/report.*"], + "outputs": ["{projectRoot}/.code-pushup"], "executor": "nx:run-commands", "options": { "command": "npx @code-pushup/cli", "args": ["--config={projectRoot}/code-pushup.config.ts", "--cache.read=true", "--persist.outputDir={projectRoot}/.code-pushup", "--upload.project={projectName}"] }, - "dependsOn": ["code-pushup-coverage", "code-pushup-js-packages"] + "dependsOn": ["code-pushup-coverage"] } } } @@ -88,14 +80,12 @@ This configuration creates the following task dependency graph: **Legend:** - 🐳 = Cached target -- 💾 = Parallel execution ```mermaid graph TD - A[lib-a:code-pushup 🐳] --> B[lib-a:code-pushup-coverage 💾🐳] - A --> C[lib-a:code-pushup-js-packages 💾] - B --> C[lib-a:unit-test 💾🐳] - B --> D[lib-a:int-test 💾🐳] + A[lib-a:code-pushup 🐳] --> B[lib-a:code-pushup-coverage 🐳] + B --> C[lib-a:unit-test 🐳] + B --> D[lib-a:int-test 🐳] ``` ## Command Line Example @@ -110,7 +100,7 @@ nx affected --target=code-pushup This approach has the following benefits: -1. **💾 Parallel Execution**: Plugins can run in parallel -2. **🐳 Fine-grained Caching**: Code level cache invalidation enables usage of [affected](https://nx.dev/recipes/affected-tasks) command +1. **Parallel Execution**: Plugins can run in parallel +2. **Fine-grained Caching**: Code level cache invalidation enables usage of [affected](https://nx.dev/recipes/affected-tasks) command 3. **Dependency Management**: Leverage Nx task dependencies and its caching strategy 4. **Clear Separation**: Each plugin has its own target for better debugging and maintainability diff --git a/packages/nx-plugin/.env.lint.local b/packages/nx-plugin/.env.lint.local new file mode 100644 index 000000000..ae6151bc4 --- /dev/null +++ b/packages/nx-plugin/.env.lint.local @@ -0,0 +1 @@ +NODE_OPTIONS=--experimental-require-module \ No newline at end of file diff --git a/packages/nx-plugin/README.md b/packages/nx-plugin/README.md new file mode 100644 index 000000000..a1fc57551 --- /dev/null +++ b/packages/nx-plugin/README.md @@ -0,0 +1,68 @@ +# @code-pushup/nx-plugin + +### Plugin + +Register this plugin in your `nx.json` to leverage a set of generators and executors to integrate Code PushUp into a Nx workspace. + +#### Registration + +```jsonc +// nx.json +{ + //... + "plugins": ["@code-pushup/nx-plugin"], +} +``` + +Resulting targets: + +- `nx run :code-pushup--configuration` (no config file present) +- `nx run :code-pushup` (`code-pushup.config.{ts,mjs,js}` is present) + +### Generators + +#### Init + +Install JS packages and register plugin. +See [init generator docs](./src/generators/init/README.md) for details + +Examples: + +- `nx g @code-pushup/nx-plugin:init` - setup code-pushup in the workspace +- `nx g @code-pushup/nx-plugin:init --skipPackageJson` - skip `package.json` update + +#### Configuration + +Adds a `code-pushup` target to your `project.json`. +See [configuration generator docs](./src/generators/configuration/README.md) for details + +Examples: + +- `nx g @code-pushup/nx-plugin:configuration --project=` +- `nx g @code-pushup/nx-plugin:configuration --project= --targetName=cp` + +### Executor + +#### CLI + +Install JS packages configure a target in your project json. +See [CLI executor docs](./src/executors/cli/README.md) for details + +Examples: + +```json +{ + "name": "my-project", + "targets": { + "code-pushup": { + "executor": "@code-pushup/nx-plugin:cli", + "options": { + "projectPrefix": "workspace-name" + } + } + } +} +``` + +- `nx run :code-pushup` +- `nx run :code-pushup print-config --persist.filename=custom-report` diff --git a/packages/nx-plugin/docs/images/nx-plugin-dynamic-target-configuration.png b/packages/nx-plugin/docs/images/nx-plugin-dynamic-target-configuration.png new file mode 100644 index 0000000000000000000000000000000000000000..6184f2e39cd47a6b546202d25ffc83164bc8faee GIT binary patch literal 48819 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%0AX8a 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/project.json +{ + "name": "my-project", + "targets": { + "code-pushup": { + "executor": "@code-pushup/nx-plugin:cli", + }, + }, +} +``` + +Run +`nx run :code-pushup` + +```text +Root/ +├── .code-pushup/ +│ ├── report.json 👈 generated +│ └── report.md 👈 generated +├── project-name/ +│ ├── project.json +│ ├── code-pushup.config.ts 👈 executed +│ └── ... +└── ... +``` + +By default, the Nx plugin will derive the options from the executor config. + +The following things happen: + +- the output directory defaults to `${workspaceRoot}/.code-pushup/${projectName}` +- the config file defaults to `${projectRoot}/code-pushup.config.ts` +- parses terminal arguments and forwards them to the CLI command (they override the executor config) +- the CLI command is executed + +```jsonc +{ + "name": "my-project", + "targets": { + "code-pushup": { + "executor": "@code-pushup/nx-plugin:autorun", + "options": { + "projectPrefix": "cli", // upload.project = cli-my-project + "verbose": true, + "progress": false, + // persist and upload options as defined in CoreConfig + }, + }, + }, +} +``` + +Show what will be executed without actually executing it: + +`nx run my-project:code-pushup --dryRun` + +## Options + +| Name | type | description | +| ----------------- | --------- | ------------------------------------------------------------------ | +| **projectPrefix** | `string` | prefix for upload.project on non root projects | +| **dryRun** | `boolean` | To debug the executor, dry run the command without real execution. | +| **bin** | `string` | Path to Code PushUp CLI | + +For all other options see the [CLI autorun documentation](../../../../cli/README.md#autorun-command). diff --git a/packages/nx-plugin/src/executors/cli/executor.int.test.ts b/packages/nx-plugin/src/executors/cli/executor.int.test.ts new file mode 100644 index 000000000..a68c9d78f --- /dev/null +++ b/packages/nx-plugin/src/executors/cli/executor.int.test.ts @@ -0,0 +1,48 @@ +import { execSync } from 'node:child_process'; +import { afterEach, expect, vi } from 'vitest'; +import { executorContext } from '@code-pushup/test-nx-utils'; +import runAutorunExecutor from './executor.js'; +import * as utils from './utils.js'; + +vi.mock('node:child_process', async () => { + const actual = await vi.importActual('node:child_process'); + return { + ...actual, + execSync: vi.fn(), + }; +}); + +describe('runAutorunExecutor', () => { + const parseAutorunExecutorOptionsSpy = vi.spyOn( + utils, + 'parseAutorunExecutorOptions', + ); + + afterEach(() => { + parseAutorunExecutorOptionsSpy.mockReset(); + }); + + it('should normalize context, parse CLI options and execute command', async () => { + const output = await runAutorunExecutor( + { verbose: true }, + executorContext('utils'), + ); + expect(output.success).toBe(true); + + expect(parseAutorunExecutorOptionsSpy).toHaveBeenCalledTimes(1); + + //is context normalized + expect(parseAutorunExecutorOptionsSpy).toHaveBeenCalledWith( + { verbose: true }, + expect.objectContaining({ + projectConfig: expect.objectContaining({ name: 'utils' }), + }), + ); + // eslint-disable-next-line n/no-sync + expect(execSync).toHaveBeenCalledTimes(1); + // eslint-disable-next-line n/no-sync + expect(execSync).toHaveBeenCalledWith(expect.stringContaining('utils'), { + cwd: process.cwd(), + }); + }); +}); diff --git a/packages/nx-plugin/src/executors/cli/executor.ts b/packages/nx-plugin/src/executors/cli/executor.ts new file mode 100644 index 000000000..2ff27ed74 --- /dev/null +++ b/packages/nx-plugin/src/executors/cli/executor.ts @@ -0,0 +1,56 @@ +import { type ExecutorContext, logger } from '@nx/devkit'; +import { execSync } from 'node:child_process'; +import { createCliCommand } from '../internal/cli.js'; +import { normalizeContext } from '../internal/context.js'; +import type { AutorunCommandExecutorOptions } from './schema.js'; +import { mergeExecutorOptions, parseAutorunExecutorOptions } from './utils.js'; + +export type ExecutorOutput = { + success: boolean; + command?: string; + error?: Error; +}; + +export default function runAutorunExecutor( + terminalAndExecutorOptions: AutorunCommandExecutorOptions, + context: ExecutorContext, +): Promise { + const normalizedContext = normalizeContext(context); + const mergedOptions = mergeExecutorOptions( + context.target?.options, + terminalAndExecutorOptions, + ); + const cliArgumentObject = parseAutorunExecutorOptions( + mergedOptions, + normalizedContext, + ); + const { dryRun, verbose, command } = mergedOptions; + + const commandString = createCliCommand({ command, args: cliArgumentObject }); + const commandStringOptions = context.cwd ? { cwd: context.cwd } : {}; + if (verbose) { + logger.info(`Run CLI executor ${command ?? ''}`); + logger.info(`Command: ${commandString}`); + } + if (dryRun) { + logger.warn(`DryRun execution of: ${commandString}`); + } else { + try { + // @TODO use executeProcess instead of execSync -> non blocking, logs #761 + // eslint-disable-next-line n/no-sync + execSync(commandString, commandStringOptions); + } catch (error) { + logger.error(error); + return Promise.resolve({ + success: false, + command: commandString, + error: error as Error, + }); + } + } + + return Promise.resolve({ + success: true, + command: commandString, + }); +} diff --git a/packages/nx-plugin/src/executors/cli/executor.unit.test.ts b/packages/nx-plugin/src/executors/cli/executor.unit.test.ts new file mode 100644 index 000000000..9af4f1b6b --- /dev/null +++ b/packages/nx-plugin/src/executors/cli/executor.unit.test.ts @@ -0,0 +1,142 @@ +import { logger } from '@nx/devkit'; +import { execSync } from 'node:child_process'; +import { afterAll, afterEach, beforeEach, expect, vi } from 'vitest'; +import { executorContext } from '@code-pushup/test-nx-utils'; +import { MEMFS_VOLUME } from '@code-pushup/test-utils'; +import runAutorunExecutor from './executor.js'; + +vi.mock('node:child_process', async () => { + const actual = await vi.importActual('node:child_process'); + + return { + ...actual, + execSync: vi.fn((command: string) => { + if (command.includes('THROW_ERROR')) { + throw new Error(command); + } + }), + }; +}); + +describe('runAutorunExecutor', () => { + const processEnvCP = Object.fromEntries( + Object.entries(process.env).filter(([k]) => k.startsWith('CP_')), + ); + const loggerInfoSpy = vi.spyOn(logger, 'info'); + const loggerWarnSpy = vi.spyOn(logger, 'warn'); + + /* eslint-disable functional/immutable-data, @typescript-eslint/no-dynamic-delete */ + beforeAll(() => { + Object.entries(process.env) + .filter(([k]) => k.startsWith('CP_')) + .forEach(([k]) => delete process.env[k]); + }); + + beforeEach(() => { + vi.unstubAllEnvs(); + }); + + afterEach(() => { + loggerWarnSpy.mockReset(); + loggerInfoSpy.mockReset(); + }); + + afterAll(() => { + Object.entries(processEnvCP).forEach(([k, v]) => (process.env[k] = v)); + }); + /* eslint-enable functional/immutable-data, @typescript-eslint/no-dynamic-delete */ + + it('should call execSync with return result', async () => { + const output = await runAutorunExecutor({}, executorContext('utils')); + expect(output.success).toBe(true); + expect(output.command).toMatch('npx @code-pushup/cli'); + // eslint-disable-next-line n/no-sync + expect(execSync).toHaveBeenCalledWith( + expect.stringContaining('npx @code-pushup/cli'), + { cwd: MEMFS_VOLUME }, + ); + }); + + it('should normalize context', async () => { + const output = await runAutorunExecutor( + {}, + { + ...executorContext('utils'), + cwd: 'cwd-form-context', + }, + ); + expect(output.success).toBe(true); + expect(output.command).toMatch('utils'); + // eslint-disable-next-line n/no-sync + expect(execSync).toHaveBeenCalledWith(expect.stringContaining('utils'), { + cwd: 'cwd-form-context', + }); + }); + + it('should process executorOptions', async () => { + const output = await runAutorunExecutor( + { persist: { filename: 'REPORT' } }, + executorContext('testing-utils'), + ); + expect(output.success).toBe(true); + expect(output.command).toMatch('--persist.filename="REPORT"'); + }); + + it('should create command from context and options if no api key is set', async () => { + vi.stubEnv('CP_PROJECT', 'CLI'); + const output = await runAutorunExecutor( + { persist: { filename: 'REPORT', format: ['md', 'json'] } }, + executorContext('core'), + ); + expect(output.command).toMatch('--persist.filename="REPORT"'); + expect(output.command).toMatch( + '--persist.format="md" --persist.format="json"', + ); + }); + + it('should create command from context, options and arguments if api key is set', async () => { + vi.stubEnv('CP_API_KEY', 'cp_1234567'); + vi.stubEnv('CP_PROJECT', 'CLI'); + const output = await runAutorunExecutor( + { persist: { filename: 'REPORT', format: ['md', 'json'] } }, + executorContext('core'), + ); + expect(output.command).toMatch('--persist.filename="REPORT"'); + expect(output.command).toMatch( + '--persist.format="md" --persist.format="json"', + ); + expect(output.command).toMatch('--upload.apiKey="cp_1234567"'); + expect(output.command).toMatch('--upload.project="CLI"'); + }); + + it('should log information if verbose is set', async () => { + const output = await runAutorunExecutor( + { verbose: true }, + { ...executorContext('github-action'), cwd: '' }, + ); + // eslint-disable-next-line n/no-sync + expect(execSync).toHaveBeenCalledTimes(1); + + expect(output.command).toMatch('--verbose'); + expect(loggerWarnSpy).toHaveBeenCalledTimes(0); + expect(loggerInfoSpy).toHaveBeenCalledTimes(2); + expect(loggerInfoSpy).toHaveBeenCalledWith( + expect.stringContaining(`Run CLI executor`), + ); + expect(loggerInfoSpy).toHaveBeenCalledWith( + expect.stringContaining('Command: npx @code-pushup/cli'), + ); + }); + + it('should log command if dryRun is set', async () => { + await runAutorunExecutor({ dryRun: true }, executorContext('utils')); + + expect(loggerInfoSpy).toHaveBeenCalledTimes(0); + expect(loggerWarnSpy).toHaveBeenCalledTimes(1); + expect(loggerWarnSpy).toHaveBeenCalledWith( + expect.stringContaining( + 'DryRun execution of: npx @code-pushup/cli --dryRun', + ), + ); + }); +}); diff --git a/packages/nx-plugin/src/executors/cli/schema.json b/packages/nx-plugin/src/executors/cli/schema.json new file mode 100644 index 000000000..e494c4cc0 --- /dev/null +++ b/packages/nx-plugin/src/executors/cli/schema.json @@ -0,0 +1,98 @@ +{ + "$schema": "http://json-schema.org/schema", + "$id": "AutorunExecutorOptions", + "title": "CodePushup CLI autorun executor", + "description": "Executes the @code-pushup/cli autorun command See: https://github.com/code-pushup/cli/blob/main/packages/cli/README.md#autorun-command", + "type": "object", + "properties": { + "command": { + "type": "string", + "description": "The command to run.", + "$default": { + "$source": "argv", + "index": 0 + } + }, + "dryRun": { + "type": "boolean", + "description": "Print the commands that would be run, but don't actually run them" + }, + "bin": { + "type": "string", + "description": "Path to Code PushUp CLI" + }, + "verbose": { + "type": "boolean", + "description": "Print additional logs" + }, + "progress": { + "type": "boolean", + "description": "Print additional logs" + }, + "onlyPlugins": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Only run the specified plugins" + }, + "config": { + "type": "string", + "description": "Path to the configuration file" + }, + "projectPrefix": { + "type": "string", + "description": "Prefix for project name" + }, + "persist": { + "type": "object", + "properties": { + "filename": { + "type": "string", + "description": "Filename to save the configuration" + }, + "outputDir": { + "type": "string", + "description": "Directory to save the configuration" + }, + "format": { + "type": "array", + "enum": ["json", "md"], + "description": "Format to save the report in" + } + } + }, + "upload": { + "type": "object", + "properties": { + "server": { + "type": "string", + "format": "uri", + "description": "URL of deployed portal API" + }, + "apiKey": { + "type": "string", + "description": "API key with write access to portal (use `process.env` for security)" + }, + "organization": { + "type": "string", + "pattern": "^[a-z\\d]+(?:-[a-z\\d]+)*$", + "maxLength": 128, + "description": "Organization slug from Code PushUp portal" + }, + "project": { + "type": "string", + "pattern": "^[a-z\\d]+(?:-[a-z\\d]+)*$", + "maxLength": 128, + "description": "Project slug from Code PushUp portal" + }, + "timeout": { + "type": "integer", + "exclusiveMinimum": 0, + "description": "Request timeout in minutes" + } + } + } + }, + "additionalProperties": true +} diff --git a/packages/nx-plugin/src/executors/cli/schema.ts b/packages/nx-plugin/src/executors/cli/schema.ts new file mode 100644 index 000000000..d73a394b6 --- /dev/null +++ b/packages/nx-plugin/src/executors/cli/schema.ts @@ -0,0 +1,19 @@ +import type { PersistConfig, UploadConfig } from '@code-pushup/models'; +import type { + CollectExecutorOnlyOptions, + GeneralExecutorOnlyOptions, + GlobalExecutorOptions, + ProjectExecutorOnlyOptions, +} from '../internal/types.js'; + +export type AutorunCommandExecutorOnlyOptions = ProjectExecutorOnlyOptions & + CollectExecutorOnlyOptions & + GeneralExecutorOnlyOptions; + +export type AutorunCommandExecutorOptions = Partial< + { + upload: Partial; + persist: Partial; + } & AutorunCommandExecutorOnlyOptions & + GlobalExecutorOptions +>; diff --git a/packages/nx-plugin/src/executors/cli/utils.int.test.ts b/packages/nx-plugin/src/executors/cli/utils.int.test.ts new file mode 100644 index 000000000..180f22af1 --- /dev/null +++ b/packages/nx-plugin/src/executors/cli/utils.int.test.ts @@ -0,0 +1,51 @@ +import { expect, vi } from 'vitest'; +import type { UploadConfig } from '@code-pushup/models'; +import { normalizedExecutorContext } from '../../../mock/utils/executor.js'; +import * as config from '../internal/config.js'; +import { parseAutorunExecutorOptions } from './utils.js'; + +describe('parseAutorunExecutorOptions', () => { + const persistConfigSpy = vi.spyOn(config, 'persistConfig'); + const uploadConfigSpy = vi.spyOn(config, 'uploadConfig'); + const globalConfigSpy = vi.spyOn(config, 'globalConfig'); + const normalizedContext = normalizedExecutorContext('portal'); + + afterEach(() => { + persistConfigSpy.mockReset(); + uploadConfigSpy.mockReset(); + globalConfigSpy.mockReset(); + }); + + it('should call child config functions with options', () => { + parseAutorunExecutorOptions( + { + verbose: true, + persist: { filename: 'my-name' }, + upload: { + server: 'https://new-portal.code-pushup.dev', + } as UploadConfig, + }, + normalizedContext, + ); + expect(persistConfigSpy).toHaveBeenCalledWith( + { filename: 'my-name' }, + normalizedContext, + ); + expect(uploadConfigSpy).toHaveBeenCalledWith( + { + server: 'https://new-portal.code-pushup.dev', + }, + normalizedContext, + ); + expect(globalConfigSpy).toHaveBeenCalledWith( + { + verbose: true, + persist: { filename: 'my-name' }, + upload: { + server: 'https://new-portal.code-pushup.dev', + } as UploadConfig, + }, + normalizedContext, + ); + }); +}); diff --git a/packages/nx-plugin/src/executors/cli/utils.ts b/packages/nx-plugin/src/executors/cli/utils.ts new file mode 100644 index 000000000..afcca4542 --- /dev/null +++ b/packages/nx-plugin/src/executors/cli/utils.ts @@ -0,0 +1,82 @@ +import { + globalConfig, + persistConfig, + uploadConfig, +} from '../internal/config.js'; +import type { NormalizedExecutorContext } from '../internal/context.js'; +import type { + AutorunCommandExecutorOnlyOptions, + AutorunCommandExecutorOptions, +} from './schema.js'; + +export function parseAutorunExecutorOnlyOptions( + options: Partial, +): AutorunCommandExecutorOnlyOptions { + const { projectPrefix, dryRun, onlyPlugins } = options; + return { + ...(projectPrefix && { projectPrefix }), + ...(dryRun != null && { dryRun }), + ...(onlyPlugins && { onlyPlugins }), + }; +} + +export function parseAutorunExecutorOptions( + options: Partial, + normalizedContext: NormalizedExecutorContext, +): AutorunCommandExecutorOptions { + const { projectPrefix, persist, upload, command } = options; + const needsUploadParams = + command === 'upload' || command === 'autorun' || command === undefined; + const uploadCfg = uploadConfig( + { projectPrefix, ...upload }, + normalizedContext, + ); + const hasApiToken = uploadCfg?.apiKey != null; + return { + ...parseAutorunExecutorOnlyOptions(options), + ...globalConfig(options, normalizedContext), + persist: persistConfig({ projectPrefix, ...persist }, normalizedContext), + // @TODO This is a hack to avoid validation errors of upload config for commands that dont need it. + // Fix: use utils and execute the core logic directly + // Blocked by Nx plugins can't compile to es6 + ...(needsUploadParams && hasApiToken ? { upload: uploadCfg } : {}), + }; +} + +/** + * Deeply merges executor options. + * + * @param targetOptions - The original options from the target configuration. + * @param cliOptions - The options from Nx, combining target options and CLI arguments. + * @returns A new object with deeply merged properties. + * + * Nx performs a shallow merge by default, where command-line arguments can override entire objects + * (e.g., `--persist.filename` replaces the entire `persist` object). + * This function ensures that nested properties are deeply merged, + * preserving the original target options where CLI arguments are not provided. + */ +export function mergeExecutorOptions( + targetOptions: Partial, + cliOptions: Partial, +): AutorunCommandExecutorOptions { + return { + ...targetOptions, + ...cliOptions, + ...(targetOptions?.persist || cliOptions?.persist + ? { + persist: { + ...targetOptions?.persist, + ...cliOptions?.persist, + }, + } + : {}), + ...(targetOptions?.upload || cliOptions?.upload + ? { + upload: { + ...targetOptions?.upload, + ...cliOptions?.upload, + }, + } + : {}), + }; +} diff --git a/packages/nx-plugin/src/executors/cli/utils.unit.test.ts b/packages/nx-plugin/src/executors/cli/utils.unit.test.ts new file mode 100644 index 000000000..7a4141eff --- /dev/null +++ b/packages/nx-plugin/src/executors/cli/utils.unit.test.ts @@ -0,0 +1,179 @@ +import { type MockInstance, expect, vi } from 'vitest'; +import { osAgnosticPath } from '@code-pushup/test-utils'; +import type { Command } from '../internal/types.js'; +import { + mergeExecutorOptions, + parseAutorunExecutorOnlyOptions, + parseAutorunExecutorOptions, +} from './utils.js'; + +describe('parseAutorunExecutorOnlyOptions', () => { + it('should provide NO default projectPrefix', () => { + expect(parseAutorunExecutorOnlyOptions({})).toStrictEqual( + expect.not.objectContaining({ projectPrefix: expect.anything() }), + ); + }); + + it('should process given projectPrefix', () => { + expect( + parseAutorunExecutorOnlyOptions({ projectPrefix: 'cli' }), + ).toStrictEqual(expect.objectContaining({ projectPrefix: 'cli' })); + }); + + it('should provide NO default dryRun', () => { + expect(parseAutorunExecutorOnlyOptions({})).toStrictEqual( + expect.not.objectContaining({ dryRun: expect.anything() }), + ); + }); + + it('should process given dryRun', () => { + expect(parseAutorunExecutorOnlyOptions({ dryRun: false })).toStrictEqual( + expect.objectContaining({ dryRun: false }), + ); + }); + + it('should provide default onlyPlugins', () => { + expect(parseAutorunExecutorOnlyOptions({})).toStrictEqual( + expect.not.objectContaining({ onlyPlugins: ['json'] }), + ); + }); + + it('should process given onlyPlugins', () => { + expect( + parseAutorunExecutorOnlyOptions({ onlyPlugins: ['md', 'json'] }), + ).toStrictEqual(expect.objectContaining({ onlyPlugins: ['md', 'json'] })); + }); +}); + +describe('parseAutorunExecutorOptions', () => { + let processEnvSpy: MockInstance<[], NodeJS.ProcessEnv>; + + beforeAll(() => { + processEnvSpy = vi.spyOn(process, 'env', 'get').mockReturnValue({}); + }); + + afterAll(() => { + processEnvSpy.mockRestore(); + }); + + it('should leverage other config helper to assemble the executor config', () => { + const projectName = 'my-app'; + const executorOptions = parseAutorunExecutorOptions( + { + persist: { + filename: 'from-options', + }, + }, + { + projectName, + workspaceRoot: 'workspaceRoot', + projectConfig: { + name: 'my-app', + root: 'root', + }, + }, + ); + expect(osAgnosticPath(executorOptions.config ?? '')).toBe( + osAgnosticPath('root/code-pushup.config.ts'), + ); + expect(executorOptions).toEqual( + expect.objectContaining({ + progress: false, + verbose: false, + }), + ); + + expect(processEnvSpy.mock.calls.length).toBeGreaterThanOrEqual(1); + + expect(executorOptions.persist).toEqual( + expect.objectContaining({ + filename: 'from-options', + }), + ); + + expect(osAgnosticPath(executorOptions.persist?.outputDir ?? '')).toBe( + osAgnosticPath('workspaceRoot/.code-pushup/my-app'), + ); + }); + + it.each(['upload', 'autorun', undefined])( + 'should include upload config for command %s if API key is provided', + command => { + const projectName = 'my-app'; + const executorOptions = parseAutorunExecutorOptions( + { + command, + upload: { + apiKey: '123456789', + }, + }, + { + projectName, + workspaceRoot: 'workspaceRoot', + projectConfig: { + name: 'my-app', + root: 'root', + }, + }, + ); + + expect(executorOptions).toEqual( + expect.objectContaining({ + upload: expect.any(Object), + }), + ); + }, + ); + + it.each(['collect'])( + 'should not include upload config for command %s', + command => { + const projectName = 'my-app'; + const executorOptions = parseAutorunExecutorOptions( + { + command, + upload: { + organization: 'code-pushup', + }, + }, + { + projectName, + workspaceRoot: 'workspaceRoot', + projectConfig: { + name: 'my-app', + root: 'root', + }, + }, + ); + + expect(executorOptions).toEqual( + expect.not.objectContaining({ + upload: expect.any(Object), + }), + ); + }, + ); +}); + +describe('mergeExecutorOptions', () => { + it('should deeply merge target and CLI options', () => { + const targetOptions = { + persist: { + outputDir: '.reports', + filename: 'report', + }, + }; + const cliOptions = { + persist: { + filename: 'report-file', + }, + }; + const expected = { + persist: { + outputDir: '.reports', + filename: 'report-file', + }, + }; + expect(mergeExecutorOptions(targetOptions, cliOptions)).toEqual(expected); + }); +}); diff --git a/packages/nx-plugin/src/executors/internal/cli.ts b/packages/nx-plugin/src/executors/internal/cli.ts new file mode 100644 index 000000000..b733eec84 --- /dev/null +++ b/packages/nx-plugin/src/executors/internal/cli.ts @@ -0,0 +1,65 @@ +export function createCliCommand(options?: { + args?: Record; + command?: string; + bin?: string; +}): string { + const { bin = '@code-pushup/cli', command, args } = options ?? {}; + return `npx ${bin} ${objectToCliArgs({ _: command ?? [], ...args }).join( + ' ', + )}`; +} + +type ArgumentValue = number | string | boolean | string[]; +export type CliArgsObject> = + T extends never + ? Record | { _: string } + : T; + +// @TODO import from @code-pushup/utils => get rid of poppins for cjs support +export function objectToCliArgs< + T extends object = Record, +>(params?: CliArgsObject): string[] { + if (!params) { + return []; + } + + return Object.entries(params).flatMap(([key, value]) => { + // process/file/script + if (key === '_') { + return (Array.isArray(value) ? value : [`${value}`]).filter( + v => v != null, + ); + } + + const prefix = key.length === 1 ? '-' : '--'; + // "-*" arguments (shorthands) + if (Array.isArray(value)) { + return value.map(v => `${prefix}${key}="${v}"`); + } + + if (typeof value === 'object') { + return Object.entries(value as Record).flatMap( + // transform nested objects to the dot notation `key.subkey` + ([k, v]) => objectToCliArgs({ [`${key}.${k}`]: v }), + ); + } + + if (typeof value === 'string') { + return [`${prefix}${key}="${value}"`]; + } + + if (typeof value === 'number') { + return [`${prefix}${key}=${value}`]; + } + + if (typeof value === 'boolean') { + return [`${prefix}${value ? '' : 'no-'}${key}`]; + } + + if (value === undefined) { + return []; + } + + throw new Error(`Unsupported type ${typeof value} for key ${key}`); + }); +} diff --git a/packages/nx-plugin/src/executors/internal/cli.unit.test.ts b/packages/nx-plugin/src/executors/internal/cli.unit.test.ts new file mode 100644 index 000000000..e65cb0ec0 --- /dev/null +++ b/packages/nx-plugin/src/executors/internal/cli.unit.test.ts @@ -0,0 +1,99 @@ +import { describe, expect, it } from 'vitest'; +import { createCliCommand, objectToCliArgs } from './cli.js'; + +describe('objectToCliArgs', () => { + it('should empty params', () => { + const result = objectToCliArgs(); + expect(result).toEqual([]); + }); + + it('should handle the "_" argument as script', () => { + const params = { _: 'bin.js' }; + const result = objectToCliArgs(params); + expect(result).toEqual(['bin.js']); + }); + + it('should handle the "_" argument with multiple values', () => { + const params = { _: ['bin.js', '--help'] }; + const result = objectToCliArgs(params); + expect(result).toEqual(['bin.js', '--help']); + }); + + it('should handle shorthands arguments', () => { + const params = { + e: `test`, + }; + const result = objectToCliArgs(params); + expect(result).toEqual([`-e="${params.e}"`]); + }); + + it('should handle string arguments', () => { + const params = { name: 'Juanita' }; + const result = objectToCliArgs(params); + expect(result).toEqual(['--name="Juanita"']); + }); + + it('should handle number arguments', () => { + const params = { parallel: 5 }; + const result = objectToCliArgs(params); + expect(result).toEqual(['--parallel=5']); + }); + + it('should handle boolean arguments', () => { + const params = { progress: true }; + const result = objectToCliArgs(params); + expect(result).toEqual(['--progress']); + }); + + it('should handle negated boolean arguments', () => { + const params = { progress: false }; + const result = objectToCliArgs(params); + expect(result).toEqual(['--no-progress']); + }); + + it('should handle array of string arguments', () => { + const params = { format: ['json', 'md'] }; + const result = objectToCliArgs(params); + expect(result).toEqual(['--format="json"', '--format="md"']); + }); + + it('should handle objects', () => { + const params = { format: { json: 'simple' } }; + const result = objectToCliArgs(params); + expect(result).toStrictEqual(['--format.json="simple"']); + }); + + it('should handle nested objects', () => { + const params = { persist: { format: ['json', 'md'], verbose: false } }; + const result = objectToCliArgs(params); + expect(result).toEqual([ + '--persist.format="json"', + '--persist.format="md"', + '--no-persist.verbose', + ]); + }); + + it('should handle objects with undefined', () => { + const params = { format: undefined }; + const result = objectToCliArgs(params); + expect(result).toStrictEqual([]); + }); + + it('should throw error for unsupported type', () => { + expect(() => objectToCliArgs({ param: Symbol('') })).toThrow( + 'Unsupported type', + ); + }); +}); + +describe('createCliCommand', () => { + it('should create command out of object for arguments', () => { + const result = createCliCommand({ args: { verbose: true } }); + expect(result).toBe('npx @code-pushup/cli --verbose'); + }); + + it('should create command out of object for arguments with positional', () => { + const result = createCliCommand({ args: { _: 'autorun', verbose: true } }); + expect(result).toBe('npx @code-pushup/cli autorun --verbose'); + }); +}); diff --git a/packages/nx-plugin/src/executors/internal/config.int.test.ts b/packages/nx-plugin/src/executors/internal/config.int.test.ts new file mode 100644 index 000000000..54b2e32dc --- /dev/null +++ b/packages/nx-plugin/src/executors/internal/config.int.test.ts @@ -0,0 +1,28 @@ +import { describe, expect } from 'vitest'; +import { ENV } from '../../../mock/fixtures/env.js'; +import { uploadConfig } from './config.js'; +import * as env from './env.js'; + +describe('uploadConfig', () => { + const processEnvSpy = vi.spyOn(process, 'env', 'get').mockReturnValue({}); + const parseEnvSpy = vi.spyOn(env, 'parseEnv'); + + it('should call parseEnv function with values from process.env', () => { + processEnvSpy.mockReturnValue(ENV); + expect( + uploadConfig( + {}, + { + workspaceRoot: 'workspaceRoot', + projectConfig: { + name: 'my-app', + root: 'root', + }, + }, + ), + ).toBeDefined(); + + expect(parseEnvSpy).toHaveBeenCalledTimes(1); + expect(parseEnvSpy).toHaveBeenCalledWith(ENV); + }); +}); diff --git a/packages/nx-plugin/src/executors/internal/config.ts b/packages/nx-plugin/src/executors/internal/config.ts new file mode 100644 index 000000000..0eb13f8a8 --- /dev/null +++ b/packages/nx-plugin/src/executors/internal/config.ts @@ -0,0 +1,69 @@ +import * as path from 'node:path'; +import type { PersistConfig, UploadConfig } from '@code-pushup/models'; +import { parseEnv } from './env.js'; +import type { + BaseNormalizedExecutorContext, + GlobalExecutorOptions, + ProjectExecutorOnlyOptions, +} from './types.js'; + +export function globalConfig( + options: Partial>, + context: BaseNormalizedExecutorContext, +): GlobalExecutorOptions { + const { projectConfig } = context; + const { root: projectRoot = '' } = projectConfig ?? {}; + // For better debugging use `--verbose --no-progress` as default + const { verbose, progress, config } = options; + return { + verbose: !!verbose, + progress: !!progress, + config: config ?? path.join(projectRoot, 'code-pushup.config.ts'), + }; +} + +export function persistConfig( + options: Partial, + context: BaseNormalizedExecutorContext, +): Partial { + const { projectConfig, workspaceRoot } = context; + + const { name: projectName = '' } = projectConfig ?? {}; + const { + format, + outputDir = path.join(workspaceRoot, '.code-pushup', projectName), // always in /.code-pushup/, + filename, + } = options; + + return { + outputDir, + ...(format ? { format } : {}), + ...(filename ? { filename } : {}), + }; +} + +export function uploadConfig( + options: Partial, + context: BaseNormalizedExecutorContext, +): Partial { + const { projectConfig, workspaceRoot } = context; + + const { name: projectName } = projectConfig ?? {}; + const { projectPrefix, server, apiKey, organization, project, timeout } = + options; + const applyPrefix = workspaceRoot === '.'; + const prefix = projectPrefix ? `${projectPrefix}-` : ''; + return { + ...(projectName + ? { + project: applyPrefix ? `${prefix}${projectName}` : projectName, + } + : {}), + ...parseEnv(process.env), + ...Object.fromEntries( + Object.entries({ server, apiKey, organization, project, timeout }).filter( + ([_, v]) => v !== undefined, + ), + ), + }; +} diff --git a/packages/nx-plugin/src/executors/internal/config.unit.test.ts b/packages/nx-plugin/src/executors/internal/config.unit.test.ts new file mode 100644 index 000000000..c38554459 --- /dev/null +++ b/packages/nx-plugin/src/executors/internal/config.unit.test.ts @@ -0,0 +1,395 @@ +import { type MockInstance, describe, expect } from 'vitest'; +import { osAgnosticPath } from '@code-pushup/test-utils'; +import { ENV } from '../../../mock/fixtures/env.js'; +import { globalConfig, persistConfig, uploadConfig } from './config.js'; + +describe('globalConfig', () => { + it('should provide default global verbose options', () => { + expect( + globalConfig( + {}, + { + workspaceRoot: '/test/root/workspace-root', + projectConfig: { + name: 'my-app', + root: 'packages/project-root', + }, + }, + ), + ).toEqual(expect.objectContaining({ verbose: false })); + }); + + it('should parse global verbose options', () => { + expect( + globalConfig( + { verbose: true }, + { + workspaceRoot: '/test/root/workspace-root', + projectConfig: { + name: 'my-app', + root: 'packages/project-root', + }, + }, + ), + ).toEqual(expect.objectContaining({ verbose: true })); + }); + + it('should provide default global progress options', () => { + expect( + globalConfig( + {}, + { + workspaceRoot: '/test/root/workspace-root', + projectConfig: { + name: 'my-app', + root: 'packages/project-root', + }, + }, + ), + ).toEqual(expect.objectContaining({ progress: false })); + }); + + it('should parse global progress options', () => { + expect( + globalConfig( + { progress: true }, + { + workspaceRoot: '/test/root/workspace-root', + projectConfig: { + name: 'my-app', + root: 'packages/project-root', + }, + }, + ), + ).toEqual(expect.objectContaining({ progress: true })); + }); + + it('should provide default global config options', () => { + const { config } = globalConfig( + {}, + { + workspaceRoot: '/test/root/workspace-root', + projectConfig: { + name: 'my-app', + root: 'packages/project-root', + }, + }, + ); + expect(osAgnosticPath(String(config))).toStrictEqual( + expect.stringContaining( + osAgnosticPath('project-root/code-pushup.config.ts'), + ), + ); + }); + + it('should parse global config options', () => { + expect( + globalConfig( + { config: 'my.config.ts' }, + { + workspaceRoot: '/test/root/workspace-root', + projectConfig: { + name: 'my-app', + root: 'packages/project-root', + }, + }, + ), + ).toEqual(expect.objectContaining({ config: 'my.config.ts' })); + }); + + it('should work with empty projectConfig', () => { + expect( + globalConfig( + {}, + { + workspaceRoot: '/test/root/workspace-root', + }, + ), + ).toEqual(expect.objectContaining({ config: 'code-pushup.config.ts' })); + }); + + it('should exclude other options', () => { + expect( + globalConfig( + { test: 42, verbose: true }, + { + workspaceRoot: '/test/root/workspace-root', + projectConfig: { + name: 'my-app', + root: 'packages/project-root', + }, + }, + ), + ).toEqual(expect.not.objectContaining({ test: expect.anything() })); + }); +}); + +describe('persistConfig', () => { + it('should NOT provide default persist format options', () => { + expect( + persistConfig( + {}, + { + workspaceRoot: 'workspaceRoot', + projectConfig: { + name: 'my-app', + root: 'root', + }, + }, + ), + ).toEqual(expect.not.objectContaining({ format: expect.anything() })); + }); + + it('should parse given persist format option', () => { + expect( + persistConfig( + { + format: ['md'], + }, + { + workspaceRoot: 'workspaceRoot', + projectConfig: { + name: 'name', + root: 'root', + }, + }, + ), + ).toEqual( + expect.objectContaining({ + format: ['md'], + }), + ); + }); + + it('should provide default outputDir options', () => { + const projectName = 'my-app'; + const { outputDir } = persistConfig( + {}, + { + workspaceRoot: '/test/root/workspace-root', + projectConfig: { + name: projectName, + root: 'packages/project-root', + }, + }, + ); + expect(osAgnosticPath(String(outputDir))).toBe( + osAgnosticPath(`/test/root/workspace-root/.code-pushup/${projectName}`), + ); + }); + + it('should parse given outputDir options', () => { + const outputDir = '../dist/packages/test-folder'; + const { outputDir: resultingOutDir } = persistConfig( + { + outputDir, + }, + { + workspaceRoot: 'workspaceRoot', + projectConfig: { + name: 'my-app', + root: 'root', + }, + }, + ); + expect(osAgnosticPath(String(resultingOutDir))).toEqual( + expect.stringContaining(osAgnosticPath('../dist/packages/test-folder')), + ); + }); + + it('should work with empty projectConfig', () => { + const { outputDir } = persistConfig( + {}, + { + workspaceRoot: '/test/root/workspace-root', + }, + ); + + expect(osAgnosticPath(String(outputDir))).toEqual( + expect.stringContaining(osAgnosticPath('.code-pushup')), + ); + }); + + it('should provide NO default persist filename', () => { + const projectName = 'my-app'; + expect( + persistConfig( + {}, + { + workspaceRoot: 'workspaceRoot', + projectConfig: { + name: projectName, + root: 'root', + }, + }, + ), + ).toEqual(expect.not.objectContaining({ filename: expect.anything() })); + }); + + it('should parse given persist filename', () => { + const projectName = 'my-app'; + expect( + persistConfig( + { + filename: 'my-name', + }, + { + workspaceRoot: 'workspaceRoot', + projectConfig: { + name: projectName, + root: 'root', + }, + }, + ), + ).toEqual(expect.objectContaining({ filename: 'my-name' })); + }); +}); + +describe('uploadConfig', () => { + const baseUploadConfig = { + server: 'https://base-portal.code.pushup.dev', + apiKey: 'apiKey', + organization: 'organization', + }; + + let processEnvSpy: MockInstance<[], NodeJS.ProcessEnv>; + + beforeAll(() => { + processEnvSpy = vi.spyOn(process, 'env', 'get').mockReturnValue({}); + }); + + afterAll(() => { + processEnvSpy.mockRestore(); + }); + + it('should provide default upload project options as project name', () => { + const projectName = 'my-app'; + expect( + uploadConfig(baseUploadConfig, { + workspaceRoot: 'workspace-root', + projectConfig: { + name: projectName, + root: 'root', + }, + }), + ).toEqual(expect.objectContaining({ project: projectName })); + }); + + it('should parse upload project options', () => { + const projectName = 'utils'; + expect( + uploadConfig( + { + ...baseUploadConfig, + project: 'cli-utils', + }, + { + workspaceRoot: 'workspace-root', + projectConfig: { + name: projectName, + root: 'root', + }, + }, + ), + ).toEqual(expect.objectContaining({ project: 'cli-utils' })); + }); + + it('should parse upload server options', () => { + expect( + uploadConfig( + { + ...baseUploadConfig, + server: 'https://new1-portal.code.pushup.dev', + }, + { + workspaceRoot: 'workspace-root', + projectConfig: { + name: 'utils', + root: 'root', + }, + }, + ), + ).toEqual( + expect.objectContaining({ + server: 'https://new1-portal.code.pushup.dev', + }), + ); + }); + + it('should parse upload organization options', () => { + expect( + uploadConfig( + { + ...baseUploadConfig, + organization: 'code-pushup-v2', + }, + { + workspaceRoot: 'workspace-root', + projectConfig: { + name: 'utils', + root: 'root', + }, + }, + ), + ).toEqual(expect.objectContaining({ organization: 'code-pushup-v2' })); + }); + + it('should parse upload apiKey options', () => { + expect( + uploadConfig( + { + ...baseUploadConfig, + apiKey: '123456789', + }, + { + workspaceRoot: 'workspace-root', + projectConfig: { + name: 'utils', + root: 'root', + }, + }, + ), + ).toEqual(expect.objectContaining({ apiKey: '123456789' })); + }); + + it('should parse process.env options', () => { + processEnvSpy.mockReturnValue(ENV); + expect( + uploadConfig( + {}, + { + workspaceRoot: 'workspaceRoot', + projectConfig: { + name: 'my-app', + root: 'root', + }, + }, + ), + ).toEqual( + expect.objectContaining({ + server: ENV.CP_SERVER, + apiKey: ENV.CP_API_KEY, + organization: ENV.CP_ORGANIZATION, + project: ENV.CP_PROJECT, + timeout: Number(ENV.CP_TIMEOUT), + }), + ); + }); + + it('should options overwrite process.env vars', () => { + expect( + uploadConfig( + { + project: 'my-app2', + }, + { + workspaceRoot: 'workspaceRoot', + projectConfig: { + name: 'my-app', + root: 'root', + }, + }, + ), + ).toEqual(expect.objectContaining({ project: 'my-app2' })); + }); +}); diff --git a/packages/nx-plugin/src/executors/internal/context.ts b/packages/nx-plugin/src/executors/internal/context.ts new file mode 100644 index 000000000..38ca33416 --- /dev/null +++ b/packages/nx-plugin/src/executors/internal/context.ts @@ -0,0 +1,21 @@ +import type { ExecutorContext } from 'nx/src/config/misc-interfaces'; +import type { BaseNormalizedExecutorContext } from './types.js'; + +export type NormalizedExecutorContext = BaseNormalizedExecutorContext & { + projectName: string; +}; + +export function normalizeContext( + context: ExecutorContext, +): NormalizedExecutorContext { + const { + projectName = '', + root: workspaceRoot, + projectsConfigurations, + } = context; + return { + projectName, + projectConfig: projectsConfigurations?.projects[projectName], + workspaceRoot, + }; +} diff --git a/packages/nx-plugin/src/executors/internal/context.unit.test.ts b/packages/nx-plugin/src/executors/internal/context.unit.test.ts new file mode 100644 index 000000000..9be17d2a9 --- /dev/null +++ b/packages/nx-plugin/src/executors/internal/context.unit.test.ts @@ -0,0 +1,28 @@ +import { describe, expect, it } from 'vitest'; +import { normalizeContext } from './context.js'; + +describe('normalizeContext', () => { + it('should normalizeContext', () => { + const normalizedContext = normalizeContext({ + root: './', + projectName: 'my-app', + cwd: 'string', + projectsConfigurations: { + projects: { + 'my-app': { + root: './my-app', + }, + }, + version: 0, + }, + isVerbose: false, + }); + expect(normalizedContext).toEqual({ + projectName: 'my-app', + projectConfig: { + root: './my-app', + }, + workspaceRoot: './', + }); + }); +}); diff --git a/packages/nx-plugin/src/executors/internal/env.ts b/packages/nx-plugin/src/executors/internal/env.ts new file mode 100644 index 000000000..16806a09e --- /dev/null +++ b/packages/nx-plugin/src/executors/internal/env.ts @@ -0,0 +1,37 @@ +import { z } from 'zod'; +import type { UploadConfig } from '@code-pushup/models'; + +// load upload configuration from environment +const envSchema = z + .object({ + CP_SERVER: z.string().url().optional(), + CP_API_KEY: z.string().min(1).optional(), + CP_ORGANIZATION: z.string().min(1).optional(), + CP_PROJECT: z.string().min(1).optional(), + CP_TIMEOUT: z.string().regex(/^\d+$/).optional(), + }) + .partial(); + +type UploadEnvVars = z.infer; + +export function parseEnv(env: unknown = {}): Partial { + const upload: UploadEnvVars = envSchema.parse(env); + return Object.fromEntries( + Object.entries(upload).map(([envKey, value]) => { + switch (envKey) { + case 'CP_SERVER': + return ['server', value]; + case 'CP_API_KEY': + return ['apiKey', value]; + case 'CP_ORGANIZATION': + return ['organization', value]; + case 'CP_PROJECT': + return ['project', value]; + case 'CP_TIMEOUT': + return Number(value) >= 0 ? ['timeout', Number(value)] : []; + default: + return []; + } + }), + ); +} diff --git a/packages/nx-plugin/src/executors/internal/env.unit.test.ts b/packages/nx-plugin/src/executors/internal/env.unit.test.ts new file mode 100644 index 000000000..4f5af94ab --- /dev/null +++ b/packages/nx-plugin/src/executors/internal/env.unit.test.ts @@ -0,0 +1,40 @@ +import { describe, expect } from 'vitest'; +import { parseEnv } from './env.js'; + +describe('parseEnv', () => { + it('should parse empty env vars', () => { + expect(parseEnv({})).toEqual({}); + }); + + it('should parse process.env.CP_SERVER option', () => { + expect(parseEnv({ CP_SERVER: 'https://portal.code.pushup.dev' })).toEqual( + expect.objectContaining({ server: 'https://portal.code.pushup.dev' }), + ); + }); + + it('should parse process.env.CP_ORGANIZATION option', () => { + expect(parseEnv({ CP_ORGANIZATION: 'code-pushup' })).toEqual( + expect.objectContaining({ organization: 'code-pushup' }), + ); + }); + + it('should parse process.env.CP_PROJECT option', () => { + expect(parseEnv({ CP_PROJECT: 'cli-utils' })).toEqual( + expect.objectContaining({ project: 'cli-utils' }), + ); + }); + + it('should parse process.env.CP_TIMEOUT option', () => { + expect(parseEnv({ CP_TIMEOUT: '3' })).toEqual( + expect.objectContaining({ timeout: 3 }), + ); + }); + + it('should throw for process.env.CP_TIMEOUT option < 0', () => { + expect(() => parseEnv({ CP_TIMEOUT: '-1' })).toThrow('Invalid string'); + }); + + it('should throw for invalid URL in process.env.CP_SERVER option', () => { + expect(() => parseEnv({ CP_SERVER: 'httptpt' })).toThrow('Invalid URL'); + }); +}); diff --git a/packages/nx-plugin/src/executors/internal/types.ts b/packages/nx-plugin/src/executors/internal/types.ts new file mode 100644 index 000000000..2f529038a --- /dev/null +++ b/packages/nx-plugin/src/executors/internal/types.ts @@ -0,0 +1,51 @@ +import type { ProjectConfiguration } from 'nx/src/config/workspace-json-project-json'; + +/** + * Types used in the executor only + */ +export type GeneralExecutorOnlyOptions = { + dryRun?: boolean; +}; + +/** + * executor types that apply for a subset of exector's. + * In this case the project related options + * + */ +export type ProjectExecutorOnlyOptions = { + projectPrefix?: string; +}; + +/** + * CLI types that apply globally for all commands. + */ +export type Command = + | 'collect' + | 'upload' + | 'autorun' + | 'print-config' + | 'compare' + | 'merge-diffs' + | 'history'; +export type GlobalExecutorOptions = { + command?: Command; + bin?: string; + verbose?: boolean; + progress?: boolean; + config?: string; +}; + +/** + * CLI types that apply for a subset of commands. + * In this case the collection of data (collect, autorun, history) + */ +export type CollectExecutorOnlyOptions = { + onlyPlugins?: string[]; +}; + +/** + * context that is normalized for all executor's + */ +export type BaseNormalizedExecutorContext = { + projectConfig?: ProjectConfiguration; +} & { workspaceRoot: string }; diff --git a/packages/nx-plugin/src/generators/configuration/README.md b/packages/nx-plugin/src/generators/configuration/README.md new file mode 100644 index 000000000..79ab3ec39 --- /dev/null +++ b/packages/nx-plugin/src/generators/configuration/README.md @@ -0,0 +1,36 @@ +# Configuration Generator + +#### @code-pushup/nx-plugin:configuration + +## Usage + +`nx generate @code-pushup/nx-plugin:configuration` + +By default, the Nx plugin will search for existing configuration files. If they are not present it creates a `code-pushup.config.ts` and adds a target to your `project.json` file. + +You can specify the project explicitly as follows: + +`nx g @code-pushup/nx-plugin:configuration ` + +```text +Root/ +├── project-name/ +│ ├── project.json 👈 updated +│ ├── code-pushup.config.ts 👈 generated +│ └── ... +└── ... +``` + +Show what will be generated without writing to disk: + +`nx g configuration ... --dry-run` + +## Options + +| Name | type | description | +| ----------------- | -------------------------------- | -------------------------------------------------------- | +| **--project** | `string` (REQUIRED) | The name of the project. | +| **--targetName** | `string` (DEFAULT 'code-pushup') | The id used to identify a target in your project.json. | +| **--bin** | `string` | Path to Code PushUp CLI | +| **--skipProject** | `boolean` (DEFAULT false) | Skip adding the target to `project.json`. | +| **--skipConfig** | `boolean` (DEFAULT false) | Skip adding the `code-pushup.config.ts` to project root. | diff --git a/packages/nx-plugin/src/generators/configuration/__snapshots__/root-code-pushup.config.ts b/packages/nx-plugin/src/generators/configuration/__snapshots__/root-code-pushup.config.ts new file mode 100644 index 000000000..eae33ec78 --- /dev/null +++ b/packages/nx-plugin/src/generators/configuration/__snapshots__/root-code-pushup.config.ts @@ -0,0 +1,15 @@ +import type { CoreConfig } from '../dist/packages/models'; +import * as myPlugin from 'my-plugin'; +import { myPluginCategory } from 'my-plugin'; + +// see: https://github.com/code-pushup/cli/blob/main/packages/models/docs/models-reference.md#coreconfig +export default { + persist: { + filename: 'report-123', + }, + upload: { + apiKey: '123', + }, + plugins: [myPlugin({ timeout: 42 })], + categories: [myPluginCategory()], +} satisfies CoreConfig; diff --git a/packages/nx-plugin/src/generators/configuration/code-pushup-config.int.test.ts b/packages/nx-plugin/src/generators/configuration/code-pushup-config.int.test.ts new file mode 100644 index 000000000..38238ff50 --- /dev/null +++ b/packages/nx-plugin/src/generators/configuration/code-pushup-config.int.test.ts @@ -0,0 +1,45 @@ +import * as devKit from '@nx/devkit'; +import { formatFiles } from '@nx/devkit'; +import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; +import * as path from 'node:path'; +import { describe, expect, it } from 'vitest'; +import { generateCodePushupConfig } from './code-pushup-config.js'; + +describe('generateCodePushupConfig options', () => { + let tree: devKit.Tree; + const project = 'test-app'; + const projectRoot = path.join('libs', project); + + beforeEach(() => { + tree = createTreeWithEmptyWorkspace(); + devKit.addProjectConfiguration(tree, project, { + root: 'test-app', + }); + }); + + it('should create code-pushup.config.ts with options in tree', async () => { + generateCodePushupConfig(tree, projectRoot, { + fileImports: 'import type { CoreConfig } from "../dist/packages/models";', + persist: { filename: 'report-123' }, + upload: { apiKey: '123' }, + plugins: [ + { + fileImports: 'import * as myPlugin from "my-plugin";', + codeStrings: 'myPlugin({ timeout: 42})', + }, + ], + categories: [ + { + fileImports: 'import {myPluginCategory} from "my-plugin";', + codeStrings: 'myPluginCategory()', + }, + ], + }); + + await formatFiles(tree); + + expect( + tree.read(path.join(projectRoot, 'code-pushup.config.ts'))?.toString(), + ).toMatchFileSnapshot('__snapshots__/root-code-pushup.config.ts'); + }); +}); diff --git a/packages/nx-plugin/src/generators/configuration/code-pushup-config.ts b/packages/nx-plugin/src/generators/configuration/code-pushup-config.ts new file mode 100644 index 000000000..6854797fb --- /dev/null +++ b/packages/nx-plugin/src/generators/configuration/code-pushup-config.ts @@ -0,0 +1,66 @@ +import { type Tree, generateFiles, logger } from '@nx/devkit'; +import * as path from 'node:path'; +import type { PersistConfig, UploadConfig } from '@code-pushup/models'; +import type { ItemOrArray } from '@code-pushup/utils'; +import type { ExecutableCode } from './types.js'; +import { + formatArrayToLinesOfJsString, + formatObjectToFormattedJsString, + normalizeExecutableCode, + normalizeItemOrArray, +} from './utils.js'; + +export const DEFAULT_IMPORTS = [ + "import type { CoreConfig } from '@code-pushup/models';", +]; + +export type GenerateCodePushupConfigOptions = { + fileImports?: ItemOrArray; + persist?: Partial; + upload?: Partial; + plugins?: ExecutableCode[]; + categories?: ExecutableCode[]; +}; + +export function generateCodePushupConfig( + tree: Tree, + root: string, + options?: GenerateCodePushupConfigOptions, +) { + const supportedFormats = ['ts', 'mjs', 'js']; + const firstExistingFormat = supportedFormats.find(ext => + tree.exists(path.join(root, `code-pushup.config.${ext}`)), + ); + if (firstExistingFormat) { + logger.warn( + `NOTE: No config file created as code-pushup.config.${firstExistingFormat} file already exists.`, + ); + } else { + const { + fileImports: rawImports, + persist, + upload, + plugins: rawPlugins = [], // plugins are required + categories: rawCategories, + } = options ?? {}; + + const plugins = rawPlugins.map(normalizeExecutableCode); + const categories = rawCategories?.map(normalizeExecutableCode); + const configFileImports = [ + ...(rawImports ? normalizeItemOrArray(rawImports) : DEFAULT_IMPORTS), + ...plugins.flatMap(({ fileImports }) => fileImports), + ...(categories ?? []).flatMap(({ fileImports }) => fileImports), + ]; + + generateFiles(tree, path.join(__dirname, 'files'), root, { + ...options, + fileImports: formatArrayToLinesOfJsString(configFileImports), + persist: formatObjectToFormattedJsString(persist), + upload: formatObjectToFormattedJsString(upload), + plugins: `[${plugins.map(({ codeStrings }) => codeStrings).join(',')}]`, + categories: + categories && + `[${categories.map(({ codeStrings }) => codeStrings).join(',')}]`, + }); + } +} diff --git a/packages/nx-plugin/src/generators/configuration/code-pushup-config.unit.test.ts b/packages/nx-plugin/src/generators/configuration/code-pushup-config.unit.test.ts new file mode 100644 index 000000000..4cd74d681 --- /dev/null +++ b/packages/nx-plugin/src/generators/configuration/code-pushup-config.unit.test.ts @@ -0,0 +1,289 @@ +import * as devKit from '@nx/devkit'; +import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; +import * as path from 'node:path'; +import { afterEach, describe, expect, it } from 'vitest'; +import { removeColorCodes } from '@code-pushup/test-utils'; +import { + DEFAULT_IMPORTS, + generateCodePushupConfig, +} from './code-pushup-config.js'; +import { + formatArrayToJSArray, + formatArrayToLinesOfJsString, + formatObjectToFormattedJsString, + normalizeExecutableCode, +} from './utils.js'; + +describe('generateCodePushupConfig options', () => { + let tree: devKit.Tree; + const testProjectName = 'test-app'; + const generateFilesSpy = vi.spyOn(devKit, 'generateFiles'); + const loggerWarnSpy = vi.spyOn(devKit.logger, 'warn'); + + beforeEach(() => { + tree = createTreeWithEmptyWorkspace(); + devKit.addProjectConfiguration(tree, testProjectName, { + root: 'test-app', + }); + }); + + afterEach(() => { + generateFilesSpy.mockReset(); + }); + + it('should create code-pushup.config.ts with options', () => { + generateCodePushupConfig(tree, testProjectName, { + fileImports: ["import type { CoreConfig } from 'dist/packages/models';"], + persist: { filename: 'report-123' }, + upload: { apiKey: '123' }, + plugins: [ + { + fileImports: "import * as myPlugin from 'my-plugin';", + codeStrings: 'myPlugin({ timeout: 42})', + }, + ], + categories: [ + { + fileImports: "import {myPluginCategory} from 'my-plugin';", + codeStrings: 'myPluginCategory()', + }, + ], + }); + + expect(generateFilesSpy).toHaveBeenCalledWith( + expect.anything(), + expect.any(String), + expect.any(String), + expect.objectContaining({ + fileImports: formatArrayToLinesOfJsString([ + 'import type { CoreConfig } from "dist/packages/models";', + 'import * as myPlugin from "my-plugin";', + 'import {myPluginCategory} from "my-plugin";', + ]), + persist: formatObjectToFormattedJsString({ filename: 'report-123' }), + upload: formatObjectToFormattedJsString({ apiKey: '123' }), + plugins: formatArrayToJSArray(['myPlugin({ timeout: 42})']), + categories: formatArrayToJSArray(['myPluginCategory()']), + }), + ); + }); + + it('should call generateFilesSpy', () => { + generateCodePushupConfig(tree, testProjectName); + expect(generateFilesSpy).toHaveBeenCalledTimes(1); + }); + + it('should skip creation if config already exists', () => { + tree.write(path.join(testProjectName, 'code-pushup.config.js'), ''); + generateCodePushupConfig(tree, testProjectName); + expect(generateFilesSpy).toHaveBeenCalledTimes(0); + expect(loggerWarnSpy).toHaveBeenCalledTimes(1); + expect(loggerWarnSpy).toHaveBeenCalledWith( + removeColorCodes( + 'NOTE: No config file created as code-pushup.config.js file already exists.', + ), + ); + }); + + it('should use correct templates', () => { + generateCodePushupConfig(tree, testProjectName); + expect(generateFilesSpy).toHaveBeenCalledWith( + expect.anything(), + expect.stringContaining( + path.join('nx-plugin', 'src', 'generators', 'configuration', 'files'), + ), + expect.any(String), + expect.any(Object), + ); + }); + + it('should use correct testProjectName', () => { + generateCodePushupConfig(tree, testProjectName); + expect(generateFilesSpy).toHaveBeenCalledWith( + expect.anything(), + expect.any(String), + testProjectName, + expect.any(Object), + ); + }); + + it('should use default options', () => { + generateCodePushupConfig(tree, testProjectName); + expect(generateFilesSpy).toHaveBeenCalledWith( + expect.anything(), + expect.any(String), + expect.any(String), + { + categories: undefined, + fileImports: formatArrayToLinesOfJsString(DEFAULT_IMPORTS), + persist: undefined, + plugins: formatArrayToJSArray([]), + upload: undefined, + }, + ); + }); + + it('should use fileImports options', () => { + generateCodePushupConfig(tree, testProjectName, { + fileImports: [ + "import type { CoreConfig } from '../../dist/packages/models.js';", + ], + }); + expect(generateFilesSpy).toHaveBeenCalledWith( + expect.anything(), + expect.any(String), + expect.any(String), + expect.objectContaining({ + fileImports: formatArrayToLinesOfJsString([ + 'import type { CoreConfig } from "../../dist/packages/models.js";', + ]), + }), + ); + }); + + it('should use persist options', () => { + generateCodePushupConfig(tree, testProjectName, { + persist: { + filename: 'test-report', + outputDir: 'tmp/results', + format: ['md'], + }, + }); + expect(generateFilesSpy).toHaveBeenCalledWith( + expect.anything(), + expect.any(String), + expect.any(String), + expect.objectContaining({ + persist: formatObjectToFormattedJsString({ + filename: 'test-report', + outputDir: 'tmp/results', + format: ['md'], + }), + }), + ); + }); + + it('should use upload options', () => { + generateCodePushupConfig(tree, testProjectName, { + upload: { + organization: 'code-pushup', + project: 'cli', + server: 'https://api.staging.code-pushup.dev/graphql', + apiKey: 'cp_12345678', + }, + }); + expect(generateFilesSpy).toHaveBeenCalledWith( + expect.anything(), + expect.any(String), + expect.any(String), + expect.objectContaining({ + upload: formatObjectToFormattedJsString({ + organization: 'code-pushup', + project: 'cli', + server: 'https://api.staging.code-pushup.dev/graphql', + apiKey: 'cp_12345678', + }), + }), + ); + }); + + it('should use plugins options', () => { + generateCodePushupConfig(tree, testProjectName, { + plugins: [ + { + fileImports: 'import * as myPlugin from "my-import";', + codeStrings: 'myPlugin({ timeout: 42})', + }, + ], + }); + expect(generateFilesSpy).toHaveBeenCalledWith( + expect.anything(), + expect.any(String), + expect.any(String), + expect.objectContaining({ + fileImports: formatArrayToLinesOfJsString([ + ...DEFAULT_IMPORTS, + 'import * as myPlugin from "my-import";', + ]), + plugins: formatArrayToJSArray(['myPlugin({ timeout: 42})']), + }), + ); + }); + + it('should use categories options', () => { + generateCodePushupConfig(tree, testProjectName, { + categories: [ + { + fileImports: 'import {defaultCategory} from "my-plugin";', + codeStrings: 'defaultCategory()', + }, + ], + }); + expect(generateFilesSpy).toHaveBeenCalledWith( + expect.anything(), + expect.any(String), + expect.any(String), + expect.objectContaining({ + fileImports: formatArrayToLinesOfJsString([ + ...DEFAULT_IMPORTS, + 'import {defaultCategory} from "my-plugin";', + ]), + categories: formatArrayToJSArray(['defaultCategory()']), + }), + ); + }); +}); + +describe('normalizeExecutableCode', () => { + it('should normalize fileImports as string', () => { + expect( + normalizeExecutableCode({ + fileImports: 'import * as test from "test"', + codeStrings: 'plugin()', + }), + ).toStrictEqual( + expect.objectContaining({ + fileImports: ['import * as test from "test"'], + }), + ); + }); + + it('should normalize fileImports as array', () => { + expect( + normalizeExecutableCode({ + fileImports: ['import * as test from "test"'], + codeStrings: 'plugin()', + }), + ).toStrictEqual( + expect.objectContaining({ + fileImports: ['import * as test from "test"'], + }), + ); + }); + + it('should normalize codeStrings as string', () => { + expect( + normalizeExecutableCode({ + fileImports: 'import * as test from "test"', + codeStrings: 'plugin()', + }), + ).toStrictEqual( + expect.objectContaining({ + codeStrings: ['plugin()'], + }), + ); + }); + + it('should normalize codeStrings as array', () => { + expect( + normalizeExecutableCode({ + fileImports: 'import * as test from "test"', + codeStrings: ['plugin()'], + }), + ).toStrictEqual( + expect.objectContaining({ + codeStrings: ['plugin()'], + }), + ); + }); +}); diff --git a/packages/nx-plugin/src/generators/configuration/files/code-pushup.config.ts.template b/packages/nx-plugin/src/generators/configuration/files/code-pushup.config.ts.template new file mode 100644 index 000000000..b354d3764 --- /dev/null +++ b/packages/nx-plugin/src/generators/configuration/files/code-pushup.config.ts.template @@ -0,0 +1,9 @@ +<%- fileImports %> + +// see: https://github.com/code-pushup/cli/blob/main/packages/models/docs/models-reference.md#coreconfig +export default { + <% if (persist) { %>persist: <%- persist %>,<% } %> + <% if (upload) { %>upload: <%- upload %>,<% } %> + <% if (plugins) { %>plugins: <%- plugins %>,<% } %> + <% if (categories) { %>categories: <%- categories %><% } %> +} satisfies CoreConfig; diff --git a/packages/nx-plugin/src/generators/configuration/generator.int.test.ts b/packages/nx-plugin/src/generators/configuration/generator.int.test.ts new file mode 100644 index 000000000..c98d60064 --- /dev/null +++ b/packages/nx-plugin/src/generators/configuration/generator.int.test.ts @@ -0,0 +1,145 @@ +import { + type Tree, + addProjectConfiguration, + logger, + readProjectConfiguration, +} from '@nx/devkit'; +import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; +import * as path from 'node:path'; +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { DEFAULT_TARGET_NAME, PACKAGE_NAME } from '../../internal/constants.js'; +import { addTargetToProject, configurationGenerator } from './generator.js'; + +describe('addTargetToProject', () => { + let tree: Tree; + const testProjectName = 'test-app'; + + beforeEach(() => { + tree = createTreeWithEmptyWorkspace(); + addProjectConfiguration(tree, 'test-app', { + root: 'test-app', + }); + }); + + afterEach(() => { + //reset tree + tree.delete(testProjectName); + }); + + it('should generate a project target', () => { + addTargetToProject( + tree, + { + root: testProjectName, + projectType: 'library', + sourceRoot: `${testProjectName}/src`, + targets: {}, + }, + { + project: testProjectName, + }, + ); + + const projectConfiguration = readProjectConfiguration( + tree, + testProjectName, + ); + + expect(projectConfiguration.targets?.[DEFAULT_TARGET_NAME]).toEqual({ + executor: `${PACKAGE_NAME}:cli`, + }); + }); + + it('should use targetName to generate a project target', () => { + addTargetToProject( + tree, + { + root: testProjectName, + projectType: 'library', + sourceRoot: `${testProjectName}/src`, + targets: {}, + }, + { + project: testProjectName, + targetName: 'cp', + }, + ); + + const projectConfiguration = readProjectConfiguration( + tree, + testProjectName, + ); + + expect(projectConfiguration.targets?.['cp']).toEqual({ + executor: `${PACKAGE_NAME}:cli`, + }); + }); +}); + +describe('configurationGenerator', () => { + let tree: Tree; + const testProjectName = 'test-app'; + const loggerInfoSpy = vi.spyOn(logger, 'info'); + + beforeEach(() => { + tree = createTreeWithEmptyWorkspace(); + addProjectConfiguration(tree, 'test-app', { + root: 'test-app', + }); + }); + + afterEach(() => { + tree.delete(testProjectName); + }); + + it('should generate a project target and config file', async () => { + await configurationGenerator(tree, { + project: testProjectName, + }); + + const projectConfiguration = readProjectConfiguration( + tree, + testProjectName, + ); + + expect(projectConfiguration.targets?.[DEFAULT_TARGET_NAME]).toEqual({ + executor: `${PACKAGE_NAME}:cli`, + }); + }); + + it('should skip config creation if skipConfig is used', async () => { + await configurationGenerator(tree, { + project: testProjectName, + skipConfig: true, + }); + + readProjectConfiguration(tree, testProjectName); + + expect( + tree.read(path.join('libs', testProjectName, 'code-pushup.config.ts')), + ).toBeNull(); + expect(loggerInfoSpy).toHaveBeenCalledWith('Skip config file creation'); + }); + + it('should skip target creation if skipTarget is used', async () => { + await configurationGenerator(tree, { + project: testProjectName, + skipTarget: true, + }); + + const projectConfiguration = readProjectConfiguration( + tree, + testProjectName, + ); + expect(projectConfiguration.targets).toBeUndefined(); + expect(loggerInfoSpy).toHaveBeenCalledWith('Skip adding target to project'); + }); + + it('should skip formatting', async () => { + await configurationGenerator(tree, { + project: testProjectName, + skipFormat: true, + }); + expect(loggerInfoSpy).toHaveBeenCalledWith('Skip formatting files'); + }); +}); diff --git a/packages/nx-plugin/src/generators/configuration/generator.ts b/packages/nx-plugin/src/generators/configuration/generator.ts new file mode 100644 index 000000000..4b71b60a2 --- /dev/null +++ b/packages/nx-plugin/src/generators/configuration/generator.ts @@ -0,0 +1,61 @@ +import { + type Tree, + formatFiles, + logger, + readProjectConfiguration, + updateProjectConfiguration, +} from '@nx/devkit'; +import type { ProjectConfiguration } from 'nx/src/config/workspace-json-project-json'; +import { DEFAULT_TARGET_NAME, PACKAGE_NAME } from '../../internal/constants.js'; +import { generateCodePushupConfig } from './code-pushup-config.js'; +import type { ConfigurationGeneratorOptions } from './schema.js'; + +export async function configurationGenerator( + tree: Tree, + options: ConfigurationGeneratorOptions, +) { + const projectConfiguration = readProjectConfiguration(tree, options.project); + + const { skipConfig, skipTarget, skipFormat } = options; + + if (skipConfig === true) { + logger.info('Skip config file creation'); + } else { + generateCodePushupConfig(tree, projectConfiguration.root); + } + + if (skipTarget === true) { + logger.info('Skip adding target to project'); + } else { + addTargetToProject(tree, projectConfiguration, options); + } + + if (skipFormat === true) { + logger.info('Skip formatting files'); + } else { + await formatFiles(tree); + } +} + +export function addTargetToProject( + tree: Tree, + projectConfiguration: ProjectConfiguration, + options: ConfigurationGeneratorOptions, +) { + const { targets } = projectConfiguration; + const { targetName, project } = options; + + const codePushupTargetConfig = { + executor: `${PACKAGE_NAME}:cli`, + }; + + updateProjectConfiguration(tree, project, { + ...projectConfiguration, + targets: { + ...targets, + [targetName ?? DEFAULT_TARGET_NAME]: codePushupTargetConfig, + }, + }); +} + +export default configurationGenerator; diff --git a/packages/nx-plugin/src/generators/configuration/schema.d.ts b/packages/nx-plugin/src/generators/configuration/schema.d.ts new file mode 100644 index 000000000..b105270c6 --- /dev/null +++ b/packages/nx-plugin/src/generators/configuration/schema.d.ts @@ -0,0 +1,9 @@ +import type { DynamicTargetOptions } from '../../internal/types.js'; + +export type ConfigurationGeneratorOptions = { + project: string; + bin?: string; + skipTarget?: boolean; + skipConfig?: boolean; + skipFormat?: boolean; +} & DynamicTargetOptions; diff --git a/packages/nx-plugin/src/generators/configuration/schema.json b/packages/nx-plugin/src/generators/configuration/schema.json new file mode 100644 index 000000000..7098daca2 --- /dev/null +++ b/packages/nx-plugin/src/generators/configuration/schema.json @@ -0,0 +1,45 @@ +{ + "$schema": "http://json-schema.org/schema", + "$id": "AddConfigurationToProject", + "title": "Add CodePushup configuration to a project", + "description": "Add CodePushup configuration to a project", + "type": "object", + "properties": { + "project": { + "type": "string", + "description": "The name of the project.", + "x-prompt": "Which project should configure Code Pushup?", + "x-dropdown": "projects", + "$default": { + "$source": "argv", + "index": 0 + } + }, + "targetName": { + "type": "string", + "description": "The name of the target.", + "x-prompt": "Which name should the target get? default is code-pushup.", + "default": "code-pushup" + }, + "bin": { + "type": "string", + "description": "Path to Code PushUp CLI" + }, + "skipTarget": { + "type": "boolean", + "description": "Skip adding the target to project.json.", + "$default": "false" + }, + "skipConfig": { + "type": "boolean", + "description": "Skip adding the code-pushup.config.ts to the project root.", + "$default": "false" + }, + "skipFormat": { + "type": "boolean", + "description": "Skip formatting of changed files", + "$default": "false" + } + }, + "required": ["project"] +} diff --git a/packages/nx-plugin/src/generators/configuration/types.ts b/packages/nx-plugin/src/generators/configuration/types.ts new file mode 100644 index 000000000..99451ced8 --- /dev/null +++ b/packages/nx-plugin/src/generators/configuration/types.ts @@ -0,0 +1,6 @@ +import type { ItemOrArray } from '@code-pushup/utils'; + +export type ExecutableCode = { + fileImports: ItemOrArray; + codeStrings: ItemOrArray; +}; diff --git a/packages/nx-plugin/src/generators/configuration/utils.ts b/packages/nx-plugin/src/generators/configuration/utils.ts new file mode 100644 index 000000000..36464358a --- /dev/null +++ b/packages/nx-plugin/src/generators/configuration/utils.ts @@ -0,0 +1,66 @@ +import type { ExtractArrays } from '@code-pushup/utils'; +import type { ExecutableCode } from './types.js'; + +export function normalizeExecutableCode( + executableCode: ExecutableCode, +): ExtractArrays { + const { fileImports: rawFileImports, codeStrings: rawCodeStrings } = + executableCode; + + return { + fileImports: normalizeItemOrArray(rawFileImports), + codeStrings: normalizeItemOrArray(rawCodeStrings), + }; +} + +export function normalizeItemOrArray(itemOrArray: T | T[]): T[]; +export function normalizeItemOrArray( + itemOrArray: T | T[] | undefined, +): T[] | undefined { + if (itemOrArray == null) { + return undefined; + } + if (Array.isArray(itemOrArray)) { + return itemOrArray; + } + return [itemOrArray]; +} + +// Return a formatted JSON in TS object with the same keys as the input object but remove the " for the properties +export function formatObjectToFormattedJsString( + jsonObj?: + | { + [key: string]: unknown; + } + | unknown[], +): string | undefined { + if (!jsonObj) { + return; + } + // Convert JSON object to a string with indentation + const jsonString = JSON.stringify(jsonObj, null, 2); + + // Remove double quotes around property names + return jsonString.replace(/"(\w+)":/g, '$1:'); +} + +export function formatArrayToLinesOfJsString( + lines?: string[], + separator = '\n', +) { + if (lines == null || lines.length === 0) { + return; + } + return lines.join(separator).replace(/'/g, '"'); +} + +export function formatArrayToJSArray(lines?: string[]) { + if (!Array.isArray(lines)) { + return; + } + + return `[${formatArrayToLinesOfJsString(lines, ',\n') ?? ''}]`.replace( + /"/g, + '', + ); +} diff --git a/packages/nx-plugin/src/generators/configuration/utils.unit.test.ts b/packages/nx-plugin/src/generators/configuration/utils.unit.test.ts new file mode 100644 index 000000000..3a140c8ff --- /dev/null +++ b/packages/nx-plugin/src/generators/configuration/utils.unit.test.ts @@ -0,0 +1,98 @@ +import { describe, expect, it } from 'vitest'; +import { + formatArrayToJSArray, + formatArrayToLinesOfJsString, + normalizeExecutableCode, + normalizeItemOrArray, +} from './utils.js'; + +describe('formatArrayToJSArray', () => { + it('should return array as JS', () => { + expect( + formatArrayToJSArray(['plugin1()', 'plugin2()']), + ).toMatchInlineSnapshot( + ` + "[plugin1(), + plugin2()]" + `, + ); + }); + + it('should return empty array as JS for empty items', () => { + expect(formatArrayToJSArray([])).toMatchInlineSnapshot('"[]"'); + }); + + it('should return undefined for undefined values', () => { + expect(formatArrayToJSArray(undefined)).toBeUndefined(); + }); +}); + +describe('formatArrayToLinesOfJsString', () => { + it('should return lines as JS', () => { + expect( + formatArrayToLinesOfJsString([`import plugin from "../mx-plugin";`]), + ).toMatchInlineSnapshot( + ` + "import plugin from "../mx-plugin";" + `, + ); + }); + + it('should return lines as JS with normalized quotes', () => { + expect( + formatArrayToLinesOfJsString([ + `import { CoreConfig } from '@code-pushup/models';`, + `import plugin from "../mx-plugin";`, + ]), + ).toMatchInlineSnapshot( + ` + "import { CoreConfig } from "@code-pushup/models"; + import plugin from "../mx-plugin";" + `, + ); + }); + + it('should return undefined for empty items', () => { + expect(formatArrayToLinesOfJsString([])).toBeUndefined(); + }); + + it('should return undefined for nullish values', () => { + expect(formatArrayToLinesOfJsString()).toBeUndefined(); + }); +}); + +describe('normalizeExecutableCode', () => { + it('should turn strings into arrays', () => { + expect( + normalizeExecutableCode({ + fileImports: 'import { CoreConfig } from "@code-pushup/models";', + codeStrings: 'myPlugin()', + }), + ).toStrictEqual({ + fileImports: ['import { CoreConfig } from "@code-pushup/models";'], + codeStrings: ['myPlugin()'], + }); + }); + + it('should keep arrays', () => { + expect( + normalizeExecutableCode({ + fileImports: ['import { CoreConfig } from "@code-pushup/models";'], + codeStrings: ['myPlugin()'], + }), + ).toStrictEqual({ + fileImports: ['import { CoreConfig } from "@code-pushup/models";'], + codeStrings: ['myPlugin()'], + }); + }); +}); + +describe('normalizeItemOrArray', () => { + it('should turn string into string array', () => { + expect(normalizeItemOrArray('myPlugin()')).toStrictEqual(['myPlugin()']); + }); + + it('should keep string array', () => { + expect(normalizeItemOrArray('myPlugin()')).toStrictEqual(['myPlugin()']); + }); +}); diff --git a/packages/nx-plugin/src/generators/init/README.md b/packages/nx-plugin/src/generators/init/README.md new file mode 100644 index 000000000..c4bfa4573 --- /dev/null +++ b/packages/nx-plugin/src/generators/init/README.md @@ -0,0 +1,32 @@ +# Init Generator + +#### @code-pushup/nx-plugin:init + +## Usage + +`nx generate @code-pushup/nx-plugin:init` + +By default, the Nx plugin will update your `package.json` with needed dependencies and register the plugin in your `nx.json` configuration. + +You can specify the collection explicitly as follows: + +`nx g @code-pushup/nx-plugin:init` + +```text +Root/ +├── ... +├── nx.json 👈 updated +├── package.json 👈 updated +└── ... +``` + +Show what will be generated without writing to disk: + +`nx g @code-pushup/nx-plugin:init --dry-run` + +## Options + +| Name | type | description | +| --------------------- | --------------------------- | ------------------------------------------- | +| **--skipPackageJson** | `boolean` (DEFAULT `false`) | Skip adding `package.json` dependencies. | +| **--skipNxJson** | `boolean` (DEFAULT `false`) | Skip updating `nx.json` with configuration. | diff --git a/packages/nx-plugin/src/generators/init/generator.int.test.ts b/packages/nx-plugin/src/generators/init/generator.int.test.ts new file mode 100644 index 000000000..5ab890bd1 --- /dev/null +++ b/packages/nx-plugin/src/generators/init/generator.int.test.ts @@ -0,0 +1,89 @@ +import { type Tree, logger, readJson, readNxJson } from '@nx/devkit'; +import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; +import { describe, expect, it, vi } from 'vitest'; +import { initGenerator } from './generator.js'; + +type PackageJson = { + devDependencies: Record; +}; + +const cpTargetName = 'code-pushup'; + +const devDependencyNames = [ + '@code-pushup/cli', + '@code-pushup/models', + '@code-pushup/nx-plugin', + '@code-pushup/utils', +]; + +describe('init generator', () => { + let tree: Tree; + const loggerInfoSpy = vi.spyOn(logger, 'info'); + + beforeEach(() => { + tree = createTreeWithEmptyWorkspace(); + }); + + it('should run successfully', () => { + initGenerator(tree, {}); + // nx.json + const targetDefaults = readNxJson(tree)!.targetDefaults!; + expect(targetDefaults).toHaveProperty(cpTargetName); + expect(targetDefaults[cpTargetName]).toEqual({ + inputs: ['default', '^production'], + cache: true, + }); + // package.json + const pkgJson = readJson(tree, 'package.json'); + expect( + Object.keys(pkgJson.devDependencies).filter(dep => + devDependencyNames.includes(dep), + ), + ).toHaveLength(devDependencyNames.length); + }); + + it('should skip package.json', () => { + initGenerator(tree, { skipPackageJson: true }); + // nx.json + const targetDefaults = readNxJson(tree)!.targetDefaults!; + expect(targetDefaults).toHaveProperty(cpTargetName); + expect(targetDefaults[cpTargetName]).toEqual({ + inputs: ['default', '^production'], + cache: true, + }); + // package.json + const pkgJson = readJson(tree, 'package.json'); + expect( + Object.keys(pkgJson.devDependencies).filter(dep => + devDependencyNames.includes(dep), + ), + ).toHaveLength(0); + expect(loggerInfoSpy).toHaveBeenCalledWith('Skip updating package.json'); + }); + + it('should skip package installation', () => { + initGenerator(tree, { skipInstall: true }); + // nx.json + const targetDefaults = readNxJson(tree)!.targetDefaults!; + expect(targetDefaults).toHaveProperty(cpTargetName); + expect(targetDefaults[cpTargetName]).toEqual({ + inputs: ['default', '^production'], + cache: true, + }); + // package.json + const pkgJson = readJson(tree, 'package.json'); + expect( + Object.keys(pkgJson.devDependencies).filter(dep => + devDependencyNames.includes(dep), + ), + ).toHaveLength(4); + expect(loggerInfoSpy).toHaveBeenCalledWith('Skip installing packages'); + }); + + it('should skip nx.json', () => { + initGenerator(tree, { skipNxJson: true }); + // nx.json + const targetDefaults = readNxJson(tree)!.targetDefaults!; + expect(targetDefaults).not.toHaveProperty(cpTargetName); + }); +}); diff --git a/packages/nx-plugin/src/generators/init/generator.ts b/packages/nx-plugin/src/generators/init/generator.ts new file mode 100644 index 000000000..265298fb0 --- /dev/null +++ b/packages/nx-plugin/src/generators/init/generator.ts @@ -0,0 +1,101 @@ +/* eslint-disable functional/immutable-data */ +import { + type NxJsonConfiguration, + type Tree, + addDependenciesToPackageJson, + convertNxGenerator, + logger, + readJson, + readNxJson, + runTasksInSerial, + updateJson, + updateNxJson, +} from '@nx/devkit'; +import type { PackageJson } from 'nx/src/utils/package-json'; +import { PACKAGE_NAME } from '../../internal/constants.js'; +import { + cpCliVersion, + cpModelVersion, + cpNxPluginVersion, + cpUtilsVersion, +} from '../../internal/versions.js'; +import type { InitGeneratorSchema } from './schema.js'; + +function checkDependenciesInstalled(host: Tree) { + const packageJson = readJson(host, 'package.json'); + const devDependencies: Record = {}; + const dependencies = {}; + packageJson.dependencies = packageJson.dependencies ?? {}; + packageJson.devDependencies = packageJson.devDependencies ?? {}; + + // base deps + devDependencies[PACKAGE_NAME] = cpNxPluginVersion; + devDependencies['@code-pushup/models'] = cpModelVersion; + devDependencies['@code-pushup/utils'] = cpUtilsVersion; + devDependencies['@code-pushup/cli'] = cpCliVersion; + + return addDependenciesToPackageJson(host, dependencies, devDependencies); +} + +function moveToDevDependencies(tree: Tree) { + updateJson(tree, 'package.json', (packageJson: PackageJson) => { + const newPackageJson: PackageJson = { + dependencies: {}, + devDependencies: {}, + ...packageJson, + }; + + if (newPackageJson.dependencies?.[PACKAGE_NAME] !== undefined) { + const { [PACKAGE_NAME]: version, ...dependencies } = + newPackageJson.dependencies; + return { + ...newPackageJson, + dependencies, + devDependencies: { + ...newPackageJson.devDependencies, + [PACKAGE_NAME]: version, + }, + }; + } + return newPackageJson; + }); +} + +function updateNxJsonConfig(tree: Tree) { + const nxJson: NxJsonConfiguration = readNxJson(tree) as NxJsonConfiguration; + + const targetName = 'code-pushup'; + + nxJson.targetDefaults ??= {}; + nxJson.targetDefaults[targetName] = { + inputs: ['default', '^production'], + cache: true, + }; + + updateNxJson(tree, nxJson); +} + +export function initGenerator(tree: Tree, schema: InitGeneratorSchema) { + if (schema.skipNxJson) { + logger.info(`Skip updating nx.json`); + } else { + updateNxJsonConfig(tree); + } + + const tasks = []; + if (schema.skipPackageJson) { + logger.info(`Skip updating package.json`); + } else { + moveToDevDependencies(tree); + const installDependencies = checkDependenciesInstalled(tree); + if (schema.skipInstall) { + logger.info(`Skip installing packages`); + } else { + tasks.push(installDependencies); + } + } + return runTasksInSerial(...tasks); +} + +export default initGenerator; +export const initSchematic = convertNxGenerator(initGenerator); diff --git a/packages/nx-plugin/src/generators/init/schema.d.ts b/packages/nx-plugin/src/generators/init/schema.d.ts new file mode 100644 index 000000000..40650a8d5 --- /dev/null +++ b/packages/nx-plugin/src/generators/init/schema.d.ts @@ -0,0 +1,5 @@ +export type InitGeneratorSchema = { + skipPackageJson?: boolean; + skipInstall?: boolean; + skipNxJson?: boolean; +}; diff --git a/packages/nx-plugin/src/generators/init/schema.json b/packages/nx-plugin/src/generators/init/schema.json new file mode 100644 index 000000000..8f7dbc0d0 --- /dev/null +++ b/packages/nx-plugin/src/generators/init/schema.json @@ -0,0 +1,23 @@ +{ + "cli": "nx", + "title": "Initialize Code Pushup in the workspace.", + "description": "Initialize Code Pushup in the workspace.", + "$id": "init-code-pushup-plugin", + "type": "object", + "properties": { + "skipPackageJson": { + "type": "boolean", + "description": "Skip adding package.json dependencies", + "x-priority": "internal" + }, + "skipInstall": { + "type": "boolean", + "description": "Skip package installation", + "x-priority": "internal" + }, + "skipNxJson": { + "type": "boolean", + "description": "Skip updating nx.json with configuration" + } + } +} diff --git a/packages/nx-plugin/src/index.ts b/packages/nx-plugin/src/index.ts new file mode 100644 index 000000000..e516b18ce --- /dev/null +++ b/packages/nx-plugin/src/index.ts @@ -0,0 +1,18 @@ +import { createNodes } from './plugin/index.js'; + +// default export for nx.json#plugins +export default createNodes; + +export type { AutorunCommandExecutorOptions } from './executors/cli/schema.js'; +export { objectToCliArgs } from './executors/internal/cli.js'; +export { generateCodePushupConfig } from './generators/configuration/code-pushup-config.js'; +export { configurationGenerator } from './generators/configuration/generator.js'; +export type { ConfigurationGeneratorOptions } from './generators/configuration/schema.js'; +export { initGenerator, initSchematic } from './generators/init/generator.js'; +export { type InitGeneratorSchema } from './generators/init/schema.js'; +export { + executeProcess, + type ProcessConfig, +} from './internal/execute-process.js'; +export * from './internal/versions.js'; +export { createNodes } from './plugin/index.js'; diff --git a/packages/nx-plugin/src/internal/constants.ts b/packages/nx-plugin/src/internal/constants.ts new file mode 100644 index 000000000..f69356ea3 --- /dev/null +++ b/packages/nx-plugin/src/internal/constants.ts @@ -0,0 +1,4 @@ +export const PROJECT_JSON_FILE_NAME = 'project.json'; +export const CODE_PUSHUP_CONFIG_REGEX = /^code-pushup(?:\.[\w-]+)?\.ts$/; +export const PACKAGE_NAME = '@code-pushup/nx-plugin'; +export const DEFAULT_TARGET_NAME = 'code-pushup'; diff --git a/packages/nx-plugin/src/internal/execute-process.ts b/packages/nx-plugin/src/internal/execute-process.ts new file mode 100644 index 000000000..cf61f3e84 --- /dev/null +++ b/packages/nx-plugin/src/internal/execute-process.ts @@ -0,0 +1,186 @@ +import { gray } from 'ansis'; +import { spawn } from 'node:child_process'; +import { ui } from '@code-pushup/utils'; + +export function calcDuration(start: number, stop?: number): number { + return Math.round((stop ?? performance.now()) - start); +} + +/** + * Represents the process result. + * @category Types + * @public + * @property {string} stdout - The stdout of the process. + * @property {string} stderr - The stderr of the process. + * @property {number | null} code - The exit code of the process. + */ +export type ProcessResult = { + stdout: string; + stderr: string; + code: number | null; + date: string; + duration: number; +}; + +/** + * Error class for process errors. + * Contains additional information about the process result. + * @category Error + * @public + * @class + * @extends Error + * @example + * const result = await executeProcess({}) + * .catch((error) => { + * if (error instanceof ProcessError) { + * console.error(error.code); + * console.error(error.stderr); + * console.error(error.stdout); + * } + * }); + * + */ +export class ProcessError extends Error { + code: number | null; + stderr: string; + stdout: string; + + constructor(result: ProcessResult) { + super(result.stderr); + this.code = result.code; + this.stderr = result.stderr; + this.stdout = result.stdout; + } +} + +/** + * Process config object. Contains the command, args and observer. + * @param cfg - process config object with command, args and observer (optional) + * @category Types + * @public + * @property {string} command - The command to execute. + * @property {string[]} args - The arguments for the command. + * @property {ProcessObserver} observer - The observer for the process. + * + * @example + * + * // bash command + * const cfg = { + * command: 'bash', + * args: ['-c', 'echo "hello world"'] + * }; + * + * // node command + * const cfg = { + * command: 'node', + * args: ['--version'] + * }; + * + * // npx command + * const cfg = { + * command: 'npx', + * args: ['--version'] + * + */ +export type ProcessConfig = { + command: string; + args?: string[]; + cwd?: string; + observer?: ProcessObserver; + ignoreExitCode?: boolean; +}; + +/** + * Process observer object. Contains the onStdout, error and complete function. + * @category Types + * @public + * @property {function} onStdout - The onStdout function of the observer (optional). + * @property {function} onError - The error function of the observer (optional). + * @property {function} onComplete - The complete function of the observer (optional). + * + * @example + * const observer = { + * onStdout: (stdout) => console.info(stdout) + * } + */ +export type ProcessObserver = { + onStdout?: (stdout: string) => void; + onError?: (error: ProcessError) => void; + onComplete?: () => void; +}; + +/** + * Executes a process and returns a promise with the result as `ProcessResult`. + * + * @example + * + * // sync process execution + * const result = await executeProcess({ + * command: 'node', + * args: ['--version'] + * }); + * + * console.info(result); + * + * // async process execution + * const result = await executeProcess({ + * command: 'node', + * args: ['download-data'], + * observer: { + * onStdout: updateProgress, + * error: handleError, + * complete: cleanLogs, + * } + * }); + * + * console.info(result); + * + * @param cfg - see {@link ProcessConfig} + */ +export function executeProcess(cfg: ProcessConfig): Promise { + const { observer, cwd, command, args, ignoreExitCode = false } = cfg; + const { onStdout, onError, onComplete } = observer ?? {}; + const date = new Date().toISOString(); + const start = performance.now(); + + const logCommand = [command, ...(args || [])].join(' '); + ui().logger.log( + gray( + `Executing command:\n${logCommand}\nIn working directory:\n${cfg.cwd ?? process.cwd()}`, + ), + ); + + return new Promise((resolve, reject) => { + // shell:true tells Windows to use shell command for spawning a child process + const process = spawn(command, args, { cwd, shell: true }); + // eslint-disable-next-line functional/no-let + let stdout = ''; + // eslint-disable-next-line functional/no-let + let stderr = ''; + + process.stdout.on('data', data => { + stdout += String(data); + onStdout?.(String(data)); + }); + + process.stderr.on('data', data => { + stderr += String(data); + }); + + process.on('error', err => { + stderr += err.toString(); + }); + + process.on('close', code => { + const timings = { date, duration: calcDuration(start) }; + if (code === 0 || ignoreExitCode) { + onComplete?.(); + resolve({ code, stdout, stderr, ...timings }); + } else { + const errorMsg = new ProcessError({ code, stdout, stderr, ...timings }); + onError?.(errorMsg); + reject(errorMsg); + } + }); + }); +} diff --git a/packages/nx-plugin/src/internal/execute-process.unit.test.ts b/packages/nx-plugin/src/internal/execute-process.unit.test.ts new file mode 100644 index 000000000..5893b867f --- /dev/null +++ b/packages/nx-plugin/src/internal/execute-process.unit.test.ts @@ -0,0 +1,92 @@ +import { describe, expect, it, vi } from 'vitest'; +import { getAsyncProcessRunnerConfig } from '@code-pushup/test-utils'; +import { type ProcessObserver, executeProcess } from './execute-process.js'; + +describe('executeProcess', () => { + const spyObserver: ProcessObserver = { + onStdout: vi.fn(), + onError: vi.fn(), + onComplete: vi.fn(), + }; + const errorSpy = vi.fn(); + + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('should work with node command `node -v`', async () => { + const processResult = await executeProcess({ + command: `node`, + args: ['-v'], + observer: spyObserver, + }); + + // Note: called once or twice depending on environment (2nd time for a new line) + expect(spyObserver.onStdout).toHaveBeenCalled(); + expect(spyObserver.onComplete).toHaveBeenCalledOnce(); + expect(spyObserver.onError).not.toHaveBeenCalled(); + expect(processResult.stdout).toMatch(/v\d{1,2}(\.\d{1,2}){0,2}/); + }); + + it('should work with npx command `npx --help`', async () => { + const processResult = await executeProcess({ + command: `npx`, + args: ['--help'], + observer: spyObserver, + }); + expect(spyObserver.onStdout).toHaveBeenCalledOnce(); + expect(spyObserver.onComplete).toHaveBeenCalledOnce(); + expect(spyObserver.onError).not.toHaveBeenCalled(); + expect(processResult.stdout).toContain('npm exec'); + }); + + it('should work with script `node custom-script.js`', async () => { + const processResult = await executeProcess({ + ...getAsyncProcessRunnerConfig({ interval: 10, runs: 4 }), + observer: spyObserver, + }).catch(errorSpy); + + expect(errorSpy).not.toHaveBeenCalled(); + expect(processResult.stdout).toContain('process:complete'); + expect(spyObserver.onStdout).toHaveBeenCalledTimes(6); // intro + 4 runs + complete + expect(spyObserver.onError).not.toHaveBeenCalled(); + expect(spyObserver.onComplete).toHaveBeenCalledOnce(); + }); + + it('should work with async script `node custom-script.js` that throws an error', async () => { + const processResult = await executeProcess({ + ...getAsyncProcessRunnerConfig({ + interval: 10, + runs: 1, + throwError: true, + }), + observer: spyObserver, + }).catch(errorSpy); + + expect(errorSpy).toHaveBeenCalledOnce(); + expect(processResult).toBeUndefined(); + expect(spyObserver.onStdout).toHaveBeenCalledTimes(2); // intro + 1 run before error + expect(spyObserver.onError).toHaveBeenCalledOnce(); + expect(spyObserver.onComplete).not.toHaveBeenCalled(); + }); + + it('should successfully exit process after an error is thrown when ignoreExitCode is set', async () => { + const processResult = await executeProcess({ + ...getAsyncProcessRunnerConfig({ + interval: 10, + runs: 1, + throwError: true, + }), + observer: spyObserver, + ignoreExitCode: true, + }).catch(errorSpy); + + expect(errorSpy).not.toHaveBeenCalled(); + expect(processResult.code).toBe(1); + expect(processResult.stdout).toContain('process:update'); + expect(processResult.stderr).toContain('dummy-error'); + expect(spyObserver.onStdout).toHaveBeenCalledTimes(2); // intro + 1 run before error + expect(spyObserver.onError).not.toHaveBeenCalled(); + expect(spyObserver.onComplete).toHaveBeenCalledOnce(); + }); +}); diff --git a/packages/nx-plugin/src/internal/types.ts b/packages/nx-plugin/src/internal/types.ts new file mode 100644 index 000000000..bf3a2d047 --- /dev/null +++ b/packages/nx-plugin/src/internal/types.ts @@ -0,0 +1,4 @@ +export type DynamicTargetOptions = { + targetName?: string; + bin?: string; +}; diff --git a/packages/nx-plugin/src/internal/versions.ts b/packages/nx-plugin/src/internal/versions.ts new file mode 100644 index 000000000..b7e24f64a --- /dev/null +++ b/packages/nx-plugin/src/internal/versions.ts @@ -0,0 +1,25 @@ +import { readJsonFile } from '@nx/devkit'; +import * as path from 'node:path'; +import type { PackageJson } from 'nx/src/utils/package-json'; + +const workspaceRoot = path.join(__dirname, '../../'); +const projectsFolder = path.join(__dirname, '../../../'); + +export const cpNxPluginVersion = loadPackageJson(workspaceRoot).version; +export const cpModelVersion = loadPackageJson( + path.join(projectsFolder, 'cli'), +).version; +export const cpUtilsVersion = loadPackageJson( + path.join(projectsFolder, 'utils'), +).version; +export const cpCliVersion = loadPackageJson( + path.join(projectsFolder, 'models'), +).version; + +/** + * Load the package.json file from the given folder path. + * @param folderPath + */ +function loadPackageJson(folderPath: string): PackageJson { + return readJsonFile(path.join(folderPath, 'package.json')); +} diff --git a/packages/nx-plugin/src/plugin/README.md b/packages/nx-plugin/src/plugin/README.md new file mode 100644 index 000000000..80216bd58 --- /dev/null +++ b/packages/nx-plugin/src/plugin/README.md @@ -0,0 +1,107 @@ +# @code-pushup/nx-plugin + +The Nx Plugin for [Code PushUp](https://github.com/code-pushup/cli#readme), an open source code quality and conformance tool. + +Why should you use this plugin? + +- Zero setup cost. Just run the `init` generator and you're good to go. +- Smoother CI integration +- Minimal configuration +- Automated setup, migration and maintenance + +## Usage + +```jsonc +// nx.json +{ + //... + "plugins": ["@code-pushup/nx-plugin"], +} +``` + +or with options: + +```jsonc +// nx.json +{ + //... + "plugins": [ + { + "plugin": "@code-pushup/nx-plugin", + "options": { + "projectPrefix": "cli", + }, + }, + ], +} +``` + +Now every project will have `code-pushup--configuration` target if no `code-pushup.{ts,mjs,js}` is present. + +- `nx run :code-pushup--configuration` +- `nx run :code-pushup--configuration --skipFormat` + +Run it and the project will get automatically configured. + +```text +Root/ +├── project-name/ +│ ├── code-pushup.config.ts 👈 generated +│ └── ... +└── ... +``` + +For details visit the [configuration generator docs](../generators/configuration/README.md). + +With the configuration from above a `code-pushup` target is now present. + +- `nx run :code-pushup` + +Run it and the project will get automatically collect the report. + +```text +Root/ +├── .code-pushup/ +│ └── project-name +│ ├── report.md 👈 generated +│ └── report.json 👈 generated +├── project-name/ +│ ├── code-pushup.config.ts +│ └── ... +└── ... +``` + +Pass positional arguments to execute a specific command, use named arguments to overwrite defaults. + +- `nx run :code-pushup --onlyPlugins=eslint` +- `nx run :code-pushup collect` +- `nx run :code-pushup upload --upload.server=https://staging.code-pushup.dev` + +For a full list of command visit the [Code PushUp CLI documentation](../../../cli/README.md#commands). + +## Options + +| Name | type | description | +| ----------------- | -------------------------------- | ------------------------------------------------------ | +| **projectPrefix** | `string` | prefix for upload.project on non root projects | +| **targetName** | `string` (DEFAULT 'code-pushup') | The id used to identify a target in your project.json. | +| **bin** | `string` | Path to Code PushUp CLI | + +All options are optional and provided in the `nx.json` file. + +```jsonc +// nx.json +{ + //... + "plugins": [ + { + "plugin": "@code-pushup/nx-plugin", + "options": { + "projectPrefix": "cli" + "targetName": "cp" + "bin": "dist/package/code-pushup-custom-build" + } + } + ] +} +``` diff --git a/packages/nx-plugin/src/plugin/constants.ts b/packages/nx-plugin/src/plugin/constants.ts new file mode 100644 index 000000000..bf2e81d9f --- /dev/null +++ b/packages/nx-plugin/src/plugin/constants.ts @@ -0,0 +1 @@ +export const CP_TARGET_NAME = 'code-pushup'; diff --git a/packages/nx-plugin/src/plugin/index.ts b/packages/nx-plugin/src/plugin/index.ts new file mode 100644 index 000000000..648d0b4aa --- /dev/null +++ b/packages/nx-plugin/src/plugin/index.ts @@ -0,0 +1,2 @@ +export { createNodes } from './plugin.js'; +export type { CreateNodesOptions } from './types.js'; diff --git a/packages/nx-plugin/src/plugin/plugin.ts b/packages/nx-plugin/src/plugin/plugin.ts new file mode 100644 index 000000000..1f125f5a8 --- /dev/null +++ b/packages/nx-plugin/src/plugin/plugin.ts @@ -0,0 +1,34 @@ +import type { + CreateNodes, + CreateNodesContext, + CreateNodesResult, +} from '@nx/devkit'; +import { PROJECT_JSON_FILE_NAME } from '../internal/constants.js'; +import { createTargets } from './target/targets.js'; +import type { CreateNodesOptions } from './types.js'; +import { normalizedCreateNodesContext } from './utils.js'; + +// name has to be "createNodes" to get picked up by Nx => { + const parsedCreateNodesOptions = createNodesOptions as CreateNodesOptions; + const normalizedContext = await normalizedCreateNodesContext( + context, + projectConfigurationFile, + parsedCreateNodesOptions, + ); + + return { + projects: { + [normalizedContext.projectRoot]: { + targets: await createTargets(normalizedContext), + }, + }, + }; + }, +]; diff --git a/packages/nx-plugin/src/plugin/plugin.unit.test.ts b/packages/nx-plugin/src/plugin/plugin.unit.test.ts new file mode 100644 index 000000000..62b3c0b2f --- /dev/null +++ b/packages/nx-plugin/src/plugin/plugin.unit.test.ts @@ -0,0 +1,139 @@ +import type { CreateNodesContext } from '@nx/devkit'; +import { vol } from 'memfs'; +import { describe, expect } from 'vitest'; +import { invokeCreateNodesOnVirtualFiles } from '@code-pushup/test-nx-utils'; +import { PACKAGE_NAME, PROJECT_JSON_FILE_NAME } from '../internal/constants.js'; +import { CP_TARGET_NAME } from './constants.js'; +import { createNodes } from './plugin.js'; + +describe('@code-pushup/nx-plugin/plugin', () => { + let context: CreateNodesContext; + + beforeEach(() => { + context = { + nxJsonConfiguration: {}, + workspaceRoot: '', + configFiles: [], + }; + }); + + afterEach(() => { + vol.reset(); + }); + + it('should normalize context and use it to create the configuration target on ROOT project', async () => { + const projectRoot = '.'; + const matchingFilesData = { + [`${projectRoot}/${PROJECT_JSON_FILE_NAME}`]: `${JSON.stringify({ + name: '@org/empty-root', + })}`, + }; + + await expect( + invokeCreateNodesOnVirtualFiles( + createNodes, + context, + {}, + { matchingFilesData }, + ), + ).resolves.toStrictEqual({ + [projectRoot]: { + targets: { + [`${CP_TARGET_NAME}--configuration`]: { + command: `nx g ${PACKAGE_NAME}:configuration --skipTarget --targetName="code-pushup" --project="@org/empty-root"`, + }, + }, + }, + }); + }); + + it('should normalize context and use it to create the configuration target on PACKAGE project', async () => { + const projectRoot = 'apps/my-app'; + const matchingFilesData = { + [`${projectRoot}/${PROJECT_JSON_FILE_NAME}`]: `${JSON.stringify({ + name: '@org/empty-root', + })}`, + }; + + await expect( + invokeCreateNodesOnVirtualFiles( + createNodes, + context, + {}, + { matchingFilesData }, + ), + ).resolves.toStrictEqual({ + [projectRoot]: { + targets: { + [`${CP_TARGET_NAME}--configuration`]: { + command: `nx g ${PACKAGE_NAME}:configuration --skipTarget --targetName="code-pushup" --project="@org/empty-root"`, + }, + }, + }, + }); + }); + + it('should create the executor target on ROOT project if configured', async () => { + const projectRoot = '.'; + const matchingFilesData = { + [`${projectRoot}/${PROJECT_JSON_FILE_NAME}`]: `${JSON.stringify({ + name: '@org/empty-root', + })}`, + [`${projectRoot}/code-pushup.config.ts`]: '{}', + }; + + await expect( + invokeCreateNodesOnVirtualFiles( + createNodes, + context, + { + projectPrefix: 'cli', + }, + { matchingFilesData }, + ), + ).resolves.toStrictEqual({ + [projectRoot]: { + targets: { + [CP_TARGET_NAME]: { + executor: `${PACKAGE_NAME}:cli`, + options: { + projectPrefix: 'cli', + }, + }, + }, + }, + }); + }); + + it('should create the executor target on PACKAGE project if configured', async () => { + const projectRoot = 'apps/my-app'; + const matchingFilesData = { + [`${projectRoot}/${PROJECT_JSON_FILE_NAME}`]: `${JSON.stringify({ + name: '@org/empty-root', + })}`, + [`${projectRoot}/code-pushup.config.ts`]: '{}', + }; + + await expect( + invokeCreateNodesOnVirtualFiles( + createNodes, + context, + { + projectPrefix: 'cli', + }, + { matchingFilesData }, + ), + ).resolves.toStrictEqual({ + [projectRoot]: { + targets: { + [CP_TARGET_NAME]: { + executor: `${PACKAGE_NAME}:cli`, + options: { + projectPrefix: 'cli', + }, + }, + }, + }, + }); + }); +}); diff --git a/packages/nx-plugin/src/plugin/target/configuration-target.ts b/packages/nx-plugin/src/plugin/target/configuration-target.ts new file mode 100644 index 000000000..d19b9325b --- /dev/null +++ b/packages/nx-plugin/src/plugin/target/configuration-target.ts @@ -0,0 +1,24 @@ +import type { TargetConfiguration } from '@nx/devkit'; +import type { RunCommandsOptions } from 'nx/src/executors/run-commands/run-commands.impl'; +import { objectToCliArgs } from '../../executors/internal/cli.js'; +import { PACKAGE_NAME } from '../../internal/constants.js'; +import { CP_TARGET_NAME } from '../constants.js'; + +export function createConfigurationTarget(options?: { + targetName?: string; + projectName?: string; + bin?: string; +}): TargetConfiguration { + const { + projectName, + bin = PACKAGE_NAME, + targetName = CP_TARGET_NAME, + } = options ?? {}; + return { + command: `nx g ${bin}:configuration ${objectToCliArgs({ + skipTarget: true, + targetName, + ...(projectName ? { project: projectName } : {}), + }).join(' ')}`, + }; +} diff --git a/packages/nx-plugin/src/plugin/target/configuration.target.unit.test.ts b/packages/nx-plugin/src/plugin/target/configuration.target.unit.test.ts new file mode 100644 index 000000000..87f4418c9 --- /dev/null +++ b/packages/nx-plugin/src/plugin/target/configuration.target.unit.test.ts @@ -0,0 +1,19 @@ +import { expect } from 'vitest'; +import { PACKAGE_NAME } from '../../internal/constants.js'; +import { createConfigurationTarget } from './configuration-target.js'; + +describe('createConfigurationTarget', () => { + it('should return code-pushup--configuration target for given project', () => { + expect( + createConfigurationTarget({ projectName: 'my-project' }), + ).toStrictEqual({ + command: `nx g ${PACKAGE_NAME}:configuration --skipTarget --targetName="code-pushup" --project="my-project"`, + }); + }); + + it('should return code-pushup--configuration target without project name', () => { + expect(createConfigurationTarget()).toStrictEqual({ + command: `nx g ${PACKAGE_NAME}:configuration --skipTarget --targetName="code-pushup"`, + }); + }); +}); diff --git a/packages/nx-plugin/src/plugin/target/constants.ts b/packages/nx-plugin/src/plugin/target/constants.ts new file mode 100644 index 000000000..79e804e40 --- /dev/null +++ b/packages/nx-plugin/src/plugin/target/constants.ts @@ -0,0 +1,2 @@ +export const CODE_PUSHUP_CONFIG_REGEX = + /^code-pushup\.config\.(\w*\.)*(ts|js|mjs)$/; diff --git a/packages/nx-plugin/src/plugin/target/executor-target.ts b/packages/nx-plugin/src/plugin/target/executor-target.ts new file mode 100644 index 000000000..e8b52eb8f --- /dev/null +++ b/packages/nx-plugin/src/plugin/target/executor-target.ts @@ -0,0 +1,20 @@ +import type { TargetConfiguration } from '@nx/devkit'; +import { PACKAGE_NAME } from '../../internal/constants.js'; +import type { ProjectPrefixOptions } from '../types.js'; + +export function createExecutorTarget(options?: { + bin?: string; + projectPrefix?: string; +}): TargetConfiguration { + const { bin = PACKAGE_NAME, projectPrefix } = options ?? {}; + return { + executor: `${bin}:cli`, + ...(projectPrefix + ? { + options: { + projectPrefix, + }, + } + : {}), + }; +} diff --git a/packages/nx-plugin/src/plugin/target/executor.target.unit.test.ts b/packages/nx-plugin/src/plugin/target/executor.target.unit.test.ts new file mode 100644 index 000000000..610b44bd7 --- /dev/null +++ b/packages/nx-plugin/src/plugin/target/executor.target.unit.test.ts @@ -0,0 +1,25 @@ +import { expect } from 'vitest'; +import { createExecutorTarget } from './executor-target.js'; + +describe('createExecutorTarget', () => { + it('should return executor target without project name', () => { + expect(createExecutorTarget()).toStrictEqual({ + executor: '@code-pushup/nx-plugin:cli', + }); + }); + + it('should use bin if provides', () => { + expect(createExecutorTarget({ bin: 'xyz' })).toStrictEqual({ + executor: 'xyz:cli', + }); + }); + + it('should use projectPrefix if provided', () => { + expect(createExecutorTarget({ projectPrefix: 'cli' })).toStrictEqual({ + executor: '@code-pushup/nx-plugin:cli', + options: { + projectPrefix: 'cli', + }, + }); + }); +}); diff --git a/packages/nx-plugin/src/plugin/target/targets.ts b/packages/nx-plugin/src/plugin/target/targets.ts new file mode 100644 index 000000000..eb68740ef --- /dev/null +++ b/packages/nx-plugin/src/plugin/target/targets.ts @@ -0,0 +1,36 @@ +import { readdir } from 'node:fs/promises'; +import { CP_TARGET_NAME } from '../constants.js'; +import type { + CreateNodesOptions, + ProjectConfigurationWithName, +} from '../types.js'; +import { createConfigurationTarget } from './configuration-target.js'; +import { CODE_PUSHUP_CONFIG_REGEX } from './constants.js'; +import { createExecutorTarget } from './executor-target.js'; + +export type CreateTargetsOptions = { + projectJson: ProjectConfigurationWithName; + projectRoot: string; + createOptions: CreateNodesOptions; +}; + +export async function createTargets(normalizedContext: CreateTargetsOptions) { + const { + targetName = CP_TARGET_NAME, + bin, + projectPrefix, + } = normalizedContext.createOptions; + const rootFiles = await readdir(normalizedContext.projectRoot); + return rootFiles.some(filename => filename.match(CODE_PUSHUP_CONFIG_REGEX)) + ? { + [targetName]: createExecutorTarget({ bin, projectPrefix }), + } + : // if NO code-pushup.config.*.(ts|js|mjs) is present return configuration target + { + [`${targetName}--configuration`]: createConfigurationTarget({ + targetName, + projectName: normalizedContext.projectJson.name, + bin, + }), + }; +} diff --git a/packages/nx-plugin/src/plugin/target/targets.unit.test.ts b/packages/nx-plugin/src/plugin/target/targets.unit.test.ts new file mode 100644 index 000000000..9b730f726 --- /dev/null +++ b/packages/nx-plugin/src/plugin/target/targets.unit.test.ts @@ -0,0 +1,189 @@ +import { vol } from 'memfs'; +import { rm } from 'node:fs/promises'; +import { afterEach, beforeEach, expect } from 'vitest'; +import { MEMFS_VOLUME } from '@code-pushup/test-utils'; +import { DEFAULT_TARGET_NAME, PACKAGE_NAME } from '../../internal/constants.js'; +import { CP_TARGET_NAME } from '../constants.js'; +import type { NormalizedCreateNodesContext } from '../types.js'; +import { createTargets } from './targets.js'; + +describe('createTargets', () => { + beforeEach(async () => { + // needed to have the folder present. readdir otherwise it fails + vol.fromJSON( + { + x: '', + }, + MEMFS_VOLUME, + ); + await rm('x'); + }); + + afterEach(() => { + vol.reset(); + }); + + it('should return configuration targets for project without code-pushup config', async () => { + const projectName = 'plugin-my-plugin'; + await expect( + createTargets({ + projectRoot: '.', + projectJson: { + name: projectName, + }, + createOptions: {}, + } as NormalizedCreateNodesContext), + ).resolves.toStrictEqual({ + [`${CP_TARGET_NAME}--configuration`]: { + command: `nx g ${PACKAGE_NAME}:configuration --skipTarget --targetName="code-pushup" --project="${projectName}"`, + }, + }); + }); + + it('should return configuration targets for empty project without code-pushup config and consider targetName', async () => { + const projectName = 'plugin-my-plugin'; + const targetName = 'cp'; + await expect( + createTargets({ + projectRoot: '.', + projectJson: { + name: projectName, + }, + createOptions: { + targetName, + }, + } as NormalizedCreateNodesContext), + ).resolves.toStrictEqual({ + [`${targetName}--configuration`]: { + command: `nx g ${PACKAGE_NAME}:configuration --skipTarget --targetName="cp" --project="${projectName}"`, + }, + }); + }); + + it('should NOT return configuration target if code-pushup config is given', async () => { + const projectName = 'plugin-my-plugin'; + vol.fromJSON( + { + [`code-pushup.config.ts`]: `{}`, + }, + MEMFS_VOLUME, + ); + const targetName = 'cp'; + await expect( + createTargets({ + projectRoot: '.', + projectJson: { + name: projectName, + }, + createOptions: { + targetName, + }, + } as NormalizedCreateNodesContext), + ).resolves.toStrictEqual( + expect.not.objectContaining({ + [`${targetName}--configuration`]: expect.any(Object), + }), + ); + }); + + it('should return executor target if code-pushup config is given', async () => { + const projectName = 'plugin-my-plugin'; + vol.fromJSON( + { + [`code-pushup.config.ts`]: `{}`, + }, + MEMFS_VOLUME, + ); + const targetName = 'cp'; + await expect( + createTargets({ + projectRoot: '.', + projectJson: { + name: projectName, + }, + createOptions: { + targetName, + }, + } as NormalizedCreateNodesContext), + ).resolves.toStrictEqual( + expect.objectContaining({ + [targetName]: { + executor: `${PACKAGE_NAME}:cli`, + }, + }), + ); + }); + + it('should return executor targets for project if configured', async () => { + const projectName = 'plugin-my-plugin'; + vol.fromJSON( + { + [`code-pushup.config.ts`]: `{}`, + }, + MEMFS_VOLUME, + ); + await expect( + createTargets({ + projectRoot: '.', + projectJson: { + name: projectName, + }, + createOptions: {}, + } as NormalizedCreateNodesContext), + ).resolves.toStrictEqual({ + [DEFAULT_TARGET_NAME]: { + executor: '@code-pushup/nx-plugin:cli', + }, + }); + }); + + it('should return executor targets for configured project and use given targetName', async () => { + const projectName = 'plugin-my-plugin'; + vol.fromJSON( + { + [`code-pushup.config.ts`]: `{}`, + }, + MEMFS_VOLUME, + ); + await expect( + createTargets({ + projectRoot: '.', + projectJson: { + name: projectName, + }, + createOptions: { + targetName: 'cp', + }, + } as NormalizedCreateNodesContext), + ).resolves.toStrictEqual({ + cp: { + executor: '@code-pushup/nx-plugin:cli', + }, + }); + }); + + it('should include projectPrefix options in executor targets if given', async () => { + const projectName = 'plugin-my-plugin'; + vol.fromJSON( + { + [`code-pushup.config.ts`]: `{}`, + }, + MEMFS_VOLUME, + ); + await expect( + createTargets({ + projectRoot: '.', + projectJson: { + name: projectName, + }, + createOptions: { + projectPrefix: 'cli', + }, + } as NormalizedCreateNodesContext), + ).resolves.toStrictEqual({ + [DEFAULT_TARGET_NAME]: expect.objectContaining({ + options: { projectPrefix: 'cli' }, + }), + }); + }); +}); diff --git a/packages/nx-plugin/src/plugin/types.ts b/packages/nx-plugin/src/plugin/types.ts new file mode 100644 index 000000000..4fd57ed95 --- /dev/null +++ b/packages/nx-plugin/src/plugin/types.ts @@ -0,0 +1,25 @@ +import type { + CreateNodesContext, + CreateNodesContextV2, + ProjectConfiguration, +} from '@nx/devkit'; +import type { WithRequired } from '@code-pushup/utils'; +import type { DynamicTargetOptions } from '../internal/types.js'; +import type { CreateTargetsOptions } from './target/targets.js'; + +export type ProjectPrefixOptions = { + projectPrefix?: string; +}; + +export type CreateNodesOptions = DynamicTargetOptions & ProjectPrefixOptions; + +export type ProjectConfigurationWithName = WithRequired< + ProjectConfiguration, + 'name' +>; + +export type NormalizedCreateNodesContext = CreateNodesContext & + CreateTargetsOptions; + +export type NormalizedCreateNodesV2Context = CreateNodesContextV2 & + CreateTargetsOptions; diff --git a/packages/nx-plugin/src/plugin/utils.ts b/packages/nx-plugin/src/plugin/utils.ts new file mode 100644 index 000000000..8d551f682 --- /dev/null +++ b/packages/nx-plugin/src/plugin/utils.ts @@ -0,0 +1,65 @@ +import type { CreateNodesContext, CreateNodesContextV2 } from '@nx/devkit'; +import { readFile } from 'node:fs/promises'; +import * as path from 'node:path'; +import { CP_TARGET_NAME } from './constants.js'; +import type { + CreateNodesOptions, + NormalizedCreateNodesContext, + NormalizedCreateNodesV2Context, + ProjectConfigurationWithName, +} from './types.js'; + +export async function normalizedCreateNodesContext( + context: CreateNodesContext, + projectConfigurationFile: string, + createOptions: CreateNodesOptions = {}, +): Promise { + const projectRoot = path.dirname(projectConfigurationFile); + + try { + const projectJson = JSON.parse( + (await readFile(projectConfigurationFile)).toString(), + ) as ProjectConfigurationWithName; + + const { targetName = CP_TARGET_NAME } = createOptions; + return { + ...context, + projectJson, + projectRoot, + createOptions: { + ...createOptions, + targetName, + }, + }; + } catch { + throw new Error( + `Error parsing project.json file ${projectConfigurationFile}.`, + ); + } +} + +export async function normalizedCreateNodesV2Context( + context: CreateNodesContextV2, + projectConfigurationFile: string, + createOptions: CreateNodesOptions = {}, +): Promise { + const projectRoot = path.dirname(projectConfigurationFile); + + try { + const projectJson = JSON.parse( + (await readFile(projectConfigurationFile)).toString(), + ) as ProjectConfigurationWithName; + + const { targetName = CP_TARGET_NAME } = createOptions; + return { + ...context, + projectJson, + projectRoot, + createOptions: { ...createOptions, targetName }, + }; + } catch { + throw new Error( + `Error parsing project.json file ${projectConfigurationFile}.`, + ); + } +} diff --git a/packages/nx-plugin/src/plugin/utils.unit.test.ts b/packages/nx-plugin/src/plugin/utils.unit.test.ts new file mode 100644 index 000000000..edf2bf1cb --- /dev/null +++ b/packages/nx-plugin/src/plugin/utils.unit.test.ts @@ -0,0 +1,160 @@ +import { vol } from 'memfs'; +import { describe, expect } from 'vitest'; +import { createNodesContext } from '@code-pushup/test-nx-utils'; +import { MEMFS_VOLUME } from '@code-pushup/test-utils'; +import { normalizedCreateNodesContext } from './utils.js'; + +describe('normalizedCreateNodesContext', () => { + it('should provide workspaceRoot', async () => { + vol.fromJSON( + { + 'project.json': JSON.stringify({ name: 'my-project' }), + }, + MEMFS_VOLUME, + ); + + await expect( + normalizedCreateNodesContext( + createNodesContext({ workspaceRoot: MEMFS_VOLUME }), + 'project.json', + ), + ).resolves.toStrictEqual( + expect.objectContaining({ + workspaceRoot: MEMFS_VOLUME, + }), + ); + }); + + it('should provide projectRoot', async () => { + vol.fromJSON( + { + 'packages/utils/project.json': JSON.stringify({ + name: 'my-project', + }), + }, + MEMFS_VOLUME, + ); + + await expect( + normalizedCreateNodesContext( + createNodesContext(), + 'packages/utils/project.json', + ), + ).resolves.toStrictEqual( + expect.objectContaining({ + projectRoot: 'packages/utils', + }), + ); + }); + + it('should provide nxJsonConfiguration', async () => { + vol.fromJSON( + { + 'project.json': JSON.stringify({ + name: 'my-project', + }), + }, + MEMFS_VOLUME, + ); + + await expect( + normalizedCreateNodesContext( + createNodesContext({ + nxJsonConfiguration: { + workspaceLayout: { + libsDir: 'libs', + }, + }, + }), + 'project.json', + ), + ).resolves.toStrictEqual( + expect.objectContaining({ + nxJsonConfiguration: { + workspaceLayout: { + libsDir: 'libs', + }, + }, + }), + ); + }); + + it('should provide projectJson', async () => { + vol.fromJSON( + { + 'project.json': JSON.stringify({ + name: 'my-project', + }), + }, + MEMFS_VOLUME, + ); + + await expect( + normalizedCreateNodesContext(createNodesContext(), 'project.json'), + ).resolves.toStrictEqual( + expect.objectContaining({ + projectJson: { + name: 'my-project', + }, + }), + ); + }); + + it('should throw for empty project.json', async () => { + vol.fromJSON( + { + 'project.json': '', + }, + MEMFS_VOLUME, + ); + + await expect( + normalizedCreateNodesContext(createNodesContext(), 'project.json'), + ).rejects.toThrow('Error parsing project.json file project.json.'); + }); + + it('should provide default targetName in createOptions', async () => { + vol.fromJSON( + { + 'project.json': JSON.stringify({ + name: 'my-project', + }), + }, + MEMFS_VOLUME, + ); + + await expect( + normalizedCreateNodesContext(createNodesContext(), 'project.json'), + ).resolves.toStrictEqual( + expect.objectContaining({ + createOptions: { + targetName: 'code-pushup', + }, + }), + ); + }); + + it('should provide createOptions', async () => { + vol.fromJSON( + { + 'project.json': JSON.stringify({ + name: 'my-project', + }), + }, + MEMFS_VOLUME, + ); + + await expect( + normalizedCreateNodesContext(createNodesContext(), 'project.json', { + projectPrefix: 'cli', + }), + ).resolves.toStrictEqual( + expect.objectContaining({ + createOptions: { + targetName: 'code-pushup', + projectPrefix: 'cli', + }, + }), + ); + }); +}); diff --git a/packages/nx-plugin/tsconfig.json b/packages/nx-plugin/tsconfig.json new file mode 100644 index 000000000..cf0aecd4f --- /dev/null +++ b/packages/nx-plugin/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "module": "CommonJS", + "verbatimModuleSyntax": false + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.test.json" + } + ] +} diff --git a/packages/nx-plugin/tsconfig.lib.json b/packages/nx-plugin/tsconfig.lib.json new file mode 100644 index 000000000..71aabc78b --- /dev/null +++ b/packages/nx-plugin/tsconfig.lib.json @@ -0,0 +1,17 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "declaration": true, + "types": ["node"] + }, + "include": ["src/**/*.ts"], + "exclude": [ + "vitest.unit.config.ts", + "vitest.int.config.ts", + "src/**/__snapshots__/*.ts", + "src/**/*.test.ts", + "src/**/*.mock.ts", + "test/**/*.ts" + ] +} diff --git a/packages/nx-plugin/tsconfig.test.json b/packages/nx-plugin/tsconfig.test.json new file mode 100644 index 000000000..e7914d68f --- /dev/null +++ b/packages/nx-plugin/tsconfig.test.json @@ -0,0 +1,17 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "types": ["vitest/globals", "vitest/importMeta", "vite/client", "node"] + }, + "include": [ + "vitest.unit.config.ts", + "vitest.int.config.ts", + "mock/**/*.ts", + "src/**/*.test.ts", + "src/**/*.test.tsx", + "src/**/*.test.js", + "src/**/*.test.jsx", + "src/**/*.d.ts" + ] +} diff --git a/packages/nx-plugin/vitest.int.config.ts b/packages/nx-plugin/vitest.int.config.ts new file mode 100644 index 000000000..25d5530d1 --- /dev/null +++ b/packages/nx-plugin/vitest.int.config.ts @@ -0,0 +1,28 @@ +/// +import { defineConfig } from 'vite'; +import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js'; + +export default defineConfig({ + cacheDir: '../../node_modules/.vite/nx-plugin', + test: { + reporters: ['basic'], + globals: true, + cache: { + dir: '../../node_modules/.vitest', + }, + alias: tsconfigPathAliases(), + pool: 'threads', + poolOptions: { threads: { singleThread: true } }, + coverage: { + reporter: ['text', 'lcov'], + reportsDirectory: '../../coverage/nx-plugin/int-tests', + exclude: ['mocks/**', '**/types.ts', '**/__snapshots__/**'], + }, + environment: 'node', + include: ['src/**/*.int.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + setupFiles: [ + '../../testing/test-setup/src/lib/console.mock.ts', + '../../testing/test-setup/src/lib/reset.mocks.ts', + ], + }, +}); diff --git a/packages/nx-plugin/vitest.unit.config.ts b/packages/nx-plugin/vitest.unit.config.ts new file mode 100644 index 000000000..db557f696 --- /dev/null +++ b/packages/nx-plugin/vitest.unit.config.ts @@ -0,0 +1,29 @@ +/// +import { defineConfig } from 'vite'; +import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js'; + +export default defineConfig({ + cacheDir: '../../node_modules/.vite/nx-plugin', + test: { + reporters: ['basic'], + globals: true, + cache: { + dir: '../../node_modules/.vitest', + }, + alias: tsconfigPathAliases(), + pool: 'threads', + poolOptions: { threads: { singleThread: true } }, + coverage: { + reporter: ['text', 'lcov'], + reportsDirectory: '../../coverage/nx-plugin/unit-tests', + exclude: ['mocks/**', '**/types.ts', '**/__snapshots__/**'], + }, + environment: 'node', + include: ['src/**/*.unit.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + setupFiles: [ + '../../testing/test-setup/src/lib/fs.mock.ts', + '../../testing/test-setup/src/lib/console.mock.ts', + '../../testing/test-setup/src/lib/reset.mocks.ts', + ], + }, +}); From f18e6e5509f08d490fac5305ec362176fe2b3887 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Sat, 16 Aug 2025 16:55:19 +0200 Subject: [PATCH 066/111] chore: adjust parallel in gh action --- .github/workflows/code-pushup-fork.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/code-pushup-fork.yml b/.github/workflows/code-pushup-fork.yml index ff9eaad97..4dd08dbb1 100644 --- a/.github/workflows/code-pushup-fork.yml +++ b/.github/workflows/code-pushup-fork.yml @@ -37,4 +37,4 @@ jobs: - name: Run Code PushUp action uses: code-pushup/github-action@v0 with: - bin: npx nx affected -t code-pushup --parallel=1 -- + bin: npx nx affected -t code-pushup --parallel=3 -- From 7d2fbb3e516bdeb3a4cb33c89e5b3df747fcc0bf Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Sat, 16 Aug 2025 16:56:31 +0200 Subject: [PATCH 067/111] chore: adjust nx caching --- nx.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nx.json b/nx.json index d37eedde3..66e78dca4 100644 --- a/nx.json +++ b/nx.json @@ -68,7 +68,7 @@ } }, "code-pushup": { - "cache": true, + "cache": false, "outputs": [ "{projectRoot}/.code-pushup/report.md", "{projectRoot}/.code-pushup/report.json" From 18707a6bb9ee7919b457178651d7b0323ec082d4 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Sat, 16 Aug 2025 17:18:14 +0200 Subject: [PATCH 068/111] chore: adjust project graph creation --- .../plugin-coverage/src/lib/nx/coverage-paths.ts | 12 ++++++------ .../plugin-eslint/src/lib/nx/find-all-projects.ts | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/plugin-coverage/src/lib/nx/coverage-paths.ts b/packages/plugin-coverage/src/lib/nx/coverage-paths.ts index a74b0a195..21419d297 100644 --- a/packages/plugin-coverage/src/lib/nx/coverage-paths.ts +++ b/packages/plugin-coverage/src/lib/nx/coverage-paths.ts @@ -1,8 +1,8 @@ /// -import type { - ProjectConfiguration, - ProjectGraphProjectNode, - Tree, +import { + type ProjectConfiguration, + type ProjectGraphProjectNode, + type Tree, } from '@nx/devkit'; import type { JestExecutorOptions } from '@nx/jest/src/executors/jest/schema'; import type { VitestExecutorOptions } from '@nx/vite/executors'; @@ -25,8 +25,8 @@ export async function getNxCoveragePaths( ); } - const { createProjectGraphAsync } = await import('@nx/devkit'); - const { nodes } = await createProjectGraphAsync({ exitOnError: false }); + const { readCachedProjectGraph } = await import('@nx/devkit'); + const { nodes } = readCachedProjectGraph(); const coverageResults = await Promise.all( targets.map(async target => { diff --git a/packages/plugin-eslint/src/lib/nx/find-all-projects.ts b/packages/plugin-eslint/src/lib/nx/find-all-projects.ts index 11ecfb284..e25c658d7 100644 --- a/packages/plugin-eslint/src/lib/nx/find-all-projects.ts +++ b/packages/plugin-eslint/src/lib/nx/find-all-projects.ts @@ -31,8 +31,8 @@ import { nxProjectsToConfig } from './projects-to-config.js'; export async function eslintConfigFromAllNxProjects( options: { exclude?: string[] } = {}, ): Promise { - const { createProjectGraphAsync } = await import('@nx/devkit'); - const projectGraph = await createProjectGraphAsync({ exitOnError: false }); + const { readCachedProjectGraph } = await import('@nx/devkit'); + const projectGraph = readCachedProjectGraph(); const filteredProjectGraph = filterProjectGraph( projectGraph, options.exclude, From 2637c386b9468579ad8b50652287fe680ce7d717 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Sat, 16 Aug 2025 17:30:37 +0200 Subject: [PATCH 069/111] chore: adjust project graph creation 2 --- .../src/lib/nx/coverage-paths.ts | 21 ++++++++++++++++-- .../src/lib/nx/find-all-projects.ts | 22 +++++++++++++++++-- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/packages/plugin-coverage/src/lib/nx/coverage-paths.ts b/packages/plugin-coverage/src/lib/nx/coverage-paths.ts index 21419d297..bceb96652 100644 --- a/packages/plugin-coverage/src/lib/nx/coverage-paths.ts +++ b/packages/plugin-coverage/src/lib/nx/coverage-paths.ts @@ -11,6 +11,24 @@ import path from 'node:path'; import { importModule, ui } from '@code-pushup/utils'; import type { CoverageResult } from '../config.js'; +/** + * Resolves the cached project graph for the current Nx workspace. + * First tries to read cache and if not possible, go for the async creation. + */ +export async function resolveCachedProjectGraph() { + const { readCachedProjectGraph, createProjectGraphAsync } = await import( + '@nx/devkit' + ); + try { + return readCachedProjectGraph(); + } catch (e) { + ui().logger.warn( + 'Could not read cached project graph, falling back to async creation.', + ); + return await createProjectGraphAsync({ exitOnError: false }); + } +} + /** * @param targets nx targets to be used for measuring coverage, test by default * @returns An array of coverage result information for the coverage plugin. @@ -25,8 +43,7 @@ export async function getNxCoveragePaths( ); } - const { readCachedProjectGraph } = await import('@nx/devkit'); - const { nodes } = readCachedProjectGraph(); + const { nodes } = await resolveCachedProjectGraph(); const coverageResults = await Promise.all( targets.map(async target => { diff --git a/packages/plugin-eslint/src/lib/nx/find-all-projects.ts b/packages/plugin-eslint/src/lib/nx/find-all-projects.ts index e25c658d7..e4d85af74 100644 --- a/packages/plugin-eslint/src/lib/nx/find-all-projects.ts +++ b/packages/plugin-eslint/src/lib/nx/find-all-projects.ts @@ -1,7 +1,26 @@ +import { ui } from '@code-pushup/utils'; import type { ESLintTarget } from '../config.js'; import { filterProjectGraph } from './filter-project-graph.js'; import { nxProjectsToConfig } from './projects-to-config.js'; +/** + * Resolves the cached project graph for the current Nx workspace. + * First tries to read cache and if not possible, go for the async creation. + */ +export async function resolveCachedProjectGraph() { + const { readCachedProjectGraph, createProjectGraphAsync } = await import( + '@nx/devkit' + ); + try { + return readCachedProjectGraph(); + } catch (e) { + ui().logger.warn( + 'Could not read cached project graph, falling back to async creation.', + ); + return await createProjectGraphAsync({ exitOnError: false }); + } +} + /** * Finds all Nx projects in workspace and converts their lint configurations to Code PushUp ESLint plugin parameters. * @@ -31,8 +50,7 @@ import { nxProjectsToConfig } from './projects-to-config.js'; export async function eslintConfigFromAllNxProjects( options: { exclude?: string[] } = {}, ): Promise { - const { readCachedProjectGraph } = await import('@nx/devkit'); - const projectGraph = readCachedProjectGraph(); + const projectGraph = await resolveCachedProjectGraph(); const filteredProjectGraph = filterProjectGraph( projectGraph, options.exclude, From da01d55b55159ca8937afa17ababc8a6f928dfcb Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Sat, 16 Aug 2025 17:37:16 +0200 Subject: [PATCH 070/111] chore: adjust project graph creation 3 --- packages/plugin-coverage/src/lib/nx/coverage-paths.ts | 2 +- packages/plugin-eslint/src/lib/nx/find-all-projects.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/plugin-coverage/src/lib/nx/coverage-paths.ts b/packages/plugin-coverage/src/lib/nx/coverage-paths.ts index bceb96652..bc94e6070 100644 --- a/packages/plugin-coverage/src/lib/nx/coverage-paths.ts +++ b/packages/plugin-coverage/src/lib/nx/coverage-paths.ts @@ -15,7 +15,7 @@ import type { CoverageResult } from '../config.js'; * Resolves the cached project graph for the current Nx workspace. * First tries to read cache and if not possible, go for the async creation. */ -export async function resolveCachedProjectGraph() { +async function resolveCachedProjectGraph() { const { readCachedProjectGraph, createProjectGraphAsync } = await import( '@nx/devkit' ); diff --git a/packages/plugin-eslint/src/lib/nx/find-all-projects.ts b/packages/plugin-eslint/src/lib/nx/find-all-projects.ts index e4d85af74..6a28edc79 100644 --- a/packages/plugin-eslint/src/lib/nx/find-all-projects.ts +++ b/packages/plugin-eslint/src/lib/nx/find-all-projects.ts @@ -7,7 +7,7 @@ import { nxProjectsToConfig } from './projects-to-config.js'; * Resolves the cached project graph for the current Nx workspace. * First tries to read cache and if not possible, go for the async creation. */ -export async function resolveCachedProjectGraph() { +async function resolveCachedProjectGraph() { const { readCachedProjectGraph, createProjectGraphAsync } = await import( '@nx/devkit' ); @@ -47,7 +47,7 @@ export async function resolveCachedProjectGraph() { * @param options.exclude - Array of project names to exclude from the ESLint configuration * @returns ESLint config and patterns, intended to be passed to {@link eslintPlugin} */ -export async function eslintConfigFromAllNxProjects( +async function eslintConfigFromAllNxProjects( options: { exclude?: string[] } = {}, ): Promise { const projectGraph = await resolveCachedProjectGraph(); From 05891ea10b69ac866d032ad21c8d8fc3861c7ab7 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Sat, 16 Aug 2025 17:40:06 +0200 Subject: [PATCH 071/111] chore: adjust project graph creation 4 --- packages/plugin-coverage/src/lib/nx/coverage-paths.ts | 2 +- packages/plugin-eslint/src/lib/nx/find-all-projects.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/plugin-coverage/src/lib/nx/coverage-paths.ts b/packages/plugin-coverage/src/lib/nx/coverage-paths.ts index bc94e6070..f3e4b01bd 100644 --- a/packages/plugin-coverage/src/lib/nx/coverage-paths.ts +++ b/packages/plugin-coverage/src/lib/nx/coverage-paths.ts @@ -22,7 +22,7 @@ async function resolveCachedProjectGraph() { try { return readCachedProjectGraph(); } catch (e) { - ui().logger.warn( + ui().logger.info( 'Could not read cached project graph, falling back to async creation.', ); return await createProjectGraphAsync({ exitOnError: false }); diff --git a/packages/plugin-eslint/src/lib/nx/find-all-projects.ts b/packages/plugin-eslint/src/lib/nx/find-all-projects.ts index 6a28edc79..ffedf6dc3 100644 --- a/packages/plugin-eslint/src/lib/nx/find-all-projects.ts +++ b/packages/plugin-eslint/src/lib/nx/find-all-projects.ts @@ -14,7 +14,7 @@ async function resolveCachedProjectGraph() { try { return readCachedProjectGraph(); } catch (e) { - ui().logger.warn( + ui().logger.info( 'Could not read cached project graph, falling back to async creation.', ); return await createProjectGraphAsync({ exitOnError: false }); From 32499ab45aa47cb6a69943f890bcd161c466cd5b Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Sat, 16 Aug 2025 17:44:43 +0200 Subject: [PATCH 072/111] chore: adjust project graph creation 4 --- packages/plugin-eslint/src/lib/nx/find-all-projects.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugin-eslint/src/lib/nx/find-all-projects.ts b/packages/plugin-eslint/src/lib/nx/find-all-projects.ts index ffedf6dc3..3c9642d0f 100644 --- a/packages/plugin-eslint/src/lib/nx/find-all-projects.ts +++ b/packages/plugin-eslint/src/lib/nx/find-all-projects.ts @@ -47,7 +47,7 @@ async function resolveCachedProjectGraph() { * @param options.exclude - Array of project names to exclude from the ESLint configuration * @returns ESLint config and patterns, intended to be passed to {@link eslintPlugin} */ -async function eslintConfigFromAllNxProjects( +export async function eslintConfigFromAllNxProjects( options: { exclude?: string[] } = {}, ): Promise { const projectGraph = await resolveCachedProjectGraph(); From c9c2c5c9ee187c9a656b0feff787d0bf3ecd1ab1 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Sat, 16 Aug 2025 18:09:04 +0200 Subject: [PATCH 073/111] chore: adjust caching --- nx.json | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/nx.json b/nx.json index 66e78dca4..931637e1b 100644 --- a/nx.json +++ b/nx.json @@ -44,7 +44,7 @@ "dependsOn": ["^build"] }, "lint": { - "inputs": ["default", "{workspaceRoot}/eslint.config.?(c)js"], + "inputs": ["eslint-inputs"], "executor": "@nx/linter:eslint", "outputs": ["{options.outputFile}"], "cache": true, @@ -114,6 +114,7 @@ }, "code-pushup-eslint": { "cache": true, + "inputs": ["code-pushup-eslint-inputs"], "outputs": ["{projectRoot}/.code-pushup/eslint/runner-output.json"], "executor": "nx:run-commands", "options": { @@ -135,6 +136,7 @@ }, "code-pushup-js-packages": { "cache": false, + "inputs": [], "outputs": ["{projectRoot}/.code-pushup/js-packages/runner-output.json"], "executor": "nx:run-commands", "options": { @@ -156,6 +158,7 @@ }, "code-pushup-lighthouse": { "cache": true, + "inputs": ["code-pushup-lighthouse-inputs"], "outputs": ["{projectRoot}/.code-pushup/lighthouse/runner-output.json"], "executor": "nx:run-commands", "options": { @@ -177,6 +180,7 @@ }, "code-pushup-jsdocs": { "cache": true, + "inputs": ["code-pushup-jsdocs-inputs"], "outputs": ["{projectRoot}/.code-pushup/jsdocs/runner-output.json"], "executor": "nx:run-commands", "options": { @@ -198,7 +202,7 @@ }, "code-pushup-typescript": { "cache": true, - "inputs": ["default", "^default", "{projectRoot}/tsconfig.lib.json"], + "inputs": ["code-pushup-typescript-inputs"], "outputs": ["{projectRoot}/.code-pushup/typescript/runner-output.json"], "executor": "nx:run-commands", "options": { @@ -248,6 +252,12 @@ "!{projectRoot}/code-pushup.config.?(m)[jt]s", "!{projectRoot}/zod2md.config.ts" ], + "eslint-inputs": ["default", "{projectRoot}/eslint.config.?(c)js"], + "code-pushup-inputs": ["{projectRoot}/code-pushup.config.?ts"], + "code-pushup-eslint-inputs": ["eslint-inputs", "code-pushup-inputs"], + "code-pushup-jsdocs-inputs": ["default", "code-pushup-inputs"], + "code-pushup-typescript-inputs": ["default", "code-pushup-inputs"], + "code-pushup-lighthouse-inputs": ["default", "code-pushup-inputs"], "sharedGlobals": [] }, "workspaceLayout": { From 5e2a859ce84533f6e2f38f061a8a4c59d593e5b1 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Sat, 16 Aug 2025 18:12:35 +0200 Subject: [PATCH 074/111] fix: adjust path helper --- packages/plugin-coverage/src/lib/nx/coverage-paths.ts | 7 ++++--- packages/plugin-eslint/src/lib/nx/find-all-projects.ts | 6 ++++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/plugin-coverage/src/lib/nx/coverage-paths.ts b/packages/plugin-coverage/src/lib/nx/coverage-paths.ts index f3e4b01bd..16faaea92 100644 --- a/packages/plugin-coverage/src/lib/nx/coverage-paths.ts +++ b/packages/plugin-coverage/src/lib/nx/coverage-paths.ts @@ -8,7 +8,7 @@ import type { JestExecutorOptions } from '@nx/jest/src/executors/jest/schema'; import type { VitestExecutorOptions } from '@nx/vite/executors'; import { bold } from 'ansis'; import path from 'node:path'; -import { importModule, ui } from '@code-pushup/utils'; +import { importModule, stringifyError, ui } from '@code-pushup/utils'; import type { CoverageResult } from '../config.js'; /** @@ -21,9 +21,10 @@ async function resolveCachedProjectGraph() { ); try { return readCachedProjectGraph(); - } catch (e) { + } catch (error) { ui().logger.info( - 'Could not read cached project graph, falling back to async creation.', + `Could not read cached project graph, falling back to async creation. + ${stringifyError(error)}`, ); return await createProjectGraphAsync({ exitOnError: false }); } diff --git a/packages/plugin-eslint/src/lib/nx/find-all-projects.ts b/packages/plugin-eslint/src/lib/nx/find-all-projects.ts index 3c9642d0f..4d0825174 100644 --- a/packages/plugin-eslint/src/lib/nx/find-all-projects.ts +++ b/packages/plugin-eslint/src/lib/nx/find-all-projects.ts @@ -1,4 +1,5 @@ import { ui } from '@code-pushup/utils'; +import { stringifyError } from '@code-pushup/utils'; import type { ESLintTarget } from '../config.js'; import { filterProjectGraph } from './filter-project-graph.js'; import { nxProjectsToConfig } from './projects-to-config.js'; @@ -13,9 +14,10 @@ async function resolveCachedProjectGraph() { ); try { return readCachedProjectGraph(); - } catch (e) { + } catch (error) { ui().logger.info( - 'Could not read cached project graph, falling back to async creation.', + `Could not read cached project graph, falling back to async creation. + ${stringifyError(error)}`, ); return await createProjectGraphAsync({ exitOnError: false }); } From 3cc826980afc1f970058f8a6ed89078a184e02de Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Sat, 16 Aug 2025 18:28:22 +0200 Subject: [PATCH 075/111] fix: adjust default inputs --- nx.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nx.json b/nx.json index 931637e1b..288cc976f 100644 --- a/nx.json +++ b/nx.json @@ -235,7 +235,10 @@ "default": [ "{projectRoot}/**/*", "sharedGlobals", - "!{projectRoot}/dist/**/*" + "!{projectRoot}/dist/**/*", + "!{projectRoot}/coverage/**/*", + "!{projectRoot}/.coverage/**/*", + "!{projectRoot}/.code-pushup/**/*" ], "production": [ "default", From df60ab7a084cf5a135a3c0682a841a80b27fc2bf Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Sat, 16 Aug 2025 18:31:44 +0200 Subject: [PATCH 076/111] fix: lint issues --- packages/plugin-coverage/src/lib/nx/coverage-paths.ts | 8 ++++---- packages/plugin-eslint/src/lib/nx/find-all-projects.ts | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/plugin-coverage/src/lib/nx/coverage-paths.ts b/packages/plugin-coverage/src/lib/nx/coverage-paths.ts index 16faaea92..1b3ad581b 100644 --- a/packages/plugin-coverage/src/lib/nx/coverage-paths.ts +++ b/packages/plugin-coverage/src/lib/nx/coverage-paths.ts @@ -1,8 +1,8 @@ /// -import { - type ProjectConfiguration, - type ProjectGraphProjectNode, - type Tree, +import type { + ProjectConfiguration, + ProjectGraphProjectNode, + Tree, } from '@nx/devkit'; import type { JestExecutorOptions } from '@nx/jest/src/executors/jest/schema'; import type { VitestExecutorOptions } from '@nx/vite/executors'; diff --git a/packages/plugin-eslint/src/lib/nx/find-all-projects.ts b/packages/plugin-eslint/src/lib/nx/find-all-projects.ts index 4d0825174..10306f83e 100644 --- a/packages/plugin-eslint/src/lib/nx/find-all-projects.ts +++ b/packages/plugin-eslint/src/lib/nx/find-all-projects.ts @@ -1,5 +1,4 @@ -import { ui } from '@code-pushup/utils'; -import { stringifyError } from '@code-pushup/utils'; +import { stringifyError, ui } from '@code-pushup/utils'; import type { ESLintTarget } from '../config.js'; import { filterProjectGraph } from './filter-project-graph.js'; import { nxProjectsToConfig } from './projects-to-config.js'; From dd9e31487ae9a2de985b5ab78fea71682786856b Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Sat, 16 Aug 2025 18:43:19 +0200 Subject: [PATCH 077/111] fix: update nx.json --- nx.json | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/nx.json b/nx.json index 288cc976f..e0db889c5 100644 --- a/nx.json +++ b/nx.json @@ -232,14 +232,7 @@ } }, "namedInputs": { - "default": [ - "{projectRoot}/**/*", - "sharedGlobals", - "!{projectRoot}/dist/**/*", - "!{projectRoot}/coverage/**/*", - "!{projectRoot}/.coverage/**/*", - "!{projectRoot}/.code-pushup/**/*" - ], + "default": ["{projectRoot}/**/*", "sharedGlobals"], "production": [ "default", "!{projectRoot}/eslint.config.?(c)js", @@ -261,7 +254,12 @@ "code-pushup-jsdocs-inputs": ["default", "code-pushup-inputs"], "code-pushup-typescript-inputs": ["default", "code-pushup-inputs"], "code-pushup-lighthouse-inputs": ["default", "code-pushup-inputs"], - "sharedGlobals": [] + "sharedGlobals": [ + "!{workspaceRoot}/**/dist/**/*", + "!{workspaceRoot}/**/coverage/**/*", + "!{workspaceRoot}/**/.coverage/**/*", + "!{workspaceRoot}/**/.code-pushup/**/*" + ] }, "workspaceLayout": { "appsDir": "examples", From b9b37bfbf0926bdbde684c6946650a377b922f18 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Sat, 16 Aug 2025 19:15:25 +0200 Subject: [PATCH 078/111] fix: update nx.json 2 --- project.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/project.json b/project.json index b18c89e17..36c4cec07 100644 --- a/project.json +++ b/project.json @@ -4,7 +4,9 @@ "targets": { "code-pushup-js-packages": {}, "code-pushup-lighthouse": {}, - "code-pushup-coverage": {}, + "code-pushup-coverage": { + "dependsOn": ["^unit-test", "^int-test"] + }, "code-pushup-eslint": {}, "code-pushup-jsdocs": {}, "code-pushup-typescript": {}, From 0ab3b501721fd7bb6576b4415ab3bed5cc7b7201 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Mon, 18 Aug 2025 16:34:48 +0200 Subject: [PATCH 079/111] fix: use "*" matcher for dependsOn tasks --- nx.json | 2 +- project.json | 11 ++--------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/nx.json b/nx.json index e0db889c5..6e62e1f2e 100644 --- a/nx.json +++ b/nx.json @@ -94,7 +94,7 @@ "cache": true, "outputs": ["{projectRoot}/.code-pushup/coverage/runner-output.json"], "executor": "nx:run-commands", - "dependsOn": ["unit-test", "int-test"], + "dependsOn": ["*-test"], "options": { "command": "node packages/cli/src/index.ts collect", "args": [ diff --git a/project.json b/project.json index 36c4cec07..4bee52545 100644 --- a/project.json +++ b/project.json @@ -5,20 +5,13 @@ "code-pushup-js-packages": {}, "code-pushup-lighthouse": {}, "code-pushup-coverage": { - "dependsOn": ["^unit-test", "^int-test"] + "dependsOn": ["^*-test"] }, "code-pushup-eslint": {}, "code-pushup-jsdocs": {}, "code-pushup-typescript": {}, "code-pushup": { - "dependsOn": [ - "code-pushup-js-packages", - "code-pushup-lighthouse", - "code-pushup-coverage", - "code-pushup-eslint", - "code-pushup-jsdocs", - "code-pushup-typescript" - ], + "dependsOn": ["code-pushup-*"], "executor": "nx:run-commands", "options": { "args": [ From 3cdb563c58731382aba089f9a1910f70f752b56a Mon Sep 17 00:00:00 2001 From: Michael Hladky <10064416+BioPhoton@users.noreply.github.com> Date: Tue, 19 Aug 2025 21:16:19 +0200 Subject: [PATCH 080/111] Update nx.json MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matěj Chalk <34691111+matejchalk@users.noreply.github.com> --- nx.json | 1 - 1 file changed, 1 deletion(-) diff --git a/nx.json b/nx.json index 6e62e1f2e..132eeb489 100644 --- a/nx.json +++ b/nx.json @@ -145,7 +145,6 @@ "--no-progress", "--verbose", "--config={projectRoot}/code-pushup.config.ts", - "--cache.write", "--onlyPlugins=js-packages", "--persist.skipReports", "--persist.outputDir={projectRoot}/.code-pushup" From 787fbf0e85cf39b8838002b77a50f13dc9cc26a8 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Tue, 19 Aug 2025 22:33:10 +0200 Subject: [PATCH 081/111] fix: add fetch 0 --- .github/workflows/code-pushup-fork.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/code-pushup-fork.yml b/.github/workflows/code-pushup-fork.yml index 4dd08dbb1..697ab8450 100644 --- a/.github/workflows/code-pushup-fork.yml +++ b/.github/workflows/code-pushup-fork.yml @@ -25,6 +25,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Set up Node.js uses: actions/setup-node@v4 with: From 51fc91398b96b40af1e84792640f219fb9fbfa4c Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Tue, 19 Aug 2025 23:37:07 +0200 Subject: [PATCH 082/111] fix: rename root project --- code-pushup.config.ts | 20 +++++++++----------- code-pushup.preset.ts | 40 ---------------------------------------- project.json | 2 +- 3 files changed, 10 insertions(+), 52 deletions(-) diff --git a/code-pushup.config.ts b/code-pushup.config.ts index c590b3cd2..4ea96774f 100644 --- a/code-pushup.config.ts +++ b/code-pushup.config.ts @@ -1,28 +1,26 @@ import 'dotenv/config'; -import { z } from 'zod'; import { coverageCoreConfigNx, eslintCoreConfigNx, jsDocsCoreConfig, jsPackagesCoreConfig, lighthouseCoreConfig, - loadEnv, typescriptPluginConfig, } from './code-pushup.preset.js'; import type { CoreConfig } from './packages/models/src/index.js'; import { mergeConfigs } from './packages/utils/src/index.js'; -// load upload configuration from environment -const envSchema = z.object({ - CP_SERVER: z.string().url(), - CP_API_KEY: z.string().min(1), - CP_ORGANIZATION: z.string().min(1), - CP_PROJECT: z.string().min(1), -}); -const projectName = 'cli'; +const project = process.env['NX_TASK_TARGET_PROJECT'] || 'cli-workspace'; const config: CoreConfig = { - ...(await loadEnv(projectName)), + ...(process.env['CP_API_KEY'] && { + upload: { + project, + organization: 'code-pushup', + server: 'https://api.staging.code-pushup.dev/graphql', + apiKey: process.env['CP_API_KEY'], + }, + }), plugins: [], }; diff --git a/code-pushup.preset.ts b/code-pushup.preset.ts index f79259a36..53654ff11 100644 --- a/code-pushup.preset.ts +++ b/code-pushup.preset.ts @@ -1,6 +1,4 @@ /* eslint-disable @nx/enforce-module-boundaries */ -import 'dotenv/config'; -import { z } from 'zod'; import type { CategoryConfig, CoreConfig, @@ -29,44 +27,6 @@ import typescriptPlugin, { getCategories, } from './packages/plugin-typescript/src/index.js'; -/** - * Helper function to load and validate Code PushUp environment variables for upload configuration - */ -export async function loadEnv( - projectName: string | undefined = process.env.NX_TASK_TARGET_PROJECT, -): Promise> { - if (projectName == null || projectName === '') { - throw new Error( - 'loadEnv failed! Project name is not defined. Please run code pushup fit Nx or provide a projectName.', - ); - } - const envSchema = z.object({ - CP_SERVER: z.string().url(), - CP_API_KEY: z.string().min(1), - CP_ORGANIZATION: z.string().min(1), - CP_PROJECT: z.string().optional(), - }); - - const { data: env, success } = await envSchema.safeParseAsync(process.env); - - if (!success || !env) { - return {}; - } - const uploadConfig = { - apiKey: env.CP_API_KEY, - server: env.CP_SERVER, - organization: env.CP_ORGANIZATION, - ...(env.CP_PROJECT - ? { project: env.CP_PROJECT } - : { project: projectName }), - }; - return ( - uploadConfig.apiKey && { - upload: uploadConfig, - } - ); -} - export const jsPackagesCategories: CategoryConfig[] = [ { slug: 'security', diff --git a/project.json b/project.json index 4bee52545..57fa0a3df 100644 --- a/project.json +++ b/project.json @@ -1,5 +1,5 @@ { - "name": "@code-pushup/cli-source", + "name": "cli-workspace", "$schema": "node_modules/nx/schemas/project-schema.json", "targets": { "code-pushup-js-packages": {}, From 458d5007c80e18c3d6e36ce91952d7babac6e62c Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Wed, 20 Aug 2025 01:01:06 +0200 Subject: [PATCH 083/111] chore: adjust caching settings --- nx.json | 78 +++++++++++++++++++++++++++++++++------------------------ 1 file changed, 45 insertions(+), 33 deletions(-) diff --git a/nx.json b/nx.json index 132eeb489..06a08677a 100644 --- a/nx.json +++ b/nx.json @@ -21,11 +21,7 @@ ], "executor": "@nx/vite:test", "options": { - "configFile": "{projectRoot}/vitest.unit.config.ts", - "passWithNoTests": true, - "coverage": { - "enabled": true - } + "configFile": "{projectRoot}/vitest.unit.config.ts" } }, "int-test": { @@ -33,18 +29,19 @@ "outputs": ["{workspaceRoot}/coverage/{projectName}/int-tests/lcov.info"], "executor": "@nx/vite:test", "options": { - "configFile": "{projectRoot}/vitest.int.config.ts", - "passWithNoTests": true, - "coverage": { - "enabled": true - } + "configFile": "{projectRoot}/vitest.int.config.ts" } }, "e2e": { - "dependsOn": ["^build"] + "cache": true, + "dependsOn": ["^build"], + "executor": "@nx/vite:test", + "options": { + "configFile": "{projectRoot}/vitest.e2e.config.ts" + } }, "lint": { - "inputs": ["eslint-inputs"], + "inputs": ["lint-eslint-inputs"], "executor": "@nx/linter:eslint", "outputs": ["{options.outputFile}"], "cache": true, @@ -61,7 +58,7 @@ }, "@nx/vite:test": { "cache": true, - "inputs": ["default", "^production"], + "inputs": ["test-vitest-inputs"], "options": { "passWithNoTests": true, "watch": false @@ -92,6 +89,7 @@ }, "code-pushup-coverage": { "cache": true, + "inputs": ["code-pushup-inputs", "test-vitest-inputs"], "outputs": ["{projectRoot}/.code-pushup/coverage/runner-output.json"], "executor": "nx:run-commands", "dependsOn": ["*-test"], @@ -114,7 +112,7 @@ }, "code-pushup-eslint": { "cache": true, - "inputs": ["code-pushup-eslint-inputs"], + "inputs": ["code-pushup-inputs", "lint-eslint-inputs"], "outputs": ["{projectRoot}/.code-pushup/eslint/runner-output.json"], "executor": "nx:run-commands", "options": { @@ -157,7 +155,7 @@ }, "code-pushup-lighthouse": { "cache": true, - "inputs": ["code-pushup-lighthouse-inputs"], + "inputs": ["code-pushup-inputs", "production", "^production"], "outputs": ["{projectRoot}/.code-pushup/lighthouse/runner-output.json"], "executor": "nx:run-commands", "options": { @@ -179,7 +177,7 @@ }, "code-pushup-jsdocs": { "cache": true, - "inputs": ["code-pushup-jsdocs-inputs"], + "inputs": ["code-pushup-inputs", "typecheck-typescript-inputs"], "outputs": ["{projectRoot}/.code-pushup/jsdocs/runner-output.json"], "executor": "nx:run-commands", "options": { @@ -201,7 +199,7 @@ }, "code-pushup-typescript": { "cache": true, - "inputs": ["code-pushup-typescript-inputs"], + "inputs": ["code-pushup-inputs"], "outputs": ["{projectRoot}/.code-pushup/typescript/runner-output.json"], "executor": "nx:run-commands", "options": { @@ -234,29 +232,43 @@ "default": ["{projectRoot}/**/*", "sharedGlobals"], "production": [ "default", + "!{projectRoot}/README.md", + "!{projectRoot}/CHANGELOG.md", + + "!{projectRoot}/perf/**/*", + "!{projectRoot}/tools/**/*", + "!{projectRoot}/zod2md.config.ts", "!{projectRoot}/eslint.config.?(c)js", + "!{projectRoot}/code-pushup.config.?(*.).?(m)[jt]s", + + "!{projectRoot}/@(test|mocks|mock)/**/*", "!{projectRoot}/**/?(*.)test.[jt]s?(x)?(.snap)", - "!{projectRoot}/tsconfig.test.json", - "!{projectRoot}/src/test-setup.[jt]s", - "!{projectRoot}/test-setup.[jt]s", + "!{projectRoot}/**/?(*.)mocks.[jt]s?(x)", "!{projectRoot}/**/?(*.)mock.[jt]s?(x)", "!{projectRoot}/vitest.@(unit|int|e2e).config.[jt]s", - "!{projectRoot}/@(test|mocks)/**/*", - "!{projectRoot}/perf/**/*", - "!{projectRoot}/tools/**/*", - "!{projectRoot}/code-pushup.config.?(m)[jt]s", - "!{projectRoot}/zod2md.config.ts" + "!{projectRoot}/tsconfig.@(test|tools).json" + ], + "test-vitest-inputs": ["default", { "externalDependencies": ["vitest"] }], + "lint-eslint-inputs": [ + "default", + "^production", + { "externalDependencies": ["eslint"] } + ], + "typecheck-typescript-inputs": [ + "default", + "^production", + { "externalDependencies": ["typescript"] } + ], + "code-pushup-inputs": [ + "default", + { "env": "NODE_OPTIONS" }, + { "env": "TSX_TSCONFIG_PATH" } ], - "eslint-inputs": ["default", "{projectRoot}/eslint.config.?(c)js"], - "code-pushup-inputs": ["{projectRoot}/code-pushup.config.?ts"], - "code-pushup-eslint-inputs": ["eslint-inputs", "code-pushup-inputs"], - "code-pushup-jsdocs-inputs": ["default", "code-pushup-inputs"], - "code-pushup-typescript-inputs": ["default", "code-pushup-inputs"], - "code-pushup-lighthouse-inputs": ["default", "code-pushup-inputs"], "sharedGlobals": [ + { "runtime": "npm --version" }, + { "runtime": "node --version" }, "!{workspaceRoot}/**/dist/**/*", - "!{workspaceRoot}/**/coverage/**/*", - "!{workspaceRoot}/**/.coverage/**/*", + "!{workspaceRoot}/**/(*.)coverage/**/*", "!{workspaceRoot}/**/.code-pushup/**/*" ] }, From 13d03b4d491658c032d5587792b4c20ea0e896b8 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Wed, 20 Aug 2025 01:32:38 +0200 Subject: [PATCH 084/111] chore: fix caching settings --- nx.json | 6 +++--- project.json | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/nx.json b/nx.json index 06a08677a..aea094f85 100644 --- a/nx.json +++ b/nx.json @@ -199,7 +199,7 @@ }, "code-pushup-typescript": { "cache": true, - "inputs": ["code-pushup-inputs"], + "inputs": ["code-pushup-inputs", "typecheck-typescript-inputs"], "outputs": ["{projectRoot}/.code-pushup/typescript/runner-output.json"], "executor": "nx:run-commands", "options": { @@ -251,12 +251,12 @@ "test-vitest-inputs": ["default", { "externalDependencies": ["vitest"] }], "lint-eslint-inputs": [ "default", - "^production", + "production", { "externalDependencies": ["eslint"] } ], "typecheck-typescript-inputs": [ "default", - "^production", + "production", { "externalDependencies": ["typescript"] } ], "code-pushup-inputs": [ diff --git a/project.json b/project.json index 57fa0a3df..27b7f945f 100644 --- a/project.json +++ b/project.json @@ -19,7 +19,8 @@ "--verbose", "--config={projectRoot}/code-pushup.config.ts", "--cache.read", - "--persist.outputDir={projectRoot}/.code-pushup" + "--persist.outputDir={projectRoot}/.code-pushup", + "--upload.project={projectName}" ], "env": { "NODE_OPTIONS": "--import tsx", From 59f9dede0e115b251448cb3a20a63cc0a29a5e47 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Wed, 20 Aug 2025 01:38:58 +0200 Subject: [PATCH 085/111] chore: reduce args --- project.json | 1 - 1 file changed, 1 deletion(-) diff --git a/project.json b/project.json index 27b7f945f..e351c25c9 100644 --- a/project.json +++ b/project.json @@ -17,7 +17,6 @@ "args": [ "--no-progress", "--verbose", - "--config={projectRoot}/code-pushup.config.ts", "--cache.read", "--persist.outputDir={projectRoot}/.code-pushup", "--upload.project={projectName}" From f7005d4d28a37a73545b1cf07434f15c854c5bef Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Wed, 20 Aug 2025 01:44:50 +0200 Subject: [PATCH 086/111] chore: rename GH actions --- .github/workflows/code-pushup-fork.yml | 4 ++-- .github/workflows/code-pushup.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/code-pushup-fork.yml b/.github/workflows/code-pushup-fork.yml index 697ab8450..fdefc6ce3 100644 --- a/.github/workflows/code-pushup-fork.yml +++ b/.github/workflows/code-pushup-fork.yml @@ -1,4 +1,4 @@ -name: Code PushUp (fork) +name: Code PushUp - Centralized (fork) # separated from code-pushup.yml for security reasons # => requires permissions to create PR comment @@ -20,7 +20,7 @@ permissions: jobs: code-pushup: runs-on: ubuntu-latest - name: Code PushUp + name: Run central layout (fork) if: github.event.pull_request.head.repo.fork steps: - name: Checkout repository diff --git a/.github/workflows/code-pushup.yml b/.github/workflows/code-pushup.yml index 56a8fd2fa..307dc5f51 100644 --- a/.github/workflows/code-pushup.yml +++ b/.github/workflows/code-pushup.yml @@ -1,4 +1,4 @@ -name: Code PushUp +name: Code PushUp - Centralized on: push: @@ -15,7 +15,7 @@ permissions: jobs: code-pushup: runs-on: ubuntu-latest - name: Code PushUp + name: Run central layout # ignore PRs from forks, handled by code-pushup-fork.yml if: ${{ !github.event.pull_request.head.repo.fork }} env: From 9192a606aa0e837d62eee801ffb60f7af510449d Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Wed, 20 Aug 2025 02:56:33 +0200 Subject: [PATCH 087/111] chore: reduce target options --- project.json | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/project.json b/project.json index e351c25c9..ac255666e 100644 --- a/project.json +++ b/project.json @@ -20,11 +20,7 @@ "--cache.read", "--persist.outputDir={projectRoot}/.code-pushup", "--upload.project={projectName}" - ], - "env": { - "NODE_OPTIONS": "--import tsx", - "TSX_TSCONFIG_PATH": "tsconfig.base.json" - } + ] } } } From a051e404b4260cef916f3b63537288a2f3e38547 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Wed, 20 Aug 2025 04:24:47 +0200 Subject: [PATCH 088/111] chore: test bail --- .github/workflows/code-pushup-fork.yml | 2 +- .github/workflows/code-pushup.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/code-pushup-fork.yml b/.github/workflows/code-pushup-fork.yml index fdefc6ce3..9a3e90673 100644 --- a/.github/workflows/code-pushup-fork.yml +++ b/.github/workflows/code-pushup-fork.yml @@ -39,4 +39,4 @@ jobs: - name: Run Code PushUp action uses: code-pushup/github-action@v0 with: - bin: npx nx affected -t code-pushup --parallel=3 -- + bin: npx nx affected -t code-pushup --nx-bail --parallel=3 -- diff --git a/.github/workflows/code-pushup.yml b/.github/workflows/code-pushup.yml index 307dc5f51..a04deda2a 100644 --- a/.github/workflows/code-pushup.yml +++ b/.github/workflows/code-pushup.yml @@ -40,4 +40,4 @@ jobs: - name: Run Code PushUp action uses: code-pushup/github-action@v0 with: - bin: npx nx affected -t code-pushup --parallel=3 -- + bin: npx nx affected -t code-pushup --nx-bail --parallel=3 -- From 61b4d79ffb8a78a334d20f95b35adf860ada5ade Mon Sep 17 00:00:00 2001 From: Michael Hladky <10064416+BioPhoton@users.noreply.github.com> Date: Wed, 20 Aug 2025 14:32:14 +0200 Subject: [PATCH 089/111] Update nx.json MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matěj Chalk <34691111+matejchalk@users.noreply.github.com> --- nx.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/nx.json b/nx.json index aea094f85..fa9d87e8e 100644 --- a/nx.json +++ b/nx.json @@ -251,12 +251,10 @@ "test-vitest-inputs": ["default", { "externalDependencies": ["vitest"] }], "lint-eslint-inputs": [ "default", - "production", { "externalDependencies": ["eslint"] } ], "typecheck-typescript-inputs": [ "default", - "production", { "externalDependencies": ["typescript"] } ], "code-pushup-inputs": [ From 84bb7e354faaad558ca945a99e5b772fe15a6bcb Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Wed, 20 Aug 2025 14:38:28 +0200 Subject: [PATCH 090/111] fix: fix format --- nx.json | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/nx.json b/nx.json index fa9d87e8e..c48edaa61 100644 --- a/nx.json +++ b/nx.json @@ -249,10 +249,7 @@ "!{projectRoot}/tsconfig.@(test|tools).json" ], "test-vitest-inputs": ["default", { "externalDependencies": ["vitest"] }], - "lint-eslint-inputs": [ - "default", - { "externalDependencies": ["eslint"] } - ], + "lint-eslint-inputs": ["default", { "externalDependencies": ["eslint"] }], "typecheck-typescript-inputs": [ "default", { "externalDependencies": ["typescript"] } From d6cc8b32740419840479b0d1caf460f695463334 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Wed, 20 Aug 2025 14:46:32 +0200 Subject: [PATCH 091/111] fix: adjust format --- .github/workflows/code-pushup-fork.yml | 4 ++-- .github/workflows/code-pushup.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/code-pushup-fork.yml b/.github/workflows/code-pushup-fork.yml index 9a3e90673..4bfb779c8 100644 --- a/.github/workflows/code-pushup-fork.yml +++ b/.github/workflows/code-pushup-fork.yml @@ -1,4 +1,4 @@ -name: Code PushUp - Centralized (fork) +name: Code PushUp - Standalone Mode (fork) # separated from code-pushup.yml for security reasons # => requires permissions to create PR comment @@ -20,7 +20,7 @@ permissions: jobs: code-pushup: runs-on: ubuntu-latest - name: Run central layout (fork) + name: Run code pushUp in standalone mode (fork) if: github.event.pull_request.head.repo.fork steps: - name: Checkout repository diff --git a/.github/workflows/code-pushup.yml b/.github/workflows/code-pushup.yml index a04deda2a..c55223d86 100644 --- a/.github/workflows/code-pushup.yml +++ b/.github/workflows/code-pushup.yml @@ -1,4 +1,4 @@ -name: Code PushUp - Centralized +name: Code PushUp - Standalone Mode on: push: @@ -15,7 +15,7 @@ permissions: jobs: code-pushup: runs-on: ubuntu-latest - name: Run central layout + name: Run code pushUp in standalone mode # ignore PRs from forks, handled by code-pushup-fork.yml if: ${{ !github.event.pull_request.head.repo.fork }} env: From 8f6c5aa209b3bec641d055908b6c7c7762166efc Mon Sep 17 00:00:00 2001 From: Michael Hladky <10064416+BioPhoton@users.noreply.github.com> Date: Wed, 20 Aug 2025 16:01:24 +0200 Subject: [PATCH 092/111] Update .github/workflows/code-pushup-fork.yml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matěj Chalk <34691111+matejchalk@users.noreply.github.com> --- .github/workflows/code-pushup-fork.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/code-pushup-fork.yml b/.github/workflows/code-pushup-fork.yml index 4bfb779c8..3f4c3e77f 100644 --- a/.github/workflows/code-pushup-fork.yml +++ b/.github/workflows/code-pushup-fork.yml @@ -20,7 +20,7 @@ permissions: jobs: code-pushup: runs-on: ubuntu-latest - name: Run code pushUp in standalone mode (fork) + name: Run Code PushUp in standalone mode (fork) if: github.event.pull_request.head.repo.fork steps: - name: Checkout repository From 0701f3bd0460d051eb0c95e7164bc7a76302c3ed Mon Sep 17 00:00:00 2001 From: Michael Hladky <10064416+BioPhoton@users.noreply.github.com> Date: Wed, 20 Aug 2025 16:01:31 +0200 Subject: [PATCH 093/111] Update .github/workflows/code-pushup.yml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matěj Chalk <34691111+matejchalk@users.noreply.github.com> --- .github/workflows/code-pushup.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/code-pushup.yml b/.github/workflows/code-pushup.yml index c55223d86..e87541602 100644 --- a/.github/workflows/code-pushup.yml +++ b/.github/workflows/code-pushup.yml @@ -15,7 +15,7 @@ permissions: jobs: code-pushup: runs-on: ubuntu-latest - name: Run code pushUp in standalone mode + name: Run Code PushUp in standalone mode # ignore PRs from forks, handled by code-pushup-fork.yml if: ${{ !github.event.pull_request.head.repo.fork }} env: From 95ac32fad5d3f0872de57fe61eae10c9100c3c97 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Wed, 20 Aug 2025 20:19:41 +0200 Subject: [PATCH 094/111] chore: adjust GH action for CP --- .github/workflows/code-pushup.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/code-pushup.yml b/.github/workflows/code-pushup.yml index e87541602..c362164e1 100644 --- a/.github/workflows/code-pushup.yml +++ b/.github/workflows/code-pushup.yml @@ -40,4 +40,4 @@ jobs: - name: Run Code PushUp action uses: code-pushup/github-action@v0 with: - bin: npx nx affected -t code-pushup --nx-bail --parallel=3 -- + bin: npx nx code-pushup --nx-bail --parallel=3 -- From 5dae3796cbb0aca9b518f54fce6a35c0b8036a1b Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Wed, 20 Aug 2025 20:24:19 +0200 Subject: [PATCH 095/111] chore: adjust GH action for CP 2 --- .github/workflows/code-pushup-fork.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/code-pushup-fork.yml b/.github/workflows/code-pushup-fork.yml index 3f4c3e77f..71d859837 100644 --- a/.github/workflows/code-pushup-fork.yml +++ b/.github/workflows/code-pushup-fork.yml @@ -39,4 +39,4 @@ jobs: - name: Run Code PushUp action uses: code-pushup/github-action@v0 with: - bin: npx nx affected -t code-pushup --nx-bail --parallel=3 -- + bin: npx nx code-pushup --nx-bail --parallel=3 -- From e7a50bd37c5d592e9e3b8d74e5c5d41b164c8d5b Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Wed, 20 Aug 2025 20:48:59 +0200 Subject: [PATCH 096/111] chore: add nxCloudId --- nx.json | 1 + 1 file changed, 1 insertion(+) diff --git a/nx.json b/nx.json index c48edaa61..a7038c478 100644 --- a/nx.json +++ b/nx.json @@ -1,5 +1,6 @@ { "$schema": "./node_modules/nx/schemas/nx-schema.json", + "nxCloudId": "65d4d862d2adb16a45a4bc7c", "targetDefaults": { "build": { "dependsOn": ["^build"], From 23d9f71755fb9db127ca21995a022823fafcb006 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Wed, 20 Aug 2025 20:50:30 +0200 Subject: [PATCH 097/111] fix: adjust GH actions --- .github/workflows/code-pushup-fork.yml | 2 +- .github/workflows/code-pushup.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/code-pushup-fork.yml b/.github/workflows/code-pushup-fork.yml index 71d859837..e8a2a00f9 100644 --- a/.github/workflows/code-pushup-fork.yml +++ b/.github/workflows/code-pushup-fork.yml @@ -20,7 +20,7 @@ permissions: jobs: code-pushup: runs-on: ubuntu-latest - name: Run Code PushUp in standalone mode (fork) + name: Run Code PushUp (fork) if: github.event.pull_request.head.repo.fork steps: - name: Checkout repository diff --git a/.github/workflows/code-pushup.yml b/.github/workflows/code-pushup.yml index c362164e1..b29647217 100644 --- a/.github/workflows/code-pushup.yml +++ b/.github/workflows/code-pushup.yml @@ -15,7 +15,7 @@ permissions: jobs: code-pushup: runs-on: ubuntu-latest - name: Run Code PushUp in standalone mode + name: Run Code PushUp # ignore PRs from forks, handled by code-pushup-fork.yml if: ${{ !github.event.pull_request.head.repo.fork }} env: From 7c792f934018496e22c6cf344234bd51ea5dd539 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Wed, 20 Aug 2025 21:16:52 +0200 Subject: [PATCH 098/111] chore: move config into targets --- nx.json | 61 +++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 19 deletions(-) diff --git a/nx.json b/nx.json index a7038c478..da88ac833 100644 --- a/nx.json +++ b/nx.json @@ -17,20 +17,32 @@ }, "unit-test": { "cache": true, + "inputs": ["test-vitest-inputs"], "outputs": [ "{workspaceRoot}/coverage/{projectName}/unit-tests/lcov.info" ], "executor": "@nx/vite:test", "options": { - "configFile": "{projectRoot}/vitest.unit.config.ts" + "configFile": "{projectRoot}/vitest.unit.config.ts", + "passWithNoTests": true, + "watch": false, + "coverage": { + "enabled": true + } } }, "int-test": { "cache": true, + "inputs": ["test-vitest-inputs"], "outputs": ["{workspaceRoot}/coverage/{projectName}/int-tests/lcov.info"], "executor": "@nx/vite:test", "options": { - "configFile": "{projectRoot}/vitest.int.config.ts" + "configFile": "{projectRoot}/vitest.int.config.ts", + "passWithNoTests": true, + "watch": false, + "coverage": { + "enabled": true + } } }, "e2e": { @@ -57,14 +69,7 @@ "nxv-pkg-install": { "parallelism": false }, - "@nx/vite:test": { - "cache": true, - "inputs": ["test-vitest-inputs"], - "options": { - "passWithNoTests": true, - "watch": false - } - }, + "@nx/vite:test": {}, "code-pushup": { "cache": false, "outputs": [ @@ -235,13 +240,11 @@ "default", "!{projectRoot}/README.md", "!{projectRoot}/CHANGELOG.md", - "!{projectRoot}/perf/**/*", "!{projectRoot}/tools/**/*", "!{projectRoot}/zod2md.config.ts", "!{projectRoot}/eslint.config.?(c)js", "!{projectRoot}/code-pushup.config.?(*.).?(m)[jt]s", - "!{projectRoot}/@(test|mocks|mock)/**/*", "!{projectRoot}/**/?(*.)test.[jt]s?(x)?(.snap)", "!{projectRoot}/**/?(*.)mocks.[jt]s?(x)", @@ -249,20 +252,40 @@ "!{projectRoot}/vitest.@(unit|int|e2e).config.[jt]s", "!{projectRoot}/tsconfig.@(test|tools).json" ], - "test-vitest-inputs": ["default", { "externalDependencies": ["vitest"] }], - "lint-eslint-inputs": ["default", { "externalDependencies": ["eslint"] }], + "test-vitest-inputs": [ + "default", + { + "externalDependencies": ["vitest"] + } + ], + "lint-eslint-inputs": [ + "default", + { + "externalDependencies": ["eslint"] + } + ], "typecheck-typescript-inputs": [ "default", - { "externalDependencies": ["typescript"] } + { + "externalDependencies": ["typescript"] + } ], "code-pushup-inputs": [ "default", - { "env": "NODE_OPTIONS" }, - { "env": "TSX_TSCONFIG_PATH" } + { + "env": "NODE_OPTIONS" + }, + { + "env": "TSX_TSCONFIG_PATH" + } ], "sharedGlobals": [ - { "runtime": "npm --version" }, - { "runtime": "node --version" }, + { + "runtime": "npm --version" + }, + { + "runtime": "node --version" + }, "!{workspaceRoot}/**/dist/**/*", "!{workspaceRoot}/**/(*.)coverage/**/*", "!{workspaceRoot}/**/.code-pushup/**/*" From d114076a17fcc66121e851b25935f5344fb85d55 Mon Sep 17 00:00:00 2001 From: Michael Hladky <10064416+BioPhoton@users.noreply.github.com> Date: Thu, 21 Aug 2025 13:30:03 +0200 Subject: [PATCH 099/111] Update nx.json MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matěj Chalk <34691111+matejchalk@users.noreply.github.com> --- nx.json | 1 - 1 file changed, 1 deletion(-) diff --git a/nx.json b/nx.json index da88ac833..d0b7cf407 100644 --- a/nx.json +++ b/nx.json @@ -69,7 +69,6 @@ "nxv-pkg-install": { "parallelism": false }, - "@nx/vite:test": {}, "code-pushup": { "cache": false, "outputs": [ From cfaedf8282a893856d70a9d31998409251fde7b4 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Fri, 22 Aug 2025 00:32:49 +0200 Subject: [PATCH 100/111] fix: remove cloud id --- nx.json | 1 - 1 file changed, 1 deletion(-) diff --git a/nx.json b/nx.json index d0b7cf407..f55437ff1 100644 --- a/nx.json +++ b/nx.json @@ -1,6 +1,5 @@ { "$schema": "./node_modules/nx/schemas/nx-schema.json", - "nxCloudId": "65d4d862d2adb16a45a4bc7c", "targetDefaults": { "build": { "dependsOn": ["^build"], From 2733442799a89a83e4ff81e3456b08533efab0b1 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Fri, 22 Aug 2025 00:52:06 +0200 Subject: [PATCH 101/111] fix: wip --- nx.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/nx.json b/nx.json index f55437ff1..bdb217ca9 100644 --- a/nx.json +++ b/nx.json @@ -25,9 +25,7 @@ "configFile": "{projectRoot}/vitest.unit.config.ts", "passWithNoTests": true, "watch": false, - "coverage": { - "enabled": true - } + "coverage": { "enabled": true } } }, "int-test": { From c176d3713b4bc71594311513e110cab83fc3e937 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Fri, 22 Aug 2025 01:00:16 +0200 Subject: [PATCH 102/111] chore: cache js-packages and invalidate daily --- nx.json | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/nx.json b/nx.json index bdb217ca9..ad1093502 100644 --- a/nx.json +++ b/nx.json @@ -135,8 +135,12 @@ } }, "code-pushup-js-packages": { - "cache": false, - "inputs": [], + "cache": true, + "inputs": [ + { + "runtime": "date +%Y-%m-%d" + } + ], "outputs": ["{projectRoot}/.code-pushup/js-packages/runner-output.json"], "executor": "nx:run-commands", "options": { From e748af907801dca8961cf41afd48a1b3acd5ad03 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Fri, 22 Aug 2025 01:15:19 +0200 Subject: [PATCH 103/111] chore: update inputs --- nx.json | 118 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/nx.json b/nx.json index ad1093502..053a8525b 100644 --- a/nx.json +++ b/nx.json @@ -1,5 +1,62 @@ { "$schema": "./node_modules/nx/schemas/nx-schema.json", + "namedInputs": { + "default": ["{projectRoot}/**/*", "sharedGlobals"], + "production": [ + "default", + "!{projectRoot}/README.md", + "!{projectRoot}/CHANGELOG.md", + "!{projectRoot}/perf/**/*", + "!{projectRoot}/tools/**/*", + "!{projectRoot}/zod2md.config.ts", + "!{projectRoot}/eslint.config.?(c)js", + "!{workspaceRoot}/**/.code-pushup/**/*", + "!{projectRoot}/code-pushup.config.?(*.).?(m)[jt]s", + "!{projectRoot}/@(test|mocks|mock)/**/*", + "!{projectRoot}/**/?(*.)test.[jt]s?(x)?(.snap)", + "!{projectRoot}/**/?(*.)mocks.[jt]s?(x)", + "!{projectRoot}/**/?(*.)mock.[jt]s?(x)", + "!{projectRoot}/vitest.@(unit|int|e2e).config.[jt]s", + "!{workspaceRoot}/**/dist/**/*", + "!{projectRoot}/tsconfig.@(test|tools).json", + "!{workspaceRoot}/**/(*.)coverage/**/*" + ], + "test-vitest-inputs": [ + "default", + { + "externalDependencies": ["vitest"] + } + ], + "lint-eslint-inputs": [ + "default", + { + "externalDependencies": ["eslint"] + } + ], + "typecheck-typescript-inputs": [ + "default", + { + "externalDependencies": ["typescript"] + } + ], + "code-pushup-inputs": [ + "default", + { + "env": "NODE_OPTIONS" + }, + { + "env": "TSX_TSCONFIG_PATH" + } + ], + "sharedGlobals": [ + { + "runtime": "npm --version" + }, + { + "runtime": "node --version" + } + ] + }, "targetDefaults": { "build": { "dependsOn": ["^build"], @@ -135,7 +192,7 @@ } }, "code-pushup-js-packages": { - "cache": true, + "cache": false, "inputs": [ { "runtime": "date +%Y-%m-%d" @@ -150,7 +207,7 @@ "--verbose", "--config={projectRoot}/code-pushup.config.ts", "--onlyPlugins=js-packages", - "--persist.skipReports", + "--persist.outputDir={projectRoot}/.code-pushup" ], "env": { @@ -234,63 +291,6 @@ } } }, - "namedInputs": { - "default": ["{projectRoot}/**/*", "sharedGlobals"], - "production": [ - "default", - "!{projectRoot}/README.md", - "!{projectRoot}/CHANGELOG.md", - "!{projectRoot}/perf/**/*", - "!{projectRoot}/tools/**/*", - "!{projectRoot}/zod2md.config.ts", - "!{projectRoot}/eslint.config.?(c)js", - "!{projectRoot}/code-pushup.config.?(*.).?(m)[jt]s", - "!{projectRoot}/@(test|mocks|mock)/**/*", - "!{projectRoot}/**/?(*.)test.[jt]s?(x)?(.snap)", - "!{projectRoot}/**/?(*.)mocks.[jt]s?(x)", - "!{projectRoot}/**/?(*.)mock.[jt]s?(x)", - "!{projectRoot}/vitest.@(unit|int|e2e).config.[jt]s", - "!{projectRoot}/tsconfig.@(test|tools).json" - ], - "test-vitest-inputs": [ - "default", - { - "externalDependencies": ["vitest"] - } - ], - "lint-eslint-inputs": [ - "default", - { - "externalDependencies": ["eslint"] - } - ], - "typecheck-typescript-inputs": [ - "default", - { - "externalDependencies": ["typescript"] - } - ], - "code-pushup-inputs": [ - "default", - { - "env": "NODE_OPTIONS" - }, - { - "env": "TSX_TSCONFIG_PATH" - } - ], - "sharedGlobals": [ - { - "runtime": "npm --version" - }, - { - "runtime": "node --version" - }, - "!{workspaceRoot}/**/dist/**/*", - "!{workspaceRoot}/**/(*.)coverage/**/*", - "!{workspaceRoot}/**/.code-pushup/**/*" - ] - }, "workspaceLayout": { "appsDir": "examples", "libsDir": "packages" From 828d8fc02b93bb5b7d8ff40904b026aaf432926f Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Fri, 22 Aug 2025 01:50:02 +0200 Subject: [PATCH 104/111] fix: test caching issue --- .github/workflows/code-pushup.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/code-pushup.yml b/.github/workflows/code-pushup.yml index b29647217..a5c1a83c6 100644 --- a/.github/workflows/code-pushup.yml +++ b/.github/workflows/code-pushup.yml @@ -40,4 +40,4 @@ jobs: - name: Run Code PushUp action uses: code-pushup/github-action@v0 with: - bin: npx nx code-pushup --nx-bail --parallel=3 -- + bin: npx nx code-pushup --skipNxCache --nx-bail --parallel=3 -- From bd4fb1f10e1f00fd5312fff78e8d3d271debbc67 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Fri, 22 Aug 2025 02:11:22 +0200 Subject: [PATCH 105/111] fix: build step --- packages/models/transformers/package.json | 5 ++++- packages/models/transformers/project.json | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/models/transformers/package.json b/packages/models/transformers/package.json index 4d245947f..e5d33d01b 100644 --- a/packages/models/transformers/package.json +++ b/packages/models/transformers/package.json @@ -7,5 +7,8 @@ "dependencies": { "typescript": "^5.5.4", "ts-patch": "^3.3.0" - } + }, + "files": [ + "src" + ] } diff --git a/packages/models/transformers/project.json b/packages/models/transformers/project.json index fdd783682..b5e7e7317 100644 --- a/packages/models/transformers/project.json +++ b/packages/models/transformers/project.json @@ -9,7 +9,7 @@ "outputs": ["{options.outputPath}"], "dependsOn": [{ "target": "pre-build" }], "options": { - "outputPath": "dist/packages/models-transformers", + "outputPath": "{projectRoot}/dist", "main": "packages/models/transformers/src/index.ts", "tsConfig": "packages/models/transformers/tsconfig.lib.json" } From 08922458765d6beebb42082c379f48f46507a63e Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Fri, 22 Aug 2025 03:33:47 +0200 Subject: [PATCH 106/111] fix: add required options to build target --- package-lock.json | 56 ++++++++++++++++--- package.json | 2 +- packages/ci/project.json | 6 +- packages/cli/project.json | 6 +- packages/core/project.json | 6 +- packages/create-cli/project.json | 6 +- packages/models/project.json | 10 +++- .../models/transformers/tsconfig.lib.json | 2 +- packages/models/tsconfig.lib.json | 2 +- packages/nx-plugin/project.json | 1 + packages/plugin-coverage/project.json | 6 +- packages/plugin-eslint/project.json | 6 +- packages/plugin-js-packages/project.json | 6 +- packages/plugin-jsdocs/project.json | 6 +- packages/plugin-lighthouse/project.json | 6 +- packages/plugin-typescript/project.json | 6 +- packages/utils/project.json | 6 +- 17 files changed, 116 insertions(+), 23 deletions(-) diff --git a/package-lock.json b/package-lock.json index 120439704..598c886e7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -50,7 +50,7 @@ "@nx/react": "19.8.13", "@nx/vite": "19.8.13", "@nx/workspace": "19.8.13", - "@push-based/nx-verdaccio": "^0.0.0", + "@push-based/nx-verdaccio": "^0.0.4", "@swc-node/register": "1.9.2", "@swc/cli": "0.3.14", "@swc/core": "1.5.7", @@ -5977,9 +5977,9 @@ } }, "node_modules/@push-based/nx-verdaccio": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/@push-based/nx-verdaccio/-/nx-verdaccio-0.0.0.tgz", - "integrity": "sha512-uQTjzSnnRKGqViegKcE42a/Rn1OQnsbEeG/xgoRIu+9SwNBItLvWMigSXGfbU6IgIYb3TUzbD7w7V18TAwwXmA==", + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@push-based/nx-verdaccio/-/nx-verdaccio-0.0.4.tgz", + "integrity": "sha512-wavx6fXz97C2i4xgc55GEyUsSag2PdY+LpWsibCnkn/5jv026UVSxjF7d8A+u9tV3X7kB6NrdaFb1+DYxi/7PQ==", "dev": true, "license": "MIT", "dependencies": { @@ -6371,6 +6371,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -6384,6 +6385,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } @@ -6393,6 +6395,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -6406,6 +6409,7 @@ "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-19.8.0.tgz", "integrity": "sha512-LehpQ2D1687+JWaUpW84NPuXsQuPosmts66LShPT4+6KozB4gd0hJGAXNXpjNs9CUfLyNf8rRdEeqNjWnPYEmA==", "dev": true, + "license": "MIT", "dependencies": { "@nx/devkit": "19.8.0" } @@ -6415,6 +6419,7 @@ "resolved": "https://registry.npmjs.org/@nrwl/js/-/js-19.8.0.tgz", "integrity": "sha512-agmIwKD6zK0l+aIEhDv3VuPW10rn5fhHeif3k5q9EgT47QL2gCNzU54oYpuXoKeenJCsDMzOEkJb1IsglVas6g==", "dev": true, + "license": "MIT", "dependencies": { "@nx/js": "19.8.0" } @@ -6424,6 +6429,7 @@ "resolved": "https://registry.npmjs.org/@nrwl/tao/-/tao-19.8.0.tgz", "integrity": "sha512-tybyYdhHNfyBRb8SOc/SasT1iwjYkp/QibS8L3ayTvpvvzJpNr8BpuTznQWIkaIjilflmcdHl+rMiQDqwABqpg==", "dev": true, + "license": "MIT", "dependencies": { "nx": "19.8.0", "tslib": "^2.3.0" @@ -6437,6 +6443,7 @@ "resolved": "https://registry.npmjs.org/@nrwl/vite/-/vite-19.8.0.tgz", "integrity": "sha512-Nux7PN5HYFnSbVj0lVIhgMRkfJ7AYRBr8lXDsJBFboxUtmnPGpG5aV6o/9Fu2XD/eiLBsHCmMcusqkD0+jCvMA==", "dev": true, + "license": "MIT", "dependencies": { "@nx/vite": "19.8.0" } @@ -6446,6 +6453,7 @@ "resolved": "https://registry.npmjs.org/@nrwl/workspace/-/workspace-19.8.0.tgz", "integrity": "sha512-HSN0GML7RaVUSRD3lOc07atCjs4Vzs3Jgs9/7+zFtldKsmsY4GzYIWpJ4G6IDl9u3YJwTKtRmuj5BVI7G+ZGmw==", "dev": true, + "license": "MIT", "dependencies": { "@nx/workspace": "19.8.0" } @@ -6455,6 +6463,7 @@ "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-19.8.0.tgz", "integrity": "sha512-nPaKHF0m2KONlt8GXjN9EhFo+NOvJnFcK6ujKFFLAyZ4TACY4F1FCjSHFTjYI82j+WukzuyjSmY9wzxYughWIQ==", "dev": true, + "license": "MIT", "dependencies": { "@nrwl/devkit": "19.8.0", "ejs": "^3.1.7", @@ -6475,6 +6484,7 @@ "resolved": "https://registry.npmjs.org/@nx/js/-/js-19.8.0.tgz", "integrity": "sha512-gexu1nYN3Hl3+yNuowgfd3sW5uooMKx9Dg6FPWWn/27+eJlTny5A2nQ3YR85yKRiJbNEP23am4le788pyVq2MQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/core": "^7.23.2", "@babel/plugin-proposal-decorators": "^7.22.7", @@ -6523,6 +6533,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -6539,6 +6550,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -6555,6 +6567,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -6571,6 +6584,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -6587,6 +6601,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -6603,6 +6618,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -6619,6 +6635,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -6635,6 +6652,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -6651,6 +6669,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -6667,6 +6686,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -6680,6 +6700,7 @@ "resolved": "https://registry.npmjs.org/@nx/vite/-/vite-19.8.0.tgz", "integrity": "sha512-Krok+zalc6as1w+V+D/mmY+vh5qKdkvz4omMds2k3d+RQNxIb7Mh78ueGVQr5zRtR9CKSSPvDMtUklnjDlp1SQ==", "dev": true, + "license": "MIT", "dependencies": { "@nrwl/vite": "19.8.0", "@nx/devkit": "19.8.0", @@ -6700,6 +6721,7 @@ "resolved": "https://registry.npmjs.org/@nx/workspace/-/workspace-19.8.0.tgz", "integrity": "sha512-8/NHRuJAqurNaFIUuSZdV8qNqiFykXlHjPp6E4raNmB8seIKYJVeYZgw9D7d5piOuLHA3o0JWSKJQ3nBElfCBw==", "dev": true, + "license": "MIT", "dependencies": { "@nrwl/workspace": "19.8.0", "@nx/devkit": "19.8.0", @@ -6715,6 +6737,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -6730,6 +6753,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -6746,6 +6770,7 @@ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", "dev": true, + "license": "MIT", "dependencies": { "restore-cursor": "^3.1.0" }, @@ -6758,6 +6783,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -6769,13 +6795,15 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@push-based/nx-verdaccio/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@push-based/nx-verdaccio/node_modules/esbuild": { "version": "0.19.12", @@ -6821,6 +6849,7 @@ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -6837,6 +6866,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -6849,6 +6879,7 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -6858,6 +6889,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -6867,6 +6899,7 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -6876,6 +6909,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -6892,6 +6926,7 @@ "integrity": "sha512-zD1ZvkfxECrd9QnvUyAUVLESmjl0bpIhB1gLcYN2BqsCkB1vkngbxIvXDorI98keOVEfHzeuwNSkufQNls1hug==", "dev": true, "hasInstallScript": true, + "license": "MIT", "dependencies": { "@napi-rs/wasm-runtime": "0.2.4", "@nrwl/tao": "19.8.0", @@ -6963,6 +6998,7 @@ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, + "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" }, @@ -6978,6 +7014,7 @@ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", "dev": true, + "license": "MIT", "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" @@ -6990,13 +7027,15 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/@push-based/nx-verdaccio/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -7011,6 +7050,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -7023,6 +7063,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -7035,6 +7076,7 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.13.tgz", "integrity": "sha512-/9ovhv2M2dGTuA+dY93B9trfyWMDRQw2jdVBhHNP6wr0oF34wG2i/N55801iZIpgUpnHDm4F/FabGQLyc+eOgg==", "dev": true, + "license": "MIT", "dependencies": { "esbuild": "^0.19.3", "postcss": "^8.4.32", diff --git a/package.json b/package.json index 1c6ddc846..31430d0c0 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "@nx/react": "19.8.13", "@nx/vite": "19.8.13", "@nx/workspace": "19.8.13", - "@push-based/nx-verdaccio": "^0.0.0", + "@push-based/nx-verdaccio": "^0.0.4", "@swc-node/register": "1.9.2", "@swc/cli": "0.3.14", "@swc/core": "1.5.7", diff --git a/packages/ci/project.json b/packages/ci/project.json index 9215f87b3..aa2e675fd 100644 --- a/packages/ci/project.json +++ b/packages/ci/project.json @@ -4,7 +4,11 @@ "sourceRoot": "packages/ci/src", "projectType": "library", "targets": { - "build": {}, + "build": { + "options": { + "outputPath": "{projectRoot}/dist" + } + }, "lint": {}, "unit-test": {}, "int-test": {} diff --git a/packages/cli/project.json b/packages/cli/project.json index bc3b384a7..8eff5f6b8 100644 --- a/packages/cli/project.json +++ b/packages/cli/project.json @@ -4,7 +4,11 @@ "sourceRoot": "packages/cli/src", "projectType": "library", "targets": { - "build": {}, + "build": { + "options": { + "outputPath": "{projectRoot}/dist" + } + }, "lint": {}, "unit-test": {}, "int-test": {}, diff --git a/packages/core/project.json b/packages/core/project.json index 4924717c5..a23d58f28 100644 --- a/packages/core/project.json +++ b/packages/core/project.json @@ -4,7 +4,11 @@ "sourceRoot": "packages/core/src", "projectType": "library", "targets": { - "build": {}, + "build": { + "options": { + "outputPath": "{projectRoot}/dist" + } + }, "lint": {}, "unit-test": {}, "int-test": {} diff --git a/packages/create-cli/project.json b/packages/create-cli/project.json index c2bc6ef60..eb3db2534 100644 --- a/packages/create-cli/project.json +++ b/packages/create-cli/project.json @@ -4,7 +4,11 @@ "sourceRoot": "packages/create-cli/src", "projectType": "library", "targets": { - "build": {}, + "build": { + "options": { + "outputPath": "{projectRoot}/dist" + } + }, "lint": {}, "unit-test": {}, "exec-node": { diff --git a/packages/models/project.json b/packages/models/project.json index 15981781f..90233094f 100644 --- a/packages/models/project.json +++ b/packages/models/project.json @@ -14,8 +14,14 @@ "dependsOn": [ "^build", "generate-docs", - { "projects": "models-transformers", "target": "build" } - ] + { + "projects": "models-transformers", + "target": "build" + } + ], + "options": { + "outputPath": "{projectRoot}/dist" + } }, "lint": {}, "unit-test": {} diff --git a/packages/models/transformers/tsconfig.lib.json b/packages/models/transformers/tsconfig.lib.json index fa583ace0..48174f134 100644 --- a/packages/models/transformers/tsconfig.lib.json +++ b/packages/models/transformers/tsconfig.lib.json @@ -1,7 +1,7 @@ { "extends": "./tsconfig.json", "compilerOptions": { - "outDir": "../../../dist/packages/models-transformers", + "outDir": "./dist", "rootDir": "./", "module": "commonjs", "types": ["node"] diff --git a/packages/models/tsconfig.lib.json b/packages/models/tsconfig.lib.json index b741c8920..2c92983e0 100644 --- a/packages/models/tsconfig.lib.json +++ b/packages/models/tsconfig.lib.json @@ -6,7 +6,7 @@ "types": ["node"], "plugins": [ { - "transform": "./dist/packages/models-transformers", + "transform": "./packages/models/transformers/dist", "afterDeclarations": true } ] diff --git a/packages/nx-plugin/project.json b/packages/nx-plugin/project.json index 52c8f2290..e92ba4ff7 100644 --- a/packages/nx-plugin/project.json +++ b/packages/nx-plugin/project.json @@ -7,6 +7,7 @@ "targets": { "build": { "options": { + "outputPath": "{projectRoot}/dist", "assets": [ "{projectRoot}/*.md", { diff --git a/packages/plugin-coverage/project.json b/packages/plugin-coverage/project.json index edb62346f..d3b11df79 100644 --- a/packages/plugin-coverage/project.json +++ b/packages/plugin-coverage/project.json @@ -4,7 +4,11 @@ "sourceRoot": "packages/plugin-coverage/src", "projectType": "library", "targets": { - "build": {}, + "build": { + "options": { + "outputPath": "{projectRoot}/dist" + } + }, "lint": {}, "unit-test": {}, "int-test": {} diff --git a/packages/plugin-eslint/project.json b/packages/plugin-eslint/project.json index 241101850..d436430aa 100644 --- a/packages/plugin-eslint/project.json +++ b/packages/plugin-eslint/project.json @@ -4,7 +4,11 @@ "sourceRoot": "packages/plugin-eslint/src", "projectType": "library", "targets": { - "build": {}, + "build": { + "options": { + "outputPath": "{projectRoot}/dist" + } + }, "lint": {}, "unit-test": {}, "int-test": {} diff --git a/packages/plugin-js-packages/project.json b/packages/plugin-js-packages/project.json index 9f0dc7789..bd3548051 100644 --- a/packages/plugin-js-packages/project.json +++ b/packages/plugin-js-packages/project.json @@ -4,7 +4,11 @@ "sourceRoot": "packages/plugin-js-packages/src", "projectType": "library", "targets": { - "build": {}, + "build": { + "options": { + "outputPath": "{projectRoot}/dist" + } + }, "lint": {}, "unit-test": {}, "int-test": {} diff --git a/packages/plugin-jsdocs/project.json b/packages/plugin-jsdocs/project.json index 745540438..e89dbdd24 100644 --- a/packages/plugin-jsdocs/project.json +++ b/packages/plugin-jsdocs/project.json @@ -5,7 +5,11 @@ "projectType": "library", "tags": ["scope:plugin", "type:feature", "publishable"], "targets": { - "build": {}, + "build": { + "options": { + "outputPath": "{projectRoot}/dist" + } + }, "lint": {}, "unit-test": {}, "int-test": {} diff --git a/packages/plugin-lighthouse/project.json b/packages/plugin-lighthouse/project.json index b93152ffb..2efc17674 100644 --- a/packages/plugin-lighthouse/project.json +++ b/packages/plugin-lighthouse/project.json @@ -4,7 +4,11 @@ "sourceRoot": "packages/plugin-lighthouse/src", "projectType": "library", "targets": { - "build": {}, + "build": { + "options": { + "outputPath": "{projectRoot}/dist" + } + }, "lint": {}, "unit-test": {} }, diff --git a/packages/plugin-typescript/project.json b/packages/plugin-typescript/project.json index 645259554..6da007fba 100644 --- a/packages/plugin-typescript/project.json +++ b/packages/plugin-typescript/project.json @@ -4,7 +4,11 @@ "sourceRoot": "packages/plugin-typescript/src", "projectType": "library", "targets": { - "build": {}, + "build": { + "options": { + "outputPath": "{projectRoot}/dist" + } + }, "lint": {}, "unit-test": {}, "int-test": {} diff --git a/packages/utils/project.json b/packages/utils/project.json index 021205deb..9ff1fd1a7 100644 --- a/packages/utils/project.json +++ b/packages/utils/project.json @@ -4,7 +4,11 @@ "sourceRoot": "packages/utils/src", "projectType": "library", "targets": { - "build": {}, + "build": { + "options": { + "outputPath": "{projectRoot}/dist" + } + }, "lint": {}, "perf": { "command": "npx tsx --tsconfig=../tsconfig.perf.json", From 858997f077cea0ad85cb63e96c3cb938b5e63ebf Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Fri, 22 Aug 2025 16:23:18 +0200 Subject: [PATCH 107/111] wip --- e2e/ci-e2e/project.json | 6 +++--- e2e/cli-e2e/project.json | 6 +++--- e2e/create-cli-e2e/project.json | 6 +++--- e2e/nx-plugin-e2e/project.json | 6 +++--- e2e/plugin-coverage-e2e/project.json | 6 +++--- e2e/plugin-eslint-e2e/project.json | 6 +++--- e2e/plugin-js-packages-e2e/project.json | 4 ++-- e2e/plugin-lighthouse-e2e/project.json | 6 +++--- e2e/plugin-typescript-e2e/project.json | 6 +++--- examples/plugins/project.json | 4 ++-- nx.json | 14 +++++--------- package-lock.json | 8 ++++---- package.json | 2 +- packages/ci/project.json | 6 +++--- packages/cli/project.json | 7 ++++--- packages/core/project.json | 6 +++--- packages/create-cli/project.json | 6 +++--- packages/models/project.json | 6 +++--- packages/models/transformers/project.json | 8 ++++++-- packages/nx-plugin/project.json | 6 +++--- packages/plugin-coverage/project.json | 6 +++--- packages/plugin-eslint/project.json | 7 ++++--- packages/plugin-js-packages/project.json | 8 ++++---- packages/plugin-jsdocs/project.json | 2 +- packages/plugin-lighthouse/project.json | 6 +++--- packages/plugin-typescript/project.json | 6 +++--- packages/utils/project.json | 6 +++--- testing/test-nx-utils/project.json | 4 ++-- testing/test-setup/project.json | 4 ++-- testing/test-utils/project.json | 4 ++-- 30 files changed, 90 insertions(+), 88 deletions(-) diff --git a/e2e/ci-e2e/project.json b/e2e/ci-e2e/project.json index f458d8d9d..e270e691d 100644 --- a/e2e/ci-e2e/project.json +++ b/e2e/ci-e2e/project.json @@ -3,6 +3,8 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "e2e/ci-e2e/src", "projectType": "application", + "tags": ["scope:tooling", "type:e2e"], + "implicitDependencies": ["cli", "ci"], "targets": { "lint": {}, "e2e": { @@ -11,7 +13,5 @@ "configFile": "{projectRoot}/vitest.e2e.config.ts" } } - }, - "implicitDependencies": ["cli", "ci"], - "tags": ["scope:tooling", "type:e2e"] + } } diff --git a/e2e/cli-e2e/project.json b/e2e/cli-e2e/project.json index 6cdabf9ae..a07c581a9 100644 --- a/e2e/cli-e2e/project.json +++ b/e2e/cli-e2e/project.json @@ -3,6 +3,8 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "e2e/cli-e2e/src", "projectType": "application", + "tags": ["scope:core", "scope:plugin", "type:e2e"], + "implicitDependencies": ["cli"], "targets": { "lint": {}, "e2e": { @@ -11,7 +13,5 @@ "configFile": "{projectRoot}/vitest.e2e.config.ts" } } - }, - "implicitDependencies": ["cli"], - "tags": ["scope:core", "scope:plugin", "type:e2e"] + } } diff --git a/e2e/create-cli-e2e/project.json b/e2e/create-cli-e2e/project.json index bf0b88071..5961931c3 100644 --- a/e2e/create-cli-e2e/project.json +++ b/e2e/create-cli-e2e/project.json @@ -3,6 +3,8 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "examples/create-cli-e2e/src", "projectType": "application", + "tags": ["scope:tooling", "type:e2e"], + "implicitDependencies": ["create-cli"], "targets": { "lint": {}, "e2e": { @@ -12,7 +14,5 @@ "configFile": "{projectRoot}/vitest.e2e.config.ts" } } - }, - "implicitDependencies": ["create-cli"], - "tags": ["scope:tooling", "type:e2e"] + } } diff --git a/e2e/nx-plugin-e2e/project.json b/e2e/nx-plugin-e2e/project.json index f569a465f..4435abd89 100644 --- a/e2e/nx-plugin-e2e/project.json +++ b/e2e/nx-plugin-e2e/project.json @@ -3,6 +3,8 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "e2e/nx-plugin-e2e/src", "projectType": "application", + "tags": ["scope:tooling", "type:e2e"], + "implicitDependencies": ["test-utils", "nx-plugin"], "targets": { "lint": {}, "e2e": { @@ -11,7 +13,5 @@ "configFile": "{projectRoot}/vitest.e2e.config.ts" } } - }, - "implicitDependencies": ["test-utils", "nx-plugin"], - "tags": ["scope:tooling", "type:e2e"] + } } diff --git a/e2e/plugin-coverage-e2e/project.json b/e2e/plugin-coverage-e2e/project.json index ca5b5b3fd..d1e559fc4 100644 --- a/e2e/plugin-coverage-e2e/project.json +++ b/e2e/plugin-coverage-e2e/project.json @@ -3,6 +3,8 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "e2e/plugin-coverage-e2e/src", "projectType": "application", + "tags": ["scope:plugin", "type:e2e"], + "implicitDependencies": ["cli", "plugin-coverage"], "targets": { "lint": {}, "e2e": { @@ -11,7 +13,5 @@ "configFile": "{projectRoot}/vitest.e2e.config.ts" } } - }, - "implicitDependencies": ["cli", "plugin-coverage"], - "tags": ["scope:plugin", "type:e2e"] + } } diff --git a/e2e/plugin-eslint-e2e/project.json b/e2e/plugin-eslint-e2e/project.json index c4000be23..cd21753ab 100644 --- a/e2e/plugin-eslint-e2e/project.json +++ b/e2e/plugin-eslint-e2e/project.json @@ -3,6 +3,8 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "e2e/plugin-eslint-e2e/src", "projectType": "application", + "tags": ["scope:plugin", "type:e2e"], + "implicitDependencies": ["cli", "plugin-eslint"], "targets": { "lint": {}, "e2e": { @@ -11,7 +13,5 @@ "configFile": "{projectRoot}/vitest.e2e.config.ts" } } - }, - "implicitDependencies": ["cli", "plugin-eslint"], - "tags": ["scope:plugin", "type:e2e"] + } } diff --git a/e2e/plugin-js-packages-e2e/project.json b/e2e/plugin-js-packages-e2e/project.json index 5c6382c06..044da7e0b 100644 --- a/e2e/plugin-js-packages-e2e/project.json +++ b/e2e/plugin-js-packages-e2e/project.json @@ -3,6 +3,7 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "projectType": "application", "sourceRoot": "e2e/plugin-js-packages-e2e/src", + "tags": ["scope:plugin", "type:e2e"], "implicitDependencies": ["cli", "plugin-js-packages"], "targets": { "lint": {}, @@ -12,6 +13,5 @@ "configFile": "{projectRoot}/vitest.e2e.config.ts" } } - }, - "tags": ["scope:plugin", "type:e2e"] + } } diff --git a/e2e/plugin-lighthouse-e2e/project.json b/e2e/plugin-lighthouse-e2e/project.json index a29950ee3..b6e7e2793 100644 --- a/e2e/plugin-lighthouse-e2e/project.json +++ b/e2e/plugin-lighthouse-e2e/project.json @@ -3,6 +3,8 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "e2e/plugin-lighthouse-e2e/src", "projectType": "application", + "tags": ["scope:plugin", "type:e2e"], + "implicitDependencies": ["cli", "plugin-lighthouse"], "targets": { "lint": {}, "e2e": { @@ -11,7 +13,5 @@ "configFile": "{projectRoot}/vitest.e2e.config.ts" } } - }, - "implicitDependencies": ["cli", "plugin-lighthouse"], - "tags": ["scope:plugin", "type:e2e"] + } } diff --git a/e2e/plugin-typescript-e2e/project.json b/e2e/plugin-typescript-e2e/project.json index 373fa2b01..b2e18546e 100644 --- a/e2e/plugin-typescript-e2e/project.json +++ b/e2e/plugin-typescript-e2e/project.json @@ -3,6 +3,8 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "e2e/plugin-typescript-e2e/src", "projectType": "application", + "tags": ["scope:plugin", "type:e2e"], + "implicitDependencies": ["cli", "plugin-typescript"], "targets": { "lint": {}, "e2e": { @@ -11,7 +13,5 @@ "configFile": "e2e/plugin-typescript-e2e/vitest.e2e.config.ts" } } - }, - "implicitDependencies": ["cli", "plugin-typescript"], - "tags": ["scope:plugin", "type:e2e"] + } } diff --git a/examples/plugins/project.json b/examples/plugins/project.json index 1370e0782..534054f4f 100644 --- a/examples/plugins/project.json +++ b/examples/plugins/project.json @@ -3,6 +3,7 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "examples/plugins/src", "projectType": "library", + "tags": ["scope:internal", "type:feature"], "targets": { "build": {}, "lint": {}, @@ -41,6 +42,5 @@ } ] } - }, - "tags": ["scope:internal", "type:feature"] + } } diff --git a/nx.json b/nx.json index 053a8525b..c34267398 100644 --- a/nx.json +++ b/nx.json @@ -17,7 +17,7 @@ "!{projectRoot}/**/?(*.)mocks.[jt]s?(x)", "!{projectRoot}/**/?(*.)mock.[jt]s?(x)", "!{projectRoot}/vitest.@(unit|int|e2e).config.[jt]s", - "!{workspaceRoot}/**/dist/**/*", + "!{projectRoot}/dist/**/*", "!{projectRoot}/tsconfig.@(test|tools).json", "!{workspaceRoot}/**/(*.)coverage/**/*" ], @@ -82,7 +82,9 @@ "configFile": "{projectRoot}/vitest.unit.config.ts", "passWithNoTests": true, "watch": false, - "coverage": { "enabled": true } + "coverage": { + "enabled": true + } } }, "int-test": { @@ -100,12 +102,7 @@ } }, "e2e": { - "cache": true, - "dependsOn": ["^build"], - "executor": "@nx/vite:test", - "options": { - "configFile": "{projectRoot}/vitest.e2e.config.ts" - } + "dependsOn": ["^build"] }, "lint": { "inputs": ["lint-eslint-inputs"], @@ -207,7 +204,6 @@ "--verbose", "--config={projectRoot}/code-pushup.config.ts", "--onlyPlugins=js-packages", - "--persist.outputDir={projectRoot}/.code-pushup" ], "env": { diff --git a/package-lock.json b/package-lock.json index 598c886e7..bd89ddc1c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -50,7 +50,7 @@ "@nx/react": "19.8.13", "@nx/vite": "19.8.13", "@nx/workspace": "19.8.13", - "@push-based/nx-verdaccio": "^0.0.4", + "@push-based/nx-verdaccio": "^0.0.0", "@swc-node/register": "1.9.2", "@swc/cli": "0.3.14", "@swc/core": "1.5.7", @@ -5977,9 +5977,9 @@ } }, "node_modules/@push-based/nx-verdaccio": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/@push-based/nx-verdaccio/-/nx-verdaccio-0.0.4.tgz", - "integrity": "sha512-wavx6fXz97C2i4xgc55GEyUsSag2PdY+LpWsibCnkn/5jv026UVSxjF7d8A+u9tV3X7kB6NrdaFb1+DYxi/7PQ==", + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/@push-based/nx-verdaccio/-/nx-verdaccio-0.0.0.tgz", + "integrity": "sha512-uQTjzSnnRKGqViegKcE42a/Rn1OQnsbEeG/xgoRIu+9SwNBItLvWMigSXGfbU6IgIYb3TUzbD7w7V18TAwwXmA==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 31430d0c0..1c6ddc846 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "@nx/react": "19.8.13", "@nx/vite": "19.8.13", "@nx/workspace": "19.8.13", - "@push-based/nx-verdaccio": "^0.0.4", + "@push-based/nx-verdaccio": "^0.0.0", "@swc-node/register": "1.9.2", "@swc/cli": "0.3.14", "@swc/core": "1.5.7", diff --git a/packages/ci/project.json b/packages/ci/project.json index aa2e675fd..eaf0e6e9e 100644 --- a/packages/ci/project.json +++ b/packages/ci/project.json @@ -3,15 +3,15 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "packages/ci/src", "projectType": "library", + "tags": ["scope:tooling", "type:feature", "publishable"], "targets": { "build": { "options": { - "outputPath": "{projectRoot}/dist" + "outputPath": "packages/ci/dist" } }, "lint": {}, "unit-test": {}, "int-test": {} - }, - "tags": ["scope:tooling", "type:feature", "publishable"] + } } diff --git a/packages/cli/project.json b/packages/cli/project.json index 8eff5f6b8..706847082 100644 --- a/packages/cli/project.json +++ b/packages/cli/project.json @@ -3,10 +3,12 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "packages/cli/src", "projectType": "library", + "tags": ["scope:core", "type:app", "publishable"], "targets": { "build": { + "outputs": ["{projectRoot}/dist"], "options": { - "outputPath": "{projectRoot}/dist" + "outputPath": "packages/cli/dist" } }, "lint": {}, @@ -30,6 +32,5 @@ }, "dependsOn": ["build"] } - }, - "tags": ["scope:core", "type:app", "publishable"] + } } diff --git a/packages/core/project.json b/packages/core/project.json index a23d58f28..63b021dc7 100644 --- a/packages/core/project.json +++ b/packages/core/project.json @@ -3,15 +3,15 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "packages/core/src", "projectType": "library", + "tags": ["scope:core", "type:feature", "publishable"], "targets": { "build": { "options": { - "outputPath": "{projectRoot}/dist" + "outputPath": "packages/core/dist" } }, "lint": {}, "unit-test": {}, "int-test": {} - }, - "tags": ["scope:core", "type:feature", "publishable"] + } } diff --git a/packages/create-cli/project.json b/packages/create-cli/project.json index eb3db2534..a41e1dd0f 100644 --- a/packages/create-cli/project.json +++ b/packages/create-cli/project.json @@ -3,10 +3,11 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "packages/create-cli/src", "projectType": "library", + "tags": ["scope:tooling", "type:app", "publishable"], "targets": { "build": { "options": { - "outputPath": "{projectRoot}/dist" + "outputPath": "packages/create-cli/dist" } }, "lint": {}, @@ -21,6 +22,5 @@ "command": "npm exec ./dist/packages/create-cli", "options": {} } - }, - "tags": ["scope:tooling", "type:app", "publishable"] + } } diff --git a/packages/models/project.json b/packages/models/project.json index 90233094f..39d9baf99 100644 --- a/packages/models/project.json +++ b/packages/models/project.json @@ -3,6 +3,7 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "packages/models/src", "projectType": "library", + "tags": ["scope:shared", "type:util", "publishable"], "targets": { "generate-docs": { "command": "npx zod2md --config packages/models/zod2md.config.ts", @@ -20,11 +21,10 @@ } ], "options": { - "outputPath": "{projectRoot}/dist" + "outputPath": "packages/models/dist" } }, "lint": {}, "unit-test": {} - }, - "tags": ["scope:shared", "type:util", "publishable"] + } } diff --git a/packages/models/transformers/project.json b/packages/models/transformers/project.json index b5e7e7317..b377da537 100644 --- a/packages/models/transformers/project.json +++ b/packages/models/transformers/project.json @@ -7,9 +7,13 @@ "build": { "executor": "@nx/js:tsc", "outputs": ["{options.outputPath}"], - "dependsOn": [{ "target": "pre-build" }], + "dependsOn": [ + { + "target": "pre-build" + } + ], "options": { - "outputPath": "{projectRoot}/dist", + "outputPath": "packages/models/transformers/dist", "main": "packages/models/transformers/src/index.ts", "tsConfig": "packages/models/transformers/tsconfig.lib.json" } diff --git a/packages/nx-plugin/project.json b/packages/nx-plugin/project.json index e92ba4ff7..a5609eaf2 100644 --- a/packages/nx-plugin/project.json +++ b/packages/nx-plugin/project.json @@ -3,11 +3,12 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "packages/nx-plugin/src", "projectType": "library", + "tags": ["scope:tooling", "type:feature", "publishable"], "implicitDependencies": ["cli"], "targets": { "build": { "options": { - "outputPath": "{projectRoot}/dist", + "outputPath": "packages/nx-plugin/dist", "assets": [ "{projectRoot}/*.md", { @@ -44,6 +45,5 @@ }, "unit-test": {}, "int-test": {} - }, - "tags": ["scope:tooling", "type:feature", "publishable"] + } } diff --git a/packages/plugin-coverage/project.json b/packages/plugin-coverage/project.json index d3b11df79..9bf6eb312 100644 --- a/packages/plugin-coverage/project.json +++ b/packages/plugin-coverage/project.json @@ -3,15 +3,15 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "packages/plugin-coverage/src", "projectType": "library", + "tags": ["scope:plugin", "type:feature", "publishable"], "targets": { "build": { "options": { - "outputPath": "{projectRoot}/dist" + "outputPath": "packages/plugin-coverage/dist" } }, "lint": {}, "unit-test": {}, "int-test": {} - }, - "tags": ["scope:plugin", "type:feature", "publishable"] + } } diff --git a/packages/plugin-eslint/project.json b/packages/plugin-eslint/project.json index d436430aa..c313d92dc 100644 --- a/packages/plugin-eslint/project.json +++ b/packages/plugin-eslint/project.json @@ -3,15 +3,16 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "packages/plugin-eslint/src", "projectType": "library", + "tags": ["scope:plugin", "type:feature", "publishable"], "targets": { "build": { + "outputs": ["{projectRoot}/dist"], "options": { - "outputPath": "{projectRoot}/dist" + "outputPath": "packages/plugin-eslint/dist" } }, "lint": {}, "unit-test": {}, "int-test": {} - }, - "tags": ["scope:plugin", "type:feature", "publishable"] + } } diff --git a/packages/plugin-js-packages/project.json b/packages/plugin-js-packages/project.json index bd3548051..90740c52c 100644 --- a/packages/plugin-js-packages/project.json +++ b/packages/plugin-js-packages/project.json @@ -3,16 +3,16 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "packages/plugin-js-packages/src", "projectType": "library", + "description": "A plugin for JavaScript packages.", + "tags": ["scope:plugin", "type:feature", "publishable"], "targets": { "build": { "options": { - "outputPath": "{projectRoot}/dist" + "outputPath": "packages/plugin-js-packages/dist" } }, "lint": {}, "unit-test": {}, "int-test": {} - }, - "tags": ["scope:plugin", "type:feature", "publishable"], - "description": "A plugin for JavaScript packages." + } } diff --git a/packages/plugin-jsdocs/project.json b/packages/plugin-jsdocs/project.json index e89dbdd24..f397c85d0 100644 --- a/packages/plugin-jsdocs/project.json +++ b/packages/plugin-jsdocs/project.json @@ -7,7 +7,7 @@ "targets": { "build": { "options": { - "outputPath": "{projectRoot}/dist" + "outputPath": "packages/plugin-jsdocs/dist" } }, "lint": {}, diff --git a/packages/plugin-lighthouse/project.json b/packages/plugin-lighthouse/project.json index 2efc17674..ad118928d 100644 --- a/packages/plugin-lighthouse/project.json +++ b/packages/plugin-lighthouse/project.json @@ -3,14 +3,14 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "packages/plugin-lighthouse/src", "projectType": "library", + "tags": ["scope:plugin", "type:feature", "publishable"], "targets": { "build": { "options": { - "outputPath": "{projectRoot}/dist" + "outputPath": "packages/plugin-lighthouse/dist" } }, "lint": {}, "unit-test": {} - }, - "tags": ["scope:plugin", "type:feature", "publishable"] + } } diff --git a/packages/plugin-typescript/project.json b/packages/plugin-typescript/project.json index 6da007fba..f0cc601e4 100644 --- a/packages/plugin-typescript/project.json +++ b/packages/plugin-typescript/project.json @@ -3,15 +3,15 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "packages/plugin-typescript/src", "projectType": "library", + "tags": ["scope:plugin", "type:feature", "publishable"], "targets": { "build": { "options": { - "outputPath": "{projectRoot}/dist" + "outputPath": "packages/plugin-typescript/dist" } }, "lint": {}, "unit-test": {}, "int-test": {} - }, - "tags": ["scope:plugin", "type:feature", "publishable"] + } } diff --git a/packages/utils/project.json b/packages/utils/project.json index 9ff1fd1a7..d7018bbf4 100644 --- a/packages/utils/project.json +++ b/packages/utils/project.json @@ -3,10 +3,11 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "packages/utils/src", "projectType": "library", + "tags": ["scope:shared", "type:util", "publishable"], "targets": { "build": { "options": { - "outputPath": "{projectRoot}/dist" + "outputPath": "packages/utils/dist" } }, "lint": {}, @@ -24,6 +25,5 @@ }, "unit-test": {}, "int-test": {} - }, - "tags": ["scope:shared", "type:util", "publishable"] + } } diff --git a/testing/test-nx-utils/project.json b/testing/test-nx-utils/project.json index d76cad67e..636eb9865 100644 --- a/testing/test-nx-utils/project.json +++ b/testing/test-nx-utils/project.json @@ -3,10 +3,10 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "testing/test-nx-utils/src", "projectType": "library", + "tags": ["scope:shared", "type:testing"], "targets": { "build": {}, "lint": {}, "unit-test": {} - }, - "tags": ["scope:shared", "type:testing"] + } } diff --git a/testing/test-setup/project.json b/testing/test-setup/project.json index 0657658a2..ce93ca919 100644 --- a/testing/test-setup/project.json +++ b/testing/test-setup/project.json @@ -3,10 +3,10 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "testing/test-setup/src", "projectType": "library", + "tags": ["scope:shared", "type:testing"], "targets": { "build": {}, "lint": {}, "unit-test": {} - }, - "tags": ["scope:shared", "type:testing"] + } } diff --git a/testing/test-utils/project.json b/testing/test-utils/project.json index a23396a9e..9f98a39c5 100644 --- a/testing/test-utils/project.json +++ b/testing/test-utils/project.json @@ -3,6 +3,7 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "testing/test-utils/src", "projectType": "library", + "tags": ["scope:shared", "type:testing"], "targets": { "build": {}, "lint": {}, @@ -10,6 +11,5 @@ "nx-release-publish": { "executor": "nx:noop" } - }, - "tags": ["scope:shared", "type:testing"] + } } From 8ffbd6762b8f037f23573000ce54bd8db68533df Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Sat, 23 Aug 2025 00:12:30 +0200 Subject: [PATCH 108/111] refactor: evert changes --- .github/workflows/code-pushup-fork.yml | 2 +- .github/workflows/code-pushup.yml | 2 +- e2e/ci-e2e/project.json | 6 +++--- e2e/cli-e2e/project.json | 6 +++--- e2e/create-cli-e2e/project.json | 6 +++--- e2e/nx-plugin-e2e/project.json | 6 +++--- e2e/plugin-coverage-e2e/project.json | 6 +++--- e2e/plugin-eslint-e2e/project.json | 6 +++--- e2e/plugin-js-packages-e2e/project.json | 4 ++-- e2e/plugin-lighthouse-e2e/project.json | 6 +++--- e2e/plugin-typescript-e2e/project.json | 6 +++--- examples/plugins/project.json | 4 ++-- packages/ci/project.json | 10 +++------- packages/cli/project.json | 11 +++-------- packages/core/project.json | 10 +++------- packages/create-cli/project.json | 10 +++------- packages/models/project.json | 14 ++++---------- packages/nx-plugin/project.json | 5 ++--- packages/plugin-coverage/project.json | 10 +++------- packages/plugin-eslint/project.json | 11 +++-------- packages/plugin-js-packages/project.json | 12 ++++-------- packages/plugin-jsdocs/project.json | 6 +----- packages/plugin-lighthouse/project.json | 10 +++------- packages/plugin-typescript/project.json | 10 +++------- packages/utils/project.json | 10 +++------- testing/test-nx-utils/project.json | 4 ++-- testing/test-setup/project.json | 4 ++-- testing/test-utils/project.json | 4 ++-- 28 files changed, 74 insertions(+), 127 deletions(-) diff --git a/.github/workflows/code-pushup-fork.yml b/.github/workflows/code-pushup-fork.yml index e8a2a00f9..7276391e3 100644 --- a/.github/workflows/code-pushup-fork.yml +++ b/.github/workflows/code-pushup-fork.yml @@ -39,4 +39,4 @@ jobs: - name: Run Code PushUp action uses: code-pushup/github-action@v0 with: - bin: npx nx code-pushup --nx-bail --parallel=3 -- + bin: npx nx code-pushup --nx-bail -- diff --git a/.github/workflows/code-pushup.yml b/.github/workflows/code-pushup.yml index e9b3044a1..21d7bce27 100644 --- a/.github/workflows/code-pushup.yml +++ b/.github/workflows/code-pushup.yml @@ -41,4 +41,4 @@ jobs: - name: Run Code PushUp action uses: code-pushup/github-action@v0 with: - bin: npx nx code-pushup --skipNxCache --nx-bail --parallel=3 -- + bin: npx nx code-pushup --nx-bail -- diff --git a/e2e/ci-e2e/project.json b/e2e/ci-e2e/project.json index e270e691d..f458d8d9d 100644 --- a/e2e/ci-e2e/project.json +++ b/e2e/ci-e2e/project.json @@ -3,8 +3,6 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "e2e/ci-e2e/src", "projectType": "application", - "tags": ["scope:tooling", "type:e2e"], - "implicitDependencies": ["cli", "ci"], "targets": { "lint": {}, "e2e": { @@ -13,5 +11,7 @@ "configFile": "{projectRoot}/vitest.e2e.config.ts" } } - } + }, + "implicitDependencies": ["cli", "ci"], + "tags": ["scope:tooling", "type:e2e"] } diff --git a/e2e/cli-e2e/project.json b/e2e/cli-e2e/project.json index a07c581a9..6cdabf9ae 100644 --- a/e2e/cli-e2e/project.json +++ b/e2e/cli-e2e/project.json @@ -3,8 +3,6 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "e2e/cli-e2e/src", "projectType": "application", - "tags": ["scope:core", "scope:plugin", "type:e2e"], - "implicitDependencies": ["cli"], "targets": { "lint": {}, "e2e": { @@ -13,5 +11,7 @@ "configFile": "{projectRoot}/vitest.e2e.config.ts" } } - } + }, + "implicitDependencies": ["cli"], + "tags": ["scope:core", "scope:plugin", "type:e2e"] } diff --git a/e2e/create-cli-e2e/project.json b/e2e/create-cli-e2e/project.json index 5961931c3..bf0b88071 100644 --- a/e2e/create-cli-e2e/project.json +++ b/e2e/create-cli-e2e/project.json @@ -3,8 +3,6 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "examples/create-cli-e2e/src", "projectType": "application", - "tags": ["scope:tooling", "type:e2e"], - "implicitDependencies": ["create-cli"], "targets": { "lint": {}, "e2e": { @@ -14,5 +12,7 @@ "configFile": "{projectRoot}/vitest.e2e.config.ts" } } - } + }, + "implicitDependencies": ["create-cli"], + "tags": ["scope:tooling", "type:e2e"] } diff --git a/e2e/nx-plugin-e2e/project.json b/e2e/nx-plugin-e2e/project.json index 4435abd89..f569a465f 100644 --- a/e2e/nx-plugin-e2e/project.json +++ b/e2e/nx-plugin-e2e/project.json @@ -3,8 +3,6 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "e2e/nx-plugin-e2e/src", "projectType": "application", - "tags": ["scope:tooling", "type:e2e"], - "implicitDependencies": ["test-utils", "nx-plugin"], "targets": { "lint": {}, "e2e": { @@ -13,5 +11,7 @@ "configFile": "{projectRoot}/vitest.e2e.config.ts" } } - } + }, + "implicitDependencies": ["test-utils", "nx-plugin"], + "tags": ["scope:tooling", "type:e2e"] } diff --git a/e2e/plugin-coverage-e2e/project.json b/e2e/plugin-coverage-e2e/project.json index d1e559fc4..ca5b5b3fd 100644 --- a/e2e/plugin-coverage-e2e/project.json +++ b/e2e/plugin-coverage-e2e/project.json @@ -3,8 +3,6 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "e2e/plugin-coverage-e2e/src", "projectType": "application", - "tags": ["scope:plugin", "type:e2e"], - "implicitDependencies": ["cli", "plugin-coverage"], "targets": { "lint": {}, "e2e": { @@ -13,5 +11,7 @@ "configFile": "{projectRoot}/vitest.e2e.config.ts" } } - } + }, + "implicitDependencies": ["cli", "plugin-coverage"], + "tags": ["scope:plugin", "type:e2e"] } diff --git a/e2e/plugin-eslint-e2e/project.json b/e2e/plugin-eslint-e2e/project.json index cd21753ab..c4000be23 100644 --- a/e2e/plugin-eslint-e2e/project.json +++ b/e2e/plugin-eslint-e2e/project.json @@ -3,8 +3,6 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "e2e/plugin-eslint-e2e/src", "projectType": "application", - "tags": ["scope:plugin", "type:e2e"], - "implicitDependencies": ["cli", "plugin-eslint"], "targets": { "lint": {}, "e2e": { @@ -13,5 +11,7 @@ "configFile": "{projectRoot}/vitest.e2e.config.ts" } } - } + }, + "implicitDependencies": ["cli", "plugin-eslint"], + "tags": ["scope:plugin", "type:e2e"] } diff --git a/e2e/plugin-js-packages-e2e/project.json b/e2e/plugin-js-packages-e2e/project.json index 044da7e0b..5c6382c06 100644 --- a/e2e/plugin-js-packages-e2e/project.json +++ b/e2e/plugin-js-packages-e2e/project.json @@ -3,7 +3,6 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "projectType": "application", "sourceRoot": "e2e/plugin-js-packages-e2e/src", - "tags": ["scope:plugin", "type:e2e"], "implicitDependencies": ["cli", "plugin-js-packages"], "targets": { "lint": {}, @@ -13,5 +12,6 @@ "configFile": "{projectRoot}/vitest.e2e.config.ts" } } - } + }, + "tags": ["scope:plugin", "type:e2e"] } diff --git a/e2e/plugin-lighthouse-e2e/project.json b/e2e/plugin-lighthouse-e2e/project.json index b6e7e2793..a29950ee3 100644 --- a/e2e/plugin-lighthouse-e2e/project.json +++ b/e2e/plugin-lighthouse-e2e/project.json @@ -3,8 +3,6 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "e2e/plugin-lighthouse-e2e/src", "projectType": "application", - "tags": ["scope:plugin", "type:e2e"], - "implicitDependencies": ["cli", "plugin-lighthouse"], "targets": { "lint": {}, "e2e": { @@ -13,5 +11,7 @@ "configFile": "{projectRoot}/vitest.e2e.config.ts" } } - } + }, + "implicitDependencies": ["cli", "plugin-lighthouse"], + "tags": ["scope:plugin", "type:e2e"] } diff --git a/e2e/plugin-typescript-e2e/project.json b/e2e/plugin-typescript-e2e/project.json index b2e18546e..373fa2b01 100644 --- a/e2e/plugin-typescript-e2e/project.json +++ b/e2e/plugin-typescript-e2e/project.json @@ -3,8 +3,6 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "e2e/plugin-typescript-e2e/src", "projectType": "application", - "tags": ["scope:plugin", "type:e2e"], - "implicitDependencies": ["cli", "plugin-typescript"], "targets": { "lint": {}, "e2e": { @@ -13,5 +11,7 @@ "configFile": "e2e/plugin-typescript-e2e/vitest.e2e.config.ts" } } - } + }, + "implicitDependencies": ["cli", "plugin-typescript"], + "tags": ["scope:plugin", "type:e2e"] } diff --git a/examples/plugins/project.json b/examples/plugins/project.json index 534054f4f..1370e0782 100644 --- a/examples/plugins/project.json +++ b/examples/plugins/project.json @@ -3,7 +3,6 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "examples/plugins/src", "projectType": "library", - "tags": ["scope:internal", "type:feature"], "targets": { "build": {}, "lint": {}, @@ -42,5 +41,6 @@ } ] } - } + }, + "tags": ["scope:internal", "type:feature"] } diff --git a/packages/ci/project.json b/packages/ci/project.json index eaf0e6e9e..9215f87b3 100644 --- a/packages/ci/project.json +++ b/packages/ci/project.json @@ -3,15 +3,11 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "packages/ci/src", "projectType": "library", - "tags": ["scope:tooling", "type:feature", "publishable"], "targets": { - "build": { - "options": { - "outputPath": "packages/ci/dist" - } - }, + "build": {}, "lint": {}, "unit-test": {}, "int-test": {} - } + }, + "tags": ["scope:tooling", "type:feature", "publishable"] } diff --git a/packages/cli/project.json b/packages/cli/project.json index 706847082..bc3b384a7 100644 --- a/packages/cli/project.json +++ b/packages/cli/project.json @@ -3,14 +3,8 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "packages/cli/src", "projectType": "library", - "tags": ["scope:core", "type:app", "publishable"], "targets": { - "build": { - "outputs": ["{projectRoot}/dist"], - "options": { - "outputPath": "packages/cli/dist" - } - }, + "build": {}, "lint": {}, "unit-test": {}, "int-test": {}, @@ -32,5 +26,6 @@ }, "dependsOn": ["build"] } - } + }, + "tags": ["scope:core", "type:app", "publishable"] } diff --git a/packages/core/project.json b/packages/core/project.json index 63b021dc7..4924717c5 100644 --- a/packages/core/project.json +++ b/packages/core/project.json @@ -3,15 +3,11 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "packages/core/src", "projectType": "library", - "tags": ["scope:core", "type:feature", "publishable"], "targets": { - "build": { - "options": { - "outputPath": "packages/core/dist" - } - }, + "build": {}, "lint": {}, "unit-test": {}, "int-test": {} - } + }, + "tags": ["scope:core", "type:feature", "publishable"] } diff --git a/packages/create-cli/project.json b/packages/create-cli/project.json index a41e1dd0f..c2bc6ef60 100644 --- a/packages/create-cli/project.json +++ b/packages/create-cli/project.json @@ -3,13 +3,8 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "packages/create-cli/src", "projectType": "library", - "tags": ["scope:tooling", "type:app", "publishable"], "targets": { - "build": { - "options": { - "outputPath": "packages/create-cli/dist" - } - }, + "build": {}, "lint": {}, "unit-test": {}, "exec-node": { @@ -22,5 +17,6 @@ "command": "npm exec ./dist/packages/create-cli", "options": {} } - } + }, + "tags": ["scope:tooling", "type:app", "publishable"] } diff --git a/packages/models/project.json b/packages/models/project.json index 39d9baf99..15981781f 100644 --- a/packages/models/project.json +++ b/packages/models/project.json @@ -3,7 +3,6 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "packages/models/src", "projectType": "library", - "tags": ["scope:shared", "type:util", "publishable"], "targets": { "generate-docs": { "command": "npx zod2md --config packages/models/zod2md.config.ts", @@ -15,16 +14,11 @@ "dependsOn": [ "^build", "generate-docs", - { - "projects": "models-transformers", - "target": "build" - } - ], - "options": { - "outputPath": "packages/models/dist" - } + { "projects": "models-transformers", "target": "build" } + ] }, "lint": {}, "unit-test": {} - } + }, + "tags": ["scope:shared", "type:util", "publishable"] } diff --git a/packages/nx-plugin/project.json b/packages/nx-plugin/project.json index a5609eaf2..52c8f2290 100644 --- a/packages/nx-plugin/project.json +++ b/packages/nx-plugin/project.json @@ -3,12 +3,10 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "packages/nx-plugin/src", "projectType": "library", - "tags": ["scope:tooling", "type:feature", "publishable"], "implicitDependencies": ["cli"], "targets": { "build": { "options": { - "outputPath": "packages/nx-plugin/dist", "assets": [ "{projectRoot}/*.md", { @@ -45,5 +43,6 @@ }, "unit-test": {}, "int-test": {} - } + }, + "tags": ["scope:tooling", "type:feature", "publishable"] } diff --git a/packages/plugin-coverage/project.json b/packages/plugin-coverage/project.json index 9bf6eb312..edb62346f 100644 --- a/packages/plugin-coverage/project.json +++ b/packages/plugin-coverage/project.json @@ -3,15 +3,11 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "packages/plugin-coverage/src", "projectType": "library", - "tags": ["scope:plugin", "type:feature", "publishable"], "targets": { - "build": { - "options": { - "outputPath": "packages/plugin-coverage/dist" - } - }, + "build": {}, "lint": {}, "unit-test": {}, "int-test": {} - } + }, + "tags": ["scope:plugin", "type:feature", "publishable"] } diff --git a/packages/plugin-eslint/project.json b/packages/plugin-eslint/project.json index c313d92dc..241101850 100644 --- a/packages/plugin-eslint/project.json +++ b/packages/plugin-eslint/project.json @@ -3,16 +3,11 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "packages/plugin-eslint/src", "projectType": "library", - "tags": ["scope:plugin", "type:feature", "publishable"], "targets": { - "build": { - "outputs": ["{projectRoot}/dist"], - "options": { - "outputPath": "packages/plugin-eslint/dist" - } - }, + "build": {}, "lint": {}, "unit-test": {}, "int-test": {} - } + }, + "tags": ["scope:plugin", "type:feature", "publishable"] } diff --git a/packages/plugin-js-packages/project.json b/packages/plugin-js-packages/project.json index 90740c52c..9f0dc7789 100644 --- a/packages/plugin-js-packages/project.json +++ b/packages/plugin-js-packages/project.json @@ -3,16 +3,12 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "packages/plugin-js-packages/src", "projectType": "library", - "description": "A plugin for JavaScript packages.", - "tags": ["scope:plugin", "type:feature", "publishable"], "targets": { - "build": { - "options": { - "outputPath": "packages/plugin-js-packages/dist" - } - }, + "build": {}, "lint": {}, "unit-test": {}, "int-test": {} - } + }, + "tags": ["scope:plugin", "type:feature", "publishable"], + "description": "A plugin for JavaScript packages." } diff --git a/packages/plugin-jsdocs/project.json b/packages/plugin-jsdocs/project.json index f397c85d0..745540438 100644 --- a/packages/plugin-jsdocs/project.json +++ b/packages/plugin-jsdocs/project.json @@ -5,11 +5,7 @@ "projectType": "library", "tags": ["scope:plugin", "type:feature", "publishable"], "targets": { - "build": { - "options": { - "outputPath": "packages/plugin-jsdocs/dist" - } - }, + "build": {}, "lint": {}, "unit-test": {}, "int-test": {} diff --git a/packages/plugin-lighthouse/project.json b/packages/plugin-lighthouse/project.json index ad118928d..b93152ffb 100644 --- a/packages/plugin-lighthouse/project.json +++ b/packages/plugin-lighthouse/project.json @@ -3,14 +3,10 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "packages/plugin-lighthouse/src", "projectType": "library", - "tags": ["scope:plugin", "type:feature", "publishable"], "targets": { - "build": { - "options": { - "outputPath": "packages/plugin-lighthouse/dist" - } - }, + "build": {}, "lint": {}, "unit-test": {} - } + }, + "tags": ["scope:plugin", "type:feature", "publishable"] } diff --git a/packages/plugin-typescript/project.json b/packages/plugin-typescript/project.json index f0cc601e4..645259554 100644 --- a/packages/plugin-typescript/project.json +++ b/packages/plugin-typescript/project.json @@ -3,15 +3,11 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "packages/plugin-typescript/src", "projectType": "library", - "tags": ["scope:plugin", "type:feature", "publishable"], "targets": { - "build": { - "options": { - "outputPath": "packages/plugin-typescript/dist" - } - }, + "build": {}, "lint": {}, "unit-test": {}, "int-test": {} - } + }, + "tags": ["scope:plugin", "type:feature", "publishable"] } diff --git a/packages/utils/project.json b/packages/utils/project.json index d7018bbf4..021205deb 100644 --- a/packages/utils/project.json +++ b/packages/utils/project.json @@ -3,13 +3,8 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "packages/utils/src", "projectType": "library", - "tags": ["scope:shared", "type:util", "publishable"], "targets": { - "build": { - "options": { - "outputPath": "packages/utils/dist" - } - }, + "build": {}, "lint": {}, "perf": { "command": "npx tsx --tsconfig=../tsconfig.perf.json", @@ -25,5 +20,6 @@ }, "unit-test": {}, "int-test": {} - } + }, + "tags": ["scope:shared", "type:util", "publishable"] } diff --git a/testing/test-nx-utils/project.json b/testing/test-nx-utils/project.json index 636eb9865..d76cad67e 100644 --- a/testing/test-nx-utils/project.json +++ b/testing/test-nx-utils/project.json @@ -3,10 +3,10 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "testing/test-nx-utils/src", "projectType": "library", - "tags": ["scope:shared", "type:testing"], "targets": { "build": {}, "lint": {}, "unit-test": {} - } + }, + "tags": ["scope:shared", "type:testing"] } diff --git a/testing/test-setup/project.json b/testing/test-setup/project.json index ce93ca919..0657658a2 100644 --- a/testing/test-setup/project.json +++ b/testing/test-setup/project.json @@ -3,10 +3,10 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "testing/test-setup/src", "projectType": "library", - "tags": ["scope:shared", "type:testing"], "targets": { "build": {}, "lint": {}, "unit-test": {} - } + }, + "tags": ["scope:shared", "type:testing"] } diff --git a/testing/test-utils/project.json b/testing/test-utils/project.json index 9f98a39c5..a23396a9e 100644 --- a/testing/test-utils/project.json +++ b/testing/test-utils/project.json @@ -3,7 +3,6 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "testing/test-utils/src", "projectType": "library", - "tags": ["scope:shared", "type:testing"], "targets": { "build": {}, "lint": {}, @@ -11,5 +10,6 @@ "nx-release-publish": { "executor": "nx:noop" } - } + }, + "tags": ["scope:shared", "type:testing"] } From 6075043cab3983c42ce33319529e85ce03d8d23d Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Sat, 23 Aug 2025 00:24:04 +0200 Subject: [PATCH 109/111] refactor: keep vitest target empty in nx.json to pass e2e --- nx.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nx.json b/nx.json index be53a42a2..1ea7a6ddd 100644 --- a/nx.json +++ b/nx.json @@ -102,7 +102,9 @@ } }, "e2e": { - "dependsOn": ["^build"] + "dependsOn": ["^build"], + "inputs": ["default"], + "cache": true }, "lint": { "inputs": ["lint-eslint-inputs"], @@ -120,6 +122,7 @@ "nxv-pkg-install": { "parallelism": false }, + "@nx/vite:test": {}, "code-pushup": { "cache": false, "outputs": [ From ff016c424bb57f40b236fd1a656dad45564da63b Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Sat, 23 Aug 2025 00:34:20 +0200 Subject: [PATCH 110/111] refactor: make executor defaults meaningful --- nx.json | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/nx.json b/nx.json index 1ea7a6ddd..2f2ebc645 100644 --- a/nx.json +++ b/nx.json @@ -72,30 +72,22 @@ } }, "unit-test": { - "cache": true, - "inputs": ["test-vitest-inputs"], "outputs": [ "{workspaceRoot}/coverage/{projectName}/unit-tests/lcov.info" ], "executor": "@nx/vite:test", "options": { "configFile": "{projectRoot}/vitest.unit.config.ts", - "passWithNoTests": true, - "watch": false, "coverage": { "enabled": true } } }, "int-test": { - "cache": true, - "inputs": ["test-vitest-inputs"], "outputs": ["{workspaceRoot}/coverage/{projectName}/int-tests/lcov.info"], "executor": "@nx/vite:test", "options": { "configFile": "{projectRoot}/vitest.int.config.ts", - "passWithNoTests": true, - "watch": false, "coverage": { "enabled": true } @@ -122,7 +114,14 @@ "nxv-pkg-install": { "parallelism": false }, - "@nx/vite:test": {}, + "@nx/vite:test": { + "cache": true, + "inputs": ["test-vitest-inputs"], + "options": { + "passWithNoTests": true, + "watch": false + } + }, "code-pushup": { "cache": false, "outputs": [ From c71ccf8d107f3b1381b15cf857499163862e4e92 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Sat, 23 Aug 2025 00:55:28 +0200 Subject: [PATCH 111/111] refactor: merge main --- code-pushup.config.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/code-pushup.config.ts b/code-pushup.config.ts index c36b92b0c..3c007a621 100644 --- a/code-pushup.config.ts +++ b/code-pushup.config.ts @@ -1,12 +1,8 @@ import 'dotenv/config'; import { z } from 'zod'; import { - coverageCoreConfigNx, - eslintCoreConfigNx, - jsDocsCoreConfig, jsPackagesCoreConfig, lighthouseCoreConfig, - typescriptPluginConfig, } from './code-pushup.preset.js'; import type { CoreConfig } from './packages/models/src/index.js'; import { mergeConfigs } from './packages/utils/src/index.js';