@code-pushup/core 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/index.js +504 -273
- package/package.json +7 -33
- package/src/index.d.ts +7 -6
- package/src/lib/collect-and-persist.d.ts +2 -2
- package/src/lib/compare.d.ts +3 -3
- package/src/lib/history.d.ts +2 -2
- package/src/lib/implementation/collect.d.ts +2 -2
- package/src/lib/implementation/compare-scorables.d.ts +2 -2
- package/src/lib/implementation/execute-plugin.d.ts +1 -1
- package/src/lib/implementation/persist.d.ts +2 -2
- package/src/lib/implementation/read-rc-file.d.ts +1 -1
- package/src/lib/implementation/runner.d.ts +1 -1
- package/src/lib/merge-diffs.d.ts +2 -0
- package/src/lib/normalize.d.ts +1 -1
- package/src/lib/upload.d.ts +2 -2
package/index.js
CHANGED
|
@@ -155,9 +155,27 @@ function hasNonZeroWeightedRef(refs) {
|
|
|
155
155
|
return refs.reduce((acc, { weight }) => weight + acc, 0) !== 0;
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
// packages/models/src/lib/
|
|
158
|
+
// packages/models/src/lib/source.ts
|
|
159
159
|
import { z as z2 } from "zod";
|
|
160
|
-
var
|
|
160
|
+
var sourceFileLocationSchema = z2.object(
|
|
161
|
+
{
|
|
162
|
+
file: filePathSchema.describe("Relative path to source file in Git repo"),
|
|
163
|
+
position: z2.object(
|
|
164
|
+
{
|
|
165
|
+
startLine: positiveIntSchema.describe("Start line"),
|
|
166
|
+
startColumn: positiveIntSchema.describe("Start column").optional(),
|
|
167
|
+
endLine: positiveIntSchema.describe("End line").optional(),
|
|
168
|
+
endColumn: positiveIntSchema.describe("End column").optional()
|
|
169
|
+
},
|
|
170
|
+
{ description: "Location in file" }
|
|
171
|
+
).optional()
|
|
172
|
+
},
|
|
173
|
+
{ description: "Source file location" }
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
// packages/models/src/lib/audit.ts
|
|
177
|
+
import { z as z3 } from "zod";
|
|
178
|
+
var auditSchema = z3.object({
|
|
161
179
|
slug: slugSchema.describe("ID (unique within plugin)")
|
|
162
180
|
}).merge(
|
|
163
181
|
metaSchema({
|
|
@@ -167,7 +185,7 @@ var auditSchema = z2.object({
|
|
|
167
185
|
description: "List of scorable metrics for the given plugin"
|
|
168
186
|
})
|
|
169
187
|
);
|
|
170
|
-
var pluginAuditsSchema =
|
|
188
|
+
var pluginAuditsSchema = z3.array(auditSchema, {
|
|
171
189
|
description: "List of audits maintained in a plugin"
|
|
172
190
|
}).min(1).refine(
|
|
173
191
|
(auditMetadata) => !getDuplicateSlugsInAudits(auditMetadata),
|
|
@@ -186,31 +204,16 @@ function getDuplicateSlugsInAudits(audits) {
|
|
|
186
204
|
}
|
|
187
205
|
|
|
188
206
|
// packages/models/src/lib/audit-output.ts
|
|
189
|
-
import { z as
|
|
207
|
+
import { z as z6 } from "zod";
|
|
190
208
|
|
|
191
209
|
// packages/models/src/lib/issue.ts
|
|
192
|
-
import { z as
|
|
193
|
-
var
|
|
194
|
-
{
|
|
195
|
-
file: filePathSchema.describe("Relative path to source file in Git repo"),
|
|
196
|
-
position: z3.object(
|
|
197
|
-
{
|
|
198
|
-
startLine: positiveIntSchema.describe("Start line"),
|
|
199
|
-
startColumn: positiveIntSchema.describe("Start column").optional(),
|
|
200
|
-
endLine: positiveIntSchema.describe("End line").optional(),
|
|
201
|
-
endColumn: positiveIntSchema.describe("End column").optional()
|
|
202
|
-
},
|
|
203
|
-
{ description: "Location in file" }
|
|
204
|
-
).optional()
|
|
205
|
-
},
|
|
206
|
-
{ description: "Source file location" }
|
|
207
|
-
);
|
|
208
|
-
var issueSeveritySchema = z3.enum(["info", "warning", "error"], {
|
|
210
|
+
import { z as z4 } from "zod";
|
|
211
|
+
var issueSeveritySchema = z4.enum(["info", "warning", "error"], {
|
|
209
212
|
description: "Severity level"
|
|
210
213
|
});
|
|
211
|
-
var issueSchema =
|
|
214
|
+
var issueSchema = z4.object(
|
|
212
215
|
{
|
|
213
|
-
message:
|
|
216
|
+
message: z4.string({ description: "Descriptive error message" }).max(MAX_ISSUE_MESSAGE_LENGTH),
|
|
214
217
|
severity: issueSeveritySchema,
|
|
215
218
|
source: sourceFileLocationSchema.optional()
|
|
216
219
|
},
|
|
@@ -218,60 +221,60 @@ var issueSchema = z3.object(
|
|
|
218
221
|
);
|
|
219
222
|
|
|
220
223
|
// packages/models/src/lib/table.ts
|
|
221
|
-
import { z as
|
|
222
|
-
var tableAlignmentSchema =
|
|
224
|
+
import { z as z5 } from "zod";
|
|
225
|
+
var tableAlignmentSchema = z5.enum(["left", "center", "right"], {
|
|
223
226
|
description: "Cell alignment"
|
|
224
227
|
});
|
|
225
|
-
var tableColumnObjectSchema =
|
|
226
|
-
key:
|
|
227
|
-
label:
|
|
228
|
+
var tableColumnObjectSchema = z5.object({
|
|
229
|
+
key: z5.string(),
|
|
230
|
+
label: z5.string().optional(),
|
|
228
231
|
align: tableAlignmentSchema.optional()
|
|
229
232
|
});
|
|
230
|
-
var tableRowObjectSchema =
|
|
233
|
+
var tableRowObjectSchema = z5.record(tableCellValueSchema, {
|
|
231
234
|
description: "Object row"
|
|
232
235
|
});
|
|
233
|
-
var tableRowPrimitiveSchema =
|
|
236
|
+
var tableRowPrimitiveSchema = z5.array(tableCellValueSchema, {
|
|
234
237
|
description: "Primitive row"
|
|
235
238
|
});
|
|
236
|
-
var tableSharedSchema =
|
|
237
|
-
title:
|
|
239
|
+
var tableSharedSchema = z5.object({
|
|
240
|
+
title: z5.string().optional().describe("Display title for table")
|
|
238
241
|
});
|
|
239
242
|
var tablePrimitiveSchema = tableSharedSchema.merge(
|
|
240
|
-
|
|
243
|
+
z5.object(
|
|
241
244
|
{
|
|
242
|
-
columns:
|
|
243
|
-
rows:
|
|
245
|
+
columns: z5.array(tableAlignmentSchema).optional(),
|
|
246
|
+
rows: z5.array(tableRowPrimitiveSchema)
|
|
244
247
|
},
|
|
245
248
|
{ description: "Table with primitive rows and optional alignment columns" }
|
|
246
249
|
)
|
|
247
250
|
);
|
|
248
251
|
var tableObjectSchema = tableSharedSchema.merge(
|
|
249
|
-
|
|
252
|
+
z5.object(
|
|
250
253
|
{
|
|
251
|
-
columns:
|
|
252
|
-
|
|
253
|
-
|
|
254
|
+
columns: z5.union([
|
|
255
|
+
z5.array(tableAlignmentSchema),
|
|
256
|
+
z5.array(tableColumnObjectSchema)
|
|
254
257
|
]).optional(),
|
|
255
|
-
rows:
|
|
258
|
+
rows: z5.array(tableRowObjectSchema)
|
|
256
259
|
},
|
|
257
260
|
{
|
|
258
261
|
description: "Table with object rows and optional alignment or object columns"
|
|
259
262
|
}
|
|
260
263
|
)
|
|
261
264
|
);
|
|
262
|
-
var tableSchema = (description = "Table information") =>
|
|
265
|
+
var tableSchema = (description = "Table information") => z5.union([tablePrimitiveSchema, tableObjectSchema], { description });
|
|
263
266
|
|
|
264
267
|
// packages/models/src/lib/audit-output.ts
|
|
265
268
|
var auditValueSchema = nonnegativeNumberSchema.describe("Raw numeric value");
|
|
266
|
-
var auditDisplayValueSchema =
|
|
267
|
-
var auditDetailsSchema =
|
|
269
|
+
var auditDisplayValueSchema = z6.string({ description: "Formatted value (e.g. '0.9 s', '2.1 MB')" }).optional();
|
|
270
|
+
var auditDetailsSchema = z6.object(
|
|
268
271
|
{
|
|
269
|
-
issues:
|
|
272
|
+
issues: z6.array(issueSchema, { description: "List of findings" }).optional(),
|
|
270
273
|
table: tableSchema("Table of related findings").optional()
|
|
271
274
|
},
|
|
272
275
|
{ description: "Detailed information" }
|
|
273
276
|
);
|
|
274
|
-
var auditOutputSchema =
|
|
277
|
+
var auditOutputSchema = z6.object(
|
|
275
278
|
{
|
|
276
279
|
slug: slugSchema.describe("Reference to audit"),
|
|
277
280
|
displayValue: auditDisplayValueSchema,
|
|
@@ -281,7 +284,7 @@ var auditOutputSchema = z5.object(
|
|
|
281
284
|
},
|
|
282
285
|
{ description: "Audit information" }
|
|
283
286
|
);
|
|
284
|
-
var auditOutputsSchema =
|
|
287
|
+
var auditOutputsSchema = z6.array(auditOutputSchema, {
|
|
285
288
|
description: "List of JSON formatted audit output emitted by the runner process of a plugin"
|
|
286
289
|
}).refine(
|
|
287
290
|
(audits) => !getDuplicateSlugsInAudits2(audits),
|
|
@@ -298,13 +301,13 @@ function getDuplicateSlugsInAudits2(audits) {
|
|
|
298
301
|
}
|
|
299
302
|
|
|
300
303
|
// packages/models/src/lib/category-config.ts
|
|
301
|
-
import { z as
|
|
304
|
+
import { z as z7 } from "zod";
|
|
302
305
|
var categoryRefSchema = weightedRefSchema(
|
|
303
306
|
"Weighted references to audits and/or groups for the category",
|
|
304
307
|
"Slug of an audit or group (depending on `type`)"
|
|
305
308
|
).merge(
|
|
306
|
-
|
|
307
|
-
type:
|
|
309
|
+
z7.object({
|
|
310
|
+
type: z7.enum(["audit", "group"], {
|
|
308
311
|
description: "Discriminant for reference kind, affects where `slug` is looked up"
|
|
309
312
|
}),
|
|
310
313
|
plugin: slugSchema.describe(
|
|
@@ -325,8 +328,8 @@ var categoryConfigSchema = scorableSchema(
|
|
|
325
328
|
description: "Meta info for category"
|
|
326
329
|
})
|
|
327
330
|
).merge(
|
|
328
|
-
|
|
329
|
-
isBinary:
|
|
331
|
+
z7.object({
|
|
332
|
+
isBinary: z7.boolean({
|
|
330
333
|
description: 'Is this a binary category (i.e. only a perfect score considered a "pass")?'
|
|
331
334
|
}).optional()
|
|
332
335
|
})
|
|
@@ -342,7 +345,7 @@ function getDuplicateRefsInCategoryMetrics(metrics) {
|
|
|
342
345
|
metrics.map(({ slug, type, plugin }) => `${type} :: ${plugin} / ${slug}`)
|
|
343
346
|
);
|
|
344
347
|
}
|
|
345
|
-
var categoriesSchema =
|
|
348
|
+
var categoriesSchema = z7.array(categoryConfigSchema, {
|
|
346
349
|
description: "Categorization of individual audits"
|
|
347
350
|
}).refine(
|
|
348
351
|
(categoryCfg) => !getDuplicateSlugCategories(categoryCfg),
|
|
@@ -361,18 +364,18 @@ function getDuplicateSlugCategories(categories) {
|
|
|
361
364
|
}
|
|
362
365
|
|
|
363
366
|
// packages/models/src/lib/commit.ts
|
|
364
|
-
import { z as
|
|
365
|
-
var commitSchema =
|
|
367
|
+
import { z as z8 } from "zod";
|
|
368
|
+
var commitSchema = z8.object(
|
|
366
369
|
{
|
|
367
|
-
hash:
|
|
370
|
+
hash: z8.string({ description: "Commit SHA (full)" }).regex(
|
|
368
371
|
/^[\da-f]{40}$/,
|
|
369
372
|
"Commit SHA should be a 40-character hexadecimal string"
|
|
370
373
|
),
|
|
371
|
-
message:
|
|
372
|
-
date:
|
|
374
|
+
message: z8.string({ description: "Commit message" }),
|
|
375
|
+
date: z8.coerce.date({
|
|
373
376
|
description: "Date and time when commit was authored"
|
|
374
377
|
}),
|
|
375
|
-
author:
|
|
378
|
+
author: z8.string({
|
|
376
379
|
description: "Commit author name"
|
|
377
380
|
}).trim()
|
|
378
381
|
},
|
|
@@ -380,22 +383,22 @@ var commitSchema = z7.object(
|
|
|
380
383
|
);
|
|
381
384
|
|
|
382
385
|
// packages/models/src/lib/core-config.ts
|
|
383
|
-
import { z as
|
|
386
|
+
import { z as z14 } from "zod";
|
|
384
387
|
|
|
385
388
|
// packages/models/src/lib/persist-config.ts
|
|
386
|
-
import { z as
|
|
387
|
-
var formatSchema =
|
|
388
|
-
var persistConfigSchema =
|
|
389
|
+
import { z as z9 } from "zod";
|
|
390
|
+
var formatSchema = z9.enum(["json", "md"]);
|
|
391
|
+
var persistConfigSchema = z9.object({
|
|
389
392
|
outputDir: filePathSchema.describe("Artifacts folder").optional(),
|
|
390
393
|
filename: fileNameSchema.describe("Artifacts file name (without extension)").optional(),
|
|
391
|
-
format:
|
|
394
|
+
format: z9.array(formatSchema).optional()
|
|
392
395
|
});
|
|
393
396
|
|
|
394
397
|
// packages/models/src/lib/plugin-config.ts
|
|
395
|
-
import { z as
|
|
398
|
+
import { z as z12 } from "zod";
|
|
396
399
|
|
|
397
400
|
// packages/models/src/lib/group.ts
|
|
398
|
-
import { z as
|
|
401
|
+
import { z as z10 } from "zod";
|
|
399
402
|
var groupRefSchema = weightedRefSchema(
|
|
400
403
|
"Weighted reference to a group",
|
|
401
404
|
"Reference slug to a group within this plugin (e.g. 'max-lines')"
|
|
@@ -412,7 +415,7 @@ var groupSchema = scorableSchema(
|
|
|
412
415
|
getDuplicateRefsInGroups,
|
|
413
416
|
duplicateRefsInGroupsErrorMsg
|
|
414
417
|
).merge(groupMetaSchema);
|
|
415
|
-
var groupsSchema =
|
|
418
|
+
var groupsSchema = z10.array(groupSchema, {
|
|
416
419
|
description: "List of groups"
|
|
417
420
|
}).optional().refine(
|
|
418
421
|
(groups) => !getDuplicateSlugsInGroups(groups),
|
|
@@ -440,14 +443,14 @@ function getDuplicateSlugsInGroups(groups) {
|
|
|
440
443
|
}
|
|
441
444
|
|
|
442
445
|
// packages/models/src/lib/runner-config.ts
|
|
443
|
-
import { z as
|
|
444
|
-
var outputTransformSchema =
|
|
445
|
-
var runnerConfigSchema =
|
|
446
|
+
import { z as z11 } from "zod";
|
|
447
|
+
var outputTransformSchema = z11.function().args(z11.unknown()).returns(z11.union([auditOutputsSchema, z11.promise(auditOutputsSchema)]));
|
|
448
|
+
var runnerConfigSchema = z11.object(
|
|
446
449
|
{
|
|
447
|
-
command:
|
|
450
|
+
command: z11.string({
|
|
448
451
|
description: "Shell command to execute"
|
|
449
452
|
}),
|
|
450
|
-
args:
|
|
453
|
+
args: z11.array(z11.string({ description: "Command arguments" })).optional(),
|
|
451
454
|
outputFile: filePathSchema.describe("Output path"),
|
|
452
455
|
outputTransform: outputTransformSchema.optional()
|
|
453
456
|
},
|
|
@@ -455,8 +458,8 @@ var runnerConfigSchema = z10.object(
|
|
|
455
458
|
description: "How to execute runner"
|
|
456
459
|
}
|
|
457
460
|
);
|
|
458
|
-
var onProgressSchema =
|
|
459
|
-
var runnerFunctionSchema =
|
|
461
|
+
var onProgressSchema = z11.function().args(z11.unknown()).returns(z11.void());
|
|
462
|
+
var runnerFunctionSchema = z11.function().args(onProgressSchema.optional()).returns(z11.union([auditOutputsSchema, z11.promise(auditOutputsSchema)]));
|
|
460
463
|
|
|
461
464
|
// packages/models/src/lib/plugin-config.ts
|
|
462
465
|
var pluginMetaSchema = packageVersionSchema().merge(
|
|
@@ -467,13 +470,13 @@ var pluginMetaSchema = packageVersionSchema().merge(
|
|
|
467
470
|
description: "Plugin metadata"
|
|
468
471
|
})
|
|
469
472
|
).merge(
|
|
470
|
-
|
|
473
|
+
z12.object({
|
|
471
474
|
slug: slugSchema.describe("Unique plugin slug within core config"),
|
|
472
475
|
icon: materialIconSchema
|
|
473
476
|
})
|
|
474
477
|
);
|
|
475
|
-
var pluginDataSchema =
|
|
476
|
-
runner:
|
|
478
|
+
var pluginDataSchema = z12.object({
|
|
479
|
+
runner: z12.union([runnerConfigSchema, runnerFunctionSchema]),
|
|
477
480
|
audits: pluginAuditsSchema,
|
|
478
481
|
groups: groupsSchema
|
|
479
482
|
});
|
|
@@ -499,22 +502,22 @@ function getMissingRefsFromGroups(pluginCfg) {
|
|
|
499
502
|
}
|
|
500
503
|
|
|
501
504
|
// packages/models/src/lib/upload-config.ts
|
|
502
|
-
import { z as
|
|
503
|
-
var uploadConfigSchema =
|
|
505
|
+
import { z as z13 } from "zod";
|
|
506
|
+
var uploadConfigSchema = z13.object({
|
|
504
507
|
server: urlSchema.describe("URL of deployed portal API"),
|
|
505
|
-
apiKey:
|
|
508
|
+
apiKey: z13.string({
|
|
506
509
|
description: "API key with write access to portal (use `process.env` for security)"
|
|
507
510
|
}),
|
|
508
511
|
organization: slugSchema.describe(
|
|
509
512
|
"Organization slug from Code PushUp portal"
|
|
510
513
|
),
|
|
511
514
|
project: slugSchema.describe("Project slug from Code PushUp portal"),
|
|
512
|
-
timeout:
|
|
515
|
+
timeout: z13.number({ description: "Request timeout in minutes (default is 5)" }).positive().int().optional()
|
|
513
516
|
});
|
|
514
517
|
|
|
515
518
|
// packages/models/src/lib/core-config.ts
|
|
516
|
-
var unrefinedCoreConfigSchema =
|
|
517
|
-
plugins:
|
|
519
|
+
var unrefinedCoreConfigSchema = z14.object({
|
|
520
|
+
plugins: z14.array(pluginConfigSchema, {
|
|
518
521
|
description: "List of plugins to be used (official, community-provided, or custom)"
|
|
519
522
|
}).min(1),
|
|
520
523
|
/** portal configuration for persisting results */
|
|
@@ -541,7 +544,7 @@ var CONFIG_FILE_NAME = "code-pushup.config";
|
|
|
541
544
|
var SUPPORTED_CONFIG_FILE_FORMATS = ["ts", "mjs", "js"];
|
|
542
545
|
|
|
543
546
|
// packages/models/src/lib/report.ts
|
|
544
|
-
import { z as
|
|
547
|
+
import { z as z15 } from "zod";
|
|
545
548
|
var auditReportSchema = auditSchema.merge(auditOutputSchema);
|
|
546
549
|
var pluginReportSchema = pluginMetaSchema.merge(
|
|
547
550
|
executionMetaSchema({
|
|
@@ -549,9 +552,9 @@ var pluginReportSchema = pluginMetaSchema.merge(
|
|
|
549
552
|
descriptionDuration: "Duration of the plugin run in ms"
|
|
550
553
|
})
|
|
551
554
|
).merge(
|
|
552
|
-
|
|
553
|
-
audits:
|
|
554
|
-
groups:
|
|
555
|
+
z15.object({
|
|
556
|
+
audits: z15.array(auditReportSchema).min(1),
|
|
557
|
+
groups: z15.array(groupSchema).optional()
|
|
555
558
|
})
|
|
556
559
|
).refine(
|
|
557
560
|
(pluginReport) => !getMissingRefsFromGroups2(pluginReport.audits, pluginReport.groups ?? []),
|
|
@@ -585,10 +588,10 @@ var reportSchema = packageVersionSchema({
|
|
|
585
588
|
descriptionDuration: "Duration of the collect run in ms"
|
|
586
589
|
})
|
|
587
590
|
).merge(
|
|
588
|
-
|
|
591
|
+
z15.object(
|
|
589
592
|
{
|
|
590
|
-
categories:
|
|
591
|
-
plugins:
|
|
593
|
+
categories: z15.array(categoryConfigSchema),
|
|
594
|
+
plugins: z15.array(pluginReportSchema).min(1),
|
|
592
595
|
commit: commitSchema.describe("Git commit for which report was collected").nullable()
|
|
593
596
|
},
|
|
594
597
|
{ description: "Collect output data" }
|
|
@@ -604,40 +607,40 @@ var reportSchema = packageVersionSchema({
|
|
|
604
607
|
);
|
|
605
608
|
|
|
606
609
|
// packages/models/src/lib/reports-diff.ts
|
|
607
|
-
import { z as
|
|
610
|
+
import { z as z16 } from "zod";
|
|
608
611
|
function makeComparisonSchema(schema) {
|
|
609
612
|
const sharedDescription = schema.description || "Result";
|
|
610
|
-
return
|
|
613
|
+
return z16.object({
|
|
611
614
|
before: schema.describe(`${sharedDescription} (source commit)`),
|
|
612
615
|
after: schema.describe(`${sharedDescription} (target commit)`)
|
|
613
616
|
});
|
|
614
617
|
}
|
|
615
618
|
function makeArraysComparisonSchema(diffSchema, resultSchema, description) {
|
|
616
|
-
return
|
|
619
|
+
return z16.object(
|
|
617
620
|
{
|
|
618
|
-
changed:
|
|
619
|
-
unchanged:
|
|
620
|
-
added:
|
|
621
|
-
removed:
|
|
621
|
+
changed: z16.array(diffSchema),
|
|
622
|
+
unchanged: z16.array(resultSchema),
|
|
623
|
+
added: z16.array(resultSchema),
|
|
624
|
+
removed: z16.array(resultSchema)
|
|
622
625
|
},
|
|
623
626
|
{ description }
|
|
624
627
|
);
|
|
625
628
|
}
|
|
626
|
-
var scorableMetaSchema =
|
|
629
|
+
var scorableMetaSchema = z16.object({
|
|
627
630
|
slug: slugSchema,
|
|
628
631
|
title: titleSchema,
|
|
629
632
|
docsUrl: docsUrlSchema
|
|
630
633
|
});
|
|
631
634
|
var scorableWithPluginMetaSchema = scorableMetaSchema.merge(
|
|
632
|
-
|
|
635
|
+
z16.object({
|
|
633
636
|
plugin: pluginMetaSchema.pick({ slug: true, title: true, docsUrl: true }).describe("Plugin which defines it")
|
|
634
637
|
})
|
|
635
638
|
);
|
|
636
639
|
var scorableDiffSchema = scorableMetaSchema.merge(
|
|
637
|
-
|
|
640
|
+
z16.object({
|
|
638
641
|
scores: makeComparisonSchema(scoreSchema).merge(
|
|
639
|
-
|
|
640
|
-
diff:
|
|
642
|
+
z16.object({
|
|
643
|
+
diff: z16.number().min(-1).max(1).describe("Score change (`scores.after - scores.before`)")
|
|
641
644
|
})
|
|
642
645
|
).describe("Score comparison")
|
|
643
646
|
})
|
|
@@ -648,10 +651,10 @@ var scorableWithPluginDiffSchema = scorableDiffSchema.merge(
|
|
|
648
651
|
var categoryDiffSchema = scorableDiffSchema;
|
|
649
652
|
var groupDiffSchema = scorableWithPluginDiffSchema;
|
|
650
653
|
var auditDiffSchema = scorableWithPluginDiffSchema.merge(
|
|
651
|
-
|
|
654
|
+
z16.object({
|
|
652
655
|
values: makeComparisonSchema(auditValueSchema).merge(
|
|
653
|
-
|
|
654
|
-
diff:
|
|
656
|
+
z16.object({
|
|
657
|
+
diff: z16.number().int().describe("Value change (`values.after - values.before`)")
|
|
655
658
|
})
|
|
656
659
|
).describe("Audit `value` comparison"),
|
|
657
660
|
displayValues: makeComparisonSchema(auditDisplayValueSchema).describe(
|
|
@@ -660,16 +663,18 @@ var auditDiffSchema = scorableWithPluginDiffSchema.merge(
|
|
|
660
663
|
})
|
|
661
664
|
);
|
|
662
665
|
var categoryResultSchema = scorableMetaSchema.merge(
|
|
663
|
-
|
|
666
|
+
z16.object({ score: scoreSchema })
|
|
664
667
|
);
|
|
665
668
|
var groupResultSchema = scorableWithPluginMetaSchema.merge(
|
|
666
|
-
|
|
669
|
+
z16.object({ score: scoreSchema })
|
|
667
670
|
);
|
|
668
671
|
var auditResultSchema = scorableWithPluginMetaSchema.merge(
|
|
669
672
|
auditOutputSchema.pick({ score: true, value: true, displayValue: true })
|
|
670
673
|
);
|
|
671
|
-
var reportsDiffSchema =
|
|
674
|
+
var reportsDiffSchema = z16.object({
|
|
672
675
|
commits: makeComparisonSchema(commitSchema).nullable().describe("Commits identifying compared reports"),
|
|
676
|
+
portalUrl: urlSchema.optional().describe("Link to comparison page in Code PushUp portal"),
|
|
677
|
+
label: z16.string().optional().describe("Label (e.g. project name)"),
|
|
673
678
|
categories: makeArraysComparisonSchema(
|
|
674
679
|
categoryDiffSchema,
|
|
675
680
|
categoryResultSchema,
|
|
@@ -739,8 +744,24 @@ function comparePairs(pairs, equalsFn) {
|
|
|
739
744
|
);
|
|
740
745
|
}
|
|
741
746
|
|
|
747
|
+
// packages/utils/src/lib/errors.ts
|
|
748
|
+
function stringifyError(error) {
|
|
749
|
+
if (error instanceof Error) {
|
|
750
|
+
if (error.name === "Error" || error.message.startsWith(error.name)) {
|
|
751
|
+
return error.message;
|
|
752
|
+
}
|
|
753
|
+
return `${error.name}: ${error.message}`;
|
|
754
|
+
}
|
|
755
|
+
if (typeof error === "string") {
|
|
756
|
+
return error;
|
|
757
|
+
}
|
|
758
|
+
return JSON.stringify(error);
|
|
759
|
+
}
|
|
760
|
+
|
|
742
761
|
// packages/utils/src/lib/execute-process.ts
|
|
743
|
-
import {
|
|
762
|
+
import {
|
|
763
|
+
spawn
|
|
764
|
+
} from "node:child_process";
|
|
744
765
|
|
|
745
766
|
// packages/utils/src/lib/reports/utils.ts
|
|
746
767
|
import ansis from "ansis";
|
|
@@ -826,9 +847,17 @@ function severityMarker(severity) {
|
|
|
826
847
|
}
|
|
827
848
|
return "\u2139\uFE0F";
|
|
828
849
|
}
|
|
850
|
+
var MIN_NON_ZERO_RESULT = 0.1;
|
|
851
|
+
function roundValue(value) {
|
|
852
|
+
const roundedValue = Math.round(value * 10) / 10;
|
|
853
|
+
if (roundedValue === 0 && value !== 0) {
|
|
854
|
+
return MIN_NON_ZERO_RESULT * Math.sign(value);
|
|
855
|
+
}
|
|
856
|
+
return roundedValue;
|
|
857
|
+
}
|
|
829
858
|
function formatScoreChange(diff) {
|
|
830
859
|
const marker = getDiffMarker(diff);
|
|
831
|
-
const text = formatDiffNumber(
|
|
860
|
+
const text = formatDiffNumber(roundValue(diff * 100));
|
|
832
861
|
return colorByScoreDiff(`${marker} ${text}`, diff);
|
|
833
862
|
}
|
|
834
863
|
function formatValueChange({
|
|
@@ -836,7 +865,7 @@ function formatValueChange({
|
|
|
836
865
|
scores
|
|
837
866
|
}) {
|
|
838
867
|
const marker = getDiffMarker(values.diff);
|
|
839
|
-
const percentage = values.before === 0 ? values.diff > 0 ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY :
|
|
868
|
+
const percentage = values.before === 0 ? values.diff > 0 ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY : roundValue(values.diff / values.before * 100);
|
|
840
869
|
const text = `${formatDiffNumber(percentage)}\u2009%`;
|
|
841
870
|
return colorByScoreDiff(`${marker} ${text}`, scores.diff);
|
|
842
871
|
}
|
|
@@ -867,12 +896,12 @@ function countCategoryAudits(refs, plugins) {
|
|
|
867
896
|
}, 0);
|
|
868
897
|
}
|
|
869
898
|
function compareCategoryAuditsAndGroups(a, b) {
|
|
870
|
-
if (a.weight !== b.weight) {
|
|
871
|
-
return b.weight - a.weight;
|
|
872
|
-
}
|
|
873
899
|
if (a.score !== b.score) {
|
|
874
900
|
return a.score - b.score;
|
|
875
901
|
}
|
|
902
|
+
if (a.weight !== b.weight) {
|
|
903
|
+
return b.weight - a.weight;
|
|
904
|
+
}
|
|
876
905
|
if ("value" in a && "value" in b && a.value !== b.value) {
|
|
877
906
|
return b.value - a.value;
|
|
878
907
|
}
|
|
@@ -964,25 +993,29 @@ var ProcessError = class extends Error {
|
|
|
964
993
|
}
|
|
965
994
|
};
|
|
966
995
|
function executeProcess(cfg) {
|
|
967
|
-
const {
|
|
968
|
-
const { onStdout, onError, onComplete } = observer ?? {};
|
|
996
|
+
const { command, args, observer, ignoreExitCode = false, ...options } = cfg;
|
|
997
|
+
const { onStdout, onStderr, onError, onComplete } = observer ?? {};
|
|
969
998
|
const date = (/* @__PURE__ */ new Date()).toISOString();
|
|
970
999
|
const start = performance.now();
|
|
971
1000
|
return new Promise((resolve, reject) => {
|
|
972
|
-
const
|
|
1001
|
+
const spawnedProcess = spawn(command, args ?? [], {
|
|
1002
|
+
shell: true,
|
|
1003
|
+
...options
|
|
1004
|
+
});
|
|
973
1005
|
let stdout = "";
|
|
974
1006
|
let stderr = "";
|
|
975
|
-
|
|
1007
|
+
spawnedProcess.stdout.on("data", (data) => {
|
|
976
1008
|
stdout += String(data);
|
|
977
|
-
onStdout?.(String(data));
|
|
1009
|
+
onStdout?.(String(data), spawnedProcess);
|
|
978
1010
|
});
|
|
979
|
-
|
|
1011
|
+
spawnedProcess.stderr.on("data", (data) => {
|
|
980
1012
|
stderr += String(data);
|
|
1013
|
+
onStderr?.(String(data), spawnedProcess);
|
|
981
1014
|
});
|
|
982
|
-
|
|
1015
|
+
spawnedProcess.on("error", (err) => {
|
|
983
1016
|
stderr += err.toString();
|
|
984
1017
|
});
|
|
985
|
-
|
|
1018
|
+
spawnedProcess.on("close", (code2) => {
|
|
986
1019
|
const timings = { date, duration: calcDuration(start) };
|
|
987
1020
|
if (code2 === 0 || ignoreExitCode) {
|
|
988
1021
|
onComplete?.();
|
|
@@ -1181,6 +1214,9 @@ import { isAbsolute, join, relative } from "node:path";
|
|
|
1181
1214
|
import { simpleGit } from "simple-git";
|
|
1182
1215
|
|
|
1183
1216
|
// packages/utils/src/lib/transform.ts
|
|
1217
|
+
function toArray(val) {
|
|
1218
|
+
return Array.isArray(val) ? val : [val];
|
|
1219
|
+
}
|
|
1184
1220
|
function objectToEntries(obj) {
|
|
1185
1221
|
return Object.entries(obj);
|
|
1186
1222
|
}
|
|
@@ -1452,7 +1488,33 @@ function getColumnAlignments(tableData) {
|
|
|
1452
1488
|
}
|
|
1453
1489
|
|
|
1454
1490
|
// packages/utils/src/lib/reports/formatting.ts
|
|
1455
|
-
import {
|
|
1491
|
+
import {
|
|
1492
|
+
MarkdownDocument,
|
|
1493
|
+
md as md2
|
|
1494
|
+
} from "build-md";
|
|
1495
|
+
import { posix as pathPosix } from "node:path";
|
|
1496
|
+
|
|
1497
|
+
// packages/utils/src/lib/reports/ide-environment.ts
|
|
1498
|
+
function getEnvironmentType() {
|
|
1499
|
+
if (isVSCode()) {
|
|
1500
|
+
return "vscode";
|
|
1501
|
+
}
|
|
1502
|
+
if (isGitHub()) {
|
|
1503
|
+
return "github";
|
|
1504
|
+
}
|
|
1505
|
+
return "other";
|
|
1506
|
+
}
|
|
1507
|
+
function isVSCode() {
|
|
1508
|
+
return process.env["TERM_PROGRAM"] === "vscode";
|
|
1509
|
+
}
|
|
1510
|
+
function isGitHub() {
|
|
1511
|
+
return process.env["GITHUB_ACTIONS"] === "true";
|
|
1512
|
+
}
|
|
1513
|
+
function getGitHubBaseUrl() {
|
|
1514
|
+
return `${process.env["GITHUB_SERVER_URL"]}/${process.env["GITHUB_REPOSITORY"]}/blob/${process.env["GITHUB_SHA"]}`;
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
// packages/utils/src/lib/reports/formatting.ts
|
|
1456
1518
|
function tableSection(tableData, options) {
|
|
1457
1519
|
if (tableData.rows.length === 0) {
|
|
1458
1520
|
return null;
|
|
@@ -1490,6 +1552,44 @@ function metaDescription(audit) {
|
|
|
1490
1552
|
}
|
|
1491
1553
|
return "";
|
|
1492
1554
|
}
|
|
1555
|
+
function linkToLocalSourceForIde(source, options) {
|
|
1556
|
+
const { file, position } = source;
|
|
1557
|
+
const { outputDir } = options ?? {};
|
|
1558
|
+
if (!outputDir) {
|
|
1559
|
+
return md2.code(file);
|
|
1560
|
+
}
|
|
1561
|
+
return md2.link(formatFileLink(file, position, outputDir), md2.code(file));
|
|
1562
|
+
}
|
|
1563
|
+
function formatSourceLine(position) {
|
|
1564
|
+
if (!position) {
|
|
1565
|
+
return "";
|
|
1566
|
+
}
|
|
1567
|
+
const { startLine, endLine } = position;
|
|
1568
|
+
return endLine && startLine !== endLine ? `${startLine}-${endLine}` : `${startLine}`;
|
|
1569
|
+
}
|
|
1570
|
+
function formatGitHubLink(file, position) {
|
|
1571
|
+
const baseUrl = getGitHubBaseUrl();
|
|
1572
|
+
if (!position) {
|
|
1573
|
+
return `${baseUrl}/${file}`;
|
|
1574
|
+
}
|
|
1575
|
+
const { startLine, endLine, startColumn, endColumn } = position;
|
|
1576
|
+
const start = startColumn ? `L${startLine}C${startColumn}` : `L${startLine}`;
|
|
1577
|
+
const end = endLine ? endColumn ? `L${endLine}C${endColumn}` : `L${endLine}` : "";
|
|
1578
|
+
const lineRange = end && start !== end ? `${start}-${end}` : start;
|
|
1579
|
+
return `${baseUrl}/${file}#${lineRange}`;
|
|
1580
|
+
}
|
|
1581
|
+
function formatFileLink(file, position, outputDir) {
|
|
1582
|
+
const relativePath = pathPosix.relative(outputDir, file);
|
|
1583
|
+
const env = getEnvironmentType();
|
|
1584
|
+
switch (env) {
|
|
1585
|
+
case "vscode":
|
|
1586
|
+
return position ? `${relativePath}#L${position.startLine}` : relativePath;
|
|
1587
|
+
case "github":
|
|
1588
|
+
return formatGitHubLink(file, position);
|
|
1589
|
+
default:
|
|
1590
|
+
return relativePath;
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1493
1593
|
|
|
1494
1594
|
// packages/utils/src/lib/reports/generate-md-report-categoy-section.ts
|
|
1495
1595
|
import { MarkdownDocument as MarkdownDocument2, md as md3 } from "build-md";
|
|
@@ -1691,16 +1791,16 @@ function auditDetailsAuditValue({
|
|
|
1691
1791
|
String(displayValue ?? value)
|
|
1692
1792
|
)} (score: ${formatReportScore(score)})`;
|
|
1693
1793
|
}
|
|
1694
|
-
function generateMdReport(report) {
|
|
1794
|
+
function generateMdReport(report, options) {
|
|
1695
1795
|
return new MarkdownDocument3().heading(HIERARCHY.level_1, REPORT_HEADLINE_TEXT).$if(
|
|
1696
1796
|
report.categories.length > 0,
|
|
1697
1797
|
(doc) => doc.$concat(
|
|
1698
1798
|
categoriesOverviewSection(report),
|
|
1699
1799
|
categoriesDetailsSection(report)
|
|
1700
1800
|
)
|
|
1701
|
-
).$concat(auditsSection(report), aboutSection(report)).rule().paragraph(md4`${FOOTER_PREFIX} ${md4.link(README_LINK, "Code PushUp")}`).toString();
|
|
1801
|
+
).$concat(auditsSection(report, options), aboutSection(report)).rule().paragraph(md4`${FOOTER_PREFIX} ${md4.link(README_LINK, "Code PushUp")}`).toString();
|
|
1702
1802
|
}
|
|
1703
|
-
function auditDetailsIssues(issues = []) {
|
|
1803
|
+
function auditDetailsIssues(issues = [], options) {
|
|
1704
1804
|
if (issues.length === 0) {
|
|
1705
1805
|
return null;
|
|
1706
1806
|
}
|
|
@@ -1716,39 +1816,36 @@ function auditDetailsIssues(issues = []) {
|
|
|
1716
1816
|
if (!source) {
|
|
1717
1817
|
return [severity, message];
|
|
1718
1818
|
}
|
|
1719
|
-
const file =
|
|
1819
|
+
const file = linkToLocalSourceForIde(source, options);
|
|
1720
1820
|
if (!source.position) {
|
|
1721
1821
|
return [severity, message, file];
|
|
1722
1822
|
}
|
|
1723
|
-
const
|
|
1724
|
-
const line = `${startLine || ""}${endLine && startLine !== endLine ? `-${endLine}` : ""}`;
|
|
1823
|
+
const line = formatSourceLine(source.position);
|
|
1725
1824
|
return [severity, message, file, line];
|
|
1726
1825
|
})
|
|
1727
1826
|
);
|
|
1728
1827
|
}
|
|
1729
|
-
function auditDetails(audit) {
|
|
1828
|
+
function auditDetails(audit, options) {
|
|
1730
1829
|
const { table: table2, issues = [] } = audit.details ?? {};
|
|
1731
1830
|
const detailsValue = auditDetailsAuditValue(audit);
|
|
1732
1831
|
if (issues.length === 0 && !table2?.rows.length) {
|
|
1733
1832
|
return new MarkdownDocument3().paragraph(detailsValue);
|
|
1734
1833
|
}
|
|
1735
1834
|
const tableSectionContent = table2 && tableSection(table2);
|
|
1736
|
-
const issuesSectionContent = issues.length > 0 && auditDetailsIssues(issues);
|
|
1835
|
+
const issuesSectionContent = issues.length > 0 && auditDetailsIssues(issues, options);
|
|
1737
1836
|
return new MarkdownDocument3().details(
|
|
1738
1837
|
detailsValue,
|
|
1739
1838
|
new MarkdownDocument3().$concat(tableSectionContent, issuesSectionContent)
|
|
1740
1839
|
);
|
|
1741
1840
|
}
|
|
1742
|
-
function auditsSection({
|
|
1743
|
-
plugins
|
|
1744
|
-
}) {
|
|
1841
|
+
function auditsSection({ plugins }, options) {
|
|
1745
1842
|
return new MarkdownDocument3().heading(HIERARCHY.level_2, "\u{1F6E1}\uFE0F Audits").$foreach(
|
|
1746
1843
|
plugins.flatMap(
|
|
1747
1844
|
(plugin) => plugin.audits.map((audit) => ({ ...audit, plugin }))
|
|
1748
1845
|
),
|
|
1749
1846
|
(doc, { plugin, ...audit }) => {
|
|
1750
1847
|
const auditTitle = `${audit.title} (${plugin.title})`;
|
|
1751
|
-
const detailsContent = auditDetails(audit);
|
|
1848
|
+
const detailsContent = auditDetails(audit, options);
|
|
1752
1849
|
const descriptionContent = metaDescription(audit);
|
|
1753
1850
|
return doc.heading(HIERARCHY.level_3, auditTitle).$concat(detailsContent).paragraph(descriptionContent);
|
|
1754
1851
|
}
|
|
@@ -1812,19 +1909,111 @@ function reportMetaTable({
|
|
|
1812
1909
|
|
|
1813
1910
|
// packages/utils/src/lib/reports/generate-md-reports-diff.ts
|
|
1814
1911
|
import {
|
|
1815
|
-
MarkdownDocument as
|
|
1816
|
-
md as
|
|
1912
|
+
MarkdownDocument as MarkdownDocument5,
|
|
1913
|
+
md as md6
|
|
1817
1914
|
} from "build-md";
|
|
1915
|
+
|
|
1916
|
+
// packages/utils/src/lib/reports/generate-md-reports-diff-utils.ts
|
|
1917
|
+
import { MarkdownDocument as MarkdownDocument4, md as md5 } from "build-md";
|
|
1818
1918
|
var MAX_ROWS = 100;
|
|
1819
|
-
function
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
createDiffGroupsSection(diff),
|
|
1824
|
-
createDiffAuditsSection(diff)
|
|
1825
|
-
).toString();
|
|
1919
|
+
function summarizeUnchanged(token, { changed, unchanged }) {
|
|
1920
|
+
const pluralizedCount = changed.length > 0 ? pluralizeToken(`other ${token}`, unchanged.length) : `All of ${pluralizeToken(token, unchanged.length)}`;
|
|
1921
|
+
const pluralizedVerb = unchanged.length === 1 ? "is" : "are";
|
|
1922
|
+
return `${pluralizedCount} ${pluralizedVerb} unchanged.`;
|
|
1826
1923
|
}
|
|
1827
|
-
function
|
|
1924
|
+
function summarizeDiffOutcomes(outcomes, token) {
|
|
1925
|
+
return objectToEntries(countDiffOutcomes(outcomes)).filter(
|
|
1926
|
+
(entry) => entry[0] !== "unchanged" && entry[1] > 0
|
|
1927
|
+
).map(([outcome, count]) => {
|
|
1928
|
+
const formattedCount = `<strong>${count}</strong> ${pluralize(
|
|
1929
|
+
token,
|
|
1930
|
+
count
|
|
1931
|
+
)}`;
|
|
1932
|
+
switch (outcome) {
|
|
1933
|
+
case "positive":
|
|
1934
|
+
return `\u{1F44D} ${formattedCount} improved`;
|
|
1935
|
+
case "negative":
|
|
1936
|
+
return `\u{1F44E} ${formattedCount} regressed`;
|
|
1937
|
+
case "mixed":
|
|
1938
|
+
return `${formattedCount} changed without impacting score`;
|
|
1939
|
+
}
|
|
1940
|
+
}).join(", ");
|
|
1941
|
+
}
|
|
1942
|
+
function createGroupsOrAuditsDetails(token, { changed, unchanged }, ...[columns, rows]) {
|
|
1943
|
+
if (changed.length === 0) {
|
|
1944
|
+
return new MarkdownDocument4().paragraph(
|
|
1945
|
+
summarizeUnchanged(token, { changed, unchanged })
|
|
1946
|
+
);
|
|
1947
|
+
}
|
|
1948
|
+
return new MarkdownDocument4().table(columns, rows.slice(0, MAX_ROWS)).paragraph(
|
|
1949
|
+
changed.length > MAX_ROWS && md5.italic(
|
|
1950
|
+
`Only the ${MAX_ROWS} most affected ${pluralize(
|
|
1951
|
+
token
|
|
1952
|
+
)} are listed above for brevity.`
|
|
1953
|
+
)
|
|
1954
|
+
).paragraph(
|
|
1955
|
+
unchanged.length > 0 && summarizeUnchanged(token, { changed, unchanged })
|
|
1956
|
+
);
|
|
1957
|
+
}
|
|
1958
|
+
function formatTitle({
|
|
1959
|
+
title,
|
|
1960
|
+
docsUrl
|
|
1961
|
+
}) {
|
|
1962
|
+
if (docsUrl) {
|
|
1963
|
+
return md5.link(docsUrl, title);
|
|
1964
|
+
}
|
|
1965
|
+
return title;
|
|
1966
|
+
}
|
|
1967
|
+
function formatPortalLink(portalUrl) {
|
|
1968
|
+
return portalUrl && md5.link(portalUrl, "\u{1F575}\uFE0F See full comparison in Code PushUp portal \u{1F50D}");
|
|
1969
|
+
}
|
|
1970
|
+
function sortChanges(changes) {
|
|
1971
|
+
return [...changes].sort(
|
|
1972
|
+
(a, b) => Math.abs(b.scores.diff) - Math.abs(a.scores.diff) || Math.abs(b.values?.diff ?? 0) - Math.abs(a.values?.diff ?? 0)
|
|
1973
|
+
);
|
|
1974
|
+
}
|
|
1975
|
+
function getDiffChanges(diff) {
|
|
1976
|
+
return [
|
|
1977
|
+
...diff.categories.changed,
|
|
1978
|
+
...diff.groups.changed,
|
|
1979
|
+
...diff.audits.changed
|
|
1980
|
+
];
|
|
1981
|
+
}
|
|
1982
|
+
function changesToDiffOutcomes(changes) {
|
|
1983
|
+
return changes.map((change) => {
|
|
1984
|
+
if (change.scores.diff > 0) {
|
|
1985
|
+
return "positive";
|
|
1986
|
+
}
|
|
1987
|
+
if (change.scores.diff < 0) {
|
|
1988
|
+
return "negative";
|
|
1989
|
+
}
|
|
1990
|
+
if (change.values != null && change.values.diff !== 0) {
|
|
1991
|
+
return "mixed";
|
|
1992
|
+
}
|
|
1993
|
+
return "unchanged";
|
|
1994
|
+
});
|
|
1995
|
+
}
|
|
1996
|
+
function mergeDiffOutcomes(outcomes) {
|
|
1997
|
+
if (outcomes.every((outcome) => outcome === "unchanged")) {
|
|
1998
|
+
return "unchanged";
|
|
1999
|
+
}
|
|
2000
|
+
if (outcomes.includes("positive") && !outcomes.includes("negative")) {
|
|
2001
|
+
return "positive";
|
|
2002
|
+
}
|
|
2003
|
+
if (outcomes.includes("negative") && !outcomes.includes("positive")) {
|
|
2004
|
+
return "negative";
|
|
2005
|
+
}
|
|
2006
|
+
return "mixed";
|
|
2007
|
+
}
|
|
2008
|
+
function countDiffOutcomes(outcomes) {
|
|
2009
|
+
return {
|
|
2010
|
+
positive: outcomes.filter((outcome) => outcome === "positive").length,
|
|
2011
|
+
negative: outcomes.filter((outcome) => outcome === "negative").length,
|
|
2012
|
+
mixed: outcomes.filter((outcome) => outcome === "mixed").length,
|
|
2013
|
+
unchanged: outcomes.filter((outcome) => outcome === "unchanged").length
|
|
2014
|
+
};
|
|
2015
|
+
}
|
|
2016
|
+
function formatReportOutcome(outcome, commits) {
|
|
1828
2017
|
const outcomeTexts = {
|
|
1829
2018
|
positive: md5`🥳 Code PushUp report has ${md5.bold("improved")}`,
|
|
1830
2019
|
negative: md5`😟 Code PushUp report has ${md5.bold("regressed")}`,
|
|
@@ -1833,36 +2022,91 @@ function createDiffHeaderSection(diff, portalUrl) {
|
|
|
1833
2022
|
)}`,
|
|
1834
2023
|
unchanged: md5`😐 Code PushUp report is ${md5.bold("unchanged")}`
|
|
1835
2024
|
};
|
|
2025
|
+
if (commits) {
|
|
2026
|
+
const commitsText = `compared target commit ${commits.after.hash} with source commit ${commits.before.hash}`;
|
|
2027
|
+
return md5`${outcomeTexts[outcome]} – ${commitsText}.`;
|
|
2028
|
+
}
|
|
2029
|
+
return md5`${outcomeTexts[outcome]}.`;
|
|
2030
|
+
}
|
|
2031
|
+
function compareDiffsBy(type, a, b) {
|
|
2032
|
+
return sumScoreChanges(b[type].changed) - sumScoreChanges(a[type].changed) || sumConfigChanges(b[type]) - sumConfigChanges(a[type]);
|
|
2033
|
+
}
|
|
2034
|
+
function sumScoreChanges(changes) {
|
|
2035
|
+
return changes.reduce(
|
|
2036
|
+
(acc, { scores }) => acc + Math.abs(scores.diff),
|
|
2037
|
+
0
|
|
2038
|
+
);
|
|
2039
|
+
}
|
|
2040
|
+
function sumConfigChanges({
|
|
2041
|
+
added,
|
|
2042
|
+
removed
|
|
2043
|
+
}) {
|
|
2044
|
+
return added.length + removed.length;
|
|
2045
|
+
}
|
|
2046
|
+
|
|
2047
|
+
// packages/utils/src/lib/reports/generate-md-reports-diff.ts
|
|
2048
|
+
function generateMdReportsDiff(diff) {
|
|
2049
|
+
return new MarkdownDocument5().$concat(
|
|
2050
|
+
createDiffHeaderSection(diff),
|
|
2051
|
+
createDiffCategoriesSection(diff),
|
|
2052
|
+
createDiffDetailsSection(diff)
|
|
2053
|
+
).toString();
|
|
2054
|
+
}
|
|
2055
|
+
function generateMdReportsDiffForMonorepo(diffs) {
|
|
2056
|
+
const diffsWithOutcomes = diffs.map((diff) => ({
|
|
2057
|
+
...diff,
|
|
2058
|
+
outcome: mergeDiffOutcomes(changesToDiffOutcomes(getDiffChanges(diff)))
|
|
2059
|
+
})).sort(
|
|
2060
|
+
(a, b) => compareDiffsBy("categories", a, b) || compareDiffsBy("groups", a, b) || compareDiffsBy("audits", a, b) || a.label.localeCompare(b.label)
|
|
2061
|
+
);
|
|
2062
|
+
const unchanged = diffsWithOutcomes.filter(
|
|
2063
|
+
({ outcome }) => outcome === "unchanged"
|
|
2064
|
+
);
|
|
2065
|
+
const changed = diffsWithOutcomes.filter((diff) => !unchanged.includes(diff));
|
|
2066
|
+
return new MarkdownDocument5().$concat(
|
|
2067
|
+
createDiffHeaderSection(diffs),
|
|
2068
|
+
...changed.map(createDiffProjectSection)
|
|
2069
|
+
).$if(
|
|
2070
|
+
unchanged.length > 0,
|
|
2071
|
+
(doc) => doc.rule().paragraph(summarizeUnchanged("project", { unchanged, changed }))
|
|
2072
|
+
).toString();
|
|
2073
|
+
}
|
|
2074
|
+
function createDiffHeaderSection(diff) {
|
|
1836
2075
|
const outcome = mergeDiffOutcomes(
|
|
1837
|
-
changesToDiffOutcomes(
|
|
1838
|
-
...diff.categories.changed,
|
|
1839
|
-
...diff.groups.changed,
|
|
1840
|
-
...diff.audits.changed
|
|
1841
|
-
])
|
|
2076
|
+
changesToDiffOutcomes(toArray(diff).flatMap(getDiffChanges))
|
|
1842
2077
|
);
|
|
1843
|
-
const
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
2078
|
+
const commits = Array.isArray(diff) ? diff[0]?.commits : diff.commits;
|
|
2079
|
+
const portalUrl = Array.isArray(diff) ? void 0 : diff.portalUrl;
|
|
2080
|
+
return new MarkdownDocument5().heading(HIERARCHY.level_1, "Code PushUp").paragraph(formatReportOutcome(outcome, commits)).paragraph(formatPortalLink(portalUrl));
|
|
2081
|
+
}
|
|
2082
|
+
function createDiffProjectSection(diff) {
|
|
2083
|
+
return new MarkdownDocument5().heading(HIERARCHY.level_2, md6`💼 Project ${md6.code(diff.label)}`).paragraph(formatReportOutcome(diff.outcome)).paragraph(formatPortalLink(diff.portalUrl)).$concat(
|
|
2084
|
+
createDiffCategoriesSection(diff, {
|
|
2085
|
+
skipHeading: true,
|
|
2086
|
+
skipUnchanged: true
|
|
2087
|
+
}),
|
|
2088
|
+
createDiffDetailsSection(diff, HIERARCHY.level_3)
|
|
1848
2089
|
);
|
|
1849
2090
|
}
|
|
1850
|
-
function createDiffCategoriesSection(diff) {
|
|
2091
|
+
function createDiffCategoriesSection(diff, options) {
|
|
1851
2092
|
const { changed, unchanged, added } = diff.categories;
|
|
2093
|
+
const { skipHeading, skipUnchanged } = options ?? {};
|
|
1852
2094
|
const categoriesCount = changed.length + unchanged.length + added.length;
|
|
1853
2095
|
const hasChanges = unchanged.length < categoriesCount;
|
|
1854
2096
|
if (categoriesCount === 0) {
|
|
1855
2097
|
return null;
|
|
1856
2098
|
}
|
|
1857
|
-
const columns =
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
}
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
2099
|
+
const [columns, rows] = createCategoriesTable(diff, {
|
|
2100
|
+
hasChanges,
|
|
2101
|
+
skipUnchanged
|
|
2102
|
+
});
|
|
2103
|
+
return new MarkdownDocument5().heading(HIERARCHY.level_2, !skipHeading && "\u{1F3F7}\uFE0F Categories").table(columns, rows).paragraph(added.length > 0 && md6.italic("(\\*) New category.")).paragraph(
|
|
2104
|
+
skipUnchanged && unchanged.length > 0 && summarizeUnchanged("category", { changed, unchanged })
|
|
2105
|
+
);
|
|
2106
|
+
}
|
|
2107
|
+
function createCategoriesTable(diff, options) {
|
|
2108
|
+
const { changed, unchanged, added } = diff.categories;
|
|
2109
|
+
const { hasChanges, skipUnchanged } = options;
|
|
1866
2110
|
const rows = [
|
|
1867
2111
|
...sortChanges(changed).map((category) => [
|
|
1868
2112
|
formatTitle(category),
|
|
@@ -1874,27 +2118,55 @@ function createDiffCategoriesSection(diff) {
|
|
|
1874
2118
|
]),
|
|
1875
2119
|
...added.map((category) => [
|
|
1876
2120
|
formatTitle(category),
|
|
1877
|
-
|
|
2121
|
+
md6.italic("n/a (\\*)"),
|
|
1878
2122
|
formatScoreWithColor(category.score),
|
|
1879
|
-
|
|
2123
|
+
md6.italic("n/a (\\*)")
|
|
1880
2124
|
]),
|
|
1881
|
-
...unchanged.map((category) => [
|
|
2125
|
+
...skipUnchanged ? [] : unchanged.map((category) => [
|
|
1882
2126
|
formatTitle(category),
|
|
1883
2127
|
formatScoreWithColor(category.score, { skipBold: true }),
|
|
1884
2128
|
formatScoreWithColor(category.score),
|
|
1885
2129
|
"\u2013"
|
|
1886
2130
|
])
|
|
1887
2131
|
];
|
|
1888
|
-
|
|
2132
|
+
if (rows.length === 0) {
|
|
2133
|
+
return [[], []];
|
|
2134
|
+
}
|
|
2135
|
+
const columns = [
|
|
2136
|
+
{ heading: "\u{1F3F7}\uFE0F Category", alignment: "left" },
|
|
2137
|
+
{
|
|
2138
|
+
heading: hasChanges ? "\u2B50 Previous score" : "\u2B50 Score",
|
|
2139
|
+
alignment: "center"
|
|
2140
|
+
},
|
|
2141
|
+
{ heading: "\u2B50 Current score", alignment: "center" },
|
|
2142
|
+
{ heading: "\u{1F504} Score change", alignment: "center" }
|
|
2143
|
+
];
|
|
2144
|
+
return [
|
|
1889
2145
|
hasChanges ? columns : columns.slice(0, 2),
|
|
1890
2146
|
rows.map((row) => hasChanges ? row : row.slice(0, 2))
|
|
1891
|
-
|
|
2147
|
+
];
|
|
2148
|
+
}
|
|
2149
|
+
function createDiffDetailsSection(diff, level = HIERARCHY.level_2) {
|
|
2150
|
+
if (diff.groups.changed.length + diff.audits.changed.length === 0) {
|
|
2151
|
+
return null;
|
|
2152
|
+
}
|
|
2153
|
+
const summary = ["group", "audit"].map(
|
|
2154
|
+
(token) => summarizeDiffOutcomes(
|
|
2155
|
+
changesToDiffOutcomes(diff[`${token}s`].changed),
|
|
2156
|
+
token
|
|
2157
|
+
)
|
|
2158
|
+
).filter(Boolean).join(", ");
|
|
2159
|
+
const details2 = new MarkdownDocument5().$concat(
|
|
2160
|
+
createDiffGroupsSection(diff, level),
|
|
2161
|
+
createDiffAuditsSection(diff, level)
|
|
2162
|
+
);
|
|
2163
|
+
return new MarkdownDocument5().details(summary, details2);
|
|
1892
2164
|
}
|
|
1893
|
-
function createDiffGroupsSection(diff) {
|
|
2165
|
+
function createDiffGroupsSection(diff, level) {
|
|
1894
2166
|
if (diff.groups.changed.length + diff.groups.unchanged.length === 0) {
|
|
1895
2167
|
return null;
|
|
1896
2168
|
}
|
|
1897
|
-
return new
|
|
2169
|
+
return new MarkdownDocument5().heading(level, "\u{1F5C3}\uFE0F Groups").$concat(
|
|
1898
2170
|
createGroupsOrAuditsDetails(
|
|
1899
2171
|
"group",
|
|
1900
2172
|
diff.groups,
|
|
@@ -1915,8 +2187,8 @@ function createDiffGroupsSection(diff) {
|
|
|
1915
2187
|
)
|
|
1916
2188
|
);
|
|
1917
2189
|
}
|
|
1918
|
-
function createDiffAuditsSection(diff) {
|
|
1919
|
-
return new
|
|
2190
|
+
function createDiffAuditsSection(diff, level) {
|
|
2191
|
+
return new MarkdownDocument5().heading(level, "\u{1F6E1}\uFE0F Audits").$concat(
|
|
1920
2192
|
createGroupsOrAuditsDetails(
|
|
1921
2193
|
"audit",
|
|
1922
2194
|
diff.audits,
|
|
@@ -1931,7 +2203,7 @@ function createDiffAuditsSection(diff) {
|
|
|
1931
2203
|
formatTitle(audit.plugin),
|
|
1932
2204
|
formatTitle(audit),
|
|
1933
2205
|
`${scoreMarker(audit.scores.before, "square")} ${audit.displayValues.before || audit.values.before.toString()}`,
|
|
1934
|
-
|
|
2206
|
+
md6`${scoreMarker(audit.scores.after, "square")} ${md6.bold(
|
|
1935
2207
|
audit.displayValues.after || audit.values.after.toString()
|
|
1936
2208
|
)}`,
|
|
1937
2209
|
formatValueChange(audit)
|
|
@@ -1939,96 +2211,6 @@ function createDiffAuditsSection(diff) {
|
|
|
1939
2211
|
)
|
|
1940
2212
|
);
|
|
1941
2213
|
}
|
|
1942
|
-
function createGroupsOrAuditsDetails(token, { changed, unchanged }, ...[columns, rows]) {
|
|
1943
|
-
if (changed.length === 0) {
|
|
1944
|
-
return new MarkdownDocument4().paragraph(
|
|
1945
|
-
summarizeUnchanged(token, { changed, unchanged })
|
|
1946
|
-
);
|
|
1947
|
-
}
|
|
1948
|
-
return new MarkdownDocument4().details(
|
|
1949
|
-
summarizeDiffOutcomes(changesToDiffOutcomes(changed), token),
|
|
1950
|
-
md5`${md5.table(columns, rows.slice(0, MAX_ROWS))}${changed.length > MAX_ROWS ? md5.paragraph(
|
|
1951
|
-
md5.italic(
|
|
1952
|
-
`Only the ${MAX_ROWS} most affected ${pluralize(
|
|
1953
|
-
token
|
|
1954
|
-
)} are listed above for brevity.`
|
|
1955
|
-
)
|
|
1956
|
-
) : ""}${unchanged.length > 0 ? md5.paragraph(summarizeUnchanged(token, { changed, unchanged })) : ""}`
|
|
1957
|
-
);
|
|
1958
|
-
}
|
|
1959
|
-
function summarizeUnchanged(token, { changed, unchanged }) {
|
|
1960
|
-
return [
|
|
1961
|
-
changed.length > 0 ? pluralizeToken(`other ${token}`, unchanged.length) : `All of ${pluralizeToken(token, unchanged.length)}`,
|
|
1962
|
-
unchanged.length === 1 ? "is" : "are",
|
|
1963
|
-
"unchanged."
|
|
1964
|
-
].join(" ");
|
|
1965
|
-
}
|
|
1966
|
-
function summarizeDiffOutcomes(outcomes, token) {
|
|
1967
|
-
return objectToEntries(countDiffOutcomes(outcomes)).filter(
|
|
1968
|
-
(entry) => entry[0] !== "unchanged" && entry[1] > 0
|
|
1969
|
-
).map(([outcome, count]) => {
|
|
1970
|
-
const formattedCount = `<strong>${count}</strong> ${pluralize(
|
|
1971
|
-
token,
|
|
1972
|
-
count
|
|
1973
|
-
)}`;
|
|
1974
|
-
switch (outcome) {
|
|
1975
|
-
case "positive":
|
|
1976
|
-
return `\u{1F44D} ${formattedCount} improved`;
|
|
1977
|
-
case "negative":
|
|
1978
|
-
return `\u{1F44E} ${formattedCount} regressed`;
|
|
1979
|
-
case "mixed":
|
|
1980
|
-
return `${formattedCount} changed without impacting score`;
|
|
1981
|
-
}
|
|
1982
|
-
}).join(", ");
|
|
1983
|
-
}
|
|
1984
|
-
function formatTitle({
|
|
1985
|
-
title,
|
|
1986
|
-
docsUrl
|
|
1987
|
-
}) {
|
|
1988
|
-
if (docsUrl) {
|
|
1989
|
-
return md5.link(docsUrl, title);
|
|
1990
|
-
}
|
|
1991
|
-
return title;
|
|
1992
|
-
}
|
|
1993
|
-
function sortChanges(changes) {
|
|
1994
|
-
return [...changes].sort(
|
|
1995
|
-
(a, b) => Math.abs(b.scores.diff) - Math.abs(a.scores.diff) || Math.abs(b.values?.diff ?? 0) - Math.abs(a.values?.diff ?? 0)
|
|
1996
|
-
);
|
|
1997
|
-
}
|
|
1998
|
-
function changesToDiffOutcomes(changes) {
|
|
1999
|
-
return changes.map((change) => {
|
|
2000
|
-
if (change.scores.diff > 0) {
|
|
2001
|
-
return "positive";
|
|
2002
|
-
}
|
|
2003
|
-
if (change.scores.diff < 0) {
|
|
2004
|
-
return "negative";
|
|
2005
|
-
}
|
|
2006
|
-
if (change.values != null && change.values.diff !== 0) {
|
|
2007
|
-
return "mixed";
|
|
2008
|
-
}
|
|
2009
|
-
return "unchanged";
|
|
2010
|
-
});
|
|
2011
|
-
}
|
|
2012
|
-
function mergeDiffOutcomes(outcomes) {
|
|
2013
|
-
if (outcomes.every((outcome) => outcome === "unchanged")) {
|
|
2014
|
-
return "unchanged";
|
|
2015
|
-
}
|
|
2016
|
-
if (outcomes.includes("positive") && !outcomes.includes("negative")) {
|
|
2017
|
-
return "positive";
|
|
2018
|
-
}
|
|
2019
|
-
if (outcomes.includes("negative") && !outcomes.includes("positive")) {
|
|
2020
|
-
return "negative";
|
|
2021
|
-
}
|
|
2022
|
-
return "mixed";
|
|
2023
|
-
}
|
|
2024
|
-
function countDiffOutcomes(outcomes) {
|
|
2025
|
-
return {
|
|
2026
|
-
positive: outcomes.filter((outcome) => outcome === "positive").length,
|
|
2027
|
-
negative: outcomes.filter((outcome) => outcome === "negative").length,
|
|
2028
|
-
mixed: outcomes.filter((outcome) => outcome === "mixed").length,
|
|
2029
|
-
unchanged: outcomes.filter((outcome) => outcome === "unchanged").length
|
|
2030
|
-
};
|
|
2031
|
-
}
|
|
2032
2214
|
|
|
2033
2215
|
// packages/utils/src/lib/reports/load-report.ts
|
|
2034
2216
|
import { join as join2 } from "node:path";
|
|
@@ -2085,7 +2267,8 @@ function logPlugins(report) {
|
|
|
2085
2267
|
},
|
|
2086
2268
|
{
|
|
2087
2269
|
text: cyanBright(audit.displayValue || `${audit.value}`),
|
|
2088
|
-
|
|
2270
|
+
// eslint-disable-next-line no-magic-numbers
|
|
2271
|
+
width: 20,
|
|
2089
2272
|
padding: [0, 0, 0, 0]
|
|
2090
2273
|
}
|
|
2091
2274
|
]);
|
|
@@ -2238,7 +2421,7 @@ var verboseUtils = (verbose = false) => ({
|
|
|
2238
2421
|
|
|
2239
2422
|
// packages/core/package.json
|
|
2240
2423
|
var name = "@code-pushup/core";
|
|
2241
|
-
var version = "0.
|
|
2424
|
+
var version = "0.51.0";
|
|
2242
2425
|
|
|
2243
2426
|
// packages/core/src/lib/implementation/execute-plugin.ts
|
|
2244
2427
|
import { bold as bold5 } from "ansis";
|
|
@@ -2447,7 +2630,7 @@ async function persistReport(report, options) {
|
|
|
2447
2630
|
case "md":
|
|
2448
2631
|
return {
|
|
2449
2632
|
format: "md",
|
|
2450
|
-
content: generateMdReport(sortedScoredReport)
|
|
2633
|
+
content: generateMdReport(sortedScoredReport, { outputDir })
|
|
2451
2634
|
};
|
|
2452
2635
|
}
|
|
2453
2636
|
});
|
|
@@ -2634,7 +2817,7 @@ function selectMeta(meta) {
|
|
|
2634
2817
|
}
|
|
2635
2818
|
|
|
2636
2819
|
// packages/core/src/lib/compare.ts
|
|
2637
|
-
async function compareReportFiles(inputPaths, persistConfig, uploadConfig) {
|
|
2820
|
+
async function compareReportFiles(inputPaths, persistConfig, uploadConfig, label) {
|
|
2638
2821
|
const { outputDir, filename, format } = persistConfig;
|
|
2639
2822
|
const [reportBefore, reportAfter] = await Promise.all([
|
|
2640
2823
|
readJsonFile(inputPaths.before),
|
|
@@ -2644,12 +2827,20 @@ async function compareReportFiles(inputPaths, persistConfig, uploadConfig) {
|
|
|
2644
2827
|
before: reportSchema.parse(reportBefore),
|
|
2645
2828
|
after: reportSchema.parse(reportAfter)
|
|
2646
2829
|
};
|
|
2647
|
-
const
|
|
2648
|
-
|
|
2830
|
+
const diff = compareReports(reports);
|
|
2831
|
+
if (label) {
|
|
2832
|
+
diff.label = label;
|
|
2833
|
+
}
|
|
2834
|
+
if (uploadConfig && diff.commits) {
|
|
2835
|
+
diff.portalUrl = await fetchPortalComparisonLink(
|
|
2836
|
+
uploadConfig,
|
|
2837
|
+
diff.commits
|
|
2838
|
+
);
|
|
2839
|
+
}
|
|
2649
2840
|
return Promise.all(
|
|
2650
2841
|
format.map(async (fmt) => {
|
|
2651
2842
|
const outputPath = join5(outputDir, `${filename}-diff.${fmt}`);
|
|
2652
|
-
const content = reportsDiffToFileContent(
|
|
2843
|
+
const content = reportsDiffToFileContent(diff, fmt);
|
|
2653
2844
|
await ensureDirectoryExists(outputDir);
|
|
2654
2845
|
await writeFile2(outputPath, content);
|
|
2655
2846
|
return outputPath;
|
|
@@ -2679,12 +2870,12 @@ function compareReports(reports) {
|
|
|
2679
2870
|
duration
|
|
2680
2871
|
};
|
|
2681
2872
|
}
|
|
2682
|
-
function reportsDiffToFileContent(reportsDiff, format
|
|
2873
|
+
function reportsDiffToFileContent(reportsDiff, format) {
|
|
2683
2874
|
switch (format) {
|
|
2684
2875
|
case "json":
|
|
2685
2876
|
return JSON.stringify(reportsDiff, null, 2);
|
|
2686
2877
|
case "md":
|
|
2687
|
-
return generateMdReportsDiff(reportsDiff
|
|
2878
|
+
return generateMdReportsDiff(reportsDiff);
|
|
2688
2879
|
}
|
|
2689
2880
|
}
|
|
2690
2881
|
async function fetchPortalComparisonLink(uploadConfig, commits) {
|
|
@@ -2956,6 +3147,45 @@ async function autoloadRc(tsconfig) {
|
|
|
2956
3147
|
tsconfig
|
|
2957
3148
|
);
|
|
2958
3149
|
}
|
|
3150
|
+
|
|
3151
|
+
// packages/core/src/lib/merge-diffs.ts
|
|
3152
|
+
import { writeFile as writeFile3 } from "node:fs/promises";
|
|
3153
|
+
import { basename, dirname, join as join7 } from "node:path";
|
|
3154
|
+
async function mergeDiffs(files, persistConfig) {
|
|
3155
|
+
const results = await Promise.allSettled(
|
|
3156
|
+
files.map(async (file) => {
|
|
3157
|
+
const json = await readJsonFile(file).catch((error) => {
|
|
3158
|
+
throw new Error(
|
|
3159
|
+
`Failed to read JSON file ${file} - ${stringifyError(error)}`
|
|
3160
|
+
);
|
|
3161
|
+
});
|
|
3162
|
+
const result = await reportsDiffSchema.safeParseAsync(json);
|
|
3163
|
+
if (!result.success) {
|
|
3164
|
+
throw new Error(
|
|
3165
|
+
`Invalid reports diff in ${file} - ${result.error.message}`
|
|
3166
|
+
);
|
|
3167
|
+
}
|
|
3168
|
+
return { ...result.data, file };
|
|
3169
|
+
})
|
|
3170
|
+
);
|
|
3171
|
+
results.filter(isPromiseRejectedResult).forEach(({ reason }) => {
|
|
3172
|
+
ui().logger.warning(
|
|
3173
|
+
`Skipped invalid report diff - ${stringifyError(reason)}`
|
|
3174
|
+
);
|
|
3175
|
+
});
|
|
3176
|
+
const diffs = results.filter(isPromiseFulfilledResult).map(({ value }) => value);
|
|
3177
|
+
const labeledDiffs = diffs.map((diff) => ({
|
|
3178
|
+
...diff,
|
|
3179
|
+
label: diff.label || basename(dirname(diff.file))
|
|
3180
|
+
// fallback is parent folder name
|
|
3181
|
+
}));
|
|
3182
|
+
const markdown = generateMdReportsDiffForMonorepo(labeledDiffs);
|
|
3183
|
+
const { outputDir, filename } = persistConfig;
|
|
3184
|
+
const outputPath = join7(outputDir, `${filename}-diff.md`);
|
|
3185
|
+
await ensureDirectoryExists(outputDir);
|
|
3186
|
+
await writeFile3(outputPath, markdown);
|
|
3187
|
+
return outputPath;
|
|
3188
|
+
}
|
|
2959
3189
|
export {
|
|
2960
3190
|
ConfigPathError,
|
|
2961
3191
|
PersistDirError,
|
|
@@ -2969,6 +3199,7 @@ export {
|
|
|
2969
3199
|
executePlugin,
|
|
2970
3200
|
executePlugins,
|
|
2971
3201
|
history,
|
|
3202
|
+
mergeDiffs,
|
|
2972
3203
|
persistReport,
|
|
2973
3204
|
readRcByPath,
|
|
2974
3205
|
upload
|