@geonosis/release 2.2.0 → 2.3.1
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 +3 -0
- package/dist/{chunk-IPCIF5DO.js → chunk-7H7SV5EP.js} +187 -20
- package/dist/index.d.ts +51 -1
- package/dist/index.js +13 -1
- package/dist/release-cli.js +39 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# @geonosis/release
|
|
2
2
|
|
|
3
|
+
Through the front door: `geonosis release` — the metapackage pins this and every other kit tool at
|
|
4
|
+
ONE version, and passes the exit code through unchanged.
|
|
5
|
+
|
|
3
6
|
The release contract with its proofs.
|
|
4
7
|
|
|
5
8
|
A release proves its **code** before serving it. Its **schema** serves immediately, to 100 % of
|
|
@@ -502,11 +502,12 @@ import {
|
|
|
502
502
|
mkdirSync as mkdirSync2,
|
|
503
503
|
readdirSync as readdirSync2,
|
|
504
504
|
readFileSync as readFileSync4,
|
|
505
|
+
renameSync,
|
|
505
506
|
rmSync,
|
|
506
507
|
statSync,
|
|
507
508
|
writeFileSync as writeFileSync2
|
|
508
509
|
} from "fs";
|
|
509
|
-
import { join as join3, relative as relative2, resolve as resolve3 } from "path";
|
|
510
|
+
import { join as join3, relative as relative2, resolve as resolve3, sep as sep2 } from "path";
|
|
510
511
|
var SNAPSHOTS_DIR = ".geonosis/consumer-snapshots";
|
|
511
512
|
var LOCKFILES = [
|
|
512
513
|
{ file: "bun.lock", manager: "bun" },
|
|
@@ -574,12 +575,17 @@ var scriptsIn = (manifest) => {
|
|
|
574
575
|
var copyInto = (from, to, excluded) => {
|
|
575
576
|
let bytes = 0;
|
|
576
577
|
let files = 0;
|
|
578
|
+
const nested = [];
|
|
577
579
|
const walk = (dir, into) => {
|
|
578
580
|
mkdirSync2(into, { recursive: true });
|
|
579
581
|
for (const entry of readdirSync2(dir, { withFileTypes: true })) {
|
|
580
582
|
if (excluded.has(entry.name)) continue;
|
|
581
583
|
const at = join3(dir, entry.name);
|
|
582
584
|
if (entry.isDirectory()) {
|
|
585
|
+
if (existsSync2(join3(at, ".git"))) {
|
|
586
|
+
nested.push(relative2(from, at).split(sep2).join("/"));
|
|
587
|
+
continue;
|
|
588
|
+
}
|
|
583
589
|
walk(at, join3(into, entry.name));
|
|
584
590
|
continue;
|
|
585
591
|
}
|
|
@@ -590,7 +596,40 @@ var copyInto = (from, to, excluded) => {
|
|
|
590
596
|
}
|
|
591
597
|
};
|
|
592
598
|
walk(from, to);
|
|
593
|
-
return { bytes, files };
|
|
599
|
+
return { bytes, files, nested: nested.toSorted() };
|
|
600
|
+
};
|
|
601
|
+
var HISTORY_DEPTH = 50;
|
|
602
|
+
var gitIn = (cwd, args) => {
|
|
603
|
+
const done = spawnSync("git", args, { cwd, encoding: "utf8" });
|
|
604
|
+
return { code: done.status ?? -1, out: `${done.stdout ?? ""}${done.stderr ?? ""}` };
|
|
605
|
+
};
|
|
606
|
+
var recordHistoryInto = (from, tree) => {
|
|
607
|
+
const head = gitIn(from, ["rev-parse", "HEAD"]);
|
|
608
|
+
if (head.code !== 0) {
|
|
609
|
+
return {
|
|
610
|
+
why: `${from} is not a git work tree with a commit in it, so this recording carries no history and a tier step that reads git will refuse in it: ${head.out.trim().split("\n")[0] ?? ""}`
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
const staging = `${tree}.history`;
|
|
614
|
+
const cloned = gitIn(from, [
|
|
615
|
+
"clone",
|
|
616
|
+
"--quiet",
|
|
617
|
+
"--no-checkout",
|
|
618
|
+
"--no-hardlinks",
|
|
619
|
+
"--no-single-branch",
|
|
620
|
+
"--depth",
|
|
621
|
+
String(HISTORY_DEPTH),
|
|
622
|
+
`file://${from}`,
|
|
623
|
+
staging
|
|
624
|
+
]);
|
|
625
|
+
if (cloned.code !== 0) {
|
|
626
|
+
rmSync(staging, { force: true, recursive: true });
|
|
627
|
+
return { why: `git clone of ${from} refused: ${cloned.out.trim().split("\n").at(-1) ?? ""}` };
|
|
628
|
+
}
|
|
629
|
+
renameSync(join3(staging, ".git"), join3(tree, ".git"));
|
|
630
|
+
rmSync(staging, { force: true, recursive: true });
|
|
631
|
+
gitIn(tree, ["reset", "--quiet", "--mixed"]);
|
|
632
|
+
return { depth: HISTORY_DEPTH, head: head.out.trim() };
|
|
594
633
|
};
|
|
595
634
|
var manifestsUnder2 = (root) => {
|
|
596
635
|
const found = [];
|
|
@@ -713,7 +752,8 @@ var runSnapshot = (input) => {
|
|
|
713
752
|
const excluded = [.../* @__PURE__ */ new Set([...EXCLUDED_DIRS, ...input.exclude ?? []])].toSorted();
|
|
714
753
|
rmSync(at, { force: true, recursive: true });
|
|
715
754
|
const tree = join3(at, "tree");
|
|
716
|
-
const { bytes, files } = copyInto(from, tree, new Set(excluded));
|
|
755
|
+
const { bytes, files, nested } = copyInto(from, tree, new Set(excluded));
|
|
756
|
+
const history = recordHistoryInto(from, tree);
|
|
717
757
|
const manifests = manifestsUnder2(tree);
|
|
718
758
|
const seams = seamsIn(tree);
|
|
719
759
|
const record = {
|
|
@@ -725,10 +765,12 @@ var runSnapshot = (input) => {
|
|
|
725
765
|
excluded,
|
|
726
766
|
files,
|
|
727
767
|
from,
|
|
768
|
+
history,
|
|
728
769
|
lockfile,
|
|
729
770
|
manager,
|
|
730
771
|
manifests,
|
|
731
|
-
name: input.name
|
|
772
|
+
name: input.name,
|
|
773
|
+
...nested.length === 0 ? {} : { nested }
|
|
732
774
|
};
|
|
733
775
|
writeFileSync2(join3(at, "snapshot.json"), `${JSON.stringify(record, void 0, 2)}
|
|
734
776
|
`);
|
|
@@ -756,7 +798,7 @@ var formatSnapshot = (record) => [
|
|
|
756
798
|
].join("");
|
|
757
799
|
|
|
758
800
|
// src/adoption.ts
|
|
759
|
-
import { existsSync as existsSync3, readFileSync as readFileSync5 } from "fs";
|
|
801
|
+
import { existsSync as existsSync3, readdirSync as readdirSync3, readFileSync as readFileSync5 } from "fs";
|
|
760
802
|
import { join as join4 } from "path";
|
|
761
803
|
var groupsOf = (root) => {
|
|
762
804
|
const at = join4(root, ".changeset/config.json");
|
|
@@ -780,6 +822,38 @@ var numberIn = (spec) => {
|
|
|
780
822
|
var declarationsIn = (record, kit) => record.manifests.flatMap(
|
|
781
823
|
(manifest) => Object.entries(manifest.versions).filter(([name]) => kit.has(name)).map(([name, spec]) => ({ name, path: manifest.path, spec }))
|
|
782
824
|
);
|
|
825
|
+
var TEST_FILE = /\.(?:test|spec)\.[cm]?[jt]sx?$/;
|
|
826
|
+
var EXAM_IMPORT = /([$\w]*Conformance)\b/g;
|
|
827
|
+
var NEVER_WALKED2 = /* @__PURE__ */ new Set([".git", "dist", "node_modules"]);
|
|
828
|
+
var examsRunIn = (dir) => {
|
|
829
|
+
const found = /* @__PURE__ */ new Set();
|
|
830
|
+
const stack = [dir];
|
|
831
|
+
while (stack.length > 0) {
|
|
832
|
+
const at = stack.pop();
|
|
833
|
+
let entries;
|
|
834
|
+
try {
|
|
835
|
+
entries = readdirSync3(at, { withFileTypes: true });
|
|
836
|
+
} catch {
|
|
837
|
+
continue;
|
|
838
|
+
}
|
|
839
|
+
for (const entry of entries) {
|
|
840
|
+
if (entry.isDirectory()) {
|
|
841
|
+
if (!NEVER_WALKED2.has(entry.name)) stack.push(join4(at, entry.name));
|
|
842
|
+
continue;
|
|
843
|
+
}
|
|
844
|
+
if (!TEST_FILE.test(entry.name)) continue;
|
|
845
|
+
let source;
|
|
846
|
+
try {
|
|
847
|
+
source = readFileSync5(join4(at, entry.name), "utf8");
|
|
848
|
+
} catch {
|
|
849
|
+
continue;
|
|
850
|
+
}
|
|
851
|
+
if (!source.includes("@geonosis/")) continue;
|
|
852
|
+
for (const match of source.matchAll(EXAM_IMPORT)) found.add(match[1]);
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
return [...found].toSorted();
|
|
856
|
+
};
|
|
783
857
|
var groupName = (index, total) => total > 1 ? `fixed group ${index + 1}` : "the fixed group";
|
|
784
858
|
var incoherence = (consumer, groups, declarations) => groups.flatMap((group, index) => {
|
|
785
859
|
const members = new Set(group);
|
|
@@ -868,6 +942,7 @@ var runAdoption = async ({
|
|
|
868
942
|
const seams = record.seams;
|
|
869
943
|
consumers.push({
|
|
870
944
|
declared: declarations.length,
|
|
945
|
+
exams: examsRunIn(join4(snapshotDir(root, one.name), "tree")),
|
|
871
946
|
...seams === void 0 ? {} : { seams },
|
|
872
947
|
findings: [
|
|
873
948
|
...distance(one.name, declarations, current),
|
|
@@ -898,10 +973,13 @@ var blockFor = (consumer) => {
|
|
|
898
973
|
const head = faults.length === 0 ? [
|
|
899
974
|
` MATCH ${consumer.name} \u2014 ${consumer.declared} spec(s) on the versions this release is cut at`
|
|
900
975
|
] : [];
|
|
976
|
+
const exams = consumer.exams.length === 0 ? [
|
|
977
|
+
` EXAMS ${consumer.name} \u2014 none: no test file in this recording runs a floor exam, so a floor bump that broke one would read as a green tier`
|
|
978
|
+
] : [` EXAMS ${consumer.name} \u2014 ${consumer.exams.join(", ")}`];
|
|
901
979
|
const seams = consumer.seams === void 0 ? [] : [
|
|
902
980
|
` SEAMS ${consumer.name} \u2014 ${consumer.seams.lines} lines in ${consumer.seams.globs.join(", ")} at this recording; a floor is adopted the day it deletes more than it adds`
|
|
903
981
|
];
|
|
904
|
-
return [...head, ...seams, ...new Set(consumer.findings.map(lineOf))];
|
|
982
|
+
return [...head, ...exams, ...seams, ...new Set(consumer.findings.map(lineOf))];
|
|
905
983
|
};
|
|
906
984
|
var formatAdoption = (report) => [
|
|
907
985
|
`adoption \u2014 ${report.considered} declared, ${report.consumers.length} read, ${report.excused.length} excused; against ${report.registry ?? "this workspace"}`,
|
|
@@ -1100,16 +1178,16 @@ var declaredIn = (config) => {
|
|
|
1100
1178
|
routes: listed.map((route) => isRecord3(route) ? route["pattern"] : route).filter((pattern) => typeof pattern === "string").toSorted()
|
|
1101
1179
|
};
|
|
1102
1180
|
};
|
|
1103
|
-
var readWrangler = (root,
|
|
1104
|
-
const path = resolve4(root,
|
|
1181
|
+
var readWrangler = (root, relative6, env) => {
|
|
1182
|
+
const path = resolve4(root, relative6);
|
|
1105
1183
|
let parsed;
|
|
1106
1184
|
try {
|
|
1107
1185
|
const source = readFileSync6(path, "utf8");
|
|
1108
|
-
parsed =
|
|
1186
|
+
parsed = relative6.endsWith(".toml") ? parseToml(source) : parseJsonc(source);
|
|
1109
1187
|
} catch (error) {
|
|
1110
|
-
throw new CannotRun(`${
|
|
1188
|
+
throw new CannotRun(`${relative6} could not be read: ${error.message}`);
|
|
1111
1189
|
}
|
|
1112
|
-
if (!isRecord3(parsed)) throw new CannotRun(`${
|
|
1190
|
+
if (!isRecord3(parsed)) throw new CannotRun(`${relative6} is not a wrangler configuration`);
|
|
1113
1191
|
const environments = parsed["env"];
|
|
1114
1192
|
const block = env !== void 0 && isRecord3(environments) && isRecord3(environments[env]) ? environments[env] : parsed;
|
|
1115
1193
|
return declaredIn(block);
|
|
@@ -1672,7 +1750,7 @@ var Runner = class {
|
|
|
1672
1750
|
if (this.closed !== void 0) {
|
|
1673
1751
|
throw new CannotRun(`the runner is gone before "${request.step}": ${this.closed}`);
|
|
1674
1752
|
}
|
|
1675
|
-
const line = await new Promise((
|
|
1753
|
+
const line = await new Promise((resolve11, reject) => {
|
|
1676
1754
|
const timer = setTimeout(() => {
|
|
1677
1755
|
reject(
|
|
1678
1756
|
new CannotRun(
|
|
@@ -1682,7 +1760,7 @@ var Runner = class {
|
|
|
1682
1760
|
}, timeoutMs);
|
|
1683
1761
|
this.waiting.push((answer) => {
|
|
1684
1762
|
clearTimeout(timer);
|
|
1685
|
-
|
|
1763
|
+
resolve11(answer);
|
|
1686
1764
|
});
|
|
1687
1765
|
this.child.on("close", () => {
|
|
1688
1766
|
clearTimeout(timer);
|
|
@@ -1795,8 +1873,8 @@ var formatVerdict = (verdict) => verdict.ok ? `OK prove: ${verdict.steps.join
|
|
|
1795
1873
|
`;
|
|
1796
1874
|
|
|
1797
1875
|
// src/schema-walls.ts
|
|
1798
|
-
import { readdirSync as
|
|
1799
|
-
import { join as join6, relative as relative3, resolve as resolve8, sep as
|
|
1876
|
+
import { readdirSync as readdirSync4, readFileSync as readFileSync9 } from "fs";
|
|
1877
|
+
import { join as join6, relative as relative3, resolve as resolve8, sep as sep3 } from "path";
|
|
1800
1878
|
var MIGRATION_FILE = /\.(?:sql|ts)$/;
|
|
1801
1879
|
var CURRENT_SETTING = /current_setting\s*\(\s*'([^']+)'/gi;
|
|
1802
1880
|
var filesUnder2 = (root, dir) => {
|
|
@@ -1804,7 +1882,7 @@ var filesUnder2 = (root, dir) => {
|
|
|
1804
1882
|
const walk = (at) => {
|
|
1805
1883
|
let entries;
|
|
1806
1884
|
try {
|
|
1807
|
-
entries =
|
|
1885
|
+
entries = readdirSync4(at, { withFileTypes: true });
|
|
1808
1886
|
} catch {
|
|
1809
1887
|
return;
|
|
1810
1888
|
}
|
|
@@ -1815,7 +1893,7 @@ var filesUnder2 = (root, dir) => {
|
|
|
1815
1893
|
}
|
|
1816
1894
|
};
|
|
1817
1895
|
walk(resolve8(root, dir));
|
|
1818
|
-
return found.map((path) => relative3(root, path).split(
|
|
1896
|
+
return found.map((path) => relative3(root, path).split(sep3).join("/")).toSorted();
|
|
1819
1897
|
};
|
|
1820
1898
|
var lineOf3 = (body, index) => body.slice(0, index).split("\n").length;
|
|
1821
1899
|
var wordFor = (table2) => new RegExp(
|
|
@@ -1910,7 +1988,7 @@ var formatSchema = (report) => {
|
|
|
1910
1988
|
|
|
1911
1989
|
// src/smoke-run.ts
|
|
1912
1990
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
1913
|
-
import { existsSync as existsSync7, mkdirSync as mkdirSync3, readdirSync as
|
|
1991
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync3, readdirSync as readdirSync5, readFileSync as readFileSync10, rmSync as rmSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
1914
1992
|
import { join as join7, relative as relative4, resolve as resolve9 } from "path";
|
|
1915
1993
|
var BASELINE_FILE = "baseline.json";
|
|
1916
1994
|
var INSTALL = {
|
|
@@ -1985,7 +2063,7 @@ var sourceManifests = (rc) => {
|
|
|
1985
2063
|
const excluded = new Set(EXCLUDED_DIRS);
|
|
1986
2064
|
const found = [];
|
|
1987
2065
|
const walk = (dir) => {
|
|
1988
|
-
for (const entry of
|
|
2066
|
+
for (const entry of readdirSync5(dir, { withFileTypes: true })) {
|
|
1989
2067
|
if (excluded.has(entry.name)) continue;
|
|
1990
2068
|
if (entry.isDirectory()) {
|
|
1991
2069
|
walk(join7(dir, entry.name));
|
|
@@ -2402,6 +2480,89 @@ var smokeEnvelope = (comparison, durationMs) => {
|
|
|
2402
2480
|
};
|
|
2403
2481
|
};
|
|
2404
2482
|
|
|
2483
|
+
// src/changelog.ts
|
|
2484
|
+
import { existsSync as existsSync8, readdirSync as readdirSync6, readFileSync as readFileSync11 } from "fs";
|
|
2485
|
+
import { join as join8, relative as relative5, resolve as resolve10, sep as sep4 } from "path";
|
|
2486
|
+
var CHANGELOG = "CHANGELOG.md";
|
|
2487
|
+
var VERSION_HEADING = /^##\s+v?(\d+\.\d+\.\d+.*)$/;
|
|
2488
|
+
var emptyHeadingsIn = (body, at) => {
|
|
2489
|
+
const lines2 = body.split("\n");
|
|
2490
|
+
const found = [];
|
|
2491
|
+
for (const [index, line] of lines2.entries()) {
|
|
2492
|
+
const heading = VERSION_HEADING.exec(line);
|
|
2493
|
+
if (heading?.[1] === void 0) continue;
|
|
2494
|
+
const under2 = [];
|
|
2495
|
+
for (const next of lines2.slice(index + 1)) {
|
|
2496
|
+
if (next.startsWith("## ")) break;
|
|
2497
|
+
under2.push(next);
|
|
2498
|
+
}
|
|
2499
|
+
if (under2.every((one) => one.trim() === "")) found.push({ at, version: heading[1].trim() });
|
|
2500
|
+
}
|
|
2501
|
+
return found;
|
|
2502
|
+
};
|
|
2503
|
+
var countVersionHeadings = (body) => body.split("\n").filter((line) => VERSION_HEADING.test(line)).length;
|
|
2504
|
+
var checkChangelogs = ({ dirs, root }) => {
|
|
2505
|
+
if (dirs.length === 0) {
|
|
2506
|
+
throw new CannotRun(
|
|
2507
|
+
"no package directories to read a CHANGELOG.md in \u2014 this check needs the workspaces the release covers"
|
|
2508
|
+
);
|
|
2509
|
+
}
|
|
2510
|
+
const empty = [];
|
|
2511
|
+
let read = 0;
|
|
2512
|
+
let versions = 0;
|
|
2513
|
+
for (const dir of dirs) {
|
|
2514
|
+
const at = join8(dir, CHANGELOG);
|
|
2515
|
+
if (!existsSync8(resolve10(root, at))) continue;
|
|
2516
|
+
read += 1;
|
|
2517
|
+
const body = readFileSync11(resolve10(root, at), "utf8");
|
|
2518
|
+
versions += countVersionHeadings(body);
|
|
2519
|
+
empty.push(...emptyHeadingsIn(body, at));
|
|
2520
|
+
}
|
|
2521
|
+
if (read === 0) {
|
|
2522
|
+
throw new CannotRun(
|
|
2523
|
+
`none of the ${dirs.length} package(s) has a ${CHANGELOG} \u2014 a release check that read nothing has not passed`
|
|
2524
|
+
);
|
|
2525
|
+
}
|
|
2526
|
+
return { empty, read, versions };
|
|
2527
|
+
};
|
|
2528
|
+
var formatChangelogs = (report) => [
|
|
2529
|
+
...report.empty.map(
|
|
2530
|
+
(one) => `\u2717 ${one.at} \u2192 ${one.version} says a version shipped and says nothing about it`
|
|
2531
|
+
),
|
|
2532
|
+
report.empty.length === 0 ? `changelog PASS \u2014 ${report.versions} version heading(s) over ${report.read} file(s), every one of them says something` : `changelog FAIL \u2014 ${report.empty.length} of ${report.versions} version heading(s) over ${report.read} file(s) are empty`
|
|
2533
|
+
].join("\n");
|
|
2534
|
+
var NEVER_WALKED3 = /* @__PURE__ */ new Set(["build", "coverage", "dist", "node_modules", "storybook-static"]);
|
|
2535
|
+
var publishableDirs = (root) => {
|
|
2536
|
+
const found = [];
|
|
2537
|
+
const walk = (dir) => {
|
|
2538
|
+
let entries;
|
|
2539
|
+
try {
|
|
2540
|
+
entries = readdirSync6(dir, { withFileTypes: true });
|
|
2541
|
+
} catch {
|
|
2542
|
+
return;
|
|
2543
|
+
}
|
|
2544
|
+
for (const entry of entries) {
|
|
2545
|
+
if (entry.isDirectory()) {
|
|
2546
|
+
if (!entry.name.startsWith(".") && !NEVER_WALKED3.has(entry.name)) {
|
|
2547
|
+
walk(join8(dir, entry.name));
|
|
2548
|
+
}
|
|
2549
|
+
continue;
|
|
2550
|
+
}
|
|
2551
|
+
if (entry.name !== "package.json") continue;
|
|
2552
|
+
let manifest;
|
|
2553
|
+
try {
|
|
2554
|
+
manifest = JSON.parse(readFileSync11(join8(dir, entry.name), "utf8"));
|
|
2555
|
+
} catch {
|
|
2556
|
+
continue;
|
|
2557
|
+
}
|
|
2558
|
+
if (manifest.private === true || typeof manifest.name !== "string") continue;
|
|
2559
|
+
found.push(relative5(root, dir).split(sep4).join("/"));
|
|
2560
|
+
}
|
|
2561
|
+
};
|
|
2562
|
+
walk(root);
|
|
2563
|
+
return found.filter((one) => one !== "").toSorted();
|
|
2564
|
+
};
|
|
2565
|
+
|
|
2405
2566
|
export {
|
|
2406
2567
|
PHASES,
|
|
2407
2568
|
CannotRun,
|
|
@@ -2479,5 +2640,11 @@ export {
|
|
|
2479
2640
|
formatBaseline,
|
|
2480
2641
|
SMOKE_TOOL,
|
|
2481
2642
|
SMOKE_NEXT,
|
|
2482
|
-
smokeEnvelope
|
|
2643
|
+
smokeEnvelope,
|
|
2644
|
+
CHANGELOG,
|
|
2645
|
+
emptyHeadingsIn,
|
|
2646
|
+
countVersionHeadings,
|
|
2647
|
+
checkChangelogs,
|
|
2648
|
+
formatChangelogs,
|
|
2649
|
+
publishableDirs
|
|
2483
2650
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -66,6 +66,8 @@ type SnapshotRecord = {
|
|
|
66
66
|
excluded: string[];
|
|
67
67
|
files: number;
|
|
68
68
|
from: string;
|
|
69
|
+
/** Absent in a recording taken before history was recorded at all. */
|
|
70
|
+
history?: RecordedHistory;
|
|
69
71
|
lockfile: string;
|
|
70
72
|
manager: Manager;
|
|
71
73
|
manifests: {
|
|
@@ -73,11 +75,20 @@ type SnapshotRecord = {
|
|
|
73
75
|
versions: Record<string, string>;
|
|
74
76
|
}[];
|
|
75
77
|
name: string;
|
|
78
|
+
/** Directories skipped because they carry their own `.git`: a different tree inside this one. */
|
|
79
|
+
nested?: string[];
|
|
76
80
|
/** Absent when this consumer declares no `adoption.seams`, or the recording predates the block. */
|
|
77
81
|
seams?: RecordedSeams;
|
|
78
82
|
};
|
|
79
83
|
/** git asked in THEIR tree, and only ever asked: law 5 forbids this tool writing a byte there. */
|
|
80
84
|
declare const headOf: (from: string) => RecordedCommit;
|
|
85
|
+
/** What the recording can answer about where it came from, or why it can answer nothing. */
|
|
86
|
+
type RecordedHistory = {
|
|
87
|
+
depth: number;
|
|
88
|
+
head: string;
|
|
89
|
+
} | {
|
|
90
|
+
why: string;
|
|
91
|
+
};
|
|
81
92
|
declare const snapshotDir: (root: string, name: string) => string;
|
|
82
93
|
declare const readSnapshot: (root: string, name: string) => SnapshotRecord;
|
|
83
94
|
type SnapshotInput = {
|
|
@@ -101,6 +112,8 @@ type AdoptionFinding = {
|
|
|
101
112
|
type AdoptionConsumer = {
|
|
102
113
|
/** How many specs naming a package of this workspace that consumer's manifests declare. */
|
|
103
114
|
declared: number;
|
|
115
|
+
/** The floor exams a test file in the recording runs. A floor nothing exams is a floor whose break their tier cannot see (#293). */
|
|
116
|
+
exams: string[];
|
|
104
117
|
findings: AdoptionFinding[];
|
|
105
118
|
name: string;
|
|
106
119
|
seams?: RecordedSeams;
|
|
@@ -684,4 +697,41 @@ declare const statementsOf: (sql: string) => string;
|
|
|
684
697
|
/** One refusal per verb per file, at the line of that verb's first occurrence. */
|
|
685
698
|
declare const refusalsIn: (path: string, body: string, firstLine?: number) => Refusal[];
|
|
686
699
|
|
|
687
|
-
|
|
700
|
+
declare const CHANGELOG = "CHANGELOG.md";
|
|
701
|
+
type EmptyHeading = {
|
|
702
|
+
at: string;
|
|
703
|
+
version: string;
|
|
704
|
+
};
|
|
705
|
+
type ChangelogReport = {
|
|
706
|
+
/** Every `## <version>` heading with nothing under it. */
|
|
707
|
+
empty: EmptyHeading[];
|
|
708
|
+
/** How many changelogs were read. The denominator a "no findings" line is worth reading over. */
|
|
709
|
+
read: number;
|
|
710
|
+
/** Version headings seen across all of them. */
|
|
711
|
+
versions: number;
|
|
712
|
+
};
|
|
713
|
+
/**
|
|
714
|
+
* A version heading with nothing under it, in a file whose whole job is to say what a version
|
|
715
|
+
* changed. The audit found fourteen of twenty-two packages carrying at least one — a reader told
|
|
716
|
+
* that 1.2.0 shipped and told nothing else, in a tree that is published.
|
|
717
|
+
*
|
|
718
|
+
* A fixed publish group makes them by construction: every package moves to one number, and one that
|
|
719
|
+
* did not change has no changeset to render. That is a reason and not an excuse — a line saying so
|
|
720
|
+
* is a sentence, and a blank is a question.
|
|
721
|
+
*/
|
|
722
|
+
declare const emptyHeadingsIn: (body: string, at: string) => EmptyHeading[];
|
|
723
|
+
declare const countVersionHeadings: (body: string) => number;
|
|
724
|
+
type ChangelogInput = {
|
|
725
|
+
dirs: readonly string[];
|
|
726
|
+
root: string;
|
|
727
|
+
};
|
|
728
|
+
declare const checkChangelogs: ({ dirs, root }: ChangelogInput) => ChangelogReport;
|
|
729
|
+
declare const formatChangelogs: (report: ChangelogReport) => string;
|
|
730
|
+
/**
|
|
731
|
+
* Every publishable package's directory, by MANIFEST rather than by a glob: a package a workspace
|
|
732
|
+
* glob no longer claims still publishes a changelog, and a check whose denominator is a glob would
|
|
733
|
+
* pass it by not looking.
|
|
734
|
+
*/
|
|
735
|
+
declare const publishableDirs: (root: string) => string[];
|
|
736
|
+
|
|
737
|
+
export { ADOPTION_NEXT, ADOPTION_TOOL, type AdoptionConsumer, type AdoptionFinding, type AdoptionReport, type AdoptionVerdict, BASELINE_FILE, CHANGELOG, CONSUMER_TREES_FILE, type ChangelogInput, type ChangelogReport, type Command, DEFAULT_REGISTRY, DEPLOYED_FILE, type Declared, type Deployed, type DeployedReport, type Dialect, type Drift, EXCLUDED_DIRS, EXISTS_BUT, type EmptyHeading, type Manager, type MigrationDir, type MigrationsReport, NARROWING, NOTHING_SAYS, PHASES, PLANTS, type Packed, type Phase, type PhaseOutcome, type PlanReport, type ProveOutcome, type PublishedLine, type PublishedReport, type PublishedVerdict, type RecordedCommit, type RecordedSeams, type Refusal, type RegistryAnswer, type ReleaseConfig, Runner, SMOKE_NEXT, SMOKE_TOOL, SNAPSHOTS_DIR, STEPS, type SchemaConfig, type SchemaDomain, type SchemaFinding, type SchemaReport, type SmokeBaseline, type SmokeComparison, type SmokePhase, type SmokeSweep, type SnapshotRecord, type SweepEntry, type SweepNote, type Verdict, WHY_VERSION_IDENTITY, type WantedSnapshot, addSqlIn, adoptionEnvelope, askRegistry, censusOf, checkChangelogs, compareToBaseline, comparisonsIn, countVersionHeadings, declaredIn, driftBetween, emptyHeadingsIn, formatAdoption, formatBaseline, formatChangelogs, formatDeployed, formatMigrations, formatPlan, formatProve, formatPublished, formatSchema, formatSmoke, formatSnapshot, formatSweep, formatVerdict, headOf, markersIn, packRc, parseJsonc, parseReleaseConfig, parseToml, promisedButNotPacked, prove, proveOver, publishableDirs, readBaseline, readDeployed, readReleaseConfig, readSnapshot, readWrangler, recordBaseline, refusalsIn, registryPathOf, rewriteManifests, runAdoption, runDeployed, runMigrations, runPlan, runPublished, runSchema, runSmoke, runSnapshot, smokeEnvelope, snapshotDir, statementsOf, sweepEnvelope, sweepSmoke };
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
ADOPTION_NEXT,
|
|
3
3
|
ADOPTION_TOOL,
|
|
4
4
|
BASELINE_FILE,
|
|
5
|
+
CHANGELOG,
|
|
5
6
|
CONSUMER_TREES_FILE,
|
|
6
7
|
DEFAULT_REGISTRY,
|
|
7
8
|
DEPLOYED_FILE,
|
|
@@ -21,12 +22,16 @@ import {
|
|
|
21
22
|
adoptionEnvelope,
|
|
22
23
|
askRegistry,
|
|
23
24
|
censusOf,
|
|
25
|
+
checkChangelogs,
|
|
24
26
|
compareToBaseline,
|
|
25
27
|
comparisonsIn,
|
|
28
|
+
countVersionHeadings,
|
|
26
29
|
declaredIn,
|
|
27
30
|
driftBetween,
|
|
31
|
+
emptyHeadingsIn,
|
|
28
32
|
formatAdoption,
|
|
29
33
|
formatBaseline,
|
|
34
|
+
formatChangelogs,
|
|
30
35
|
formatDeployed,
|
|
31
36
|
formatMigrations,
|
|
32
37
|
formatPlan,
|
|
@@ -46,6 +51,7 @@ import {
|
|
|
46
51
|
promisedButNotPacked,
|
|
47
52
|
prove,
|
|
48
53
|
proveOver,
|
|
54
|
+
publishableDirs,
|
|
49
55
|
readBaseline,
|
|
50
56
|
readDeployed,
|
|
51
57
|
readReleaseConfig,
|
|
@@ -68,11 +74,12 @@ import {
|
|
|
68
74
|
statementsOf,
|
|
69
75
|
sweepEnvelope,
|
|
70
76
|
sweepSmoke
|
|
71
|
-
} from "./chunk-
|
|
77
|
+
} from "./chunk-7H7SV5EP.js";
|
|
72
78
|
export {
|
|
73
79
|
ADOPTION_NEXT,
|
|
74
80
|
ADOPTION_TOOL,
|
|
75
81
|
BASELINE_FILE,
|
|
82
|
+
CHANGELOG,
|
|
76
83
|
CONSUMER_TREES_FILE,
|
|
77
84
|
DEFAULT_REGISTRY,
|
|
78
85
|
DEPLOYED_FILE,
|
|
@@ -92,12 +99,16 @@ export {
|
|
|
92
99
|
adoptionEnvelope,
|
|
93
100
|
askRegistry,
|
|
94
101
|
censusOf,
|
|
102
|
+
checkChangelogs,
|
|
95
103
|
compareToBaseline,
|
|
96
104
|
comparisonsIn,
|
|
105
|
+
countVersionHeadings,
|
|
97
106
|
declaredIn,
|
|
98
107
|
driftBetween,
|
|
108
|
+
emptyHeadingsIn,
|
|
99
109
|
formatAdoption,
|
|
100
110
|
formatBaseline,
|
|
111
|
+
formatChangelogs,
|
|
101
112
|
formatDeployed,
|
|
102
113
|
formatMigrations,
|
|
103
114
|
formatPlan,
|
|
@@ -117,6 +128,7 @@ export {
|
|
|
117
128
|
promisedButNotPacked,
|
|
118
129
|
prove,
|
|
119
130
|
proveOver,
|
|
131
|
+
publishableDirs,
|
|
120
132
|
readBaseline,
|
|
121
133
|
readDeployed,
|
|
122
134
|
readReleaseConfig,
|
package/dist/release-cli.js
CHANGED
|
@@ -7,9 +7,11 @@ import {
|
|
|
7
7
|
SCHEMA_NEXT,
|
|
8
8
|
SMOKE_NEXT,
|
|
9
9
|
adoptionEnvelope,
|
|
10
|
+
checkChangelogs,
|
|
10
11
|
comparisonsIn,
|
|
11
12
|
formatAdoption,
|
|
12
13
|
formatBaseline,
|
|
14
|
+
formatChangelogs,
|
|
13
15
|
formatDeployed,
|
|
14
16
|
formatMigrations,
|
|
15
17
|
formatPlan,
|
|
@@ -22,6 +24,7 @@ import {
|
|
|
22
24
|
migrationsEnvelope,
|
|
23
25
|
prove,
|
|
24
26
|
proveOver,
|
|
27
|
+
publishableDirs,
|
|
25
28
|
publishedEnvelope,
|
|
26
29
|
readReleaseConfig,
|
|
27
30
|
recordBaseline,
|
|
@@ -36,11 +39,24 @@ import {
|
|
|
36
39
|
sweepEnvelope,
|
|
37
40
|
sweepSmoke,
|
|
38
41
|
writeEnvelope
|
|
39
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-7H7SV5EP.js";
|
|
40
43
|
|
|
41
44
|
// src/release-cli.ts
|
|
42
45
|
import { existsSync } from "fs";
|
|
43
46
|
import { join, resolve } from "path";
|
|
47
|
+
|
|
48
|
+
// src/since.ts
|
|
49
|
+
var MEANS = {
|
|
50
|
+
date: {
|
|
51
|
+
is: (value) => /^\d{4}-\d{2}-\d{2}$/.test(value) && !Number.isNaN(Date.parse(value)),
|
|
52
|
+
shape: "a YYYY-MM-DD date"
|
|
53
|
+
},
|
|
54
|
+
plan: { is: (value) => /^\d+$/.test(value), shape: "a plan number" },
|
|
55
|
+
ref: { is: (value) => value !== "" && !value.startsWith("-"), shape: "a git ref" }
|
|
56
|
+
};
|
|
57
|
+
var unreadableSince = (value, kind) => MEANS[kind].is(value) ? void 0 : `--since must be ${MEANS[kind].shape} \u2014 "${value}" is not one`;
|
|
58
|
+
|
|
59
|
+
// src/release-cli.ts
|
|
44
60
|
var USAGE = `geonosis-release <command> [options]
|
|
45
61
|
|
|
46
62
|
migrations --since <ref> [--dialect <name>] [--root <dir>] [--json]
|
|
@@ -57,6 +73,15 @@ var USAGE = `geonosis-release <command> [options]
|
|
|
57
73
|
|
|
58
74
|
Exit 0 clean, 1 refusals, 2 the run could not be made.
|
|
59
75
|
|
|
76
|
+
changelog [--root <dir>] [--json]
|
|
77
|
+
|
|
78
|
+
Every publishable package's CHANGELOG.md, and every "## <version>" heading with
|
|
79
|
+
nothing under it. A reader told that 1.2.0 shipped and told nothing else has been
|
|
80
|
+
told less than nothing; a fixed publish group makes those headings by construction,
|
|
81
|
+
which is a reason to write the sentence and not a reason to leave the blank.
|
|
82
|
+
|
|
83
|
+
Exit 0 clean, 1 an empty heading, 2 no changelog to read at all.
|
|
84
|
+
|
|
60
85
|
schema [--root <dir>] [--json]
|
|
61
86
|
|
|
62
87
|
The wall no oxlint rule can see. Over every migration under every directory
|
|
@@ -199,6 +224,8 @@ var rootOf = (parsed, cwd) => resolve(cwd, parsed.read["--root"] ?? cwd);
|
|
|
199
224
|
var migrations = (parsed, cwd) => {
|
|
200
225
|
const since = parsed.read["--since"];
|
|
201
226
|
if (since === void 0) throw new CannotRun("migrations needs --since <ref>");
|
|
227
|
+
const unreadable = unreadableSince(since, "ref");
|
|
228
|
+
if (unreadable !== void 0) throw new CannotRun(unreadable);
|
|
202
229
|
const dialect = parsed.read["--dialect"];
|
|
203
230
|
if (dialect !== void 0 && !DIALECTS.has(dialect)) {
|
|
204
231
|
throw new CannotRun(`--dialect must be one of ${[...DIALECTS].toSorted().join(", ")}`);
|
|
@@ -242,6 +269,16 @@ var schema = (parsed, cwd) => {
|
|
|
242
269
|
if (report.unreadable.length > 0) return 2;
|
|
243
270
|
return report.ok ? 0 : 1;
|
|
244
271
|
};
|
|
272
|
+
var changelog = (parsed, cwd) => {
|
|
273
|
+
const root = rootOf(parsed, cwd);
|
|
274
|
+
const report = checkChangelogs({ dirs: publishableDirs(root), root });
|
|
275
|
+
process.stdout.write(
|
|
276
|
+
parsed.json ? `${JSON.stringify(report, void 0, 2)}
|
|
277
|
+
` : `${formatChangelogs(report)}
|
|
278
|
+
`
|
|
279
|
+
);
|
|
280
|
+
return report.empty.length === 0 ? 0 : 1;
|
|
281
|
+
};
|
|
245
282
|
var plan = (parsed, cwd) => {
|
|
246
283
|
const report = runPlan({
|
|
247
284
|
accept: parsed.flags.has("--i-accept-an-unproven-smoke"),
|
|
@@ -487,6 +524,7 @@ var main = async () => {
|
|
|
487
524
|
if (stray !== void 0) throw new CannotRun(`unknown argument "${stray}"`);
|
|
488
525
|
if (parsed.command === "migrations") return migrations(parsed, process.cwd());
|
|
489
526
|
if (parsed.command === "plan") return plan(parsed, process.cwd());
|
|
527
|
+
if (parsed.command === "changelog") return changelog(parsed, process.cwd());
|
|
490
528
|
if (parsed.command === "schema") return schema(parsed, process.cwd());
|
|
491
529
|
if (parsed.command === "prove") return proving(parsed, process.cwd());
|
|
492
530
|
if (parsed.command === "deployed") return deployed(parsed, process.cwd());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geonosis/release",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.1",
|
|
4
4
|
"types": "./dist/index.d.ts",
|
|
5
5
|
"description": "The release contract with its proofs: an expand-only migration gate over three dialects, a smoke that must name the version that answered it, and declared ≠ deployed.",
|
|
6
6
|
"keywords": [
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"squawk-cli": "2.63.0",
|
|
48
|
-
"@geonosis/ratchet": "2.
|
|
48
|
+
"@geonosis/ratchet": "2.3.1"
|
|
49
49
|
},
|
|
50
50
|
"engines": {
|
|
51
51
|
"node": ">=22"
|