diff --git a/.github/actions/code-pushup/action.yml b/.github/actions/code-pushup/action.yml index 82e759bf5..7cbea0acc 100644 --- a/.github/actions/code-pushup/action.yml +++ b/.github/actions/code-pushup/action.yml @@ -16,3 +16,4 @@ runs: env: TSX_TSCONFIG_PATH: .github/actions/code-pushup/tsconfig.json GH_TOKEN: ${{ inputs.token }} + CP_VERBOSE: true diff --git a/.github/actions/code-pushup/src/runner.ts b/.github/actions/code-pushup/src/runner.ts index 5db13799d..bf4aeef16 100644 --- a/.github/actions/code-pushup/src/runner.ts +++ b/.github/actions/code-pushup/src/runner.ts @@ -127,7 +127,7 @@ function createGitHubApiClient(): ProviderAPIClient { async function run(): Promise { try { const options: Options = { - bin: 'npx nx code-pushup --nx-bail --', + bin: 'npx nx code-pushup --nx-bail --', }; const gitRefs = parseGitRefs(); diff --git a/e2e/ci-e2e/mocks/fixtures/npm-workspaces/packages/cli/_package.json b/e2e/ci-e2e/mocks/fixtures/npm-workspaces/packages/cli/_package.json index 8be8e49a2..591b888c2 100644 --- a/e2e/ci-e2e/mocks/fixtures/npm-workspaces/packages/cli/_package.json +++ b/e2e/ci-e2e/mocks/fixtures/npm-workspaces/packages/cli/_package.json @@ -2,7 +2,7 @@ "name": "@example/cli", "version": "1.2.3", "scripts": { - "code-pushup": "code-pushup --no-progress" + "code-pushup": "code-pushup" }, "dependencies": { "@example/core": "1.2.3" diff --git a/e2e/ci-e2e/mocks/fixtures/npm-workspaces/packages/core/_package.json b/e2e/ci-e2e/mocks/fixtures/npm-workspaces/packages/core/_package.json index 7d1338389..b5b954998 100644 --- a/e2e/ci-e2e/mocks/fixtures/npm-workspaces/packages/core/_package.json +++ b/e2e/ci-e2e/mocks/fixtures/npm-workspaces/packages/core/_package.json @@ -2,7 +2,7 @@ "name": "@example/core", "version": "1.2.3", "scripts": { - "code-pushup": "code-pushup --no-progress" + "code-pushup": "code-pushup" }, "dependencies": { "@example/utils": "1.2.3" diff --git a/e2e/ci-e2e/mocks/fixtures/npm-workspaces/packages/utils/_package.json b/e2e/ci-e2e/mocks/fixtures/npm-workspaces/packages/utils/_package.json index b739b5d9d..55db64fbe 100644 --- a/e2e/ci-e2e/mocks/fixtures/npm-workspaces/packages/utils/_package.json +++ b/e2e/ci-e2e/mocks/fixtures/npm-workspaces/packages/utils/_package.json @@ -2,6 +2,6 @@ "name": "@example/utils", "version": "1.2.3", "scripts": { - "code-pushup": "code-pushup --no-progress" + "code-pushup": "code-pushup" } } diff --git a/e2e/ci-e2e/mocks/fixtures/nx-monorepo/apps/api/_project.json b/e2e/ci-e2e/mocks/fixtures/nx-monorepo/apps/api/_project.json index 9a9308248..5b4309d27 100644 --- a/e2e/ci-e2e/mocks/fixtures/nx-monorepo/apps/api/_project.json +++ b/e2e/ci-e2e/mocks/fixtures/nx-monorepo/apps/api/_project.json @@ -3,7 +3,7 @@ "projectType": "application", "targets": { "code-pushup": { - "command": "npx @code-pushup/cli --no-progress --config=apps/api/code-pushup.config.js" + "command": "npx @code-pushup/cli --config=apps/api/code-pushup.config.js" } } } diff --git a/e2e/ci-e2e/mocks/fixtures/nx-monorepo/apps/cms/_project.json b/e2e/ci-e2e/mocks/fixtures/nx-monorepo/apps/cms/_project.json index dfc038de3..cbc071ccb 100644 --- a/e2e/ci-e2e/mocks/fixtures/nx-monorepo/apps/cms/_project.json +++ b/e2e/ci-e2e/mocks/fixtures/nx-monorepo/apps/cms/_project.json @@ -3,7 +3,7 @@ "projectType": "application", "targets": { "code-pushup": { - "command": "npx @code-pushup/cli --no-progress --config=apps/cms/code-pushup.config.js" + "command": "npx @code-pushup/cli --config=apps/cms/code-pushup.config.js" } } } diff --git a/e2e/ci-e2e/mocks/fixtures/nx-monorepo/apps/web/_project.json b/e2e/ci-e2e/mocks/fixtures/nx-monorepo/apps/web/_project.json index 992d0e57e..0cd56cfc4 100644 --- a/e2e/ci-e2e/mocks/fixtures/nx-monorepo/apps/web/_project.json +++ b/e2e/ci-e2e/mocks/fixtures/nx-monorepo/apps/web/_project.json @@ -3,7 +3,7 @@ "projectType": "application", "targets": { "code-pushup": { - "command": "npx @code-pushup/cli --no-progress --config=apps/web/code-pushup.config.js" + "command": "npx @code-pushup/cli --config=apps/web/code-pushup.config.js" } } } diff --git a/e2e/ci-e2e/mocks/fixtures/nx-monorepo/libs/ui/_project.json b/e2e/ci-e2e/mocks/fixtures/nx-monorepo/libs/ui/_project.json index aec5ff267..02cb7a8d4 100644 --- a/e2e/ci-e2e/mocks/fixtures/nx-monorepo/libs/ui/_project.json +++ b/e2e/ci-e2e/mocks/fixtures/nx-monorepo/libs/ui/_project.json @@ -3,7 +3,7 @@ "projectType": "library", "targets": { "code-pushup": { - "command": "npx @code-pushup/cli --no-progress --config=libs/ui/code-pushup.config.js" + "command": "npx @code-pushup/cli --config=libs/ui/code-pushup.config.js" } } } diff --git a/e2e/ci-e2e/mocks/fixtures/nx-monorepo/libs/utils/_project.json b/e2e/ci-e2e/mocks/fixtures/nx-monorepo/libs/utils/_project.json index fc0812779..e92a05c11 100644 --- a/e2e/ci-e2e/mocks/fixtures/nx-monorepo/libs/utils/_project.json +++ b/e2e/ci-e2e/mocks/fixtures/nx-monorepo/libs/utils/_project.json @@ -3,7 +3,7 @@ "projectType": "library", "targets": { "code-pushup": { - "command": "npx @code-pushup/cli --no-progress --config=libs/utils/code-pushup.config.js" + "command": "npx @code-pushup/cli --config=libs/utils/code-pushup.config.js" } } } diff --git a/e2e/cli-e2e/tests/__snapshots__/help.e2e.test.ts.snap b/e2e/cli-e2e/tests/__snapshots__/help.e2e.test.ts.snap index e9f9d47fd..32dc4aee7 100644 --- a/e2e/cli-e2e/tests/__snapshots__/help.e2e.test.ts.snap +++ b/e2e/cli-e2e/tests/__snapshots__/help.e2e.test.ts.snap @@ -18,8 +18,6 @@ Commands: Global Options: - --progress Show progress bar in stdout. - [boolean] [default: false in CI environment, otherwise true] --verbose When true creates more verbose output. This is helpful w hen debugging. You may also set CP_VERBOSE env variable instead. [boolean] [default: false] diff --git a/e2e/cli-e2e/tests/collect.e2e.test.ts b/e2e/cli-e2e/tests/collect.e2e.test.ts index c0c2688f1..3799cd59f 100644 --- a/e2e/cli-e2e/tests/collect.e2e.test.ts +++ b/e2e/cli-e2e/tests/collect.e2e.test.ts @@ -51,12 +51,7 @@ describe('CLI collect', () => { it('should create report.md', async () => { const { code } = await executeProcess({ command: 'npx', - args: [ - '@code-pushup/cli', - '--no-progress', - 'collect', - '--persist.format=md', - ], + args: ['@code-pushup/cli', 'collect', '--persist.format=md'], cwd: dummyDir, }); @@ -72,7 +67,7 @@ describe('CLI collect', () => { it('should write runner outputs if --cache is given', async () => { const { code } = await executeProcess({ command: 'npx', - args: ['@code-pushup/cli', '--no-progress', 'collect', '--cache'], + args: ['@code-pushup/cli', 'collect', '--cache'], cwd: dummyDir, }); @@ -94,12 +89,7 @@ describe('CLI collect', () => { it('should not create reports if --persist.skipReports is given', async () => { const { code } = await executeProcess({ command: 'npx', - args: [ - '@code-pushup/cli', - '--no-progress', - 'collect', - '--persist.skipReports', - ], + args: ['@code-pushup/cli', 'collect', '--persist.skipReports'], cwd: dummyDir, }); @@ -116,7 +106,7 @@ describe('CLI collect', () => { it('should print report summary to stdout', async () => { const { code, stdout } = await executeProcess({ command: 'npx', - args: ['@code-pushup/cli', '--no-progress', 'collect'], + args: ['@code-pushup/cli', 'collect'], cwd: dummyDir, }); diff --git a/e2e/cli-e2e/tests/print-config.e2e.test.ts b/e2e/cli-e2e/tests/print-config.e2e.test.ts index 2365b2ea5..bf87be7dd 100644 --- a/e2e/cli-e2e/tests/print-config.e2e.test.ts +++ b/e2e/cli-e2e/tests/print-config.e2e.test.ts @@ -45,7 +45,6 @@ describe('CLI print-config', () => { args: [ '@code-pushup/cli', 'print-config', - '--no-progress', `--config=${configFilePath(ext)}`, '--tsconfig=tsconfig.base.json', '--persist.outputDir=output-dir', diff --git a/e2e/plugin-axe-e2e/tests/collect.e2e.test.ts b/e2e/plugin-axe-e2e/tests/collect.e2e.test.ts index a1b2d8cce..2d663c1d7 100644 --- a/e2e/plugin-axe-e2e/tests/collect.e2e.test.ts +++ b/e2e/plugin-axe-e2e/tests/collect.e2e.test.ts @@ -42,7 +42,7 @@ describe('PLUGIN collect report with axe-plugin NPM package', () => { it('should run plugin over CLI and create report.json', async () => { const { code } = await executeProcess({ command: 'npx', - args: ['@code-pushup/cli', 'collect', '--no-progress'], + args: ['@code-pushup/cli', 'collect'], cwd: defaultSetupDir, }); diff --git a/e2e/plugin-coverage-e2e/tests/collect.e2e.test.ts b/e2e/plugin-coverage-e2e/tests/collect.e2e.test.ts index 974c258c5..3f36c3a22 100644 --- a/e2e/plugin-coverage-e2e/tests/collect.e2e.test.ts +++ b/e2e/plugin-coverage-e2e/tests/collect.e2e.test.ts @@ -43,7 +43,7 @@ describe('PLUGIN collect report with coverage-plugin NPM package', () => { it('should run Code coverage plugin which runs tests and creates report.json', async () => { const { code } = await executeProcess({ command: 'npx', - args: ['code-pushup', 'collect', '--no-progress'], + args: ['code-pushup', 'collect'], cwd: basicDir, }); @@ -60,7 +60,7 @@ describe('PLUGIN collect report with coverage-plugin NPM package', () => { it('should run Code coverage plugin which parses existing lcov report and creates report.json', async () => { const { code } = await executeProcess({ command: 'npx', - args: ['@code-pushup/cli', 'collect', '--no-progress'], + args: ['@code-pushup/cli', 'collect'], cwd: existingDir, }); diff --git a/e2e/plugin-eslint-e2e/tests/collect.e2e.test.ts b/e2e/plugin-eslint-e2e/tests/collect.e2e.test.ts index 93ae1e4f9..a2e20bd54 100644 --- a/e2e/plugin-eslint-e2e/tests/collect.e2e.test.ts +++ b/e2e/plugin-eslint-e2e/tests/collect.e2e.test.ts @@ -64,7 +64,7 @@ describe('PLUGIN collect report with eslint-plugin NPM package', () => { it('should run ESLint plugin for flat config and create report.json', async () => { const { code } = await executeProcess({ command: 'npx', - args: ['@code-pushup/cli', 'collect', '--no-progress'], + args: ['@code-pushup/cli', 'collect'], cwd: flatConfigDir, }); @@ -81,7 +81,7 @@ describe('PLUGIN collect report with eslint-plugin NPM package', () => { it('should run ESLint plugin for legacy config and create report.json', async () => { const { code } = await executeProcess({ command: 'npx', - args: ['@code-pushup/cli', 'collect', '--no-progress'], + args: ['@code-pushup/cli', 'collect'], cwd: legacyConfigDir, env: { ...process.env, ESLINT_USE_FLAT_CONFIG: 'false' }, }); @@ -99,7 +99,7 @@ describe('PLUGIN collect report with eslint-plugin NPM package', () => { it('should run ESLint plugin with artifacts options and create eslint-report.json and report.json', async () => { const { code } = await executeProcess({ command: 'npx', - args: ['@code-pushup/cli', 'collect', '--no-progress'], + args: ['@code-pushup/cli', 'collect'], cwd: artifactsConfigDir, }); diff --git a/e2e/plugin-js-packages-e2e/tests/plugin-js-packages.e2e.test.ts b/e2e/plugin-js-packages-e2e/tests/plugin-js-packages.e2e.test.ts index bec2b8129..b5bd882ad 100644 --- a/e2e/plugin-js-packages-e2e/tests/plugin-js-packages.e2e.test.ts +++ b/e2e/plugin-js-packages-e2e/tests/plugin-js-packages.e2e.test.ts @@ -47,7 +47,6 @@ describe('plugin-js-packages', () => { '@code-pushup/cli', 'collect', '--verbose', - '--no-progress', `--config=${path.join( TEST_OUTPUT_DIR, 'npm-repo', diff --git a/e2e/plugin-jsdocs-e2e/tests/collect.e2e.test.ts b/e2e/plugin-jsdocs-e2e/tests/collect.e2e.test.ts index 5f38a5422..4b9bdc492 100644 --- a/e2e/plugin-jsdocs-e2e/tests/collect.e2e.test.ts +++ b/e2e/plugin-jsdocs-e2e/tests/collect.e2e.test.ts @@ -56,7 +56,7 @@ describe('PLUGIN collect report with jsdocs-plugin NPM package', () => { it('should run JSDoc plugin for Angular example dir and create report.json', async () => { const { code } = await executeProcess({ command: 'npx', - args: ['@code-pushup/cli', 'collect', '--no-progress'], + args: ['@code-pushup/cli', 'collect'], cwd: angularDir, }); diff --git a/e2e/plugin-lighthouse-e2e/tests/collect.e2e.test.ts b/e2e/plugin-lighthouse-e2e/tests/collect.e2e.test.ts index d00350679..85c734c0c 100644 --- a/e2e/plugin-lighthouse-e2e/tests/collect.e2e.test.ts +++ b/e2e/plugin-lighthouse-e2e/tests/collect.e2e.test.ts @@ -36,7 +36,7 @@ describe('PLUGIN collect report with lighthouse-plugin NPM package', () => { const { code, stdout } = await executeProcess({ command: 'npx', // verbose exposes audits with perfect scores that are hidden in the default stdout - args: ['@code-pushup/cli', 'collect', '--no-progress', '--verbose'], + args: ['@code-pushup/cli', 'collect', '--verbose'], cwd: defaultSetupDir, }); diff --git a/e2e/plugin-typescript-e2e/tests/collect.e2e.test.ts b/e2e/plugin-typescript-e2e/tests/collect.e2e.test.ts index c1e5af653..b92e53153 100644 --- a/e2e/plugin-typescript-e2e/tests/collect.e2e.test.ts +++ b/e2e/plugin-typescript-e2e/tests/collect.e2e.test.ts @@ -71,7 +71,6 @@ describe('PLUGIN collect report with typescript-plugin NPM package', () => { args: [ '@code-pushup/cli', 'collect', - '--no-progress', '--verbose', `--persist.outputDir=${outputDir}`, ], diff --git a/examples/plugins/code-pushup.config.ts b/examples/plugins/code-pushup.config.ts index aaa5ce5b2..ce5be0671 100644 --- a/examples/plugins/code-pushup.config.ts +++ b/examples/plugins/code-pushup.config.ts @@ -16,7 +16,7 @@ import { * `nx run-collect examples-plugins` * * - For all formats use `--persist.format=md,json` - * - For better debugging, use `--verbose --no-progress` + * - For better debugging, use `--verbose` * */ diff --git a/nx.json b/nx.json index 916de8697..4f9f515b5 100644 --- a/nx.json +++ b/nx.json @@ -150,7 +150,6 @@ "options": { "command": "node packages/cli/src/index.ts", "args": [ - "--no-progress", "--verbose", "--config={projectRoot}/code-pushup.config.ts", "--cache.read", @@ -172,7 +171,6 @@ "options": { "command": "node packages/cli/src/index.ts collect", "args": [ - "--no-progress", "--verbose", "--config={projectRoot}/code-pushup.config.ts", "--cache.write", @@ -194,7 +192,6 @@ "options": { "command": "node packages/cli/src/index.ts collect", "args": [ - "--no-progress", "--verbose", "--config={projectRoot}/code-pushup.config.ts", "--cache.write", @@ -220,7 +217,6 @@ "options": { "command": "node packages/cli/src/index.ts collect", "args": [ - "--no-progress", "--verbose", "--config={projectRoot}/code-pushup.config.ts", "--onlyPlugins=js-packages", @@ -240,7 +236,6 @@ "options": { "command": "node packages/cli/src/index.ts collect", "args": [ - "--no-progress", "--verbose", "--config={projectRoot}/code-pushup.config.ts", "--cache.write", @@ -266,7 +261,6 @@ "options": { "command": "node packages/cli/src/index.ts collect", "args": [ - "--no-progress", "--verbose", "--config={projectRoot}/code-pushup.config.ts", "--cache.write", @@ -292,7 +286,6 @@ "options": { "command": "node packages/cli/src/index.ts collect", "args": [ - "--no-progress", "--verbose", "--config={projectRoot}/code-pushup.config.ts", "--cache.write", @@ -314,7 +307,6 @@ "options": { "command": "node packages/cli/src/index.ts collect", "args": [ - "--no-progress", "--verbose", "--config={projectRoot}/code-pushup.config.ts", "--cache.write", diff --git a/package-lock.json b/package-lock.json index cbb2f418e..deb4b547d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,6 @@ "glob": "^11.0.1", "lighthouse": "^12.0.0", "lighthouse-logger": "2.0.1", - "multi-progress-bars": "^5.0.3", "nx": "21.4.1", "ora": "^9.0.0", "parse-lcov": "^1.0.4", @@ -23180,61 +23179,6 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/multi-progress-bars": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/multi-progress-bars/-/multi-progress-bars-5.0.3.tgz", - "integrity": "sha512-/EzDF3NVeYTFLoLQ33fgvM6933rS2MZlEPWBivsc94Y/lj2xpWOs/DpJrCG+XrPOo4/P6DW+oxZyKnRKw0d/nQ==", - "dependencies": { - "chalk": "^5.2.0", - "string-width": "5.1.2", - "strip-ansi": "7.0.1" - }, - "engines": { - "node": ">14.18.0" - } - }, - "node_modules/multi-progress-bars/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/multi-progress-bars/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/multi-progress-bars/node_modules/strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/mute-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", diff --git a/package.json b/package.json index 3af1d474c..e4c55ca77 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,6 @@ "glob": "^11.0.1", "lighthouse": "^12.0.0", "lighthouse-logger": "2.0.1", - "multi-progress-bars": "^5.0.3", "nx": "21.4.1", "ora": "^9.0.0", "parse-lcov": "^1.0.4", diff --git a/packages/ci/src/lib/monorepo/handlers/npm.unit.test.ts b/packages/ci/src/lib/monorepo/handlers/npm.unit.test.ts index 1cff90eb9..0bb5719aa 100644 --- a/packages/ci/src/lib/monorepo/handlers/npm.unit.test.ts +++ b/packages/ci/src/lib/monorepo/handlers/npm.unit.test.ts @@ -70,7 +70,7 @@ describe('npmHandler', () => { 'package-lock.json': '', 'apps/backend/package.json': pkgJsonContent({ name: 'backend', - scripts: { 'code-pushup': 'code-pushup --no-progress' }, + scripts: { 'code-pushup': 'code-pushup' }, devDependencies: { '@code-pushup/cli': 'latest' }, }), 'apps/frontend/package.json': pkgJsonContent({ @@ -79,7 +79,7 @@ describe('npmHandler', () => { }), 'libs/shared/package.json': pkgJsonContent({ name: 'shared', - scripts: { 'code-pushup': 'code-pushup --no-progress' }, + scripts: { 'code-pushup': 'code-pushup' }, devDependencies: { '@code-pushup/cli': 'latest' }, }), }, diff --git a/packages/ci/src/lib/monorepo/handlers/pnpm.unit.test.ts b/packages/ci/src/lib/monorepo/handlers/pnpm.unit.test.ts index 386d62aaa..4ef39bfbd 100644 --- a/packages/ci/src/lib/monorepo/handlers/pnpm.unit.test.ts +++ b/packages/ci/src/lib/monorepo/handlers/pnpm.unit.test.ts @@ -64,7 +64,7 @@ describe('pnpmHandler', () => { 'pnpm-workspace.yaml': 'packages:\n- apps/*\n- libs/*\n\n', 'apps/backend/package.json': pkgJsonContent({ name: 'backend', - scripts: { 'code-pushup': 'code-pushup --no-progress' }, + scripts: { 'code-pushup': 'code-pushup' }, devDependencies: { '@code-pushup/cli': 'latest' }, }), 'apps/frontend/package.json': pkgJsonContent({ @@ -73,7 +73,7 @@ describe('pnpmHandler', () => { }), 'libs/shared/package.json': pkgJsonContent({ name: 'shared', - scripts: { 'code-pushup': 'code-pushup --no-progress' }, + scripts: { 'code-pushup': 'code-pushup' }, devDependencies: { '@code-pushup/cli': 'latest' }, }), }, diff --git a/packages/ci/src/lib/monorepo/handlers/turbo.unit.test.ts b/packages/ci/src/lib/monorepo/handlers/turbo.unit.test.ts index c4d397883..776dab0df 100644 --- a/packages/ci/src/lib/monorepo/handlers/turbo.unit.test.ts +++ b/packages/ci/src/lib/monorepo/handlers/turbo.unit.test.ts @@ -116,12 +116,12 @@ describe('turboHandler', () => { 'e2e/package.json': pkgJsonContent({ name: 'e2e' }), // not in workspace patterns 'packages/cli/package.json': pkgJsonContent({ name: '@example/cli', - scripts: { 'code-pushup': 'code-pushup --no-progress' }, + scripts: { 'code-pushup': 'code-pushup' }, devDependencies: { '@code-pushup/cli': 'latest' }, }), 'packages/core/package.json': pkgJsonContent({ name: '@example/core', - scripts: { 'code-pushup': 'code-pushup --no-progress' }, + scripts: { 'code-pushup': 'code-pushup' }, devDependencies: { '@code-pushup/cli': 'latest' }, }), 'packages/utils/package.json': pkgJsonContent({ diff --git a/packages/ci/src/lib/monorepo/handlers/yarn.unit.test.ts b/packages/ci/src/lib/monorepo/handlers/yarn.unit.test.ts index a846af3c4..6d2c3419f 100644 --- a/packages/ci/src/lib/monorepo/handlers/yarn.unit.test.ts +++ b/packages/ci/src/lib/monorepo/handlers/yarn.unit.test.ts @@ -72,7 +72,7 @@ describe('yarnHandler', () => { 'yarn.lock': '', 'apps/backend/package.json': pkgJsonContent({ name: 'backend', - scripts: { 'code-pushup': 'code-pushup --no-progress' }, + scripts: { 'code-pushup': 'code-pushup' }, devDependencies: { '@code-pushup/cli': 'latest' }, }), 'apps/frontend/package.json': pkgJsonContent({ @@ -81,7 +81,7 @@ describe('yarnHandler', () => { }), 'libs/shared/package.json': pkgJsonContent({ name: 'shared', - scripts: { 'code-pushup': 'code-pushup --no-progress' }, + scripts: { 'code-pushup': 'code-pushup' }, devDependencies: { '@code-pushup/cli': 'latest' }, }), }, diff --git a/packages/ci/src/lib/monorepo/list-projects.unit.test.ts b/packages/ci/src/lib/monorepo/list-projects.unit.test.ts index 6adbee150..4680b54f6 100644 --- a/packages/ci/src/lib/monorepo/list-projects.unit.test.ts +++ b/packages/ci/src/lib/monorepo/list-projects.unit.test.ts @@ -86,22 +86,22 @@ describe('listMonorepoProjects', () => { }), 'backend/api/package.json': pkgJsonContent({ name: 'api', - scripts: { 'code-pushup': 'code-pushup --no-progress' }, + scripts: { 'code-pushup': 'code-pushup' }, }), 'backend/auth/package.json': pkgJsonContent({ name: 'auth', - scripts: { 'code-pushup': 'code-pushup --no-progress' }, + scripts: { 'code-pushup': 'code-pushup' }, }), 'e2e/package.json': pkgJsonContent({ name: 'e2e', }), 'frontend/cms/package.json': pkgJsonContent({ name: 'cms', - scripts: { 'code-pushup': 'code-pushup --no-progress' }, + scripts: { 'code-pushup': 'code-pushup' }, }), 'frontend/web/package.json': pkgJsonContent({ name: 'web', - scripts: { 'code-pushup': 'code-pushup --no-progress' }, + scripts: { 'code-pushup': 'code-pushup' }, }), }, MEMFS_VOLUME, diff --git a/packages/ci/src/lib/monorepo/packages.unit.test.ts b/packages/ci/src/lib/monorepo/packages.unit.test.ts index b7024e953..af7c31669 100644 --- a/packages/ci/src/lib/monorepo/packages.unit.test.ts +++ b/packages/ci/src/lib/monorepo/packages.unit.test.ts @@ -309,10 +309,7 @@ describe('readRootPackageJson', () => { describe('hasScript', () => { it('should return true if script in package.json "scripts"', () => { expect( - hasScript( - { scripts: { 'code-pushup': 'code-pushup --no-progress' } }, - 'code-pushup', - ), + hasScript({ scripts: { 'code-pushup': 'code-pushup' } }, 'code-pushup'), ).toBeTrue(); }); diff --git a/packages/cli/README.md b/packages/cli/README.md index 294599b49..5227524fe 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -197,7 +197,6 @@ Each example is fully tested to demonstrate best practices for plugin testing as | Option | Type | Default | Description | | ---------------- | --------- | -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | -| **`--progress`** | `boolean` | `false` in CI, otherwise `true` | Show progress bar in stdout. | | **`--verbose`** | `boolean` | `false` | When true creates more verbose output. This is helpful when debugging. You may also set `CP_VERBOSE` env variable instead. | | **`--config`** | `string` | looks for `code-pushup.config.{ts\|mjs\|js}` | Path to config file. | | **`--tsconfig`** | `string` | n/a | Path to a TypeScript config, used to load config file. | diff --git a/packages/cli/docs/custom-plugins.md b/packages/cli/docs/custom-plugins.md index 93c1bb725..6847c4159 100644 --- a/packages/cli/docs/custom-plugins.md +++ b/packages/cli/docs/custom-plugins.md @@ -365,7 +365,7 @@ function lhrOutputTransform(audits: string[]): OutputTransform { } ``` -Now we can execute the CLI with `npx code-pushup collect --no-progress` and see a similar output as the following: +Now we can execute the CLI with `npx code-pushup collect` and see a similar output as the following:
stdout of CLI for the above code (collapsed for brevity) @@ -682,7 +682,4 @@ Following options are helpful in debugging: - use [`--config`](../README.md#global-options) to point to a different config file - use [`--verbose`](../README.md#global-options) to get more information printed in the terminal -- use [`--no-progress`](../README.md#global-options) to get better readability of logs. - The progressbar would otherwise interfere with your logs and makes them harder to read. -- use [`--format=md`](../README.md#common-command-options) to see all information provided by plugin outputs - use [`--onlyPlugin`](../README.md#common-command-options) to restrict the execution of plugins to only the listed ones diff --git a/packages/cli/src/lib/implementation/core-config.middleware.int.test.ts b/packages/cli/src/lib/implementation/core-config.middleware.int.test.ts index 99288a834..464b1dfc2 100644 --- a/packages/cli/src/lib/implementation/core-config.middleware.int.test.ts +++ b/packages/cli/src/lib/implementation/core-config.middleware.int.test.ts @@ -20,7 +20,6 @@ const configDirPath = path.join( describe('coreConfigMiddleware', () => { const CLI_DEFAULTS = { - progress: true, plugins: [], onlyPlugins: [], skipPlugins: [], diff --git a/packages/cli/src/lib/implementation/core-config.middleware.ts b/packages/cli/src/lib/implementation/core-config.middleware.ts index dea6a7aea..ad2fda834 100644 --- a/packages/cli/src/lib/implementation/core-config.middleware.ts +++ b/packages/cli/src/lib/implementation/core-config.middleware.ts @@ -12,9 +12,9 @@ import { } from '@code-pushup/models'; import type { CoreConfigCliOptions } from './core-config.model.js'; import type { FilterOptions } from './filter.model.js'; -import type { GeneralCliOptions } from './global.model.js'; +import type { GlobalOptions } from './global.model.js'; -export type CoreConfigMiddlewareOptions = GeneralCliOptions & +export type CoreConfigMiddlewareOptions = GlobalOptions & CoreConfigCliOptions & FilterOptions; @@ -38,7 +38,7 @@ function buildPersistConfig( export async function coreConfigMiddleware< T extends CoreConfigMiddlewareOptions, ->(processArgs: T): Promise { +>(processArgs: T): Promise { const { config, tsconfig, diff --git a/packages/cli/src/lib/implementation/core-config.model.ts b/packages/cli/src/lib/implementation/core-config.model.ts index cf36caadf..ea2d657ef 100644 --- a/packages/cli/src/lib/implementation/core-config.model.ts +++ b/packages/cli/src/lib/implementation/core-config.model.ts @@ -25,12 +25,6 @@ export type CacheConfigCliOptions = { cache?: boolean; }; -export type ConfigCliOptions = { - config?: string; - tsconfig?: string; - verbose?: string; -}; - export type CoreConfigCliOptions = Pick & { upload?: Partial>; cache?: CacheConfig; diff --git a/packages/cli/src/lib/implementation/filter.model.ts b/packages/cli/src/lib/implementation/filter.model.ts index 5d36bcdf9..75a792f62 100644 --- a/packages/cli/src/lib/implementation/filter.model.ts +++ b/packages/cli/src/lib/implementation/filter.model.ts @@ -1,8 +1,6 @@ -import type { GlobalOptions } from '@code-pushup/core'; import type { CoreConfig } from '@code-pushup/models'; -export type FilterOptions = Partial & - Pick & +export type FilterOptions = Pick & FilterCliOptions; export type FilterCliOptions = Partial>; diff --git a/packages/cli/src/lib/implementation/global.model.ts b/packages/cli/src/lib/implementation/global.model.ts index 5c5c408b7..36edf4893 100644 --- a/packages/cli/src/lib/implementation/global.model.ts +++ b/packages/cli/src/lib/implementation/global.model.ts @@ -1,4 +1,5 @@ -import type { GlobalOptions } from '@code-pushup/core'; -import type { ConfigCliOptions } from './core-config.model.js'; - -export type GeneralCliOptions = ConfigCliOptions & GlobalOptions; +export type GlobalOptions = { + config?: string; + tsconfig?: string; + verbose?: string; +}; diff --git a/packages/cli/src/lib/implementation/global.options.ts b/packages/cli/src/lib/implementation/global.options.ts index e0ca4b41c..4340c1f1d 100644 --- a/packages/cli/src/lib/implementation/global.options.ts +++ b/packages/cli/src/lib/implementation/global.options.ts @@ -1,18 +1,11 @@ import type { Options } from 'yargs'; -import { isCI } from '@code-pushup/utils'; -import type { GeneralCliOptions } from './global.model.js'; +import type { GlobalOptions } from './global.model.js'; export function yargsGlobalOptionsDefinition(): Record< - keyof GeneralCliOptions, + keyof GlobalOptions, Options > { return { - progress: { - describe: 'Show progress bar in stdout.', - type: 'boolean', - default: !isCI(), - defaultDescription: 'false in CI environment, otherwise true', - }, verbose: { describe: 'When true creates more verbose output. This is helpful when debugging. You may also set CP_VERBOSE env variable instead.', diff --git a/packages/cli/src/lib/implementation/set-verbose.middleware.ts b/packages/cli/src/lib/implementation/set-verbose.middleware.ts index 24291a994..161e3cad7 100644 --- a/packages/cli/src/lib/implementation/set-verbose.middleware.ts +++ b/packages/cli/src/lib/implementation/set-verbose.middleware.ts @@ -1,8 +1,7 @@ -import type { GlobalOptions } from '@code-pushup/core'; import type { CoreConfig } from '@code-pushup/models'; import { coerceBooleanValue, logger } from '@code-pushup/utils'; import type { FilterOptions } from './filter.model.js'; -import type { GeneralCliOptions } from './global.model'; +import type { GlobalOptions } from './global.model'; /** * @@ -21,7 +20,7 @@ import type { GeneralCliOptions } from './global.model'; * @param originalProcessArgs */ export function setVerboseMiddleware< - T extends GeneralCliOptions & CoreConfig & FilterOptions & GlobalOptions, + T extends GlobalOptions & CoreConfig & FilterOptions, >(originalProcessArgs: T): T { const cliVerbose = coerceBooleanValue(originalProcessArgs.verbose); if (cliVerbose != null) { diff --git a/packages/cli/src/lib/yargs-cli.int.test.ts b/packages/cli/src/lib/yargs-cli.int.test.ts index a6ac7bd6b..248e8ff10 100644 --- a/packages/cli/src/lib/yargs-cli.int.test.ts +++ b/packages/cli/src/lib/yargs-cli.int.test.ts @@ -1,8 +1,7 @@ import { describe, expect, it } from 'vitest'; +import type { CompareOptions } from '@code-pushup/core'; import type { CoreConfig, Format } from '@code-pushup/models'; -import { isCI } from '@code-pushup/utils'; import { yargsHistoryOptionsDefinition } from './history/history.options.js'; -import type { CompareOptions } from './implementation/compare.model.js'; import { yargsCompareOptionsDefinition } from './implementation/compare.options.js'; import type { PersistConfigCliOptions, @@ -10,7 +9,7 @@ import type { } from './implementation/core-config.model.js'; import type { FilterOptions } from './implementation/filter.model.js'; import { yargsFilterOptionsDefinition } from './implementation/filter.options.js'; -import type { GeneralCliOptions } from './implementation/global.model.js'; +import type { GlobalOptions } from './implementation/global.model.js'; import type { MergeDiffsOptions } from './implementation/merge-diffs.model.js'; import { yargsMergeDiffsOptionsDefinition } from './implementation/merge-diffs.options.js'; import { options } from './options.js'; @@ -18,29 +17,28 @@ import { yargsCli } from './yargs-cli.js'; describe('yargsCli', () => { it('should provide correct default values for global options', async () => { - const parsedArgv = await yargsCli([], { + const parsedArgv = await yargsCli([], { options, }).parseAsync(); expect(parsedArgv.verbose).toBe(false); - expect(parsedArgv.progress).toBe(!isCI()); }); it('should parse an empty array as a default onlyPlugins option', async () => { - const parsedArgv = await yargsCli([], { + const parsedArgv = await yargsCli([], { options: { ...options, ...yargsFilterOptionsDefinition() }, }).parseAsync(); expect(parsedArgv.onlyPlugins).toEqual([]); }); it('should parse an empty array as a default skipPlugins option', async () => { - const parsedArgv = await yargsCli([], { + const parsedArgv = await yargsCli([], { options: { ...options, ...yargsFilterOptionsDefinition() }, }).parseAsync(); expect(parsedArgv.skipPlugins).toEqual([]); }); it('should parse the overrides of skipPlugins and onlyPlugins even with different formats', async () => { - const parsedArgv = await yargsCli( + const parsedArgv = await yargsCli( [ '--onlyPlugins=lighthouse', '--onlyPlugins=eslint', @@ -57,14 +55,14 @@ describe('yargsCli', () => { }); it('should parse a single boolean negated argument', async () => { - const parsedArgv = await yargsCli(['--no-progress'], { + const parsedArgv = await yargsCli(['--no-verbose'], { options, }).parseAsync(); - expect(parsedArgv.progress).toBe(false); + expect(parsedArgv.verbose).toBe(false); }); it('should parse a single config argument as a string', async () => { - const parsedArgv = await yargsCli( + const parsedArgv = await yargsCli( ['--config=./config.a.ts'], { options }, ).parseAsync(); @@ -89,25 +87,33 @@ describe('yargsCli', () => { }); it('should parse global options correctly', async () => { - const parsedArgv = await yargsCli( - ['--verbose', '--no-progress'], + const parsedArgv = await yargsCli( + ['--verbose', '--tsconfig', 'tsconfig.json'], { options }, ).parseAsync(); expect(parsedArgv.verbose).toBe(true); - expect(parsedArgv.progress).toBe(false); + expect(parsedArgv.tsconfig).toBe('tsconfig.json'); }); it('should use the last occurrence of an argument if config is passed multiple times', async () => { - const parsedArgv = await yargsCli( + const parsedArgv = await yargsCli( ['--config=./config.a.ts', '--config=./config.b.ts'], { options }, ).parseAsync(); expect(parsedArgv.config).toBe('./config.b.ts'); }); + it('should ignore unknown options', async () => { + const parsedArgv = await yargsCli( + ['--no-progress', '--verbose'], + { options }, + ).parseAsync(); + expect(parsedArgv.verbose).toBe(true); + }); + it('should handle global options and middleware argument overrides correctly', async () => { const parsedArgv = await yargsCli< - GeneralCliOptions & + GlobalOptions & PersistConfigCliOptions & UploadConfigCliOptions & FilterOptions @@ -150,7 +156,7 @@ describe('yargsCli', () => { }); it('should parse compare options', async () => { - const parsedArgv = await yargsCli( + const parsedArgv = await yargsCli( ['--before=source-report.json', '--after', 'target-report.json'], { options: { ...options, ...yargsCompareOptionsDefinition() }, @@ -161,7 +167,7 @@ describe('yargsCli', () => { }); it('should parse merge-diffs options', async () => { - const parsedArgv = await yargsCli( + const parsedArgv = await yargsCli( [ '--files', '.code-pushup/frontend/report-diff.json', @@ -177,7 +183,7 @@ describe('yargsCli', () => { it('should error if required merge-diffs option is missing', () => { expect(() => - yargsCli([], { + yargsCli([], { options: { ...options, ...yargsMergeDiffsOptionsDefinition() }, noExitProcess: true, }).parse(), diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 259602273..52883e901 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -31,5 +31,4 @@ export { } from './lib/implementation/read-rc-file.js'; export { AuditOutputsMissingAuditError } from './lib/implementation/runner.js'; export { mergeDiffs } from './lib/merge-diffs.js'; -export type { GlobalOptions } from './lib/types.js'; export { upload, type UploadOptions } from './lib/upload.js'; diff --git a/packages/core/src/lib/collect-and-persist.ts b/packages/core/src/lib/collect-and-persist.ts index d3db86792..f0bb16ff5 100644 --- a/packages/core/src/lib/collect-and-persist.ts +++ b/packages/core/src/lib/collect-and-persist.ts @@ -16,7 +16,6 @@ import { logPersistedResults, persistReport, } from './implementation/persist.js'; -import type { GlobalOptions } from './types.js'; export type CollectAndPersistReportsOptions = Pick< CoreConfig, @@ -25,7 +24,7 @@ export type CollectAndPersistReportsOptions = Pick< persist: Required> & Pick; cache: CacheConfigObject; -} & Partial; +}; export async function collectAndPersistReports( options: CollectAndPersistReportsOptions, diff --git a/packages/core/src/lib/collect-and-persist.unit.test.ts b/packages/core/src/lib/collect-and-persist.unit.test.ts index 0b95022ca..ffd3a5975 100644 --- a/packages/core/src/lib/collect-and-persist.unit.test.ts +++ b/packages/core/src/lib/collect-and-persist.unit.test.ts @@ -50,7 +50,6 @@ describe('collectAndPersistReports', () => { ...MINIMAL_CONFIG_MOCK, persist: { outputDir: 'output', filename: 'report', format: ['md'] }, cache: { read: false, write: false }, - progress: false, }; await collectAndPersistReports(config); @@ -75,7 +74,6 @@ describe('collectAndPersistReports', () => { format: ['md'], skipReports: true, }, - progress: false, cache: { read: false, write: false }, }; await collectAndPersistReports(verboseConfig); diff --git a/packages/core/src/lib/history.ts b/packages/core/src/lib/history.ts index 257192c3c..d8c34d92e 100644 --- a/packages/core/src/lib/history.ts +++ b/packages/core/src/lib/history.ts @@ -10,7 +10,6 @@ import { safeCheckout, } from '@code-pushup/utils'; import { collectAndPersistReports } from './collect-and-persist.js'; -import type { GlobalOptions } from './types.js'; import { upload } from './upload.js'; export type HistoryOnlyOptions = { @@ -22,8 +21,7 @@ export type HistoryOptions = Pick & { persist: Required; cache: CacheConfigObject; upload?: Required; -} & HistoryOnlyOptions & - Partial; +} & HistoryOnlyOptions; export async function history( config: HistoryOptions, diff --git a/packages/core/src/lib/implementation/collect.int.test.ts b/packages/core/src/lib/implementation/collect.int.test.ts index 2d1e5dc3a..0e2c86972 100644 --- a/packages/core/src/lib/implementation/collect.int.test.ts +++ b/packages/core/src/lib/implementation/collect.int.test.ts @@ -64,7 +64,6 @@ describe('collect', () => { ...MINIMAL_CONFIG_MOCK, persist: { outputDir }, cache: { read: false, write: false }, - progress: false, }); expect(report.plugins[0]).toStrictEqual({ @@ -85,7 +84,6 @@ describe('collect', () => { ...MINIMAL_CONFIG_MOCK, persist: { outputDir }, cache: { read: false, write: true }, - progress: false, }); expect(report.plugins[0]).toStrictEqual({ @@ -108,7 +106,6 @@ describe('collect', () => { ...MINIMAL_CONFIG_MOCK, persist: { outputDir }, cache: { read: true, write: false }, - progress: false, }); expect(report.plugins[0]?.audits[0]).toStrictEqual( @@ -131,7 +128,6 @@ describe('collect', () => { ...MINIMAL_CONFIG_MOCK, persist: { outputDir }, cache: { read: true, write: true }, - progress: false, }); expect(report.plugins[0]).toStrictEqual({ diff --git a/packages/core/src/lib/implementation/collect.ts b/packages/core/src/lib/implementation/collect.ts index 9efa4a311..5c7a97e73 100644 --- a/packages/core/src/lib/implementation/collect.ts +++ b/packages/core/src/lib/implementation/collect.ts @@ -6,27 +6,23 @@ import type { Report, } from '@code-pushup/models'; import { calcDuration, getLatestCommit } from '@code-pushup/utils'; -import type { GlobalOptions } from '../types.js'; import { executePlugins } from './execute-plugin.js'; export type CollectOptions = Pick & { persist?: PersistConfig; cache: CacheConfigObject; -} & Partial; +}; /** * Run audits, collect plugin output and aggregate it into a JSON object * @param options */ export async function collect(options: CollectOptions): Promise { - const { plugins, categories, persist = {}, cache, ...otherOptions } = options; + const { plugins, categories, persist = {}, cache } = options; const date = new Date().toISOString(); const start = performance.now(); const commit = await getLatestCommit(); - const pluginOutputs = await executePlugins( - { plugins, persist, cache }, - otherOptions, - ); + const pluginOutputs = await executePlugins({ plugins, persist, cache }); const packageJson = createRequire(import.meta.url)( '../../../package.json', ) as typeof import('../../../package.json'); diff --git a/packages/core/src/lib/implementation/execute-plugin.ts b/packages/core/src/lib/implementation/execute-plugin.ts index e12dda8be..1366cf85d 100644 --- a/packages/core/src/lib/implementation/execute-plugin.ts +++ b/packages/core/src/lib/implementation/execute-plugin.ts @@ -10,15 +10,9 @@ import { type RunnerArgs, } from '@code-pushup/models'; import { - type ProgressBar, asyncSequential, - getProgressBar, - groupByStatus, - logMultipleResults, - pluralizeToken, + logger, scoreAuditsWithTarget, - settlePromise, - stringifyError, } from '@code-pushup/utils'; import { executePluginRunner, @@ -110,92 +104,31 @@ export async function executePlugin( }; } -const wrapProgress = async ( - cfg: { - plugin: PluginConfig; - persist: PersistConfig; - cache: CacheConfigObject; - }, - steps: number, - progressBar: ProgressBar | null, -) => { - const { plugin: pluginCfg, ...rest } = cfg; - progressBar?.updateTitle(`Executing ${ansis.bold(pluginCfg.title)}`); - try { - const pluginReport = await executePlugin(pluginCfg, rest); - progressBar?.incrementInSteps(steps); - return pluginReport; - } catch (error) { - progressBar?.incrementInSteps(steps); - throw new Error( - `- Plugin ${ansis.bold(pluginCfg.title)} (${ansis.bold( - pluginCfg.slug, - )}) produced the following error:\n - ${stringifyError(error)}`, - ); - } -}; - /** * Execute multiple plugins and aggregates their output. - * @public - * @param cfg - * @param {Object} [options] execution options - * @param {boolean} options.progress show progress bar - * @returns {Promise} plugin report * - * @example - * // plugin execution - * const plugins = [validate(pluginConfigSchema, {...})]; + * @param config + * @returns plugin reports * * @example - * // error handling * try { - * await executePlugins(plugins); + * await executePlugins(config); * } catch (error) { * console.error(error); // Plugin output is invalid * } - * */ -export async function executePlugins( - cfg: { - plugins: PluginConfig[]; - persist: PersistConfig; - cache: CacheConfigObject; - }, - options?: { progress?: boolean }, -): Promise { - const { plugins, ...cacheCfg } = cfg; - const { progress = false } = options ?? {}; - - const progressBar = progress ? getProgressBar('Run plugins') : null; - - const pluginsResult = plugins.map(pluginCfg => - wrapProgress( - { plugin: pluginCfg, ...cacheCfg }, - plugins.length, - progressBar, - ), - ); - - const errorsTransform = ({ reason }: PromiseRejectedResult) => String(reason); - const results = await asyncSequential(pluginsResult, settlePromise); - - progressBar?.endProgress('Done running plugins'); - - logMultipleResults(results, 'Plugins', undefined, errorsTransform); - - const { fulfilled, rejected } = groupByStatus(results); - if (rejected.length > 0) { - const errorMessages = rejected - .map(({ reason }) => String(reason)) - .join('\n'); - throw new Error( - `Executing ${pluralizeToken( - 'plugin', - rejected.length, - )} failed.\n\n${errorMessages}\n\n`, - ); - } - - return fulfilled.map(result => result.value); +export function executePlugins(config: { + plugins: PluginConfig[]; + persist: PersistConfig; + cache: CacheConfigObject; +}): Promise { + return asyncSequential(config.plugins, async (pluginConfig, index) => { + const suffix = ansis.gray(`[${index + 1}/${config.plugins.length}]`); + const title = `Running plugin "${pluginConfig.title}" ${suffix}`; + const message = `Completed "${pluginConfig.title}" plugin execution`; + return logger.group(title, async () => { + const result = await executePlugin(pluginConfig, config); + return { message, result }; + }); + }); } diff --git a/packages/core/src/lib/implementation/execute-plugin.unit.test.ts b/packages/core/src/lib/implementation/execute-plugin.unit.test.ts index c6a5eac3c..9762be94a 100644 --- a/packages/core/src/lib/implementation/execute-plugin.unit.test.ts +++ b/packages/core/src/lib/implementation/execute-plugin.unit.test.ts @@ -10,6 +10,7 @@ import { MEMFS_VOLUME, MINIMAL_PLUGIN_CONFIG_MOCK, } from '@code-pushup/test-utils'; +import { logger } from '@code-pushup/utils'; import { executePlugin, executePlugins } from './execute-plugin.js'; import * as runnerModule from './runner.js'; @@ -215,177 +216,96 @@ describe('executePlugin', () => { describe('executePlugins', () => { it('should execute valid plugins', async () => { - const pluginResult = await executePlugins( - { - plugins: [ - MINIMAL_PLUGIN_CONFIG_MOCK, - { - ...MINIMAL_PLUGIN_CONFIG_MOCK, - icon: 'nodejs', - }, - ], - persist: { outputDir: '.code-pushup' }, - cache: { read: false, write: false }, - }, - { progress: false }, - ); + const pluginResult = await executePlugins({ + plugins: [ + MINIMAL_PLUGIN_CONFIG_MOCK, + { + ...MINIMAL_PLUGIN_CONFIG_MOCK, + icon: 'nodejs', + }, + ], + persist: { outputDir: '.code-pushup' }, + cache: { read: false, write: false }, + }); expect(pluginResult[0]?.icon).toBe('javascript'); expect(pluginResult[1]?.icon).toBe('nodejs'); expect(pluginResult[0]?.audits[0]?.slug).toBe('node-version'); }); - it('should throw for invalid audit output', async () => { - const slug = 'simulate-invalid-audit-slug'; - const title = 'Simulate an invalid audit slug in outputs'; - await expect(() => - executePlugins( - { - plugins: [ - { - ...MINIMAL_PLUGIN_CONFIG_MOCK, - slug, - title, - runner: () => [ - { - slug: 'invalid-audit-slug-', - score: 0.3, - value: 16, - displayValue: '16.0.0', - }, - ], - }, - ] satisfies PluginConfig[], - persist: { outputDir: '.code-pushup' }, - cache: { read: false, write: false }, - }, - { progress: false }, - ), - ).rejects.toThrow( - `Executing 1 plugin failed.\n\nError: - Plugin ${ansis.bold( - title, - )} (${ansis.bold(slug)}) produced the following error:\n - Audit output is invalid`, - ); - }); + it('should throw for 1st invalid audit output', async () => { + const plugins = [ + { + ...MINIMAL_PLUGIN_CONFIG_MOCK, + runner: () => [{ slug: 'my-audit', score: 0 }] as AuditOutputs, + }, + { ...MINIMAL_PLUGIN_CONFIG_MOCK, runner: vi.fn() }, + ] as const satisfies PluginConfig[]; - it('should throw for one failing plugin', async () => { - const missingAuditSlug = 'missing-audit-slug'; await expect(() => - executePlugins( - { - plugins: [ - { - ...MINIMAL_PLUGIN_CONFIG_MOCK, - slug: 'plg1', - title: 'plg1', - runner: () => [ - { - slug: `${missingAuditSlug}-a`, - score: 0.3, - value: 16, - displayValue: '16.0.0', - }, - ], - }, - ] satisfies PluginConfig[], - persist: { outputDir: '.code-pushup' }, - cache: { read: false, write: false }, - }, - { progress: false }, - ), - ).rejects.toThrow('Executing 1 plugin failed.\n\n'); + executePlugins({ + plugins, + persist: { outputDir: '.code-pushup' }, + cache: { read: false, write: false }, + }), + ).rejects.toThrow(`Invalid ${ansis.bold('AuditOutputs')} +✖ Invalid input: expected number, received undefined + → at [0].value +`); + expect(plugins[1].runner).not.toHaveBeenCalled(); }); - it('should throw for multiple failing plugins', async () => { - const missingAuditSlug = 'missing-audit-slug'; - await expect(() => - executePlugins( - { - plugins: [ - { - ...MINIMAL_PLUGIN_CONFIG_MOCK, - slug: 'plg1', - title: 'plg1', - runner: () => [ - { - slug: `${missingAuditSlug}-a`, - score: 0.3, - value: 16, - displayValue: '16.0.0', - }, - ], - }, - { - ...MINIMAL_PLUGIN_CONFIG_MOCK, - slug: 'plg2', - title: 'plg2', - runner: () => [ - { - slug: `${missingAuditSlug}-b`, - score: 0.3, - value: 16, - displayValue: '16.0.0', - }, - ], - }, - ] satisfies PluginConfig[], - persist: { outputDir: '.code-pushup' }, - cache: { read: false, write: false }, - }, - { progress: false }, - ), - ).rejects.toThrow('Executing 2 plugins failed.\n\n'); + it('should resolve plugin reports', async () => { + await expect( + executePlugins({ + plugins: [MINIMAL_PLUGIN_CONFIG_MOCK], + persist: { outputDir: '.code-pushup' }, + cache: { read: false, write: false }, + }), + ).resolves.toEqual([ + expect.objectContaining({ + slug: 'node', + title: 'Node', + audits: expect.arrayContaining([ + expect.objectContaining({ + slug: 'node-version', + title: 'Node version', + score: 0.3, + value: 16, + }), + ]), + }), + ]); }); - it('should throw with indentation in message', async () => { - const missingAuditSlug = 'missing-audit-slug'; + it('should print log groups for each plugin', async () => { + await expect( + executePlugins({ + plugins: [ + { ...MINIMAL_PLUGIN_CONFIG_MOCK, title: 'Plugin A' }, + { ...MINIMAL_PLUGIN_CONFIG_MOCK, title: 'Plugin B' }, + { ...MINIMAL_PLUGIN_CONFIG_MOCK, title: 'Plugin C' }, + ], + persist: { outputDir: '.code-pushup' }, + cache: { read: false, write: false }, + }), + ).resolves.toBeArrayOfSize(3); - await expect(() => - executePlugins( - { - plugins: [ - { - ...MINIMAL_PLUGIN_CONFIG_MOCK, - slug: 'plg1', - title: 'plg1', - runner: () => [ - { - slug: `${missingAuditSlug}-a`, - score: 0.3, - value: 16, - displayValue: '16.0.0', - }, - ], - }, - { - ...MINIMAL_PLUGIN_CONFIG_MOCK, - slug: 'plg2', - title: 'plg2', - runner: () => [ - { - slug: `${missingAuditSlug}-b`, - score: 0.3, - value: 16, - displayValue: '16.0.0', - }, - ], - }, - ] satisfies PluginConfig[], - persist: { outputDir: '.code-pushup' }, - cache: { read: false, write: false }, - }, - { progress: false }, - ), - ).rejects.toThrow( - `Error: - Plugin ${ansis.bold('plg1')} (${ansis.bold( - 'plg1', - )}) produced the following error:\n - Audit metadata not present in plugin config. Missing slug: ${ansis.bold( - 'missing-audit-slug-a', - )}\nError: - Plugin ${ansis.bold('plg2')} (${ansis.bold( - 'plg2', - )}) produced the following error:\n - Audit metadata not present in plugin config. Missing slug: ${ansis.bold( - 'missing-audit-slug-b', - )}`, + expect(logger.group).toHaveBeenCalledTimes(3); + expect(logger.group).toHaveBeenNthCalledWith( + 1, + `Running plugin "Plugin A" ${ansis.gray('[1/3]')}`, + expect.any(Function), + ); + expect(logger.group).toHaveBeenNthCalledWith( + 2, + `Running plugin "Plugin B" ${ansis.gray('[2/3]')}`, + expect.any(Function), + ); + expect(logger.group).toHaveBeenNthCalledWith( + 3, + `Running plugin "Plugin C" ${ansis.gray('[3/3]')}`, + expect.any(Function), ); }); @@ -403,32 +323,29 @@ describe('executePlugins', () => { MEMFS_VOLUME, ); - const pluginResult = await executePlugins( - { - plugins: [ - { - ...MINIMAL_PLUGIN_CONFIG_MOCK, - runner: { - command: 'echo', - args: ['16'], - outputFile: 'output.json', - outputTransform: (outputs: unknown): Promise => - Promise.resolve([ - { - slug: (outputs as AuditOutputs)[0]!.slug, - score: 0.3, - value: 16, - displayValue: '16.0.0', - }, - ]), - }, + const pluginResult = await executePlugins({ + plugins: [ + { + ...MINIMAL_PLUGIN_CONFIG_MOCK, + runner: { + command: 'echo', + args: ['16'], + outputFile: 'output.json', + outputTransform: (outputs: unknown): Promise => + Promise.resolve([ + { + slug: (outputs as AuditOutputs)[0]!.slug, + score: 0.3, + value: 16, + displayValue: '16.0.0', + }, + ]), }, - ], - persist: { outputDir: MEMFS_VOLUME }, - cache: { read: false, write: false }, - }, - { progress: false }, - ); + }, + ], + persist: { outputDir: MEMFS_VOLUME }, + cache: { read: false, write: false }, + }); expect(pluginResult[0]?.audits[0]?.slug).toBe('node-version'); expect(pluginResult[0]?.audits[0]?.displayValue).toBe('16.0.0'); }); diff --git a/packages/core/src/lib/implementation/runner.ts b/packages/core/src/lib/implementation/runner.ts index 8aa6174e1..83c807f61 100644 --- a/packages/core/src/lib/implementation/runner.ts +++ b/packages/core/src/lib/implementation/runner.ts @@ -8,6 +8,7 @@ import { type RunnerConfig, type RunnerFunction, auditOutputsSchema, + validate, } from '@code-pushup/models'; import { calcDuration, @@ -87,11 +88,7 @@ export async function executePluginRunner( const duration = calcDuration(start); - const result = auditOutputsSchema.safeParse(unvalidatedAuditOutputs); - if (!result.success) { - throw new Error(`Audit output is invalid: ${result.error.message}`); - } - const auditOutputs = result.data; + const auditOutputs = validate(auditOutputsSchema, unvalidatedAuditOutputs); auditOutputsCorrelateWithPluginOutput(auditOutputs, pluginConfigAudits); return { diff --git a/packages/core/src/lib/types.ts b/packages/core/src/lib/types.ts deleted file mode 100644 index 98f1b7f52..000000000 --- a/packages/core/src/lib/types.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type GlobalOptions = { - // Show progress bar in stdout - progress: boolean; -}; diff --git a/packages/core/src/lib/upload.ts b/packages/core/src/lib/upload.ts index c63fef4c1..0dbd68c29 100644 --- a/packages/core/src/lib/upload.ts +++ b/packages/core/src/lib/upload.ts @@ -3,11 +3,10 @@ import type { PersistConfig, Report, UploadConfig } from '@code-pushup/models'; import { loadReport } from '@code-pushup/utils'; import { reportToGQL } from './implementation/report-to-gql.js'; import { loadPortalClient } from './load-portal-client.js'; -import type { GlobalOptions } from './types.js'; export type UploadOptions = { upload?: UploadConfig } & { persist: Required; -} & Partial; +}; /** * Uploads collected audits to the portal diff --git a/packages/core/src/lib/upload.unit.test.ts b/packages/core/src/lib/upload.unit.test.ts index dd8a86ece..92712b113 100644 --- a/packages/core/src/lib/upload.unit.test.ts +++ b/packages/core/src/lib/upload.unit.test.ts @@ -20,7 +20,6 @@ describe('upload', () => { it('should call upload with correct data', async () => { const result = await upload({ - progress: false, upload: { apiKey: 'dummy-api-key', server: 'https://example.com/api', @@ -31,6 +30,7 @@ describe('upload', () => { outputDir: MEMFS_VOLUME, filename: 'report', format: ['json'], + skipReports: false, }, }); @@ -58,11 +58,11 @@ describe('upload', () => { it('should throw for missing upload configuration', async () => { await expect( upload({ - progress: false, persist: { outputDir: MEMFS_VOLUME, filename: 'report', format: ['json'], + skipReports: false, }, upload: undefined, }), diff --git a/packages/models/src/lib/implementation/schemas.unit.test.ts b/packages/models/src/lib/implementation/schemas.unit.test.ts index f42c773b3..fd76746f4 100644 --- a/packages/models/src/lib/implementation/schemas.unit.test.ts +++ b/packages/models/src/lib/implementation/schemas.unit.test.ts @@ -38,6 +38,10 @@ describe('weightSchema', () => { }); describe('docsUrlSchema', () => { + beforeAll(() => { + vi.spyOn(console, 'warn').mockImplementation(() => {}); + }); + it('should accept a valid URL', () => { expect(() => docsUrlSchema.parse( diff --git a/packages/nx-plugin/src/executors/cli/README.md b/packages/nx-plugin/src/executors/cli/README.md index 720432911..24fd1f71b 100644 --- a/packages/nx-plugin/src/executors/cli/README.md +++ b/packages/nx-plugin/src/executors/cli/README.md @@ -54,7 +54,6 @@ The following things happen: "options": { "projectPrefix": "cli", // upload.project = cli-my-project "verbose": true, - "progress": false, // persist and upload options as defined in CoreConfig }, }, diff --git a/packages/nx-plugin/src/executors/cli/schema.json b/packages/nx-plugin/src/executors/cli/schema.json index 85cd0de19..b03736e23 100644 --- a/packages/nx-plugin/src/executors/cli/schema.json +++ b/packages/nx-plugin/src/executors/cli/schema.json @@ -25,10 +25,6 @@ "type": "boolean", "description": "Print additional logs" }, - "progress": { - "type": "boolean", - "description": "Print additional logs" - }, "onlyPlugins": { "type": "array", "items": { diff --git a/packages/nx-plugin/src/executors/cli/utils.unit.test.ts b/packages/nx-plugin/src/executors/cli/utils.unit.test.ts index 025c322fb..5f94d7b37 100644 --- a/packages/nx-plugin/src/executors/cli/utils.unit.test.ts +++ b/packages/nx-plugin/src/executors/cli/utils.unit.test.ts @@ -95,7 +95,6 @@ describe('parseAutorunExecutorOptions', () => { ); expect(executorOptions).toEqual( expect.objectContaining({ - progress: false, verbose: false, }), ); diff --git a/packages/nx-plugin/src/executors/internal/cli.unit.test.ts b/packages/nx-plugin/src/executors/internal/cli.unit.test.ts index 279f23505..71f00ea0b 100644 --- a/packages/nx-plugin/src/executors/internal/cli.unit.test.ts +++ b/packages/nx-plugin/src/executors/internal/cli.unit.test.ts @@ -44,15 +44,15 @@ describe('objectToCliArgs', () => { }); it('should handle boolean arguments', () => { - const params = { progress: true }; + const params = { verbose: true }; const result = objectToCliArgs(params); - expect(result).toEqual(['--progress']); + expect(result).toEqual(['--verbose']); }); it('should handle negated boolean arguments', () => { - const params = { progress: false }; + const params = { verbose: false }; const result = objectToCliArgs(params); - expect(result).toEqual(['--no-progress']); + expect(result).toEqual(['--no-verbose']); }); it('should handle array of string arguments', () => { @@ -68,12 +68,12 @@ describe('objectToCliArgs', () => { }); it('should handle nested objects', () => { - const params = { persist: { format: ['json', 'md'], verbose: false } }; + const params = { persist: { format: ['json', 'md'], skipReports: false } }; const result = objectToCliArgs(params); expect(result).toEqual([ '--persist.format="json"', '--persist.format="md"', - '--no-persist.verbose', + '--no-persist.skipReports', ]); }); diff --git a/packages/nx-plugin/src/executors/internal/config.ts b/packages/nx-plugin/src/executors/internal/config.ts index 1ef022a44..d656cecce 100644 --- a/packages/nx-plugin/src/executors/internal/config.ts +++ b/packages/nx-plugin/src/executors/internal/config.ts @@ -14,11 +14,9 @@ export function globalConfig( ): GlobalExecutorOptions { const { projectConfig } = context; const { root: projectRoot = '' } = projectConfig ?? {}; - // For better debugging use `--verbose --no-progress` as default - const { verbose, progress, config } = options; + const { verbose, config } = options; return { verbose: !!verbose, - progress: !!progress, config: config ?? path.join(projectRoot, 'code-pushup.config.ts'), }; } diff --git a/packages/nx-plugin/src/executors/internal/config.unit.test.ts b/packages/nx-plugin/src/executors/internal/config.unit.test.ts index 6cb8ed0e8..298f12290 100644 --- a/packages/nx-plugin/src/executors/internal/config.unit.test.ts +++ b/packages/nx-plugin/src/executors/internal/config.unit.test.ts @@ -34,36 +34,6 @@ describe('globalConfig', () => { ).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( {}, @@ -276,20 +246,13 @@ describe('uploadConfig', () => { }); it('should parse upload project options', () => { - const projectName = 'utils'; expect( uploadConfig( { ...baseUploadConfig, project: 'cli-utils', }, - { - workspaceRoot: 'workspace-root', - projectConfig: { - name: projectName, - root: 'root', - }, - }, + { workspaceRoot: 'workspace-root', projectName: 'utils' }, ), ).toEqual(expect.objectContaining({ project: 'cli-utils' })); }); @@ -301,13 +264,7 @@ describe('uploadConfig', () => { ...baseUploadConfig, server: 'https://new1-portal.code.pushup.dev', }, - { - workspaceRoot: 'workspace-root', - projectConfig: { - name: 'utils', - root: 'root', - }, - }, + { workspaceRoot: 'workspace-root', projectName: 'utils' }, ), ).toEqual( expect.objectContaining({ @@ -323,13 +280,7 @@ describe('uploadConfig', () => { ...baseUploadConfig, organization: 'code-pushup-v2', }, - { - workspaceRoot: 'workspace-root', - projectConfig: { - name: 'utils', - root: 'root', - }, - }, + { workspaceRoot: 'workspace-root', projectName: 'utils' }, ), ).toEqual(expect.objectContaining({ organization: 'code-pushup-v2' })); }); @@ -341,13 +292,7 @@ describe('uploadConfig', () => { ...baseUploadConfig, apiKey: '123456789', }, - { - workspaceRoot: 'workspace-root', - projectConfig: { - name: 'utils', - root: 'root', - }, - }, + { workspaceRoot: 'workspace-root', projectName: 'utils' }, ), ).toEqual(expect.objectContaining({ apiKey: '123456789' })); }); @@ -357,13 +302,7 @@ describe('uploadConfig', () => { expect( uploadConfig( {}, - { - workspaceRoot: 'workspaceRoot', - projectConfig: { - name: 'my-app', - root: 'root', - }, - }, + { workspaceRoot: 'workspaceRoot', projectName: 'my-app' }, ), ).toEqual( expect.objectContaining({ @@ -378,13 +317,7 @@ describe('uploadConfig', () => { { project: 'my-app2', }, - { - workspaceRoot: 'workspaceRoot', - projectConfig: { - name: 'my-app', - root: 'root', - }, - }, + { workspaceRoot: 'workspaceRoot', projectName: 'my-app' }, ), ).toEqual(expect.objectContaining({ project: 'my-app2' })); }); diff --git a/packages/nx-plugin/src/executors/internal/types.ts b/packages/nx-plugin/src/executors/internal/types.ts index 2f529038a..cb630cc0a 100644 --- a/packages/nx-plugin/src/executors/internal/types.ts +++ b/packages/nx-plugin/src/executors/internal/types.ts @@ -31,7 +31,6 @@ export type GlobalExecutorOptions = { command?: Command; bin?: string; verbose?: boolean; - progress?: boolean; config?: string; }; diff --git a/packages/plugin-typescript/src/lib/utils.unit.test.ts b/packages/plugin-typescript/src/lib/utils.unit.test.ts index 90c65026c..f9fd9b99e 100644 --- a/packages/plugin-typescript/src/lib/utils.unit.test.ts +++ b/packages/plugin-typescript/src/lib/utils.unit.test.ts @@ -115,10 +115,10 @@ describe('getCategoryRefsFromGroups', () => { }); describe('logSkippedAudits', () => { - it('should not warn when all audits are included', () => { + it('should not print anything when all audits are included', () => { logSkippedAudits(AUDITS); - expect(console.warn).not.toHaveBeenCalled(); + expect(logger.info).not.toHaveBeenCalled(); }); it('should warn about skipped audits', () => { diff --git a/packages/utils/mocks/fixtures/execute-progress.mock.mjs b/packages/utils/mocks/fixtures/execute-progress.mock.mjs deleted file mode 100644 index 557375f32..000000000 --- a/packages/utils/mocks/fixtures/execute-progress.mock.mjs +++ /dev/null @@ -1,49 +0,0 @@ -import ansis from 'ansis'; -import { getProgressBar } from '../../../../dist/packages/utils'; - -const _arg = (name, fallback = '') => - process.argv - .find(a => a.includes(`${name}=`)) - ?.split('=') - ?.pop() || fallback; -const duration = parseInt(_arg('duration', '300')); -const steps = parseInt(_arg('steps', '10')); -const verbose = Boolean(_arg('verbose', false)); - -/** - * Custom runner implementation that simulates asynchronous situations. - * It logs progress to the console with a configurable interval and defaults to 100ms. - * The number of runs is also configurable and defaults to 4. - * We can decide if the process should error or complete. By default, it completes. - * - * Usage: - * nx build utils - * npx node ./execute-progress.mock.mjs --verbose=1 - * - * @arg duration: number - duration of plugin run in ms; defaults to 300 - * @arg steps: number - number of updates; defaults to 4 - * @arg steps: verbose - number 0 or 1 for more information - **/ -(async () => { - verbose && - console.info( - ansis.gray( - `Start progress with duration: ${ansis.bold(duration)}, steps: ${ansis.bold( - steps, - )}`, - ), - ); - const progress = getProgressBar('mock-progress'); - - let i = 0; - const id = setInterval(() => { - if (i < steps) { - progress.incrementInSteps(steps); - verbose && console.info('Step: ', i); - } else { - clearInterval(id); - progress.endProgress(); - } - i++; - }, duration); -})(); diff --git a/packages/utils/package.json b/packages/utils/package.json index d014e93e8..09c252424 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -32,7 +32,6 @@ "build-md": "^0.4.2", "bundle-require": "^5.1.0", "esbuild": "^0.25.2", - "multi-progress-bars": "^5.0.3", "ora": "^9.0.0", "semver": "^7.6.0", "simple-git": "^3.20.0", diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 0dd6b322c..ba7a7c2b5 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -104,7 +104,6 @@ export { normalizeUrlInput, type PluginUrlContext, } from './lib/plugin-url-config.js'; -export { getProgressBar, type ProgressBar } from './lib/progress.js'; export { asyncSequential, groupByStatus, diff --git a/packages/utils/src/lib/logger.int.test.ts b/packages/utils/src/lib/logger.int.test.ts index 4d2313eea..e71ea5327 100644 --- a/packages/utils/src/lib/logger.int.test.ts +++ b/packages/utils/src/lib/logger.int.test.ts @@ -229,20 +229,17 @@ ${ansis.cyan('└')} ${ansis.green(`Total line coverage is ${ansis.bold('82%')}` ); }); - it('should use log group prefix in child loggers', async () => { - performanceNowSpy.mockReturnValueOnce(0).mockReturnValueOnce(1234); // group duration: 1.23 s + it('should return result from worker', async () => { + const result = { stats: { errors: 0, warnings: 0 }, problems: [] }; - await new Logger().group('Running plugin "ESLint"', async () => { - new Logger().info(`${ansis.blue('$')} npx eslint . --format=json`); - return 'ESLint reported 4 errors and 11 warnings'; - }); - - expect(output).toBe(` -${ansis.bold.cyan('❯ Running plugin "ESLint"')} -${ansis.cyan('│')} ${ansis.blue('$')} npx eslint . --format=json -${ansis.cyan('└')} ${ansis.green('ESLint reported 4 errors and 11 warnings')} ${ansis.gray('(1.23 s)')} + await expect( + new Logger().group('Running plugin "ESLint"', async () => ({ + message: 'Completed "ESLint" plugin execution', + result, + })), + ).resolves.toBe(result); -`); + expect(output).toContain('Completed "ESLint" plugin execution'); }); it('should use workflow commands to group logs in GitHub Actions environment', async () => { @@ -898,20 +895,6 @@ ${ansis.red.bold('Cancelled by SIGINT')} ); }); - it('should throw if nesting groups across logger instances', async () => { - await expect( - new Logger().group('Outer group', async () => { - await new Logger().group( - 'Inner group', - async () => 'Inner group complete', - ); - return 'Outer group complete'; - }), - ).rejects.toThrow( - 'Internal Logger error - nested groups are not supported', - ); - }); - it('should throw if creating group while spinner is running', async () => { const logger = new Logger(); diff --git a/packages/utils/src/lib/logger.ts b/packages/utils/src/lib/logger.ts index c8ba41033..6e6bfe38d 100644 --- a/packages/utils/src/lib/logger.ts +++ b/packages/utils/src/lib/logger.ts @@ -11,8 +11,6 @@ import { settlePromise } from './promises.js'; type GroupColor = Extract; type CiPlatform = 'GitHub Actions' | 'GitLab CI/CD'; -const GROUP_COLOR_ENV_VAR_NAME = 'CP_LOGGER_GROUP_COLOR'; - /** * Rich logging implementation for Code PushUp CLI, plugins, etc. * @@ -26,11 +24,7 @@ export class Logger { : isEnvVarEnabled('GITLAB_CI') ? 'GitLab CI/CD' : undefined; - #groupColor: GroupColor | undefined = - process.env[GROUP_COLOR_ENV_VAR_NAME] === 'cyan' || - process.env[GROUP_COLOR_ENV_VAR_NAME] === 'magenta' - ? process.env[GROUP_COLOR_ENV_VAR_NAME] - : undefined; + #groupColor: GroupColor | undefined; #groupsCount = 0; #activeSpinner: Ora | undefined; @@ -51,7 +45,7 @@ export class Logger { text, symbol: this.#colorize(this.#groupSymbols.end, this.#groupColor), }); - this.#setGroupColor(undefined); + this.#groupColor = undefined; } else { this.#activeSpinner.fail(text); } @@ -237,19 +231,25 @@ export class Logger { * Nested groups are not supported. * * @example - * await logger.group('Running plugin "ESLint"', async () => { + * const eslintResult = await logger.group('Running plugin "ESLint"', async () => { * logger.debug('ESLint version is 9.16.0'); - * await logger.command('npx eslint . --format=json', () => { + * const result = await logger.command('npx eslint . --format=json', () => { * // ... * }) * logger.info('Found 42 lint errors.'); - * return 'Completed "ESLint" plugin execution'; + * return { + * message: 'Completed "ESLint" plugin execution', + * result, + * }; * }); * * @param title Display title for the group. * @param worker Asynchronous implementation. Returned promise determines group status and ending message. Inner logs are attached to the group. */ - async group(title: string, worker: () => Promise): Promise { + async group( + title: string, + worker: () => Promise, + ): Promise { if (this.#groupColor) { throw new Error( 'Internal Logger error - nested groups are not supported', @@ -265,7 +265,7 @@ export class Logger { this.newline(); } - this.#setGroupColor(this.#groupsCount % 2 === 0 ? 'cyan' : 'magenta'); + this.#groupColor = this.#groupsCount % 2 === 0 ? 'cyan' : 'magenta'; this.#groupsCount++; const groupMarkers = this.#createGroupMarkers(); @@ -277,10 +277,12 @@ export class Logger { const end = performance.now(); if (result.status === 'fulfilled') { + const message = + typeof result.value === 'string' ? result.value : result.value.message; console.log( [ this.#colorize(this.#groupSymbols.end, this.#groupColor), - this.#colorize(result.value, 'green'), + this.#colorize(message, 'green'), this.#formatDurationSuffix({ start, end }), ].join(' '), ); @@ -300,12 +302,17 @@ export class Logger { if (endMarker) { console.log(endMarker); } - this.#setGroupColor(undefined); + this.#groupColor = undefined; this.newline(); if (result.status === 'rejected') { throw result.reason; } + + if (typeof result.value === 'object') { + return result.value.result; + } + return undefined as T; } #createGroupMarkers(): { @@ -353,15 +360,6 @@ export class Logger { return ansis.bold(this.#colorize(text, this.#groupColor)); } - #setGroupColor(groupColor: GroupColor | undefined) { - this.#groupColor = groupColor; - if (groupColor) { - process.env[GROUP_COLOR_ENV_VAR_NAME] = groupColor; - } else { - delete process.env[GROUP_COLOR_ENV_VAR_NAME]; - } - } - async #spinner( worker: () => Promise, messages: { diff --git a/packages/utils/src/lib/progress.int.test.ts b/packages/utils/src/lib/progress.int.test.ts deleted file mode 100644 index a9aaff054..000000000 --- a/packages/utils/src/lib/progress.int.test.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { describe, expect, it } from 'vitest'; -import { - barStyles, - getProgressBar, - getSingletonProgressBars, -} from './progress.js'; - -/** - * ANSI escape codes in terminal stdout: - * - `\u001b[30m` black - * - `\u001b[90m` gray - * - `\u001b[32m` green - * - `\u001b[39m` reset or default color - */ - -describe('getSingletonMultiProgressBars', () => { - it('should be singleton', async () => { - const a = getSingletonProgressBars(); - const b = getSingletonProgressBars(); - expect(a).toBe(b); - a.close(); - await a.promise; // check if all tasks are done - }); - - // @TODO 'should end all tasks on close' -}); - -const taskAName = 'a'; -const bars = getSingletonProgressBars({ progressWidth: 1 }); -const tasks = bars['tasks']; -const progressBuffer: string[] = bars['logger'].progressBuffer; - -describe('getProgressBar', () => { - it('should init task', () => { - expect(bars.getIndex(taskAName)).toBeUndefined(); - getProgressBar(taskAName); - expect(bars.getIndex(taskAName)).toBe(0); - expect(progressBuffer[0]!.trim()).toBe( - `${taskAName}: ${barStyles.idle(' ')} 0% |`, - ); - - // safety checks int the first test only - bars.removeTask(taskAName); - expect(bars.getIndex(taskAName)).toBeUndefined(); - }); - - it('should update task message', () => { - const taskA = getProgressBar(taskAName); - expect(tasks[taskAName].message).toBe(''); - - taskA.updateTitle('0'); - expect(tasks[taskAName].message).toBe('0'); - expect(progressBuffer[0]!.trim()).toBe( - `${taskAName}: ${barStyles.active(' ')} 0% | 0`, - ); - taskA.updateTitle('1'); - expect(tasks[taskAName].message).toBe('1'); - expect(progressBuffer[0]!.trim()).toBe( - `${taskAName}: ${barStyles.active(' ')} 0% | 1`, - ); - - bars.removeTask(taskAName); - }); - - it('should update task progress', () => { - const taskA = getProgressBar(taskAName); - taskA.incrementInSteps(2); - expect(tasks[taskAName].message).toBe(''); - expect(progressBuffer[0]!.trim()).toBe( - `${taskAName}: ${barStyles.active('▌')} 50% |`, - ); - taskA.incrementInSteps(2); - expect(tasks[taskAName].message).toBe(''); - expect(progressBuffer[0]!.trim()).toBe( - `${taskAName}: ${barStyles.active('█')} 100% |`, - ); - bars.removeTask(taskAName); - }); - - it('should end task when endProgress is called', () => { - const taskA = getProgressBar(taskAName); - expect(bars.isDone(taskAName)).toBe(false); - taskA.endProgress(); - expect(bars.isDone(taskAName)).toBe(true); - expect(progressBuffer[0]!.trim()).toBe( - `${taskAName}: ${barStyles.done('█')} 100% |`, - ); - }); -}); diff --git a/packages/utils/src/lib/progress.ts b/packages/utils/src/lib/progress.ts deleted file mode 100644 index fa642151c..000000000 --- a/packages/utils/src/lib/progress.ts +++ /dev/null @@ -1,74 +0,0 @@ -import ansis from 'ansis'; -import { type CtorOptions, MultiProgressBars } from 'multi-progress-bars'; -import { TERMINAL_WIDTH } from './text-formats/constants.js'; - -type BarStyles = 'active' | 'done' | 'idle'; -type StatusStyles = Record string>; -export const barStyles: StatusStyles = { - active: (s: string) => ansis.green(s), - done: (s: string) => ansis.gray(s), - idle: (s: string) => ansis.gray(s), -}; - -export const messageStyles: StatusStyles = { - active: (s: string) => ansis.black(s), - done: (s: string) => ansis.bold.green(s), - idle: (s: string) => ansis.gray(s), -}; - -export type ProgressBar = { - // @TODO find better naming - incrementInSteps: (numSteps: number) => void; - updateTitle: (title: string) => void; - endProgress: (message?: string) => void; -}; - -// eslint-disable-next-line functional/no-let -let mpb: MultiProgressBars; - -export function getSingletonProgressBars( - options?: Partial, -): MultiProgressBars { - if (!mpb) { - mpb = new MultiProgressBars({ - progressWidth: TERMINAL_WIDTH, - initMessage: '', - border: true, - ...options, - }); - } - return mpb; -} - -export function getProgressBar(taskName: string): ProgressBar { - const tasks = getSingletonProgressBars(); - - // Initialize progress bar if not set - tasks.addTask(taskName, { - type: 'percentage', - percentage: 0, - message: '', - barTransformFn: barStyles.idle, - }); - - return { - incrementInSteps: (numPlugins: number) => { - tasks.incrementTask(taskName, { - percentage: 1 / numPlugins, - barTransformFn: barStyles.active, - }); - }, - updateTitle: (title: string) => { - tasks.updateTask(taskName, { - message: title, - barTransformFn: barStyles.active, - }); - }, - endProgress: (message = '') => { - tasks.done(taskName, { - message: messageStyles.done(message), - barTransformFn: barStyles.done, - }); - }, - }; -} diff --git a/packages/utils/src/lib/promises.ts b/packages/utils/src/lib/promises.ts index 9e554a302..b5b92316b 100644 --- a/packages/utils/src/lib/promises.ts +++ b/packages/utils/src/lib/promises.ts @@ -16,13 +16,13 @@ export function groupByStatus(results: PromiseSettledResult[]): { export async function asyncSequential( items: TInput[], - work: (item: TInput) => Promise, + work: (item: TInput, index: number) => Promise, ): Promise { // for-loop used instead of reduce for performance const results: TOutput[] = []; // eslint-disable-next-line functional/no-loop-statements - for (const item of items) { - const result = await work(item); + for (const [index, item] of items.entries()) { + const result = await work(item, index); // eslint-disable-next-line functional/immutable-data results.push(result); } diff --git a/packages/utils/src/lib/promises.unit.test.ts b/packages/utils/src/lib/promises.unit.test.ts index 9139ba43c..540f87eef 100644 --- a/packages/utils/src/lib/promises.unit.test.ts +++ b/packages/utils/src/lib/promises.unit.test.ts @@ -49,6 +49,17 @@ describe('asyncSequential', () => { expect(sequentialResult).not.toEqual(parallelResult); }); + + it('should provide array item and index to callback', async () => { + const callback = vi.fn(); + await expect( + asyncSequential(['a', 'b', 'c'], callback), + ).resolves.toBeArrayOfSize(3); + expect(callback).toHaveBeenCalledTimes(3); + expect(callback).toHaveBeenNthCalledWith(1, 'a', 0); + expect(callback).toHaveBeenNthCalledWith(2, 'b', 1); + expect(callback).toHaveBeenNthCalledWith(3, 'c', 2); + }); }); describe('settlePromise', () => { diff --git a/packages/utils/src/lib/transform.unit.test.ts b/packages/utils/src/lib/transform.unit.test.ts index b72982e3d..e15e93224 100644 --- a/packages/utils/src/lib/transform.unit.test.ts +++ b/packages/utils/src/lib/transform.unit.test.ts @@ -199,15 +199,15 @@ describe('objectToCliArgs', () => { }); it('should handle boolean arguments', () => { - const params = { progress: true }; + const params = { verbose: true }; const result = objectToCliArgs(params); - expect(result).toEqual(['--progress']); + expect(result).toEqual(['--verbose']); }); it('should handle negated boolean arguments', () => { - const params = { progress: false }; + const params = { verbose: false }; const result = objectToCliArgs(params); - expect(result).toEqual(['--no-progress']); + expect(result).toEqual(['--no-verbose']); }); it('should handle array of string arguments', () => { diff --git a/project.json b/project.json index 45a488e43..2b378ab31 100644 --- a/project.json +++ b/project.json @@ -32,7 +32,6 @@ "executor": "nx:run-commands", "options": { "args": [ - "--no-progress", "--verbose", "--cache.read", "--persist.outputDir={projectRoot}/.code-pushup", diff --git a/testing/test-setup-config/src/lib/vitest-config-factory.unit.test.ts b/testing/test-setup-config/src/lib/vitest-config-factory.unit.test.ts index 59f980078..8891d8e04 100644 --- a/testing/test-setup-config/src/lib/vitest-config-factory.unit.test.ts +++ b/testing/test-setup-config/src/lib/vitest-config-factory.unit.test.ts @@ -29,7 +29,6 @@ describe('createVitestConfig', () => { ], globalSetup: ['../../global-setup.ts'], setupFiles: expect.arrayContaining([ - '../../testing/test-setup/src/lib/console.mock.ts', '../../testing/test-setup/src/lib/reset.mocks.ts', '../../testing/test-setup/src/lib/fs.mock.ts', ]), @@ -47,9 +46,6 @@ describe('createVitestConfig', () => { const config = createVitestConfig('test-package', 'unit'); const setupFiles = config.test!.setupFiles; - expect(setupFiles).toContain( - '../../testing/test-setup/src/lib/console.mock.ts', - ); expect(setupFiles).toContain( '../../testing/test-setup/src/lib/reset.mocks.ts', ); @@ -121,9 +117,6 @@ describe('createVitestConfig', () => { const config = createVitestConfig('test-package', 'int'); const setupFiles = config.test!.setupFiles; - expect(setupFiles).toContain( - '../../testing/test-setup/src/lib/console.mock.ts', - ); expect(setupFiles).toContain( '../../testing/test-setup/src/lib/logger.mock.ts', ); @@ -172,9 +165,9 @@ describe('createVitestConfig', () => { expect(setupFiles).toContain( '../../testing/test-setup/src/lib/reset.mocks.ts', ); - // Should NOT include console, fs, git, etc. + // Should NOT include fs, git, etc. expect(setupFiles).not.toContain( - '../../testing/test-setup/src/lib/console.mock.ts', + '../../testing/test-setup/src/lib/git.mock.ts', ); expect(setupFiles).not.toContain( '../../testing/test-setup/src/lib/fs.mock.ts', diff --git a/testing/test-setup-config/src/lib/vitest-setup-files.ts b/testing/test-setup-config/src/lib/vitest-setup-files.ts index b08388b78..4e286d1df 100644 --- a/testing/test-setup-config/src/lib/vitest-setup-files.ts +++ b/testing/test-setup-config/src/lib/vitest-setup-files.ts @@ -7,9 +7,9 @@ import type { TestKind } from './vitest-config-factory.js'; * which is why they use `../../` to navigate to the workspace root first. */ const CUSTOM_MATCHERS = [ - '../../testing/test-setup/src/lib/extend/markdown-table.matcher.ts', '../../testing/test-setup/src/lib/extend/jest-extended.matcher.ts', '../../testing/test-setup/src/lib/extend/path.matcher.ts', + '../../testing/test-setup/src/lib/extend/markdown-table.matcher.ts', ] as const; /** @@ -19,12 +19,11 @@ const CUSTOM_MATCHERS = [ * which is why they use `../../` to navigate to the workspace root first. */ const UNIT_TEST_SETUP_FILES = [ - '../../testing/test-setup/src/lib/fs.mock.ts', - '../../testing/test-setup/src/lib/console.mock.ts', '../../testing/test-setup/src/lib/reset.mocks.ts', + '../../testing/test-setup/src/lib/fs.mock.ts', + '../../testing/test-setup/src/lib/logger.mock.ts', '../../testing/test-setup/src/lib/git.mock.ts', '../../testing/test-setup/src/lib/portal-client.mock.ts', - '../../testing/test-setup/src/lib/logger.mock.ts', ...CUSTOM_MATCHERS, ] as const; @@ -36,10 +35,9 @@ const UNIT_TEST_SETUP_FILES = [ */ const INT_TEST_SETUP_FILES = [ - '../../testing/test-setup/src/lib/console.mock.ts', '../../testing/test-setup/src/lib/reset.mocks.ts', - '../../testing/test-setup/src/lib/chrome-path.mock.ts', '../../testing/test-setup/src/lib/logger.mock.ts', + '../../testing/test-setup/src/lib/chrome-path.mock.ts', ...CUSTOM_MATCHERS, ] as const; diff --git a/testing/test-setup/src/lib/chrome-path.mock.ts b/testing/test-setup/src/lib/chrome-path.mock.ts index c31788adf..dbe1542af 100644 --- a/testing/test-setup/src/lib/chrome-path.mock.ts +++ b/testing/test-setup/src/lib/chrome-path.mock.ts @@ -15,12 +15,9 @@ beforeEach(async () => { error.message.includes('No Chrome installations found.') ) { const chromium = await import('chromium'); - // console.info may be overridden by multi-progress-bars or other libraries - if (typeof console.info === 'function') { - console.info( - `${error.message} Using chromium from node_modules instead: ${chromium.path}`, - ); - } + console.info( + `${error.message} Using chromium from node_modules instead: ${chromium.path}`, + ); vi.stubEnv('CHROME_PATH', chromium.path); } else { throw error; diff --git a/testing/test-setup/src/lib/console.mock.ts b/testing/test-setup/src/lib/console.mock.ts deleted file mode 100644 index 9d8cbfbcd..000000000 --- a/testing/test-setup/src/lib/console.mock.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { type MockInstance, afterEach, beforeEach, vi } from 'vitest'; - -// TODO: remove once logger is used everywhere - -let consoleInfoSpy: MockInstance | undefined; -let consoleWarnSpy: MockInstance | undefined; -let consoleErrorSpy: MockInstance | undefined; - -beforeEach(() => { - // In multi-progress-bars, console methods are overriden - if (console.info != null) { - consoleInfoSpy = vi.spyOn(console, 'info').mockImplementation(() => {}); - } - - if (console.warn != null) { - consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}); - } - - if (console.error != null) { - consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); - } -}); - -afterEach(() => { - consoleInfoSpy?.mockRestore(); - consoleWarnSpy?.mockRestore(); - consoleErrorSpy?.mockRestore(); -}); diff --git a/testing/test-setup/src/lib/logger.mock.ts b/testing/test-setup/src/lib/logger.mock.ts index c0c6cdb92..54c21184e 100644 --- a/testing/test-setup/src/lib/logger.mock.ts +++ b/testing/test-setup/src/lib/logger.mock.ts @@ -29,7 +29,8 @@ beforeAll(async () => { vi.spyOn(logger, 'newline').mockImplementation(() => {}), // make sure worker still gets executed vi.spyOn(logger, 'group').mockImplementation(async (_, worker) => { - await worker(); + const value = await worker(); + return typeof value === 'object' ? value.result : undefined; }), vi.spyOn(logger, 'task').mockImplementation(async (_, worker) => { await worker(); diff --git a/testing/test-utils/src/lib/fixtures/configs/progress-bar.config.mock.ts b/testing/test-utils/src/lib/fixtures/configs/progress-bar.config.mock.ts deleted file mode 100644 index ee22a3d7d..000000000 --- a/testing/test-utils/src/lib/fixtures/configs/progress-bar.config.mock.ts +++ /dev/null @@ -1,79 +0,0 @@ -/** - * This config file is here to demonstrate the progress bar for plugins - * - * Usage: - * npx ./dist/packages/cli collect --config=./testing/test-utils/src/lib/fixtures/configs/progress-bar.config.mock.ts - */ -import path from 'node:path'; -import { fileURLToPath } from 'url'; - -// Small hack to control the number of plugins while debugging -const numPlugins = parseInt( - process.argv - .find(arg => arg.includes('numPlugins=')) - ?.split('=') - .pop() || '6', -); - -const outputDir = './tmp'; -const pluginProcess = path.join( - fileURLToPath(path.dirname(import.meta.url)), - '..', - '..', - 'utils', - 'progress-bar-process.mock.mjs', -); -const pluginSlug = (id: string): string => 'progress-mock-plugin-' + id; -const auditSlug = (pId: string, aId: string): string => - pluginSlug(pId) + '-a' + aId; -const pluginTitle = (end: string): string => 'Async Plugin ' + end; -const auditTitle = (end: string): string => 'Async Audit ' + end; -const asyncPlugin = (pId: string, duration = 1000) => { - const aId = '0'; - const outputFile = path.join(outputDir, `${pluginSlug(pId)}-output.json`); - return { - slug: pluginSlug(pId), - title: pluginTitle(pId), - icon: 'javascript', - audits: [{ slug: auditSlug(pId, aId), title: auditTitle(aId) }], - runner: { - command: 'node', - args: [ - pluginProcess, - `--verbose`, - `--duration=${duration}`, - `--steps=${1}`, - `--throwError=${0}`, - `--outputDir=${outputDir}`, - `--pluginPostfix=${pId}`, - `--auditPostfix=${aId}`, - ], - outputFile, - }, - }; -}; - -export default { - upload: { - organization: 'code-pushup', - project: 'cli', - apiKey: 'dummy-api-key', - server: 'https://example.com/api', - }, - persist: { outputDir }, - plugins: new Array(numPlugins) - .fill(0) - .map((_, idx) => asyncPlugin(idx + '', 300)), - categories: new Array(numPlugins).fill(0).map((_, idx) => ({ - slug: 'category-' + idx, - title: 'Category ' + idx, - refs: [ - { - type: 'audit', - slug: auditSlug(idx.toString(), '0'), - plugin: pluginSlug(idx.toString()), - weight: 1, - }, - ], - })), -}; diff --git a/testing/test-utils/src/lib/utils/progress-bar-process.mock.mjs b/testing/test-utils/src/lib/utils/progress-bar-process.mock.mjs deleted file mode 100644 index 37894cfb8..000000000 --- a/testing/test-utils/src/lib/utils/progress-bar-process.mock.mjs +++ /dev/null @@ -1,108 +0,0 @@ -import { existsSync, mkdirSync, writeFileSync } from 'fs'; -import path from 'node:path'; - -/** - * Custom runner implementation that simulates asynchronous situations. - * It logs progress to the console with a configurable interval and defaults to 100ms. - * The number of runs is also configurable and defaults to 4. - * We can decide if the process should error or complete. By default, it completes. - * - * @arg interval: number - interval of updates in ms; defaults to 100 - * @arg runs: number - number of updates; defaults to 4 - * @arg throwError: '1' | '0' - if the process completes or throws; defaults to '0' - **/ -let verbose = process.argv.find(arg => arg.includes('verbose')) ? true : false; -verbose = process.argv.find(arg => arg.includes('no-verbose=')) - ? false - : verbose; -const duration = parseInt( - process.argv - .find(arg => arg.includes('duration=')) - ?.split('=') - .pop() || '100', -); -let steps = parseInt( - process.argv - .find(arg => arg.includes('steps=')) - ?.split('=') - .pop() || '4', -); -let throwError = parseInt( - process.argv - .find(arg => arg.includes('throwError=')) - ?.split('=') - .pop() || '0', -); -let outputDir = - process.argv - .find(arg => arg.includes('outputDir=')) - ?.split('=') - .pop() || './tmp'; -let pluginPostfix = - process.argv - .find(arg => arg.includes('pluginPostfix=')) - ?.split('=') - .pop() || '0'; -let auditPostfix = - process.argv - .find(arg => arg.includes('auditPostfix=')) - ?.split('=') - .pop() || '0'; - -const pluginSlug = 'progress-mock-plugin-' + pluginPostfix; -const auditSlug = pluginSlug + '-a' + auditPostfix; -const auditTitle = 'Async Audit ' + auditPostfix; -const outputFile = './' + path.join(outputDir, `${pluginSlug}-output.json`); - -(async () => { - if (verbose) { - console.info('Plugin Progress Bar Mock - Async Plugin Process'); - console.info(`Duration: ${duration}`); - console.info(`Steps: ${steps}`); - console.error(`Throw Error: ${throwError}`); - console.info(`Plugin Postfix: ${pluginPostfix} - Slug: ${pluginSlug}`); - console.info( - `Audit Postfix: ${auditPostfix} - Slug: ${auditSlug}; Title: ${auditTitle}`, - ); - console.info(`Output Dir: ${outputDir} - Output File: ${outputFile}`); - console.info(''); - } - - await new Promise(resolve => { - verbose && console.info('--- plugin-process:start ---'); - const id = setInterval(() => { - if (steps === 0) { - clearInterval(id); - if (throwError) { - throw new Error('dummy-error'); - } else { - resolve('result'); - } - } else { - steps--; - verbose && console.info(`--- plugin-process:update ${steps} ---`); - } - }, duration); - }); - - verbose && console.info('--- plugin-process:complete ---'); - if (!existsSync(outputDir)) { - try { - mkdirSync(outputDir, { recursive: true }); - } catch (e) { - console.warn(e); - throw e; - } - } - writeFileSync( - outputFile, - JSON.stringify([ - { - slug: auditSlug, - title: auditTitle, - value: Math.floor(Math.random() * 100, 0), - score: Math.floor(Math.random(), 2), - }, - ]), - ); -})();