Skip to content

Commit 1782904

Browse files
committed
q
1 parent fafda02 commit 1782904

1 file changed

Lines changed: 119 additions & 0 deletions

File tree

bash/pnpm/minimumReleaseAge.ts

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
#!/usr/bin/env node
2+
3+
/**
4+
*
5+
export __MINIMUMRELEASEAGE=@koa/router
6+
export __MINIMUMRELEASEAGE_MODE=dev|prod
7+
NODE_OPTIONS= pnpm view "${__MINIMUMRELEASEAGE}" name time --json | NODE_OPTIONS= node bash/pnpm/minimumReleaseAge.ts ${__MINIMUMRELEASEAGE_MODE}
8+
9+
* to find version which satisfies
10+
* minimumReleaseAge: 43200 from pnpm-workspace.yaml
11+
*
12+
* Assuming file pnpm-workspace.yaml exist with content
13+
14+
vvvvvvv
15+
cat <<EEE > pnpm-workspace.yaml
16+
# 30 days - run pnpm config get minimumReleaseAge to see value
17+
minimumReleaseAge: 43200
18+
# to see how to find valid version of given library see bash/pnpm/minimumReleaseAge.ts
19+
20+
EEE
21+
^^^^^^^
22+
23+
*/
24+
25+
type TimeMap = Record<string, string>;
26+
27+
const MIN_AGE_DAYS = Number(process.env.MIN_AGE_DAYS ?? 30);
28+
const MIN_AGE_MS = MIN_AGE_DAYS * 24 * 60 * 60 * 1000;
29+
30+
const mode = process.argv[2];
31+
if (!mode || (mode !== "dev" && mode !== "prod")) {
32+
throw new Error("Parameter 'dev' or 'prod' is required as the first argument.");
33+
}
34+
let pkgName = process.argv[3] || "[library]";
35+
const installCmd = mode === "dev" ? "pnpm install -D" : "pnpm install";
36+
37+
function readStdin(): Promise<string> {
38+
return new Promise((resolve, reject) => {
39+
let data = "";
40+
41+
process.stdin.setEncoding("utf8");
42+
43+
process.stdin.on("data", (chunk) => {
44+
data += chunk;
45+
});
46+
47+
process.stdin.on("end", () => resolve(data));
48+
process.stdin.on("error", reject);
49+
});
50+
}
51+
52+
function error(msg: string): never {
53+
console.error(`❌ ${msg}`);
54+
process.exit(1);
55+
}
56+
57+
(async () => {
58+
const raw = await readStdin();
59+
60+
if (!raw || raw.trim().length === 0) {
61+
error("No input provided. Expected: pnpm view <pkg> name time --json | node minimumReleaseAge.ts <dev|prod>");
62+
}
63+
64+
let data: TimeMap;
65+
66+
try {
67+
const parsed = JSON.parse(raw);
68+
if (parsed && typeof parsed === "object") {
69+
if (parsed.name && parsed.time && typeof parsed.time === "object") {
70+
pkgName = parsed.name;
71+
data = parsed.time;
72+
} else {
73+
data = parsed;
74+
}
75+
} else {
76+
throw new Error("Invalid structure");
77+
}
78+
} catch (e) {
79+
error("Invalid JSON input (expected pnpm --json output)");
80+
}
81+
82+
const now = Date.now();
83+
84+
const rows = Object.entries(data).map(([version, time]) => {
85+
const t = new Date(time).getTime();
86+
const age = now - t;
87+
88+
return {
89+
version,
90+
time,
91+
ageDays: +(age / 86400000).toFixed(2),
92+
ok: age >= MIN_AGE_MS,
93+
};
94+
});
95+
96+
rows.sort((a, b) => new Date(b.time).getTime() - new Date(a.time).getTime());
97+
98+
const okRows = rows.filter((r) => r.ok);
99+
100+
console.log(`\nMinimum age: ${MIN_AGE_DAYS} days\n`);
101+
console.log(`Total versions: ${rows.length}`);
102+
console.log(`Valid versions: ${okRows.length}\n`);
103+
104+
for (const r of rows) {
105+
const mark = r.ok ? "✅" : "❌";
106+
const versionStr = r.version.padEnd(20);
107+
const ageStr = `${r.ageDays}d`.padStart(10);
108+
const cmdStr = r.ok ? `pnpm remove ${pkgName} && ${installCmd} ${pkgName}@${r.version}` : "";
109+
console.log(`${mark} ${versionStr} | ${ageStr} | ${r.time} | ${cmdStr}`);
110+
}
111+
112+
const best = okRows[0];
113+
114+
if (best) {
115+
console.log(`\n👉 Best matching version: ${best.version}`);
116+
} else {
117+
console.log("\n⚠️ No versions satisfy minimumReleaseAge");
118+
}
119+
})();

0 commit comments

Comments
 (0)