@code-pushup/cli 0.46.0 → 0.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -198,9 +198,10 @@ Each example is fully tested to demonstrate best practices for plugin testing as
198
198
  | **`--upload.server`** | `string` | n/a | URL to your portal server. |
199
199
  | **`--upload.apiKey`** | `string` | n/a | API key for the portal server. |
200
200
  | **`--onlyPlugins`** | `string[]` | `[]` | Only run the specified plugins. Applicable to all commands except `upload`. |
201
+ | **`--skipPlugins`** | `string[]` | `[]` | Skip the specified plugins. Applicable to all commands except `upload`. |
201
202
 
202
203
  > [!NOTE]
203
- > All common options, except `--onlyPlugins`, can be specified in the configuration file as well.
204
+ > All common options, except `--onlyPlugins` and `--skipPlugins`, can be specified in the configuration file as well.
204
205
  > CLI arguments take precedence over configuration file options.
205
206
 
206
207
  > [!NOTE]
package/index.js CHANGED
@@ -71,7 +71,7 @@ function missingRefsForCategoriesErrorMsg(categories, plugins) {
71
71
  }
72
72
 
73
73
  // packages/models/src/lib/implementation/schemas.ts
74
- var primitiveValueSchema = z.union([z.string(), z.number()]);
74
+ var tableCellValueSchema = z.union([z.string(), z.number(), z.boolean(), z.null()]).default(null);
75
75
  function executionMetaSchema(options2 = {
76
76
  descriptionDate: "Execution start date and time",
77
77
  descriptionDuration: "Execution duration in ms"
@@ -235,10 +235,10 @@ var tableColumnObjectSchema = z4.object({
235
235
  label: z4.string().optional(),
236
236
  align: tableAlignmentSchema.optional()
237
237
  });
238
- var tableRowObjectSchema = z4.record(primitiveValueSchema, {
238
+ var tableRowObjectSchema = z4.record(tableCellValueSchema, {
239
239
  description: "Object row"
240
240
  });
241
- var tableRowPrimitiveSchema = z4.array(primitiveValueSchema, {
241
+ var tableRowPrimitiveSchema = z4.array(tableCellValueSchema, {
242
242
  description: "Primitive row"
243
243
  });
244
244
  var tableSharedSchema = z4.object({
@@ -793,9 +793,9 @@ function formatBytes(bytes, decimals = 2) {
793
793
  function pluralizeToken(token, times) {
794
794
  return `${times} ${Math.abs(times) === 1 ? token : pluralize(token)}`;
795
795
  }
796
- function formatDuration(duration) {
796
+ function formatDuration(duration, granularity = 0) {
797
797
  if (duration < 1e3) {
798
- return `${duration} ms`;
798
+ return `${granularity ? duration.toFixed(granularity) : duration} ms`;
799
799
  }
800
800
  return `${(duration / 1e3).toFixed(2)} s`;
801
801
  }
@@ -981,20 +981,12 @@ function logMultipleFileResults(fileResults, messagePrefix) {
981
981
  failedTransform
982
982
  );
983
983
  }
984
- var NoExportError = class extends Error {
985
- constructor(filepath) {
986
- super(`No default export found in ${filepath}`);
984
+ async function importModule(options2) {
985
+ const { mod } = await bundleRequire(options2);
986
+ if (typeof mod === "object" && "default" in mod) {
987
+ return mod.default;
987
988
  }
988
- };
989
- async function importEsmModule(options2) {
990
- const { mod } = await bundleRequire({
991
- format: "esm",
992
- ...options2
993
- });
994
- if (!("default" in mod)) {
995
- throw new NoExportError(options2.filepath);
996
- }
997
- return mod.default;
989
+ return mod;
998
990
  }
999
991
 
1000
992
  // packages/utils/src/lib/text-formats/constants.ts
@@ -1027,7 +1019,7 @@ function code(text) {
1027
1019
 
1028
1020
  // packages/utils/src/lib/text-formats/html/link.ts
1029
1021
  function link2(href, text) {
1030
- return `<a href="${href}">${text || href}"</a>`;
1022
+ return `<a href="${href}">${text || href}</a>`;
1031
1023
  }
1032
1024
 
1033
1025
  // packages/utils/src/lib/transform.ts
@@ -1049,7 +1041,7 @@ function capitalize(text) {
1049
1041
  )}`;
1050
1042
  }
1051
1043
 
1052
- // packages/utils/src/lib/table.ts
1044
+ // packages/utils/src/lib/text-formats/table.ts
1053
1045
  function rowToStringArray({ rows, columns = [] }) {
1054
1046
  if (Array.isArray(rows.at(0)) && typeof columns.at(0) === "object") {
1055
1047
  throw new TypeError(
@@ -1062,14 +1054,19 @@ function rowToStringArray({ rows, columns = [] }) {
1062
1054
  }
1063
1055
  const objectRow = row;
1064
1056
  if (columns.length === 0 || typeof columns.at(0) === "string") {
1065
- return Object.values(objectRow).map(String);
1057
+ return Object.values(objectRow).map(
1058
+ (value) => value == null ? "" : String(value)
1059
+ );
1066
1060
  }
1067
1061
  return columns.map(
1068
- ({ key }) => String(objectRow[key])
1062
+ ({ key }) => objectRow[key] == null ? "" : String(objectRow[key])
1069
1063
  );
1070
1064
  });
1071
1065
  }
1072
- function columnsToStringArray({ rows, columns = [] }) {
1066
+ function columnsToStringArray({
1067
+ rows,
1068
+ columns = []
1069
+ }) {
1073
1070
  const firstRow = rows.at(0);
1074
1071
  const primitiveRows = Array.isArray(firstRow);
1075
1072
  if (typeof columns.at(0) === "string" && !primitiveRows) {
@@ -1109,10 +1106,8 @@ function getColumnAlignmentForIndex(targetIdx, columns = []) {
1109
1106
  return "center";
1110
1107
  }
1111
1108
  }
1112
- function getColumnAlignments({
1113
- rows,
1114
- columns = []
1115
- }) {
1109
+ function getColumnAlignments(tableData) {
1110
+ const { rows, columns = [] } = tableData;
1116
1111
  if (rows.at(0) == null) {
1117
1112
  throw new Error("first row can`t be undefined.");
1118
1113
  }
@@ -1122,10 +1117,17 @@ function getColumnAlignments({
1122
1117
  (_, idx) => getColumnAlignmentForIndex(idx, columns)
1123
1118
  );
1124
1119
  }
1125
- const firstObject = rows.at(0);
1126
- return Object.keys(firstObject).map(
1127
- (key, idx) => getColumnAlignmentForKeyAndIndex(key, idx, columns)
1128
- );
1120
+ const biggestRow = [...rows].sort((a, b) => Object.keys(a).length - Object.keys(b).length).at(-1);
1121
+ if (columns.length > 0) {
1122
+ return columns.map(
1123
+ (column, idx) => typeof column === "string" ? column : getColumnAlignmentForKeyAndIndex(
1124
+ column.key,
1125
+ idx,
1126
+ columns
1127
+ )
1128
+ );
1129
+ }
1130
+ return Object.keys(biggestRow ?? {}).map((_) => "center");
1129
1131
  }
1130
1132
 
1131
1133
  // packages/utils/src/lib/text-formats/html/table.ts
@@ -1222,7 +1224,10 @@ function section(...contents) {
1222
1224
  return `${lines(...contents)}${NEW_LINE}`;
1223
1225
  }
1224
1226
  function lines(...contents) {
1225
- return `${contents.filter(Boolean).join(NEW_LINE)}`;
1227
+ const filteredContent = contents.filter(
1228
+ (value) => value != null && value !== "" && value !== false
1229
+ );
1230
+ return `${filteredContent.join(NEW_LINE)}`;
1226
1231
  }
1227
1232
 
1228
1233
  // packages/utils/src/lib/text-formats/md/table.ts
@@ -2134,8 +2139,8 @@ function formatDiffCategoriesSection(diff) {
2134
2139
  }
2135
2140
  const columns = [
2136
2141
  { key: "category", label: "\u{1F3F7}\uFE0F Category", align: "left" },
2137
- { key: "after", label: hasChanges ? "\u2B50 Current score" : "\u2B50 Score" },
2138
- { key: "before", label: "\u2B50 Previous score" },
2142
+ { key: "before", label: hasChanges ? "\u2B50 Previous score" : "\u2B50 Score" },
2143
+ { key: "after", label: "\u2B50 Current score" },
2139
2144
  { key: "change", label: "\u{1F504} Score change" }
2140
2145
  ];
2141
2146
  return lines5(
@@ -2164,7 +2169,7 @@ function formatDiffCategoriesSection(diff) {
2164
2169
  change: "\u2013"
2165
2170
  }))
2166
2171
  ].map(
2167
- (row) => hasChanges ? row : { category: row.category, after: row.after }
2172
+ (row) => hasChanges ? row : { category: row.category, before: row.before }
2168
2173
  )
2169
2174
  }),
2170
2175
  added.length > 0 && section5(italicMd("(\\*) New category."))
@@ -2180,8 +2185,8 @@ function formatDiffGroupsSection(diff) {
2180
2185
  columns: [
2181
2186
  { key: "plugin", label: "\u{1F50C} Plugin", align: "left" },
2182
2187
  { key: "group", label: "\u{1F5C3}\uFE0F Group", align: "left" },
2183
- { key: "after", label: "\u2B50 Current score" },
2184
2188
  { key: "before", label: "\u2B50 Previous score" },
2189
+ { key: "after", label: "\u2B50 Current score" },
2185
2190
  { key: "change", label: "\u{1F504} Score change" }
2186
2191
  ],
2187
2192
  rows: sortChanges(diff.groups.changed).map((group) => ({
@@ -2201,8 +2206,8 @@ function formatDiffAuditsSection(diff) {
2201
2206
  columns: [
2202
2207
  { key: "plugin", label: "\u{1F50C} Plugin", align: "left" },
2203
2208
  { key: "audit", label: "\u{1F6E1}\uFE0F Audit", align: "left" },
2204
- { key: "after", label: "\u{1F4CF} Current value" },
2205
2209
  { key: "before", label: "\u{1F4CF} Previous value" },
2210
+ { key: "after", label: "\u{1F4CF} Current value" },
2206
2211
  { key: "change", label: "\u{1F504} Value change" }
2207
2212
  ],
2208
2213
  rows: sortChanges(diff.audits.changed).map((audit) => ({
@@ -2573,7 +2578,7 @@ var verboseUtils = (verbose = false) => ({
2573
2578
 
2574
2579
  // packages/core/package.json
2575
2580
  var name = "@code-pushup/core";
2576
- var version = "0.46.0";
2581
+ var version = "0.48.0";
2577
2582
 
2578
2583
  // packages/core/src/lib/implementation/execute-plugin.ts
2579
2584
  import chalk5 from "chalk";
@@ -3118,9 +3123,9 @@ function tableToGQL(table5) {
3118
3123
  )
3119
3124
  },
3120
3125
  rows: table5.rows.map(
3121
- (row) => Array.isArray(row) ? row.map((content) => ({ content: content.toString() })) : Object.entries(row).map(([key, content]) => ({
3126
+ (row) => Array.isArray(row) ? row.map((content) => ({ content: content?.toString() ?? "" })) : Object.entries(row).map(([key, content]) => ({
3122
3127
  key,
3123
- content: content.toString()
3128
+ content: content?.toString() ?? ""
3124
3129
  }))
3125
3130
  )
3126
3131
  };
@@ -3238,7 +3243,7 @@ async function readRcByPath(filepath, tsconfig) {
3238
3243
  if (!await fileExists(filepath)) {
3239
3244
  throw new ConfigPathError(filepath);
3240
3245
  }
3241
- const cfg = await importEsmModule({ filepath, tsconfig });
3246
+ const cfg = await importModule({ filepath, tsconfig, format: "esm" });
3242
3247
  return coreConfigSchema.parse(cfg);
3243
3248
  }
3244
3249
  async function autoloadRc(tsconfig) {
@@ -3464,6 +3469,19 @@ function yargsOnlyPluginsOptionsDefinition() {
3464
3469
  };
3465
3470
  }
3466
3471
 
3472
+ // packages/cli/src/lib/implementation/skip-plugins.options.ts
3473
+ var skipPluginsOption = {
3474
+ describe: "List of plugins to skip. If not set all plugins are run.",
3475
+ type: "array",
3476
+ default: [],
3477
+ coerce: coerceArray
3478
+ };
3479
+ function yargsSkipPluginsOptionsDefinition() {
3480
+ return {
3481
+ skipPlugins: skipPluginsOption
3482
+ };
3483
+ }
3484
+
3467
3485
  // packages/cli/src/lib/history/history.options.ts
3468
3486
  function yargsHistoryOptionsDefinition() {
3469
3487
  return {
@@ -3574,7 +3592,8 @@ function yargsHistoryCommandObject() {
3574
3592
  builder: (yargs2) => {
3575
3593
  yargs2.options({
3576
3594
  ...yargsHistoryOptionsDefinition(),
3577
- ...yargsOnlyPluginsOptionsDefinition()
3595
+ ...yargsOnlyPluginsOptionsDefinition(),
3596
+ ...yargsSkipPluginsOptionsDefinition()
3578
3597
  });
3579
3598
  yargs2.group(
3580
3599
  Object.keys(yargsHistoryOptionsDefinition()),
@@ -3669,35 +3688,37 @@ async function coreConfigMiddleware(processArgs) {
3669
3688
  };
3670
3689
  }
3671
3690
 
3672
- // packages/cli/src/lib/implementation/only-plugins.utils.ts
3691
+ // packages/cli/src/lib/implementation/validate-plugin-filter-options.utils.ts
3673
3692
  import chalk12 from "chalk";
3674
- function validateOnlyPluginsOption({
3693
+ function validatePluginFilterOption(filterOption, {
3675
3694
  plugins,
3676
3695
  categories
3677
3696
  }, {
3678
- onlyPlugins = [],
3697
+ pluginsToFilter = [],
3679
3698
  verbose = false
3680
3699
  } = {}) {
3681
- const onlyPluginsSet = new Set(onlyPlugins);
3682
- const missingPlugins = onlyPlugins.filter(
3700
+ const pluginsToFilterSet = new Set(pluginsToFilter);
3701
+ const missingPlugins = pluginsToFilter.filter(
3683
3702
  (plugin) => !plugins.some(({ slug }) => slug === plugin)
3684
3703
  );
3704
+ const isSkipOption = filterOption === "skipPlugins";
3705
+ const filterFunction = (plugin) => isSkipOption ? pluginsToFilterSet.has(plugin) : !pluginsToFilterSet.has(plugin);
3685
3706
  if (missingPlugins.length > 0 && verbose) {
3686
3707
  ui().logger.info(
3687
3708
  `${chalk12.yellow(
3688
3709
  "\u26A0"
3689
- )} The --onlyPlugin argument references plugins with "${missingPlugins.join(
3710
+ )} The --${filterOption} argument references plugins with "${missingPlugins.join(
3690
3711
  '", "'
3691
3712
  )}" slugs, but no such plugins are present in the configuration. Expected one of the following plugin slugs: "${plugins.map(({ slug }) => slug).join('", "')}".`
3692
3713
  );
3693
3714
  }
3694
- if (categories.length > 0) {
3695
- const removedCategorieSlugs = filterItemRefsBy(
3715
+ if (categories.length > 0 && verbose) {
3716
+ const removedCategorySlugs = filterItemRefsBy(
3696
3717
  categories,
3697
- ({ plugin }) => !onlyPluginsSet.has(plugin)
3718
+ ({ plugin }) => filterFunction(plugin)
3698
3719
  ).map(({ slug }) => slug);
3699
3720
  ui().logger.info(
3700
- `The --onlyPlugin argument removed categories with "${removedCategorieSlugs.join(
3721
+ `The --${filterOption} argument removed categories with "${removedCategorySlugs.join(
3701
3722
  '", "'
3702
3723
  )}" slugs.
3703
3724
  `
@@ -3710,9 +3731,10 @@ function onlyPluginsMiddleware(originalProcessArgs) {
3710
3731
  const { categories = [], onlyPlugins: originalOnlyPlugins } = originalProcessArgs;
3711
3732
  if (originalOnlyPlugins && originalOnlyPlugins.length > 0) {
3712
3733
  const { verbose, plugins, onlyPlugins = [] } = originalProcessArgs;
3713
- validateOnlyPluginsOption(
3734
+ validatePluginFilterOption(
3735
+ "onlyPlugins",
3714
3736
  { plugins, categories },
3715
- { onlyPlugins, verbose }
3737
+ { pluginsToFilter: onlyPlugins, verbose }
3716
3738
  );
3717
3739
  const validOnlyPlugins = onlyPlugins.filter(
3718
3740
  (oP) => plugins.find((p) => p.slug === oP)
@@ -3734,6 +3756,36 @@ function onlyPluginsMiddleware(originalProcessArgs) {
3734
3756
  };
3735
3757
  }
3736
3758
 
3759
+ // packages/cli/src/lib/implementation/skip-plugins.middleware.ts
3760
+ function skipPluginsMiddleware(originalProcessArgs) {
3761
+ const { categories = [], skipPlugins: originalSkipPlugins } = originalProcessArgs;
3762
+ if (originalSkipPlugins && originalSkipPlugins.length > 0) {
3763
+ const { verbose, plugins, skipPlugins = [] } = originalProcessArgs;
3764
+ validatePluginFilterOption(
3765
+ "skipPlugins",
3766
+ { plugins, categories },
3767
+ { pluginsToFilter: skipPlugins, verbose }
3768
+ );
3769
+ const validSkipPlugins = skipPlugins.filter(
3770
+ (sP) => plugins.find((p) => p.slug === sP)
3771
+ );
3772
+ const skipPluginsSet = new Set(validSkipPlugins);
3773
+ return {
3774
+ ...originalProcessArgs,
3775
+ plugins: skipPluginsSet.size > 0 ? plugins.filter(({ slug }) => !skipPluginsSet.has(slug)) : plugins,
3776
+ categories: skipPluginsSet.size > 0 ? filterItemRefsBy(
3777
+ categories,
3778
+ ({ plugin }) => !skipPluginsSet.has(plugin)
3779
+ ) : categories
3780
+ };
3781
+ }
3782
+ return {
3783
+ ...originalProcessArgs,
3784
+ // if undefined fill categories with empty array
3785
+ categories
3786
+ };
3787
+ }
3788
+
3737
3789
  // packages/cli/src/lib/middlewares.ts
3738
3790
  var middlewares = [
3739
3791
  {
@@ -3743,6 +3795,10 @@ var middlewares = [
3743
3795
  {
3744
3796
  middlewareFunction: onlyPluginsMiddleware,
3745
3797
  applyBeforeValidation: false
3798
+ },
3799
+ {
3800
+ middlewareFunction: skipPluginsMiddleware,
3801
+ applyBeforeValidation: false
3746
3802
  }
3747
3803
  ];
3748
3804
 
@@ -3818,12 +3874,14 @@ function yargsGlobalOptionsDefinition() {
3818
3874
  var options = {
3819
3875
  ...yargsGlobalOptionsDefinition(),
3820
3876
  ...yargsCoreConfigOptionsDefinition(),
3821
- ...yargsOnlyPluginsOptionsDefinition()
3877
+ ...yargsOnlyPluginsOptionsDefinition(),
3878
+ ...yargsSkipPluginsOptionsDefinition()
3822
3879
  };
3823
3880
  var groups = {
3824
3881
  "Global Options:": [
3825
3882
  ...Object.keys(yargsGlobalOptionsDefinition()),
3826
- ...Object.keys(yargsOnlyPluginsOptionsDefinition())
3883
+ ...Object.keys(yargsOnlyPluginsOptionsDefinition()),
3884
+ ...Object.keys(yargsSkipPluginsOptionsDefinition())
3827
3885
  ],
3828
3886
  "Persist Options:": Object.keys(yargsPersistConfigOptionsDefinition()),
3829
3887
  "Upload Options:": Object.keys(yargsUploadConfigOptionsDefinition())
@@ -3915,6 +3973,10 @@ var cli = (args) => yargsCli(args, {
3915
3973
  "code-pushup collect --onlyPlugins=coverage",
3916
3974
  "Run collect with only coverage plugin, other plugins from config file will be skipped."
3917
3975
  ],
3976
+ [
3977
+ "code-pushup collect --skipPlugins=coverage",
3978
+ "Run collect skiping the coverage plugin, other plugins from config file will be included."
3979
+ ],
3918
3980
  [
3919
3981
  "code-pushup upload --persist.outputDir=dist --persist.filename=cp-report --upload.apiKey=$CP_API_KEY",
3920
3982
  "Upload dist/cp-report.json to portal using API key from environment variable"
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@code-pushup/cli",
3
- "version": "0.46.0",
3
+ "version": "0.48.0",
4
4
  "license": "MIT",
5
5
  "bin": {
6
6
  "code-pushup": "index.js"
7
7
  },
8
8
  "dependencies": {
9
- "@code-pushup/models": "0.46.0",
10
- "@code-pushup/core": "0.46.0",
11
- "@code-pushup/utils": "0.46.0",
9
+ "@code-pushup/models": "0.48.0",
10
+ "@code-pushup/core": "0.48.0",
11
+ "@code-pushup/utils": "0.48.0",
12
12
  "yargs": "^17.7.2",
13
13
  "chalk": "^5.3.0",
14
14
  "simple-git": "^3.20.0"
@@ -2,4 +2,5 @@ import { CoreConfig } from '@code-pushup/models';
2
2
  import { CoreConfigCliOptions } from './core-config.model';
3
3
  import { GeneralCliOptions } from './global.model';
4
4
  import { OnlyPluginsOptions } from './only-plugins.model';
5
- export declare function coreConfigMiddleware<T extends GeneralCliOptions & CoreConfigCliOptions & OnlyPluginsOptions>(processArgs: T): Promise<GeneralCliOptions & CoreConfig & OnlyPluginsOptions>;
5
+ import { SkipPluginsOptions } from './skip-plugins.model';
6
+ export declare function coreConfigMiddleware<T extends GeneralCliOptions & CoreConfigCliOptions & OnlyPluginsOptions & SkipPluginsOptions>(processArgs: T): Promise<GeneralCliOptions & CoreConfig & OnlyPluginsOptions & SkipPluginsOptions>;
@@ -0,0 +1,2 @@
1
+ import { SkipPluginsOptions } from './skip-plugins.model';
2
+ export declare function skipPluginsMiddleware<T extends SkipPluginsOptions>(originalProcessArgs: T): T;
@@ -0,0 +1,6 @@
1
+ import { GlobalOptions } from '@code-pushup/core';
2
+ import { CoreConfig } from '@code-pushup/models';
3
+ export type SkipPluginsCliOptions = {
4
+ skipPlugins?: string[];
5
+ };
6
+ export type SkipPluginsOptions = Partial<GlobalOptions> & Pick<CoreConfig, 'categories' | 'plugins'> & SkipPluginsCliOptions;
@@ -0,0 +1,3 @@
1
+ import { Options } from 'yargs';
2
+ export declare const skipPluginsOption: Options;
3
+ export declare function yargsSkipPluginsOptionsDefinition(): Record<'skipPlugins', Options>;
@@ -0,0 +1,8 @@
1
+ import type { CategoryConfig, PluginConfig } from '@code-pushup/models';
2
+ export declare function validatePluginFilterOption(filterOption: 'onlyPlugins' | 'skipPlugins', { plugins, categories, }: {
3
+ plugins: PluginConfig[];
4
+ categories: CategoryConfig[];
5
+ }, { pluginsToFilter, verbose, }?: {
6
+ pluginsToFilter?: string[];
7
+ verbose?: boolean;
8
+ }): void;
@@ -1,4 +1,5 @@
1
1
  export declare const options: {
2
+ skipPlugins: import("yargs").Options;
2
3
  onlyPlugins: import("yargs").Options;
3
4
  "persist.outputDir": import("yargs").Options;
4
5
  "persist.filename": import("yargs").Options;
@@ -1,8 +0,0 @@
1
- import type { CategoryConfig, PluginConfig } from '@code-pushup/models';
2
- export declare function validateOnlyPluginsOption({ plugins, categories, }: {
3
- plugins: PluginConfig[];
4
- categories: CategoryConfig[];
5
- }, { onlyPlugins, verbose, }?: {
6
- onlyPlugins?: string[];
7
- verbose?: boolean;
8
- }): void;