@code-pushup/cli 0.8.14 → 0.8.15
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 +150 -110
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -7,8 +7,7 @@ import { hideBin } from "yargs/helpers";
|
|
|
7
7
|
import chalk5 from "chalk";
|
|
8
8
|
|
|
9
9
|
// packages/core/src/lib/implementation/persist.ts
|
|
10
|
-
import {
|
|
11
|
-
import { stat as stat2, writeFile } from "node:fs/promises";
|
|
10
|
+
import { mkdir as mkdir2, stat as stat2, writeFile } from "node:fs/promises";
|
|
12
11
|
import { join as join2 } from "node:path";
|
|
13
12
|
|
|
14
13
|
// packages/utils/src/lib/execute-process.ts
|
|
@@ -656,6 +655,14 @@ async function fileExists(path) {
|
|
|
656
655
|
return false;
|
|
657
656
|
}
|
|
658
657
|
}
|
|
658
|
+
async function directoryExists(path) {
|
|
659
|
+
try {
|
|
660
|
+
const stats = await stat(path);
|
|
661
|
+
return stats.isDirectory();
|
|
662
|
+
} catch {
|
|
663
|
+
return false;
|
|
664
|
+
}
|
|
665
|
+
}
|
|
659
666
|
async function ensureDirectoryExists(baseDir) {
|
|
660
667
|
try {
|
|
661
668
|
await mkdir(baseDir, { recursive: true });
|
|
@@ -1556,47 +1563,55 @@ async function persistReport(report, options2) {
|
|
|
1556
1563
|
const { outputDir, filename, format } = options2;
|
|
1557
1564
|
const sortedScoredReport = sortReport(scoreReport(report));
|
|
1558
1565
|
console.info(generateStdoutSummary(sortedScoredReport));
|
|
1559
|
-
const results =
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1566
|
+
const results = await Promise.all(
|
|
1567
|
+
format.map(async (reportType) => {
|
|
1568
|
+
switch (reportType) {
|
|
1569
|
+
case "json":
|
|
1570
|
+
return {
|
|
1571
|
+
format: "json",
|
|
1572
|
+
content: JSON.stringify(report, null, 2)
|
|
1573
|
+
};
|
|
1574
|
+
case "md":
|
|
1575
|
+
const commitData = await getLatestCommit();
|
|
1576
|
+
validateCommitData(commitData);
|
|
1577
|
+
return {
|
|
1578
|
+
format: "md",
|
|
1579
|
+
content: generateMdReport(sortedScoredReport, commitData)
|
|
1580
|
+
};
|
|
1581
|
+
}
|
|
1582
|
+
})
|
|
1583
|
+
);
|
|
1584
|
+
if (!await directoryExists(outputDir)) {
|
|
1575
1585
|
try {
|
|
1576
|
-
|
|
1577
|
-
} catch (
|
|
1578
|
-
console.warn(
|
|
1586
|
+
await mkdir2(outputDir, { recursive: true });
|
|
1587
|
+
} catch (error) {
|
|
1588
|
+
console.warn(error);
|
|
1579
1589
|
throw new PersistDirError(outputDir);
|
|
1580
1590
|
}
|
|
1581
1591
|
}
|
|
1582
1592
|
return Promise.allSettled(
|
|
1583
|
-
results.map(
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
})
|
|
1593
|
+
results.map(
|
|
1594
|
+
(result) => persistResult(
|
|
1595
|
+
join2(outputDir, `${filename}.${result.format}`),
|
|
1596
|
+
result.content
|
|
1597
|
+
)
|
|
1598
|
+
)
|
|
1590
1599
|
);
|
|
1591
1600
|
}
|
|
1592
|
-
function logPersistedResults(persistResults) {
|
|
1593
|
-
logMultipleFileResults(persistResults, "Generated reports");
|
|
1594
|
-
}
|
|
1595
1601
|
function validateCommitData(commitData) {
|
|
1596
1602
|
if (!commitData) {
|
|
1597
1603
|
console.warn("no commit data available");
|
|
1598
1604
|
}
|
|
1599
1605
|
}
|
|
1606
|
+
async function persistResult(reportPath, content) {
|
|
1607
|
+
return writeFile(reportPath, content).then(() => stat2(reportPath)).then((stats) => [reportPath, stats.size]).catch((error) => {
|
|
1608
|
+
console.warn(error);
|
|
1609
|
+
throw new PersistError(reportPath);
|
|
1610
|
+
});
|
|
1611
|
+
}
|
|
1612
|
+
function logPersistedResults(persistResults) {
|
|
1613
|
+
logMultipleFileResults(persistResults, "Generated reports");
|
|
1614
|
+
}
|
|
1600
1615
|
|
|
1601
1616
|
// packages/core/src/lib/implementation/execute-plugin.ts
|
|
1602
1617
|
import chalk4 from "chalk";
|
|
@@ -1610,12 +1625,8 @@ async function executeRunnerConfig(cfg, onProgress) {
|
|
|
1610
1625
|
args,
|
|
1611
1626
|
observer: { onStdout: onProgress }
|
|
1612
1627
|
});
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
);
|
|
1616
|
-
if (outputTransform) {
|
|
1617
|
-
audits = await outputTransform(audits);
|
|
1618
|
-
}
|
|
1628
|
+
const outputs = await readJsonFile(join3(process.cwd(), outputFile));
|
|
1629
|
+
const audits = outputTransform ? await outputTransform(outputs) : outputs;
|
|
1619
1630
|
return {
|
|
1620
1631
|
duration,
|
|
1621
1632
|
date,
|
|
@@ -1670,30 +1681,31 @@ async function executePlugin(pluginConfig, onProgress) {
|
|
|
1670
1681
|
};
|
|
1671
1682
|
}
|
|
1672
1683
|
async function executePlugins(plugins, options2) {
|
|
1673
|
-
const { progress = false } = options2
|
|
1674
|
-
const
|
|
1675
|
-
const progressBar = progress ? getProgressBar(progressName) : null;
|
|
1684
|
+
const { progress = false } = options2 ?? {};
|
|
1685
|
+
const progressBar = progress ? getProgressBar("Run plugins") : null;
|
|
1676
1686
|
const pluginsResult = await plugins.reduce(async (acc, pluginCfg) => {
|
|
1677
|
-
|
|
1678
|
-
progressBar?.updateTitle(`Executing ${chalk4.bold(pluginCfg.title)}`);
|
|
1687
|
+
progressBar?.updateTitle(`Executing ${chalk4.bold(pluginCfg.title)}`);
|
|
1679
1688
|
try {
|
|
1680
1689
|
const pluginReport = await executePlugin(pluginCfg);
|
|
1681
1690
|
progressBar?.incrementInSteps(plugins.length);
|
|
1682
|
-
return
|
|
1683
|
-
} catch (
|
|
1691
|
+
return [...await acc, Promise.resolve(pluginReport)];
|
|
1692
|
+
} catch (error) {
|
|
1684
1693
|
progressBar?.incrementInSteps(plugins.length);
|
|
1685
|
-
return
|
|
1686
|
-
|
|
1687
|
-
|
|
1694
|
+
return [
|
|
1695
|
+
...await acc,
|
|
1696
|
+
Promise.reject(error instanceof Error ? error.message : String(error))
|
|
1697
|
+
];
|
|
1688
1698
|
}
|
|
1689
1699
|
}, Promise.resolve([]));
|
|
1690
1700
|
progressBar?.endProgress("Done running plugins");
|
|
1691
|
-
const errorsCallback = ({ reason }) =>
|
|
1701
|
+
const errorsCallback = ({ reason }) => {
|
|
1702
|
+
console.error(reason);
|
|
1703
|
+
};
|
|
1692
1704
|
const results = await Promise.allSettled(pluginsResult);
|
|
1693
1705
|
logMultipleResults(results, "Plugins", void 0, errorsCallback);
|
|
1694
1706
|
const { fulfilled, rejected } = groupByStatus(results);
|
|
1695
|
-
if (rejected.length) {
|
|
1696
|
-
const errorMessages = rejected.map(({ reason }) => reason).join(", ");
|
|
1707
|
+
if (rejected.length > 0) {
|
|
1708
|
+
const errorMessages = rejected.map(({ reason }) => String(reason)).join(", ");
|
|
1697
1709
|
throw new Error(
|
|
1698
1710
|
`Plugins failed: ${rejected.length} errors: ${errorMessages}`
|
|
1699
1711
|
);
|
|
@@ -1713,14 +1725,11 @@ function auditOutputsCorrelateWithPluginOutput(auditOutputs, pluginConfigAudits)
|
|
|
1713
1725
|
|
|
1714
1726
|
// packages/core/package.json
|
|
1715
1727
|
var name = "@code-pushup/core";
|
|
1716
|
-
var version = "0.8.
|
|
1728
|
+
var version = "0.8.15";
|
|
1717
1729
|
|
|
1718
1730
|
// packages/core/src/lib/implementation/collect.ts
|
|
1719
1731
|
async function collect(options2) {
|
|
1720
1732
|
const { plugins, categories } = options2;
|
|
1721
|
-
if (!plugins?.length) {
|
|
1722
|
-
throw new Error("No plugins registered");
|
|
1723
|
-
}
|
|
1724
1733
|
const date = (/* @__PURE__ */ new Date()).toISOString();
|
|
1725
1734
|
const start = performance.now();
|
|
1726
1735
|
const pluginOutputs = await executePlugins(plugins, options2);
|
|
@@ -1743,62 +1752,74 @@ import {
|
|
|
1743
1752
|
IssueSourceType,
|
|
1744
1753
|
IssueSeverity as PortalIssueSeverity
|
|
1745
1754
|
} from "@code-pushup/portal-client";
|
|
1746
|
-
function
|
|
1755
|
+
function jsonReportToGql(report) {
|
|
1747
1756
|
return {
|
|
1748
1757
|
packageName: report.packageName,
|
|
1749
1758
|
packageVersion: report.version,
|
|
1750
1759
|
commandStartDate: report.date,
|
|
1751
1760
|
commandDuration: report.duration,
|
|
1752
|
-
plugins: report.plugins
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
},
|
|
1767
|
-
docsUrl: audit.docsUrl,
|
|
1768
|
-
formattedValue: audit.displayValue,
|
|
1769
|
-
score: audit.score,
|
|
1770
|
-
slug: audit.slug,
|
|
1771
|
-
title: audit.title,
|
|
1772
|
-
value: audit.value
|
|
1773
|
-
})),
|
|
1774
|
-
description: plugin.description,
|
|
1775
|
-
docsUrl: plugin.docsUrl,
|
|
1776
|
-
groups: plugin.groups?.map((group) => ({
|
|
1777
|
-
slug: group.slug,
|
|
1778
|
-
title: group.title,
|
|
1779
|
-
description: group.description,
|
|
1780
|
-
refs: group.refs.map((ref) => ({ slug: ref.slug, weight: ref.weight }))
|
|
1781
|
-
})),
|
|
1782
|
-
icon: plugin.icon,
|
|
1783
|
-
slug: plugin.slug,
|
|
1784
|
-
title: plugin.title,
|
|
1785
|
-
packageName: plugin.packageName,
|
|
1786
|
-
packageVersion: plugin.version,
|
|
1787
|
-
runnerDuration: plugin.duration,
|
|
1788
|
-
runnerStartDate: plugin.date
|
|
1761
|
+
plugins: pluginReportsToGql(report.plugins),
|
|
1762
|
+
categories: categoryConfigsToGql(toArray(report.categories))
|
|
1763
|
+
};
|
|
1764
|
+
}
|
|
1765
|
+
function pluginReportsToGql(plugins) {
|
|
1766
|
+
return plugins.map((plugin) => ({
|
|
1767
|
+
audits: auditReportsToGql(plugin.audits),
|
|
1768
|
+
description: plugin.description,
|
|
1769
|
+
docsUrl: plugin.docsUrl,
|
|
1770
|
+
groups: plugin.groups?.map((group) => ({
|
|
1771
|
+
slug: group.slug,
|
|
1772
|
+
title: group.title,
|
|
1773
|
+
description: group.description,
|
|
1774
|
+
refs: group.refs.map((ref) => ({ slug: ref.slug, weight: ref.weight }))
|
|
1789
1775
|
})),
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1776
|
+
icon: plugin.icon,
|
|
1777
|
+
slug: plugin.slug,
|
|
1778
|
+
title: plugin.title,
|
|
1779
|
+
packageName: plugin.packageName,
|
|
1780
|
+
packageVersion: plugin.version,
|
|
1781
|
+
runnerDuration: plugin.duration,
|
|
1782
|
+
runnerStartDate: plugin.date
|
|
1783
|
+
}));
|
|
1784
|
+
}
|
|
1785
|
+
function auditReportsToGql(audits) {
|
|
1786
|
+
return audits.map((audit) => ({
|
|
1787
|
+
description: audit.description,
|
|
1788
|
+
details: {
|
|
1789
|
+
issues: issuesToGql(audit.details?.issues)
|
|
1790
|
+
},
|
|
1791
|
+
docsUrl: audit.docsUrl,
|
|
1792
|
+
formattedValue: audit.displayValue,
|
|
1793
|
+
score: audit.score,
|
|
1794
|
+
slug: audit.slug,
|
|
1795
|
+
title: audit.title,
|
|
1796
|
+
value: audit.value
|
|
1797
|
+
}));
|
|
1798
|
+
}
|
|
1799
|
+
function issuesToGql(issues) {
|
|
1800
|
+
return issues?.map((issue) => ({
|
|
1801
|
+
message: issue.message,
|
|
1802
|
+
severity: transformSeverity(issue.severity),
|
|
1803
|
+
sourceEndColumn: issue.source?.position?.endColumn,
|
|
1804
|
+
sourceEndLine: issue.source?.position?.endLine,
|
|
1805
|
+
sourceFilePath: issue.source?.file,
|
|
1806
|
+
sourceStartColumn: issue.source?.position?.startColumn,
|
|
1807
|
+
sourceStartLine: issue.source?.position?.startLine,
|
|
1808
|
+
sourceType: IssueSourceType.SourceCode
|
|
1809
|
+
})) ?? [];
|
|
1810
|
+
}
|
|
1811
|
+
function categoryConfigsToGql(categories) {
|
|
1812
|
+
return categories.map((category) => ({
|
|
1813
|
+
slug: category.slug,
|
|
1814
|
+
title: category.title,
|
|
1815
|
+
description: category.description,
|
|
1816
|
+
refs: category.refs.map((ref) => ({
|
|
1817
|
+
plugin: ref.plugin,
|
|
1818
|
+
type: ref.type === "audit" ? CategoryConfigRefType.Audit : CategoryConfigRefType.Group,
|
|
1819
|
+
weight: ref.weight,
|
|
1820
|
+
slug: ref.slug
|
|
1800
1821
|
}))
|
|
1801
|
-
};
|
|
1822
|
+
}));
|
|
1802
1823
|
}
|
|
1803
1824
|
function transformSeverity(severity) {
|
|
1804
1825
|
switch (severity) {
|
|
@@ -1821,8 +1842,8 @@ var normalizePersistConfig = (cfg) => ({
|
|
|
1821
1842
|
|
|
1822
1843
|
// packages/core/src/lib/upload.ts
|
|
1823
1844
|
async function upload(options2, uploadFn = uploadToPortal) {
|
|
1824
|
-
const persist = normalizePersistConfig(options2
|
|
1825
|
-
if (!options2
|
|
1845
|
+
const persist = normalizePersistConfig(options2.persist);
|
|
1846
|
+
if (!options2.upload) {
|
|
1826
1847
|
throw new Error("upload config must be set");
|
|
1827
1848
|
}
|
|
1828
1849
|
const { apiKey, server, organization, project } = options2.upload;
|
|
@@ -1838,7 +1859,7 @@ async function upload(options2, uploadFn = uploadToPortal) {
|
|
|
1838
1859
|
organization,
|
|
1839
1860
|
project,
|
|
1840
1861
|
commit: commitData.hash,
|
|
1841
|
-
...
|
|
1862
|
+
...jsonReportToGql(report)
|
|
1842
1863
|
};
|
|
1843
1864
|
return uploadFn({ apiKey, server, data });
|
|
1844
1865
|
}
|
|
@@ -1847,9 +1868,11 @@ async function upload(options2, uploadFn = uploadToPortal) {
|
|
|
1847
1868
|
async function collectAndPersistReports(options2) {
|
|
1848
1869
|
const { exec } = verboseUtils(options2.verbose);
|
|
1849
1870
|
const report = await collect(options2);
|
|
1850
|
-
const persist = normalizePersistConfig(options2
|
|
1871
|
+
const persist = normalizePersistConfig(options2.persist);
|
|
1851
1872
|
const persistResults = await persistReport(report, persist);
|
|
1852
|
-
exec(() =>
|
|
1873
|
+
exec(() => {
|
|
1874
|
+
logPersistedResults(persistResults);
|
|
1875
|
+
});
|
|
1853
1876
|
report.plugins.forEach((plugin) => {
|
|
1854
1877
|
pluginReportSchema.parse(plugin);
|
|
1855
1878
|
});
|
|
@@ -2175,9 +2198,12 @@ function yargsCli(argv, cfg) {
|
|
|
2175
2198
|
const middlewares2 = cfg.middlewares ?? [];
|
|
2176
2199
|
const options2 = cfg.options ?? {};
|
|
2177
2200
|
const cli2 = yargs(argv);
|
|
2178
|
-
cli2.help().version(false).alias("h", "help").
|
|
2201
|
+
cli2.help().version(false).alias("h", "help").check((args) => {
|
|
2202
|
+
const persist = args["persist"];
|
|
2203
|
+
return persist == null || validatePersistFormat(persist);
|
|
2204
|
+
}).parserConfiguration({
|
|
2179
2205
|
"strip-dashed": true
|
|
2180
|
-
}).
|
|
2206
|
+
}).coerce(
|
|
2181
2207
|
"config",
|
|
2182
2208
|
(config) => Array.isArray(config) ? config.at(-1) : config
|
|
2183
2209
|
).options(options2);
|
|
@@ -2207,6 +2233,20 @@ function yargsCli(argv, cfg) {
|
|
|
2207
2233
|
}
|
|
2208
2234
|
return cli2;
|
|
2209
2235
|
}
|
|
2236
|
+
function validatePersistFormat(persist) {
|
|
2237
|
+
try {
|
|
2238
|
+
if (persist?.format != null) {
|
|
2239
|
+
persist.format.forEach((format) => formatSchema.parse(format));
|
|
2240
|
+
}
|
|
2241
|
+
return true;
|
|
2242
|
+
} catch {
|
|
2243
|
+
throw new Error(
|
|
2244
|
+
`Invalid persist.format option. Valid options are: ${Object.values(
|
|
2245
|
+
formatSchema.Values
|
|
2246
|
+
).join(", ")}`
|
|
2247
|
+
);
|
|
2248
|
+
}
|
|
2249
|
+
}
|
|
2210
2250
|
|
|
2211
2251
|
// packages/cli/src/lib/cli.ts
|
|
2212
2252
|
var cli = (args) => yargsCli(args, {
|