@intentius/sql-yodeler 0.0.0-stage → 0.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.
Files changed (324) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +112 -2
  3. package/dist/bin.d.ts +2 -0
  4. package/dist/bin.js +29 -0
  5. package/dist/bin.js.map +1 -0
  6. package/dist/chant/apply.d.ts +59 -0
  7. package/dist/chant/apply.js +116 -0
  8. package/dist/chant/apply.js.map +1 -0
  9. package/dist/chant/build.d.ts +34 -0
  10. package/dist/chant/build.js +48 -0
  11. package/dist/chant/build.js.map +1 -0
  12. package/dist/chant/drift.d.ts +112 -0
  13. package/dist/chant/drift.js +238 -0
  14. package/dist/chant/drift.js.map +1 -0
  15. package/dist/chant/plan.d.ts +45 -0
  16. package/dist/chant/plan.js +61 -0
  17. package/dist/chant/plan.js.map +1 -0
  18. package/dist/chant/process.d.ts +41 -0
  19. package/dist/chant/process.js +87 -0
  20. package/dist/chant/process.js.map +1 -0
  21. package/dist/chant/runnable.d.ts +19 -0
  22. package/dist/chant/runnable.js +47 -0
  23. package/dist/chant/runnable.js.map +1 -0
  24. package/dist/cli.d.ts +8 -0
  25. package/dist/cli.js +99 -0
  26. package/dist/cli.js.map +1 -0
  27. package/dist/command.d.ts +23 -0
  28. package/dist/command.js +13 -0
  29. package/dist/command.js.map +1 -0
  30. package/dist/commands/apply.d.ts +3 -0
  31. package/dist/commands/apply.js +426 -0
  32. package/dist/commands/apply.js.map +1 -0
  33. package/dist/commands/approve.d.ts +5 -0
  34. package/dist/commands/approve.js +111 -0
  35. package/dist/commands/approve.js.map +1 -0
  36. package/dist/commands/drift.d.ts +14 -0
  37. package/dist/commands/drift.js +267 -0
  38. package/dist/commands/drift.js.map +1 -0
  39. package/dist/commands/index.d.ts +3 -0
  40. package/dist/commands/index.js +28 -0
  41. package/dist/commands/index.js.map +1 -0
  42. package/dist/commands/init.d.ts +6 -0
  43. package/dist/commands/init.js +139 -0
  44. package/dist/commands/init.js.map +1 -0
  45. package/dist/commands/lint.d.ts +3 -0
  46. package/dist/commands/lint.js +202 -0
  47. package/dist/commands/lint.js.map +1 -0
  48. package/dist/commands/mcp.d.ts +3 -0
  49. package/dist/commands/mcp.js +50 -0
  50. package/dist/commands/mcp.js.map +1 -0
  51. package/dist/commands/new.d.ts +5 -0
  52. package/dist/commands/new.js +292 -0
  53. package/dist/commands/new.js.map +1 -0
  54. package/dist/commands/override.d.ts +3 -0
  55. package/dist/commands/override.js +118 -0
  56. package/dist/commands/override.js.map +1 -0
  57. package/dist/commands/plan.d.ts +3 -0
  58. package/dist/commands/plan.js +183 -0
  59. package/dist/commands/plan.js.map +1 -0
  60. package/dist/commands/rebase.d.ts +3 -0
  61. package/dist/commands/rebase.js +167 -0
  62. package/dist/commands/rebase.js.map +1 -0
  63. package/dist/commands/repair.d.ts +14 -0
  64. package/dist/commands/repair.js +125 -0
  65. package/dist/commands/repair.js.map +1 -0
  66. package/dist/commands/status.d.ts +7 -0
  67. package/dist/commands/status.js +54 -0
  68. package/dist/commands/status.js.map +1 -0
  69. package/dist/config/define.d.ts +148 -0
  70. package/dist/config/define.js +20 -0
  71. package/dist/config/define.js.map +1 -0
  72. package/dist/config/index.d.ts +11 -0
  73. package/dist/config/index.js +12 -0
  74. package/dist/config/index.js.map +1 -0
  75. package/dist/config/load.d.ts +17 -0
  76. package/dist/config/load.js +162 -0
  77. package/dist/config/load.js.map +1 -0
  78. package/dist/config/settings.d.ts +53 -0
  79. package/dist/config/settings.js +116 -0
  80. package/dist/config/settings.js.map +1 -0
  81. package/dist/env-args.d.ts +24 -0
  82. package/dist/env-args.js +92 -0
  83. package/dist/env-args.js.map +1 -0
  84. package/dist/exit.d.ts +20 -0
  85. package/dist/exit.js +28 -0
  86. package/dist/exit.js.map +1 -0
  87. package/dist/history/client.d.ts +25 -0
  88. package/dist/history/client.js +42 -0
  89. package/dist/history/client.js.map +1 -0
  90. package/dist/history/ddl.d.ts +58 -0
  91. package/dist/history/ddl.js +100 -0
  92. package/dist/history/ddl.js.map +1 -0
  93. package/dist/history/index.d.ts +25 -0
  94. package/dist/history/index.js +26 -0
  95. package/dist/history/index.js.map +1 -0
  96. package/dist/history/lock.d.ts +104 -0
  97. package/dist/history/lock.js +230 -0
  98. package/dist/history/lock.js.map +1 -0
  99. package/dist/history/postgres/ddl.d.ts +22 -0
  100. package/dist/history/postgres/ddl.js +47 -0
  101. package/dist/history/postgres/ddl.js.map +1 -0
  102. package/dist/history/postgres/index.d.ts +12 -0
  103. package/dist/history/postgres/index.js +13 -0
  104. package/dist/history/postgres/index.js.map +1 -0
  105. package/dist/history/postgres/lock.d.ts +48 -0
  106. package/dist/history/postgres/lock.js +95 -0
  107. package/dist/history/postgres/lock.js.map +1 -0
  108. package/dist/history/postgres/store.d.ts +39 -0
  109. package/dist/history/postgres/store.js +68 -0
  110. package/dist/history/postgres/store.js.map +1 -0
  111. package/dist/history/rows.d.ts +96 -0
  112. package/dist/history/rows.js +73 -0
  113. package/dist/history/rows.js.map +1 -0
  114. package/dist/history/store.d.ts +72 -0
  115. package/dist/history/store.js +134 -0
  116. package/dist/history/store.js.map +1 -0
  117. package/dist/history/topology.d.ts +41 -0
  118. package/dist/history/topology.js +54 -0
  119. package/dist/history/topology.js.map +1 -0
  120. package/dist/index.d.ts +10 -0
  121. package/dist/index.js +10 -0
  122. package/dist/index.js.map +1 -0
  123. package/dist/init/adopt.d.ts +70 -0
  124. package/dist/init/adopt.js +143 -0
  125. package/dist/init/adopt.js.map +1 -0
  126. package/dist/init/baseline.d.ts +61 -0
  127. package/dist/init/baseline.js +88 -0
  128. package/dist/init/baseline.js.map +1 -0
  129. package/dist/init/files.d.ts +23 -0
  130. package/dist/init/files.js +77 -0
  131. package/dist/init/files.js.map +1 -0
  132. package/dist/init/index.d.ts +16 -0
  133. package/dist/init/index.js +17 -0
  134. package/dist/init/index.js.map +1 -0
  135. package/dist/init/live.d.ts +39 -0
  136. package/dist/init/live.js +68 -0
  137. package/dist/init/live.js.map +1 -0
  138. package/dist/lint/check.d.ts +88 -0
  139. package/dist/lint/check.js +227 -0
  140. package/dist/lint/check.js.map +1 -0
  141. package/dist/lint/config.d.ts +21 -0
  142. package/dist/lint/config.js +43 -0
  143. package/dist/lint/config.js.map +1 -0
  144. package/dist/lint/index.d.ts +31 -0
  145. package/dist/lint/index.js +43 -0
  146. package/dist/lint/index.js.map +1 -0
  147. package/dist/lint/project-rules.d.ts +19 -0
  148. package/dist/lint/project-rules.js +32 -0
  149. package/dist/lint/project-rules.js.map +1 -0
  150. package/dist/lint/report.d.ts +7 -0
  151. package/dist/lint/report.js +48 -0
  152. package/dist/lint/report.js.map +1 -0
  153. package/dist/lint/rules.d.ts +53 -0
  154. package/dist/lint/rules.js +42 -0
  155. package/dist/lint/rules.js.map +1 -0
  156. package/dist/lint/silences.d.ts +49 -0
  157. package/dist/lint/silences.js +91 -0
  158. package/dist/lint/silences.js.map +1 -0
  159. package/dist/lint/statements.d.ts +38 -0
  160. package/dist/lint/statements.js +120 -0
  161. package/dist/lint/statements.js.map +1 -0
  162. package/dist/mcp/server.d.ts +40 -0
  163. package/dist/mcp/server.js +106 -0
  164. package/dist/mcp/server.js.map +1 -0
  165. package/dist/mcp/tools.d.ts +72 -0
  166. package/dist/mcp/tools.js +178 -0
  167. package/dist/mcp/tools.js.map +1 -0
  168. package/dist/migrations/checks.d.ts +28 -0
  169. package/dist/migrations/checks.js +97 -0
  170. package/dist/migrations/checks.js.map +1 -0
  171. package/dist/migrations/checksum.d.ts +56 -0
  172. package/dist/migrations/checksum.js +72 -0
  173. package/dist/migrations/checksum.js.map +1 -0
  174. package/dist/migrations/create.d.ts +75 -0
  175. package/dist/migrations/create.js +120 -0
  176. package/dist/migrations/create.js.map +1 -0
  177. package/dist/migrations/directory.d.ts +119 -0
  178. package/dist/migrations/directory.js +229 -0
  179. package/dist/migrations/directory.js.map +1 -0
  180. package/dist/migrations/document.d.ts +106 -0
  181. package/dist/migrations/document.js +83 -0
  182. package/dist/migrations/document.js.map +1 -0
  183. package/dist/migrations/index.d.ts +21 -0
  184. package/dist/migrations/index.js +22 -0
  185. package/dist/migrations/index.js.map +1 -0
  186. package/dist/pr/comment.d.ts +32 -0
  187. package/dist/pr/comment.js +99 -0
  188. package/dist/pr/comment.js.map +1 -0
  189. package/dist/pr/forge.d.ts +54 -0
  190. package/dist/pr/forge.js +119 -0
  191. package/dist/pr/forge.js.map +1 -0
  192. package/dist/pr/issue.d.ts +68 -0
  193. package/dist/pr/issue.js +107 -0
  194. package/dist/pr/issue.js.map +1 -0
  195. package/dist/pr/model.d.ts +99 -0
  196. package/dist/pr/model.js +137 -0
  197. package/dist/pr/model.js.map +1 -0
  198. package/dist/pr/render.d.ts +29 -0
  199. package/dist/pr/render.js +279 -0
  200. package/dist/pr/render.js.map +1 -0
  201. package/dist/project.d.ts +62 -0
  202. package/dist/project.js +92 -0
  203. package/dist/project.js.map +1 -0
  204. package/dist/rebase/index.d.ts +121 -0
  205. package/dist/rebase/index.js +390 -0
  206. package/dist/rebase/index.js.map +1 -0
  207. package/dist/rebase/repair.d.ts +41 -0
  208. package/dist/rebase/repair.js +68 -0
  209. package/dist/rebase/repair.js.map +1 -0
  210. package/dist/replay/clickhouse.d.ts +33 -0
  211. package/dist/replay/clickhouse.js +106 -0
  212. package/dist/replay/clickhouse.js.map +1 -0
  213. package/dist/replay/index.d.ts +39 -0
  214. package/dist/replay/index.js +57 -0
  215. package/dist/replay/index.js.map +1 -0
  216. package/dist/replay/postgres.d.ts +31 -0
  217. package/dist/replay/postgres.js +140 -0
  218. package/dist/replay/postgres.js.map +1 -0
  219. package/dist/replay/replay.d.ts +114 -0
  220. package/dist/replay/replay.js +98 -0
  221. package/dist/replay/replay.js.map +1 -0
  222. package/dist/replay/report.d.ts +18 -0
  223. package/dist/replay/report.js +72 -0
  224. package/dist/replay/report.js.map +1 -0
  225. package/dist/replay/shared.d.ts +28 -0
  226. package/dist/replay/shared.js +77 -0
  227. package/dist/replay/shared.js.map +1 -0
  228. package/dist/schemas.d.ts +34 -0
  229. package/dist/schemas.js +38 -0
  230. package/dist/schemas.js.map +1 -0
  231. package/dist/server.d.ts +40 -0
  232. package/dist/server.js +87 -0
  233. package/dist/server.js.map +1 -0
  234. package/dist/steps/backfill.d.ts +132 -0
  235. package/dist/steps/backfill.js +307 -0
  236. package/dist/steps/backfill.js.map +1 -0
  237. package/dist/steps/index.d.ts +52 -0
  238. package/dist/steps/index.js +52 -0
  239. package/dist/steps/index.js.map +1 -0
  240. package/dist/steps/kinds.d.ts +101 -0
  241. package/dist/steps/kinds.js +143 -0
  242. package/dist/steps/kinds.js.map +1 -0
  243. package/dist/steps/postgres-migration.d.ts +95 -0
  244. package/dist/steps/postgres-migration.js +149 -0
  245. package/dist/steps/postgres-migration.js.map +1 -0
  246. package/dist/steps/rebuild.d.ts +97 -0
  247. package/dist/steps/rebuild.js +155 -0
  248. package/dist/steps/rebuild.js.map +1 -0
  249. package/dist/steps/run.d.ts +45 -0
  250. package/dist/steps/run.js +72 -0
  251. package/dist/steps/run.js.map +1 -0
  252. package/dist/topology/render.d.ts +17 -0
  253. package/dist/topology/render.js +17 -0
  254. package/dist/topology/render.js.map +1 -0
  255. package/dist/version.d.ts +2 -0
  256. package/dist/version.js +11 -0
  257. package/dist/version.js.map +1 -0
  258. package/dist/versioned/approval.d.ts +35 -0
  259. package/dist/versioned/approval.js +53 -0
  260. package/dist/versioned/approval.js.map +1 -0
  261. package/dist/versioned/checks.d.ts +29 -0
  262. package/dist/versioned/checks.js +54 -0
  263. package/dist/versioned/checks.js.map +1 -0
  264. package/dist/versioned/clickhouse.d.ts +24 -0
  265. package/dist/versioned/clickhouse.js +42 -0
  266. package/dist/versioned/clickhouse.js.map +1 -0
  267. package/dist/versioned/digest.d.ts +77 -0
  268. package/dist/versioned/digest.js +69 -0
  269. package/dist/versioned/digest.js.map +1 -0
  270. package/dist/versioned/driver.d.ts +51 -0
  271. package/dist/versioned/driver.js +13 -0
  272. package/dist/versioned/driver.js.map +1 -0
  273. package/dist/versioned/engine.d.ts +206 -0
  274. package/dist/versioned/engine.js +370 -0
  275. package/dist/versioned/engine.js.map +1 -0
  276. package/dist/versioned/explain.d.ts +123 -0
  277. package/dist/versioned/explain.js +294 -0
  278. package/dist/versioned/explain.js.map +1 -0
  279. package/dist/versioned/index.d.ts +46 -0
  280. package/dist/versioned/index.js +77 -0
  281. package/dist/versioned/index.js.map +1 -0
  282. package/dist/versioned/op.d.ts +72 -0
  283. package/dist/versioned/op.js +185 -0
  284. package/dist/versioned/op.js.map +1 -0
  285. package/dist/versioned/policy.d.ts +67 -0
  286. package/dist/versioned/policy.js +161 -0
  287. package/dist/versioned/policy.js.map +1 -0
  288. package/dist/versioned/postgres/catalog.d.ts +33 -0
  289. package/dist/versioned/postgres/catalog.js +34 -0
  290. package/dist/versioned/postgres/catalog.js.map +1 -0
  291. package/dist/versioned/postgres/driver.d.ts +71 -0
  292. package/dist/versioned/postgres/driver.js +140 -0
  293. package/dist/versioned/postgres/driver.js.map +1 -0
  294. package/dist/versioned/postgres/executor.d.ts +104 -0
  295. package/dist/versioned/postgres/executor.js +172 -0
  296. package/dist/versioned/postgres/executor.js.map +1 -0
  297. package/dist/versioned/postgres/index.d.ts +11 -0
  298. package/dist/versioned/postgres/index.js +12 -0
  299. package/dist/versioned/postgres/index.js.map +1 -0
  300. package/dist/versioned/postgres/waits.d.ts +46 -0
  301. package/dist/versioned/postgres/waits.js +78 -0
  302. package/dist/versioned/postgres/waits.js.map +1 -0
  303. package/dist/versioned/report.d.ts +25 -0
  304. package/dist/versioned/report.js +84 -0
  305. package/dist/versioned/report.js.map +1 -0
  306. package/dist/versioned/stand-down.d.ts +30 -0
  307. package/dist/versioned/stand-down.js +56 -0
  308. package/dist/versioned/stand-down.js.map +1 -0
  309. package/dist/versioned/state.d.ts +108 -0
  310. package/dist/versioned/state.js +153 -0
  311. package/dist/versioned/state.js.map +1 -0
  312. package/package.json +61 -4
  313. package/schemas/apply.schema.json +269 -0
  314. package/schemas/common.schema.json +213 -0
  315. package/schemas/drift.schema.json +36 -0
  316. package/schemas/init.schema.json +31 -0
  317. package/schemas/lint-rules.schema.json +54 -0
  318. package/schemas/lint.schema.json +290 -0
  319. package/schemas/mcp.schema.json +70 -0
  320. package/schemas/new.schema.json +71 -0
  321. package/schemas/plan.schema.json +371 -0
  322. package/schemas/rebase.schema.json +54 -0
  323. package/schemas/repair.schema.json +20 -0
  324. package/schemas/status.schema.json +310 -0
@@ -0,0 +1,294 @@
1
+ /**
2
+ * What moved: why the plan digest now differs from one approved earlier.
3
+ *
4
+ * The digest is a hash of its subject (`./digest.ts`): the environment, the
5
+ * history database, the topology, the applied migrations with their recorded checksums,
6
+ * the pending ones with their checksums and the statements of each already
7
+ * done, and the live schema's fingerprint. A hash says nothing about which
8
+ * of those changed, so yodel works back to the subject it was taken over:
9
+ *
10
+ * - When the older subject is known (the pull request comment carries it,
11
+ * hidden), the two subjects are compared part by part.
12
+ * - Otherwise it rebuilds candidates from what it can read: the history as
13
+ * it stood at the approval's time (the rows recorded up to then), each
14
+ * ordered subset of today's pending migrations (one added after approval
15
+ * is missing from the older plan), and each pending migration's files as
16
+ * git has held them (one edited after approval had another checksum). A
17
+ * candidate whose digest equals the approved one is the subject it was
18
+ * taken over, and the comparison is exact ("confirmed").
19
+ * - When no candidate matches, today's live schema is not the one it was
20
+ * approved against (or a part yodel cannot rebuild moved): it says so, and
21
+ * lists what it saw move (rows recorded since, files committed since).
22
+ */
23
+ import { execFileSync } from "node:child_process";
24
+ import { dirname } from "node:path";
25
+ import { computeChecksum } from "../migrations/index.js";
26
+ import { deriveState } from "../history/index.js";
27
+ import { topologyLabel } from "@intentius/chant-lexicon-sql/clickhouse/topology";
28
+ import { digestSubject, planDigest, sameDigest } from "./digest.js";
29
+ import { compareHistory } from "./state.js";
30
+ /** The subject `currentDigest` hashes, read now. */
31
+ export async function currentSubject(venv, status, toApply) {
32
+ const live = await venv.driver.liveFingerprint();
33
+ return digestSubject({ environment: venv.environment, historyDatabase: venv.location.database, topology: venv.topology, applied: status.applied, toApply, live });
34
+ }
35
+ /** A subject as text safe to carry in an HTML comment: base64url of its JSON. */
36
+ export const encodeSubject = (s) => Buffer.from(JSON.stringify(s), "utf8").toString("base64url");
37
+ export function decodeSubject(text) {
38
+ try {
39
+ const s = JSON.parse(Buffer.from(text, "base64url").toString("utf8"));
40
+ if (typeof s.environment !== "string" || typeof s.historyDatabase !== "string" || typeof s.live !== "string" || !Array.isArray(s.applied) || !Array.isArray(s.pending))
41
+ return undefined;
42
+ return s;
43
+ }
44
+ catch {
45
+ return undefined;
46
+ }
47
+ }
48
+ const list = (ids) => ids.join(", ");
49
+ /**
50
+ * How `after` differs from `before`, part by part. `applied` (today's, with
51
+ * who applied each and when) names the run that applied a migration since.
52
+ */
53
+ export function diffSubjects(before, after, applied = []) {
54
+ const out = [];
55
+ if (before.environment !== after.environment)
56
+ out.push({ part: "environment", message: `the environment changed: ${before.environment} -> ${after.environment}` });
57
+ if (before.historyDatabase !== after.historyDatabase)
58
+ out.push({ part: "environment", message: `the history database changed: ${before.historyDatabase} -> ${after.historyDatabase}` });
59
+ const topology = (s) => JSON.stringify(Object.entries(s.topology ?? { kind: "single" }).sort(([a], [b]) => a.localeCompare(b)));
60
+ if (topology(before) !== topology(after)) {
61
+ const label = (s) => topologyLabel(s.topology ?? { kind: "single" });
62
+ out.push({ part: "environment", message: `the topology changed: ${label(before)} -> ${label(after)}` });
63
+ }
64
+ const wasApplied = new Map(before.applied.map((a) => [a.id, a]));
65
+ const isApplied = new Map(after.applied.map((a) => [a.id, a]));
66
+ const who = new Map(applied.map((a) => [a.id, a]));
67
+ const newlyApplied = after.applied.filter((a) => !wasApplied.has(a.id));
68
+ if (newlyApplied.length > 0) {
69
+ const named = newlyApplied.map((a) => {
70
+ const w = who.get(a.id);
71
+ return w ? `${a.id} (by ${w.appliedBy} at ${w.recordedAt})` : a.id;
72
+ });
73
+ out.push({ part: "history", message: `applied since: ${list(named)}` });
74
+ }
75
+ const unapplied = before.applied.filter((a) => !isApplied.has(a.id)).map((a) => a.id);
76
+ if (unapplied.length > 0)
77
+ out.push({ part: "history", message: `no longer recorded applied: ${list(unapplied)}` });
78
+ const repaired = after.applied.filter((a) => wasApplied.has(a.id) && wasApplied.get(a.id)?.checksum !== a.checksum).map((a) => a.id);
79
+ if (repaired.length > 0)
80
+ out.push({ part: "history", message: `recorded checksum changed (yodel repair): ${list(repaired)}` });
81
+ const wasPending = new Map(before.pending.map((p) => [p.id, p]));
82
+ const isPending = new Map(after.pending.map((p) => [p.id, p]));
83
+ const added = after.pending.filter((p) => !wasPending.has(p.id) && !wasApplied.has(p.id)).map((p) => p.id);
84
+ if (added.length > 0)
85
+ out.push({ part: "pending", message: `new pending migration${added.length === 1 ? "" : "s"}: ${list(added)}` });
86
+ const gone = before.pending.filter((p) => !isPending.has(p.id) && !isApplied.has(p.id)).map((p) => p.id);
87
+ if (gone.length > 0)
88
+ out.push({ part: "pending", message: `no longer pending (gone from the directory): ${list(gone)}` });
89
+ const edited = after.pending.filter((p) => wasPending.has(p.id) && wasPending.get(p.id)?.checksum !== p.checksum).map((p) => p.id);
90
+ if (edited.length > 0)
91
+ out.push({ part: "pending", message: `files changed: ${list(edited)}` });
92
+ const progressed = after.pending.filter((p) => {
93
+ const b = wasPending.get(p.id);
94
+ return b !== undefined && b.checksum === p.checksum && JSON.stringify(b.done) !== JSON.stringify(p.done);
95
+ });
96
+ for (const p of progressed)
97
+ out.push({ part: "history", message: `${p.id} ran part way since: statements ${p.done.join(", ") || "none"} done now` });
98
+ const reordered = before.pending.filter((p) => isPending.has(p.id)).map((p) => p.id);
99
+ const nowOrder = after.pending.filter((p) => wasPending.has(p.id)).map((p) => p.id);
100
+ if (JSON.stringify(reordered) !== JSON.stringify(nowOrder))
101
+ out.push({ part: "pending", message: `the chain order changed: ${list(reordered)} -> ${list(nowOrder)}` });
102
+ if (before.live !== after.live)
103
+ out.push({ part: "live", message: "an object in the environment's live schema (a table, view, index, dictionary, database or schema) is not as it was" });
104
+ return out;
105
+ }
106
+ /** The checksums git has held for one migration's files, newest first. Empty outside git. */
107
+ export function gitChecksums(migrationsDir, id, limit = 10) {
108
+ const git = (...args) => execFileSync("git", args, { cwd: migrationsDir, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
109
+ try {
110
+ const commits = git("log", `-n${String(limit)}`, "--format=%H", "--", id).split("\n").filter(Boolean);
111
+ const out = new Set();
112
+ for (const c of commits) {
113
+ try {
114
+ const sql = git("show", `${c}:./${id}/migration.sql`);
115
+ out.add(computeChecksum({ sql, json: git("show", `${c}:./${id}/migration.json`) }));
116
+ }
117
+ catch {
118
+ // Deleted at that commit, or not a migration then.
119
+ }
120
+ }
121
+ return [...out];
122
+ }
123
+ catch {
124
+ return [];
125
+ }
126
+ }
127
+ /** Migration directories git saw commits to after `sinceIso`, with the newest commit. Empty outside git. */
128
+ export function gitChangesSince(migrationsDir, sinceIso) {
129
+ try {
130
+ const log = execFileSync("git", ["log", `--since=${sinceIso}`, "--format=@%h %cI", "--name-only", "--relative", "--", "."], {
131
+ cwd: migrationsDir,
132
+ encoding: "utf8",
133
+ stdio: ["ignore", "pipe", "ignore"],
134
+ });
135
+ const seen = new Map();
136
+ let commit = "";
137
+ let at = "";
138
+ for (const line of log.split("\n")) {
139
+ if (line.startsWith("@"))
140
+ [commit, at] = line.slice(1).split(" ");
141
+ else if (line.trim()) {
142
+ const id = line.split("/")[0] ?? "";
143
+ if (id && !seen.has(id))
144
+ seen.set(id, { id, commit, at });
145
+ }
146
+ }
147
+ return [...seen.values()];
148
+ }
149
+ catch {
150
+ return [];
151
+ }
152
+ }
153
+ /** ClickHouse's `YYYY-MM-DD hh:mm:ss.ffffff` (UTC) or ISO, as epoch ms. */
154
+ export const recordedTime = (t) => (t ? Date.parse(/[zZ]|[+-]\d\d:?\d\d$/.test(t) ? t : `${t.replace(" ", "T")}Z`) : Number.NaN);
155
+ /** Ordered subsets of `items`, every one when there are few, else the prefixes and each with one left out. */
156
+ function subsets(items) {
157
+ if (items.length <= 10) {
158
+ const out = [];
159
+ for (let mask = (1 << items.length) - 1; mask >= 0; mask--)
160
+ out.push(items.filter((_, i) => (mask & (1 << i)) !== 0));
161
+ return out;
162
+ }
163
+ const out = [];
164
+ for (let k = items.length; k >= 0; k--)
165
+ out.push(items.slice(0, k));
166
+ for (let i = 0; i < items.length; i++)
167
+ out.push(items.filter((_, j) => j !== i));
168
+ return out;
169
+ }
170
+ /** Why `input.now` no longer hashes to `input.approvedDigest`. */
171
+ export async function explainMove(input) {
172
+ const now = await planDigest(input.now);
173
+ const done = (confirmed, changes) => ({ approved: input.approvedDigest, now, confirmed, changes });
174
+ if (await sameDigest(now, input.approvedDigest))
175
+ return done(true, []);
176
+ if (input.previous && (await sameDigest(await planDigest(input.previous), input.approvedDigest))) {
177
+ return done(true, diffSubjects(input.previous, input.now, input.applied));
178
+ }
179
+ // The history as it stood at approval, and as it is.
180
+ const states = [];
181
+ const at = recordedTime(input.approvedAt);
182
+ if (input.rows && Number.isFinite(at))
183
+ states.push(deriveState(input.rows.filter((r) => recordedTime(r.recorded_at) <= at)));
184
+ if (input.rows)
185
+ states.push(deriveState(input.rows));
186
+ let budget = input.budget ?? 20_000;
187
+ const tried = new Set();
188
+ const baselines = [];
189
+ for (const state of states) {
190
+ const status = compareHistory(input.ordered, state);
191
+ const base = digestSubject({ environment: input.now.environment, historyDatabase: input.now.historyDatabase, topology: input.now.topology, applied: status.applied, toApply: status.pending, live: input.now.live });
192
+ // A subject carried from before #9 has no topology; rebuild it the same way.
193
+ if (input.now.topology === undefined)
194
+ delete base.topology;
195
+ baselines.push(base);
196
+ for (const pending of subsets(base.pending)) {
197
+ const variants = pending.map((p) => [p.checksum, ...(input.checksums?.(p.id) ?? []).filter((c) => c !== p.checksum)]);
198
+ for (const combo of product(variants)) {
199
+ if (budget-- <= 0)
200
+ break;
201
+ const candidate = { ...base, pending: pending.map((p, i) => ({ ...p, checksum: combo[i] ?? p.checksum })) };
202
+ const key = JSON.stringify(candidate);
203
+ if (tried.has(key))
204
+ continue;
205
+ tried.add(key);
206
+ if (await sameDigest(await planDigest(candidate), input.approvedDigest))
207
+ return done(true, diffSubjects(candidate, input.now, input.applied));
208
+ }
209
+ }
210
+ }
211
+ // Unconfirmed: what yodel saw move, and the part it cannot rebuild.
212
+ const base = baselines[0];
213
+ const changes = base ? diffSubjects(base, input.now, input.applied).filter((c) => c.part === "history") : [];
214
+ if (input.approvedAt && input.changedSince) {
215
+ const committed = input.changedSince(input.approvedAt);
216
+ if (committed.length > 0) {
217
+ changes.push({ part: "pending", message: `committed to since approval: ${list(committed.map((c) => `${c.id} (${c.commit} at ${c.at})`))}` });
218
+ }
219
+ }
220
+ // Migrations applied since approval change the live schema themselves; yodel cannot rebuild the live schema as it was, so it says the change is the expected one rather than one out of band (#19).
221
+ const appliedSince = changes.some((c) => c.part === "history");
222
+ changes.push({
223
+ part: "live",
224
+ message: appliedSince
225
+ ? "as expected after the history change above: applying a migration changes the live schema, and yodel cannot rebuild the live schema as it " +
226
+ "was at approval, so it cannot confirm that nothing else in it changed"
227
+ : "no state yodel can rebuild from the history and git hashes to the approved digest with today's live schema, so an object in " +
228
+ "the environment's live schema (a table, view, index, dictionary, database or schema) changed since approval (or a part yodel cannot rebuild did)",
229
+ });
230
+ return done(false, changes);
231
+ }
232
+ function* product(lists) {
233
+ if (lists.length === 0) {
234
+ yield [];
235
+ return;
236
+ }
237
+ const [head, ...rest] = lists;
238
+ for (const h of head)
239
+ for (const tail of product(rest))
240
+ yield [h, ...tail];
241
+ }
242
+ /** One line: "the plan moved since it was approved: <part>: <what>; ...". */
243
+ export function describeMove(e) {
244
+ if (e.changes.length === 0)
245
+ return "nothing moved";
246
+ const label = { environment: "environment", history: "history changed", pending: "pending migrations changed", live: "live schema changed" };
247
+ return e.changes.map((c) => `${label[c.part]}: ${c.message}`).join("; ");
248
+ }
249
+ /** The newest approval of `op`'s gate in the ledger, and whether it holds for `digest` by the gate's rule (for that digest, newer than the gate's newest pending fact). */
250
+ export async function latestApproval(ledger, op, digest) {
251
+ const read = await ledger.read(op.name);
252
+ const newest = read.resolutions.filter((r) => r.gate === op.gate).sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp)).at(-1);
253
+ if (!newest)
254
+ return undefined;
255
+ const approvedAt = Date.parse(newest.timestamp);
256
+ const after = read.pending.filter((p) => p.gate === op.gate && Date.parse(p.timestamp) > approvedAt).sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp))[0];
257
+ const same = digest !== undefined && (await sameDigest(newest.planDigest, digest));
258
+ return {
259
+ digest: newest.planDigest,
260
+ by: newest.resolvedBy,
261
+ at: newest.timestamp,
262
+ holds: same && after === undefined,
263
+ sameDigest: same,
264
+ ...(after ? { askedAgain: { at: after.timestamp, digest: after.planDigest } } : {}),
265
+ };
266
+ }
267
+ /** Why an approval for this very digest does not hold: a run asked for approval again after it. */
268
+ export function askedAgainLine(a, code = (s) => s) {
269
+ const again = a.askedAgain;
270
+ const when = again ? ` at ${again.at}${again.digest ? ` (a run holding ${code(again.digest)})` : ""}` : "";
271
+ return `is for this plan's digest, but approval was asked for again after it${when}, so it does not hold; approve this plan again`;
272
+ }
273
+ /**
274
+ * {@link explainMove} with what yodel can read itself: today's subject (the
275
+ * pending migrations of `ordered` against the history now, unless `now` is
276
+ * given), the history's rows, and git's copies of the migrations' files.
277
+ */
278
+ export async function explainAgainst(venv, ordered, input) {
279
+ const rows = await venv.store.rows({ sync: false });
280
+ const status = compareHistory(ordered, deriveState(rows));
281
+ const now = input.now ?? (await currentSubject(venv, status, status.pending));
282
+ const dir = ordered[0] ? dirname(ordered[0].dir) : undefined;
283
+ return explainMove({
284
+ approvedDigest: input.approvedDigest,
285
+ approvedAt: input.approvedAt,
286
+ now,
287
+ previous: input.previous,
288
+ ordered,
289
+ applied: status.applied,
290
+ rows,
291
+ ...(dir ? { checksums: (id) => gitChecksums(dir, id), changedSince: (iso) => gitChangesSince(dir, iso) } : {}),
292
+ });
293
+ }
294
+ //# sourceMappingURL=explain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explain.js","sourceRoot":"","sources":["../../src/versioned/explain.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * The versioned path (#8): `yodel apply <env>` and `yodel status <env>` for a
3
+ * project with a `migrations/` directory.
4
+ *
5
+ * hasMigrations(project) whether apply takes the versioned path
6
+ * openVersioned(project, env) the server, the history, the lock settings
7
+ * inspect(venv, ordered) history state and how the directory compares (no lock)
8
+ * compareHistory(ordered, state) the same, pure
9
+ * selectToApply(status, allowOutOfOrder) the pending migrations, or the refusal
10
+ * currentDigest(venv, status, toApply) the plan digest
11
+ * executeApply(venv, ordered, options) apply under the lock, after checking the digest
12
+ * findMigrateOp / runMigrateOp the approval Op (see ./op.ts)
13
+ */
14
+ import type { Project } from "../project.js";
15
+ import type { Migration } from "../migrations/index.js";
16
+ import { type VersionedEnv } from "./engine.js";
17
+ import type { StatusReport } from "./report.js";
18
+ export * from "./approval.js";
19
+ export * from "./checks.js";
20
+ export * from "./digest.js";
21
+ export * from "./engine.js";
22
+ export * from "./op.js";
23
+ export * from "./policy.js";
24
+ export * from "./report.js";
25
+ export * from "./state.js";
26
+ /** The project's migrations directory. */
27
+ export declare const migrationsDir: (project: Project) => string;
28
+ /** Why nothing can be applied while the migrations directory has a problem (a fork, a missing parent, a cycle, an unreadable migration). */
29
+ export declare const BROKEN_CHAIN = "the migrations directory is not one unbroken chain; nothing can be applied until it is";
30
+ /**
31
+ * The migrations in chain order, for apply and status. A directory problem is
32
+ * a refusal (exit 4), as yodel plan reports it: nothing is applied.
33
+ */
34
+ export declare function readChain(project: Project): Migration[];
35
+ /**
36
+ * Whether `yodel apply` takes the versioned path: the project has a
37
+ * `migrations/` directory holding at least one migration directory. A
38
+ * directory that is there but malformed still takes it, and is refused
39
+ * there, rather than falling back to the declarative path.
40
+ */
41
+ export declare function hasMigrations(project: Project): boolean;
42
+ /** The status, with the digest apply would ask approval for, or why it would refuse. */
43
+ export declare function statusReport(venv: VersionedEnv, ordered: readonly Migration[], options?: {
44
+ allowOutOfOrder?: boolean;
45
+ sync?: boolean;
46
+ }): Promise<StatusReport>;
@@ -0,0 +1,77 @@
1
+ /**
2
+ * The versioned path (#8): `yodel apply <env>` and `yodel status <env>` for a
3
+ * project with a `migrations/` directory.
4
+ *
5
+ * hasMigrations(project) whether apply takes the versioned path
6
+ * openVersioned(project, env) the server, the history, the lock settings
7
+ * inspect(venv, ordered) history state and how the directory compares (no lock)
8
+ * compareHistory(ordered, state) the same, pure
9
+ * selectToApply(status, allowOutOfOrder) the pending migrations, or the refusal
10
+ * currentDigest(venv, status, toApply) the plan digest
11
+ * executeApply(venv, ordered, options) apply under the lock, after checking the digest
12
+ * findMigrateOp / runMigrateOp the approval Op (see ./op.ts)
13
+ */
14
+ import { existsSync, readdirSync, statSync } from "node:fs";
15
+ import { join } from "node:path";
16
+ import { MIGRATIONS_DIR, MigrationDirectoryError, readMigrations } from "../migrations/index.js";
17
+ import { YodelError } from "../project.js";
18
+ import { EXIT_REFUSED } from "../exit.js";
19
+ import { currentDigest, inspect, integrityRefusal, stepRefusal } from "./engine.js";
20
+ import { describeSettingsTopology } from "../config/settings.js";
21
+ import { softly } from "../server.js";
22
+ export * from "./approval.js";
23
+ export * from "./checks.js";
24
+ export * from "./digest.js";
25
+ export * from "./engine.js";
26
+ export * from "./op.js";
27
+ export * from "./policy.js";
28
+ export * from "./report.js";
29
+ export * from "./state.js";
30
+ /** The project's migrations directory. */
31
+ export const migrationsDir = (project) => join(project.dir, MIGRATIONS_DIR);
32
+ /** Why nothing can be applied while the migrations directory has a problem (a fork, a missing parent, a cycle, an unreadable migration). */
33
+ export const BROKEN_CHAIN = "the migrations directory is not one unbroken chain; nothing can be applied until it is";
34
+ /**
35
+ * The migrations in chain order, for apply and status. A directory problem is
36
+ * a refusal (exit 4), as yodel plan reports it: nothing is applied.
37
+ */
38
+ export function readChain(project) {
39
+ try {
40
+ return readMigrations(migrationsDir(project));
41
+ }
42
+ catch (e) {
43
+ if (e instanceof MigrationDirectoryError)
44
+ throw new YodelError(`refused: ${BROKEN_CHAIN}:\n${e.problems.map((p) => ` ${p.message}`).join("\n")}`, EXIT_REFUSED);
45
+ throw e;
46
+ }
47
+ }
48
+ /**
49
+ * Whether `yodel apply` takes the versioned path: the project has a
50
+ * `migrations/` directory holding at least one migration directory. A
51
+ * directory that is there but malformed still takes it, and is refused
52
+ * there, rather than falling back to the declarative path.
53
+ */
54
+ export function hasMigrations(project) {
55
+ const dir = migrationsDir(project);
56
+ if (!existsSync(dir))
57
+ return false;
58
+ return readdirSync(dir).some((e) => !e.startsWith(".") && statSync(join(dir, e)).isDirectory());
59
+ }
60
+ /** The status, with the digest apply would ask approval for, or why it would refuse. */
61
+ export async function statusReport(venv, ordered, options = {}) {
62
+ const { status } = await inspect(venv, ordered, options.sync === undefined ? {} : { sync: options.sync });
63
+ const refusal = integrityRefusal(status, options.allowOutOfOrder === true) ?? stepRefusal(status.pending);
64
+ const digest = !refusal && status.pending.length > 0 ? await currentDigest(venv, status, status.pending) : undefined;
65
+ const server = venv.server ? await softly(venv.server) : undefined;
66
+ return {
67
+ ...(server ? { server } : {}),
68
+ environment: venv.environment,
69
+ dialect: venv.dialect,
70
+ location: venv.location,
71
+ topology: venv.topology ? describeSettingsTopology({ topology: venv.topology, topologySource: venv.topologySource ?? "default" }) : undefined,
72
+ status,
73
+ digest,
74
+ refusal: refusal ? { exitCode: refusal.exitCode, message: refusal.message } : undefined,
75
+ };
76
+ }
77
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/versioned/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * The approval: a versioned apply runs as a chant Op, behind a gate bound to
3
+ * the plan digest, the same machinery #6's declarative apply runs through.
4
+ *
5
+ * The project declares one Op per environment:
6
+ *
7
+ * Plan shell("yodel apply <env> --digest", { id: "plan" })
8
+ * prints the digest of the pending migrations and the live schema
9
+ * Approve gate(..., { plan: stepOutput(plan, "stdout") })
10
+ * a resolution counts only for that digest (`chant approve <op> <gate> --plan <digest>`)
11
+ * Apply shell("yodel apply <env> --execute", { env: { YODEL_APPROVED_PLAN: stepOutput(plan, "stdout") } })
12
+ * takes the lock, computes the digest again, refuses if it moved, applies
13
+ *
14
+ * `yodel apply <env>` runs it with `chant run <op>`, as #6 runs an ApplyOp.
15
+ * The gate ledger is chant's (the `chant/lifecycle` branch); yodel keeps no
16
+ * approval store of its own. The digest is checked twice: by the gate, on
17
+ * every run, against the approval; and by the Apply step, under the lock,
18
+ * against the digest the gate passed, so a change between the two (another
19
+ * runner applying, a table altered out of band) refuses too.
20
+ *
21
+ * `chant run <op>` run directly (in CI) needs `yodel` on PATH, e.g.
22
+ * `PATH="$PWD/node_modules/.bin:$PATH"`. When `yodel apply` runs it, yodel
23
+ * puts a `yodel` that runs itself first on the child's PATH.
24
+ */
25
+ import type { OpConfig } from "@intentius/chant/op/types";
26
+ import { type Environment, type Project } from "../project.js";
27
+ import { type ApplyRun } from "../chant/apply.js";
28
+ /** The env var the Apply step reads the approved digest from. */
29
+ export declare const APPROVED_PLAN_ENV = "YODEL_APPROVED_PLAN";
30
+ /** Passes `--allow-out-of-order` through `chant run` to the Op's steps. */
31
+ export declare const ALLOW_OUT_OF_ORDER_ENV = "YODEL_ALLOW_OUT_OF_ORDER";
32
+ export interface MigrateOpRef {
33
+ name: string;
34
+ filePath: string;
35
+ gate: string;
36
+ /** The gate declares a quorum or policy (`approval`). */
37
+ quorum: boolean;
38
+ }
39
+ /** The parts of a migrations Op for `env`, when `config` is one. */
40
+ export declare function migrateOpParts(config: OpConfig, env: string): {
41
+ gate: string | undefined;
42
+ quorum: boolean;
43
+ } | undefined;
44
+ /** How to declare the Op `yodel apply` looks for. */
45
+ export declare function migrateOpExample(env: string): string;
46
+ /** Picks the migrations Op for `env` from discovered Ops. Pure. */
47
+ export declare function selectMigrateOp(ops: ReadonlyMap<string, {
48
+ config: OpConfig;
49
+ filePath: string;
50
+ }>, project: Project, env: Environment, name?: string): MigrateOpRef;
51
+ export declare function findMigrateOp(project: Project, env: Environment, name?: string): Promise<MigrateOpRef>;
52
+ /** A directory holding a `yodel` that runs this yodel, for a child's PATH. */
53
+ export declare function yodelShim(): {
54
+ dir: string;
55
+ dispose: () => void;
56
+ };
57
+ /**
58
+ * Where `yodel apply --execute` (the Op's Apply step) writes its exit code,
59
+ * so the outer `yodel apply` exits with it (5 for the lock, 4 for a refusal)
60
+ * rather than with `chant run`'s 1.
61
+ */
62
+ export declare const STEP_EXIT_ENV = "YODEL_STEP_EXIT_FILE";
63
+ /** Records an Op step's exit code where the outer `yodel apply` reads it. Never fails the step. */
64
+ export declare function recordStepExit(code: number, env?: NodeJS.ProcessEnv): void;
65
+ /** The exit code the Op's Apply step recorded, when it ran. */
66
+ export declare function readStepExit(file: string): number | undefined;
67
+ /** Runs the migrations Op with `chant run`, with this yodel on PATH and `--allow-out-of-order` passed through. */
68
+ export declare function runMigrateOp(project: Project, op: MigrateOpRef, options: {
69
+ allowOutOfOrder: boolean;
70
+ env?: NodeJS.ProcessEnv;
71
+ onOutput?: (text: string) => void;
72
+ }): Promise<ApplyRun>;