@reddoorla/maintenance 0.14.0 → 0.15.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/dist/cli/bin.js +119 -41
- package/dist/cli/bin.js.map +1 -1
- package/dist/cli/commands/audit.js +115 -44
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/index.js +16 -14
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/cli/bin.js
CHANGED
|
@@ -938,6 +938,7 @@ import { cac } from "cac";
|
|
|
938
938
|
|
|
939
939
|
// src/cli/commands/audit.ts
|
|
940
940
|
import { resolve as resolve2 } from "path";
|
|
941
|
+
import { Listr } from "listr2";
|
|
941
942
|
|
|
942
943
|
// src/audits/util/spawn.ts
|
|
943
944
|
import { spawn } from "child_process";
|
|
@@ -1694,29 +1695,27 @@ var DEFAULT_AUDIT_TIMEOUT_MS = 3e4;
|
|
|
1694
1695
|
function timedSpawn(timeoutMs) {
|
|
1695
1696
|
return (cmd, args, opts = {}) => defaultSpawn(cmd, args, { ...opts, timeoutMs: opts.timeoutMs ?? timeoutMs });
|
|
1696
1697
|
}
|
|
1698
|
+
async function runOneAudit(site, name) {
|
|
1699
|
+
if (!(name in REGISTRY)) throw new Error(`unknown audit: ${name}`);
|
|
1700
|
+
const spawn2 = timedSpawn(DEFAULT_AUDIT_TIMEOUT_MS);
|
|
1701
|
+
const label = site.name ?? site.path;
|
|
1702
|
+
try {
|
|
1703
|
+
return await REGISTRY[name]({ site, spawn: spawn2 });
|
|
1704
|
+
} catch (err) {
|
|
1705
|
+
return {
|
|
1706
|
+
audit: name,
|
|
1707
|
+
site: label,
|
|
1708
|
+
status: "fail",
|
|
1709
|
+
summary: `${name}: unexpected error \u2014 ${String(err)}`
|
|
1710
|
+
};
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1697
1713
|
async function runAudits(site, which) {
|
|
1698
1714
|
const names = which ?? ALL_AUDIT_NAMES;
|
|
1699
1715
|
for (const n of names) {
|
|
1700
1716
|
if (!(n in REGISTRY)) throw new Error(`unknown audit: ${n}`);
|
|
1701
1717
|
}
|
|
1702
|
-
|
|
1703
|
-
const label = site.name ?? site.path;
|
|
1704
|
-
return Promise.all(
|
|
1705
|
-
names.map(
|
|
1706
|
-
(n) => REGISTRY[n]({ site, spawn: spawn2 }).catch(
|
|
1707
|
-
(err) => ({
|
|
1708
|
-
audit: n,
|
|
1709
|
-
site: label,
|
|
1710
|
-
status: "fail",
|
|
1711
|
-
summary: `${n}: unexpected error \u2014 ${String(err)}`
|
|
1712
|
-
})
|
|
1713
|
-
)
|
|
1714
|
-
)
|
|
1715
|
-
);
|
|
1716
|
-
}
|
|
1717
|
-
async function runAuditsAcross(sites, which) {
|
|
1718
|
-
const all = await Promise.all(sites.map((s) => runAudits(s, which)));
|
|
1719
|
-
return all.flat();
|
|
1718
|
+
return Promise.all(names.map((n) => runOneAudit(site, n)));
|
|
1720
1719
|
}
|
|
1721
1720
|
|
|
1722
1721
|
// src/cli/fleet/resolve-sites.ts
|
|
@@ -1882,8 +1881,87 @@ function formatTable(results) {
|
|
|
1882
1881
|
function exitCode(results) {
|
|
1883
1882
|
return results.some((r) => r.status === "fail") ? 1 : 0;
|
|
1884
1883
|
}
|
|
1884
|
+
function formatDuration(ms) {
|
|
1885
|
+
if (ms < 1e3) return `${ms}ms`;
|
|
1886
|
+
const totalSeconds = Math.round(ms / 1e3);
|
|
1887
|
+
if (totalSeconds < 60) return `${totalSeconds}s`;
|
|
1888
|
+
const m = Math.floor(totalSeconds / 60);
|
|
1889
|
+
const s = totalSeconds % 60;
|
|
1890
|
+
return `${m}m${s.toString().padStart(2, "0")}s`;
|
|
1891
|
+
}
|
|
1892
|
+
function buildAuditTasks(sites, which, results, renderer) {
|
|
1893
|
+
const singleSite = sites.length === 1;
|
|
1894
|
+
if (singleSite) {
|
|
1895
|
+
const site = sites[0];
|
|
1896
|
+
return new Listr(
|
|
1897
|
+
which.map((name) => ({
|
|
1898
|
+
title: name,
|
|
1899
|
+
task: async (_ctx, task) => {
|
|
1900
|
+
const start = Date.now();
|
|
1901
|
+
const result = await runOneAudit(site, name);
|
|
1902
|
+
results.push(result);
|
|
1903
|
+
const elapsed = formatDuration(Date.now() - start);
|
|
1904
|
+
task.title = `${name}: ${result.summary} (${elapsed})`;
|
|
1905
|
+
if (result.status === "fail") throw new Error(result.summary);
|
|
1906
|
+
}
|
|
1907
|
+
})),
|
|
1908
|
+
{ concurrent: true, exitOnError: false, renderer }
|
|
1909
|
+
);
|
|
1910
|
+
}
|
|
1911
|
+
return new Listr(
|
|
1912
|
+
sites.map((site) => {
|
|
1913
|
+
const label = site.name ?? site.path;
|
|
1914
|
+
return {
|
|
1915
|
+
title: label,
|
|
1916
|
+
task: async (_ctx, task) => {
|
|
1917
|
+
const start = Date.now();
|
|
1918
|
+
let done = 0;
|
|
1919
|
+
task.output = `0/${which.length} audits`;
|
|
1920
|
+
const settled = await Promise.all(
|
|
1921
|
+
which.map(async (name) => {
|
|
1922
|
+
const r = await runOneAudit(site, name);
|
|
1923
|
+
results.push(r);
|
|
1924
|
+
done += 1;
|
|
1925
|
+
task.output = `${done}/${which.length} audits`;
|
|
1926
|
+
return r;
|
|
1927
|
+
})
|
|
1928
|
+
);
|
|
1929
|
+
const elapsed = formatDuration(Date.now() - start);
|
|
1930
|
+
const failed = settled.filter((r) => r.status === "fail").length;
|
|
1931
|
+
const warned = settled.filter((r) => r.status === "warn").length;
|
|
1932
|
+
const note = failed > 0 ? `${failed} failed` : warned > 0 ? `${warned} warning${warned === 1 ? "" : "s"}` : "all green";
|
|
1933
|
+
task.title = `${label}: ${note} (${elapsed})`;
|
|
1934
|
+
if (failed > 0) throw new Error(`${label}: ${failed} audit(s) failed`);
|
|
1935
|
+
}
|
|
1936
|
+
};
|
|
1937
|
+
}),
|
|
1938
|
+
{ concurrent: true, exitOnError: false, renderer }
|
|
1939
|
+
);
|
|
1940
|
+
}
|
|
1941
|
+
function formatWriteSummary(summary) {
|
|
1942
|
+
const lines = summary.writes.map((w) => {
|
|
1943
|
+
if (w.audit === "lighthouse") {
|
|
1944
|
+
const s = w.counts;
|
|
1945
|
+
return ` lighthouse: P=${s.performance} A=${s.accessibility} BP=${s.bestPractices} SEO=${s.seo}`;
|
|
1946
|
+
}
|
|
1947
|
+
if (w.audit === "a11y") {
|
|
1948
|
+
return ` a11y: ${w.counts.violations} violations`;
|
|
1949
|
+
}
|
|
1950
|
+
if (w.audit === "deps") {
|
|
1951
|
+
const c2 = w.counts;
|
|
1952
|
+
return ` deps: ${c2.drifted} drifted (${c2.majorBehind} major)`;
|
|
1953
|
+
}
|
|
1954
|
+
const c = w.counts;
|
|
1955
|
+
return ` security: ${c.critical}C/${c.high}H/${c.moderate}M/${c.low}L`;
|
|
1956
|
+
});
|
|
1957
|
+
return `\u2192 wrote to Websites[${summary.siteName}]:
|
|
1958
|
+
${lines.join("\n")}`;
|
|
1959
|
+
}
|
|
1960
|
+
function rendererFor(json) {
|
|
1961
|
+
return json ? "silent" : "default";
|
|
1962
|
+
}
|
|
1885
1963
|
async function runAuditCommand(site, opts) {
|
|
1886
|
-
const which = parseOnly(opts.only);
|
|
1964
|
+
const which = parseOnly(opts.only) ?? ALL_AUDIT_NAMES;
|
|
1887
1965
|
const cwd = opts.cwd ? resolve2(opts.cwd) : process.cwd();
|
|
1888
1966
|
let sites = await resolveSites({
|
|
1889
1967
|
...site !== void 0 ? { site } : {},
|
|
@@ -1895,7 +1973,9 @@ async function runAuditCommand(site, opts) {
|
|
|
1895
1973
|
const workdir = opts.workdir ?? `${process.env.HOME ?? ""}/.reddoor-maint/sites`;
|
|
1896
1974
|
sites = await Promise.all(sites.map((s) => cloneIfNeeded(s, { workdir })));
|
|
1897
1975
|
}
|
|
1898
|
-
const results =
|
|
1976
|
+
const results = [];
|
|
1977
|
+
const renderer = rendererFor(opts.json);
|
|
1978
|
+
await buildAuditTasks(sites, which, results, renderer).run();
|
|
1899
1979
|
let output = opts.json ? JSON.stringify(results, null, 2) : formatTable(results);
|
|
1900
1980
|
if (opts.writeAirtable !== void 0) {
|
|
1901
1981
|
const { openBase: openBase2, readAirtableConfig: readAirtableConfig2 } = await Promise.resolve().then(() => (init_client(), client_exports));
|
|
@@ -1903,28 +1983,26 @@ async function runAuditCommand(site, opts) {
|
|
|
1903
1983
|
const { resolveSlugFromCwd: resolveSlugFromCwd2 } = await Promise.resolve().then(() => (init_lighthouse_airtable(), lighthouse_airtable_exports));
|
|
1904
1984
|
const { writeAuditsToAirtable: writeAuditsToAirtable2 } = await Promise.resolve().then(() => (init_write_audits_to_airtable(), write_audits_to_airtable_exports));
|
|
1905
1985
|
const slug = typeof opts.writeAirtable === "string" && opts.writeAirtable.length > 0 ? opts.writeAirtable : await resolveSlugFromCwd2(cwd);
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
output += `
|
|
1986
|
+
let writeSummary = null;
|
|
1987
|
+
await new Listr(
|
|
1988
|
+
[
|
|
1989
|
+
{
|
|
1990
|
+
title: `Write to Airtable[${slug}]`,
|
|
1991
|
+
task: async (_ctx, task) => {
|
|
1992
|
+
const base = openBase2(readAirtableConfig2());
|
|
1993
|
+
task.output = "loading Websites\u2026";
|
|
1994
|
+
const websites = await listWebsites2(base);
|
|
1995
|
+
task.output = "writing scores\u2026";
|
|
1996
|
+
writeSummary = await writeAuditsToAirtable2({ base, websites, slug, results });
|
|
1997
|
+
task.title = `Wrote to Websites[${writeSummary.siteName}] (${writeSummary.writes.length} audit type${writeSummary.writes.length === 1 ? "" : "s"})`;
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
],
|
|
2001
|
+
{ renderer }
|
|
2002
|
+
).run();
|
|
2003
|
+
if (writeSummary) output += `
|
|
1925
2004
|
|
|
1926
|
-
|
|
1927
|
-
${lines.join("\n")}`;
|
|
2005
|
+
${formatWriteSummary(writeSummary)}`;
|
|
1928
2006
|
}
|
|
1929
2007
|
return { output, code: exitCode(results) };
|
|
1930
2008
|
}
|