@code-pushup/cli 0.4.5 → 0.5.1

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
@@ -144,6 +144,7 @@ Each example is fully tested to give demonstrate best practices for plugin testi
144
144
  **Example for custom plugins:**
145
145
 
146
146
  - [File Size](../../examples/plugins/src/file-size)
147
+ - [Package Json](../../examples/plugins/src/package-json)
147
148
 
148
149
  ## CLI commands and options
149
150
 
package/index.js CHANGED
@@ -137,12 +137,14 @@ function scorableSchema(description, refSchema, duplicateCheckFn, duplicateMessa
137
137
  return z.object(
138
138
  {
139
139
  slug: slugSchema('Human-readable unique ID, e.g. "performance"'),
140
- refs: z.array(refSchema).refine(
140
+ refs: z.array(refSchema).min(1).refine(
141
141
  (refs) => !duplicateCheckFn(refs),
142
142
  (refs) => ({
143
143
  message: duplicateMessageFn(refs)
144
144
  })
145
- )
145
+ ).refine(hasWeightedRefsInCategories, () => ({
146
+ message: `In a category there has to be at least one ref with weight > 0`
147
+ }))
146
148
  },
147
149
  { description }
148
150
  );
@@ -151,6 +153,9 @@ var materialIconSchema = z.enum(
151
153
  MATERIAL_ICONS,
152
154
  { description: "Icon from VSCode Material Icons extension" }
153
155
  );
156
+ function hasWeightedRefsInCategories(categoryRefs) {
157
+ return categoryRefs.reduce((acc, { weight }) => weight + acc, 0) !== 0;
158
+ }
154
159
 
155
160
  // packages/models/src/lib/category-config.ts
156
161
  var categoryRefSchema = weightedRefSchema(
@@ -196,6 +201,23 @@ function getDuplicateRefsInCategoryMetrics(metrics) {
196
201
  metrics.map(({ slug, type, plugin }) => `${type} :: ${plugin} / ${slug}`)
197
202
  );
198
203
  }
204
+ var categoriesSchema = z2.array(categoryConfigSchema, {
205
+ description: "Categorization of individual audits"
206
+ }).min(1).refine(
207
+ (categoryCfg) => !getDuplicateSlugCategories(categoryCfg),
208
+ (categoryCfg) => ({
209
+ message: duplicateSlugCategoriesErrorMsg(categoryCfg)
210
+ })
211
+ );
212
+ function duplicateSlugCategoriesErrorMsg(categories) {
213
+ const duplicateStringSlugs = getDuplicateSlugCategories(categories);
214
+ return `In the categories, the following slugs are duplicated: ${errorItems(
215
+ duplicateStringSlugs
216
+ )}`;
217
+ }
218
+ function getDuplicateSlugCategories(categories) {
219
+ return hasDuplicateStrings(categories.map(({ slug }) => slug));
220
+ }
199
221
 
200
222
  // packages/models/src/lib/core-config.ts
201
223
  import { z as z11 } from "zod";
@@ -204,10 +226,10 @@ import { z as z11 } from "zod";
204
226
  import { z as z3 } from "zod";
205
227
  var formatSchema = z3.enum(["json", "md"]);
206
228
  var persistConfigSchema = z3.object({
207
- outputDir: filePathSchema("Artifacts folder"),
208
- filename: fileNameSchema("Artifacts file name (without extension)").default(
209
- "report"
210
- ),
229
+ outputDir: filePathSchema("Artifacts folder").optional(),
230
+ filename: fileNameSchema(
231
+ "Artifacts file name (without extension)"
232
+ ).optional(),
211
233
  format: z3.array(formatSchema).default(["json"]).optional()
212
234
  // @TODO remove default or optional value and otherwise it will not set defaults.
213
235
  });
@@ -443,17 +465,10 @@ var unrefinedCoreConfigSchema = z11.object({
443
465
  description: "List of plugins to be used (official, community-provided, or custom)"
444
466
  }),
445
467
  /** portal configuration for persisting results */
446
- persist: persistConfigSchema,
468
+ persist: persistConfigSchema.optional(),
447
469
  /** portal configuration for uploading results */
448
470
  upload: uploadConfigSchema.optional(),
449
- categories: z11.array(categoryConfigSchema, {
450
- description: "Categorization of individual audits"
451
- }).refine(
452
- (categoryCfg) => !getDuplicateSlugCategories(categoryCfg),
453
- (categoryCfg) => ({
454
- message: duplicateSlugCategoriesErrorMsg(categoryCfg)
455
- })
456
- )
471
+ categories: categoriesSchema
457
472
  });
458
473
  var coreConfigSchema = refineCoreConfig(unrefinedCoreConfigSchema);
459
474
  function refineCoreConfig(schema) {
@@ -504,15 +519,11 @@ function getMissingRefsForCategories(coreCfg) {
504
519
  }
505
520
  return missingRefs.length ? missingRefs : false;
506
521
  }
507
- function duplicateSlugCategoriesErrorMsg(categories) {
508
- const duplicateStringSlugs = getDuplicateSlugCategories(categories);
509
- return `In the categories, the following slugs are duplicated: ${errorItems(
510
- duplicateStringSlugs
511
- )}`;
512
- }
513
- function getDuplicateSlugCategories(categories) {
514
- return hasDuplicateStrings(categories.map(({ slug }) => slug));
515
- }
522
+
523
+ // packages/models/src/lib/implementation/constants.ts
524
+ var PERSIST_OUTPUT_DIR = ".code-pushup";
525
+ var PERSIST_FORMAT = ["json"];
526
+ var PERSIST_FILENAME = "report";
516
527
 
517
528
  // packages/models/src/lib/report.ts
518
529
  import { z as z12 } from "zod";
@@ -1399,6 +1410,11 @@ function calculateScore(refs, scoreFn) {
1399
1410
  },
1400
1411
  { numerator: 0, denominator: 0 }
1401
1412
  );
1413
+ if (!numerator && !denominator) {
1414
+ throw new Error(
1415
+ "0 division for score. This can be caused by refs only weighted with 0 or empty refs"
1416
+ );
1417
+ }
1402
1418
  return numerator / denominator;
1403
1419
  }
1404
1420
  function scoreReport(report) {
@@ -1481,11 +1497,8 @@ var PersistError = class extends Error {
1481
1497
  super(`fileName: ${reportPath} could not be saved.`);
1482
1498
  }
1483
1499
  };
1484
- async function persistReport(report, config) {
1485
- const { persist } = config;
1486
- const outputDir = persist.outputDir;
1487
- const filename = persist.filename;
1488
- const format = persist.format ?? [];
1500
+ async function persistReport(report, options2) {
1501
+ const { outputDir, filename, format } = options2;
1489
1502
  let scoredReport = scoreReport(report);
1490
1503
  console.info(reportToStdout(scoredReport));
1491
1504
  const results = [
@@ -1640,7 +1653,7 @@ function auditOutputsCorrelateWithPluginOutput(auditOutputs, pluginConfigAudits)
1640
1653
 
1641
1654
  // packages/core/package.json
1642
1655
  var name = "@code-pushup/core";
1643
- var version = "0.4.5";
1656
+ var version = "0.5.1";
1644
1657
 
1645
1658
  // packages/core/src/lib/implementation/collect.ts
1646
1659
  async function collect(options2) {
@@ -1738,16 +1751,23 @@ function transformSeverity(severity) {
1738
1751
  }
1739
1752
  }
1740
1753
 
1754
+ // packages/core/src/lib/normalize.ts
1755
+ var normalizePersistConfig = (cfg) => ({
1756
+ outputDir: PERSIST_OUTPUT_DIR,
1757
+ filename: PERSIST_FILENAME,
1758
+ format: PERSIST_FORMAT,
1759
+ ...cfg
1760
+ });
1761
+
1741
1762
  // packages/core/src/lib/upload.ts
1742
1763
  async function upload(options2, uploadFn = uploadToPortal) {
1743
- if (options2?.upload === void 0) {
1744
- throw new Error("upload config needs to be set");
1764
+ const persist = normalizePersistConfig(options2?.persist);
1765
+ if (!options2?.upload) {
1766
+ throw new Error("upload config must be set");
1745
1767
  }
1746
1768
  const { apiKey, server, organization, project } = options2.upload;
1747
- const { outputDir, filename } = options2.persist;
1748
1769
  const report = await loadReport({
1749
- outputDir,
1750
- filename,
1770
+ ...persist,
1751
1771
  format: "json"
1752
1772
  });
1753
1773
  const commitData = await getLatestCommit();
@@ -1767,7 +1787,8 @@ async function upload(options2, uploadFn = uploadToPortal) {
1767
1787
  async function collectAndPersistReports(options2) {
1768
1788
  const { exec } = verboseUtils(options2.verbose);
1769
1789
  const report = await collect(options2);
1770
- const persistResults = await persistReport(report, options2);
1790
+ const persist = normalizePersistConfig(options2?.persist);
1791
+ const persistResults = await persistReport(report, persist);
1771
1792
  exec(() => logPersistedResults(persistResults));
1772
1793
  report.plugins.forEach((plugin) => {
1773
1794
  pluginReportSchema.parse(plugin);
@@ -1791,7 +1812,7 @@ async function readCodePushupConfig(filepath) {
1791
1812
  {
1792
1813
  filepath
1793
1814
  },
1794
- coreConfigSchema.parse
1815
+ (d) => coreConfigSchema.parse(d)
1795
1816
  );
1796
1817
  }
1797
1818
 
@@ -1961,9 +1982,13 @@ async function configMiddleware(processArgs) {
1961
1982
  ...importedRc.upload,
1962
1983
  ...cliOptions.upload
1963
1984
  },
1985
+ // we can't use a async rc file as yargs does not support it. see: https://github.com/yargs/yargs/issues/2234
1986
+ // therefore this can't live in option defaults as the order would be `config`->`provided options`->default
1987
+ // so we have to manually implement the order
1964
1988
  persist: {
1965
- ...importedRc.persist,
1966
- ...cliOptions.persist
1989
+ outputDir: cliOptions?.persist?.outputDir || importedRc?.persist?.outputDir || PERSIST_OUTPUT_DIR,
1990
+ filename: cliOptions?.persist?.filename || importedRc?.persist?.filename || PERSIST_FILENAME,
1991
+ format: cliOptions?.persist?.format || importedRc?.persist?.format || PERSIST_FORMAT
1967
1992
  },
1968
1993
  plugins: filterPluginsByOnlyPluginsOption(importedRc.plugins, cliOptions),
1969
1994
  categories: filterCategoryByOnlyPluginsOption(
@@ -1982,6 +2007,14 @@ var middlewares = [
1982
2007
 
1983
2008
  // packages/cli/src/lib/implementation/core-config-options.ts
1984
2009
  function yargsCoreConfigOptionsDefinition() {
2010
+ return {
2011
+ // persist
2012
+ ...yargsPersistConfigOptionsDefinition(),
2013
+ // upload
2014
+ ...yargsUploadConfigOptionsDefinition()
2015
+ };
2016
+ }
2017
+ function yargsPersistConfigOptionsDefinition() {
1985
2018
  return {
1986
2019
  // persist
1987
2020
  "persist.outputDir": {
@@ -1995,7 +2028,11 @@ function yargsCoreConfigOptionsDefinition() {
1995
2028
  "persist.format": {
1996
2029
  describe: "Format of the report output. e.g. `md`, `json`",
1997
2030
  type: "array"
1998
- },
2031
+ }
2032
+ };
2033
+ }
2034
+ function yargsUploadConfigOptionsDefinition() {
2035
+ return {
1999
2036
  // upload
2000
2037
  "upload.organization": {
2001
2038
  describe: "Organization slug from portal",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-pushup/cli",
3
- "version": "0.4.5",
3
+ "version": "0.5.1",
4
4
  "bin": {
5
5
  "code-pushup": "index.js"
6
6
  },
@@ -197,11 +197,6 @@ export declare function configMiddleware<T extends Partial<GeneralCliOptions & C
197
197
  docsUrl?: string | undefined;
198
198
  }[] | undefined;
199
199
  }[];
200
- persist: {
201
- outputDir: string;
202
- filename: string;
203
- format?: ("json" | "md")[] | undefined;
204
- };
205
200
  categories: {
206
201
  title: string;
207
202
  slug: string;
@@ -215,6 +210,11 @@ export declare function configMiddleware<T extends Partial<GeneralCliOptions & C
215
210
  docsUrl?: string | undefined;
216
211
  isBinary?: boolean | undefined;
217
212
  }[];
213
+ persist?: {
214
+ outputDir?: string | undefined;
215
+ filename?: string | undefined;
216
+ format?: ("json" | "md")[] | undefined;
217
+ } | undefined;
218
218
  upload?: {
219
219
  server: string;
220
220
  apiKey: string;
@@ -1,5 +1,5 @@
1
1
  import { Options } from 'yargs';
2
- import { CoreConfigCliOptions } from './model';
3
- type ArgNames = keyof CoreConfigCliOptions;
4
- export declare function yargsCoreConfigOptionsDefinition(): Record<ArgNames, Options>;
5
- export {};
2
+ import { CoreConfigCliOptions, PersistConfigCliOptions, UploadConfigCliOptions } from './model';
3
+ export declare function yargsCoreConfigOptionsDefinition(): Record<keyof CoreConfigCliOptions, Options>;
4
+ export declare function yargsPersistConfigOptionsDefinition(): Record<keyof PersistConfigCliOptions, Options>;
5
+ export declare function yargsUploadConfigOptionsDefinition(): Record<keyof UploadConfigCliOptions, Options>;