@code-pushup/ci 0.54.0 → 0.55.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
@@ -94,20 +94,23 @@ A `Comment` object has the following required properties:
94
94
 
95
95
  Optionally, you can override default options for further customization:
96
96
 
97
- | Property | Type | Default | Description |
98
- | :---------------- | :------------------------ | :------------------------------- | :-------------------------------------------------------------------------------- |
99
- | `monorepo` | `boolean \| MonorepoTool` | `false` | Enables [monorepo mode](#monorepo-mode) |
100
- | `projects` | `string[] \| null` | `null` | Custom projects configuration for [monorepo mode](#monorepo-mode) |
101
- | `task` | `string` | `'code-pushup'` | Name of command to run Code PushUp per project in [monorepo mode](#monorepo-mode) |
102
- | `directory` | `string` | `process.cwd()` | Directory in which Code PushUp CLI should run |
103
- | `config` | `string \| null` | `null` [^1] | Path to config file (`--config` option) |
104
- | `silent` | `boolean` | `false` | Toggles if logs from CLI commands are printed |
105
- | `bin` | `string` | `'npx --no-install code-pushup'` | Command for executing Code PushUp CLI |
106
- | `detectNewIssues` | `boolean` | `true` | Toggles if new issues should be detected and returned in `newIssues` property |
107
- | `logger` | `Logger` | `console` | Logger for reporting progress and encountered problems |
97
+ | Property | Type | Default | Description |
98
+ | :---------------- | :------------------------ | :------------------------------- | :----------------------------------------------------------------------------------- |
99
+ | `monorepo` | `boolean \| MonorepoTool` | `false` | Enables [monorepo mode](#monorepo-mode) |
100
+ | `projects` | `string[] \| null` | `null` | Custom projects configuration for [monorepo mode](#monorepo-mode) |
101
+ | `task` | `string` | `'code-pushup'` | Name of command to run Code PushUp per project in [monorepo mode](#monorepo-mode) |
102
+ | `directory` | `string` | `process.cwd()` | Directory in which Code PushUp CLI should run |
103
+ | `config` | `string \| null` | `null` [^1] | Path to config file (`--config` option) |
104
+ | `silent` | `boolean` | `false` | Toggles if logs from CLI commands are printed |
105
+ | `bin` | `string` | `'npx --no-install code-pushup'` | Command for executing Code PushUp CLI |
106
+ | `detectNewIssues` | `boolean` | `true` | Toggles if new issues should be detected and returned in `newIssues` property |
107
+ | `logger` | `Logger` | `console` | Logger for reporting progress and encountered problems |
108
+ | `output` | `string` | `'.code-pushup'` | Directory where Code PushUp reports will be created (interpolates project name [^2]) |
108
109
 
109
110
  [^1]: By default, the `code-pushup.config` file is autodetected as described in [`@code-pushup/cli` docs](../cli/README.md#configuration).
110
111
 
112
+ [^2]: In monorepo mode, any occurrence of `{project}` in the `output` path will be replaced with a project name. This separation of folders per project (e.g. `output: '.code-pushup/{project}'`) may be useful for caching purposes.
113
+
111
114
  The `Logger` object has the following required properties:
112
115
 
113
116
  | Property | Type | Description |
package/index.js CHANGED
@@ -36,7 +36,7 @@ function exists(value) {
36
36
  return value != null;
37
37
  }
38
38
  function getMissingRefsForCategories(categories, plugins) {
39
- if (categories.length === 0) {
39
+ if (!categories || categories.length === 0) {
40
40
  return false;
41
41
  }
42
42
  const auditRefsFromCategory = categories.flatMap(
@@ -535,12 +535,9 @@ var unrefinedCoreConfigSchema = z14.object({
535
535
  var coreConfigSchema = refineCoreConfig(unrefinedCoreConfigSchema);
536
536
  function refineCoreConfig(schema) {
537
537
  return schema.refine(
538
- (coreCfg) => !getMissingRefsForCategories(coreCfg.categories ?? [], coreCfg.plugins),
539
- (coreCfg) => ({
540
- message: missingRefsForCategoriesErrorMsg(
541
- coreCfg.categories ?? [],
542
- coreCfg.plugins
543
- )
538
+ ({ categories, plugins }) => !getMissingRefsForCategories(categories, plugins),
539
+ ({ categories, plugins }) => ({
540
+ message: missingRefsForCategoriesErrorMsg(categories, plugins)
544
541
  })
545
542
  );
546
543
  }
@@ -597,19 +594,16 @@ var reportSchema = packageVersionSchema({
597
594
  ).merge(
598
595
  z15.object(
599
596
  {
600
- categories: z15.array(categoryConfigSchema),
601
597
  plugins: z15.array(pluginReportSchema).min(1),
598
+ categories: z15.array(categoryConfigSchema).optional(),
602
599
  commit: commitSchema.describe("Git commit for which report was collected").nullable()
603
600
  },
604
601
  { description: "Collect output data" }
605
602
  )
606
603
  ).refine(
607
- (report) => !getMissingRefsForCategories(report.categories, report.plugins),
608
- (report) => ({
609
- message: missingRefsForCategoriesErrorMsg(
610
- report.categories,
611
- report.plugins
612
- )
604
+ ({ categories, plugins }) => !getMissingRefsForCategories(categories, plugins),
605
+ ({ categories, plugins }) => ({
606
+ message: missingRefsForCategoriesErrorMsg(categories, plugins)
613
607
  })
614
608
  );
615
609
 
@@ -1171,10 +1165,11 @@ import { simpleGit as simpleGit4 } from "simple-git";
1171
1165
  import path from "node:path";
1172
1166
  function persistCliOptions({
1173
1167
  directory,
1174
- project
1168
+ project,
1169
+ output
1175
1170
  }) {
1176
1171
  return [
1177
- `--persist.outputDir=${path.join(directory, DEFAULT_PERSIST_OUTPUT_DIR)}`,
1172
+ `--persist.outputDir=${path.join(directory, output)}`,
1178
1173
  `--persist.filename=${createFilename(project)}`,
1179
1174
  ...DEFAULT_PERSIST_FORMAT.map((format) => `--persist.format=${format}`)
1180
1175
  ];
@@ -1183,9 +1178,10 @@ function persistedCliFiles({
1183
1178
  directory,
1184
1179
  isDiff,
1185
1180
  project,
1186
- formats
1181
+ formats,
1182
+ output
1187
1183
  }) {
1188
- const rootDir = path.join(directory, DEFAULT_PERSIST_OUTPUT_DIR);
1184
+ const rootDir = path.join(directory, output);
1189
1185
  const filename = isDiff ? `${createFilename(project)}-diff` : createFilename(project);
1190
1186
  const filePaths = (formats ?? DEFAULT_PERSIST_FORMAT).reduce(
1191
1187
  (acc, format) => ({
@@ -1218,24 +1214,25 @@ async function runCollect({
1218
1214
  config,
1219
1215
  directory,
1220
1216
  silent,
1221
- project
1217
+ project,
1218
+ output
1222
1219
  }) {
1223
1220
  const { stdout } = await executeProcess({
1224
1221
  command: bin,
1225
1222
  args: [
1226
1223
  ...config ? [`--config=${config}`] : [],
1227
- ...persistCliOptions({ directory, project })
1224
+ ...persistCliOptions({ directory, project, output })
1228
1225
  ],
1229
1226
  cwd: directory
1230
1227
  });
1231
1228
  if (!silent) {
1232
1229
  console.info(stdout);
1233
1230
  }
1234
- return persistedCliFiles({ directory, project });
1231
+ return persistedCliFiles({ directory, project, output });
1235
1232
  }
1236
1233
 
1237
1234
  // packages/ci/src/lib/cli/commands/compare.ts
1238
- async function runCompare({ before, after, label }, { bin, config, directory, silent, project }) {
1235
+ async function runCompare({ before, after, label }, { bin, config, directory, silent, project, output }) {
1239
1236
  const { stdout } = await executeProcess({
1240
1237
  command: bin,
1241
1238
  args: [
@@ -1244,32 +1241,37 @@ async function runCompare({ before, after, label }, { bin, config, directory, si
1244
1241
  `--after=${after}`,
1245
1242
  ...label ? [`--label=${label}`] : [],
1246
1243
  ...config ? [`--config=${config}`] : [],
1247
- ...persistCliOptions({ directory, project })
1244
+ ...persistCliOptions({ directory, project, output })
1248
1245
  ],
1249
1246
  cwd: directory
1250
1247
  });
1251
1248
  if (!silent) {
1252
1249
  console.info(stdout);
1253
1250
  }
1254
- return persistedCliFiles({ directory, isDiff: true, project });
1251
+ return persistedCliFiles({ directory, isDiff: true, project, output });
1255
1252
  }
1256
1253
 
1257
1254
  // packages/ci/src/lib/cli/commands/merge-diffs.ts
1258
- async function runMergeDiffs(files, { bin, config, directory, silent }) {
1255
+ async function runMergeDiffs(files, { bin, config, directory, silent, output }) {
1259
1256
  const { stdout } = await executeProcess({
1260
1257
  command: bin,
1261
1258
  args: [
1262
1259
  "merge-diffs",
1263
1260
  ...files.map((file) => `--files=${file}`),
1264
1261
  ...config ? [`--config=${config}`] : [],
1265
- ...persistCliOptions({ directory })
1262
+ ...persistCliOptions({ directory, output })
1266
1263
  ],
1267
1264
  cwd: directory
1268
1265
  });
1269
1266
  if (!silent) {
1270
1267
  console.info(stdout);
1271
1268
  }
1272
- return persistedCliFiles({ directory, isDiff: true, formats: ["md"] });
1269
+ return persistedCliFiles({
1270
+ directory,
1271
+ isDiff: true,
1272
+ formats: ["md"],
1273
+ output
1274
+ });
1273
1275
  }
1274
1276
 
1275
1277
  // packages/ci/src/lib/cli/commands/print-config.ts
@@ -1296,7 +1298,8 @@ function createCommandContext(settings, project) {
1296
1298
  bin: project?.bin ?? settings.bin,
1297
1299
  directory: project?.directory ?? settings.directory,
1298
1300
  config: settings.config,
1299
- silent: settings.silent
1301
+ silent: settings.silent,
1302
+ output: settings.output.replaceAll("{project}", project?.name ?? "")
1300
1303
  };
1301
1304
  }
1302
1305
 
@@ -1350,7 +1353,8 @@ var DEFAULT_SETTINGS = {
1350
1353
  silent: false,
1351
1354
  debug: false,
1352
1355
  detectNewIssues: true,
1353
- logger: console
1356
+ logger: console,
1357
+ output: DEFAULT_PERSIST_OUTPUT_DIR
1354
1358
  };
1355
1359
 
1356
1360
  // packages/ci/src/lib/git.ts
@@ -1510,6 +1514,9 @@ function createIssuesSortCompareFn(report) {
1510
1514
  return (a, b) => getAuditImpactValue(b, report) - getAuditImpactValue(a, report);
1511
1515
  }
1512
1516
  function getAuditImpactValue({ audit, plugin }, report) {
1517
+ if (!report.categories) {
1518
+ return 0;
1519
+ }
1513
1520
  return report.categories.map((category) => {
1514
1521
  const weights = category.refs.map((ref) => {
1515
1522
  if (ref.plugin !== plugin.slug) {
@@ -1519,17 +1526,20 @@ function getAuditImpactValue({ audit, plugin }, report) {
1519
1526
  case "audit":
1520
1527
  return ref.slug === audit.slug ? ref.weight : 0;
1521
1528
  case "group":
1522
- const group = report.plugins.find(({ slug }) => slug === ref.plugin)?.groups?.find(({ slug }) => slug === ref.slug);
1523
- if (!group?.refs.length) {
1524
- return 0;
1525
- }
1526
- const groupRatio = (group.refs.find(({ slug }) => slug === audit.slug)?.weight ?? 0) / group.refs.reduce((acc, { weight }) => acc + weight, 0);
1527
- return ref.weight * groupRatio;
1529
+ return calculateGroupImpact(ref, audit, report);
1528
1530
  }
1529
1531
  });
1530
1532
  return weights.reduce((acc, weight) => acc + weight, 0) / category.refs.reduce((acc, { weight }) => acc + weight, 0);
1531
1533
  }).reduce((acc, value) => acc + value, 0);
1532
1534
  }
1535
+ function calculateGroupImpact(ref, audit, report) {
1536
+ const group = report.plugins.find(({ slug }) => slug === ref.plugin)?.groups?.find(({ slug }) => slug === ref.slug);
1537
+ if (!group?.refs.length) {
1538
+ return 0;
1539
+ }
1540
+ const groupRatio = (group.refs.find(({ slug }) => slug === audit.slug)?.weight ?? 0) / group.refs.reduce((acc, { weight }) => acc + weight, 0);
1541
+ return ref.weight * groupRatio;
1542
+ }
1533
1543
 
1534
1544
  // packages/ci/src/lib/run.ts
1535
1545
  async function runInCI(refs, api, options, git = simpleGit4()) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-pushup/ci",
3
- "version": "0.54.0",
3
+ "version": "0.55.0",
4
4
  "description": "CI automation logic for Code PushUp (provider-agnostic)",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/code-pushup/cli/tree/main/packages/ci#readme",
@@ -28,8 +28,8 @@
28
28
  "main": "./index.js",
29
29
  "types": "./src/index.d.ts",
30
30
  "dependencies": {
31
- "@code-pushup/models": "0.54.0",
32
- "@code-pushup/utils": "0.54.0",
31
+ "@code-pushup/models": "0.55.0",
32
+ "@code-pushup/utils": "0.55.0",
33
33
  "glob": "^10.4.5",
34
34
  "simple-git": "^3.20.0",
35
35
  "yaml": "^2.5.1"
@@ -1,3 +1,3 @@
1
1
  import type { CommandContext } from '../context';
2
2
  import { type PersistedCliFiles } from '../persist';
3
- export declare function runCollect({ bin, config, directory, silent, project, }: CommandContext): Promise<PersistedCliFiles>;
3
+ export declare function runCollect({ bin, config, directory, silent, project, output, }: CommandContext): Promise<PersistedCliFiles>;
@@ -5,5 +5,5 @@ type CompareOptions = {
5
5
  after: string;
6
6
  label?: string;
7
7
  };
8
- export declare function runCompare({ before, after, label }: CompareOptions, { bin, config, directory, silent, project }: CommandContext): Promise<PersistedCliFiles>;
8
+ export declare function runCompare({ before, after, label }: CompareOptions, { bin, config, directory, silent, project, output }: CommandContext): Promise<PersistedCliFiles>;
9
9
  export {};
@@ -1,3 +1,3 @@
1
1
  import type { CommandContext } from '../context';
2
2
  import { type PersistedCliFiles } from '../persist';
3
- export declare function runMergeDiffs(files: string[], { bin, config, directory, silent }: CommandContext): Promise<PersistedCliFiles<'md'>>;
3
+ export declare function runMergeDiffs(files: string[], { bin, config, directory, silent, output }: CommandContext): Promise<PersistedCliFiles<'md'>>;
@@ -1,6 +1,6 @@
1
1
  import type { Settings } from '../models';
2
2
  import type { ProjectConfig } from '../monorepo';
3
- export type CommandContext = Pick<Settings, 'bin' | 'config' | 'directory' | 'silent'> & {
3
+ export type CommandContext = Pick<Settings, 'bin' | 'config' | 'directory' | 'silent' | 'output'> & {
4
4
  project?: string;
5
5
  };
6
6
  export declare function createCommandContext(settings: Settings, project: ProjectConfig | null | undefined): CommandContext;
@@ -8,14 +8,20 @@ export type PersistedCliFiles<T extends Format = Format> = PersistedCliFilesForm
8
8
  export type PersistedCliFilesFormats<T extends Format = Format> = {
9
9
  [F in T as `${F}FilePath`]: string;
10
10
  };
11
- export declare function persistCliOptions({ directory, project, }: {
11
+ export declare function persistCliOptions({ directory, project, output, }: {
12
12
  directory: string;
13
13
  project?: string;
14
+ output: string;
14
15
  }): string[];
15
- export declare function persistedCliFiles<TFormat extends Format = Format>({ directory, isDiff, project, formats, }: {
16
+ export declare function persistedCliFiles<TFormat extends Format = Format>({ directory, isDiff, project, formats, output, }: {
16
17
  directory: string;
17
18
  isDiff?: boolean;
18
19
  project?: string;
19
20
  formats?: TFormat[];
21
+ output: string;
20
22
  }): PersistedCliFiles<TFormat>;
21
- export declare function findPersistedFiles(rootDir: string, files: string[], project?: string): PersistedCliFiles;
23
+ export declare function findPersistedFiles({ rootDir, files, project, }: {
24
+ rootDir: string;
25
+ files: string[];
26
+ project?: string;
27
+ }): PersistedCliFiles;
@@ -1,4 +1,4 @@
1
- import type { Audit, Issue, PluginMeta, Report, ReportsDiff } from '@code-pushup/models';
1
+ import type { Audit, CategoryRef, Issue, PluginMeta, Report, ReportsDiff } from '@code-pushup/models';
2
2
  import { type ChangedFiles } from './git';
3
3
  export type SourceFileIssue = Required<Issue> & IssueContext;
4
4
  type IssueContext = {
@@ -13,4 +13,5 @@ export declare function filterRelevantIssues({ currReport, prevReport, reportsDi
13
13
  }): SourceFileIssue[];
14
14
  export declare function issuesMatch(prev: SourceFileIssue, curr: SourceFileIssue, changedFiles: ChangedFiles): boolean;
15
15
  export declare function getAuditImpactValue({ audit, plugin }: IssueContext, report: Report): number;
16
+ export declare function calculateGroupImpact(ref: CategoryRef, audit: Audit, report: Report): number;
16
17
  export {};
@@ -15,6 +15,7 @@ export type Options = {
15
15
  debug?: boolean;
16
16
  detectNewIssues?: boolean;
17
17
  logger?: Logger;
18
+ output?: string;
18
19
  };
19
20
  /**
20
21
  * {@link Options} with filled-in defaults.