@code-pushup/cli 0.49.0 → 0.50.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 +415 -170
- 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/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.middleware.d.ts +1 -1
- 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.middleware.d.ts +1 -1
- 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/README.md
CHANGED
|
@@ -268,12 +268,13 @@ Usage:
|
|
|
268
268
|
Description:
|
|
269
269
|
Compare 2 reports and produce a report diff file.
|
|
270
270
|
|
|
271
|
-
In addition to the [Common Command Options](#common-command-options), the following options are
|
|
271
|
+
In addition to the [Common Command Options](#common-command-options), the following options are recognized by the `compare` command:
|
|
272
272
|
|
|
273
|
-
| Option | Type | Description
|
|
274
|
-
| -------------- | -------- |
|
|
275
|
-
| **`--before`** | `string` | Path to source `report.json`.
|
|
276
|
-
| **`--after`** | `string` | Path to target `report.json`.
|
|
273
|
+
| Option | Required | Type | Description |
|
|
274
|
+
| -------------- | :------: | -------- | ----------------------------------- |
|
|
275
|
+
| **`--before`** | yes | `string` | Path to source `report.json`. |
|
|
276
|
+
| **`--after`** | yes | `string` | Path to target `report.json`. |
|
|
277
|
+
| **`--label`** | no | `string` | Label for diff (e.g. project name). |
|
|
277
278
|
|
|
278
279
|
#### `print-config` command
|
|
279
280
|
|
|
@@ -284,3 +285,17 @@ Description:
|
|
|
284
285
|
Print the resolved configuration.
|
|
285
286
|
|
|
286
287
|
Refer to the [Common Command Options](#common-command-options) for the list of available options.
|
|
288
|
+
|
|
289
|
+
### `merge-diffs` command
|
|
290
|
+
|
|
291
|
+
Usage:
|
|
292
|
+
`code-pushup merge-diffs --files PATH_1 PATH_2 ... [options]`
|
|
293
|
+
|
|
294
|
+
Description:
|
|
295
|
+
Combine multiple report diffs into a single `report-diff.md`.
|
|
296
|
+
|
|
297
|
+
In addition to the [Common Command Options](#common-command-options), the following options are recognized by the `merge-diffs` command:
|
|
298
|
+
|
|
299
|
+
| Option | Required | Type | Description |
|
|
300
|
+
| ------------- | :------: | ---------- | --------------------------------- |
|
|
301
|
+
| **`--files`** | yes | `string[]` | List of `report-diff.json` paths. |
|
package/index.js
CHANGED
|
@@ -683,6 +683,8 @@ var auditResultSchema = scorableWithPluginMetaSchema.merge(
|
|
|
683
683
|
);
|
|
684
684
|
var reportsDiffSchema = z15.object({
|
|
685
685
|
commits: makeComparisonSchema(commitSchema).nullable().describe("Commits identifying compared reports"),
|
|
686
|
+
portalUrl: urlSchema.optional().describe("Link to comparison page in Code PushUp portal"),
|
|
687
|
+
label: z15.string().optional().describe("Label (e.g. project name)"),
|
|
686
688
|
categories: makeArraysComparisonSchema(
|
|
687
689
|
categoryDiffSchema,
|
|
688
690
|
categoryResultSchema,
|
|
@@ -752,8 +754,24 @@ function comparePairs(pairs, equalsFn) {
|
|
|
752
754
|
);
|
|
753
755
|
}
|
|
754
756
|
|
|
757
|
+
// packages/utils/src/lib/errors.ts
|
|
758
|
+
function stringifyError(error) {
|
|
759
|
+
if (error instanceof Error) {
|
|
760
|
+
if (error.name === "Error" || error.message.startsWith(error.name)) {
|
|
761
|
+
return error.message;
|
|
762
|
+
}
|
|
763
|
+
return `${error.name}: ${error.message}`;
|
|
764
|
+
}
|
|
765
|
+
if (typeof error === "string") {
|
|
766
|
+
return error;
|
|
767
|
+
}
|
|
768
|
+
return JSON.stringify(error);
|
|
769
|
+
}
|
|
770
|
+
|
|
755
771
|
// packages/utils/src/lib/execute-process.ts
|
|
756
|
-
import {
|
|
772
|
+
import {
|
|
773
|
+
spawn
|
|
774
|
+
} from "node:child_process";
|
|
757
775
|
|
|
758
776
|
// packages/utils/src/lib/reports/utils.ts
|
|
759
777
|
import ansis from "ansis";
|
|
@@ -880,12 +898,12 @@ function countCategoryAudits(refs, plugins) {
|
|
|
880
898
|
}, 0);
|
|
881
899
|
}
|
|
882
900
|
function compareCategoryAuditsAndGroups(a, b) {
|
|
883
|
-
if (a.weight !== b.weight) {
|
|
884
|
-
return b.weight - a.weight;
|
|
885
|
-
}
|
|
886
901
|
if (a.score !== b.score) {
|
|
887
902
|
return a.score - b.score;
|
|
888
903
|
}
|
|
904
|
+
if (a.weight !== b.weight) {
|
|
905
|
+
return b.weight - a.weight;
|
|
906
|
+
}
|
|
889
907
|
if ("value" in a && "value" in b && a.value !== b.value) {
|
|
890
908
|
return b.value - a.value;
|
|
891
909
|
}
|
|
@@ -977,25 +995,29 @@ var ProcessError = class extends Error {
|
|
|
977
995
|
}
|
|
978
996
|
};
|
|
979
997
|
function executeProcess(cfg) {
|
|
980
|
-
const {
|
|
981
|
-
const { onStdout, onError, onComplete } = observer ?? {};
|
|
998
|
+
const { command: command2, args, observer, ignoreExitCode = false, ...options2 } = cfg;
|
|
999
|
+
const { onStdout, onStderr, onError, onComplete } = observer ?? {};
|
|
982
1000
|
const date = (/* @__PURE__ */ new Date()).toISOString();
|
|
983
1001
|
const start = performance.now();
|
|
984
1002
|
return new Promise((resolve, reject) => {
|
|
985
|
-
const
|
|
1003
|
+
const spawnedProcess = spawn(command2, args ?? [], {
|
|
1004
|
+
shell: true,
|
|
1005
|
+
...options2
|
|
1006
|
+
});
|
|
986
1007
|
let stdout = "";
|
|
987
1008
|
let stderr = "";
|
|
988
|
-
|
|
1009
|
+
spawnedProcess.stdout.on("data", (data) => {
|
|
989
1010
|
stdout += String(data);
|
|
990
|
-
onStdout?.(String(data));
|
|
1011
|
+
onStdout?.(String(data), spawnedProcess);
|
|
991
1012
|
});
|
|
992
|
-
|
|
1013
|
+
spawnedProcess.stderr.on("data", (data) => {
|
|
993
1014
|
stderr += String(data);
|
|
1015
|
+
onStderr?.(String(data), spawnedProcess);
|
|
994
1016
|
});
|
|
995
|
-
|
|
1017
|
+
spawnedProcess.on("error", (err) => {
|
|
996
1018
|
stderr += err.toString();
|
|
997
1019
|
});
|
|
998
|
-
|
|
1020
|
+
spawnedProcess.on("close", (code2) => {
|
|
999
1021
|
const timings = { date, duration: calcDuration(start) };
|
|
1000
1022
|
if (code2 === 0 || ignoreExitCode) {
|
|
1001
1023
|
onComplete?.();
|
|
@@ -1569,7 +1591,10 @@ function getColumnAlignments(tableData) {
|
|
|
1569
1591
|
}
|
|
1570
1592
|
|
|
1571
1593
|
// packages/utils/src/lib/reports/formatting.ts
|
|
1572
|
-
import {
|
|
1594
|
+
import {
|
|
1595
|
+
MarkdownDocument,
|
|
1596
|
+
md as md2
|
|
1597
|
+
} from "build-md";
|
|
1573
1598
|
function tableSection(tableData, options2) {
|
|
1574
1599
|
if (tableData.rows.length === 0) {
|
|
1575
1600
|
return null;
|
|
@@ -1890,17 +1915,17 @@ function pluginMetaTable({
|
|
|
1890
1915
|
{ heading: "Version", alignment: "center" },
|
|
1891
1916
|
{ heading: "Duration", alignment: "right" }
|
|
1892
1917
|
],
|
|
1893
|
-
plugins.map(({ title, audits, version:
|
|
1918
|
+
plugins.map(({ title, audits, version: version3 = "", duration }) => [
|
|
1894
1919
|
title,
|
|
1895
1920
|
audits.length.toString(),
|
|
1896
|
-
|
|
1921
|
+
version3 && md4.code(version3),
|
|
1897
1922
|
formatDuration(duration)
|
|
1898
1923
|
])
|
|
1899
1924
|
];
|
|
1900
1925
|
}
|
|
1901
1926
|
function reportMetaTable({
|
|
1902
1927
|
commit,
|
|
1903
|
-
version:
|
|
1928
|
+
version: version3,
|
|
1904
1929
|
duration,
|
|
1905
1930
|
plugins,
|
|
1906
1931
|
categories
|
|
@@ -1917,7 +1942,7 @@ function reportMetaTable({
|
|
|
1917
1942
|
[
|
|
1918
1943
|
[
|
|
1919
1944
|
commit ? `${commit.message} (${commit.hash})` : "N/A",
|
|
1920
|
-
md4.code(
|
|
1945
|
+
md4.code(version3),
|
|
1921
1946
|
formatDuration(duration),
|
|
1922
1947
|
plugins.length.toString(),
|
|
1923
1948
|
categories.length.toString(),
|
|
@@ -1929,19 +1954,111 @@ function reportMetaTable({
|
|
|
1929
1954
|
|
|
1930
1955
|
// packages/utils/src/lib/reports/generate-md-reports-diff.ts
|
|
1931
1956
|
import {
|
|
1932
|
-
MarkdownDocument as
|
|
1933
|
-
md as
|
|
1957
|
+
MarkdownDocument as MarkdownDocument5,
|
|
1958
|
+
md as md6
|
|
1934
1959
|
} from "build-md";
|
|
1960
|
+
|
|
1961
|
+
// packages/utils/src/lib/reports/generate-md-reports-diff-utils.ts
|
|
1962
|
+
import { MarkdownDocument as MarkdownDocument4, md as md5 } from "build-md";
|
|
1935
1963
|
var MAX_ROWS = 100;
|
|
1936
|
-
function
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
).
|
|
1964
|
+
function summarizeUnchanged(token, { changed, unchanged }) {
|
|
1965
|
+
const pluralizedCount = changed.length > 0 ? pluralizeToken(`other ${token}`, unchanged.length) : `All of ${pluralizeToken(token, unchanged.length)}`;
|
|
1966
|
+
const pluralizedVerb = unchanged.length === 1 ? "is" : "are";
|
|
1967
|
+
return `${pluralizedCount} ${pluralizedVerb} unchanged.`;
|
|
1968
|
+
}
|
|
1969
|
+
function summarizeDiffOutcomes(outcomes, token) {
|
|
1970
|
+
return objectToEntries(countDiffOutcomes(outcomes)).filter(
|
|
1971
|
+
(entry) => entry[0] !== "unchanged" && entry[1] > 0
|
|
1972
|
+
).map(([outcome, count]) => {
|
|
1973
|
+
const formattedCount = `<strong>${count}</strong> ${pluralize(
|
|
1974
|
+
token,
|
|
1975
|
+
count
|
|
1976
|
+
)}`;
|
|
1977
|
+
switch (outcome) {
|
|
1978
|
+
case "positive":
|
|
1979
|
+
return `\u{1F44D} ${formattedCount} improved`;
|
|
1980
|
+
case "negative":
|
|
1981
|
+
return `\u{1F44E} ${formattedCount} regressed`;
|
|
1982
|
+
case "mixed":
|
|
1983
|
+
return `${formattedCount} changed without impacting score`;
|
|
1984
|
+
}
|
|
1985
|
+
}).join(", ");
|
|
1986
|
+
}
|
|
1987
|
+
function createGroupsOrAuditsDetails(token, { changed, unchanged }, ...[columns, rows]) {
|
|
1988
|
+
if (changed.length === 0) {
|
|
1989
|
+
return new MarkdownDocument4().paragraph(
|
|
1990
|
+
summarizeUnchanged(token, { changed, unchanged })
|
|
1991
|
+
);
|
|
1992
|
+
}
|
|
1993
|
+
return new MarkdownDocument4().table(columns, rows.slice(0, MAX_ROWS)).paragraph(
|
|
1994
|
+
changed.length > MAX_ROWS && md5.italic(
|
|
1995
|
+
`Only the ${MAX_ROWS} most affected ${pluralize(
|
|
1996
|
+
token
|
|
1997
|
+
)} are listed above for brevity.`
|
|
1998
|
+
)
|
|
1999
|
+
).paragraph(
|
|
2000
|
+
unchanged.length > 0 && summarizeUnchanged(token, { changed, unchanged })
|
|
2001
|
+
);
|
|
2002
|
+
}
|
|
2003
|
+
function formatTitle({
|
|
2004
|
+
title,
|
|
2005
|
+
docsUrl
|
|
2006
|
+
}) {
|
|
2007
|
+
if (docsUrl) {
|
|
2008
|
+
return md5.link(docsUrl, title);
|
|
2009
|
+
}
|
|
2010
|
+
return title;
|
|
2011
|
+
}
|
|
2012
|
+
function formatPortalLink(portalUrl) {
|
|
2013
|
+
return portalUrl && md5.link(portalUrl, "\u{1F575}\uFE0F See full comparison in Code PushUp portal \u{1F50D}");
|
|
2014
|
+
}
|
|
2015
|
+
function sortChanges(changes) {
|
|
2016
|
+
return [...changes].sort(
|
|
2017
|
+
(a, b) => Math.abs(b.scores.diff) - Math.abs(a.scores.diff) || Math.abs(b.values?.diff ?? 0) - Math.abs(a.values?.diff ?? 0)
|
|
2018
|
+
);
|
|
2019
|
+
}
|
|
2020
|
+
function getDiffChanges(diff) {
|
|
2021
|
+
return [
|
|
2022
|
+
...diff.categories.changed,
|
|
2023
|
+
...diff.groups.changed,
|
|
2024
|
+
...diff.audits.changed
|
|
2025
|
+
];
|
|
2026
|
+
}
|
|
2027
|
+
function changesToDiffOutcomes(changes) {
|
|
2028
|
+
return changes.map((change) => {
|
|
2029
|
+
if (change.scores.diff > 0) {
|
|
2030
|
+
return "positive";
|
|
2031
|
+
}
|
|
2032
|
+
if (change.scores.diff < 0) {
|
|
2033
|
+
return "negative";
|
|
2034
|
+
}
|
|
2035
|
+
if (change.values != null && change.values.diff !== 0) {
|
|
2036
|
+
return "mixed";
|
|
2037
|
+
}
|
|
2038
|
+
return "unchanged";
|
|
2039
|
+
});
|
|
2040
|
+
}
|
|
2041
|
+
function mergeDiffOutcomes(outcomes) {
|
|
2042
|
+
if (outcomes.every((outcome) => outcome === "unchanged")) {
|
|
2043
|
+
return "unchanged";
|
|
2044
|
+
}
|
|
2045
|
+
if (outcomes.includes("positive") && !outcomes.includes("negative")) {
|
|
2046
|
+
return "positive";
|
|
2047
|
+
}
|
|
2048
|
+
if (outcomes.includes("negative") && !outcomes.includes("positive")) {
|
|
2049
|
+
return "negative";
|
|
2050
|
+
}
|
|
2051
|
+
return "mixed";
|
|
1943
2052
|
}
|
|
1944
|
-
function
|
|
2053
|
+
function countDiffOutcomes(outcomes) {
|
|
2054
|
+
return {
|
|
2055
|
+
positive: outcomes.filter((outcome) => outcome === "positive").length,
|
|
2056
|
+
negative: outcomes.filter((outcome) => outcome === "negative").length,
|
|
2057
|
+
mixed: outcomes.filter((outcome) => outcome === "mixed").length,
|
|
2058
|
+
unchanged: outcomes.filter((outcome) => outcome === "unchanged").length
|
|
2059
|
+
};
|
|
2060
|
+
}
|
|
2061
|
+
function formatReportOutcome(outcome, commits) {
|
|
1945
2062
|
const outcomeTexts = {
|
|
1946
2063
|
positive: md5`🥳 Code PushUp report has ${md5.bold("improved")}`,
|
|
1947
2064
|
negative: md5`😟 Code PushUp report has ${md5.bold("regressed")}`,
|
|
@@ -1950,27 +2067,91 @@ function createDiffHeaderSection(diff, portalUrl) {
|
|
|
1950
2067
|
)}`,
|
|
1951
2068
|
unchanged: md5`😐 Code PushUp report is ${md5.bold("unchanged")}`
|
|
1952
2069
|
};
|
|
2070
|
+
if (commits) {
|
|
2071
|
+
const commitsText = `compared target commit ${commits.after.hash} with source commit ${commits.before.hash}`;
|
|
2072
|
+
return md5`${outcomeTexts[outcome]} – ${commitsText}.`;
|
|
2073
|
+
}
|
|
2074
|
+
return md5`${outcomeTexts[outcome]}.`;
|
|
2075
|
+
}
|
|
2076
|
+
function compareDiffsBy(type, a, b) {
|
|
2077
|
+
return sumScoreChanges(b[type].changed) - sumScoreChanges(a[type].changed) || sumConfigChanges(b[type]) - sumConfigChanges(a[type]);
|
|
2078
|
+
}
|
|
2079
|
+
function sumScoreChanges(changes) {
|
|
2080
|
+
return changes.reduce(
|
|
2081
|
+
(acc, { scores }) => acc + Math.abs(scores.diff),
|
|
2082
|
+
0
|
|
2083
|
+
);
|
|
2084
|
+
}
|
|
2085
|
+
function sumConfigChanges({
|
|
2086
|
+
added,
|
|
2087
|
+
removed
|
|
2088
|
+
}) {
|
|
2089
|
+
return added.length + removed.length;
|
|
2090
|
+
}
|
|
2091
|
+
|
|
2092
|
+
// packages/utils/src/lib/reports/generate-md-reports-diff.ts
|
|
2093
|
+
function generateMdReportsDiff(diff) {
|
|
2094
|
+
return new MarkdownDocument5().$concat(
|
|
2095
|
+
createDiffHeaderSection(diff),
|
|
2096
|
+
createDiffCategoriesSection(diff),
|
|
2097
|
+
createDiffDetailsSection(diff)
|
|
2098
|
+
).toString();
|
|
2099
|
+
}
|
|
2100
|
+
function generateMdReportsDiffForMonorepo(diffs) {
|
|
2101
|
+
const diffsWithOutcomes = diffs.map((diff) => ({
|
|
2102
|
+
...diff,
|
|
2103
|
+
outcome: mergeDiffOutcomes(changesToDiffOutcomes(getDiffChanges(diff)))
|
|
2104
|
+
})).sort(
|
|
2105
|
+
(a, b) => compareDiffsBy("categories", a, b) || compareDiffsBy("groups", a, b) || compareDiffsBy("audits", a, b) || a.label.localeCompare(b.label)
|
|
2106
|
+
);
|
|
2107
|
+
const unchanged = diffsWithOutcomes.filter(
|
|
2108
|
+
({ outcome }) => outcome === "unchanged"
|
|
2109
|
+
);
|
|
2110
|
+
const changed = diffsWithOutcomes.filter((diff) => !unchanged.includes(diff));
|
|
2111
|
+
return new MarkdownDocument5().$concat(
|
|
2112
|
+
createDiffHeaderSection(diffs),
|
|
2113
|
+
...changed.map(createDiffProjectSection)
|
|
2114
|
+
).$if(
|
|
2115
|
+
unchanged.length > 0,
|
|
2116
|
+
(doc) => doc.rule().paragraph(summarizeUnchanged("project", { unchanged, changed }))
|
|
2117
|
+
).toString();
|
|
2118
|
+
}
|
|
2119
|
+
function createDiffHeaderSection(diff) {
|
|
1953
2120
|
const outcome = mergeDiffOutcomes(
|
|
1954
|
-
changesToDiffOutcomes(
|
|
1955
|
-
...diff.categories.changed,
|
|
1956
|
-
...diff.groups.changed,
|
|
1957
|
-
...diff.audits.changed
|
|
1958
|
-
])
|
|
2121
|
+
changesToDiffOutcomes(toArray(diff).flatMap(getDiffChanges))
|
|
1959
2122
|
);
|
|
1960
|
-
const
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
2123
|
+
const commits = Array.isArray(diff) ? diff[0]?.commits : diff.commits;
|
|
2124
|
+
const portalUrl = Array.isArray(diff) ? void 0 : diff.portalUrl;
|
|
2125
|
+
return new MarkdownDocument5().heading(HIERARCHY.level_1, "Code PushUp").paragraph(formatReportOutcome(outcome, commits)).paragraph(formatPortalLink(portalUrl));
|
|
2126
|
+
}
|
|
2127
|
+
function createDiffProjectSection(diff) {
|
|
2128
|
+
return new MarkdownDocument5().heading(HIERARCHY.level_2, md6`💼 Project ${md6.code(diff.label)}`).paragraph(formatReportOutcome(diff.outcome)).paragraph(formatPortalLink(diff.portalUrl)).$concat(
|
|
2129
|
+
createDiffCategoriesSection(diff, {
|
|
2130
|
+
skipHeading: true,
|
|
2131
|
+
skipUnchanged: true
|
|
2132
|
+
}),
|
|
2133
|
+
createDiffDetailsSection(diff, HIERARCHY.level_3)
|
|
1965
2134
|
);
|
|
1966
2135
|
}
|
|
1967
|
-
function createDiffCategoriesSection(diff) {
|
|
2136
|
+
function createDiffCategoriesSection(diff, options2) {
|
|
1968
2137
|
const { changed, unchanged, added } = diff.categories;
|
|
2138
|
+
const { skipHeading, skipUnchanged } = options2 ?? {};
|
|
1969
2139
|
const categoriesCount = changed.length + unchanged.length + added.length;
|
|
1970
2140
|
const hasChanges = unchanged.length < categoriesCount;
|
|
1971
2141
|
if (categoriesCount === 0) {
|
|
1972
2142
|
return null;
|
|
1973
2143
|
}
|
|
2144
|
+
const [columns, rows] = createCategoriesTable(diff, {
|
|
2145
|
+
hasChanges,
|
|
2146
|
+
skipUnchanged
|
|
2147
|
+
});
|
|
2148
|
+
return new MarkdownDocument5().heading(HIERARCHY.level_2, !skipHeading && "\u{1F3F7}\uFE0F Categories").table(columns, rows).paragraph(added.length > 0 && md6.italic("(\\*) New category.")).paragraph(
|
|
2149
|
+
skipUnchanged && unchanged.length > 0 && summarizeUnchanged("category", { changed, unchanged })
|
|
2150
|
+
);
|
|
2151
|
+
}
|
|
2152
|
+
function createCategoriesTable(diff, options2) {
|
|
2153
|
+
const { changed, unchanged, added } = diff.categories;
|
|
2154
|
+
const { hasChanges, skipUnchanged } = options2;
|
|
1974
2155
|
const columns = [
|
|
1975
2156
|
{ heading: "\u{1F3F7}\uFE0F Category", alignment: "left" },
|
|
1976
2157
|
{
|
|
@@ -1991,27 +2172,43 @@ function createDiffCategoriesSection(diff) {
|
|
|
1991
2172
|
]),
|
|
1992
2173
|
...added.map((category) => [
|
|
1993
2174
|
formatTitle(category),
|
|
1994
|
-
|
|
2175
|
+
md6.italic("n/a (\\*)"),
|
|
1995
2176
|
formatScoreWithColor(category.score),
|
|
1996
|
-
|
|
2177
|
+
md6.italic("n/a (\\*)")
|
|
1997
2178
|
]),
|
|
1998
|
-
...unchanged.map((category) => [
|
|
2179
|
+
...skipUnchanged ? [] : unchanged.map((category) => [
|
|
1999
2180
|
formatTitle(category),
|
|
2000
2181
|
formatScoreWithColor(category.score, { skipBold: true }),
|
|
2001
2182
|
formatScoreWithColor(category.score),
|
|
2002
2183
|
"\u2013"
|
|
2003
2184
|
])
|
|
2004
2185
|
];
|
|
2005
|
-
return
|
|
2186
|
+
return [
|
|
2006
2187
|
hasChanges ? columns : columns.slice(0, 2),
|
|
2007
2188
|
rows.map((row) => hasChanges ? row : row.slice(0, 2))
|
|
2008
|
-
|
|
2189
|
+
];
|
|
2190
|
+
}
|
|
2191
|
+
function createDiffDetailsSection(diff, level = HIERARCHY.level_2) {
|
|
2192
|
+
if (diff.groups.changed.length + diff.audits.changed.length === 0) {
|
|
2193
|
+
return null;
|
|
2194
|
+
}
|
|
2195
|
+
const summary = ["group", "audit"].map(
|
|
2196
|
+
(token) => summarizeDiffOutcomes(
|
|
2197
|
+
changesToDiffOutcomes(diff[`${token}s`].changed),
|
|
2198
|
+
token
|
|
2199
|
+
)
|
|
2200
|
+
).filter(Boolean).join(", ");
|
|
2201
|
+
const details2 = new MarkdownDocument5().$concat(
|
|
2202
|
+
createDiffGroupsSection(diff, level),
|
|
2203
|
+
createDiffAuditsSection(diff, level)
|
|
2204
|
+
);
|
|
2205
|
+
return new MarkdownDocument5().details(summary, details2);
|
|
2009
2206
|
}
|
|
2010
|
-
function createDiffGroupsSection(diff) {
|
|
2207
|
+
function createDiffGroupsSection(diff, level) {
|
|
2011
2208
|
if (diff.groups.changed.length + diff.groups.unchanged.length === 0) {
|
|
2012
2209
|
return null;
|
|
2013
2210
|
}
|
|
2014
|
-
return new
|
|
2211
|
+
return new MarkdownDocument5().heading(level, "\u{1F5C3}\uFE0F Groups").$concat(
|
|
2015
2212
|
createGroupsOrAuditsDetails(
|
|
2016
2213
|
"group",
|
|
2017
2214
|
diff.groups,
|
|
@@ -2032,8 +2229,8 @@ function createDiffGroupsSection(diff) {
|
|
|
2032
2229
|
)
|
|
2033
2230
|
);
|
|
2034
2231
|
}
|
|
2035
|
-
function createDiffAuditsSection(diff) {
|
|
2036
|
-
return new
|
|
2232
|
+
function createDiffAuditsSection(diff, level) {
|
|
2233
|
+
return new MarkdownDocument5().heading(level, "\u{1F6E1}\uFE0F Audits").$concat(
|
|
2037
2234
|
createGroupsOrAuditsDetails(
|
|
2038
2235
|
"audit",
|
|
2039
2236
|
diff.audits,
|
|
@@ -2048,7 +2245,7 @@ function createDiffAuditsSection(diff) {
|
|
|
2048
2245
|
formatTitle(audit.plugin),
|
|
2049
2246
|
formatTitle(audit),
|
|
2050
2247
|
`${scoreMarker(audit.scores.before, "square")} ${audit.displayValues.before || audit.values.before.toString()}`,
|
|
2051
|
-
|
|
2248
|
+
md6`${scoreMarker(audit.scores.after, "square")} ${md6.bold(
|
|
2052
2249
|
audit.displayValues.after || audit.values.after.toString()
|
|
2053
2250
|
)}`,
|
|
2054
2251
|
formatValueChange(audit)
|
|
@@ -2056,96 +2253,6 @@ function createDiffAuditsSection(diff) {
|
|
|
2056
2253
|
)
|
|
2057
2254
|
);
|
|
2058
2255
|
}
|
|
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
2256
|
|
|
2150
2257
|
// packages/utils/src/lib/reports/load-report.ts
|
|
2151
2258
|
import { join as join2 } from "node:path";
|
|
@@ -2178,8 +2285,8 @@ function logStdoutSummary(report) {
|
|
|
2178
2285
|
log();
|
|
2179
2286
|
}
|
|
2180
2287
|
function reportToHeaderSection(report) {
|
|
2181
|
-
const { packageName, version:
|
|
2182
|
-
return `${bold4(REPORT_HEADLINE_TEXT)} - ${packageName}@${
|
|
2288
|
+
const { packageName, version: version3 } = report;
|
|
2289
|
+
return `${bold4(REPORT_HEADLINE_TEXT)} - ${packageName}@${version3}`;
|
|
2183
2290
|
}
|
|
2184
2291
|
function logPlugins(report) {
|
|
2185
2292
|
const { plugins } = report;
|
|
@@ -2202,7 +2309,8 @@ function logPlugins(report) {
|
|
|
2202
2309
|
},
|
|
2203
2310
|
{
|
|
2204
2311
|
text: cyanBright(audit.displayValue || `${audit.value}`),
|
|
2205
|
-
|
|
2312
|
+
// eslint-disable-next-line no-magic-numbers
|
|
2313
|
+
width: 20,
|
|
2206
2314
|
padding: [0, 0, 0, 0]
|
|
2207
2315
|
}
|
|
2208
2316
|
]);
|
|
@@ -2355,7 +2463,7 @@ var verboseUtils = (verbose = false) => ({
|
|
|
2355
2463
|
|
|
2356
2464
|
// packages/core/package.json
|
|
2357
2465
|
var name = "@code-pushup/core";
|
|
2358
|
-
var version = "0.
|
|
2466
|
+
var version = "0.50.0";
|
|
2359
2467
|
|
|
2360
2468
|
// packages/core/src/lib/implementation/execute-plugin.ts
|
|
2361
2469
|
import { bold as bold5 } from "ansis";
|
|
@@ -2751,7 +2859,7 @@ function selectMeta(meta) {
|
|
|
2751
2859
|
}
|
|
2752
2860
|
|
|
2753
2861
|
// packages/core/src/lib/compare.ts
|
|
2754
|
-
async function compareReportFiles(inputPaths, persistConfig, uploadConfig) {
|
|
2862
|
+
async function compareReportFiles(inputPaths, persistConfig, uploadConfig, label) {
|
|
2755
2863
|
const { outputDir, filename, format } = persistConfig;
|
|
2756
2864
|
const [reportBefore, reportAfter] = await Promise.all([
|
|
2757
2865
|
readJsonFile(inputPaths.before),
|
|
@@ -2761,12 +2869,20 @@ async function compareReportFiles(inputPaths, persistConfig, uploadConfig) {
|
|
|
2761
2869
|
before: reportSchema.parse(reportBefore),
|
|
2762
2870
|
after: reportSchema.parse(reportAfter)
|
|
2763
2871
|
};
|
|
2764
|
-
const
|
|
2765
|
-
|
|
2872
|
+
const diff = compareReports(reports);
|
|
2873
|
+
if (label) {
|
|
2874
|
+
diff.label = label;
|
|
2875
|
+
}
|
|
2876
|
+
if (uploadConfig && diff.commits) {
|
|
2877
|
+
diff.portalUrl = await fetchPortalComparisonLink(
|
|
2878
|
+
uploadConfig,
|
|
2879
|
+
diff.commits
|
|
2880
|
+
);
|
|
2881
|
+
}
|
|
2766
2882
|
return Promise.all(
|
|
2767
2883
|
format.map(async (fmt) => {
|
|
2768
2884
|
const outputPath = join5(outputDir, `${filename}-diff.${fmt}`);
|
|
2769
|
-
const content = reportsDiffToFileContent(
|
|
2885
|
+
const content = reportsDiffToFileContent(diff, fmt);
|
|
2770
2886
|
await ensureDirectoryExists(outputDir);
|
|
2771
2887
|
await writeFile2(outputPath, content);
|
|
2772
2888
|
return outputPath;
|
|
@@ -2796,12 +2912,12 @@ function compareReports(reports) {
|
|
|
2796
2912
|
duration
|
|
2797
2913
|
};
|
|
2798
2914
|
}
|
|
2799
|
-
function reportsDiffToFileContent(reportsDiff, format
|
|
2915
|
+
function reportsDiffToFileContent(reportsDiff, format) {
|
|
2800
2916
|
switch (format) {
|
|
2801
2917
|
case "json":
|
|
2802
2918
|
return JSON.stringify(reportsDiff, null, 2);
|
|
2803
2919
|
case "md":
|
|
2804
|
-
return generateMdReportsDiff(reportsDiff
|
|
2920
|
+
return generateMdReportsDiff(reportsDiff);
|
|
2805
2921
|
}
|
|
2806
2922
|
}
|
|
2807
2923
|
async function fetchPortalComparisonLink(uploadConfig, commits) {
|
|
@@ -3074,6 +3190,45 @@ async function autoloadRc(tsconfig) {
|
|
|
3074
3190
|
);
|
|
3075
3191
|
}
|
|
3076
3192
|
|
|
3193
|
+
// packages/core/src/lib/merge-diffs.ts
|
|
3194
|
+
import { writeFile as writeFile3 } from "node:fs/promises";
|
|
3195
|
+
import { basename, dirname, join as join7 } from "node:path";
|
|
3196
|
+
async function mergeDiffs(files, persistConfig) {
|
|
3197
|
+
const results = await Promise.allSettled(
|
|
3198
|
+
files.map(async (file) => {
|
|
3199
|
+
const json = await readJsonFile(file).catch((error) => {
|
|
3200
|
+
throw new Error(
|
|
3201
|
+
`Failed to read JSON file ${file} - ${stringifyError(error)}`
|
|
3202
|
+
);
|
|
3203
|
+
});
|
|
3204
|
+
const result = await reportsDiffSchema.safeParseAsync(json);
|
|
3205
|
+
if (!result.success) {
|
|
3206
|
+
throw new Error(
|
|
3207
|
+
`Invalid reports diff in ${file} - ${result.error.message}`
|
|
3208
|
+
);
|
|
3209
|
+
}
|
|
3210
|
+
return { ...result.data, file };
|
|
3211
|
+
})
|
|
3212
|
+
);
|
|
3213
|
+
results.filter(isPromiseRejectedResult).forEach(({ reason }) => {
|
|
3214
|
+
ui().logger.warning(
|
|
3215
|
+
`Skipped invalid report diff - ${stringifyError(reason)}`
|
|
3216
|
+
);
|
|
3217
|
+
});
|
|
3218
|
+
const diffs = results.filter(isPromiseFulfilledResult).map(({ value }) => value);
|
|
3219
|
+
const labeledDiffs = diffs.map((diff) => ({
|
|
3220
|
+
...diff,
|
|
3221
|
+
label: diff.label || basename(dirname(diff.file))
|
|
3222
|
+
// fallback is parent folder name
|
|
3223
|
+
}));
|
|
3224
|
+
const markdown = generateMdReportsDiffForMonorepo(labeledDiffs);
|
|
3225
|
+
const { outputDir, filename } = persistConfig;
|
|
3226
|
+
const outputPath = join7(outputDir, `${filename}-diff.md`);
|
|
3227
|
+
await ensureDirectoryExists(outputDir);
|
|
3228
|
+
await writeFile3(outputPath, markdown);
|
|
3229
|
+
return outputPath;
|
|
3230
|
+
}
|
|
3231
|
+
|
|
3077
3232
|
// packages/cli/src/lib/constants.ts
|
|
3078
3233
|
var CLI_NAME = "Code PushUp CLI";
|
|
3079
3234
|
var CLI_SCRIPT_NAME = "code-pushup";
|
|
@@ -3207,6 +3362,10 @@ function yargsCompareOptionsDefinition() {
|
|
|
3207
3362
|
describe: "Path to target report.json",
|
|
3208
3363
|
type: "string",
|
|
3209
3364
|
demandOption: true
|
|
3365
|
+
},
|
|
3366
|
+
label: {
|
|
3367
|
+
describe: "Label for diff (e.g. project name)",
|
|
3368
|
+
type: "string"
|
|
3210
3369
|
}
|
|
3211
3370
|
};
|
|
3212
3371
|
}
|
|
@@ -3222,11 +3381,12 @@ function yargsCompareCommandObject() {
|
|
|
3222
3381
|
ui().logger.log(bold9(CLI_NAME));
|
|
3223
3382
|
ui().logger.info(gray6(`Run ${command2}...`));
|
|
3224
3383
|
const options2 = args;
|
|
3225
|
-
const { before, after, persist, upload: upload2 } = options2;
|
|
3384
|
+
const { before, after, label, persist, upload: upload2 } = options2;
|
|
3226
3385
|
const outputPaths = await compareReportFiles(
|
|
3227
3386
|
{ before, after },
|
|
3228
3387
|
persist,
|
|
3229
|
-
upload2
|
|
3388
|
+
upload2,
|
|
3389
|
+
label
|
|
3230
3390
|
);
|
|
3231
3391
|
ui().logger.info(
|
|
3232
3392
|
`Reports diff written to ${outputPaths.map((path) => bold9(path)).join(" and ")}`
|
|
@@ -3412,6 +3572,38 @@ function yargsHistoryCommandObject() {
|
|
|
3412
3572
|
};
|
|
3413
3573
|
}
|
|
3414
3574
|
|
|
3575
|
+
// packages/cli/src/lib/merge-diffs/merge-diffs-command.ts
|
|
3576
|
+
import { bold as bold11, gray as gray8 } from "ansis";
|
|
3577
|
+
|
|
3578
|
+
// packages/cli/src/lib/implementation/merge-diffs.options.ts
|
|
3579
|
+
function yargsMergeDiffsOptionsDefinition() {
|
|
3580
|
+
return {
|
|
3581
|
+
files: {
|
|
3582
|
+
describe: "List of report-diff.json paths",
|
|
3583
|
+
type: "array",
|
|
3584
|
+
demandOption: true
|
|
3585
|
+
}
|
|
3586
|
+
};
|
|
3587
|
+
}
|
|
3588
|
+
|
|
3589
|
+
// packages/cli/src/lib/merge-diffs/merge-diffs-command.ts
|
|
3590
|
+
function yargsMergeDiffsCommandObject() {
|
|
3591
|
+
const command2 = "merge-diffs";
|
|
3592
|
+
return {
|
|
3593
|
+
command: command2,
|
|
3594
|
+
describe: "Combine many report diffs into a single diff file",
|
|
3595
|
+
builder: yargsMergeDiffsOptionsDefinition(),
|
|
3596
|
+
handler: async (args) => {
|
|
3597
|
+
ui().logger.log(bold11(CLI_NAME));
|
|
3598
|
+
ui().logger.info(gray8(`Run ${command2}...`));
|
|
3599
|
+
const options2 = args;
|
|
3600
|
+
const { files, persist } = options2;
|
|
3601
|
+
const outputPath = await mergeDiffs(files, persist);
|
|
3602
|
+
ui().logger.info(`Reports diff written to ${bold11(outputPath)}`);
|
|
3603
|
+
}
|
|
3604
|
+
};
|
|
3605
|
+
}
|
|
3606
|
+
|
|
3415
3607
|
// packages/cli/src/lib/print-config/print-config-command.ts
|
|
3416
3608
|
function yargsConfigCommandObject() {
|
|
3417
3609
|
const command2 = "print-config";
|
|
@@ -3427,15 +3619,15 @@ function yargsConfigCommandObject() {
|
|
|
3427
3619
|
}
|
|
3428
3620
|
|
|
3429
3621
|
// packages/cli/src/lib/upload/upload-command.ts
|
|
3430
|
-
import { bold as
|
|
3622
|
+
import { bold as bold12, gray as gray9 } from "ansis";
|
|
3431
3623
|
function yargsUploadCommandObject() {
|
|
3432
3624
|
const command2 = "upload";
|
|
3433
3625
|
return {
|
|
3434
3626
|
command: command2,
|
|
3435
3627
|
describe: "Upload report results to the portal",
|
|
3436
3628
|
handler: async (args) => {
|
|
3437
|
-
ui().logger.log(
|
|
3438
|
-
ui().logger.info(
|
|
3629
|
+
ui().logger.log(bold12(CLI_NAME));
|
|
3630
|
+
ui().logger.info(gray9(`Run ${command2}...`));
|
|
3439
3631
|
const options2 = args;
|
|
3440
3632
|
if (options2.upload == null) {
|
|
3441
3633
|
renderIntegratePortalHint();
|
|
@@ -3458,7 +3650,8 @@ var commands = [
|
|
|
3458
3650
|
yargsUploadCommandObject(),
|
|
3459
3651
|
yargsHistoryCommandObject(),
|
|
3460
3652
|
yargsCompareCommandObject(),
|
|
3461
|
-
yargsConfigCommandObject()
|
|
3653
|
+
yargsConfigCommandObject(),
|
|
3654
|
+
yargsMergeDiffsCommandObject()
|
|
3462
3655
|
];
|
|
3463
3656
|
|
|
3464
3657
|
// packages/cli/src/lib/implementation/core-config.middleware.ts
|
|
@@ -3670,7 +3863,7 @@ function yargsGlobalOptionsDefinition() {
|
|
|
3670
3863
|
default: false
|
|
3671
3864
|
},
|
|
3672
3865
|
config: {
|
|
3673
|
-
describe: "Path to config file
|
|
3866
|
+
describe: "Path to config file. By default it loads code-pushup.config.(ts|mjs|js).",
|
|
3674
3867
|
type: "string"
|
|
3675
3868
|
},
|
|
3676
3869
|
tsconfig: {
|
|
@@ -3698,8 +3891,55 @@ var groups = {
|
|
|
3698
3891
|
};
|
|
3699
3892
|
|
|
3700
3893
|
// packages/cli/src/lib/yargs-cli.ts
|
|
3701
|
-
import {
|
|
3894
|
+
import { blue, dim as dim2, green as green4 } from "ansis";
|
|
3702
3895
|
import yargs from "yargs";
|
|
3896
|
+
|
|
3897
|
+
// packages/cli/package.json
|
|
3898
|
+
var version2 = "0.50.0";
|
|
3899
|
+
|
|
3900
|
+
// packages/cli/src/lib/implementation/formatting.ts
|
|
3901
|
+
import { bold as bold13, dim, green as green3 } from "ansis";
|
|
3902
|
+
function titleStyle(title) {
|
|
3903
|
+
return `${bold13(title)}`;
|
|
3904
|
+
}
|
|
3905
|
+
function headerStyle(title) {
|
|
3906
|
+
return `${green3(title)}`;
|
|
3907
|
+
}
|
|
3908
|
+
function descriptionStyle(title) {
|
|
3909
|
+
return `${dim(title)}`;
|
|
3910
|
+
}
|
|
3911
|
+
function formatObjectValue(opts, propName) {
|
|
3912
|
+
const description = opts[propName];
|
|
3913
|
+
return {
|
|
3914
|
+
...opts,
|
|
3915
|
+
...typeof description === "string" && {
|
|
3916
|
+
[propName]: descriptionStyle(description)
|
|
3917
|
+
}
|
|
3918
|
+
};
|
|
3919
|
+
}
|
|
3920
|
+
function formatNestedValues(options2, propName) {
|
|
3921
|
+
return Object.fromEntries(
|
|
3922
|
+
Object.entries(options2).map(([key, opts]) => [
|
|
3923
|
+
key,
|
|
3924
|
+
formatObjectValue(opts, propName)
|
|
3925
|
+
])
|
|
3926
|
+
);
|
|
3927
|
+
}
|
|
3928
|
+
|
|
3929
|
+
// packages/cli/src/lib/yargs-cli.ts
|
|
3930
|
+
var yargsDecorator = {
|
|
3931
|
+
"Commands:": `${green4("Commands")}:`,
|
|
3932
|
+
"Options:": `${green4("Options")}:`,
|
|
3933
|
+
"Examples:": `${green4("Examples")}:`,
|
|
3934
|
+
boolean: blue("boolean"),
|
|
3935
|
+
count: blue("count"),
|
|
3936
|
+
string: blue("string"),
|
|
3937
|
+
array: blue("array"),
|
|
3938
|
+
required: blue("required"),
|
|
3939
|
+
"default:": `${blue("default")}:`,
|
|
3940
|
+
"choices:": `${blue("choices")}:`,
|
|
3941
|
+
"aliases:": `${blue("aliases")}:`
|
|
3942
|
+
};
|
|
3703
3943
|
function yargsCli(argv, cfg) {
|
|
3704
3944
|
const { usageMessage, scriptName, noExitProcess } = cfg;
|
|
3705
3945
|
const commands2 = cfg.commands ?? [];
|
|
@@ -3708,7 +3948,7 @@ function yargsCli(argv, cfg) {
|
|
|
3708
3948
|
const groups2 = cfg.groups ?? {};
|
|
3709
3949
|
const examples = cfg.examples ?? [];
|
|
3710
3950
|
const cli2 = yargs(argv);
|
|
3711
|
-
cli2.
|
|
3951
|
+
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
3952
|
const persist = args["persist"];
|
|
3713
3953
|
return persist == null || validatePersistFormat(persist);
|
|
3714
3954
|
}).parserConfiguration({
|
|
@@ -3716,18 +3956,18 @@ function yargsCli(argv, cfg) {
|
|
|
3716
3956
|
}).coerce(
|
|
3717
3957
|
"config",
|
|
3718
3958
|
(config) => Array.isArray(config) ? config.at(-1) : config
|
|
3719
|
-
).options(options2)
|
|
3959
|
+
).options(formatNestedValues(options2, "describe"));
|
|
3720
3960
|
if (usageMessage) {
|
|
3721
|
-
cli2.usage(
|
|
3961
|
+
cli2.usage(titleStyle(usageMessage));
|
|
3722
3962
|
}
|
|
3723
3963
|
if (scriptName) {
|
|
3724
3964
|
cli2.scriptName(scriptName);
|
|
3725
3965
|
}
|
|
3726
3966
|
examples.forEach(
|
|
3727
|
-
([exampleName, description]) => cli2.example(exampleName, description)
|
|
3967
|
+
([exampleName, description]) => cli2.example(exampleName, descriptionStyle(description))
|
|
3728
3968
|
);
|
|
3729
3969
|
Object.entries(groups2).forEach(
|
|
3730
|
-
([groupName, optionNames]) => cli2.group(optionNames, groupName)
|
|
3970
|
+
([groupName, optionNames]) => cli2.group(optionNames, headerStyle(groupName))
|
|
3731
3971
|
);
|
|
3732
3972
|
middlewares2.forEach(({ middlewareFunction, applyBeforeValidation }) => {
|
|
3733
3973
|
cli2.middleware(
|
|
@@ -3736,13 +3976,18 @@ function yargsCli(argv, cfg) {
|
|
|
3736
3976
|
);
|
|
3737
3977
|
});
|
|
3738
3978
|
commands2.forEach((commandObj) => {
|
|
3739
|
-
cli2.command(
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3979
|
+
cli2.command(
|
|
3980
|
+
formatObjectValue(
|
|
3981
|
+
{
|
|
3982
|
+
...commandObj,
|
|
3983
|
+
handler: logErrorBeforeThrow(commandObj.handler),
|
|
3984
|
+
...typeof commandObj.builder === "function" && {
|
|
3985
|
+
builder: logErrorBeforeThrow(commandObj.builder)
|
|
3986
|
+
}
|
|
3987
|
+
},
|
|
3988
|
+
"describe"
|
|
3989
|
+
)
|
|
3990
|
+
);
|
|
3746
3991
|
});
|
|
3747
3992
|
if (noExitProcess) {
|
|
3748
3993
|
cli2.exitProcess(false);
|
|
@@ -3788,8 +4033,8 @@ var cli = (args) => yargsCli(args, {
|
|
|
3788
4033
|
"Run collect skiping the coverage plugin, other plugins from config file will be included."
|
|
3789
4034
|
],
|
|
3790
4035
|
[
|
|
3791
|
-
"code-pushup upload --persist.outputDir=dist --
|
|
3792
|
-
"Upload dist/
|
|
4036
|
+
"code-pushup upload --persist.outputDir=dist --upload.apiKey=$CP_API_KEY",
|
|
4037
|
+
"Upload dist/report.json to portal using API key from environment variable"
|
|
3793
4038
|
],
|
|
3794
4039
|
[
|
|
3795
4040
|
"code-pushup print-config --config code-pushup.config.test.js",
|
package/package.json
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@code-pushup/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.50.0",
|
|
4
4
|
"license": "MIT",
|
|
5
|
+
"description": "A CLI to run all kinds of code quality measurements to align your team with company goals",
|
|
5
6
|
"bin": {
|
|
6
7
|
"code-pushup": "index.js"
|
|
7
8
|
},
|
|
8
9
|
"dependencies": {
|
|
9
|
-
"@code-pushup/models": "0.
|
|
10
|
-
"@code-pushup/core": "0.
|
|
11
|
-
"@code-pushup/utils": "0.
|
|
10
|
+
"@code-pushup/models": "0.50.0",
|
|
11
|
+
"@code-pushup/core": "0.50.0",
|
|
12
|
+
"@code-pushup/utils": "0.50.0",
|
|
12
13
|
"yargs": "^17.7.2",
|
|
13
14
|
"ansis": "^3.3.0",
|
|
14
15
|
"simple-git": "^3.20.0"
|
|
15
16
|
},
|
|
16
|
-
"homepage": "
|
|
17
|
+
"homepage": "code-pushup.dev",
|
|
17
18
|
"bugs": {
|
|
18
19
|
"url": "https://github.com/code-pushup/cli/issues"
|
|
19
20
|
},
|
|
@@ -22,33 +23,6 @@
|
|
|
22
23
|
"url": "git+https://github.com/code-pushup/cli.git",
|
|
23
24
|
"directory": "packages/cli"
|
|
24
25
|
},
|
|
25
|
-
"contributors": [
|
|
26
|
-
{
|
|
27
|
-
"name": "Igor Katsuba",
|
|
28
|
-
"email": "igor@katsuba.dev",
|
|
29
|
-
"url": "https://katsuba.dev"
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
"name": "Kateřina Pilátová",
|
|
33
|
-
"email": "katerina.pilatova@flowup.cz",
|
|
34
|
-
"url": "https://github.com/Tlacenka"
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
"name": "Matěj Chalk",
|
|
38
|
-
"email": "matej.chalk@flowup.cz",
|
|
39
|
-
"url": "https://github.com/matejchalk"
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
"name": "Michael Hladky",
|
|
43
|
-
"email": "michael.hladky@push-based.io",
|
|
44
|
-
"url": "https://push-based.io"
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
"name": "Michael Seredenko",
|
|
48
|
-
"email": "misha.seredenko@push-based.io",
|
|
49
|
-
"url": "https://github.com/MishaSeredenkoPushBased"
|
|
50
|
-
}
|
|
51
|
-
],
|
|
52
26
|
"type": "module",
|
|
53
27
|
"main": "./index.js",
|
|
54
28
|
"types": "./src/index.d.ts"
|
package/src/lib/commands.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { CommandModule } from 'yargs';
|
|
1
|
+
import type { CommandModule } from 'yargs';
|
|
2
2
|
export declare const commands: CommandModule[];
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { CompareOptions } from '../implementation/compare.model';
|
|
2
1
|
export declare function yargsCompareCommandObject(): {
|
|
3
2
|
command: string;
|
|
4
3
|
describe: string;
|
|
5
|
-
builder: Record<keyof
|
|
4
|
+
builder: Record<"label" | keyof import("@code-pushup/utils").Diff<string>, import("yargs").Options>;
|
|
6
5
|
handler: (args: unknown) => Promise<void>;
|
|
7
6
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { HistoryOnlyOptions } from '@code-pushup/core';
|
|
1
|
+
import type { LogOptions } from 'simple-git';
|
|
2
|
+
import type { HistoryOnlyOptions } from '@code-pushup/core';
|
|
3
3
|
export type HistoryCliOptions = {
|
|
4
4
|
targetBranch?: string;
|
|
5
5
|
onlySemverTags?: boolean;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { Options } from 'yargs';
|
|
2
|
-
import { HistoryCliOptions } from './history.model';
|
|
1
|
+
import type { Options } from 'yargs';
|
|
2
|
+
import type { HistoryCliOptions } from './history.model';
|
|
3
3
|
export declare function yargsHistoryOptionsDefinition(): Record<keyof HistoryCliOptions, Options>;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { HistoryOptions } from '@code-pushup/core';
|
|
2
|
-
import { HistoryCliOptions } from './history.model';
|
|
1
|
+
import type { HistoryOptions } from '@code-pushup/core';
|
|
2
|
+
import type { HistoryCliOptions } from './history.model';
|
|
3
3
|
export declare function normalizeHashOptions(processArgs: HistoryCliOptions & HistoryOptions): Promise<HistoryCliOptions & HistoryOptions>;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { CoreConfig, Format } from '@code-pushup/models';
|
|
2
|
-
import { CoreConfigCliOptions } from './core-config.model';
|
|
3
|
-
import { GeneralCliOptions } from './global.model';
|
|
4
|
-
import { OnlyPluginsOptions } from './only-plugins.model';
|
|
5
|
-
import { SkipPluginsOptions } from './skip-plugins.model';
|
|
1
|
+
import { type CoreConfig, type Format } from '@code-pushup/models';
|
|
2
|
+
import type { CoreConfigCliOptions } from './core-config.model';
|
|
3
|
+
import type { GeneralCliOptions } from './global.model';
|
|
4
|
+
import type { OnlyPluginsOptions } from './only-plugins.model';
|
|
5
|
+
import type { SkipPluginsOptions } from './skip-plugins.model';
|
|
6
6
|
export type CoreConfigMiddlewareOptions = GeneralCliOptions & CoreConfigCliOptions & OnlyPluginsOptions & SkipPluginsOptions;
|
|
7
7
|
export declare function coreConfigMiddleware<T extends CoreConfigMiddlewareOptions>(processArgs: T): Promise<GeneralCliOptions & CoreConfig & OnlyPluginsOptions & SkipPluginsOptions>;
|
|
8
8
|
export declare const normalizeFormats: (formats?: string[]) => Format[];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Options } from 'yargs';
|
|
2
|
-
import { PersistConfigCliOptions, UploadConfigCliOptions } from './core-config.model';
|
|
1
|
+
import type { Options } from 'yargs';
|
|
2
|
+
import type { PersistConfigCliOptions, UploadConfigCliOptions } from './core-config.model';
|
|
3
3
|
export declare function yargsCoreConfigOptionsDefinition(): Record<keyof (PersistConfigCliOptions & UploadConfigCliOptions), Options>;
|
|
4
4
|
export declare function yargsPersistConfigOptionsDefinition(): Record<keyof PersistConfigCliOptions, Options>;
|
|
5
5
|
export declare function yargsUploadConfigOptionsDefinition(): Record<keyof UploadConfigCliOptions, Options>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare function titleStyle(title: string): string;
|
|
2
|
+
export declare function headerStyle(title: string): string;
|
|
3
|
+
export declare function descriptionStyle(title: string): string;
|
|
4
|
+
export declare function formatObjectValue<T>(opts: T, propName: keyof T): T & {
|
|
5
|
+
[x: string]: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function formatNestedValues<T>(options: Record<string, T>, propName: keyof T): {
|
|
8
|
+
[k: string]: T & {
|
|
9
|
+
[x: string]: string;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { GlobalOptions } from '@code-pushup/core';
|
|
2
|
-
import { ConfigCliOptions } from './core-config.model';
|
|
1
|
+
import type { GlobalOptions } from '@code-pushup/core';
|
|
2
|
+
import type { ConfigCliOptions } from './core-config.model';
|
|
3
3
|
export type GeneralCliOptions = ConfigCliOptions & GlobalOptions;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { Options } from 'yargs';
|
|
2
|
-
import { GeneralCliOptions } from './global.model';
|
|
1
|
+
import type { Options } from 'yargs';
|
|
2
|
+
import type { GeneralCliOptions } from './global.model';
|
|
3
3
|
export declare function yargsGlobalOptionsDefinition(): Record<keyof GeneralCliOptions, Options>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { OnlyPluginsOptions } from './only-plugins.model';
|
|
1
|
+
import type { OnlyPluginsOptions } from './only-plugins.model';
|
|
2
2
|
export declare function onlyPluginsMiddleware<T extends OnlyPluginsOptions>(originalProcessArgs: T): T;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { GlobalOptions } from '@code-pushup/core';
|
|
2
|
-
import { CoreConfig } from '@code-pushup/models';
|
|
1
|
+
import type { GlobalOptions } from '@code-pushup/core';
|
|
2
|
+
import type { CoreConfig } from '@code-pushup/models';
|
|
3
3
|
export type OnlyPluginsCliOptions = {
|
|
4
4
|
onlyPlugins?: string[];
|
|
5
5
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import { Options } from 'yargs';
|
|
1
|
+
import type { Options } from 'yargs';
|
|
2
|
+
import type { OnlyPluginsCliOptions } from './only-plugins.model';
|
|
2
3
|
export declare const onlyPluginsOption: Options;
|
|
3
|
-
export declare function yargsOnlyPluginsOptionsDefinition(): Record<
|
|
4
|
+
export declare function yargsOnlyPluginsOptionsDefinition(): Record<keyof OnlyPluginsCliOptions, Options>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { SkipPluginsOptions } from './skip-plugins.model';
|
|
1
|
+
import type { SkipPluginsOptions } from './skip-plugins.model';
|
|
2
2
|
export declare function skipPluginsMiddleware<T extends SkipPluginsOptions>(originalProcessArgs: T): T;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { GlobalOptions } from '@code-pushup/core';
|
|
2
|
-
import { CoreConfig } from '@code-pushup/models';
|
|
1
|
+
import type { GlobalOptions } from '@code-pushup/core';
|
|
2
|
+
import type { CoreConfig } from '@code-pushup/models';
|
|
3
3
|
export type SkipPluginsCliOptions = {
|
|
4
4
|
skipPlugins?: string[];
|
|
5
5
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import { Options } from 'yargs';
|
|
1
|
+
import type { Options } from 'yargs';
|
|
2
|
+
import type { SkipPluginsCliOptions } from './skip-plugins.model';
|
|
2
3
|
export declare const skipPluginsOption: Options;
|
|
3
|
-
export declare function yargsSkipPluginsOptionsDefinition(): Record<
|
|
4
|
+
export declare function yargsSkipPluginsOptionsDefinition(): Record<keyof SkipPluginsCliOptions, Options>;
|
package/src/lib/middlewares.d.ts
CHANGED
package/src/lib/yargs-cli.d.ts
CHANGED
|
@@ -1,4 +1,17 @@
|
|
|
1
|
-
import { Argv, CommandModule, Options } from 'yargs';
|
|
1
|
+
import { type Argv, type CommandModule, type Options } from 'yargs';
|
|
2
|
+
export declare const yargsDecorator: {
|
|
3
|
+
'Commands:': string;
|
|
4
|
+
'Options:': string;
|
|
5
|
+
'Examples:': string;
|
|
6
|
+
boolean: string;
|
|
7
|
+
count: string;
|
|
8
|
+
string: string;
|
|
9
|
+
array: string;
|
|
10
|
+
required: string;
|
|
11
|
+
'default:': string;
|
|
12
|
+
'choices:': string;
|
|
13
|
+
'aliases:': string;
|
|
14
|
+
};
|
|
2
15
|
/**
|
|
3
16
|
* returns configurable yargs CLI for code-pushup
|
|
4
17
|
*
|