Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion e2e/cli-e2e/tests/__snapshots__/help.e2e.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Commands:

Global Options:
--progress Show progress bar in stdout.
[boolean] [default: true]
[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]
Expand Down
1 change: 0 additions & 1 deletion packages/ci/src/lib/cli/commands/collect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ export async function runCollect({
command: bin,
args: [
...(isVerbose() ? ['--verbose'] : []),
'--no-progress',
...(config ? [`--config=${config}`] : []),
...DEFAULT_PERSIST_FORMAT.map(format => `--persist.format=${format}`),
],
Expand Down
56 changes: 8 additions & 48 deletions packages/ci/src/lib/run.int.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,12 +260,7 @@ describe('runInCI', () => {
} satisfies utils.ProcessConfig);
expect(utils.executeProcess).toHaveBeenNthCalledWith(2, {
command: options.bin,
args: [
'--verbose',
'--no-progress',
'--persist.format=json',
'--persist.format=md',
],
args: ['--verbose', '--persist.format=json', '--persist.format=md'],
cwd: workDir,
observer: expectedObserver,
} satisfies utils.ProcessConfig);
Expand Down Expand Up @@ -347,12 +342,7 @@ describe('runInCI', () => {
} satisfies utils.ProcessConfig);
expect(utils.executeProcess).toHaveBeenNthCalledWith(2, {
command: options.bin,
args: [
'--verbose',
'--no-progress',
'--persist.format=json',
'--persist.format=md',
],
args: ['--verbose', '--persist.format=json', '--persist.format=md'],
cwd: workDir,
observer: expectedObserver,
} satisfies utils.ProcessConfig);
Expand All @@ -368,12 +358,7 @@ describe('runInCI', () => {
} satisfies utils.ProcessConfig);
expect(utils.executeProcess).toHaveBeenNthCalledWith(4, {
command: options.bin,
args: [
'--verbose',
'--no-progress',
'--persist.format=json',
'--persist.format=md',
],
args: ['--verbose', '--persist.format=json', '--persist.format=md'],
cwd: workDir,
observer: expectedObserver,
} satisfies utils.ProcessConfig);
Expand Down Expand Up @@ -450,12 +435,7 @@ describe('runInCI', () => {
} satisfies utils.ProcessConfig);
expect(utils.executeProcess).toHaveBeenNthCalledWith(2, {
command: options.bin,
args: [
'--verbose',
'--no-progress',
'--persist.format=json',
'--persist.format=md',
],
args: ['--verbose', '--persist.format=json', '--persist.format=md'],
cwd: workDir,
observer: expectedObserver,
} satisfies utils.ProcessConfig);
Expand Down Expand Up @@ -647,12 +627,7 @@ describe('runInCI', () => {
} satisfies utils.ProcessConfig);
expect(utils.executeProcess).toHaveBeenCalledWith({
command: runMany,
args: [
'--verbose',
'--no-progress',
'--persist.format=json',
'--persist.format=md',
],
args: ['--verbose', '--persist.format=json', '--persist.format=md'],
cwd: expect.stringContaining(workDir),
observer: expectedObserver,
} satisfies utils.ProcessConfig);
Expand Down Expand Up @@ -814,12 +789,7 @@ describe('runInCI', () => {
} satisfies utils.ProcessConfig);
expect(utils.executeProcess).toHaveBeenCalledWith({
command: runMany,
args: [
'--verbose',
'--no-progress',
'--persist.format=json',
'--persist.format=md',
],
args: ['--verbose', '--persist.format=json', '--persist.format=md'],
cwd: expect.stringContaining(workDir),
observer: expectedObserver,
} satisfies utils.ProcessConfig);
Expand Down Expand Up @@ -1013,12 +983,7 @@ describe('runInCI', () => {
} satisfies utils.ProcessConfig);
expect(utils.executeProcess).toHaveBeenCalledWith({
command: options.bin,
args: [
'--verbose',
'--no-progress',
'--persist.format=json',
'--persist.format=md',
],
args: ['--verbose', '--persist.format=json', '--persist.format=md'],
cwd: expect.stringContaining(workDir),
observer: expectedObserver,
} satisfies utils.ProcessConfig);
Expand Down Expand Up @@ -1191,12 +1156,7 @@ describe('runInCI', () => {
} satisfies utils.ProcessConfig);
expect(utils.executeProcess).toHaveBeenCalledWith({
command: options.bin,
args: [
'--verbose',
'--no-progress',
'--persist.format=json',
'--persist.format=md',
],
args: ['--verbose', '--persist.format=json', '--persist.format=md'],
cwd: expect.stringContaining(workDir),
observer: expectedObserver,
} satisfies utils.ProcessConfig);
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ Each example is fully tested to demonstrate best practices for plugin testing as

| Option | Type | Default | Description |
| ---------------- | --------- | -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| **`--progress`** | `boolean` | `true` | Show progress bar in stdout. |
| **`--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. |
Expand Down
4 changes: 3 additions & 1 deletion packages/cli/src/lib/implementation/global.options.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Options } from 'yargs';
import { isCI } from '@code-pushup/utils';
import type { GeneralCliOptions } from './global.model.js';

export function yargsGlobalOptionsDefinition(): Record<
Expand All @@ -9,7 +10,8 @@ export function yargsGlobalOptionsDefinition(): Record<
progress: {
describe: 'Show progress bar in stdout.',
type: 'boolean',
default: true,
default: !isCI(),
defaultDescription: 'false in CI environment, otherwise true',
},
verbose: {
describe:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ describe('setVerboseMiddleware', () => {
[false, false, false],
['True', undefined, true],
['TRUE', undefined, true],
[42, undefined, false],
[0, undefined, false],
[undefined, 'true', true],
[true, 'False', false],
])(
Expand Down
22 changes: 3 additions & 19 deletions packages/cli/src/lib/implementation/set-verbose.middleware.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { GlobalOptions } from '@code-pushup/core';
import type { CoreConfig } from '@code-pushup/models';
import { coerceBooleanValue } from '@code-pushup/utils';
import type { FilterOptions } from './filter.model.js';
import type { GeneralCliOptions } from './global.model';

Expand All @@ -21,8 +22,8 @@ import type { GeneralCliOptions } from './global.model';
export function setVerboseMiddleware<
T extends GeneralCliOptions & CoreConfig & FilterOptions & GlobalOptions,
>(originalProcessArgs: T): T {
const envVerbose = getNormalizedOptionValue(process.env['CP_VERBOSE']);
const cliVerbose = getNormalizedOptionValue(originalProcessArgs.verbose);
const envVerbose = coerceBooleanValue(process.env['CP_VERBOSE']);
const cliVerbose = coerceBooleanValue(originalProcessArgs.verbose);
const verboseEffect = cliVerbose ?? envVerbose ?? false;

// eslint-disable-next-line functional/immutable-data
Expand All @@ -33,20 +34,3 @@ export function setVerboseMiddleware<
verbose: verboseEffect,
};
}

export function getNormalizedOptionValue(value: unknown): boolean | undefined {
if (typeof value === 'boolean') {
return value;
}
if (typeof value === 'string') {
const lowerCaseValue = value.toLowerCase();
if (lowerCaseValue === 'true') {
return true;
}
if (lowerCaseValue === 'false') {
return false;
}
}

return undefined;
}
Original file line number Diff line number Diff line change
@@ -1,32 +1,7 @@
import { describe, expect, it, vi } from 'vitest';
import {
getNormalizedOptionValue,
setVerboseMiddleware,
} from './set-verbose.middleware.js';
import { setVerboseMiddleware } from './set-verbose.middleware.js';

describe('setVerboseMiddleware', () => {
it.each([
[true, true],
['true', true],
['True', true],
['TRUE', true],
[false, false],
['false', false],
['False', false],
['FALSE', false],
[undefined, undefined],
['undefined', undefined],
['Whatever else', undefined],
[0, undefined],
[1, undefined],
[null, undefined],
])(
'should return normalize value of `%j` option set as `%j`',
(value, expected) => {
expect(getNormalizedOptionValue(value)).toBe(expected);
},
);

it.each([
[true, undefined, true],
[false, undefined, false],
Expand Down
7 changes: 3 additions & 4 deletions packages/cli/src/lib/yargs-cli.int.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { describe, expect, it } from 'vitest';
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';
Expand All @@ -21,7 +22,7 @@ describe('yargsCli', () => {
options,
}).parseAsync();
expect(parsedArgv.verbose).toBe(false);
expect(parsedArgv.progress).toBe(true);
expect(parsedArgv.progress).toBe(!isCI());
});

it('should parse an empty array as a default onlyPlugins option', async () => {
Expand Down Expand Up @@ -112,7 +113,6 @@ describe('yargsCli', () => {
FilterOptions
>(
[
'--verbose',
'--persist.format=md',
'--persist.outputDir=code-pushdown/output/dir',
'--persist.filename=code-pushdown-report',
Expand All @@ -130,9 +130,8 @@ describe('yargsCli', () => {
expect(parsedArgv).toEqual(
expect.objectContaining({
// default values
progress: true,
verbose: false,
// overridden arguments
verbose: true,
persist: expect.objectContaining({
outputDir: 'code-pushdown/output/dir',
filename: 'code-pushdown-report',
Expand Down
8 changes: 7 additions & 1 deletion packages/utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ export {
export { filesCoverageToTree, type FileCoverage } from './lib/coverage-tree.js';
export { createRunnerFiles } from './lib/create-runner-files.js';
export { comparePairs, matchArrayItemsByKey, type Diff } from './lib/diff.js';
export {
coerceBooleanValue,
isCI,
isEnvVarEnabled,
isVerbose,
} from './lib/env.js';
export { stringifyError } from './lib/errors.js';
export {
executeProcess,
Expand Down Expand Up @@ -69,7 +75,7 @@ export {
isPromiseRejectedResult,
} from './lib/guards.js';
export { logMultipleResults } from './lib/log-results.js';
export { isVerbose, link, ui, type CliUi, type Column } from './lib/logging.js';
export { link, ui, type CliUi, type Column } from './lib/logging.js';
export { mergeConfigs } from './lib/merge-configs.js';
export { getProgressBar, type ProgressBar } from './lib/progress.js';
export { asyncSequential, groupByStatus } from './lib/promises.js';
Expand Down
53 changes: 53 additions & 0 deletions packages/utils/src/lib/env.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { ui } from './logging.js';

export function isCI() {
return isEnvVarEnabled('CI');
}

export function isVerbose() {
return isEnvVarEnabled('CP_VERBOSE');
}

export function isEnvVarEnabled(name: string): boolean {
const value = coerceBooleanValue(process.env[name]);

if (typeof value === 'boolean') {
return value;
}

if (process.env[name]) {
ui().logger.warning(
`Environment variable ${name} expected to be a boolean (true/false/1/0), but received value ${process.env[name]}. Treating it as disabled.`,
);
}

return false;
}

export function coerceBooleanValue(value: unknown): boolean | undefined {
if (typeof value === 'boolean') {
return value;
}

if (typeof value === 'string') {
const booleanValuePairs = [
['true', 'false'],
['on', 'off'],
['yes', 'no'],
];
const lowerCaseValue = value.toLowerCase();
// eslint-disable-next-line functional/no-loop-statements
for (const [trueValue, falseValue] of booleanValuePairs) {
if (lowerCaseValue === trueValue || lowerCaseValue === falseValue) {
return lowerCaseValue === trueValue;
}
}

const intValue = Number.parseInt(value, 10);
if (!Number.isNaN(intValue)) {
return intValue !== 0;
}
}

return undefined;
}
Loading
Loading