@intentius/sql-yodeler 0.1.0 → 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 (177) hide show
  1. package/README.md +26 -24
  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/drift.d.ts +69 -1
  8. package/dist/chant/drift.js +152 -5
  9. package/dist/chant/drift.js.map +1 -1
  10. package/dist/chant/runnable.d.ts +19 -0
  11. package/dist/chant/runnable.js +47 -0
  12. package/dist/chant/runnable.js.map +1 -0
  13. package/dist/cli.d.ts +4 -0
  14. package/dist/cli.js +40 -0
  15. package/dist/cli.js.map +1 -1
  16. package/dist/command.d.ts +6 -0
  17. package/dist/command.js.map +1 -1
  18. package/dist/commands/apply.js +161 -41
  19. package/dist/commands/apply.js.map +1 -1
  20. package/dist/commands/approve.d.ts +5 -0
  21. package/dist/commands/approve.js +111 -0
  22. package/dist/commands/approve.js.map +1 -0
  23. package/dist/commands/drift.d.ts +11 -0
  24. package/dist/commands/drift.js +247 -18
  25. package/dist/commands/drift.js.map +1 -1
  26. package/dist/commands/index.js +6 -0
  27. package/dist/commands/index.js.map +1 -1
  28. package/dist/commands/init.d.ts +3 -0
  29. package/dist/commands/init.js +15 -11
  30. package/dist/commands/init.js.map +1 -1
  31. package/dist/commands/lint.js +14 -5
  32. package/dist/commands/lint.js.map +1 -1
  33. package/dist/commands/mcp.d.ts +3 -0
  34. package/dist/commands/mcp.js +50 -0
  35. package/dist/commands/mcp.js.map +1 -0
  36. package/dist/commands/new.d.ts +2 -0
  37. package/dist/commands/new.js +134 -10
  38. package/dist/commands/new.js.map +1 -1
  39. package/dist/commands/override.d.ts +3 -0
  40. package/dist/commands/override.js +118 -0
  41. package/dist/commands/override.js.map +1 -0
  42. package/dist/commands/plan.js +38 -26
  43. package/dist/commands/plan.js.map +1 -1
  44. package/dist/commands/repair.d.ts +11 -0
  45. package/dist/commands/repair.js +15 -7
  46. package/dist/commands/repair.js.map +1 -1
  47. package/dist/commands/status.js +12 -12
  48. package/dist/commands/status.js.map +1 -1
  49. package/dist/config/define.d.ts +101 -3
  50. package/dist/config/define.js +1 -1
  51. package/dist/config/define.js.map +1 -1
  52. package/dist/config/load.js +64 -4
  53. package/dist/config/load.js.map +1 -1
  54. package/dist/config/settings.d.ts +14 -1
  55. package/dist/config/settings.js +32 -4
  56. package/dist/config/settings.js.map +1 -1
  57. package/dist/env-args.d.ts +6 -0
  58. package/dist/env-args.js +31 -1
  59. package/dist/env-args.js.map +1 -1
  60. package/dist/exit.d.ts +20 -0
  61. package/dist/exit.js +28 -0
  62. package/dist/exit.js.map +1 -0
  63. package/dist/history/client.d.ts +8 -0
  64. package/dist/history/client.js +24 -1
  65. package/dist/history/client.js.map +1 -1
  66. package/dist/history/lock.d.ts +5 -1
  67. package/dist/history/lock.js +8 -2
  68. package/dist/history/lock.js.map +1 -1
  69. package/dist/index.d.ts +1 -1
  70. package/dist/init/adopt.js +8 -3
  71. package/dist/init/adopt.js.map +1 -1
  72. package/dist/init/live.d.ts +11 -0
  73. package/dist/init/live.js +25 -2
  74. package/dist/init/live.js.map +1 -1
  75. package/dist/lint/check.d.ts +8 -1
  76. package/dist/lint/check.js +23 -4
  77. package/dist/lint/check.js.map +1 -1
  78. package/dist/mcp/server.d.ts +40 -0
  79. package/dist/mcp/server.js +106 -0
  80. package/dist/mcp/server.js.map +1 -0
  81. package/dist/mcp/tools.d.ts +72 -0
  82. package/dist/mcp/tools.js +178 -0
  83. package/dist/mcp/tools.js.map +1 -0
  84. package/dist/migrations/checks.d.ts +28 -0
  85. package/dist/migrations/checks.js +97 -0
  86. package/dist/migrations/checks.js.map +1 -0
  87. package/dist/migrations/create.d.ts +3 -1
  88. package/dist/migrations/create.js +1 -0
  89. package/dist/migrations/create.js.map +1 -1
  90. package/dist/migrations/directory.js +4 -0
  91. package/dist/migrations/directory.js.map +1 -1
  92. package/dist/migrations/document.d.ts +23 -0
  93. package/dist/migrations/document.js +1 -0
  94. package/dist/migrations/document.js.map +1 -1
  95. package/dist/migrations/index.d.ts +1 -0
  96. package/dist/migrations/index.js +1 -0
  97. package/dist/migrations/index.js.map +1 -1
  98. package/dist/pr/forge.d.ts +4 -0
  99. package/dist/pr/forge.js +21 -7
  100. package/dist/pr/forge.js.map +1 -1
  101. package/dist/pr/issue.d.ts +68 -0
  102. package/dist/pr/issue.js +107 -0
  103. package/dist/pr/issue.js.map +1 -0
  104. package/dist/pr/model.d.ts +9 -1
  105. package/dist/pr/model.js +30 -6
  106. package/dist/pr/model.js.map +1 -1
  107. package/dist/pr/render.d.ts +3 -1
  108. package/dist/pr/render.js +36 -3
  109. package/dist/pr/render.js.map +1 -1
  110. package/dist/replay/index.d.ts +3 -0
  111. package/dist/replay/index.js +3 -0
  112. package/dist/replay/index.js.map +1 -1
  113. package/dist/replay/replay.js +1 -1
  114. package/dist/replay/replay.js.map +1 -1
  115. package/dist/replay/shared.d.ts +28 -0
  116. package/dist/replay/shared.js +77 -0
  117. package/dist/replay/shared.js.map +1 -0
  118. package/dist/schemas.d.ts +34 -0
  119. package/dist/schemas.js +38 -0
  120. package/dist/schemas.js.map +1 -0
  121. package/dist/server.d.ts +40 -0
  122. package/dist/server.js +87 -0
  123. package/dist/server.js.map +1 -0
  124. package/dist/steps/backfill.d.ts +21 -17
  125. package/dist/steps/backfill.js +20 -20
  126. package/dist/steps/backfill.js.map +1 -1
  127. package/dist/steps/index.d.ts +2 -2
  128. package/dist/steps/index.js +3 -3
  129. package/dist/steps/index.js.map +1 -1
  130. package/dist/steps/rebuild.d.ts +15 -15
  131. package/dist/steps/rebuild.js +17 -24
  132. package/dist/steps/rebuild.js.map +1 -1
  133. package/dist/versioned/checks.d.ts +29 -0
  134. package/dist/versioned/checks.js +54 -0
  135. package/dist/versioned/checks.js.map +1 -0
  136. package/dist/versioned/clickhouse.js +8 -0
  137. package/dist/versioned/clickhouse.js.map +1 -1
  138. package/dist/versioned/driver.d.ts +10 -0
  139. package/dist/versioned/engine.d.ts +55 -1
  140. package/dist/versioned/engine.js +99 -6
  141. package/dist/versioned/engine.js.map +1 -1
  142. package/dist/versioned/explain.js +7 -2
  143. package/dist/versioned/explain.js.map +1 -1
  144. package/dist/versioned/index.d.ts +9 -0
  145. package/dist/versioned/index.js +24 -1
  146. package/dist/versioned/index.js.map +1 -1
  147. package/dist/versioned/op.d.ts +10 -0
  148. package/dist/versioned/op.js +36 -4
  149. package/dist/versioned/op.js.map +1 -1
  150. package/dist/versioned/policy.d.ts +67 -0
  151. package/dist/versioned/policy.js +161 -0
  152. package/dist/versioned/policy.js.map +1 -0
  153. package/dist/versioned/postgres/driver.d.ts +3 -1
  154. package/dist/versioned/postgres/driver.js +30 -3
  155. package/dist/versioned/postgres/driver.js.map +1 -1
  156. package/dist/versioned/postgres/waits.d.ts +46 -0
  157. package/dist/versioned/postgres/waits.js +78 -0
  158. package/dist/versioned/postgres/waits.js.map +1 -0
  159. package/dist/versioned/report.d.ts +3 -0
  160. package/dist/versioned/report.js +4 -1
  161. package/dist/versioned/report.js.map +1 -1
  162. package/dist/versioned/stand-down.d.ts +30 -0
  163. package/dist/versioned/stand-down.js +56 -0
  164. package/dist/versioned/stand-down.js.map +1 -0
  165. package/package.json +18 -8
  166. package/schemas/apply.schema.json +269 -0
  167. package/schemas/common.schema.json +213 -0
  168. package/schemas/drift.schema.json +36 -0
  169. package/schemas/init.schema.json +31 -0
  170. package/schemas/lint-rules.schema.json +54 -0
  171. package/schemas/lint.schema.json +290 -0
  172. package/schemas/mcp.schema.json +70 -0
  173. package/schemas/new.schema.json +71 -0
  174. package/schemas/plan.schema.json +371 -0
  175. package/schemas/rebase.schema.json +54 -0
  176. package/schemas/repair.schema.json +20 -0
  177. package/schemas/status.schema.json +310 -0
package/README.md CHANGED
@@ -1,38 +1,36 @@
1
1
  # SQL Yodeler
2
2
 
3
- Schema management and migrations for ClickHouse and Postgres, on chant's `sql` lexicon. `design/README.md` is the design, and `research/` holds the reports it is based on.
3
+ Schema management and migrations for ClickHouse and Postgres, on chant's `sql` lexicon.
4
4
 
5
- ## Documentation
6
-
7
- [`docs/`](docs/README.md) covers installing (the package is not on npm; it installs from git, which needs read access to this private repository, or from a clone or a packed tarball), [starting a project](docs/adoption.md) from a template or with `yodel init --from`, [the declarative and versioned workflows](docs/workflows.md), [migrations](docs/migrations.md), [steps](docs/steps.md), [lint](docs/lint.md), [approval](docs/approval.md), [drift](docs/drift.md) and [topology](docs/topology.md).
5
+ SQL Yodeler is built on [chant](https://www.npmjs.com/package/@intentius/chant), a declarative infrastructure-as-code toolkit in TypeScript. You need chant's CLI (`@intentius/chant` on npm) for three things only: `chant init` to make a project from a template, `chant approve` to approve a plan, and `chant emulator up` for a local database. Run it as `npx @intentius/chant@latest` before the project exists, and as `npx chant` inside it, where `npm install` put it.
8
6
 
9
- [`examples/clickhouse`](examples/clickhouse/README.md) and [`examples/postgres`](examples/postgres/README.md) are example projects, each with a transcript of a run against chant's emulator.
7
+ ## Getting started
10
8
 
11
- ## Starting a project
12
-
13
- `templates/clickhouse` and `templates/postgres` are starter projects for `chant init --from`:
9
+ [Your first migration](docs/getting-started.md) goes from an empty directory to two applied migrations on a local ClickHouse, with every command and its output. In short:
14
10
 
15
11
  ```sh
16
- chant init --from INTENTIUS/sql-yodeler@main#templates/clickhouse --param name=events-schema --param database=events my-schema
17
- chant init --from INTENTIUS/sql-yodeler@main#templates/postgres --param name=app-schema --param schema=app my-schema
12
+ npx @intentius/chant@latest init --from INTENTIUS/sql-yodeler@main#templates/clickhouse --param name=events-schema --param database=events my-schema
13
+ cd my-schema && npm install && git init -b main && git add -A && git commit -m "chore: a new yodel project"
14
+ npx chant emulator up --lexicon sql # ClickHouse and Postgres in Docker
15
+ export DEV_CLICKHOUSE_READER_USER=default DEV_CLICKHOUSE_READER_PASSWORD= DEV_CLICKHOUSE_WRITER_USER=default DEV_CLICKHOUSE_WRITER_PASSWORD=
16
+ npx yodel new init && npx yodel lint
17
+ git add -A && git commit -m "feat: the first migration"
18
+ npx yodel apply dev # stops at the approval
19
+ npx chant approve migrate-dev approve-migrate-dev --plan "$(npx yodel apply dev --digest)"
20
+ npx yodel apply dev
18
21
  ```
19
22
 
20
- Each gives `chant.config.ts` with a profile per environment (`dev`, `prod`), `yodel.config.ts`, a migrate Op per environment (`yodel apply` behind a gate bound to the plan digest), a `WatchOp` per environment for drift on a schedule, and pipelines for GitHub Actions, GitLab CI and Forgejo Actions: `yodel lint` and the plan comment on pull requests with read-only credentials, `yodel apply` on a push to main with the writer, and the drift watch on its cron with the reader. `scripts/ci.ts` in the project renders the pipelines again after an environment is added (`npm run ci`). The parameters are in each template's `chant.template.json`; the template's README covers the credentials and each forge's setup.
23
+ For Postgres, use `templates/postgres` with `--param name=app-schema --param schema=app`.
21
24
 
22
- ## Development
25
+ Each template gives `chant.config.ts` with a profile per environment (`dev`, `prod`), `yodel.config.ts`, a migrate Op per environment (`yodel apply` behind a gate bound to the plan digest), a `WatchOp` per environment for drift on a schedule, and pipelines for GitHub Actions, GitLab CI and Forgejo Actions: `yodel lint` and the plan comment on pull requests with read-only credentials, `yodel apply` on a push to main with the writer, and the drift watch on its cron with the reader. `scripts/ci.ts` in the project renders the pipelines again after an environment is added (`npm run ci`). The parameters are in each template's `chant.template.json`; the template's README covers the credentials and each forge's setup.
23
26
 
24
- Node 22 (`.nvmrc`).
27
+ ## Documentation
25
28
 
26
- ```sh
27
- npm ci
28
- npm run build
29
- npx yodel --help
30
- npm run check # typecheck, lint and test
31
- ```
29
+ The documentation is at [intentius.io/sql-yodeler](https://intentius.io/sql-yodeler/), built from [`docs/`](docs/README.md): [installing](docs/configuration.md#installing) (`npm install @intentius/sql-yodeler`), [starting a project](docs/adoption.md) from a template or with `yodel init --from`, [the declarative and versioned workflows](docs/workflows.md), [migrations](docs/migrations.md), [steps](docs/steps.md), [lint](docs/lint.md), [approval](docs/approval.md), [drift](docs/drift.md) and [topology](docs/topology.md).
32
30
 
33
- Working rules are in `AGENTS.md`.
31
+ [`examples/clickhouse`](examples/clickhouse/README.md) and [`examples/postgres`](examples/postgres/README.md) are finished example projects, each with a transcript of a run against chant's emulator.
34
32
 
35
- ## Versioned migrations (ClickHouse)
33
+ ## Versioned migrations
36
34
 
37
35
  `yodel apply <env>` takes the versioned path when the project has a `migrations/` directory holding at least one migration (`yodel new` writes them); otherwise it is the declarative path, unchanged. `yodel status <env>` lists applied, pending, out-of-order and part-way migrations and checksum mismatches (`--json`; exit 0 up to date, 3 pending, 4 mismatch or out of order, 2 an Op step, 1 error).
38
36
 
@@ -63,7 +61,7 @@ export default defineConfig({
63
61
 
64
62
  One migrations directory serves every topology. `yodel new` writes each statement for a single node and records nothing about where it runs; `yodel apply` renders each statement for the environment's topology as it sends it (chant's `renderStatement`). The history records a statement by the hash of the statement as written, so a migration that failed part way resumes the same way on any topology, and the statement row's `note` says the topology it was sent for (`topology=cluster:main`). The plan digest covers the topology, so an approval given for one topology does not apply on another. The history table's own engine follows the topology too: MergeTree on a single node and on Cloud, `ReplicatedMergeTree` `ON CLUSTER` on a cluster (one copy for the whole cluster), `ReplicatedMergeTree` inside a `Replicated` database. `yodel status` and `yodel plan` print the topology and where it came from.
65
63
 
66
- The declarative path (no `migrations/`) plans and applies through chant, which reads `sql.profiles.<env>.topology` only, so a topology set in `yodel.config.ts` alone is refused there; set it in chant.config.ts as well. A rebuild step (`ClickHouseRebuildOp`) runs through chant too, but yodel hands its activities the environment's topology, so it renders for the same topology as the statements around it.
64
+ The declarative path (no `migrations/`) plans and applies through chant, which reads `sql.profiles.<env>.topology` only, so a topology other than `single` set in `yodel.config.ts` alone is refused there; set it in chant.config.ts as well. A rebuild step (`ClickHouseRebuildOp`) runs through chant too, but yodel hands its activities the environment's topology, so it renders for the same topology as the statements around it.
67
65
 
68
66
  One apply runs at a time: the lock is a row in a KeeperMap table, `<db>.lock`, which needs Keeper and `keeper_map_path_prefix` on the server. A single node without them gets a lock file on the runner's machine, and the run says cross-runner locking needs Keeper. A lock left by a dead runner expires; to clear it sooner, once you know nothing is applying: `ALTER TABLE <db>.lock DELETE WHERE name = 'apply'` (or remove the lock file the refusal names).
69
67
 
@@ -87,7 +85,7 @@ export const op = Op({
87
85
  });
88
86
  ```
89
87
 
90
- `yodel apply prod` stops at the gate and prints `chant approve migrate-prod approve-migrate-prod --plan <digest>`; approve, then run it again. `yodel apply prod --plan` prints the pending migrations and the digest without applying. Running `chant run migrate-prod` directly needs `yodel` on PATH.
88
+ `yodel apply prod` stops at the gate and prints `chant approve migrate-prod approve-migrate-prod --plan <digest>`; approve (inside the project, `npx chant approve ...`), then run it again. `yodel apply prod --plan` prints the pending migrations and the digest without applying. Running `chant run migrate-prod` directly needs `yodel` on PATH.
91
89
 
92
90
  ## yodel lint
93
91
 
@@ -108,4 +106,8 @@ The reason is required. `yodel apply` records each silence (step, rule, reason)
108
106
 
109
107
  `yodel lint --env <env>` also reads the environment's history: an applied migration whose files changed since it ran is a `checksum` error, a pending migration's edit a warning. `yodel.config.ts` sets rule levels: `lint: { rules: { "ch-mutation": "warning", "pg-lock": "off" } }`; the integrity rules cannot be lowered. `yodel lint --rules` lists the rules and their levels.
110
108
 
111
- `yodel lint --replay <env>` also replays every migration, in order, into `<env>`'s server (a throwaway emulator, `chant emulator up --lexicon sql`) and compares each with its recorded schema; the first that differs fails the run (rule `replay`, exit 3), named. The databases or schemas the history names must not exist there yet: otherwise it exits 4 and runs nothing, unless `--reset`, which drops them first (never point it at a server whose data matters). `--keep` leaves the replayed database in place to look at.
109
+ `yodel lint --replay <env>` also replays every migration, in order, into `<env>`'s server (a throwaway emulator, `npx chant emulator up --lexicon sql`) and compares each with its recorded schema; the first that differs fails the run (rule `replay`, exit 3), named. The databases or schemas the history names must not exist there yet: otherwise it exits 4 and runs nothing, unless `--reset`, which drops them first (never point it at a server whose data matters). `--keep` leaves the replayed database in place to look at.
110
+
111
+ ## Contributing
112
+
113
+ [CONTRIBUTING.md](CONTRIBUTING.md) covers building SQL Yodeler from a clone, the checks, and the scenario claims.
package/dist/bin.js CHANGED
@@ -6,9 +6,24 @@
6
6
  import { register } from "tsx/esm/api";
7
7
  register();
8
8
  const { main } = await import("./cli.js");
9
+ const terminal = process.stdin.isTTY && process.stderr.isTTY;
9
10
  const code = await main(process.argv.slice(2), {
10
11
  out: (text) => process.stdout.write(text),
11
12
  err: (text) => process.stderr.write(text),
13
+ ...(terminal
14
+ ? {
15
+ ask: async (question) => {
16
+ const { createInterface } = await import("node:readline/promises");
17
+ const rl = createInterface({ input: process.stdin, output: process.stderr });
18
+ try {
19
+ return await rl.question(question);
20
+ }
21
+ finally {
22
+ rl.close();
23
+ }
24
+ },
25
+ }
26
+ : {}),
12
27
  });
13
28
  process.exitCode = code;
14
29
  //# sourceMappingURL=bin.js.map
package/dist/bin.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,6EAA6E;AAC7E,wEAAwE;AACxE,4EAA4E;AAC5E,iEAAiE;AACjE,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,QAAQ,EAAE,CAAC;AACX,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;AAE1C,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;IAC7C,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC;IACzC,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC;CAC1C,CAAC,CAAC;AACH,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC"}
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,6EAA6E;AAC7E,wEAAwE;AACxE,4EAA4E;AAC5E,iEAAiE;AACjE,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,QAAQ,EAAE,CAAC;AACX,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;AAE1C,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;AAC7D,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;IAC7C,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC;IACzC,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC;IACzC,GAAG,CAAC,QAAQ;QACV,CAAC,CAAC;YACE,GAAG,EAAE,KAAK,EAAE,QAAgB,EAAE,EAAE;gBAC9B,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,MAAM,CAAC,wBAAwB,CAAC,CAAC;gBACnE,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;gBAC7E,IAAI,CAAC;oBACH,OAAO,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;gBACrC,CAAC;wBAAS,CAAC;oBACT,EAAE,CAAC,KAAK,EAAE,CAAC;gBACb,CAAC;YACH,CAAC;SACF;QACH,CAAC,CAAC,EAAE,CAAC;CACR,CAAC,CAAC;AACH,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC"}
@@ -8,7 +8,7 @@
8
8
  * through it.
9
9
  */
10
10
  import type { OpConfig } from "@intentius/chant/op/types";
11
- import { type Environment, type Project, type SqlDialect } from "../project.js";
11
+ import { YodelError, type Environment, type Project, type SqlDialect } from "../project.js";
12
12
  /** The ApplyOp yodel runs for an environment. */
13
13
  export interface ApplyOpRef {
14
14
  name: string;
@@ -28,6 +28,12 @@ export declare function selectApplyOp(ops: ReadonlyMap<string, {
28
28
  config: OpConfig;
29
29
  filePath: string;
30
30
  }>, project: Project, env: Environment, name?: string): ApplyOpRef;
31
+ /**
32
+ * Why the project's Ops could not be found. chant discovers Ops through git
33
+ * (the files git knows), so a project that is not in a git repository has
34
+ * none; say so, and what to run (#19).
35
+ */
36
+ export declare function discoveryError(dir: string, e: unknown): YodelError;
31
37
  /** Discovers the project's Ops the way `chant run` does and picks the ApplyOp for `env`. */
32
38
  export declare function findApplyOp(project: Project, env: Environment, name?: string): Promise<ApplyOpRef>;
33
39
  /** `chant run`'s exit code for a run that stopped at its gate. */
@@ -41,6 +47,8 @@ export interface ApplyRun {
41
47
  /** The plan digest the gate is waiting on. */
42
48
  planDigest?: string;
43
49
  output: string;
50
+ /** The exit code of the Op's Apply step (`yodel apply --execute`), when it ran. */
51
+ stepExit?: number;
44
52
  }
45
53
  /** What a `chant run` of an ApplyOp says about its outcome. */
46
54
  export declare function readApplyRun(code: number, output: string): ApplyRun;
@@ -68,6 +68,18 @@ export function selectApplyOp(ops, project, env, name) {
68
68
  }
69
69
  return { name: op.config.name, filePath: op.filePath, target, gate };
70
70
  }
71
+ /**
72
+ * Why the project's Ops could not be found. chant discovers Ops through git
73
+ * (the files git knows), so a project that is not in a git repository has
74
+ * none; say so, and what to run (#19).
75
+ */
76
+ export function discoveryError(dir, e) {
77
+ const message = e instanceof Error ? e.message : String(e);
78
+ if (/not in a git repository|not a git repository/i.test(message)) {
79
+ return new YodelError(`yodel apply finds the project's Ops through git, and ${dir} is not in a git repository: run git init, then commit the project (git add -A && git commit -m init)`);
80
+ }
81
+ return new YodelError(`could not discover Ops in ${dir}: ${message}`);
82
+ }
71
83
  /** Discovers the project's Ops the way `chant run` does and picks the ApplyOp for `env`. */
72
84
  export async function findApplyOp(project, env, name) {
73
85
  const { discoverOps } = await import("@intentius/chant/op/discover");
@@ -76,7 +88,7 @@ export async function findApplyOp(project, env, name) {
76
88
  found = await discoverOps({ cwd: project.dir });
77
89
  }
78
90
  catch (e) {
79
- throw new YodelError(`could not discover Ops in ${project.dir}: ${e instanceof Error ? e.message : String(e)}`);
91
+ throw discoveryError(project.dir, e);
80
92
  }
81
93
  if (found.errors.length > 0 && found.ops.size === 0) {
82
94
  throw new YodelError(`could not discover Ops in ${project.dir}:\n${found.errors.join("\n")}`);
@@ -1 +1 @@
1
- {"version":3,"file":"apply.js","sourceRoot":"","sources":["../../src/chant/apply.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,UAAU,EAAmD,MAAM,eAAe,CAAC;AAC5F,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAWxC,MAAM,KAAK,GAAG,CAAC,MAAgB,EAAoB,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;AAE5F,oFAAoF;AACpF,SAAS,aAAa,CAAC,MAAgB;IACrC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;QACjC,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,IAAI,IAAI,CAAC,EAAE,KAAK,aAAa;YAAE,OAAO,IAAI,CAAC,IAAI,CAAC;IAC9E,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,6FAA6F;AAC7F,SAAS,aAAa,CAAC,MAAgB;IACrC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;QACjC,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC,IAAI,CAAC;IACxE,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,cAAc,CAAC,GAAW,EAAE,OAAmB;IAC7D,OAAO;QACL,gBAAgB,GAAG,QAAQ;QAC3B,gDAAgD;QAChD,EAAE;QACF,gDAAgD,GAAG,YAAY,GAAG,eAAe,OAAO,iBAAiB;KAC1G,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAC3B,GAAgE,EAChE,OAAgB,EAChB,GAAgB,EAChB,IAAa;IAEb,MAAM,UAAU,GAAG,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;QAChD,MAAM,KAAK,GAAG,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACtC,OAAO,KAAK,EAAE,GAAG,KAAK,GAAG,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,YAAY,IAAI,KAAK,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC;IACnG,CAAC,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;IACpF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,IAAI,IAAI,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,UAAU,CAAC,OAAO,IAAI,uCAAuC,GAAG,CAAC,IAAI,qCAAqC,CAAC,CAAC;QACjJ,MAAM,IAAI,UAAU,CAClB,IAAI;YACF,CAAC,CAAC,gBAAgB,IAAI,QAAQ,OAAO,CAAC,GAAG,EAAE;YAC3C,CAAC,CAAC,kCAAkC,GAAG,CAAC,IAAI,OAAO,OAAO,CAAC,GAAG,kCAAkC,cAAc,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,CAC9I,CAAC;IACJ,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,UAAU,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,0BAA0B,GAAG,CAAC,IAAI,KAAK,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;IACjK,CAAC;IACD,MAAM,CAAC,EAAE,CAAC,GAAG,MAAmC,CAAC;IACjD,MAAM,MAAM,GAAG,aAAa,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,MAAoB,CAAC;IAC9D,IAAI,MAAM,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC;QAC/B,MAAM,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC,MAAM,CAAC,IAAI,oBAAoB,MAAM,kCAAkC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IAC3H,CAAC;IACD,MAAM,IAAI,GAAG,aAAa,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;IACtC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,UAAU,CAClB,OAAO,EAAE,CAAC,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC,QAAQ,+EAA+E;YACnH,uDAAuD,CAC1D,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AACvE,CAAC;AAED,4FAA4F;AAC5F,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAAgB,EAAE,GAAgB,EAAE,IAAa;IACjF,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,8BAA8B,CAAC,CAAC;IACrE,IAAI,KAA8C,CAAC;IACnD,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,WAAW,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAClD,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,IAAI,UAAU,CAAC,6BAA6B,OAAO,CAAC,GAAG,KAAK,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAClH,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACpD,MAAM,IAAI,UAAU,CAAC,6BAA6B,OAAO,CAAC,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAChG,CAAC;IACD,OAAO,aAAa,CAAC,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;AACtD,CAAC;AAED,kEAAkE;AAClE,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC;AAcvB,+DAA+D;AAC/D,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,MAAc;IACvD,MAAM,MAAM,GAAmB,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC5F,MAAM,OAAO,GAAG,4CAA4C,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC/E,MAAM,UAAU,GAAG,2BAA2B,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACjE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;AAC1G,CAAC;AAED,6FAA6F;AAC7F,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,OAAgB,EAAE,EAAc,EAAE,UAA0E,EAAE;IAC7I,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,EAAE,cAAc,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE;QAC7E,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5C,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACxF,CAAC,CAAC;IACH,OAAO,YAAY,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;AACzE,CAAC"}
1
+ {"version":3,"file":"apply.js","sourceRoot":"","sources":["../../src/chant/apply.ts"],"names":[],"mappings":"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"}
@@ -16,6 +16,8 @@
16
16
  import type { LiveDiffResult, UnobservedResource } from "@intentius/chant/lifecycle/live-diff";
17
17
  import type { DeepDiffResult, DeepEntityDrift } from "@intentius/chant/lifecycle/deep-diff";
18
18
  import { type Environment, type Project } from "../project.js";
19
+ import { type ServerInfo } from "../server.js";
20
+ import type { BuildOutput } from "./build.js";
19
21
  /** The `lexicons.sql` section of `chant lifecycle diff --live --json`. */
20
22
  export interface SqlLiveDiff {
21
23
  resources?: LiveDiffResult;
@@ -29,7 +31,44 @@ export interface Drift {
29
31
  missing: string[];
30
32
  /** Declared objects chant could not read. */
31
33
  unobserved: UnobservedResource[];
34
+ /** Postgres: a read gave up at the lock timeout, and what it waited on (#18). */
35
+ lockWait?: string | undefined;
36
+ /** Each changed table's declared column names, by position, so `columns[3]` reads as the column's name (#19). */
37
+ columns?: Record<string, string[]>;
38
+ /** What the server was compared with (#49): `src/`, or the schema the newest applied migration records. */
39
+ against?: DriftAgainst;
32
40
  }
41
+ /**
42
+ * The declaration drift compares the server with: the project's `src/`,
43
+ * or the recorded schema of the newest migration the environment's history
44
+ * records as applied (`migration` null when none is applied yet).
45
+ */
46
+ export type DriftAgainst = {
47
+ source: "src";
48
+ } | {
49
+ source: "history";
50
+ migration: string | null;
51
+ };
52
+ /**
53
+ * A stable fingerprint of the drift: the environment and what drifted
54
+ * (each changed object's changes, declared and live, and the objects gone),
55
+ * order-free, so two reads of the same drift give the same one and a
56
+ * tracking issue updated with it changes only when the drift does. Objects
57
+ * that could not be read are not drift and are left out.
58
+ */
59
+ export declare function driftFingerprint(drift: Drift): string;
60
+ /**
61
+ * The recorded schema as declarations chant can build: one file, written
62
+ * by the sql lexicon's import generator from each object's DDL, each named
63
+ * by its export as the build named it. Written under the project directory,
64
+ * so the generated imports resolve from the project's node_modules, in a
65
+ * directory {@link RecordedSource.dispose} removes.
66
+ */
67
+ export interface RecordedSource {
68
+ dir: string;
69
+ dispose: () => void;
70
+ }
71
+ export declare function writeRecordedSource(projectDir: string, schema: BuildOutput): Promise<RecordedSource>;
33
72
  /** Exit code: an owned object changed or is gone. */
34
73
  export declare const DRIFTED = 2;
35
74
  /** `2` on drift; `1` when there is none but part of the environment could not be read; `0` when clean. */
@@ -39,6 +78,35 @@ export declare function driftFromLifecycle(environment: string, doc: unknown): D
39
78
  /** Runs `chant lifecycle diff <env> --live --json` in the project and reads the drift from it. */
40
79
  export declare function readDrift(project: Project, env: Environment, options?: {
41
80
  env?: NodeJS.ProcessEnv;
81
+ src?: string;
42
82
  }): Promise<Drift>;
83
+ /**
84
+ * The declared column names of each changed object whose drift is named by
85
+ * column position (chant's ClickHouse tables keep columns as a list, so a
86
+ * change reads `columns[3].default.expr`). Read from the project's build,
87
+ * with the dialect's own tag, the way chant reads the declaration.
88
+ */
89
+ export declare function declaredColumns(project: Project, drift: Drift, build: () => Promise<{
90
+ output: {
91
+ objects: Array<{
92
+ export: string;
93
+ ddl: string;
94
+ }>;
95
+ };
96
+ dispose: () => void;
97
+ }>): Promise<Record<string, string[]>>;
98
+ /** `columns[3].default.expr` as `column country: default.expr`, when the declaration names column 3. */
99
+ export declare function describePath(path: string, columns: readonly string[] | undefined): string;
100
+ /** What the server was compared with, in words. */
101
+ export declare function describeAgainst(against: DriftAgainst | undefined): string | undefined;
43
102
  /** The drift as text. */
44
- export declare function renderDrift(drift: Drift): string;
103
+ export declare function renderDrift(drift: Drift, server?: ServerInfo): string;
104
+ /**
105
+ * The drift as markdown, for the tracking issue: the environment and
106
+ * server, what it was compared with, each changed object with its changes,
107
+ * the objects gone, the run that found it, and the fingerprint.
108
+ */
109
+ export declare function renderDriftMarkdown(drift: Drift, server: ServerInfo | undefined, extra: {
110
+ fingerprint: string;
111
+ run?: string;
112
+ }): string;
@@ -13,8 +13,54 @@
13
13
  * An object the project does not declare is never reported: chant only reads
14
14
  * what the project declares, and only touches what carries its marker.
15
15
  */
16
+ import { createHash } from "node:crypto";
17
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
18
+ import { dirname, join } from "node:path";
16
19
  import { YodelError } from "../project.js";
17
20
  import { lastJsonLine, runChant } from "./process.js";
21
+ import { describeServer } from "../server.js";
22
+ /**
23
+ * A stable fingerprint of the drift: the environment and what drifted
24
+ * (each changed object's changes, declared and live, and the objects gone),
25
+ * order-free, so two reads of the same drift give the same one and a
26
+ * tracking issue updated with it changes only when the drift does. Objects
27
+ * that could not be read are not drift and are left out.
28
+ */
29
+ export function driftFingerprint(drift) {
30
+ const changed = drift.changed
31
+ .map((e) => ({
32
+ name: e.name,
33
+ type: e.type,
34
+ changes: e.changes.map((c) => ({ path: c.path, kind: c.kind, declared: c.declared ?? null, live: c.live ?? null })).sort((a, b) => JSON.stringify(a).localeCompare(JSON.stringify(b))),
35
+ }))
36
+ .sort((a, b) => a.name.localeCompare(b.name));
37
+ const subject = JSON.stringify({ environment: drift.environment, changed, missing: [...drift.missing].sort() });
38
+ return `sha256:${createHash("sha256").update(subject, "utf8").digest("hex")}`;
39
+ }
40
+ export async function writeRecordedSource(projectDir, schema) {
41
+ const { sqlTemplateGenerator } = await import("@intentius/chant-lexicon-sql/import-generator");
42
+ const resources = schema.objects.map((o) => {
43
+ const own = o;
44
+ const where = typeof own.database === "string" ? { database: own.database } : typeof own.schema === "string" ? { schema: own.schema } : {};
45
+ return { type: o.type ?? "", logicalId: o.export, properties: { ...where, name: typeof own.name === "string" ? own.name : o.export, ddl: o.ddl } };
46
+ });
47
+ const dir = mkdtempSync(join(projectDir, ".yodel-recorded-"));
48
+ const dispose = () => {
49
+ rmSync(dir, { recursive: true, force: true });
50
+ };
51
+ try {
52
+ for (const f of resources.length === 0 ? [] : sqlTemplateGenerator.generate({ resources, parameters: [] })) {
53
+ const path = join(dir, f.path);
54
+ mkdirSync(dirname(path), { recursive: true });
55
+ writeFileSync(path, f.content);
56
+ }
57
+ }
58
+ catch (e) {
59
+ dispose();
60
+ throw new YodelError(`the recorded schema could not be written as declarations: ${e instanceof Error ? e.message : String(e)}`);
61
+ }
62
+ return { dir, dispose };
63
+ }
18
64
  /** Exit code: an owned object changed or is gone. */
19
65
  export const DRIFTED = 2;
20
66
  /** `2` on drift; `1` when there is none but part of the environment could not be read; `0` when clean. */
@@ -47,7 +93,7 @@ export function driftFromLifecycle(environment, doc) {
47
93
  }
48
94
  /** Runs `chant lifecycle diff <env> --live --json` in the project and reads the drift from it. */
49
95
  export async function readDrift(project, env, options = {}) {
50
- const result = await runChant(["lifecycle", "diff", env.name, "--live", "--json"], {
96
+ const result = await runChant(["lifecycle", "diff", env.name, "--live", "--json", ...(options.src ? ["--src", options.src] : [])], {
51
97
  cwd: project.dir,
52
98
  ...(options.env ? { env: options.env } : {}),
53
99
  });
@@ -58,19 +104,78 @@ export async function readDrift(project, env, options = {}) {
58
104
  }
59
105
  return driftFromLifecycle(env.name, doc);
60
106
  }
107
+ const COLUMN_PATH = /^columns\[(\d+)\]/;
108
+ /**
109
+ * The declared column names of each changed object whose drift is named by
110
+ * column position (chant's ClickHouse tables keep columns as a list, so a
111
+ * change reads `columns[3].default.expr`). Read from the project's build,
112
+ * with the dialect's own tag, the way chant reads the declaration.
113
+ */
114
+ export async function declaredColumns(project, drift, build) {
115
+ const wanted = new Set(drift.changed.filter((e) => e.changes.some((c) => COLUMN_PATH.test(c.path))).map((e) => e.name));
116
+ if (wanted.size === 0)
117
+ return {};
118
+ const b = await build();
119
+ try {
120
+ const tag = project.dialect === "postgres"
121
+ ? (await import("@intentius/chant-lexicon-sql/postgres/entities")).table
122
+ : (await import("@intentius/chant-lexicon-sql/clickhouse/entities")).table;
123
+ const out = {};
124
+ for (const o of b.output.objects) {
125
+ if (!wanted.has(o.export))
126
+ continue;
127
+ try {
128
+ const strings = Object.assign([o.ddl], { raw: [o.ddl] });
129
+ const columns = tag(strings).props.columns;
130
+ if (Array.isArray(columns))
131
+ out[o.export] = columns.map((c) => { const n = c.name; return typeof n === "string" ? n : ""; });
132
+ }
133
+ catch {
134
+ // Not a table this tag reads: its paths stay as chant gives them.
135
+ }
136
+ }
137
+ return out;
138
+ }
139
+ finally {
140
+ b.dispose();
141
+ }
142
+ }
143
+ /** `columns[3].default.expr` as `column country: default.expr`, when the declaration names column 3. */
144
+ export function describePath(path, columns) {
145
+ const m = COLUMN_PATH.exec(path);
146
+ const name = m && columns ? columns[Number(m[1])] : undefined;
147
+ if (!m || !name)
148
+ return path;
149
+ const rest = path.slice(m[0].length).replace(/^\./, "");
150
+ return `column ${name}${rest ? ` ${rest}` : ""}`;
151
+ }
61
152
  const show = (v) => (v === undefined ? "(none)" : typeof v === "string" ? v : JSON.stringify(v));
153
+ /** What the server was compared with, in words. */
154
+ export function describeAgainst(against) {
155
+ if (!against)
156
+ return undefined;
157
+ if (against.source === "src")
158
+ return "Compared with the declared schema in src/.";
159
+ return against.migration
160
+ ? `Compared with the schema ${against.migration} records, the newest migration the history records as applied.`
161
+ : "No migration is applied yet, so the history records no schema to compare with.";
162
+ }
62
163
  /** The drift as text. */
63
- export function renderDrift(drift) {
64
- const lines = [`Drift in ${drift.environment}`, ""];
164
+ export function renderDrift(drift, server) {
165
+ const lines = [`Drift in ${drift.environment}${server ? ` (${describeServer(server)})` : ""}`, ""];
166
+ const against = describeAgainst(drift.against);
167
+ if (against)
168
+ lines.push(against, "");
65
169
  if (drift.changed.length === 0 && drift.missing.length === 0) {
66
- lines.push("No drift: every declared object matches the server.");
170
+ lines.push(drift.unobserved.length > 0 ? "No drift in the declared objects that could be read." : "No drift: every declared object matches the server.");
67
171
  }
68
172
  if (drift.changed.length > 0) {
69
173
  lines.push("Changed out of band:");
70
174
  for (const e of drift.changed) {
71
175
  lines.push(` ${e.name} (${e.type})`);
72
176
  for (const c of e.changes) {
73
- lines.push(c.kind === "absent" ? ` ${c.path}: declared ${show(c.declared)}, absent live` : ` ${c.path}: declared ${show(c.declared)}, live ${show(c.live)}`);
177
+ const path = describePath(c.path, drift.columns?.[e.name]);
178
+ lines.push(c.kind === "absent" ? ` ${path}: declared ${show(c.declared)}, absent live` : ` ${path}: declared ${show(c.declared)}, live ${show(c.live)}`);
74
179
  }
75
180
  }
76
181
  }
@@ -85,7 +190,49 @@ export function renderDrift(drift) {
85
190
  lines.push("", "Could not be read, so their state is unknown:");
86
191
  for (const u of drift.unobserved)
87
192
  lines.push(` ${u.name}: ${u.reason}${u.detail ? ` (${u.detail})` : ""}`);
193
+ if (drift.lockWait)
194
+ lines.push("", `The read ${drift.lockWait}.`);
195
+ }
196
+ return `${lines.join("\n")}\n`;
197
+ }
198
+ const code = (v) => `\`${show(v).replace(/`/g, "'")}\``;
199
+ /**
200
+ * The drift as markdown, for the tracking issue: the environment and
201
+ * server, what it was compared with, each changed object with its changes,
202
+ * the objects gone, the run that found it, and the fingerprint.
203
+ */
204
+ export function renderDriftMarkdown(drift, server, extra) {
205
+ const lines = [`**${drift.environment}**${server ? ` (${describeServer(server)})` : ""} has drifted: declared objects were changed out of band, or are gone.`, ""];
206
+ const against = describeAgainst(drift.against);
207
+ if (against)
208
+ lines.push(against, "");
209
+ if (drift.changed.length > 0) {
210
+ lines.push("Changed out of band:", "");
211
+ for (const e of drift.changed) {
212
+ lines.push(`- \`${e.name}\` (${e.type})`);
213
+ for (const c of e.changes) {
214
+ const path = describePath(c.path, drift.columns?.[e.name]);
215
+ lines.push(c.kind === "absent" ? ` - ${path}: declared ${code(c.declared)}, absent live` : ` - ${path}: declared ${code(c.declared)}, live ${code(c.live)}`);
216
+ }
217
+ }
218
+ lines.push("");
219
+ }
220
+ if (drift.missing.length > 0) {
221
+ lines.push("Gone (declared, not on the server):", "");
222
+ for (const name of drift.missing)
223
+ lines.push(`- \`${name}\``);
224
+ lines.push("");
225
+ }
226
+ if (drift.unobserved.length > 0) {
227
+ lines.push("Could not be read, so their state is unknown:", "");
228
+ for (const u of drift.unobserved)
229
+ lines.push(`- \`${u.name}\`: ${u.reason}`);
230
+ lines.push("");
88
231
  }
232
+ lines.push(`Run \`yodel drift ${drift.environment}\` to see it again. yodel closes this issue when the drift is gone.`);
233
+ if (extra.run)
234
+ lines.push("", `Found by ${extra.run}`);
235
+ lines.push("", `<sub>drift fingerprint ${extra.fingerprint}</sub>`);
89
236
  return `${lines.join("\n")}\n`;
90
237
  }
91
238
  //# sourceMappingURL=drift.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"drift.js","sourceRoot":"","sources":["../../src/chant/drift.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"drift.js","sourceRoot":"","sources":["../../src/chant/drift.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Commands yodel prints for a person to run (#14): `chant approve ...`,
3
+ * `yodel apply ...`. In a project that installs chant and yodel locally,
4
+ * neither is on PATH, only in node_modules/.bin, so a printed `chant approve`
5
+ * fails with "command not found". Such a command is printed as `npx chant
6
+ * ...` instead, which runs the project's own copy. When the tool is on PATH,
7
+ * or the project does not install it (where `npx` would fetch an unrelated
8
+ * package of that name), the command is printed as it is.
9
+ */
10
+ /**
11
+ * Whether `name` is an executable on `PATH`, not counting `node_modules/.bin`
12
+ * directories: `npx yodel` puts the project's on yodel's PATH, but the
13
+ * person's shell does not have it.
14
+ */
15
+ export declare function onPath(name: string, env?: NodeJS.ProcessEnv): boolean;
16
+ /** Whether `dir` or a directory above it has `node_modules/.bin/<name>`. */
17
+ export declare function installedLocally(name: string, dir: string): boolean;
18
+ /** `command` as a person can run it in `projectDir`: prefixed with `npx ` when its tool is installed there but not on PATH. */
19
+ export declare function runnable(command: string, projectDir: string, env?: NodeJS.ProcessEnv): string;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Commands yodel prints for a person to run (#14): `chant approve ...`,
3
+ * `yodel apply ...`. In a project that installs chant and yodel locally,
4
+ * neither is on PATH, only in node_modules/.bin, so a printed `chant approve`
5
+ * fails with "command not found". Such a command is printed as `npx chant
6
+ * ...` instead, which runs the project's own copy. When the tool is on PATH,
7
+ * or the project does not install it (where `npx` would fetch an unrelated
8
+ * package of that name), the command is printed as it is.
9
+ */
10
+ import { accessSync, constants } from "node:fs";
11
+ import { delimiter, dirname, join } from "node:path";
12
+ const executable = (path) => {
13
+ try {
14
+ accessSync(path, constants.X_OK);
15
+ return true;
16
+ }
17
+ catch {
18
+ return false;
19
+ }
20
+ };
21
+ /**
22
+ * Whether `name` is an executable on `PATH`, not counting `node_modules/.bin`
23
+ * directories: `npx yodel` puts the project's on yodel's PATH, but the
24
+ * person's shell does not have it.
25
+ */
26
+ export function onPath(name, env = process.env) {
27
+ return (env.PATH ?? "")
28
+ .split(delimiter)
29
+ .some((d) => d !== "" && !/[\\/]node_modules[\\/]\.bin[\\/]?$/.test(d) && executable(join(d, name)));
30
+ }
31
+ /** Whether `dir` or a directory above it has `node_modules/.bin/<name>`. */
32
+ export function installedLocally(name, dir) {
33
+ for (let d = dir;; d = dirname(d)) {
34
+ if (executable(join(d, "node_modules", ".bin", name)))
35
+ return true;
36
+ if (dirname(d) === d)
37
+ return false;
38
+ }
39
+ }
40
+ /** `command` as a person can run it in `projectDir`: prefixed with `npx ` when its tool is installed there but not on PATH. */
41
+ export function runnable(command, projectDir, env = process.env) {
42
+ const tool = command.split(" ", 1)[0] ?? "";
43
+ if (tool === "" || tool === "npx" || onPath(tool, env) || !installedLocally(tool, projectDir))
44
+ return command;
45
+ return `npx ${command}`;
46
+ }
47
+ //# sourceMappingURL=runnable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runnable.js","sourceRoot":"","sources":["../../src/chant/runnable.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAErD,MAAM,UAAU,GAAG,CAAC,IAAY,EAAW,EAAE;IAC3C,IAAI,CAAC;QACH,UAAU,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;QACjC,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,MAAM,CAAC,IAAY,EAAE,MAAyB,OAAO,CAAC,GAAG;IACvE,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;SACpB,KAAK,CAAC,SAAS,CAAC;SAChB,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,oCAAoC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;AACzG,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,GAAW;IACxD,KAAK,IAAI,CAAC,GAAG,GAAG,GAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QACnC,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,cAAc,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QACnE,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;IACrC,CAAC;AACH,CAAC;AAED,+HAA+H;AAC/H,MAAM,UAAU,QAAQ,CAAC,OAAe,EAAE,UAAkB,EAAE,MAAyB,OAAO,CAAC,GAAG;IAChG,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC5C,IAAI,IAAI,KAAK,EAAE,IAAI,IAAI,KAAK,KAAK,IAAI,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,UAAU,CAAC;QAAE,OAAO,OAAO,CAAC;IAC9G,OAAO,OAAO,OAAO,EAAE,CAAC;AAC1B,CAAC"}
package/dist/cli.d.ts CHANGED
@@ -1,4 +1,8 @@
1
1
  import type { Command, Io } from "./command.js";
2
+ /** Where the docs are published from docs/. */
3
+ export declare const DOCS_URL = "https://intentius.io/sql-yodeler/";
2
4
  export declare function help(list?: readonly Command[]): string;
5
+ /** Wraps `line` at 80 columns, continuing with `indent`. */
6
+ export declare function wrap(line: string, indent: string, width?: number): string;
3
7
  /** Parses argv (without the node and script paths) and runs a verb; resolves to the exit code. */
4
8
  export declare function main(argv: string[], io: Io, list?: readonly Command[]): Promise<number>;