@geonosis/release 2.0.0 → 2.2.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/index.d.ts CHANGED
@@ -1,5 +1,133 @@
1
1
  import { ReportEnvelope } from '@geonosis/ratchet';
2
2
 
3
+ /** What a phase runs: a script of theirs, a binary their install put there, or nothing at all. */
4
+ type Command = {
5
+ exec: string;
6
+ } | {
7
+ run: string;
8
+ } | {
9
+ why: string;
10
+ };
11
+ type SmokePhase = 'doctor' | 'lint' | 'test' | 'typecheck';
12
+ /**
13
+ * The gates a release is read against, in the order they run.
14
+ *
15
+ * Its own module because the runner and the config reader both need it and each imports the other:
16
+ * read through `smoke.ts`, `PHASES` was still undefined when `config.ts` initialised, and the
17
+ * config refused every `geonosis.json` with `Cannot read properties of undefined`.
18
+ *
19
+ * #272: `test` is here because a floor change can keep a consumer's types and their linter green
20
+ * and still redden their suites — the one thing only their own tests can say. A recording taken
21
+ * before it existed has no baseline for the phase, and a phase with nothing to compare against is
22
+ * reported as uncomparable rather than as a pass.
23
+ */
24
+ declare const PHASES: SmokePhase[];
25
+
26
+ /**
27
+ * Where a consumer's bytes live while the release is being read against them.
28
+ *
29
+ * D-048: a consumer tree is private, and a copy of one that reaches a commit cannot be taken back.
30
+ * The directory is under `.geonosis/`, which every repo in this kit's orbit already ignores, and
31
+ * `smoke snapshot` asks git — in the tree it is about to write into — whether that is still true
32
+ * before it copies a single file.
33
+ */
34
+ declare const SNAPSHOTS_DIR = ".geonosis/consumer-snapshots";
35
+ /** The managers a snapshot can be installed with here, each measured on this machine. */
36
+ type Manager = 'bun' | 'pnpm';
37
+ /**
38
+ * Directories a consumer builds or installs into. They are excluded by name at every depth: the
39
+ * snapshot is the SOURCE of a tree, and the install the smoke runs is the thing under test.
40
+ */
41
+ declare const EXCLUDED_DIRS: string[];
42
+ /** Where the source tree stood, or the sentence saying why nothing here could say. */
43
+ type RecordedCommit = {
44
+ sha: string;
45
+ } | {
46
+ why: string;
47
+ };
48
+ /**
49
+ * The seam a consumer declared, measured on the bytes this recording holds (#280).
50
+ *
51
+ * The user's rule for a floor: it is adopted the day it deletes more than it adds. The sweep can
52
+ * only say so about trees it has recorded, so the number is taken WHERE the tree is read — a
53
+ * `.geonosis/` of theirs never reaches a snapshot (it is an excluded directory), so their own bump
54
+ * report is not available here and this is the figure that is.
55
+ */
56
+ type RecordedSeams = {
57
+ globs: string[];
58
+ lines: number;
59
+ };
60
+ type SnapshotRecord = {
61
+ at: string;
62
+ bytes: number;
63
+ /** Absent in a recording taken before this was recorded at all. */
64
+ commit?: RecordedCommit;
65
+ commands: Record<SmokePhase, Command>;
66
+ excluded: string[];
67
+ files: number;
68
+ from: string;
69
+ lockfile: string;
70
+ manager: Manager;
71
+ manifests: {
72
+ path: string;
73
+ versions: Record<string, string>;
74
+ }[];
75
+ name: string;
76
+ /** Absent when this consumer declares no `adoption.seams`, or the recording predates the block. */
77
+ seams?: RecordedSeams;
78
+ };
79
+ /** git asked in THEIR tree, and only ever asked: law 5 forbids this tool writing a byte there. */
80
+ declare const headOf: (from: string) => RecordedCommit;
81
+ declare const snapshotDir: (root: string, name: string) => string;
82
+ declare const readSnapshot: (root: string, name: string) => SnapshotRecord;
83
+ type SnapshotInput = {
84
+ exclude?: string[];
85
+ from: string;
86
+ name: string;
87
+ named: Partial<Record<SmokePhase, string>>;
88
+ replace: boolean;
89
+ root: string;
90
+ };
91
+ declare const runSnapshot: (input: SnapshotInput) => SnapshotRecord;
92
+ declare const formatSnapshot: (record: SnapshotRecord) => string;
93
+
94
+ type AdoptionVerdict = 'BEHIND' | 'FLOOR UNDECLARED' | 'INCOHERENT' | 'UNJUDGED';
95
+ type AdoptionFinding = {
96
+ consumer: string;
97
+ detail: string;
98
+ name: string;
99
+ verdict: AdoptionVerdict;
100
+ };
101
+ type AdoptionConsumer = {
102
+ /** How many specs naming a package of this workspace that consumer's manifests declare. */
103
+ declared: number;
104
+ findings: AdoptionFinding[];
105
+ name: string;
106
+ seams?: RecordedSeams;
107
+ };
108
+ type AdoptionReport = {
109
+ considered: number;
110
+ consumers: AdoptionConsumer[];
111
+ excused: {
112
+ path: string;
113
+ reason: string;
114
+ }[];
115
+ /** The registry the current numbers came from, or undefined when they came off this workspace. */
116
+ registry: string | undefined;
117
+ versions: Record<string, string>;
118
+ };
119
+ declare const runAdoption: ({ declared, registry, root, }: {
120
+ declared: {
121
+ name: string;
122
+ }[];
123
+ registry?: string;
124
+ root: string;
125
+ }) => Promise<AdoptionReport>;
126
+ declare const formatAdoption: (report: AdoptionReport) => string;
127
+ declare const ADOPTION_TOOL = "release-adoption";
128
+ declare const ADOPTION_NEXT = "geonosis-release adoption --json and read `consumers` \u2014 every declared consumer leaves by exactly one door, read or excused, and a release review carries one row per consumer from it (D-061)";
129
+ declare const adoptionEnvelope: (report: AdoptionReport, durationMs: number) => ReportEnvelope;
130
+
3
131
  /** The dialects the gate can route to. A dialect is never sniffed: it is what the repo declared. */
4
132
  type Dialect = 'mikro-orm-ts' | 'postgres' | 'sqlite';
5
133
  type Phase = 'down' | 'up';
@@ -40,8 +168,12 @@ type SchemaReport = {
40
168
  why: string;
41
169
  }[];
42
170
  };
43
- /** One consumer tree a release must be read against, and how that one is installed. */
171
+ /**
172
+ * One consumer tree a release must be read against, how that one is installed, and the commands
173
+ * that are ITS gates when the three script names are not what that tree calls them.
174
+ */
44
175
  type SmokeSnapshotConfig = {
176
+ commands?: Partial<Record<'doctor' | 'lint' | 'typecheck', string>>;
45
177
  install?: string;
46
178
  name: string;
47
179
  };
@@ -372,60 +504,6 @@ declare class Runner {
372
504
  close(): void;
373
505
  }
374
506
 
375
- /**
376
- * Where a consumer's bytes live while the release is being read against them.
377
- *
378
- * D-048: a consumer tree is private, and a copy of one that reaches a commit cannot be taken back.
379
- * The directory is under `.geonosis/`, which every repo in this kit's orbit already ignores, and
380
- * `smoke snapshot` asks git — in the tree it is about to write into — whether that is still true
381
- * before it copies a single file.
382
- */
383
- declare const SNAPSHOTS_DIR = ".geonosis/consumer-snapshots";
384
- /** The managers a snapshot can be installed with here, each measured on this machine. */
385
- type Manager = 'bun' | 'pnpm';
386
- /**
387
- * Directories a consumer builds or installs into. They are excluded by name at every depth: the
388
- * snapshot is the SOURCE of a tree, and the install the smoke runs is the thing under test.
389
- */
390
- declare const EXCLUDED_DIRS: string[];
391
- /** What a phase runs: a script of theirs, a binary their install put there, or nothing at all. */
392
- type Command = {
393
- exec: string;
394
- } | {
395
- run: string;
396
- } | {
397
- why: string;
398
- };
399
- type SmokePhase = 'doctor' | 'lint' | 'typecheck';
400
- declare const PHASES: SmokePhase[];
401
- type SnapshotRecord = {
402
- at: string;
403
- bytes: number;
404
- commands: Record<SmokePhase, Command>;
405
- excluded: string[];
406
- files: number;
407
- from: string;
408
- lockfile: string;
409
- manager: Manager;
410
- manifests: {
411
- path: string;
412
- versions: Record<string, string>;
413
- }[];
414
- name: string;
415
- };
416
- declare const snapshotDir: (root: string, name: string) => string;
417
- declare const readSnapshot: (root: string, name: string) => SnapshotRecord;
418
- type SnapshotInput = {
419
- exclude?: string[];
420
- from: string;
421
- name: string;
422
- named: Partial<Record<SmokePhase, string>>;
423
- replace: boolean;
424
- root: string;
425
- };
426
- declare const runSnapshot: (input: SnapshotInput) => SnapshotRecord;
427
- declare const formatSnapshot: (record: SnapshotRecord) => string;
428
-
429
507
  /** What a phase did, or the sentence saying there was nothing of theirs to do it with. */
430
508
  type PhaseOutcome = {
431
509
  code: number;
@@ -490,6 +568,7 @@ declare const rewriteManifests: (tree: string, manifests: string[], packed: Pack
490
568
  path: string;
491
569
  }[];
492
570
  type RunInput = {
571
+ commands?: Partial<Record<SmokePhase, string>>;
493
572
  install?: string;
494
573
  name: string;
495
574
  rc?: string;
@@ -499,16 +578,42 @@ declare const recordBaseline: (input: RunInput) => SmokeBaseline;
499
578
  declare const readBaseline: (root: string, name: string) => SmokeBaseline;
500
579
  declare const compareToBaseline: (name: string, baseline: SmokeBaseline, outcomes: PhaseOutcome[], findings: string[]) => SmokeComparison;
501
580
  declare const runSmoke: (input: RunInput) => SmokeComparison;
502
- type SmokeSkip = {
581
+ /**
582
+ * What the sweep can say about WHEN a recording was taken: that its source has moved on, or that
583
+ * the question cannot be asked of it at all.
584
+ */
585
+ type SweepNote = {
586
+ stale: string;
587
+ } | {
588
+ undated: string;
589
+ };
590
+ /** One declared consumer's turn in the sweep, in the order the repo declared it. */
591
+ type SweepEntry = {
592
+ comparison: SmokeComparison;
593
+ name: string;
594
+ note?: SweepNote;
595
+ } | {
503
596
  name: string;
504
597
  why: string;
505
598
  };
506
599
  type SmokeSweep = {
507
- comparisons: SmokeComparison[];
508
- skipped: SmokeSkip[];
600
+ entries: SweepEntry[];
601
+ };
602
+ type WantedSnapshot = {
603
+ commands?: Partial<Record<SmokePhase, string>>;
604
+ install?: string;
605
+ name: string;
509
606
  };
510
607
  /**
511
- * Every snapshot the release expects, read in turn.
608
+ * Where a consumer tree that has never been recorded lives on THIS machine.
609
+ *
610
+ * A never-recorded name has no `from` to look at, so the paths are declared here — uncommitted,
611
+ * under the directory D-048 already keeps out of git, because a machine's checkout layout is one
612
+ * developer's and not the repo's.
613
+ */
614
+ declare const CONSUMER_TREES_FILE = ".geonosis/consumer-trees.local.json";
615
+ /**
616
+ * Every snapshot the release expects, read in turn, in the order the repo declared them.
512
617
  *
513
618
  * A tree that is not on this machine is SKIPPED with the sentence saying so — a laptop without the
514
619
  * consumer trees must not fail, it must say what it could not ask. The skip is not free: its three
@@ -516,6 +621,8 @@ type SmokeSweep = {
516
621
  * read as a sweep that asked everything.
517
622
  */
518
623
  declare const sweepSmoke: (input: {
624
+ /** Declared names this run is excused from reading, each said out loud on the command line. */
625
+ absent?: string[];
519
626
  rc?: string;
520
627
  root: string;
521
628
  /**
@@ -524,11 +631,9 @@ declare const sweepSmoke: (input: {
524
631
  * has to be answered, not stepped around.
525
632
  */
526
633
  skipMissing: boolean;
527
- wanted: {
528
- install?: string;
529
- name: string;
530
- }[];
634
+ wanted: WantedSnapshot[];
531
635
  }) => SmokeSweep;
636
+ declare const comparisonsIn: (sweep: SmokeSweep) => SmokeComparison[];
532
637
  declare const formatSweep: (sweep: SmokeSweep) => string;
533
638
  declare const sweepEnvelope: (sweep: SmokeSweep, durationMs: number) => ReportEnvelope;
534
639
  declare const formatSmoke: (comparison: SmokeComparison) => string;
@@ -579,4 +684,4 @@ declare const statementsOf: (sql: string) => string;
579
684
  /** One refusal per verb per file, at the line of that verb's first occurrence. */
580
685
  declare const refusalsIn: (path: string, body: string, firstLine?: number) => Refusal[];
581
686
 
582
- export { BASELINE_FILE, type Command, DEFAULT_REGISTRY, DEPLOYED_FILE, type Declared, type Deployed, type DeployedReport, type Dialect, type Drift, EXCLUDED_DIRS, EXISTS_BUT, 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 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 SmokeSkip, type SmokeSweep, type SnapshotRecord, type Verdict, WHY_VERSION_IDENTITY, addSqlIn, askRegistry, censusOf, compareToBaseline, declaredIn, driftBetween, formatBaseline, formatDeployed, formatMigrations, formatPlan, formatProve, formatPublished, formatSchema, formatSmoke, formatSnapshot, formatSweep, formatVerdict, markersIn, packRc, parseJsonc, parseReleaseConfig, parseToml, promisedButNotPacked, prove, proveOver, readBaseline, readDeployed, readReleaseConfig, readSnapshot, readWrangler, recordBaseline, refusalsIn, registryPathOf, rewriteManifests, runDeployed, runMigrations, runPlan, runPublished, runSchema, runSmoke, runSnapshot, smokeEnvelope, snapshotDir, statementsOf, sweepEnvelope, sweepSmoke };
687
+ export { ADOPTION_NEXT, ADOPTION_TOOL, type AdoptionConsumer, type AdoptionFinding, type AdoptionReport, type AdoptionVerdict, BASELINE_FILE, CONSUMER_TREES_FILE, type Command, DEFAULT_REGISTRY, DEPLOYED_FILE, type Declared, type Deployed, type DeployedReport, type Dialect, type Drift, EXCLUDED_DIRS, EXISTS_BUT, 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, compareToBaseline, comparisonsIn, declaredIn, driftBetween, formatAdoption, formatBaseline, formatDeployed, formatMigrations, formatPlan, formatProve, formatPublished, formatSchema, formatSmoke, formatSnapshot, formatSweep, formatVerdict, headOf, markersIn, packRc, parseJsonc, parseReleaseConfig, parseToml, promisedButNotPacked, prove, proveOver, 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
@@ -1,5 +1,8 @@
1
1
  import {
2
+ ADOPTION_NEXT,
3
+ ADOPTION_TOOL,
2
4
  BASELINE_FILE,
5
+ CONSUMER_TREES_FILE,
3
6
  DEFAULT_REGISTRY,
4
7
  DEPLOYED_FILE,
5
8
  EXCLUDED_DIRS,
@@ -15,11 +18,14 @@ import {
15
18
  STEPS,
16
19
  WHY_VERSION_IDENTITY,
17
20
  addSqlIn,
21
+ adoptionEnvelope,
18
22
  askRegistry,
19
23
  censusOf,
20
24
  compareToBaseline,
25
+ comparisonsIn,
21
26
  declaredIn,
22
27
  driftBetween,
28
+ formatAdoption,
23
29
  formatBaseline,
24
30
  formatDeployed,
25
31
  formatMigrations,
@@ -31,6 +37,7 @@ import {
31
37
  formatSnapshot,
32
38
  formatSweep,
33
39
  formatVerdict,
40
+ headOf,
34
41
  markersIn,
35
42
  packRc,
36
43
  parseJsonc,
@@ -48,6 +55,7 @@ import {
48
55
  refusalsIn,
49
56
  registryPathOf,
50
57
  rewriteManifests,
58
+ runAdoption,
51
59
  runDeployed,
52
60
  runMigrations,
53
61
  runPlan,
@@ -60,9 +68,12 @@ import {
60
68
  statementsOf,
61
69
  sweepEnvelope,
62
70
  sweepSmoke
63
- } from "./chunk-KQIWTXQP.js";
71
+ } from "./chunk-IPCIF5DO.js";
64
72
  export {
73
+ ADOPTION_NEXT,
74
+ ADOPTION_TOOL,
65
75
  BASELINE_FILE,
76
+ CONSUMER_TREES_FILE,
66
77
  DEFAULT_REGISTRY,
67
78
  DEPLOYED_FILE,
68
79
  EXCLUDED_DIRS,
@@ -78,11 +89,14 @@ export {
78
89
  STEPS,
79
90
  WHY_VERSION_IDENTITY,
80
91
  addSqlIn,
92
+ adoptionEnvelope,
81
93
  askRegistry,
82
94
  censusOf,
83
95
  compareToBaseline,
96
+ comparisonsIn,
84
97
  declaredIn,
85
98
  driftBetween,
99
+ formatAdoption,
86
100
  formatBaseline,
87
101
  formatDeployed,
88
102
  formatMigrations,
@@ -94,6 +108,7 @@ export {
94
108
  formatSnapshot,
95
109
  formatSweep,
96
110
  formatVerdict,
111
+ headOf,
97
112
  markersIn,
98
113
  packRc,
99
114
  parseJsonc,
@@ -111,6 +126,7 @@ export {
111
126
  refusalsIn,
112
127
  registryPathOf,
113
128
  rewriteManifests,
129
+ runAdoption,
114
130
  runDeployed,
115
131
  runMigrations,
116
132
  runPlan,
@@ -1,10 +1,14 @@
1
1
  import {
2
+ ADOPTION_NEXT,
2
3
  CannotRun,
3
4
  DEFAULT_REGISTRY,
4
5
  MIGRATIONS_NEXT,
5
6
  PUBLISHED_NEXT,
6
7
  SCHEMA_NEXT,
7
8
  SMOKE_NEXT,
9
+ adoptionEnvelope,
10
+ comparisonsIn,
11
+ formatAdoption,
8
12
  formatBaseline,
9
13
  formatDeployed,
10
14
  formatMigrations,
@@ -21,6 +25,7 @@ import {
21
25
  publishedEnvelope,
22
26
  readReleaseConfig,
23
27
  recordBaseline,
28
+ runAdoption,
24
29
  runDeployed,
25
30
  runMigrations,
26
31
  runPlan,
@@ -31,7 +36,7 @@ import {
31
36
  sweepEnvelope,
32
37
  sweepSmoke,
33
38
  writeEnvelope
34
- } from "./chunk-KQIWTXQP.js";
39
+ } from "./chunk-IPCIF5DO.js";
35
40
 
36
41
  // src/release-cli.ts
37
42
  import { existsSync } from "fs";
@@ -101,8 +106,20 @@ var USAGE = `geonosis-release <command> [options]
101
106
 
102
107
  Exit 0 the whole group is there, 1 a gap, 2 the registry could not be asked.
103
108
 
109
+ adoption [--registry <url>] [--root <dir>] [--json]
110
+
111
+ How far every declared consumer is from the version this workspace holds, read off
112
+ the recordings the smoke keeps and never off a consumer's disk. Per consumer: MATCH,
113
+ BEHIND <name> <declared> \u2192 <current>, INCOHERENT (a group published as one number
114
+ declared at two), FLOOR UNDECLARED (informational \u2014 a floor is opted into).
115
+
116
+ --registry compares against what npm answers instead of against this workspace.
117
+
118
+ Exit 0 always: it is a report, and the release review carries one row per consumer
119
+ from it (D-061).
120
+
104
121
  smoke snapshot <name> --from <their tree> [--replace] [--root <dir>] [--json]
105
- [--typecheck <cmd>] [--lint <cmd>] [--doctor <cmd>]
122
+ [--typecheck <cmd>] [--lint <cmd>] [--test <cmd>] [--doctor <cmd>]
106
123
 
107
124
  Copy a consumer tree, read-only, into .geonosis/consumer-snapshots/<name>/ \u2014 the
108
125
  thing a release must be read against. Installed packages, build output and the git
@@ -113,20 +130,28 @@ var USAGE = `geonosis-release <command> [options]
113
130
  them be committed.
114
131
 
115
132
  smoke baseline --snapshot <name> [--rc-dir <workspace>] [--install <cmd>] [--json]
116
- smoke run --snapshot <name> [--rc-dir <workspace>] [--install <cmd>] [--json]
133
+ smoke run [--snapshot <name>] [--absent <name>]... [--rc-dir <workspace>] [--install <cmd>]
134
+ [--json]
117
135
 
118
136
  Pack every workspace package of the release candidate (\`pnpm pack\` \u2014 a tarball is
119
137
  what a consumer installs, and a release that shipped no declarations shipped them in
120
138
  the tree and not in the tarball), point a COPY of the snapshot's manifests at those
121
139
  tarballs, install with the snapshot's own manager, and run the snapshot's own
122
- typecheck, lint and doctor.
140
+ typecheck, lint, tests and doctor.
123
141
 
124
- \`baseline\` records what those three answered at the versions the consumer is on.
142
+ \`baseline\` records what those four answered at the versions the consumer is on.
125
143
  \`run\` compares against it and refuses only what THIS release broke, in their
126
144
  compiler's and their doctor's own lines. Exit 0 nothing new, 1 a new failure,
127
145
  2 the run could not be made \u2014 including a phase the baseline cannot be compared to.
146
+
147
+ With no --snapshot it sweeps every consumer geonosis.json declares, one block each in
148
+ declaration order. A declared name with no recording whose tree is on this machine \u2014
149
+ named in .geonosis/consumer-trees.local.json, uncommitted \u2014 REFUSES with the snapshot
150
+ command to run; --absent <name> excuses one out loud and keeps it in the count. A
151
+ recording whose source tree has moved since it was taken prints STALE.
128
152
  `;
129
153
  var VALUED = /* @__PURE__ */ new Set([
154
+ "--absent",
130
155
  "--dialect",
131
156
  "--doctor",
132
157
  "--from",
@@ -138,12 +163,14 @@ var VALUED = /* @__PURE__ */ new Set([
138
163
  "--runner",
139
164
  "--since",
140
165
  "--snapshot",
166
+ "--test",
141
167
  "--typecheck",
142
168
  "--wait"
143
169
  ]);
144
170
  var FLAGS = /* @__PURE__ */ new Set(["--check", "--group", "--i-accept-an-unproven-smoke", "--json", "--replace"]);
145
171
  var DIALECTS = /* @__PURE__ */ new Set(["mikro-orm-ts", "postgres", "sqlite"]);
146
172
  var parseArgs = (argv) => {
173
+ const many = {};
147
174
  const read = {};
148
175
  const flags = /* @__PURE__ */ new Set();
149
176
  const rest = [];
@@ -163,9 +190,10 @@ var parseArgs = (argv) => {
163
190
  const value = argv[index + 1];
164
191
  if (value === void 0 || value.startsWith("--")) throw new CannotRun(`${flag} needs a value`);
165
192
  read[flag] = value;
193
+ many[flag] = [...many[flag] ?? [], value];
166
194
  index += 1;
167
195
  }
168
- return { command: argv[0] ?? "", flags, json, read, rest };
196
+ return { command: argv[0] ?? "", flags, json, many, read, rest };
169
197
  };
170
198
  var rootOf = (parsed, cwd) => resolve(cwd, parsed.read["--root"] ?? cwd);
171
199
  var migrations = (parsed, cwd) => {
@@ -281,9 +309,32 @@ var published = async (parsed, cwd) => {
281
309
  if (report.unreachable > 0) return 2;
282
310
  return report.ok ? 0 : 1;
283
311
  };
312
+ var adoption = async (parsed, cwd) => {
313
+ const root = rootOf(parsed, cwd);
314
+ const startedAt = Date.now();
315
+ const registry = parsed.read["--registry"];
316
+ const report = await runAdoption({
317
+ declared: readReleaseConfig(root).smoke?.snapshots ?? [],
318
+ ...registry === void 0 ? {} : { registry },
319
+ root
320
+ });
321
+ process.stdout.write(
322
+ parsed.json ? `${JSON.stringify(report, void 0, 2)}
323
+ ` : formatAdoption(report)
324
+ );
325
+ const at = writeEnvelope({
326
+ envelope: adoptionEnvelope(report, Date.now() - startedAt),
327
+ next: ADOPTION_NEXT,
328
+ root
329
+ });
330
+ if (!parsed.json) process.stdout.write(`envelope: ${at}
331
+ `);
332
+ return 0;
333
+ };
284
334
  var namedCommands = (parsed) => ({
285
335
  ...parsed.read["--doctor"] === void 0 ? {} : { doctor: parsed.read["--doctor"] },
286
336
  ...parsed.read["--lint"] === void 0 ? {} : { lint: parsed.read["--lint"] },
337
+ ...parsed.read["--test"] === void 0 ? {} : { test: parsed.read["--test"] },
287
338
  ...parsed.read["--typecheck"] === void 0 ? {} : { typecheck: parsed.read["--typecheck"] }
288
339
  });
289
340
  var snapshot = (parsed, root) => {
@@ -315,7 +366,11 @@ var wantedSnapshots = (parsed, root) => {
315
366
  const install = parsed.read["--install"];
316
367
  const withFlag = (one) => {
317
368
  const chosen = install ?? one.install;
318
- return { ...chosen === void 0 ? {} : { install: chosen }, name: one.name };
369
+ return {
370
+ ...one.commands === void 0 ? {} : { commands: one.commands },
371
+ ...chosen === void 0 ? {} : { install: chosen },
372
+ name: one.name
373
+ };
319
374
  };
320
375
  if (named === void 0) return configured.map(withFlag);
321
376
  return [withFlag(configured.find((one) => one.name === named) ?? { name: named })];
@@ -336,6 +391,7 @@ var baseline = (parsed, root, cwd) => {
336
391
  }
337
392
  const rc = parsed.read["--rc-dir"];
338
393
  const recorded = recordBaseline({
394
+ ...one.commands === void 0 ? {} : { commands: one.commands },
339
395
  ...one.install === void 0 ? {} : { install: one.install },
340
396
  name: one.name,
341
397
  ...rc === void 0 ? {} : { rc: resolve(cwd, rc) },
@@ -356,6 +412,7 @@ var smokeRun = (parsed, root, cwd) => {
356
412
  );
357
413
  }
358
414
  const swept = sweepSmoke({
415
+ absent: parsed.many["--absent"] ?? [],
359
416
  rc: rcOf(parsed, root, cwd),
360
417
  root,
361
418
  skipMissing: parsed.read["--snapshot"] === void 0,
@@ -372,8 +429,9 @@ var smokeRun = (parsed, root, cwd) => {
372
429
  });
373
430
  if (!parsed.json) process.stdout.write(`envelope: ${at}
374
431
  `);
375
- if (swept.comparisons.some((one) => one.refused.length > 0)) return 2;
376
- return swept.comparisons.every((one) => one.ok) ? 0 : 1;
432
+ const comparisons = comparisonsIn(swept);
433
+ if (comparisons.some((one) => one.refused.length > 0)) return 2;
434
+ return comparisons.every((one) => one.ok) ? 0 : 1;
377
435
  };
378
436
  var smoke = (parsed, cwd) => {
379
437
  const root = rootOf(parsed, cwd);
@@ -397,8 +455,10 @@ geonosis.json \u2192 "release" every key optional; a repo that configured n
397
455
  sessionVariables string[]? the session variable names DDL may name
398
456
  smoke object? the consumer trees this release is read against
399
457
  exclude string[]? what a snapshot leaves behind, beyond the built and the installed
400
- snapshots Entry[]? { name, install? } \u2014 the recorded snapshot, and the command that
401
- tree is installed with when the manager's default is not it
458
+ snapshots Entry[]? { name, install?, commands? } \u2014 the recorded snapshot, the command
459
+ that tree is installed with when the manager's default is not it,
460
+ and { doctor?, lint?, typecheck? } when their gates are not the
461
+ scripts of those names
402
462
  secrets string[]? the secret names a deployment carries
403
463
  steps string[]? the release steps
404
464
  workers string[]? the workers it deploys
@@ -431,8 +491,9 @@ var main = async () => {
431
491
  if (parsed.command === "prove") return proving(parsed, process.cwd());
432
492
  if (parsed.command === "deployed") return deployed(parsed, process.cwd());
433
493
  if (parsed.command === "published") return published(parsed, process.cwd());
494
+ if (parsed.command === "adoption") return adoption(parsed, process.cwd());
434
495
  throw new CannotRun(
435
- `no command called "${parsed.command}" \u2014 this bin has migrations, plan, prove, deployed, published`
496
+ `no command called "${parsed.command}" \u2014 this bin has migrations, schema, plan, prove, deployed, published, adoption, smoke`
436
497
  );
437
498
  };
438
499
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geonosis/release",
3
- "version": "2.0.0",
3
+ "version": "2.2.0",
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.0.0"
48
+ "@geonosis/ratchet": "2.2.0"
49
49
  },
50
50
  "engines": {
51
51
  "node": ">=22"