@code-pushup/cli 0.49.0 → 0.51.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 +20 -5
- package/index.js +666 -374
- package/package.json +6 -32
- package/src/lib/autorun/autorun-command.d.ts +1 -1
- package/src/lib/collect/collect-command.d.ts +1 -1
- package/src/lib/commands.d.ts +1 -1
- package/src/lib/compare/compare-command.d.ts +1 -2
- package/src/lib/history/history.model.d.ts +2 -2
- package/src/lib/history/history.options.d.ts +2 -2
- package/src/lib/history/utils.d.ts +2 -2
- package/src/lib/implementation/compare.model.d.ts +4 -2
- package/src/lib/implementation/compare.options.d.ts +1 -1
- package/src/lib/implementation/core-config.middleware.d.ts +5 -5
- package/src/lib/implementation/core-config.options.d.ts +2 -2
- package/src/lib/implementation/filter-plugins.middleware.d.ts +3 -0
- package/src/lib/implementation/formatting.d.ts +11 -0
- package/src/lib/implementation/global.model.d.ts +2 -2
- package/src/lib/implementation/global.options.d.ts +2 -2
- package/src/lib/implementation/merge-diffs.model.d.ts +3 -0
- package/src/lib/implementation/merge-diffs.options.d.ts +3 -0
- package/src/lib/implementation/only-plugins.model.d.ts +2 -2
- package/src/lib/implementation/only-plugins.options.d.ts +3 -2
- package/src/lib/implementation/skip-plugins.model.d.ts +2 -2
- package/src/lib/implementation/skip-plugins.options.d.ts +3 -2
- package/src/lib/merge-diffs/merge-diffs-command.d.ts +6 -0
- package/src/lib/middlewares.d.ts +1 -1
- package/src/lib/upload/upload-command.d.ts +1 -1
- package/src/lib/yargs-cli.d.ts +14 -1
- package/src/lib/implementation/only-plugins.middleware.d.ts +0 -2
- package/src/lib/implementation/skip-plugins.middleware.d.ts +0 -2
package/index.js
CHANGED
|
@@ -163,9 +163,27 @@ function hasNonZeroWeightedRef(refs) {
|
|
|
163
163
|
return refs.reduce((acc, { weight }) => weight + acc, 0) !== 0;
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
-
// packages/models/src/lib/
|
|
166
|
+
// packages/models/src/lib/source.ts
|
|
167
167
|
import { z as z2 } from "zod";
|
|
168
|
-
var
|
|
168
|
+
var sourceFileLocationSchema = z2.object(
|
|
169
|
+
{
|
|
170
|
+
file: filePathSchema.describe("Relative path to source file in Git repo"),
|
|
171
|
+
position: z2.object(
|
|
172
|
+
{
|
|
173
|
+
startLine: positiveIntSchema.describe("Start line"),
|
|
174
|
+
startColumn: positiveIntSchema.describe("Start column").optional(),
|
|
175
|
+
endLine: positiveIntSchema.describe("End line").optional(),
|
|
176
|
+
endColumn: positiveIntSchema.describe("End column").optional()
|
|
177
|
+
},
|
|
178
|
+
{ description: "Location in file" }
|
|
179
|
+
).optional()
|
|
180
|
+
},
|
|
181
|
+
{ description: "Source file location" }
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
// packages/models/src/lib/audit.ts
|
|
185
|
+
import { z as z3 } from "zod";
|
|
186
|
+
var auditSchema = z3.object({
|
|
169
187
|
slug: slugSchema.describe("ID (unique within plugin)")
|
|
170
188
|
}).merge(
|
|
171
189
|
metaSchema({
|
|
@@ -175,7 +193,7 @@ var auditSchema = z2.object({
|
|
|
175
193
|
description: "List of scorable metrics for the given plugin"
|
|
176
194
|
})
|
|
177
195
|
);
|
|
178
|
-
var pluginAuditsSchema =
|
|
196
|
+
var pluginAuditsSchema = z3.array(auditSchema, {
|
|
179
197
|
description: "List of audits maintained in a plugin"
|
|
180
198
|
}).min(1).refine(
|
|
181
199
|
(auditMetadata) => !getDuplicateSlugsInAudits(auditMetadata),
|
|
@@ -194,31 +212,16 @@ function getDuplicateSlugsInAudits(audits) {
|
|
|
194
212
|
}
|
|
195
213
|
|
|
196
214
|
// packages/models/src/lib/audit-output.ts
|
|
197
|
-
import { z as
|
|
215
|
+
import { z as z6 } from "zod";
|
|
198
216
|
|
|
199
217
|
// packages/models/src/lib/issue.ts
|
|
200
|
-
import { z as
|
|
201
|
-
var
|
|
202
|
-
{
|
|
203
|
-
file: filePathSchema.describe("Relative path to source file in Git repo"),
|
|
204
|
-
position: z3.object(
|
|
205
|
-
{
|
|
206
|
-
startLine: positiveIntSchema.describe("Start line"),
|
|
207
|
-
startColumn: positiveIntSchema.describe("Start column").optional(),
|
|
208
|
-
endLine: positiveIntSchema.describe("End line").optional(),
|
|
209
|
-
endColumn: positiveIntSchema.describe("End column").optional()
|
|
210
|
-
},
|
|
211
|
-
{ description: "Location in file" }
|
|
212
|
-
).optional()
|
|
213
|
-
},
|
|
214
|
-
{ description: "Source file location" }
|
|
215
|
-
);
|
|
216
|
-
var issueSeveritySchema = z3.enum(["info", "warning", "error"], {
|
|
218
|
+
import { z as z4 } from "zod";
|
|
219
|
+
var issueSeveritySchema = z4.enum(["info", "warning", "error"], {
|
|
217
220
|
description: "Severity level"
|
|
218
221
|
});
|
|
219
|
-
var issueSchema =
|
|
222
|
+
var issueSchema = z4.object(
|
|
220
223
|
{
|
|
221
|
-
message:
|
|
224
|
+
message: z4.string({ description: "Descriptive error message" }).max(MAX_ISSUE_MESSAGE_LENGTH),
|
|
222
225
|
severity: issueSeveritySchema,
|
|
223
226
|
source: sourceFileLocationSchema.optional()
|
|
224
227
|
},
|
|
@@ -226,60 +229,60 @@ var issueSchema = z3.object(
|
|
|
226
229
|
);
|
|
227
230
|
|
|
228
231
|
// packages/models/src/lib/table.ts
|
|
229
|
-
import { z as
|
|
230
|
-
var tableAlignmentSchema =
|
|
232
|
+
import { z as z5 } from "zod";
|
|
233
|
+
var tableAlignmentSchema = z5.enum(["left", "center", "right"], {
|
|
231
234
|
description: "Cell alignment"
|
|
232
235
|
});
|
|
233
|
-
var tableColumnObjectSchema =
|
|
234
|
-
key:
|
|
235
|
-
label:
|
|
236
|
+
var tableColumnObjectSchema = z5.object({
|
|
237
|
+
key: z5.string(),
|
|
238
|
+
label: z5.string().optional(),
|
|
236
239
|
align: tableAlignmentSchema.optional()
|
|
237
240
|
});
|
|
238
|
-
var tableRowObjectSchema =
|
|
241
|
+
var tableRowObjectSchema = z5.record(tableCellValueSchema, {
|
|
239
242
|
description: "Object row"
|
|
240
243
|
});
|
|
241
|
-
var tableRowPrimitiveSchema =
|
|
244
|
+
var tableRowPrimitiveSchema = z5.array(tableCellValueSchema, {
|
|
242
245
|
description: "Primitive row"
|
|
243
246
|
});
|
|
244
|
-
var tableSharedSchema =
|
|
245
|
-
title:
|
|
247
|
+
var tableSharedSchema = z5.object({
|
|
248
|
+
title: z5.string().optional().describe("Display title for table")
|
|
246
249
|
});
|
|
247
250
|
var tablePrimitiveSchema = tableSharedSchema.merge(
|
|
248
|
-
|
|
251
|
+
z5.object(
|
|
249
252
|
{
|
|
250
|
-
columns:
|
|
251
|
-
rows:
|
|
253
|
+
columns: z5.array(tableAlignmentSchema).optional(),
|
|
254
|
+
rows: z5.array(tableRowPrimitiveSchema)
|
|
252
255
|
},
|
|
253
256
|
{ description: "Table with primitive rows and optional alignment columns" }
|
|
254
257
|
)
|
|
255
258
|
);
|
|
256
259
|
var tableObjectSchema = tableSharedSchema.merge(
|
|
257
|
-
|
|
260
|
+
z5.object(
|
|
258
261
|
{
|
|
259
|
-
columns:
|
|
260
|
-
|
|
261
|
-
|
|
262
|
+
columns: z5.union([
|
|
263
|
+
z5.array(tableAlignmentSchema),
|
|
264
|
+
z5.array(tableColumnObjectSchema)
|
|
262
265
|
]).optional(),
|
|
263
|
-
rows:
|
|
266
|
+
rows: z5.array(tableRowObjectSchema)
|
|
264
267
|
},
|
|
265
268
|
{
|
|
266
269
|
description: "Table with object rows and optional alignment or object columns"
|
|
267
270
|
}
|
|
268
271
|
)
|
|
269
272
|
);
|
|
270
|
-
var tableSchema = (description = "Table information") =>
|
|
273
|
+
var tableSchema = (description = "Table information") => z5.union([tablePrimitiveSchema, tableObjectSchema], { description });
|
|
271
274
|
|
|
272
275
|
// packages/models/src/lib/audit-output.ts
|
|
273
276
|
var auditValueSchema = nonnegativeNumberSchema.describe("Raw numeric value");
|
|
274
|
-
var auditDisplayValueSchema =
|
|
275
|
-
var auditDetailsSchema =
|
|
277
|
+
var auditDisplayValueSchema = z6.string({ description: "Formatted value (e.g. '0.9 s', '2.1 MB')" }).optional();
|
|
278
|
+
var auditDetailsSchema = z6.object(
|
|
276
279
|
{
|
|
277
|
-
issues:
|
|
280
|
+
issues: z6.array(issueSchema, { description: "List of findings" }).optional(),
|
|
278
281
|
table: tableSchema("Table of related findings").optional()
|
|
279
282
|
},
|
|
280
283
|
{ description: "Detailed information" }
|
|
281
284
|
);
|
|
282
|
-
var auditOutputSchema =
|
|
285
|
+
var auditOutputSchema = z6.object(
|
|
283
286
|
{
|
|
284
287
|
slug: slugSchema.describe("Reference to audit"),
|
|
285
288
|
displayValue: auditDisplayValueSchema,
|
|
@@ -289,7 +292,7 @@ var auditOutputSchema = z5.object(
|
|
|
289
292
|
},
|
|
290
293
|
{ description: "Audit information" }
|
|
291
294
|
);
|
|
292
|
-
var auditOutputsSchema =
|
|
295
|
+
var auditOutputsSchema = z6.array(auditOutputSchema, {
|
|
293
296
|
description: "List of JSON formatted audit output emitted by the runner process of a plugin"
|
|
294
297
|
}).refine(
|
|
295
298
|
(audits) => !getDuplicateSlugsInAudits2(audits),
|
|
@@ -306,13 +309,13 @@ function getDuplicateSlugsInAudits2(audits) {
|
|
|
306
309
|
}
|
|
307
310
|
|
|
308
311
|
// packages/models/src/lib/category-config.ts
|
|
309
|
-
import { z as
|
|
312
|
+
import { z as z7 } from "zod";
|
|
310
313
|
var categoryRefSchema = weightedRefSchema(
|
|
311
314
|
"Weighted references to audits and/or groups for the category",
|
|
312
315
|
"Slug of an audit or group (depending on `type`)"
|
|
313
316
|
).merge(
|
|
314
|
-
|
|
315
|
-
type:
|
|
317
|
+
z7.object({
|
|
318
|
+
type: z7.enum(["audit", "group"], {
|
|
316
319
|
description: "Discriminant for reference kind, affects where `slug` is looked up"
|
|
317
320
|
}),
|
|
318
321
|
plugin: slugSchema.describe(
|
|
@@ -333,8 +336,8 @@ var categoryConfigSchema = scorableSchema(
|
|
|
333
336
|
description: "Meta info for category"
|
|
334
337
|
})
|
|
335
338
|
).merge(
|
|
336
|
-
|
|
337
|
-
isBinary:
|
|
339
|
+
z7.object({
|
|
340
|
+
isBinary: z7.boolean({
|
|
338
341
|
description: 'Is this a binary category (i.e. only a perfect score considered a "pass")?'
|
|
339
342
|
}).optional()
|
|
340
343
|
})
|
|
@@ -350,7 +353,7 @@ function getDuplicateRefsInCategoryMetrics(metrics) {
|
|
|
350
353
|
metrics.map(({ slug, type, plugin }) => `${type} :: ${plugin} / ${slug}`)
|
|
351
354
|
);
|
|
352
355
|
}
|
|
353
|
-
var categoriesSchema =
|
|
356
|
+
var categoriesSchema = z7.array(categoryConfigSchema, {
|
|
354
357
|
description: "Categorization of individual audits"
|
|
355
358
|
}).refine(
|
|
356
359
|
(categoryCfg) => !getDuplicateSlugCategories(categoryCfg),
|
|
@@ -369,18 +372,18 @@ function getDuplicateSlugCategories(categories) {
|
|
|
369
372
|
}
|
|
370
373
|
|
|
371
374
|
// packages/models/src/lib/commit.ts
|
|
372
|
-
import { z as
|
|
373
|
-
var commitSchema =
|
|
375
|
+
import { z as z8 } from "zod";
|
|
376
|
+
var commitSchema = z8.object(
|
|
374
377
|
{
|
|
375
|
-
hash:
|
|
378
|
+
hash: z8.string({ description: "Commit SHA (full)" }).regex(
|
|
376
379
|
/^[\da-f]{40}$/,
|
|
377
380
|
"Commit SHA should be a 40-character hexadecimal string"
|
|
378
381
|
),
|
|
379
|
-
message:
|
|
380
|
-
date:
|
|
382
|
+
message: z8.string({ description: "Commit message" }),
|
|
383
|
+
date: z8.coerce.date({
|
|
381
384
|
description: "Date and time when commit was authored"
|
|
382
385
|
}),
|
|
383
|
-
author:
|
|
386
|
+
author: z8.string({
|
|
384
387
|
description: "Commit author name"
|
|
385
388
|
}).trim()
|
|
386
389
|
},
|
|
@@ -388,22 +391,22 @@ var commitSchema = z7.object(
|
|
|
388
391
|
);
|
|
389
392
|
|
|
390
393
|
// packages/models/src/lib/core-config.ts
|
|
391
|
-
import { z as
|
|
394
|
+
import { z as z14 } from "zod";
|
|
392
395
|
|
|
393
396
|
// packages/models/src/lib/persist-config.ts
|
|
394
|
-
import { z as
|
|
395
|
-
var formatSchema =
|
|
396
|
-
var persistConfigSchema =
|
|
397
|
+
import { z as z9 } from "zod";
|
|
398
|
+
var formatSchema = z9.enum(["json", "md"]);
|
|
399
|
+
var persistConfigSchema = z9.object({
|
|
397
400
|
outputDir: filePathSchema.describe("Artifacts folder").optional(),
|
|
398
401
|
filename: fileNameSchema.describe("Artifacts file name (without extension)").optional(),
|
|
399
|
-
format:
|
|
402
|
+
format: z9.array(formatSchema).optional()
|
|
400
403
|
});
|
|
401
404
|
|
|
402
405
|
// packages/models/src/lib/plugin-config.ts
|
|
403
|
-
import { z as
|
|
406
|
+
import { z as z12 } from "zod";
|
|
404
407
|
|
|
405
408
|
// packages/models/src/lib/group.ts
|
|
406
|
-
import { z as
|
|
409
|
+
import { z as z10 } from "zod";
|
|
407
410
|
var groupRefSchema = weightedRefSchema(
|
|
408
411
|
"Weighted reference to a group",
|
|
409
412
|
"Reference slug to a group within this plugin (e.g. 'max-lines')"
|
|
@@ -420,7 +423,7 @@ var groupSchema = scorableSchema(
|
|
|
420
423
|
getDuplicateRefsInGroups,
|
|
421
424
|
duplicateRefsInGroupsErrorMsg
|
|
422
425
|
).merge(groupMetaSchema);
|
|
423
|
-
var groupsSchema =
|
|
426
|
+
var groupsSchema = z10.array(groupSchema, {
|
|
424
427
|
description: "List of groups"
|
|
425
428
|
}).optional().refine(
|
|
426
429
|
(groups2) => !getDuplicateSlugsInGroups(groups2),
|
|
@@ -448,14 +451,14 @@ function getDuplicateSlugsInGroups(groups2) {
|
|
|
448
451
|
}
|
|
449
452
|
|
|
450
453
|
// packages/models/src/lib/runner-config.ts
|
|
451
|
-
import { z as
|
|
452
|
-
var outputTransformSchema =
|
|
453
|
-
var runnerConfigSchema =
|
|
454
|
+
import { z as z11 } from "zod";
|
|
455
|
+
var outputTransformSchema = z11.function().args(z11.unknown()).returns(z11.union([auditOutputsSchema, z11.promise(auditOutputsSchema)]));
|
|
456
|
+
var runnerConfigSchema = z11.object(
|
|
454
457
|
{
|
|
455
|
-
command:
|
|
458
|
+
command: z11.string({
|
|
456
459
|
description: "Shell command to execute"
|
|
457
460
|
}),
|
|
458
|
-
args:
|
|
461
|
+
args: z11.array(z11.string({ description: "Command arguments" })).optional(),
|
|
459
462
|
outputFile: filePathSchema.describe("Output path"),
|
|
460
463
|
outputTransform: outputTransformSchema.optional()
|
|
461
464
|
},
|
|
@@ -463,8 +466,8 @@ var runnerConfigSchema = z10.object(
|
|
|
463
466
|
description: "How to execute runner"
|
|
464
467
|
}
|
|
465
468
|
);
|
|
466
|
-
var onProgressSchema =
|
|
467
|
-
var runnerFunctionSchema =
|
|
469
|
+
var onProgressSchema = z11.function().args(z11.unknown()).returns(z11.void());
|
|
470
|
+
var runnerFunctionSchema = z11.function().args(onProgressSchema.optional()).returns(z11.union([auditOutputsSchema, z11.promise(auditOutputsSchema)]));
|
|
468
471
|
|
|
469
472
|
// packages/models/src/lib/plugin-config.ts
|
|
470
473
|
var pluginMetaSchema = packageVersionSchema().merge(
|
|
@@ -475,13 +478,13 @@ var pluginMetaSchema = packageVersionSchema().merge(
|
|
|
475
478
|
description: "Plugin metadata"
|
|
476
479
|
})
|
|
477
480
|
).merge(
|
|
478
|
-
|
|
481
|
+
z12.object({
|
|
479
482
|
slug: slugSchema.describe("Unique plugin slug within core config"),
|
|
480
483
|
icon: materialIconSchema
|
|
481
484
|
})
|
|
482
485
|
);
|
|
483
|
-
var pluginDataSchema =
|
|
484
|
-
runner:
|
|
486
|
+
var pluginDataSchema = z12.object({
|
|
487
|
+
runner: z12.union([runnerConfigSchema, runnerFunctionSchema]),
|
|
485
488
|
audits: pluginAuditsSchema,
|
|
486
489
|
groups: groupsSchema
|
|
487
490
|
});
|
|
@@ -507,22 +510,22 @@ function getMissingRefsFromGroups(pluginCfg) {
|
|
|
507
510
|
}
|
|
508
511
|
|
|
509
512
|
// packages/models/src/lib/upload-config.ts
|
|
510
|
-
import { z as
|
|
511
|
-
var uploadConfigSchema =
|
|
513
|
+
import { z as z13 } from "zod";
|
|
514
|
+
var uploadConfigSchema = z13.object({
|
|
512
515
|
server: urlSchema.describe("URL of deployed portal API"),
|
|
513
|
-
apiKey:
|
|
516
|
+
apiKey: z13.string({
|
|
514
517
|
description: "API key with write access to portal (use `process.env` for security)"
|
|
515
518
|
}),
|
|
516
519
|
organization: slugSchema.describe(
|
|
517
520
|
"Organization slug from Code PushUp portal"
|
|
518
521
|
),
|
|
519
522
|
project: slugSchema.describe("Project slug from Code PushUp portal"),
|
|
520
|
-
timeout:
|
|
523
|
+
timeout: z13.number({ description: "Request timeout in minutes (default is 5)" }).positive().int().optional()
|
|
521
524
|
});
|
|
522
525
|
|
|
523
526
|
// packages/models/src/lib/core-config.ts
|
|
524
|
-
var unrefinedCoreConfigSchema =
|
|
525
|
-
plugins:
|
|
527
|
+
var unrefinedCoreConfigSchema = z14.object({
|
|
528
|
+
plugins: z14.array(pluginConfigSchema, {
|
|
526
529
|
description: "List of plugins to be used (official, community-provided, or custom)"
|
|
527
530
|
}).min(1),
|
|
528
531
|
/** portal configuration for persisting results */
|
|
@@ -554,7 +557,7 @@ var DEFAULT_PERSIST_FILENAME = "report";
|
|
|
554
557
|
var DEFAULT_PERSIST_FORMAT = ["json", "md"];
|
|
555
558
|
|
|
556
559
|
// packages/models/src/lib/report.ts
|
|
557
|
-
import { z as
|
|
560
|
+
import { z as z15 } from "zod";
|
|
558
561
|
var auditReportSchema = auditSchema.merge(auditOutputSchema);
|
|
559
562
|
var pluginReportSchema = pluginMetaSchema.merge(
|
|
560
563
|
executionMetaSchema({
|
|
@@ -562,9 +565,9 @@ var pluginReportSchema = pluginMetaSchema.merge(
|
|
|
562
565
|
descriptionDuration: "Duration of the plugin run in ms"
|
|
563
566
|
})
|
|
564
567
|
).merge(
|
|
565
|
-
|
|
566
|
-
audits:
|
|
567
|
-
groups:
|
|
568
|
+
z15.object({
|
|
569
|
+
audits: z15.array(auditReportSchema).min(1),
|
|
570
|
+
groups: z15.array(groupSchema).optional()
|
|
568
571
|
})
|
|
569
572
|
).refine(
|
|
570
573
|
(pluginReport) => !getMissingRefsFromGroups2(pluginReport.audits, pluginReport.groups ?? []),
|
|
@@ -598,10 +601,10 @@ var reportSchema = packageVersionSchema({
|
|
|
598
601
|
descriptionDuration: "Duration of the collect run in ms"
|
|
599
602
|
})
|
|
600
603
|
).merge(
|
|
601
|
-
|
|
604
|
+
z15.object(
|
|
602
605
|
{
|
|
603
|
-
categories:
|
|
604
|
-
plugins:
|
|
606
|
+
categories: z15.array(categoryConfigSchema),
|
|
607
|
+
plugins: z15.array(pluginReportSchema).min(1),
|
|
605
608
|
commit: commitSchema.describe("Git commit for which report was collected").nullable()
|
|
606
609
|
},
|
|
607
610
|
{ description: "Collect output data" }
|
|
@@ -617,40 +620,40 @@ var reportSchema = packageVersionSchema({
|
|
|
617
620
|
);
|
|
618
621
|
|
|
619
622
|
// packages/models/src/lib/reports-diff.ts
|
|
620
|
-
import { z as
|
|
623
|
+
import { z as z16 } from "zod";
|
|
621
624
|
function makeComparisonSchema(schema) {
|
|
622
625
|
const sharedDescription = schema.description || "Result";
|
|
623
|
-
return
|
|
626
|
+
return z16.object({
|
|
624
627
|
before: schema.describe(`${sharedDescription} (source commit)`),
|
|
625
628
|
after: schema.describe(`${sharedDescription} (target commit)`)
|
|
626
629
|
});
|
|
627
630
|
}
|
|
628
631
|
function makeArraysComparisonSchema(diffSchema, resultSchema, description) {
|
|
629
|
-
return
|
|
632
|
+
return z16.object(
|
|
630
633
|
{
|
|
631
|
-
changed:
|
|
632
|
-
unchanged:
|
|
633
|
-
added:
|
|
634
|
-
removed:
|
|
634
|
+
changed: z16.array(diffSchema),
|
|
635
|
+
unchanged: z16.array(resultSchema),
|
|
636
|
+
added: z16.array(resultSchema),
|
|
637
|
+
removed: z16.array(resultSchema)
|
|
635
638
|
},
|
|
636
639
|
{ description }
|
|
637
640
|
);
|
|
638
641
|
}
|
|
639
|
-
var scorableMetaSchema =
|
|
642
|
+
var scorableMetaSchema = z16.object({
|
|
640
643
|
slug: slugSchema,
|
|
641
644
|
title: titleSchema,
|
|
642
645
|
docsUrl: docsUrlSchema
|
|
643
646
|
});
|
|
644
647
|
var scorableWithPluginMetaSchema = scorableMetaSchema.merge(
|
|
645
|
-
|
|
648
|
+
z16.object({
|
|
646
649
|
plugin: pluginMetaSchema.pick({ slug: true, title: true, docsUrl: true }).describe("Plugin which defines it")
|
|
647
650
|
})
|
|
648
651
|
);
|
|
649
652
|
var scorableDiffSchema = scorableMetaSchema.merge(
|
|
650
|
-
|
|
653
|
+
z16.object({
|
|
651
654
|
scores: makeComparisonSchema(scoreSchema).merge(
|
|
652
|
-
|
|
653
|
-
diff:
|
|
655
|
+
z16.object({
|
|
656
|
+
diff: z16.number().min(-1).max(1).describe("Score change (`scores.after - scores.before`)")
|
|
654
657
|
})
|
|
655
658
|
).describe("Score comparison")
|
|
656
659
|
})
|
|
@@ -661,10 +664,10 @@ var scorableWithPluginDiffSchema = scorableDiffSchema.merge(
|
|
|
661
664
|
var categoryDiffSchema = scorableDiffSchema;
|
|
662
665
|
var groupDiffSchema = scorableWithPluginDiffSchema;
|
|
663
666
|
var auditDiffSchema = scorableWithPluginDiffSchema.merge(
|
|
664
|
-
|
|
667
|
+
z16.object({
|
|
665
668
|
values: makeComparisonSchema(auditValueSchema).merge(
|
|
666
|
-
|
|
667
|
-
diff:
|
|
669
|
+
z16.object({
|
|
670
|
+
diff: z16.number().int().describe("Value change (`values.after - values.before`)")
|
|
668
671
|
})
|
|
669
672
|
).describe("Audit `value` comparison"),
|
|
670
673
|
displayValues: makeComparisonSchema(auditDisplayValueSchema).describe(
|
|
@@ -673,16 +676,18 @@ var auditDiffSchema = scorableWithPluginDiffSchema.merge(
|
|
|
673
676
|
})
|
|
674
677
|
);
|
|
675
678
|
var categoryResultSchema = scorableMetaSchema.merge(
|
|
676
|
-
|
|
679
|
+
z16.object({ score: scoreSchema })
|
|
677
680
|
);
|
|
678
681
|
var groupResultSchema = scorableWithPluginMetaSchema.merge(
|
|
679
|
-
|
|
682
|
+
z16.object({ score: scoreSchema })
|
|
680
683
|
);
|
|
681
684
|
var auditResultSchema = scorableWithPluginMetaSchema.merge(
|
|
682
685
|
auditOutputSchema.pick({ score: true, value: true, displayValue: true })
|
|
683
686
|
);
|
|
684
|
-
var reportsDiffSchema =
|
|
687
|
+
var reportsDiffSchema = z16.object({
|
|
685
688
|
commits: makeComparisonSchema(commitSchema).nullable().describe("Commits identifying compared reports"),
|
|
689
|
+
portalUrl: urlSchema.optional().describe("Link to comparison page in Code PushUp portal"),
|
|
690
|
+
label: z16.string().optional().describe("Label (e.g. project name)"),
|
|
686
691
|
categories: makeArraysComparisonSchema(
|
|
687
692
|
categoryDiffSchema,
|
|
688
693
|
categoryResultSchema,
|
|
@@ -752,8 +757,24 @@ function comparePairs(pairs, equalsFn) {
|
|
|
752
757
|
);
|
|
753
758
|
}
|
|
754
759
|
|
|
760
|
+
// packages/utils/src/lib/errors.ts
|
|
761
|
+
function stringifyError(error) {
|
|
762
|
+
if (error instanceof Error) {
|
|
763
|
+
if (error.name === "Error" || error.message.startsWith(error.name)) {
|
|
764
|
+
return error.message;
|
|
765
|
+
}
|
|
766
|
+
return `${error.name}: ${error.message}`;
|
|
767
|
+
}
|
|
768
|
+
if (typeof error === "string") {
|
|
769
|
+
return error;
|
|
770
|
+
}
|
|
771
|
+
return JSON.stringify(error);
|
|
772
|
+
}
|
|
773
|
+
|
|
755
774
|
// packages/utils/src/lib/execute-process.ts
|
|
756
|
-
import {
|
|
775
|
+
import {
|
|
776
|
+
spawn
|
|
777
|
+
} from "node:child_process";
|
|
757
778
|
|
|
758
779
|
// packages/utils/src/lib/reports/utils.ts
|
|
759
780
|
import ansis from "ansis";
|
|
@@ -839,9 +860,17 @@ function severityMarker(severity) {
|
|
|
839
860
|
}
|
|
840
861
|
return "\u2139\uFE0F";
|
|
841
862
|
}
|
|
863
|
+
var MIN_NON_ZERO_RESULT = 0.1;
|
|
864
|
+
function roundValue(value) {
|
|
865
|
+
const roundedValue = Math.round(value * 10) / 10;
|
|
866
|
+
if (roundedValue === 0 && value !== 0) {
|
|
867
|
+
return MIN_NON_ZERO_RESULT * Math.sign(value);
|
|
868
|
+
}
|
|
869
|
+
return roundedValue;
|
|
870
|
+
}
|
|
842
871
|
function formatScoreChange(diff) {
|
|
843
872
|
const marker = getDiffMarker(diff);
|
|
844
|
-
const text = formatDiffNumber(
|
|
873
|
+
const text = formatDiffNumber(roundValue(diff * 100));
|
|
845
874
|
return colorByScoreDiff(`${marker} ${text}`, diff);
|
|
846
875
|
}
|
|
847
876
|
function formatValueChange({
|
|
@@ -849,7 +878,7 @@ function formatValueChange({
|
|
|
849
878
|
scores
|
|
850
879
|
}) {
|
|
851
880
|
const marker = getDiffMarker(values.diff);
|
|
852
|
-
const percentage = values.before === 0 ? values.diff > 0 ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY :
|
|
881
|
+
const percentage = values.before === 0 ? values.diff > 0 ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY : roundValue(values.diff / values.before * 100);
|
|
853
882
|
const text = `${formatDiffNumber(percentage)}\u2009%`;
|
|
854
883
|
return colorByScoreDiff(`${marker} ${text}`, scores.diff);
|
|
855
884
|
}
|
|
@@ -880,12 +909,12 @@ function countCategoryAudits(refs, plugins) {
|
|
|
880
909
|
}, 0);
|
|
881
910
|
}
|
|
882
911
|
function compareCategoryAuditsAndGroups(a, b) {
|
|
883
|
-
if (a.weight !== b.weight) {
|
|
884
|
-
return b.weight - a.weight;
|
|
885
|
-
}
|
|
886
912
|
if (a.score !== b.score) {
|
|
887
913
|
return a.score - b.score;
|
|
888
914
|
}
|
|
915
|
+
if (a.weight !== b.weight) {
|
|
916
|
+
return b.weight - a.weight;
|
|
917
|
+
}
|
|
889
918
|
if ("value" in a && "value" in b && a.value !== b.value) {
|
|
890
919
|
return b.value - a.value;
|
|
891
920
|
}
|
|
@@ -977,25 +1006,29 @@ var ProcessError = class extends Error {
|
|
|
977
1006
|
}
|
|
978
1007
|
};
|
|
979
1008
|
function executeProcess(cfg) {
|
|
980
|
-
const {
|
|
981
|
-
const { onStdout, onError, onComplete } = observer ?? {};
|
|
1009
|
+
const { command: command2, args, observer, ignoreExitCode = false, ...options2 } = cfg;
|
|
1010
|
+
const { onStdout, onStderr, onError, onComplete } = observer ?? {};
|
|
982
1011
|
const date = (/* @__PURE__ */ new Date()).toISOString();
|
|
983
1012
|
const start = performance.now();
|
|
984
1013
|
return new Promise((resolve, reject) => {
|
|
985
|
-
const
|
|
1014
|
+
const spawnedProcess = spawn(command2, args ?? [], {
|
|
1015
|
+
shell: true,
|
|
1016
|
+
...options2
|
|
1017
|
+
});
|
|
986
1018
|
let stdout = "";
|
|
987
1019
|
let stderr = "";
|
|
988
|
-
|
|
1020
|
+
spawnedProcess.stdout.on("data", (data) => {
|
|
989
1021
|
stdout += String(data);
|
|
990
|
-
onStdout?.(String(data));
|
|
1022
|
+
onStdout?.(String(data), spawnedProcess);
|
|
991
1023
|
});
|
|
992
|
-
|
|
1024
|
+
spawnedProcess.stderr.on("data", (data) => {
|
|
993
1025
|
stderr += String(data);
|
|
1026
|
+
onStderr?.(String(data), spawnedProcess);
|
|
994
1027
|
});
|
|
995
|
-
|
|
1028
|
+
spawnedProcess.on("error", (err) => {
|
|
996
1029
|
stderr += err.toString();
|
|
997
1030
|
});
|
|
998
|
-
|
|
1031
|
+
spawnedProcess.on("close", (code2) => {
|
|
999
1032
|
const timings = { date, duration: calcDuration(start) };
|
|
1000
1033
|
if (code2 === 0 || ignoreExitCode) {
|
|
1001
1034
|
onComplete?.();
|
|
@@ -1569,7 +1602,33 @@ function getColumnAlignments(tableData) {
|
|
|
1569
1602
|
}
|
|
1570
1603
|
|
|
1571
1604
|
// packages/utils/src/lib/reports/formatting.ts
|
|
1572
|
-
import {
|
|
1605
|
+
import {
|
|
1606
|
+
MarkdownDocument,
|
|
1607
|
+
md as md2
|
|
1608
|
+
} from "build-md";
|
|
1609
|
+
import { posix as pathPosix } from "node:path";
|
|
1610
|
+
|
|
1611
|
+
// packages/utils/src/lib/reports/ide-environment.ts
|
|
1612
|
+
function getEnvironmentType() {
|
|
1613
|
+
if (isVSCode()) {
|
|
1614
|
+
return "vscode";
|
|
1615
|
+
}
|
|
1616
|
+
if (isGitHub()) {
|
|
1617
|
+
return "github";
|
|
1618
|
+
}
|
|
1619
|
+
return "other";
|
|
1620
|
+
}
|
|
1621
|
+
function isVSCode() {
|
|
1622
|
+
return process.env["TERM_PROGRAM"] === "vscode";
|
|
1623
|
+
}
|
|
1624
|
+
function isGitHub() {
|
|
1625
|
+
return process.env["GITHUB_ACTIONS"] === "true";
|
|
1626
|
+
}
|
|
1627
|
+
function getGitHubBaseUrl() {
|
|
1628
|
+
return `${process.env["GITHUB_SERVER_URL"]}/${process.env["GITHUB_REPOSITORY"]}/blob/${process.env["GITHUB_SHA"]}`;
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
// packages/utils/src/lib/reports/formatting.ts
|
|
1573
1632
|
function tableSection(tableData, options2) {
|
|
1574
1633
|
if (tableData.rows.length === 0) {
|
|
1575
1634
|
return null;
|
|
@@ -1607,6 +1666,44 @@ function metaDescription(audit) {
|
|
|
1607
1666
|
}
|
|
1608
1667
|
return "";
|
|
1609
1668
|
}
|
|
1669
|
+
function linkToLocalSourceForIde(source, options2) {
|
|
1670
|
+
const { file, position } = source;
|
|
1671
|
+
const { outputDir } = options2 ?? {};
|
|
1672
|
+
if (!outputDir) {
|
|
1673
|
+
return md2.code(file);
|
|
1674
|
+
}
|
|
1675
|
+
return md2.link(formatFileLink(file, position, outputDir), md2.code(file));
|
|
1676
|
+
}
|
|
1677
|
+
function formatSourceLine(position) {
|
|
1678
|
+
if (!position) {
|
|
1679
|
+
return "";
|
|
1680
|
+
}
|
|
1681
|
+
const { startLine, endLine } = position;
|
|
1682
|
+
return endLine && startLine !== endLine ? `${startLine}-${endLine}` : `${startLine}`;
|
|
1683
|
+
}
|
|
1684
|
+
function formatGitHubLink(file, position) {
|
|
1685
|
+
const baseUrl = getGitHubBaseUrl();
|
|
1686
|
+
if (!position) {
|
|
1687
|
+
return `${baseUrl}/${file}`;
|
|
1688
|
+
}
|
|
1689
|
+
const { startLine, endLine, startColumn, endColumn } = position;
|
|
1690
|
+
const start = startColumn ? `L${startLine}C${startColumn}` : `L${startLine}`;
|
|
1691
|
+
const end = endLine ? endColumn ? `L${endLine}C${endColumn}` : `L${endLine}` : "";
|
|
1692
|
+
const lineRange = end && start !== end ? `${start}-${end}` : start;
|
|
1693
|
+
return `${baseUrl}/${file}#${lineRange}`;
|
|
1694
|
+
}
|
|
1695
|
+
function formatFileLink(file, position, outputDir) {
|
|
1696
|
+
const relativePath = pathPosix.relative(outputDir, file);
|
|
1697
|
+
const env = getEnvironmentType();
|
|
1698
|
+
switch (env) {
|
|
1699
|
+
case "vscode":
|
|
1700
|
+
return position ? `${relativePath}#L${position.startLine}` : relativePath;
|
|
1701
|
+
case "github":
|
|
1702
|
+
return formatGitHubLink(file, position);
|
|
1703
|
+
default:
|
|
1704
|
+
return relativePath;
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1610
1707
|
|
|
1611
1708
|
// packages/utils/src/lib/reports/generate-md-report-categoy-section.ts
|
|
1612
1709
|
import { MarkdownDocument as MarkdownDocument2, md as md3 } from "build-md";
|
|
@@ -1808,16 +1905,16 @@ function auditDetailsAuditValue({
|
|
|
1808
1905
|
String(displayValue ?? value)
|
|
1809
1906
|
)} (score: ${formatReportScore(score)})`;
|
|
1810
1907
|
}
|
|
1811
|
-
function generateMdReport(report) {
|
|
1908
|
+
function generateMdReport(report, options2) {
|
|
1812
1909
|
return new MarkdownDocument3().heading(HIERARCHY.level_1, REPORT_HEADLINE_TEXT).$if(
|
|
1813
1910
|
report.categories.length > 0,
|
|
1814
1911
|
(doc) => doc.$concat(
|
|
1815
1912
|
categoriesOverviewSection(report),
|
|
1816
1913
|
categoriesDetailsSection(report)
|
|
1817
1914
|
)
|
|
1818
|
-
).$concat(auditsSection(report), aboutSection(report)).rule().paragraph(md4`${FOOTER_PREFIX} ${md4.link(README_LINK, "Code PushUp")}`).toString();
|
|
1915
|
+
).$concat(auditsSection(report, options2), aboutSection(report)).rule().paragraph(md4`${FOOTER_PREFIX} ${md4.link(README_LINK, "Code PushUp")}`).toString();
|
|
1819
1916
|
}
|
|
1820
|
-
function auditDetailsIssues(issues = []) {
|
|
1917
|
+
function auditDetailsIssues(issues = [], options2) {
|
|
1821
1918
|
if (issues.length === 0) {
|
|
1822
1919
|
return null;
|
|
1823
1920
|
}
|
|
@@ -1833,39 +1930,36 @@ function auditDetailsIssues(issues = []) {
|
|
|
1833
1930
|
if (!source) {
|
|
1834
1931
|
return [severity, message];
|
|
1835
1932
|
}
|
|
1836
|
-
const file =
|
|
1933
|
+
const file = linkToLocalSourceForIde(source, options2);
|
|
1837
1934
|
if (!source.position) {
|
|
1838
1935
|
return [severity, message, file];
|
|
1839
1936
|
}
|
|
1840
|
-
const
|
|
1841
|
-
const line = `${startLine || ""}${endLine && startLine !== endLine ? `-${endLine}` : ""}`;
|
|
1937
|
+
const line = formatSourceLine(source.position);
|
|
1842
1938
|
return [severity, message, file, line];
|
|
1843
1939
|
})
|
|
1844
1940
|
);
|
|
1845
1941
|
}
|
|
1846
|
-
function auditDetails(audit) {
|
|
1942
|
+
function auditDetails(audit, options2) {
|
|
1847
1943
|
const { table: table2, issues = [] } = audit.details ?? {};
|
|
1848
1944
|
const detailsValue = auditDetailsAuditValue(audit);
|
|
1849
1945
|
if (issues.length === 0 && !table2?.rows.length) {
|
|
1850
1946
|
return new MarkdownDocument3().paragraph(detailsValue);
|
|
1851
1947
|
}
|
|
1852
1948
|
const tableSectionContent = table2 && tableSection(table2);
|
|
1853
|
-
const issuesSectionContent = issues.length > 0 && auditDetailsIssues(issues);
|
|
1949
|
+
const issuesSectionContent = issues.length > 0 && auditDetailsIssues(issues, options2);
|
|
1854
1950
|
return new MarkdownDocument3().details(
|
|
1855
1951
|
detailsValue,
|
|
1856
1952
|
new MarkdownDocument3().$concat(tableSectionContent, issuesSectionContent)
|
|
1857
1953
|
);
|
|
1858
1954
|
}
|
|
1859
|
-
function auditsSection({
|
|
1860
|
-
plugins
|
|
1861
|
-
}) {
|
|
1955
|
+
function auditsSection({ plugins }, options2) {
|
|
1862
1956
|
return new MarkdownDocument3().heading(HIERARCHY.level_2, "\u{1F6E1}\uFE0F Audits").$foreach(
|
|
1863
1957
|
plugins.flatMap(
|
|
1864
1958
|
(plugin) => plugin.audits.map((audit) => ({ ...audit, plugin }))
|
|
1865
1959
|
),
|
|
1866
1960
|
(doc, { plugin, ...audit }) => {
|
|
1867
1961
|
const auditTitle = `${audit.title} (${plugin.title})`;
|
|
1868
|
-
const detailsContent = auditDetails(audit);
|
|
1962
|
+
const detailsContent = auditDetails(audit, options2);
|
|
1869
1963
|
const descriptionContent = metaDescription(audit);
|
|
1870
1964
|
return doc.heading(HIERARCHY.level_3, auditTitle).$concat(detailsContent).paragraph(descriptionContent);
|
|
1871
1965
|
}
|
|
@@ -1890,17 +1984,17 @@ function pluginMetaTable({
|
|
|
1890
1984
|
{ heading: "Version", alignment: "center" },
|
|
1891
1985
|
{ heading: "Duration", alignment: "right" }
|
|
1892
1986
|
],
|
|
1893
|
-
plugins.map(({ title, audits, version:
|
|
1987
|
+
plugins.map(({ title, audits, version: version3 = "", duration }) => [
|
|
1894
1988
|
title,
|
|
1895
1989
|
audits.length.toString(),
|
|
1896
|
-
|
|
1990
|
+
version3 && md4.code(version3),
|
|
1897
1991
|
formatDuration(duration)
|
|
1898
1992
|
])
|
|
1899
1993
|
];
|
|
1900
1994
|
}
|
|
1901
1995
|
function reportMetaTable({
|
|
1902
1996
|
commit,
|
|
1903
|
-
version:
|
|
1997
|
+
version: version3,
|
|
1904
1998
|
duration,
|
|
1905
1999
|
plugins,
|
|
1906
2000
|
categories
|
|
@@ -1917,7 +2011,7 @@ function reportMetaTable({
|
|
|
1917
2011
|
[
|
|
1918
2012
|
[
|
|
1919
2013
|
commit ? `${commit.message} (${commit.hash})` : "N/A",
|
|
1920
|
-
md4.code(
|
|
2014
|
+
md4.code(version3),
|
|
1921
2015
|
formatDuration(duration),
|
|
1922
2016
|
plugins.length.toString(),
|
|
1923
2017
|
categories.length.toString(),
|
|
@@ -1929,19 +2023,111 @@ function reportMetaTable({
|
|
|
1929
2023
|
|
|
1930
2024
|
// packages/utils/src/lib/reports/generate-md-reports-diff.ts
|
|
1931
2025
|
import {
|
|
1932
|
-
MarkdownDocument as
|
|
1933
|
-
md as
|
|
2026
|
+
MarkdownDocument as MarkdownDocument5,
|
|
2027
|
+
md as md6
|
|
1934
2028
|
} from "build-md";
|
|
2029
|
+
|
|
2030
|
+
// packages/utils/src/lib/reports/generate-md-reports-diff-utils.ts
|
|
2031
|
+
import { MarkdownDocument as MarkdownDocument4, md as md5 } from "build-md";
|
|
1935
2032
|
var MAX_ROWS = 100;
|
|
1936
|
-
function
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
).
|
|
2033
|
+
function summarizeUnchanged(token, { changed, unchanged }) {
|
|
2034
|
+
const pluralizedCount = changed.length > 0 ? pluralizeToken(`other ${token}`, unchanged.length) : `All of ${pluralizeToken(token, unchanged.length)}`;
|
|
2035
|
+
const pluralizedVerb = unchanged.length === 1 ? "is" : "are";
|
|
2036
|
+
return `${pluralizedCount} ${pluralizedVerb} unchanged.`;
|
|
2037
|
+
}
|
|
2038
|
+
function summarizeDiffOutcomes(outcomes, token) {
|
|
2039
|
+
return objectToEntries(countDiffOutcomes(outcomes)).filter(
|
|
2040
|
+
(entry) => entry[0] !== "unchanged" && entry[1] > 0
|
|
2041
|
+
).map(([outcome, count]) => {
|
|
2042
|
+
const formattedCount = `<strong>${count}</strong> ${pluralize(
|
|
2043
|
+
token,
|
|
2044
|
+
count
|
|
2045
|
+
)}`;
|
|
2046
|
+
switch (outcome) {
|
|
2047
|
+
case "positive":
|
|
2048
|
+
return `\u{1F44D} ${formattedCount} improved`;
|
|
2049
|
+
case "negative":
|
|
2050
|
+
return `\u{1F44E} ${formattedCount} regressed`;
|
|
2051
|
+
case "mixed":
|
|
2052
|
+
return `${formattedCount} changed without impacting score`;
|
|
2053
|
+
}
|
|
2054
|
+
}).join(", ");
|
|
2055
|
+
}
|
|
2056
|
+
function createGroupsOrAuditsDetails(token, { changed, unchanged }, ...[columns, rows]) {
|
|
2057
|
+
if (changed.length === 0) {
|
|
2058
|
+
return new MarkdownDocument4().paragraph(
|
|
2059
|
+
summarizeUnchanged(token, { changed, unchanged })
|
|
2060
|
+
);
|
|
2061
|
+
}
|
|
2062
|
+
return new MarkdownDocument4().table(columns, rows.slice(0, MAX_ROWS)).paragraph(
|
|
2063
|
+
changed.length > MAX_ROWS && md5.italic(
|
|
2064
|
+
`Only the ${MAX_ROWS} most affected ${pluralize(
|
|
2065
|
+
token
|
|
2066
|
+
)} are listed above for brevity.`
|
|
2067
|
+
)
|
|
2068
|
+
).paragraph(
|
|
2069
|
+
unchanged.length > 0 && summarizeUnchanged(token, { changed, unchanged })
|
|
2070
|
+
);
|
|
2071
|
+
}
|
|
2072
|
+
function formatTitle({
|
|
2073
|
+
title,
|
|
2074
|
+
docsUrl
|
|
2075
|
+
}) {
|
|
2076
|
+
if (docsUrl) {
|
|
2077
|
+
return md5.link(docsUrl, title);
|
|
2078
|
+
}
|
|
2079
|
+
return title;
|
|
2080
|
+
}
|
|
2081
|
+
function formatPortalLink(portalUrl) {
|
|
2082
|
+
return portalUrl && md5.link(portalUrl, "\u{1F575}\uFE0F See full comparison in Code PushUp portal \u{1F50D}");
|
|
2083
|
+
}
|
|
2084
|
+
function sortChanges(changes) {
|
|
2085
|
+
return [...changes].sort(
|
|
2086
|
+
(a, b) => Math.abs(b.scores.diff) - Math.abs(a.scores.diff) || Math.abs(b.values?.diff ?? 0) - Math.abs(a.values?.diff ?? 0)
|
|
2087
|
+
);
|
|
2088
|
+
}
|
|
2089
|
+
function getDiffChanges(diff) {
|
|
2090
|
+
return [
|
|
2091
|
+
...diff.categories.changed,
|
|
2092
|
+
...diff.groups.changed,
|
|
2093
|
+
...diff.audits.changed
|
|
2094
|
+
];
|
|
2095
|
+
}
|
|
2096
|
+
function changesToDiffOutcomes(changes) {
|
|
2097
|
+
return changes.map((change) => {
|
|
2098
|
+
if (change.scores.diff > 0) {
|
|
2099
|
+
return "positive";
|
|
2100
|
+
}
|
|
2101
|
+
if (change.scores.diff < 0) {
|
|
2102
|
+
return "negative";
|
|
2103
|
+
}
|
|
2104
|
+
if (change.values != null && change.values.diff !== 0) {
|
|
2105
|
+
return "mixed";
|
|
2106
|
+
}
|
|
2107
|
+
return "unchanged";
|
|
2108
|
+
});
|
|
1943
2109
|
}
|
|
1944
|
-
function
|
|
2110
|
+
function mergeDiffOutcomes(outcomes) {
|
|
2111
|
+
if (outcomes.every((outcome) => outcome === "unchanged")) {
|
|
2112
|
+
return "unchanged";
|
|
2113
|
+
}
|
|
2114
|
+
if (outcomes.includes("positive") && !outcomes.includes("negative")) {
|
|
2115
|
+
return "positive";
|
|
2116
|
+
}
|
|
2117
|
+
if (outcomes.includes("negative") && !outcomes.includes("positive")) {
|
|
2118
|
+
return "negative";
|
|
2119
|
+
}
|
|
2120
|
+
return "mixed";
|
|
2121
|
+
}
|
|
2122
|
+
function countDiffOutcomes(outcomes) {
|
|
2123
|
+
return {
|
|
2124
|
+
positive: outcomes.filter((outcome) => outcome === "positive").length,
|
|
2125
|
+
negative: outcomes.filter((outcome) => outcome === "negative").length,
|
|
2126
|
+
mixed: outcomes.filter((outcome) => outcome === "mixed").length,
|
|
2127
|
+
unchanged: outcomes.filter((outcome) => outcome === "unchanged").length
|
|
2128
|
+
};
|
|
2129
|
+
}
|
|
2130
|
+
function formatReportOutcome(outcome, commits) {
|
|
1945
2131
|
const outcomeTexts = {
|
|
1946
2132
|
positive: md5`🥳 Code PushUp report has ${md5.bold("improved")}`,
|
|
1947
2133
|
negative: md5`😟 Code PushUp report has ${md5.bold("regressed")}`,
|
|
@@ -1950,36 +2136,91 @@ function createDiffHeaderSection(diff, portalUrl) {
|
|
|
1950
2136
|
)}`,
|
|
1951
2137
|
unchanged: md5`😐 Code PushUp report is ${md5.bold("unchanged")}`
|
|
1952
2138
|
};
|
|
2139
|
+
if (commits) {
|
|
2140
|
+
const commitsText = `compared target commit ${commits.after.hash} with source commit ${commits.before.hash}`;
|
|
2141
|
+
return md5`${outcomeTexts[outcome]} – ${commitsText}.`;
|
|
2142
|
+
}
|
|
2143
|
+
return md5`${outcomeTexts[outcome]}.`;
|
|
2144
|
+
}
|
|
2145
|
+
function compareDiffsBy(type, a, b) {
|
|
2146
|
+
return sumScoreChanges(b[type].changed) - sumScoreChanges(a[type].changed) || sumConfigChanges(b[type]) - sumConfigChanges(a[type]);
|
|
2147
|
+
}
|
|
2148
|
+
function sumScoreChanges(changes) {
|
|
2149
|
+
return changes.reduce(
|
|
2150
|
+
(acc, { scores }) => acc + Math.abs(scores.diff),
|
|
2151
|
+
0
|
|
2152
|
+
);
|
|
2153
|
+
}
|
|
2154
|
+
function sumConfigChanges({
|
|
2155
|
+
added,
|
|
2156
|
+
removed
|
|
2157
|
+
}) {
|
|
2158
|
+
return added.length + removed.length;
|
|
2159
|
+
}
|
|
2160
|
+
|
|
2161
|
+
// packages/utils/src/lib/reports/generate-md-reports-diff.ts
|
|
2162
|
+
function generateMdReportsDiff(diff) {
|
|
2163
|
+
return new MarkdownDocument5().$concat(
|
|
2164
|
+
createDiffHeaderSection(diff),
|
|
2165
|
+
createDiffCategoriesSection(diff),
|
|
2166
|
+
createDiffDetailsSection(diff)
|
|
2167
|
+
).toString();
|
|
2168
|
+
}
|
|
2169
|
+
function generateMdReportsDiffForMonorepo(diffs) {
|
|
2170
|
+
const diffsWithOutcomes = diffs.map((diff) => ({
|
|
2171
|
+
...diff,
|
|
2172
|
+
outcome: mergeDiffOutcomes(changesToDiffOutcomes(getDiffChanges(diff)))
|
|
2173
|
+
})).sort(
|
|
2174
|
+
(a, b) => compareDiffsBy("categories", a, b) || compareDiffsBy("groups", a, b) || compareDiffsBy("audits", a, b) || a.label.localeCompare(b.label)
|
|
2175
|
+
);
|
|
2176
|
+
const unchanged = diffsWithOutcomes.filter(
|
|
2177
|
+
({ outcome }) => outcome === "unchanged"
|
|
2178
|
+
);
|
|
2179
|
+
const changed = diffsWithOutcomes.filter((diff) => !unchanged.includes(diff));
|
|
2180
|
+
return new MarkdownDocument5().$concat(
|
|
2181
|
+
createDiffHeaderSection(diffs),
|
|
2182
|
+
...changed.map(createDiffProjectSection)
|
|
2183
|
+
).$if(
|
|
2184
|
+
unchanged.length > 0,
|
|
2185
|
+
(doc) => doc.rule().paragraph(summarizeUnchanged("project", { unchanged, changed }))
|
|
2186
|
+
).toString();
|
|
2187
|
+
}
|
|
2188
|
+
function createDiffHeaderSection(diff) {
|
|
1953
2189
|
const outcome = mergeDiffOutcomes(
|
|
1954
|
-
changesToDiffOutcomes(
|
|
1955
|
-
...diff.categories.changed,
|
|
1956
|
-
...diff.groups.changed,
|
|
1957
|
-
...diff.audits.changed
|
|
1958
|
-
])
|
|
2190
|
+
changesToDiffOutcomes(toArray(diff).flatMap(getDiffChanges))
|
|
1959
2191
|
);
|
|
1960
|
-
const
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
2192
|
+
const commits = Array.isArray(diff) ? diff[0]?.commits : diff.commits;
|
|
2193
|
+
const portalUrl = Array.isArray(diff) ? void 0 : diff.portalUrl;
|
|
2194
|
+
return new MarkdownDocument5().heading(HIERARCHY.level_1, "Code PushUp").paragraph(formatReportOutcome(outcome, commits)).paragraph(formatPortalLink(portalUrl));
|
|
2195
|
+
}
|
|
2196
|
+
function createDiffProjectSection(diff) {
|
|
2197
|
+
return new MarkdownDocument5().heading(HIERARCHY.level_2, md6`💼 Project ${md6.code(diff.label)}`).paragraph(formatReportOutcome(diff.outcome)).paragraph(formatPortalLink(diff.portalUrl)).$concat(
|
|
2198
|
+
createDiffCategoriesSection(diff, {
|
|
2199
|
+
skipHeading: true,
|
|
2200
|
+
skipUnchanged: true
|
|
2201
|
+
}),
|
|
2202
|
+
createDiffDetailsSection(diff, HIERARCHY.level_3)
|
|
1965
2203
|
);
|
|
1966
2204
|
}
|
|
1967
|
-
function createDiffCategoriesSection(diff) {
|
|
2205
|
+
function createDiffCategoriesSection(diff, options2) {
|
|
1968
2206
|
const { changed, unchanged, added } = diff.categories;
|
|
2207
|
+
const { skipHeading, skipUnchanged } = options2 ?? {};
|
|
1969
2208
|
const categoriesCount = changed.length + unchanged.length + added.length;
|
|
1970
2209
|
const hasChanges = unchanged.length < categoriesCount;
|
|
1971
2210
|
if (categoriesCount === 0) {
|
|
1972
2211
|
return null;
|
|
1973
2212
|
}
|
|
1974
|
-
const columns =
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
}
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
2213
|
+
const [columns, rows] = createCategoriesTable(diff, {
|
|
2214
|
+
hasChanges,
|
|
2215
|
+
skipUnchanged
|
|
2216
|
+
});
|
|
2217
|
+
return new MarkdownDocument5().heading(HIERARCHY.level_2, !skipHeading && "\u{1F3F7}\uFE0F Categories").table(columns, rows).paragraph(added.length > 0 && md6.italic("(\\*) New category.")).paragraph(
|
|
2218
|
+
skipUnchanged && unchanged.length > 0 && summarizeUnchanged("category", { changed, unchanged })
|
|
2219
|
+
);
|
|
2220
|
+
}
|
|
2221
|
+
function createCategoriesTable(diff, options2) {
|
|
2222
|
+
const { changed, unchanged, added } = diff.categories;
|
|
2223
|
+
const { hasChanges, skipUnchanged } = options2;
|
|
1983
2224
|
const rows = [
|
|
1984
2225
|
...sortChanges(changed).map((category) => [
|
|
1985
2226
|
formatTitle(category),
|
|
@@ -1991,27 +2232,55 @@ function createDiffCategoriesSection(diff) {
|
|
|
1991
2232
|
]),
|
|
1992
2233
|
...added.map((category) => [
|
|
1993
2234
|
formatTitle(category),
|
|
1994
|
-
|
|
2235
|
+
md6.italic("n/a (\\*)"),
|
|
1995
2236
|
formatScoreWithColor(category.score),
|
|
1996
|
-
|
|
2237
|
+
md6.italic("n/a (\\*)")
|
|
1997
2238
|
]),
|
|
1998
|
-
...unchanged.map((category) => [
|
|
2239
|
+
...skipUnchanged ? [] : unchanged.map((category) => [
|
|
1999
2240
|
formatTitle(category),
|
|
2000
2241
|
formatScoreWithColor(category.score, { skipBold: true }),
|
|
2001
2242
|
formatScoreWithColor(category.score),
|
|
2002
2243
|
"\u2013"
|
|
2003
2244
|
])
|
|
2004
2245
|
];
|
|
2005
|
-
|
|
2246
|
+
if (rows.length === 0) {
|
|
2247
|
+
return [[], []];
|
|
2248
|
+
}
|
|
2249
|
+
const columns = [
|
|
2250
|
+
{ heading: "\u{1F3F7}\uFE0F Category", alignment: "left" },
|
|
2251
|
+
{
|
|
2252
|
+
heading: hasChanges ? "\u2B50 Previous score" : "\u2B50 Score",
|
|
2253
|
+
alignment: "center"
|
|
2254
|
+
},
|
|
2255
|
+
{ heading: "\u2B50 Current score", alignment: "center" },
|
|
2256
|
+
{ heading: "\u{1F504} Score change", alignment: "center" }
|
|
2257
|
+
];
|
|
2258
|
+
return [
|
|
2006
2259
|
hasChanges ? columns : columns.slice(0, 2),
|
|
2007
2260
|
rows.map((row) => hasChanges ? row : row.slice(0, 2))
|
|
2008
|
-
|
|
2261
|
+
];
|
|
2262
|
+
}
|
|
2263
|
+
function createDiffDetailsSection(diff, level = HIERARCHY.level_2) {
|
|
2264
|
+
if (diff.groups.changed.length + diff.audits.changed.length === 0) {
|
|
2265
|
+
return null;
|
|
2266
|
+
}
|
|
2267
|
+
const summary = ["group", "audit"].map(
|
|
2268
|
+
(token) => summarizeDiffOutcomes(
|
|
2269
|
+
changesToDiffOutcomes(diff[`${token}s`].changed),
|
|
2270
|
+
token
|
|
2271
|
+
)
|
|
2272
|
+
).filter(Boolean).join(", ");
|
|
2273
|
+
const details2 = new MarkdownDocument5().$concat(
|
|
2274
|
+
createDiffGroupsSection(diff, level),
|
|
2275
|
+
createDiffAuditsSection(diff, level)
|
|
2276
|
+
);
|
|
2277
|
+
return new MarkdownDocument5().details(summary, details2);
|
|
2009
2278
|
}
|
|
2010
|
-
function createDiffGroupsSection(diff) {
|
|
2279
|
+
function createDiffGroupsSection(diff, level) {
|
|
2011
2280
|
if (diff.groups.changed.length + diff.groups.unchanged.length === 0) {
|
|
2012
2281
|
return null;
|
|
2013
2282
|
}
|
|
2014
|
-
return new
|
|
2283
|
+
return new MarkdownDocument5().heading(level, "\u{1F5C3}\uFE0F Groups").$concat(
|
|
2015
2284
|
createGroupsOrAuditsDetails(
|
|
2016
2285
|
"group",
|
|
2017
2286
|
diff.groups,
|
|
@@ -2032,8 +2301,8 @@ function createDiffGroupsSection(diff) {
|
|
|
2032
2301
|
)
|
|
2033
2302
|
);
|
|
2034
2303
|
}
|
|
2035
|
-
function createDiffAuditsSection(diff) {
|
|
2036
|
-
return new
|
|
2304
|
+
function createDiffAuditsSection(diff, level) {
|
|
2305
|
+
return new MarkdownDocument5().heading(level, "\u{1F6E1}\uFE0F Audits").$concat(
|
|
2037
2306
|
createGroupsOrAuditsDetails(
|
|
2038
2307
|
"audit",
|
|
2039
2308
|
diff.audits,
|
|
@@ -2048,7 +2317,7 @@ function createDiffAuditsSection(diff) {
|
|
|
2048
2317
|
formatTitle(audit.plugin),
|
|
2049
2318
|
formatTitle(audit),
|
|
2050
2319
|
`${scoreMarker(audit.scores.before, "square")} ${audit.displayValues.before || audit.values.before.toString()}`,
|
|
2051
|
-
|
|
2320
|
+
md6`${scoreMarker(audit.scores.after, "square")} ${md6.bold(
|
|
2052
2321
|
audit.displayValues.after || audit.values.after.toString()
|
|
2053
2322
|
)}`,
|
|
2054
2323
|
formatValueChange(audit)
|
|
@@ -2056,96 +2325,6 @@ function createDiffAuditsSection(diff) {
|
|
|
2056
2325
|
)
|
|
2057
2326
|
);
|
|
2058
2327
|
}
|
|
2059
|
-
function createGroupsOrAuditsDetails(token, { changed, unchanged }, ...[columns, rows]) {
|
|
2060
|
-
if (changed.length === 0) {
|
|
2061
|
-
return new MarkdownDocument4().paragraph(
|
|
2062
|
-
summarizeUnchanged(token, { changed, unchanged })
|
|
2063
|
-
);
|
|
2064
|
-
}
|
|
2065
|
-
return new MarkdownDocument4().details(
|
|
2066
|
-
summarizeDiffOutcomes(changesToDiffOutcomes(changed), token),
|
|
2067
|
-
md5`${md5.table(columns, rows.slice(0, MAX_ROWS))}${changed.length > MAX_ROWS ? md5.paragraph(
|
|
2068
|
-
md5.italic(
|
|
2069
|
-
`Only the ${MAX_ROWS} most affected ${pluralize(
|
|
2070
|
-
token
|
|
2071
|
-
)} are listed above for brevity.`
|
|
2072
|
-
)
|
|
2073
|
-
) : ""}${unchanged.length > 0 ? md5.paragraph(summarizeUnchanged(token, { changed, unchanged })) : ""}`
|
|
2074
|
-
);
|
|
2075
|
-
}
|
|
2076
|
-
function summarizeUnchanged(token, { changed, unchanged }) {
|
|
2077
|
-
return [
|
|
2078
|
-
changed.length > 0 ? pluralizeToken(`other ${token}`, unchanged.length) : `All of ${pluralizeToken(token, unchanged.length)}`,
|
|
2079
|
-
unchanged.length === 1 ? "is" : "are",
|
|
2080
|
-
"unchanged."
|
|
2081
|
-
].join(" ");
|
|
2082
|
-
}
|
|
2083
|
-
function summarizeDiffOutcomes(outcomes, token) {
|
|
2084
|
-
return objectToEntries(countDiffOutcomes(outcomes)).filter(
|
|
2085
|
-
(entry) => entry[0] !== "unchanged" && entry[1] > 0
|
|
2086
|
-
).map(([outcome, count]) => {
|
|
2087
|
-
const formattedCount = `<strong>${count}</strong> ${pluralize(
|
|
2088
|
-
token,
|
|
2089
|
-
count
|
|
2090
|
-
)}`;
|
|
2091
|
-
switch (outcome) {
|
|
2092
|
-
case "positive":
|
|
2093
|
-
return `\u{1F44D} ${formattedCount} improved`;
|
|
2094
|
-
case "negative":
|
|
2095
|
-
return `\u{1F44E} ${formattedCount} regressed`;
|
|
2096
|
-
case "mixed":
|
|
2097
|
-
return `${formattedCount} changed without impacting score`;
|
|
2098
|
-
}
|
|
2099
|
-
}).join(", ");
|
|
2100
|
-
}
|
|
2101
|
-
function formatTitle({
|
|
2102
|
-
title,
|
|
2103
|
-
docsUrl
|
|
2104
|
-
}) {
|
|
2105
|
-
if (docsUrl) {
|
|
2106
|
-
return md5.link(docsUrl, title);
|
|
2107
|
-
}
|
|
2108
|
-
return title;
|
|
2109
|
-
}
|
|
2110
|
-
function sortChanges(changes) {
|
|
2111
|
-
return [...changes].sort(
|
|
2112
|
-
(a, b) => Math.abs(b.scores.diff) - Math.abs(a.scores.diff) || Math.abs(b.values?.diff ?? 0) - Math.abs(a.values?.diff ?? 0)
|
|
2113
|
-
);
|
|
2114
|
-
}
|
|
2115
|
-
function changesToDiffOutcomes(changes) {
|
|
2116
|
-
return changes.map((change) => {
|
|
2117
|
-
if (change.scores.diff > 0) {
|
|
2118
|
-
return "positive";
|
|
2119
|
-
}
|
|
2120
|
-
if (change.scores.diff < 0) {
|
|
2121
|
-
return "negative";
|
|
2122
|
-
}
|
|
2123
|
-
if (change.values != null && change.values.diff !== 0) {
|
|
2124
|
-
return "mixed";
|
|
2125
|
-
}
|
|
2126
|
-
return "unchanged";
|
|
2127
|
-
});
|
|
2128
|
-
}
|
|
2129
|
-
function mergeDiffOutcomes(outcomes) {
|
|
2130
|
-
if (outcomes.every((outcome) => outcome === "unchanged")) {
|
|
2131
|
-
return "unchanged";
|
|
2132
|
-
}
|
|
2133
|
-
if (outcomes.includes("positive") && !outcomes.includes("negative")) {
|
|
2134
|
-
return "positive";
|
|
2135
|
-
}
|
|
2136
|
-
if (outcomes.includes("negative") && !outcomes.includes("positive")) {
|
|
2137
|
-
return "negative";
|
|
2138
|
-
}
|
|
2139
|
-
return "mixed";
|
|
2140
|
-
}
|
|
2141
|
-
function countDiffOutcomes(outcomes) {
|
|
2142
|
-
return {
|
|
2143
|
-
positive: outcomes.filter((outcome) => outcome === "positive").length,
|
|
2144
|
-
negative: outcomes.filter((outcome) => outcome === "negative").length,
|
|
2145
|
-
mixed: outcomes.filter((outcome) => outcome === "mixed").length,
|
|
2146
|
-
unchanged: outcomes.filter((outcome) => outcome === "unchanged").length
|
|
2147
|
-
};
|
|
2148
|
-
}
|
|
2149
2328
|
|
|
2150
2329
|
// packages/utils/src/lib/reports/load-report.ts
|
|
2151
2330
|
import { join as join2 } from "node:path";
|
|
@@ -2178,8 +2357,8 @@ function logStdoutSummary(report) {
|
|
|
2178
2357
|
log();
|
|
2179
2358
|
}
|
|
2180
2359
|
function reportToHeaderSection(report) {
|
|
2181
|
-
const { packageName, version:
|
|
2182
|
-
return `${bold4(REPORT_HEADLINE_TEXT)} - ${packageName}@${
|
|
2360
|
+
const { packageName, version: version3 } = report;
|
|
2361
|
+
return `${bold4(REPORT_HEADLINE_TEXT)} - ${packageName}@${version3}`;
|
|
2183
2362
|
}
|
|
2184
2363
|
function logPlugins(report) {
|
|
2185
2364
|
const { plugins } = report;
|
|
@@ -2202,7 +2381,8 @@ function logPlugins(report) {
|
|
|
2202
2381
|
},
|
|
2203
2382
|
{
|
|
2204
2383
|
text: cyanBright(audit.displayValue || `${audit.value}`),
|
|
2205
|
-
|
|
2384
|
+
// eslint-disable-next-line no-magic-numbers
|
|
2385
|
+
width: 20,
|
|
2206
2386
|
padding: [0, 0, 0, 0]
|
|
2207
2387
|
}
|
|
2208
2388
|
]);
|
|
@@ -2355,7 +2535,7 @@ var verboseUtils = (verbose = false) => ({
|
|
|
2355
2535
|
|
|
2356
2536
|
// packages/core/package.json
|
|
2357
2537
|
var name = "@code-pushup/core";
|
|
2358
|
-
var version = "0.
|
|
2538
|
+
var version = "0.51.0";
|
|
2359
2539
|
|
|
2360
2540
|
// packages/core/src/lib/implementation/execute-plugin.ts
|
|
2361
2541
|
import { bold as bold5 } from "ansis";
|
|
@@ -2564,7 +2744,7 @@ async function persistReport(report, options2) {
|
|
|
2564
2744
|
case "md":
|
|
2565
2745
|
return {
|
|
2566
2746
|
format: "md",
|
|
2567
|
-
content: generateMdReport(sortedScoredReport)
|
|
2747
|
+
content: generateMdReport(sortedScoredReport, { outputDir })
|
|
2568
2748
|
};
|
|
2569
2749
|
}
|
|
2570
2750
|
});
|
|
@@ -2751,7 +2931,7 @@ function selectMeta(meta) {
|
|
|
2751
2931
|
}
|
|
2752
2932
|
|
|
2753
2933
|
// packages/core/src/lib/compare.ts
|
|
2754
|
-
async function compareReportFiles(inputPaths, persistConfig, uploadConfig) {
|
|
2934
|
+
async function compareReportFiles(inputPaths, persistConfig, uploadConfig, label) {
|
|
2755
2935
|
const { outputDir, filename, format } = persistConfig;
|
|
2756
2936
|
const [reportBefore, reportAfter] = await Promise.all([
|
|
2757
2937
|
readJsonFile(inputPaths.before),
|
|
@@ -2761,12 +2941,20 @@ async function compareReportFiles(inputPaths, persistConfig, uploadConfig) {
|
|
|
2761
2941
|
before: reportSchema.parse(reportBefore),
|
|
2762
2942
|
after: reportSchema.parse(reportAfter)
|
|
2763
2943
|
};
|
|
2764
|
-
const
|
|
2765
|
-
|
|
2944
|
+
const diff = compareReports(reports);
|
|
2945
|
+
if (label) {
|
|
2946
|
+
diff.label = label;
|
|
2947
|
+
}
|
|
2948
|
+
if (uploadConfig && diff.commits) {
|
|
2949
|
+
diff.portalUrl = await fetchPortalComparisonLink(
|
|
2950
|
+
uploadConfig,
|
|
2951
|
+
diff.commits
|
|
2952
|
+
);
|
|
2953
|
+
}
|
|
2766
2954
|
return Promise.all(
|
|
2767
2955
|
format.map(async (fmt) => {
|
|
2768
2956
|
const outputPath = join5(outputDir, `${filename}-diff.${fmt}`);
|
|
2769
|
-
const content = reportsDiffToFileContent(
|
|
2957
|
+
const content = reportsDiffToFileContent(diff, fmt);
|
|
2770
2958
|
await ensureDirectoryExists(outputDir);
|
|
2771
2959
|
await writeFile2(outputPath, content);
|
|
2772
2960
|
return outputPath;
|
|
@@ -2796,12 +2984,12 @@ function compareReports(reports) {
|
|
|
2796
2984
|
duration
|
|
2797
2985
|
};
|
|
2798
2986
|
}
|
|
2799
|
-
function reportsDiffToFileContent(reportsDiff, format
|
|
2987
|
+
function reportsDiffToFileContent(reportsDiff, format) {
|
|
2800
2988
|
switch (format) {
|
|
2801
2989
|
case "json":
|
|
2802
2990
|
return JSON.stringify(reportsDiff, null, 2);
|
|
2803
2991
|
case "md":
|
|
2804
|
-
return generateMdReportsDiff(reportsDiff
|
|
2992
|
+
return generateMdReportsDiff(reportsDiff);
|
|
2805
2993
|
}
|
|
2806
2994
|
}
|
|
2807
2995
|
async function fetchPortalComparisonLink(uploadConfig, commits) {
|
|
@@ -3074,6 +3262,45 @@ async function autoloadRc(tsconfig) {
|
|
|
3074
3262
|
);
|
|
3075
3263
|
}
|
|
3076
3264
|
|
|
3265
|
+
// packages/core/src/lib/merge-diffs.ts
|
|
3266
|
+
import { writeFile as writeFile3 } from "node:fs/promises";
|
|
3267
|
+
import { basename, dirname, join as join7 } from "node:path";
|
|
3268
|
+
async function mergeDiffs(files, persistConfig) {
|
|
3269
|
+
const results = await Promise.allSettled(
|
|
3270
|
+
files.map(async (file) => {
|
|
3271
|
+
const json = await readJsonFile(file).catch((error) => {
|
|
3272
|
+
throw new Error(
|
|
3273
|
+
`Failed to read JSON file ${file} - ${stringifyError(error)}`
|
|
3274
|
+
);
|
|
3275
|
+
});
|
|
3276
|
+
const result = await reportsDiffSchema.safeParseAsync(json);
|
|
3277
|
+
if (!result.success) {
|
|
3278
|
+
throw new Error(
|
|
3279
|
+
`Invalid reports diff in ${file} - ${result.error.message}`
|
|
3280
|
+
);
|
|
3281
|
+
}
|
|
3282
|
+
return { ...result.data, file };
|
|
3283
|
+
})
|
|
3284
|
+
);
|
|
3285
|
+
results.filter(isPromiseRejectedResult).forEach(({ reason }) => {
|
|
3286
|
+
ui().logger.warning(
|
|
3287
|
+
`Skipped invalid report diff - ${stringifyError(reason)}`
|
|
3288
|
+
);
|
|
3289
|
+
});
|
|
3290
|
+
const diffs = results.filter(isPromiseFulfilledResult).map(({ value }) => value);
|
|
3291
|
+
const labeledDiffs = diffs.map((diff) => ({
|
|
3292
|
+
...diff,
|
|
3293
|
+
label: diff.label || basename(dirname(diff.file))
|
|
3294
|
+
// fallback is parent folder name
|
|
3295
|
+
}));
|
|
3296
|
+
const markdown = generateMdReportsDiffForMonorepo(labeledDiffs);
|
|
3297
|
+
const { outputDir, filename } = persistConfig;
|
|
3298
|
+
const outputPath = join7(outputDir, `${filename}-diff.md`);
|
|
3299
|
+
await ensureDirectoryExists(outputDir);
|
|
3300
|
+
await writeFile3(outputPath, markdown);
|
|
3301
|
+
return outputPath;
|
|
3302
|
+
}
|
|
3303
|
+
|
|
3077
3304
|
// packages/cli/src/lib/constants.ts
|
|
3078
3305
|
var CLI_NAME = "Code PushUp CLI";
|
|
3079
3306
|
var CLI_SCRIPT_NAME = "code-pushup";
|
|
@@ -3207,6 +3434,10 @@ function yargsCompareOptionsDefinition() {
|
|
|
3207
3434
|
describe: "Path to target report.json",
|
|
3208
3435
|
type: "string",
|
|
3209
3436
|
demandOption: true
|
|
3437
|
+
},
|
|
3438
|
+
label: {
|
|
3439
|
+
describe: "Label for diff (e.g. project name)",
|
|
3440
|
+
type: "string"
|
|
3210
3441
|
}
|
|
3211
3442
|
};
|
|
3212
3443
|
}
|
|
@@ -3222,11 +3453,12 @@ function yargsCompareCommandObject() {
|
|
|
3222
3453
|
ui().logger.log(bold9(CLI_NAME));
|
|
3223
3454
|
ui().logger.info(gray6(`Run ${command2}...`));
|
|
3224
3455
|
const options2 = args;
|
|
3225
|
-
const { before, after, persist, upload: upload2 } = options2;
|
|
3456
|
+
const { before, after, label, persist, upload: upload2 } = options2;
|
|
3226
3457
|
const outputPaths = await compareReportFiles(
|
|
3227
3458
|
{ before, after },
|
|
3228
3459
|
persist,
|
|
3229
|
-
upload2
|
|
3460
|
+
upload2,
|
|
3461
|
+
label
|
|
3230
3462
|
);
|
|
3231
3463
|
ui().logger.info(
|
|
3232
3464
|
`Reports diff written to ${outputPaths.map((path) => bold9(path)).join(" and ")}`
|
|
@@ -3268,7 +3500,8 @@ var onlyPluginsOption = {
|
|
|
3268
3500
|
describe: "List of plugins to run. If not set all plugins are run.",
|
|
3269
3501
|
type: "array",
|
|
3270
3502
|
default: [],
|
|
3271
|
-
coerce: coerceArray
|
|
3503
|
+
coerce: coerceArray,
|
|
3504
|
+
alias: "p"
|
|
3272
3505
|
};
|
|
3273
3506
|
function yargsOnlyPluginsOptionsDefinition() {
|
|
3274
3507
|
return {
|
|
@@ -3281,7 +3514,8 @@ var skipPluginsOption = {
|
|
|
3281
3514
|
describe: "List of plugins to skip. If not set all plugins are run.",
|
|
3282
3515
|
type: "array",
|
|
3283
3516
|
default: [],
|
|
3284
|
-
coerce: coerceArray
|
|
3517
|
+
coerce: coerceArray,
|
|
3518
|
+
alias: "P"
|
|
3285
3519
|
};
|
|
3286
3520
|
function yargsSkipPluginsOptionsDefinition() {
|
|
3287
3521
|
return {
|
|
@@ -3412,6 +3646,38 @@ function yargsHistoryCommandObject() {
|
|
|
3412
3646
|
};
|
|
3413
3647
|
}
|
|
3414
3648
|
|
|
3649
|
+
// packages/cli/src/lib/merge-diffs/merge-diffs-command.ts
|
|
3650
|
+
import { bold as bold11, gray as gray8 } from "ansis";
|
|
3651
|
+
|
|
3652
|
+
// packages/cli/src/lib/implementation/merge-diffs.options.ts
|
|
3653
|
+
function yargsMergeDiffsOptionsDefinition() {
|
|
3654
|
+
return {
|
|
3655
|
+
files: {
|
|
3656
|
+
describe: "List of report-diff.json paths",
|
|
3657
|
+
type: "array",
|
|
3658
|
+
demandOption: true
|
|
3659
|
+
}
|
|
3660
|
+
};
|
|
3661
|
+
}
|
|
3662
|
+
|
|
3663
|
+
// packages/cli/src/lib/merge-diffs/merge-diffs-command.ts
|
|
3664
|
+
function yargsMergeDiffsCommandObject() {
|
|
3665
|
+
const command2 = "merge-diffs";
|
|
3666
|
+
return {
|
|
3667
|
+
command: command2,
|
|
3668
|
+
describe: "Combine many report diffs into a single diff file",
|
|
3669
|
+
builder: yargsMergeDiffsOptionsDefinition(),
|
|
3670
|
+
handler: async (args) => {
|
|
3671
|
+
ui().logger.log(bold11(CLI_NAME));
|
|
3672
|
+
ui().logger.info(gray8(`Run ${command2}...`));
|
|
3673
|
+
const options2 = args;
|
|
3674
|
+
const { files, persist } = options2;
|
|
3675
|
+
const outputPath = await mergeDiffs(files, persist);
|
|
3676
|
+
ui().logger.info(`Reports diff written to ${bold11(outputPath)}`);
|
|
3677
|
+
}
|
|
3678
|
+
};
|
|
3679
|
+
}
|
|
3680
|
+
|
|
3415
3681
|
// packages/cli/src/lib/print-config/print-config-command.ts
|
|
3416
3682
|
function yargsConfigCommandObject() {
|
|
3417
3683
|
const command2 = "print-config";
|
|
@@ -3427,15 +3693,15 @@ function yargsConfigCommandObject() {
|
|
|
3427
3693
|
}
|
|
3428
3694
|
|
|
3429
3695
|
// packages/cli/src/lib/upload/upload-command.ts
|
|
3430
|
-
import { bold as
|
|
3696
|
+
import { bold as bold12, gray as gray9 } from "ansis";
|
|
3431
3697
|
function yargsUploadCommandObject() {
|
|
3432
3698
|
const command2 = "upload";
|
|
3433
3699
|
return {
|
|
3434
3700
|
command: command2,
|
|
3435
3701
|
describe: "Upload report results to the portal",
|
|
3436
3702
|
handler: async (args) => {
|
|
3437
|
-
ui().logger.log(
|
|
3438
|
-
ui().logger.info(
|
|
3703
|
+
ui().logger.log(bold12(CLI_NAME));
|
|
3704
|
+
ui().logger.info(gray9(`Run ${command2}...`));
|
|
3439
3705
|
const options2 = args;
|
|
3440
3706
|
if (options2.upload == null) {
|
|
3441
3707
|
renderIntegratePortalHint();
|
|
@@ -3458,7 +3724,8 @@ var commands = [
|
|
|
3458
3724
|
yargsUploadCommandObject(),
|
|
3459
3725
|
yargsHistoryCommandObject(),
|
|
3460
3726
|
yargsCompareCommandObject(),
|
|
3461
|
-
yargsConfigCommandObject()
|
|
3727
|
+
yargsConfigCommandObject(),
|
|
3728
|
+
yargsMergeDiffsCommandObject()
|
|
3462
3729
|
];
|
|
3463
3730
|
|
|
3464
3731
|
// packages/cli/src/lib/implementation/core-config.middleware.ts
|
|
@@ -3499,7 +3766,6 @@ async function coreConfigMiddleware(processArgs) {
|
|
|
3499
3766
|
var normalizeFormats = (formats) => (formats ?? []).flatMap((format) => format.split(","));
|
|
3500
3767
|
|
|
3501
3768
|
// packages/cli/src/lib/implementation/validate-plugin-filter-options.utils.ts
|
|
3502
|
-
import { yellow } from "ansis";
|
|
3503
3769
|
function validatePluginFilterOption(filterOption, {
|
|
3504
3770
|
plugins,
|
|
3505
3771
|
categories
|
|
@@ -3513,13 +3779,9 @@ function validatePluginFilterOption(filterOption, {
|
|
|
3513
3779
|
);
|
|
3514
3780
|
const isSkipOption = filterOption === "skipPlugins";
|
|
3515
3781
|
const filterFunction = (plugin) => isSkipOption ? pluginsToFilterSet.has(plugin) : !pluginsToFilterSet.has(plugin);
|
|
3516
|
-
if (missingPlugins.length > 0
|
|
3517
|
-
ui().logger.
|
|
3518
|
-
|
|
3519
|
-
"\u26A0"
|
|
3520
|
-
)} The --${filterOption} argument references plugins with "${missingPlugins.join(
|
|
3521
|
-
'", "'
|
|
3522
|
-
)}" slugs, but no such plugins are present in the configuration. Expected one of the following plugin slugs: "${plugins.map(({ slug }) => slug).join('", "')}".`
|
|
3782
|
+
if (missingPlugins.length > 0) {
|
|
3783
|
+
ui().logger.warning(
|
|
3784
|
+
`The --${filterOption} argument references ${missingPlugins.length === 1 ? "a plugin that does" : "plugins that do"} not exist: ${missingPlugins.join(", ")}. The valid plugin ${plugins.length === 1 ? "slug is" : "slugs are"} ${plugins.map(({ slug }) => slug).join(", ")}.`
|
|
3523
3785
|
);
|
|
3524
3786
|
}
|
|
3525
3787
|
if (categories.length > 0 && verbose) {
|
|
@@ -3528,71 +3790,53 @@ function validatePluginFilterOption(filterOption, {
|
|
|
3528
3790
|
({ plugin }) => filterFunction(plugin)
|
|
3529
3791
|
).map(({ slug }) => slug);
|
|
3530
3792
|
ui().logger.info(
|
|
3531
|
-
`The --${filterOption} argument removed categories
|
|
3532
|
-
|
|
3533
|
-
)}
|
|
3534
|
-
`
|
|
3793
|
+
`The --${filterOption} argument removed the following categories: ${removedCategorySlugs.join(
|
|
3794
|
+
", "
|
|
3795
|
+
)}.`
|
|
3535
3796
|
);
|
|
3536
3797
|
}
|
|
3537
3798
|
}
|
|
3538
3799
|
|
|
3539
|
-
// packages/cli/src/lib/implementation/
|
|
3540
|
-
function
|
|
3541
|
-
const {
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
(oP) => plugins.find((p) => p.slug === oP)
|
|
3551
|
-
);
|
|
3552
|
-
const onlyPluginsSet = new Set(validOnlyPlugins);
|
|
3553
|
-
return {
|
|
3554
|
-
...originalProcessArgs,
|
|
3555
|
-
plugins: onlyPluginsSet.size > 0 ? plugins.filter(({ slug }) => onlyPluginsSet.has(slug)) : plugins,
|
|
3556
|
-
categories: onlyPluginsSet.size > 0 ? filterItemRefsBy(
|
|
3557
|
-
categories,
|
|
3558
|
-
({ plugin }) => onlyPluginsSet.has(plugin)
|
|
3559
|
-
) : categories
|
|
3560
|
-
};
|
|
3561
|
-
}
|
|
3562
|
-
return {
|
|
3563
|
-
...originalProcessArgs,
|
|
3564
|
-
// if undefined fill categories with empty array
|
|
3565
|
-
categories
|
|
3566
|
-
};
|
|
3567
|
-
}
|
|
3568
|
-
|
|
3569
|
-
// packages/cli/src/lib/implementation/skip-plugins.middleware.ts
|
|
3570
|
-
function skipPluginsMiddleware(originalProcessArgs) {
|
|
3571
|
-
const { categories = [], skipPlugins: originalSkipPlugins } = originalProcessArgs;
|
|
3572
|
-
if (originalSkipPlugins && originalSkipPlugins.length > 0) {
|
|
3573
|
-
const { verbose, plugins, skipPlugins = [] } = originalProcessArgs;
|
|
3574
|
-
validatePluginFilterOption(
|
|
3575
|
-
"skipPlugins",
|
|
3576
|
-
{ plugins, categories },
|
|
3577
|
-
{ pluginsToFilter: skipPlugins, verbose }
|
|
3578
|
-
);
|
|
3579
|
-
const validSkipPlugins = skipPlugins.filter(
|
|
3580
|
-
(sP) => plugins.find((p) => p.slug === sP)
|
|
3581
|
-
);
|
|
3582
|
-
const skipPluginsSet = new Set(validSkipPlugins);
|
|
3583
|
-
return {
|
|
3584
|
-
...originalProcessArgs,
|
|
3585
|
-
plugins: skipPluginsSet.size > 0 ? plugins.filter(({ slug }) => !skipPluginsSet.has(slug)) : plugins,
|
|
3586
|
-
categories: skipPluginsSet.size > 0 ? filterItemRefsBy(
|
|
3587
|
-
categories,
|
|
3588
|
-
({ plugin }) => !skipPluginsSet.has(plugin)
|
|
3589
|
-
) : categories
|
|
3590
|
-
};
|
|
3800
|
+
// packages/cli/src/lib/implementation/filter-plugins.middleware.ts
|
|
3801
|
+
function filterPluginsMiddleware(originalProcessArgs) {
|
|
3802
|
+
const {
|
|
3803
|
+
plugins,
|
|
3804
|
+
categories = [],
|
|
3805
|
+
skipPlugins = [],
|
|
3806
|
+
onlyPlugins = [],
|
|
3807
|
+
verbose
|
|
3808
|
+
} = originalProcessArgs;
|
|
3809
|
+
if (skipPlugins.length === 0 && onlyPlugins.length === 0) {
|
|
3810
|
+
return { ...originalProcessArgs, categories };
|
|
3591
3811
|
}
|
|
3812
|
+
validatePluginFilterOption(
|
|
3813
|
+
"skipPlugins",
|
|
3814
|
+
{ plugins, categories },
|
|
3815
|
+
{ pluginsToFilter: skipPlugins, verbose }
|
|
3816
|
+
);
|
|
3817
|
+
validatePluginFilterOption(
|
|
3818
|
+
"onlyPlugins",
|
|
3819
|
+
{ plugins, categories },
|
|
3820
|
+
{ pluginsToFilter: onlyPlugins, verbose }
|
|
3821
|
+
);
|
|
3822
|
+
const validSkipPlugins = new Set(
|
|
3823
|
+
skipPlugins.filter((sP) => plugins.some((p) => p.slug === sP))
|
|
3824
|
+
);
|
|
3825
|
+
const pluginsAfterSkip = plugins.filter(
|
|
3826
|
+
({ slug }) => !validSkipPlugins.has(slug)
|
|
3827
|
+
);
|
|
3828
|
+
const validOnlyPlugins = new Set(
|
|
3829
|
+
onlyPlugins.filter((oP) => pluginsAfterSkip.some((p) => p.slug === oP))
|
|
3830
|
+
);
|
|
3831
|
+
const filteredPlugins = validOnlyPlugins.size > 0 ? pluginsAfterSkip.filter(({ slug }) => validOnlyPlugins.has(slug)) : pluginsAfterSkip;
|
|
3832
|
+
const filteredCategories = filteredPlugins.length > 0 ? filterItemRefsBy(
|
|
3833
|
+
categories,
|
|
3834
|
+
({ plugin }) => filteredPlugins.some(({ slug }) => slug === plugin)
|
|
3835
|
+
) : categories;
|
|
3592
3836
|
return {
|
|
3593
3837
|
...originalProcessArgs,
|
|
3594
|
-
|
|
3595
|
-
categories
|
|
3838
|
+
plugins: filteredPlugins,
|
|
3839
|
+
categories: filteredCategories
|
|
3596
3840
|
};
|
|
3597
3841
|
}
|
|
3598
3842
|
|
|
@@ -3603,11 +3847,7 @@ var middlewares = [
|
|
|
3603
3847
|
applyBeforeValidation: false
|
|
3604
3848
|
},
|
|
3605
3849
|
{
|
|
3606
|
-
middlewareFunction:
|
|
3607
|
-
applyBeforeValidation: false
|
|
3608
|
-
},
|
|
3609
|
-
{
|
|
3610
|
-
middlewareFunction: skipPluginsMiddleware,
|
|
3850
|
+
middlewareFunction: filterPluginsMiddleware,
|
|
3611
3851
|
applyBeforeValidation: false
|
|
3612
3852
|
}
|
|
3613
3853
|
];
|
|
@@ -3670,7 +3910,7 @@ function yargsGlobalOptionsDefinition() {
|
|
|
3670
3910
|
default: false
|
|
3671
3911
|
},
|
|
3672
3912
|
config: {
|
|
3673
|
-
describe: "Path to config file
|
|
3913
|
+
describe: "Path to config file. By default it loads code-pushup.config.(ts|mjs|js).",
|
|
3674
3914
|
type: "string"
|
|
3675
3915
|
},
|
|
3676
3916
|
tsconfig: {
|
|
@@ -3698,8 +3938,55 @@ var groups = {
|
|
|
3698
3938
|
};
|
|
3699
3939
|
|
|
3700
3940
|
// packages/cli/src/lib/yargs-cli.ts
|
|
3701
|
-
import {
|
|
3941
|
+
import { blue, dim as dim2, green as green4 } from "ansis";
|
|
3702
3942
|
import yargs from "yargs";
|
|
3943
|
+
|
|
3944
|
+
// packages/cli/package.json
|
|
3945
|
+
var version2 = "0.51.0";
|
|
3946
|
+
|
|
3947
|
+
// packages/cli/src/lib/implementation/formatting.ts
|
|
3948
|
+
import { bold as bold13, dim, green as green3 } from "ansis";
|
|
3949
|
+
function titleStyle(title) {
|
|
3950
|
+
return `${bold13(title)}`;
|
|
3951
|
+
}
|
|
3952
|
+
function headerStyle(title) {
|
|
3953
|
+
return `${green3(title)}`;
|
|
3954
|
+
}
|
|
3955
|
+
function descriptionStyle(title) {
|
|
3956
|
+
return `${dim(title)}`;
|
|
3957
|
+
}
|
|
3958
|
+
function formatObjectValue(opts, propName) {
|
|
3959
|
+
const description = opts[propName];
|
|
3960
|
+
return {
|
|
3961
|
+
...opts,
|
|
3962
|
+
...typeof description === "string" && {
|
|
3963
|
+
[propName]: descriptionStyle(description)
|
|
3964
|
+
}
|
|
3965
|
+
};
|
|
3966
|
+
}
|
|
3967
|
+
function formatNestedValues(options2, propName) {
|
|
3968
|
+
return Object.fromEntries(
|
|
3969
|
+
Object.entries(options2).map(([key, opts]) => [
|
|
3970
|
+
key,
|
|
3971
|
+
formatObjectValue(opts, propName)
|
|
3972
|
+
])
|
|
3973
|
+
);
|
|
3974
|
+
}
|
|
3975
|
+
|
|
3976
|
+
// packages/cli/src/lib/yargs-cli.ts
|
|
3977
|
+
var yargsDecorator = {
|
|
3978
|
+
"Commands:": `${green4("Commands")}:`,
|
|
3979
|
+
"Options:": `${green4("Options")}:`,
|
|
3980
|
+
"Examples:": `${green4("Examples")}:`,
|
|
3981
|
+
boolean: blue("boolean"),
|
|
3982
|
+
count: blue("count"),
|
|
3983
|
+
string: blue("string"),
|
|
3984
|
+
array: blue("array"),
|
|
3985
|
+
required: blue("required"),
|
|
3986
|
+
"default:": `${blue("default")}:`,
|
|
3987
|
+
"choices:": `${blue("choices")}:`,
|
|
3988
|
+
"aliases:": `${blue("aliases")}:`
|
|
3989
|
+
};
|
|
3703
3990
|
function yargsCli(argv, cfg) {
|
|
3704
3991
|
const { usageMessage, scriptName, noExitProcess } = cfg;
|
|
3705
3992
|
const commands2 = cfg.commands ?? [];
|
|
@@ -3708,7 +3995,7 @@ function yargsCli(argv, cfg) {
|
|
|
3708
3995
|
const groups2 = cfg.groups ?? {};
|
|
3709
3996
|
const examples = cfg.examples ?? [];
|
|
3710
3997
|
const cli2 = yargs(argv);
|
|
3711
|
-
cli2.
|
|
3998
|
+
cli2.updateLocale(yargsDecorator).wrap(Math.max(TERMINAL_WIDTH, cli2.terminalWidth())).help("help", descriptionStyle("Show help")).alias("h", "help").showHelpOnFail(false).version("version", dim2`Show version`, version2).check((args) => {
|
|
3712
3999
|
const persist = args["persist"];
|
|
3713
4000
|
return persist == null || validatePersistFormat(persist);
|
|
3714
4001
|
}).parserConfiguration({
|
|
@@ -3716,18 +4003,18 @@ function yargsCli(argv, cfg) {
|
|
|
3716
4003
|
}).coerce(
|
|
3717
4004
|
"config",
|
|
3718
4005
|
(config) => Array.isArray(config) ? config.at(-1) : config
|
|
3719
|
-
).options(options2)
|
|
4006
|
+
).options(formatNestedValues(options2, "describe"));
|
|
3720
4007
|
if (usageMessage) {
|
|
3721
|
-
cli2.usage(
|
|
4008
|
+
cli2.usage(titleStyle(usageMessage));
|
|
3722
4009
|
}
|
|
3723
4010
|
if (scriptName) {
|
|
3724
4011
|
cli2.scriptName(scriptName);
|
|
3725
4012
|
}
|
|
3726
4013
|
examples.forEach(
|
|
3727
|
-
([exampleName, description]) => cli2.example(exampleName, description)
|
|
4014
|
+
([exampleName, description]) => cli2.example(exampleName, descriptionStyle(description))
|
|
3728
4015
|
);
|
|
3729
4016
|
Object.entries(groups2).forEach(
|
|
3730
|
-
([groupName, optionNames]) => cli2.group(optionNames, groupName)
|
|
4017
|
+
([groupName, optionNames]) => cli2.group(optionNames, headerStyle(groupName))
|
|
3731
4018
|
);
|
|
3732
4019
|
middlewares2.forEach(({ middlewareFunction, applyBeforeValidation }) => {
|
|
3733
4020
|
cli2.middleware(
|
|
@@ -3736,13 +4023,18 @@ function yargsCli(argv, cfg) {
|
|
|
3736
4023
|
);
|
|
3737
4024
|
});
|
|
3738
4025
|
commands2.forEach((commandObj) => {
|
|
3739
|
-
cli2.command(
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
4026
|
+
cli2.command(
|
|
4027
|
+
formatObjectValue(
|
|
4028
|
+
{
|
|
4029
|
+
...commandObj,
|
|
4030
|
+
handler: logErrorBeforeThrow(commandObj.handler),
|
|
4031
|
+
...typeof commandObj.builder === "function" && {
|
|
4032
|
+
builder: logErrorBeforeThrow(commandObj.builder)
|
|
4033
|
+
}
|
|
4034
|
+
},
|
|
4035
|
+
"describe"
|
|
4036
|
+
)
|
|
4037
|
+
);
|
|
3746
4038
|
});
|
|
3747
4039
|
if (noExitProcess) {
|
|
3748
4040
|
cli2.exitProcess(false);
|
|
@@ -3788,8 +4080,8 @@ var cli = (args) => yargsCli(args, {
|
|
|
3788
4080
|
"Run collect skiping the coverage plugin, other plugins from config file will be included."
|
|
3789
4081
|
],
|
|
3790
4082
|
[
|
|
3791
|
-
"code-pushup upload --persist.outputDir=dist --
|
|
3792
|
-
"Upload dist/
|
|
4083
|
+
"code-pushup upload --persist.outputDir=dist --upload.apiKey=$CP_API_KEY",
|
|
4084
|
+
"Upload dist/report.json to portal using API key from environment variable"
|
|
3793
4085
|
],
|
|
3794
4086
|
[
|
|
3795
4087
|
"code-pushup print-config --config code-pushup.config.test.js",
|