@intentius/sql-yodeler 0.1.0 → 0.3.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 (297) hide show
  1. package/README.md +28 -26
  2. package/dist/bin.js +15 -0
  3. package/dist/bin.js.map +1 -1
  4. package/dist/chant/apply.d.ts +9 -1
  5. package/dist/chant/apply.js +13 -1
  6. package/dist/chant/apply.js.map +1 -1
  7. package/dist/chant/build.js +7 -0
  8. package/dist/chant/build.js.map +1 -1
  9. package/dist/chant/drift.d.ts +69 -1
  10. package/dist/chant/drift.js +152 -5
  11. package/dist/chant/drift.js.map +1 -1
  12. package/dist/chant/runnable.d.ts +19 -0
  13. package/dist/chant/runnable.js +47 -0
  14. package/dist/chant/runnable.js.map +1 -0
  15. package/dist/ci/render.d.ts +289 -0
  16. package/dist/ci/render.js +688 -0
  17. package/dist/ci/render.js.map +1 -0
  18. package/dist/ci/replay.d.ts +17 -0
  19. package/dist/ci/replay.js +69 -0
  20. package/dist/ci/replay.js.map +1 -0
  21. package/dist/cli.d.ts +4 -0
  22. package/dist/cli.js +40 -0
  23. package/dist/cli.js.map +1 -1
  24. package/dist/command.d.ts +6 -0
  25. package/dist/command.js.map +1 -1
  26. package/dist/commands/apply.d.ts +113 -0
  27. package/dist/commands/apply.js +376 -49
  28. package/dist/commands/apply.js.map +1 -1
  29. package/dist/commands/approve.d.ts +5 -0
  30. package/dist/commands/approve.js +155 -0
  31. package/dist/commands/approve.js.map +1 -0
  32. package/dist/commands/checkpoint.d.ts +3 -0
  33. package/dist/commands/checkpoint.js +78 -0
  34. package/dist/commands/checkpoint.js.map +1 -0
  35. package/dist/commands/ci.d.ts +3 -0
  36. package/dist/commands/ci.js +118 -0
  37. package/dist/commands/ci.js.map +1 -0
  38. package/dist/commands/docs.d.ts +11 -0
  39. package/dist/commands/docs.js +108 -0
  40. package/dist/commands/docs.js.map +1 -0
  41. package/dist/commands/drift.d.ts +23 -0
  42. package/dist/commands/drift.js +263 -18
  43. package/dist/commands/drift.js.map +1 -1
  44. package/dist/commands/index.js +16 -0
  45. package/dist/commands/index.js.map +1 -1
  46. package/dist/commands/init.d.ts +3 -0
  47. package/dist/commands/init.js +15 -11
  48. package/dist/commands/init.js.map +1 -1
  49. package/dist/commands/lint.js +25 -8
  50. package/dist/commands/lint.js.map +1 -1
  51. package/dist/commands/mcp.d.ts +3 -0
  52. package/dist/commands/mcp.js +50 -0
  53. package/dist/commands/mcp.js.map +1 -0
  54. package/dist/commands/new.d.ts +2 -0
  55. package/dist/commands/new.js +134 -10
  56. package/dist/commands/new.js.map +1 -1
  57. package/dist/commands/override.d.ts +3 -0
  58. package/dist/commands/override.js +150 -0
  59. package/dist/commands/override.js.map +1 -0
  60. package/dist/commands/plan.js +43 -27
  61. package/dist/commands/plan.js.map +1 -1
  62. package/dist/commands/repair.d.ts +11 -0
  63. package/dist/commands/repair.js +15 -7
  64. package/dist/commands/repair.js.map +1 -1
  65. package/dist/commands/report.d.ts +13 -0
  66. package/dist/commands/report.js +121 -0
  67. package/dist/commands/report.js.map +1 -0
  68. package/dist/commands/revert.d.ts +20 -0
  69. package/dist/commands/revert.js +246 -0
  70. package/dist/commands/revert.js.map +1 -0
  71. package/dist/commands/status.js +44 -17
  72. package/dist/commands/status.js.map +1 -1
  73. package/dist/config/base.d.ts +69 -0
  74. package/dist/config/base.js +121 -0
  75. package/dist/config/base.js.map +1 -0
  76. package/dist/config/define.d.ts +223 -3
  77. package/dist/config/define.js +3 -1
  78. package/dist/config/define.js.map +1 -1
  79. package/dist/config/index.d.ts +2 -0
  80. package/dist/config/index.js +2 -0
  81. package/dist/config/index.js.map +1 -1
  82. package/dist/config/load.d.ts +1 -1
  83. package/dist/config/load.js +150 -5
  84. package/dist/config/load.js.map +1 -1
  85. package/dist/config/settings.d.ts +18 -2
  86. package/dist/config/settings.js +40 -6
  87. package/dist/config/settings.js.map +1 -1
  88. package/dist/env-args.d.ts +6 -0
  89. package/dist/env-args.js +31 -1
  90. package/dist/env-args.js.map +1 -1
  91. package/dist/exit.d.ts +20 -0
  92. package/dist/exit.js +28 -0
  93. package/dist/exit.js.map +1 -0
  94. package/dist/history/client.d.ts +8 -0
  95. package/dist/history/client.js +24 -1
  96. package/dist/history/client.js.map +1 -1
  97. package/dist/history/lock.d.ts +5 -1
  98. package/dist/history/lock.js +8 -2
  99. package/dist/history/lock.js.map +1 -1
  100. package/dist/history/postgres/ddl.d.ts +18 -0
  101. package/dist/history/postgres/ddl.js +27 -2
  102. package/dist/history/postgres/ddl.js.map +1 -1
  103. package/dist/history/postgres/store.d.ts +2 -0
  104. package/dist/history/postgres/store.js +7 -1
  105. package/dist/history/postgres/store.js.map +1 -1
  106. package/dist/history/rows.d.ts +16 -3
  107. package/dist/history/rows.js +30 -1
  108. package/dist/history/rows.js.map +1 -1
  109. package/dist/history/store.d.ts +2 -0
  110. package/dist/history/store.js +2 -2
  111. package/dist/history/store.js.map +1 -1
  112. package/dist/index.d.ts +4 -1
  113. package/dist/index.js +1 -0
  114. package/dist/index.js.map +1 -1
  115. package/dist/init/adopt.js +8 -3
  116. package/dist/init/adopt.js.map +1 -1
  117. package/dist/init/live.d.ts +11 -0
  118. package/dist/init/live.js +25 -2
  119. package/dist/init/live.js.map +1 -1
  120. package/dist/lint/check.d.ts +8 -1
  121. package/dist/lint/check.js +38 -4
  122. package/dist/lint/check.js.map +1 -1
  123. package/dist/lint/report.js +1 -1
  124. package/dist/lint/report.js.map +1 -1
  125. package/dist/lint/routines.d.ts +26 -0
  126. package/dist/lint/routines.js +65 -0
  127. package/dist/lint/routines.js.map +1 -0
  128. package/dist/lint/rules.d.ts +16 -4
  129. package/dist/lint/rules.js +9 -4
  130. package/dist/lint/rules.js.map +1 -1
  131. package/dist/mcp/server.d.ts +40 -0
  132. package/dist/mcp/server.js +106 -0
  133. package/dist/mcp/server.js.map +1 -0
  134. package/dist/mcp/tools.d.ts +72 -0
  135. package/dist/mcp/tools.js +178 -0
  136. package/dist/mcp/tools.js.map +1 -0
  137. package/dist/migrations/checkpoint.d.ts +45 -0
  138. package/dist/migrations/checkpoint.js +110 -0
  139. package/dist/migrations/checkpoint.js.map +1 -0
  140. package/dist/migrations/checks.d.ts +28 -0
  141. package/dist/migrations/checks.js +97 -0
  142. package/dist/migrations/checks.js.map +1 -0
  143. package/dist/migrations/create.d.ts +3 -1
  144. package/dist/migrations/create.js +3 -0
  145. package/dist/migrations/create.js.map +1 -1
  146. package/dist/migrations/directory.js +4 -0
  147. package/dist/migrations/directory.js.map +1 -1
  148. package/dist/migrations/document.d.ts +33 -0
  149. package/dist/migrations/document.js +2 -0
  150. package/dist/migrations/document.js.map +1 -1
  151. package/dist/migrations/index.d.ts +3 -0
  152. package/dist/migrations/index.js +3 -0
  153. package/dist/migrations/index.js.map +1 -1
  154. package/dist/migrations/routines.d.ts +31 -0
  155. package/dist/migrations/routines.js +55 -0
  156. package/dist/migrations/routines.js.map +1 -0
  157. package/dist/notify/index.d.ts +124 -0
  158. package/dist/notify/index.js +210 -0
  159. package/dist/notify/index.js.map +1 -0
  160. package/dist/notify/verify.d.ts +53 -0
  161. package/dist/notify/verify.js +71 -0
  162. package/dist/notify/verify.js.map +1 -0
  163. package/dist/pr/forge.d.ts +4 -0
  164. package/dist/pr/forge.js +21 -7
  165. package/dist/pr/forge.js.map +1 -1
  166. package/dist/pr/issue.d.ts +68 -0
  167. package/dist/pr/issue.js +107 -0
  168. package/dist/pr/issue.js.map +1 -0
  169. package/dist/pr/model.d.ts +12 -1
  170. package/dist/pr/model.js +44 -6
  171. package/dist/pr/model.js.map +1 -1
  172. package/dist/pr/render.d.ts +3 -1
  173. package/dist/pr/render.js +63 -4
  174. package/dist/pr/render.js.map +1 -1
  175. package/dist/project.d.ts +19 -2
  176. package/dist/project.js +33 -1
  177. package/dist/project.js.map +1 -1
  178. package/dist/replay/index.d.ts +3 -0
  179. package/dist/replay/index.js +3 -0
  180. package/dist/replay/index.js.map +1 -1
  181. package/dist/replay/replay.d.ts +9 -1
  182. package/dist/replay/replay.js +63 -32
  183. package/dist/replay/replay.js.map +1 -1
  184. package/dist/replay/report.js +1 -1
  185. package/dist/replay/report.js.map +1 -1
  186. package/dist/replay/shared.d.ts +28 -0
  187. package/dist/replay/shared.js +77 -0
  188. package/dist/replay/shared.js.map +1 -0
  189. package/dist/report/audit.d.ts +138 -0
  190. package/dist/report/audit.js +202 -0
  191. package/dist/report/audit.js.map +1 -0
  192. package/dist/report/jsonl.d.ts +21 -0
  193. package/dist/report/jsonl.js +52 -0
  194. package/dist/report/jsonl.js.map +1 -0
  195. package/dist/report/model.d.ts +68 -0
  196. package/dist/report/model.js +127 -0
  197. package/dist/report/model.js.map +1 -0
  198. package/dist/report/render.d.ts +18 -0
  199. package/dist/report/render.js +127 -0
  200. package/dist/report/render.js.map +1 -0
  201. package/dist/schema-docs/render.d.ts +49 -0
  202. package/dist/schema-docs/render.js +359 -0
  203. package/dist/schema-docs/render.js.map +1 -0
  204. package/dist/schemas.d.ts +37 -0
  205. package/dist/schemas.js +41 -0
  206. package/dist/schemas.js.map +1 -0
  207. package/dist/server.d.ts +40 -0
  208. package/dist/server.js +87 -0
  209. package/dist/server.js.map +1 -0
  210. package/dist/sources/ddl.d.ts +53 -0
  211. package/dist/sources/ddl.js +347 -0
  212. package/dist/sources/ddl.js.map +1 -0
  213. package/dist/sources/index.d.ts +69 -0
  214. package/dist/sources/index.js +170 -0
  215. package/dist/sources/index.js.map +1 -0
  216. package/dist/steps/backfill.d.ts +21 -17
  217. package/dist/steps/backfill.js +20 -20
  218. package/dist/steps/backfill.js.map +1 -1
  219. package/dist/steps/index.d.ts +2 -2
  220. package/dist/steps/index.js +3 -3
  221. package/dist/steps/index.js.map +1 -1
  222. package/dist/steps/postgres-migration.d.ts +35 -25
  223. package/dist/steps/postgres-migration.js +42 -29
  224. package/dist/steps/postgres-migration.js.map +1 -1
  225. package/dist/steps/rebuild.d.ts +15 -15
  226. package/dist/steps/rebuild.js +17 -24
  227. package/dist/steps/rebuild.js.map +1 -1
  228. package/dist/tenants/index.d.ts +40 -0
  229. package/dist/tenants/index.js +122 -0
  230. package/dist/tenants/index.js.map +1 -0
  231. package/dist/tenants/target.d.ts +23 -0
  232. package/dist/tenants/target.js +29 -0
  233. package/dist/tenants/target.js.map +1 -0
  234. package/dist/versioned/checks.d.ts +29 -0
  235. package/dist/versioned/checks.js +54 -0
  236. package/dist/versioned/checks.js.map +1 -0
  237. package/dist/versioned/clickhouse.js +8 -0
  238. package/dist/versioned/clickhouse.js.map +1 -1
  239. package/dist/versioned/driver.d.ts +10 -0
  240. package/dist/versioned/engine.d.ts +61 -1
  241. package/dist/versioned/engine.js +109 -6
  242. package/dist/versioned/engine.js.map +1 -1
  243. package/dist/versioned/explain.js +7 -2
  244. package/dist/versioned/explain.js.map +1 -1
  245. package/dist/versioned/index.d.ts +10 -0
  246. package/dist/versioned/index.js +25 -1
  247. package/dist/versioned/index.js.map +1 -1
  248. package/dist/versioned/op.d.ts +16 -1
  249. package/dist/versioned/op.js +43 -6
  250. package/dist/versioned/op.js.map +1 -1
  251. package/dist/versioned/policy.d.ts +98 -0
  252. package/dist/versioned/policy.js +212 -0
  253. package/dist/versioned/policy.js.map +1 -0
  254. package/dist/versioned/postgres/driver.d.ts +3 -1
  255. package/dist/versioned/postgres/driver.js +30 -3
  256. package/dist/versioned/postgres/driver.js.map +1 -1
  257. package/dist/versioned/postgres/waits.d.ts +46 -0
  258. package/dist/versioned/postgres/waits.js +78 -0
  259. package/dist/versioned/postgres/waits.js.map +1 -0
  260. package/dist/versioned/report.d.ts +3 -0
  261. package/dist/versioned/report.js +13 -1
  262. package/dist/versioned/report.js.map +1 -1
  263. package/dist/versioned/revert.d.ts +128 -0
  264. package/dist/versioned/revert.js +251 -0
  265. package/dist/versioned/revert.js.map +1 -0
  266. package/dist/versioned/stand-down.d.ts +30 -0
  267. package/dist/versioned/stand-down.js +56 -0
  268. package/dist/versioned/stand-down.js.map +1 -0
  269. package/dist/versioned/state.d.ts +25 -0
  270. package/dist/versioned/state.js +36 -3
  271. package/dist/versioned/state.js.map +1 -1
  272. package/dist/waves/index.d.ts +179 -0
  273. package/dist/waves/index.js +268 -0
  274. package/dist/waves/index.js.map +1 -0
  275. package/dist/waves/promotion.d.ts +56 -0
  276. package/dist/waves/promotion.js +108 -0
  277. package/dist/waves/promotion.js.map +1 -0
  278. package/dist/waves/record.d.ts +24 -0
  279. package/dist/waves/record.js +20 -0
  280. package/dist/waves/record.js.map +1 -0
  281. package/package.json +22 -8
  282. package/schemas/apply.schema.json +428 -0
  283. package/schemas/checkpoint.schema.json +19 -0
  284. package/schemas/common.schema.json +213 -0
  285. package/schemas/drift.schema.json +61 -0
  286. package/schemas/event.schema.json +36 -0
  287. package/schemas/init.schema.json +31 -0
  288. package/schemas/lint-rules.schema.json +54 -0
  289. package/schemas/lint.schema.json +294 -0
  290. package/schemas/mcp.schema.json +70 -0
  291. package/schemas/new.schema.json +71 -0
  292. package/schemas/plan.schema.json +489 -0
  293. package/schemas/rebase.schema.json +54 -0
  294. package/schemas/repair.schema.json +20 -0
  295. package/schemas/report.schema.json +114 -0
  296. package/schemas/revert.schema.json +69 -0
  297. package/schemas/status.schema.json +371 -0
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Reads of the live schema that another session's lock can block (#18): the
3
+ * fingerprint the plan digest covers, read before every apply and plan.
4
+ * chant's catalog reader calls `pg_get_viewdef()` and friends, which wait
5
+ * for a table's ACCESS SHARE lock, so a session holding ACCESS EXCLUSIVE on
6
+ * a declared table (a long `ALTER TABLE`, a `LOCK TABLE`) would hold the read
7
+ * up for as long as it holds the lock, with nothing printed.
8
+ *
9
+ * So the read runs under the profile's `lockTimeoutMs`, and when that passes
10
+ * (SQLSTATE 55P03) yodel says which lock it waited on and who holds it, and
11
+ * tries again with the same pauses and count as a statement (250 ms, then
12
+ * doubling, YODEL_LOCK_RETRIES more times). When the lock is still held after
13
+ * the last try, the read fails with the same description.
14
+ */
15
+ import { YodelError } from "../../project.js";
16
+ import { DEFAULT_RETRY_BASE_MS, LOCK_NOT_AVAILABLE } from "./executor.js";
17
+ const sqlstate = (e) => e && typeof e === "object" && "code" in e && typeof e.code === "string" ? e.code : undefined;
18
+ /** The ACCESS EXCLUSIVE locks other sessions hold (or wait for) on relations in `schemas` (every schema but the server's own when undefined). */
19
+ export async function lockHolders(client, schemas) {
20
+ const rows = await client.query(`SELECT n.nspname AS schema, c.relname AS name, l.pid, l.granted, a.application_name AS application
21
+ FROM pg_catalog.pg_locks l
22
+ JOIN pg_catalog.pg_class c ON c.oid = l.relation
23
+ JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
24
+ LEFT JOIN pg_catalog.pg_stat_activity a ON a.pid = l.pid
25
+ WHERE l.locktype = 'relation' AND l.mode = 'AccessExclusiveLock' AND l.pid <> pg_catalog.pg_backend_pid()
26
+ AND n.nspname NOT IN ('pg_catalog', 'information_schema') AND n.nspname NOT LIKE 'pg\\_toast%'
27
+ AND ($1::text[] IS NULL OR n.nspname = ANY ($1::text[]))
28
+ ORDER BY l.granted DESC, n.nspname, c.relname, l.pid
29
+ LIMIT 5`, [schemas ? [...schemas] : null]);
30
+ return rows.map((r) => ({ schema: r.schema, name: r.name, pid: Number(r.pid), granted: r.granted, application: r.application ?? "" }));
31
+ }
32
+ /** `a lock on shop.orders (held by pid 123, psql)`, or `a lock held by another session` when none could be named. */
33
+ export function describeHolders(holders) {
34
+ if (holders.length === 0)
35
+ return "a lock another session holds on an object in scope";
36
+ const one = (h) => `${h.schema}.${h.name} (${h.granted ? "held" : "queued for"} by pid ${String(h.pid)}${h.application ? `, ${h.application}` : ""})`;
37
+ return `a lock on ${holders.map(one).join(", ")}`;
38
+ }
39
+ const sleeper = (ms) => new Promise((r) => setTimeout(r, ms));
40
+ const seconds = (ms) => (ms < 1000 ? `${String(ms)}ms` : `${String(Math.round(ms / 100) / 10)}s`);
41
+ /** Runs `read` on `client` with `lock_timeout` set, retrying (and saying why) when another session's lock holds it up. */
42
+ export async function readUnderLockTimeout(client, read, o) {
43
+ const sleep = o.sleep ?? sleeper;
44
+ const base = o.retryBaseMs ?? DEFAULT_RETRY_BASE_MS;
45
+ const [prev] = await client.query("SELECT pg_catalog.current_setting('lock_timeout') AS lock_timeout");
46
+ await client.query("SELECT pg_catalog.set_config('lock_timeout', $1, false)", [`${String(Math.max(0, Math.floor(o.lockTimeoutMs)))}ms`]);
47
+ try {
48
+ for (let attempt = 0;; attempt++) {
49
+ try {
50
+ return await read();
51
+ }
52
+ catch (e) {
53
+ if (sqlstate(e) !== LOCK_NOT_AVAILABLE)
54
+ throw e;
55
+ const holders = await lockHolders(client, o.schemas).catch(() => []);
56
+ const waited = `reading ${o.what} waited ${seconds(o.lockTimeoutMs)} for ${describeHolders(holders)}`;
57
+ if (attempt >= o.retries) {
58
+ const pid = holders.find((h) => h.granted)?.pid;
59
+ throw new YodelError(`${waited}, ${String(attempt + 1)} time(s); nothing was changed. Try again once it is released${pid !== undefined ? `, or end that session with: SELECT pg_terminate_backend(${String(pid)})` : ""}`);
60
+ }
61
+ const pause = base * 2 ** attempt;
62
+ o.log(`${waited}; trying again in ${seconds(pause)} (${String(attempt + 1)} of ${String(o.retries)})`);
63
+ await sleep(pause);
64
+ }
65
+ }
66
+ }
67
+ finally {
68
+ await client.query("SELECT pg_catalog.set_config('lock_timeout', $1, false)", [prev?.lock_timeout ?? "0"]).catch(() => undefined);
69
+ }
70
+ }
71
+ /** The `PGOPTIONS` a chant child reads Postgres under, so a read blocked by a lock gives up after `lockTimeoutMs` (node-postgres passes it to the server). */
72
+ export function lockTimeoutOptions(lockTimeoutMs, existing) {
73
+ return [existing?.trim(), `-c lock_timeout=${String(Math.max(0, Math.floor(lockTimeoutMs)))}`].filter(Boolean).join(" ");
74
+ }
75
+ /** Whether a read failed because the lock timeout passed. */
76
+ export const isLockTimeout = (text) => text !== undefined && /lock timeout/i.test(text);
77
+ export { seconds as describeMs };
78
+ //# sourceMappingURL=waits.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"waits.js","sourceRoot":"","sources":["../../../src/versioned/postgres/waits.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,12 @@
1
1
  /** The versioned status as text and as JSON, for `yodel status` and `yodel apply --plan`. */
2
2
  import type { SqlDialect } from "../project.js";
3
3
  import { type HistoryLocation } from "../history/index.js";
4
+ import { type ServerInfo } from "../server.js";
4
5
  import { type VersionedStatus } from "./state.js";
5
6
  export interface StatusReport {
6
7
  environment: string;
8
+ /** The server the history was read from (#11). */
9
+ server?: ServerInfo | undefined;
7
10
  /** Postgres has no topology: its report leaves it out. Default ClickHouse. */
8
11
  dialect?: SqlDialect | undefined;
9
12
  location: HistoryLocation;
@@ -1,11 +1,13 @@
1
1
  /** The versioned status as text and as JSON, for `yodel status` and `yodel apply --plan`. */
2
2
  import { describeTopology } from "../history/index.js";
3
3
  import { describeStep } from "../steps/index.js";
4
+ import { describeServer } from "../server.js";
4
5
  import { outOfOrder, partWay } from "./state.js";
5
6
  export function statusJson(r) {
6
7
  const { status } = r;
7
8
  return {
8
9
  environment: r.environment,
10
+ ...(r.server ? { server: r.server } : {}),
9
11
  ...(r.dialect === "postgres"
10
12
  ? { history: { database: r.location.database } }
11
13
  : { history: { database: r.location.database, topology: describeTopology(r.location.topology) }, topology: r.topology ?? describeTopology(r.location.topology) }),
@@ -23,12 +25,14 @@ export function statusJson(r) {
23
25
  checksum: p.checksum,
24
26
  outOfOrder: p.outOfOrder,
25
27
  partWay: p.partWay ?? null,
28
+ ...(p.reverted ? { reverted: p.reverted } : {}),
26
29
  opSteps: p.opSteps.map(({ index, step }) => ({ index, kind: step.kind, object: step.object, name: step.name, ...(step.kind === "op" ? { op: step.op } : {}) })),
27
30
  refusedSteps: p.refusedSteps.map(({ index, step, reason }) => ({ index, kind: step.kind, object: step.object, name: step.name, ...(step.kind === "op" ? { op: step.op } : {}), reason })),
28
31
  })),
29
32
  outOfOrder: outOfOrder(status).map((p) => p.id),
30
33
  partWay: partWay(status).map((p) => ({ id: p.id, resumeAt: p.partWay?.resumeAt, failedStatement: p.partWay?.failedStatement ?? null })),
31
34
  mismatches: status.mismatches,
35
+ ...(status.skipped ? { skipped: status.skipped } : {}),
32
36
  ...(r.digest ? { planDigest: r.digest } : {}),
33
37
  ...(r.refusal ? { refusal: r.refusal } : {}),
34
38
  };
@@ -36,7 +40,8 @@ export function statusJson(r) {
36
40
  export function renderStatus(r) {
37
41
  const { status } = r;
38
42
  const topology = r.dialect === "postgres" ? "" : `, topology ${r.topology ?? describeTopology(r.location.topology)}`;
39
- const lines = [`Migrations in ${r.environment} (history ${r.location.database}.history${topology})`, ""];
43
+ const server = r.server ? `${describeServer(r.server)}, ` : "";
44
+ const lines = [`Migrations in ${r.environment} (${server}history ${r.location.database}.history${topology})`, ""];
40
45
  lines.push(status.applied.length === 0 ? "Applied: none" : `Applied (${String(status.applied.length)}):`);
41
46
  for (const a of status.applied) {
42
47
  lines.push(` ${a.id}${a.index === undefined ? " (not in the directory)" : ""} ${a.recordedAt} by ${a.appliedBy}`);
@@ -48,6 +53,8 @@ export function renderStatus(r) {
48
53
  const marks = [];
49
54
  if (p.outOfOrder)
50
55
  marks.push("out of order");
56
+ if (p.reverted)
57
+ marks.push(`reverted ${p.reverted.at} by ${p.reverted.by}`);
51
58
  if (p.partWay) {
52
59
  const pw = p.partWay;
53
60
  marks.push(pw.status === "failed"
@@ -64,6 +71,11 @@ export function renderStatus(r) {
64
71
  if (p.partWay?.error)
65
72
  lines.push(` error: ${p.partWay.error.split("\n")[0] ?? ""}`);
66
73
  }
74
+ if (status.skipped) {
75
+ lines.push("", `Skipped (${String(status.skipped.length)}), never run here:`);
76
+ for (const k of status.skipped)
77
+ lines.push(` ${k.id} (${k.reason === "covered" ? `before ${k.checkpoint ?? "the checkpoint"}, the checkpoint this environment starts from` : "a checkpoint; this environment ran the migrations it creates"})`);
78
+ }
67
79
  const late = outOfOrder(status);
68
80
  if (late.length > 0)
69
81
  lines.push("", `Out of order (${String(late.length)}): ${late.map((p) => p.id).join(", ")}; apply with --allow-out-of-order`);
@@ -1 +1 @@
1
- {"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/versioned/report.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/versioned/report.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,128 @@
1
+ /**
2
+ * `yodel revert` (#55): undoing an applied migration from its recorded
3
+ * schemas, through the same plan, gate and history as `yodel apply`.
4
+ *
5
+ * A migration records the schema after it, and its parent records the
6
+ * schema before it, so the reverse is planned offline: chant's
7
+ * `diffStatements` from the migration's recorded schema to its parent's
8
+ * (an empty schema for the first migration). Only the newest migration
9
+ * applied in the environment can be reverted, since a later one was
10
+ * written against it.
11
+ *
12
+ * Statements carry the schema back, never the data. A migration with a
13
+ * data step (a backfill) is refused unless a hand-written revert step is
14
+ * given (`--step <file>`): SQL statements, each ending with `;` at the end
15
+ * of a line, that undo what the data step did. They run first, before the
16
+ * reverse statements, as the migration ran its data step after the
17
+ * statements it needed. A reverse that needs an Op or a manual step (a
18
+ * ClickHouse sort-key change back, a Postgres rename back) is refused:
19
+ * write it as a new migration.
20
+ *
21
+ * The run goes through the project's migrations Op (`./op.ts`), with the
22
+ * migration and the step's file in `YODEL_REVERT` and `YODEL_REVERT_STEP`:
23
+ * its Plan step (`yodel apply <env> --digest`) prints the revert's digest,
24
+ * the gate binds the approval to it, and its Apply step (`yodel apply <env>
25
+ * --execute`) takes the lock, plans the revert again, refuses if the digest
26
+ * moved, checks the approval in chant's gate ledger, and runs it. The
27
+ * history gets a `revert` row for each statement as it starts, succeeds or
28
+ * fails, then a migration row `reverted` (`../history/rows.ts`): the
29
+ * migration is pending again, and `yodel status` shows it reverted.
30
+ */
31
+ import { type StatementStep } from "@intentius/chant-lexicon-sql/migration-statements";
32
+ import { YodelError } from "../project.js";
33
+ import { type Migration } from "../migrations/index.js";
34
+ import { type HistoryState } from "../history/index.js";
35
+ import { type VersionedEnv } from "./engine.js";
36
+ import type { VersionedStatus } from "./state.js";
37
+ import type { PolicyOverride } from "./policy.js";
38
+ /** The migration `yodel apply --digest` and `--execute` revert instead of applying, set by `yodel revert` for its Op run. */
39
+ export declare const REVERT_ENV = "YODEL_REVERT";
40
+ /** The hand-written revert step's file, absolute, set with {@link REVERT_ENV}. */
41
+ export declare const REVERT_STEP_ENV = "YODEL_REVERT_STEP";
42
+ /** chant's plan-digest kind for a revert: a revert's digest is never an apply's. */
43
+ export declare const REVERT_DIGEST_KIND = "yodel-revert";
44
+ /** A hand-written revert step: its file and the statements in it. */
45
+ export interface RevertStepFile {
46
+ /** As given; for messages. */
47
+ file: string;
48
+ /** `sha256:<hex>` of its text. */
49
+ sha: string;
50
+ statements: string[];
51
+ }
52
+ /** The statements of a SQL file: each ends with `;` at the end of a line; `--` comment lines and blank ones between them are dropped. */
53
+ export declare function splitStatements(text: string): string[];
54
+ /** Reads a hand-written revert step, relative to `dir`. */
55
+ export declare function readRevertStep(path: string, dir: string): RevertStepFile;
56
+ /** One statement of a revert, in the order it runs. */
57
+ export interface RevertStatement {
58
+ /** `step`: from the hand-written revert step. `reverse`: diffed from the recorded schemas. */
59
+ source: "step" | "reverse";
60
+ step: StatementStep;
61
+ }
62
+ export interface RevertPlan {
63
+ environment: string;
64
+ migration: Migration;
65
+ /** The migration it goes back to, or `null` for none (the first migration reverted). */
66
+ to: string | null;
67
+ /** The checksum the history recorded when it was applied. */
68
+ checksum: string;
69
+ statements: RevertStatement[];
70
+ /** The migration's data steps, which the hand-written step undoes. */
71
+ dataSteps: string[];
72
+ step?: RevertStepFile;
73
+ /** The indexes in {@link statements} that already succeeded: a revert that failed part way resumes. */
74
+ done: number[];
75
+ }
76
+ /**
77
+ * The revert of migration `id` in an environment whose status is `status`,
78
+ * or a YodelError: exit 1 for no such migration, 4 when the history does not
79
+ * match the directory, the migration is not applied, or one after it is;
80
+ * 2 when the reverse needs a step revert does not run, or the migration has
81
+ * a data step and no hand-written revert step is given.
82
+ */
83
+ export declare function planRevert(input: {
84
+ environment: string;
85
+ ordered: readonly Migration[];
86
+ status: VersionedStatus;
87
+ state: HistoryState;
88
+ id: string;
89
+ step?: RevertStepFile | undefined;
90
+ }): RevertPlan;
91
+ /** The revert's plan digest: what it runs, what it starts from and the live schema, as chant computes digests. */
92
+ export declare function revertDigest(venv: VersionedEnv, status: VersionedStatus, plan: RevertPlan): Promise<string>;
93
+ /** Plans the revert from the history as it is now, with its digest. Reads only; takes no lock. */
94
+ export declare function currentRevert(venv: VersionedEnv, ordered: readonly Migration[], id: string, step?: RevertStepFile): Promise<{
95
+ plan: RevertPlan;
96
+ digest: string;
97
+ status: VersionedStatus;
98
+ }>;
99
+ export declare class RevertFailed extends YodelError {
100
+ readonly migration: string;
101
+ readonly statement: number;
102
+ readonly serverError: string;
103
+ constructor(migration: string, statement: number, serverError: string);
104
+ }
105
+ export interface ExecuteRevertOptions {
106
+ id: string;
107
+ step?: RevertStepFile | undefined;
108
+ /** The digest the Op's gate passed. A revert whose digest moved since is refused. */
109
+ approvedDigest: string;
110
+ /** Checks the approval for the digest computed under the lock; throws to refuse. */
111
+ approve: (digest: string) => Promise<unknown>;
112
+ /**
113
+ * Judges the policy (#53, #97) over the revert for the digest computed
114
+ * under the lock; throws to refuse. Resolves to the overrides it relied
115
+ * on, which the `reverted` row records. Absent: no policy.
116
+ */
117
+ policy?: (digest: string, plan: RevertPlan) => Promise<PolicyOverride[]>;
118
+ log: (line: string) => void;
119
+ processEnv?: NodeJS.ProcessEnv;
120
+ lockWaitMs?: number;
121
+ }
122
+ /** Runs the revert under the lock, after planning it again and checking its digest and approval. Returns the plan run. */
123
+ export declare function executeRevert(venv: VersionedEnv, ordered: readonly Migration[], options: ExecuteRevertOptions): Promise<RevertPlan>;
124
+ /** The revert `yodel apply --digest` or `--execute` runs instead, when `yodel revert` started the Op run. */
125
+ export declare function revertFromEnv(env: NodeJS.ProcessEnv, dir: string): {
126
+ id: string;
127
+ step?: RevertStepFile;
128
+ } | undefined;
@@ -0,0 +1,251 @@
1
+ /**
2
+ * `yodel revert` (#55): undoing an applied migration from its recorded
3
+ * schemas, through the same plan, gate and history as `yodel apply`.
4
+ *
5
+ * A migration records the schema after it, and its parent records the
6
+ * schema before it, so the reverse is planned offline: chant's
7
+ * `diffStatements` from the migration's recorded schema to its parent's
8
+ * (an empty schema for the first migration). Only the newest migration
9
+ * applied in the environment can be reverted, since a later one was
10
+ * written against it.
11
+ *
12
+ * Statements carry the schema back, never the data. A migration with a
13
+ * data step (a backfill) is refused unless a hand-written revert step is
14
+ * given (`--step <file>`): SQL statements, each ending with `;` at the end
15
+ * of a line, that undo what the data step did. They run first, before the
16
+ * reverse statements, as the migration ran its data step after the
17
+ * statements it needed. A reverse that needs an Op or a manual step (a
18
+ * ClickHouse sort-key change back, a Postgres rename back) is refused:
19
+ * write it as a new migration.
20
+ *
21
+ * The run goes through the project's migrations Op (`./op.ts`), with the
22
+ * migration and the step's file in `YODEL_REVERT` and `YODEL_REVERT_STEP`:
23
+ * its Plan step (`yodel apply <env> --digest`) prints the revert's digest,
24
+ * the gate binds the approval to it, and its Apply step (`yodel apply <env>
25
+ * --execute`) takes the lock, plans the revert again, refuses if the digest
26
+ * moved, checks the approval in chant's gate ledger, and runs it. The
27
+ * history gets a `revert` row for each statement as it starts, succeeds or
28
+ * fails, then a migration row `reverted` (`../history/rows.ts`): the
29
+ * migration is pending again, and `yodel status` shows it reverted.
30
+ */
31
+ import { createHash } from "node:crypto";
32
+ import { readFileSync } from "node:fs";
33
+ import { resolve } from "node:path";
34
+ import { diffStatements } from "@intentius/chant-lexicon-sql/migration-statements";
35
+ import { YodelError } from "../project.js";
36
+ import { EXIT_NEEDS_OP, EXIT_REFUSED } from "../exit.js";
37
+ import { emptyBuild, isCheckpoint } from "../migrations/index.js";
38
+ import { asBackfill, describeStep } from "../steps/index.js";
39
+ import { HistoryRecorder, MIGRATION_ROW, newRunContext, statementSha, withLock, appliedBy } from "../history/index.js";
40
+ import { acquireWaiting, inspect } from "./engine.js";
41
+ import { sameDigest } from "./digest.js";
42
+ /** The migration `yodel apply --digest` and `--execute` revert instead of applying, set by `yodel revert` for its Op run. */
43
+ export const REVERT_ENV = "YODEL_REVERT";
44
+ /** The hand-written revert step's file, absolute, set with {@link REVERT_ENV}. */
45
+ export const REVERT_STEP_ENV = "YODEL_REVERT_STEP";
46
+ /** chant's plan-digest kind for a revert: a revert's digest is never an apply's. */
47
+ export const REVERT_DIGEST_KIND = "yodel-revert";
48
+ /** The statements of a SQL file: each ends with `;` at the end of a line; `--` comment lines and blank ones between them are dropped. */
49
+ export function splitStatements(text) {
50
+ const out = [];
51
+ let current = [];
52
+ for (const line of text.replace(/\r\n?/g, "\n").split("\n")) {
53
+ if (current.length === 0 && (/^\s*--/.test(line) || line.trim() === ""))
54
+ continue;
55
+ current.push(line);
56
+ if (/;\s*$/.test(line)) {
57
+ out.push(current.join("\n").replace(/;\s*$/, "").trim());
58
+ current = [];
59
+ }
60
+ }
61
+ const rest = current.join("\n").trim();
62
+ if (rest)
63
+ out.push(rest);
64
+ return out.filter((s) => s !== "");
65
+ }
66
+ /** Reads a hand-written revert step, relative to `dir`. */
67
+ export function readRevertStep(path, dir) {
68
+ let text;
69
+ try {
70
+ text = readFileSync(resolve(dir, path), "utf8");
71
+ }
72
+ catch (e) {
73
+ throw new YodelError(`--step ${path}: ${e instanceof Error ? e.message : String(e)}`);
74
+ }
75
+ const statements = splitStatements(text);
76
+ if (statements.length === 0)
77
+ throw new YodelError(`--step ${path} holds no statement`);
78
+ return { file: path, sha: `sha256:${createHash("sha256").update(text, "utf8").digest("hex")}`, statements };
79
+ }
80
+ /** A hand-written statement as a step the driver sends. */
81
+ function handStatement(sql, i, dialect) {
82
+ return {
83
+ kind: "statement",
84
+ object: "revert-step",
85
+ type: "revert-step",
86
+ name: `revert step statement ${String(i + 1)}`,
87
+ sql,
88
+ rule: "revert-step",
89
+ class: "data",
90
+ transactional: dialect === "postgres",
91
+ ...(dialect === "clickhouse" && /^\s*ALTER\s+TABLE\b[\s\S]*\b(UPDATE|DELETE)\b/i.test(sql) ? { waitsForMutation: true } : {}),
92
+ };
93
+ }
94
+ /**
95
+ * The revert of migration `id` in an environment whose status is `status`,
96
+ * or a YodelError: exit 1 for no such migration, 4 when the history does not
97
+ * match the directory, the migration is not applied, or one after it is;
98
+ * 2 when the reverse needs a step revert does not run, or the migration has
99
+ * a data step and no hand-written revert step is given.
100
+ */
101
+ export function planRevert(input) {
102
+ const { ordered, status, id, environment } = input;
103
+ const at = ordered.findIndex((m) => m.id === id);
104
+ const m = ordered[at];
105
+ if (!m)
106
+ throw new YodelError(`no migration ${id} in the migrations directory`);
107
+ if (status.mismatches.length > 0) {
108
+ throw new YodelError(`refused: the history does not match the migrations directory; nothing was reverted:\n${status.mismatches.map((x) => ` ${x.message}`).join("\n")}`, EXIT_REFUSED);
109
+ }
110
+ // Checkpoints (#63): one an environment started from has no schema before it there, and the migrations before it never ran there.
111
+ const skipped = status.skipped?.find((k) => k.id === id);
112
+ if (skipped) {
113
+ throw new YodelError(skipped.reason === "covered"
114
+ ? `refused: ${id} comes before the checkpoint ${skipped.checkpoint ?? ""}, which ${environment} started from: it never ran in ${environment}, so there is nothing to revert. Nothing was reverted.`
115
+ : `refused: ${id} is a checkpoint ${environment} skips, since it ran the migrations before it: it never ran in ${environment}, so there is nothing to revert. Nothing was reverted.`, EXIT_REFUSED);
116
+ }
117
+ if (isCheckpoint(m) && status.applied.some((a) => a.id === id)) {
118
+ throw new YodelError(`refused: ${id} is the checkpoint ${environment} started from: it created the whole schema, and ${environment} never ran the migrations before it, so there is no earlier schema to go back to. Nothing was reverted.`, EXIT_REFUSED);
119
+ }
120
+ const applied = status.applied.find((a) => a.id === id);
121
+ if (!applied)
122
+ throw new YodelError(`refused: ${id} is not applied in ${environment}, so there is nothing to revert. Nothing was reverted.`, EXIT_REFUSED);
123
+ const later = status.applied.filter((a) => a.index !== undefined && a.index > at).map((a) => a.id);
124
+ if (later.length > 0) {
125
+ throw new YodelError(`refused: ${later.join(", ")} ${later.length === 1 ? "is" : "are"} applied in ${environment} after ${id}, and ${later.length === 1 ? "was" : "were"} written against it; revert ${later.length === 1 ? "it" : "them"} first, newest first. Nothing was reverted.`, EXIT_REFUSED);
126
+ }
127
+ const parent = m.parent === null ? undefined : ordered.find((x) => x.id === m.parent);
128
+ const doc = m.document;
129
+ const before = parent?.document.schema ?? emptyBuild(doc.schema);
130
+ let steps;
131
+ try {
132
+ steps = diffStatements(doc.schema, before, {
133
+ ...(doc.defaultDatabase !== undefined ? { defaultDatabase: doc.defaultDatabase } : {}),
134
+ ...(doc.defaultSchema !== undefined ? { defaultSchema: doc.defaultSchema } : {}),
135
+ }).steps;
136
+ }
137
+ catch (e) {
138
+ throw new YodelError(`the reverse of ${id} cannot be planned from the recorded schemas: ${e instanceof Error ? e.message : String(e)}`);
139
+ }
140
+ const notStatements = steps.filter((s) => s.kind !== "statement");
141
+ if (notStatements.length > 0) {
142
+ throw new YodelError(`refused: going back from ${id} to ${parent?.id ?? "an empty schema"} takes a step yodel revert does not run (${notStatements.map((s) => describeStep(s)).join("; ")}); write the change as a new migration (yodel new). Nothing was reverted.`, EXIT_NEEDS_OP);
143
+ }
144
+ const dataSteps = doc.steps.flatMap((s, i) => (asBackfill(s) ? [`step ${String(i)}: ${describeStep(s)}`] : []));
145
+ if (dataSteps.length > 0 && !input.step) {
146
+ throw new YodelError(`refused: ${id} has a data step the recorded schemas cannot undo (${dataSteps.join("; ")}). Write the statements that undo it in a file and pass --step <file>; they run before the reverse statements. Nothing was reverted.`, EXIT_NEEDS_OP);
147
+ }
148
+ const statements = [
149
+ ...(input.step?.statements ?? []).map((sql, i) => ({ source: "step", step: handStatement(sql, i, doc.dialect) })),
150
+ ...steps.map((s) => ({ source: "reverse", step: s })),
151
+ ];
152
+ const rec = input.state.byId.get(id);
153
+ const done = statements.flatMap((s, i) => {
154
+ const r = rec?.reverts.get(i);
155
+ return r?.status === "succeeded" && r.sha === statementSha(s.step.sql) ? [i] : [];
156
+ });
157
+ return { environment, migration: m, to: parent?.id ?? null, checksum: applied.checksum, statements, dataSteps, ...(input.step ? { step: input.step } : {}), done };
158
+ }
159
+ /** The revert's plan digest: what it runs, what it starts from and the live schema, as chant computes digests. */
160
+ export async function revertDigest(venv, status, plan) {
161
+ const { computePlanDigest } = await import("@intentius/chant/lifecycle/plan-digest");
162
+ const live = await venv.driver.liveFingerprint();
163
+ return computePlanDigest(REVERT_DIGEST_KIND, {
164
+ environment: venv.environment,
165
+ historyDatabase: venv.location.database,
166
+ topology: venv.topology ?? { kind: "single" },
167
+ applied: status.applied.map((a) => ({ id: a.id, checksum: a.checksum })),
168
+ revert: { id: plan.migration.id, checksum: plan.checksum, to: plan.to, statements: plan.statements.map((s) => statementSha(s.step.sql)), step: plan.step?.sha ?? null, done: plan.done },
169
+ live,
170
+ });
171
+ }
172
+ /** Plans the revert from the history as it is now, with its digest. Reads only; takes no lock. */
173
+ export async function currentRevert(venv, ordered, id, step) {
174
+ const { state, status } = await inspect(venv, ordered);
175
+ const plan = planRevert({ environment: venv.environment, ordered, status, state, id, step });
176
+ return { plan, digest: await revertDigest(venv, status, plan), status };
177
+ }
178
+ export class RevertFailed extends YodelError {
179
+ migration;
180
+ statement;
181
+ serverError;
182
+ constructor(migration, statement, serverError) {
183
+ super(`the revert of ${migration} failed at its statement ${String(statement)}: ${serverError}\n` +
184
+ `Fix the cause, then run yodel revert again: it resumes at statement ${String(statement)} and never sends again the statements that succeeded. ${migration} is still applied.`, 1);
185
+ this.migration = migration;
186
+ this.statement = statement;
187
+ this.serverError = serverError;
188
+ this.name = "RevertFailed";
189
+ }
190
+ }
191
+ /** Runs the revert under the lock, after planning it again and checking its digest and approval. Returns the plan run. */
192
+ export async function executeRevert(venv, ordered, options) {
193
+ const got = await acquireWaiting(venv, appliedBy(options.processEnv), { waitMs: options.lockWaitMs ?? venv.lockWaitMs ?? 0, log: options.log });
194
+ if ("stoodDown" in got)
195
+ throw new YodelError("the revert stood down", 1);
196
+ const { lock } = got;
197
+ options.log(lock.notice ? `lock: ${lock.notice}` : `lock: held in ${lock.where}`);
198
+ return withLock(lock, venv.lockTtlMs, async (beat) => {
199
+ await venv.store.ensure();
200
+ await venv.store.allowRevert?.();
201
+ const { state, status } = await inspect(venv, ordered);
202
+ const plan = planRevert({ environment: venv.environment, ordered, status, state, id: options.id, step: options.step });
203
+ const digest = await revertDigest(venv, status, plan);
204
+ if (!(await sameDigest(digest, options.approvedDigest))) {
205
+ throw new YodelError(`refused: the revert's plan moved since it was approved (approved ${options.approvedDigest}, now ${digest}). Nothing was reverted; run yodel revert ${venv.environment} ${options.id} again and approve the new plan.`, 1);
206
+ }
207
+ await options.approve(digest);
208
+ // The policy, judged again under the lock for the digest computed here: a denial with no override for it refuses.
209
+ const overrides = options.policy ? await options.policy(digest, plan) : [];
210
+ const m = plan.migration;
211
+ const recorder = new HistoryRecorder(venv.store, newRunContext(options.approvedDigest, options.processEnv), state.maxSeq);
212
+ const base = { migration_id: m.id, parent: m.parent ?? "", checksum: plan.checksum, silences: "[]" };
213
+ options.log(`${m.id}: reverting to ${plan.to ?? "an empty schema"}${plan.done.length > 0 ? `, resuming at statement ${String(plan.statements.findIndex((_, i) => !plan.done.includes(i)))}` : ""}`);
214
+ const rowNote = venv.driver.rowNote ?? "";
215
+ for (const [i, s] of plan.statements.entries()) {
216
+ if (plan.done.includes(i)) {
217
+ options.log(` statement ${String(i)}: succeeded in an earlier run; not sent`);
218
+ continue;
219
+ }
220
+ await beat();
221
+ const row = { ...base, kind: "revert", statement_index: i, statement_sha: statementSha(s.step.sql), note: rowNote };
222
+ await recorder.record({ ...row, status: "started" });
223
+ try {
224
+ await venv.driver.runStatement(s.step, { succeeded: (note) => recorder.record({ ...row, status: "succeeded", note: [rowNote, note].filter(Boolean).join("; ") }), log: options.log });
225
+ }
226
+ catch (e) {
227
+ const error = e instanceof Error ? e.message : String(e);
228
+ await recorder.record({ ...row, status: "failed", error });
229
+ options.log(` statement ${String(i)}: failed: ${error.split("\n")[0] ?? ""}`);
230
+ throw new RevertFailed(m.id, i, error.split("\n")[0] ?? error);
231
+ }
232
+ options.log(` statement ${String(i)}: ok (${s.source === "step" ? `the revert step ${plan.step?.file ?? ""}` : `${s.step.rule} ${s.step.class}, ${s.step.name}`})`);
233
+ }
234
+ const note = JSON.stringify({
235
+ revert: { to: plan.to, statements: plan.statements.length, ...(plan.step ? { step: plan.step.file, stepSha: plan.step.sha } : {}) },
236
+ ...(overrides.length > 0 ? { policy: { overrides } } : {}),
237
+ });
238
+ await recorder.record({ ...base, kind: "migration", statement_index: MIGRATION_ROW, statement_sha: "", status: "reverted", note });
239
+ options.log(`${m.id}: reverted`);
240
+ return plan;
241
+ });
242
+ }
243
+ /** The revert `yodel apply --digest` or `--execute` runs instead, when `yodel revert` started the Op run. */
244
+ export function revertFromEnv(env, dir) {
245
+ const id = env[REVERT_ENV];
246
+ if (!id)
247
+ return undefined;
248
+ const file = env[REVERT_STEP_ENV];
249
+ return { id, ...(file ? { step: readRevertStep(file, dir) } : {}) };
250
+ }
251
+ //# sourceMappingURL=revert.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"revert.js","sourceRoot":"","sources":["../../src/versioned/revert.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * `yodel apply --stand-down` (`YODEL_STAND_DOWN=1`): an apply that a newer
3
+ * commit will make anyway steps aside instead of queueing for the lock.
4
+ *
5
+ * The branch is the one the run is for: `GITHUB_REF_NAME` (GitHub and
6
+ * Forgejo Actions), `CI_COMMIT_BRANCH` (GitLab CI), else the checked-out
7
+ * branch. Its tip is fetched from `origin`; when that tip is a different
8
+ * commit that contains this one, a newer commit is on the branch, and its
9
+ * own apply job applies the same environment, this run included. Anything
10
+ * that cannot be told (no branch, no origin, a fetch that fails, a tip that
11
+ * does not contain this commit, as after a force-push) is not a newer
12
+ * commit: the apply goes ahead.
13
+ */
14
+ export declare const STAND_DOWN_ENV = "YODEL_STAND_DOWN";
15
+ /** Whether the environment asks for stand-down: `YODEL_STAND_DOWN=1` (or `true`). */
16
+ export declare const standDownFromEnv: (env: NodeJS.ProcessEnv) => boolean;
17
+ /** A newer commit on the run's branch, which will apply the environment itself. */
18
+ export interface NewerCommit {
19
+ branch: string;
20
+ /** This run's commit. */
21
+ head: string;
22
+ /** The branch's tip on origin. */
23
+ tip: string;
24
+ }
25
+ /** The branch a run is for; see the module comment. */
26
+ export declare function runBranch(dir: string, env: NodeJS.ProcessEnv): Promise<string | undefined>;
27
+ /** The newer commit on the run's branch, or `undefined` when there is none or it cannot be told. */
28
+ export declare function newerCommit(dir: string, env?: NodeJS.ProcessEnv): Promise<NewerCommit | undefined>;
29
+ /** What a run that stands down says. */
30
+ export declare const standDownLine: (env: string, n: NewerCommit) => string;