@intentius/sql-yodeler 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/apply-steps/index.d.ts +65 -0
- package/dist/apply-steps/index.js +106 -0
- package/dist/apply-steps/index.js.map +1 -0
- package/dist/approval-mode/index.d.ts +78 -0
- package/dist/approval-mode/index.js +105 -0
- package/dist/approval-mode/index.js.map +1 -0
- package/dist/chant/access.d.ts +87 -0
- package/dist/chant/access.js +169 -0
- package/dist/chant/access.js.map +1 -0
- package/dist/chant/build.js +7 -0
- package/dist/chant/build.js.map +1 -1
- package/dist/chant/drift.d.ts +17 -1
- package/dist/chant/drift.js +55 -2
- package/dist/chant/drift.js.map +1 -1
- package/dist/chant/plan.d.ts +18 -2
- package/dist/chant/plan.js +21 -3
- package/dist/chant/plan.js.map +1 -1
- package/dist/ci/render.d.ts +333 -0
- package/dist/ci/render.js +885 -0
- package/dist/ci/render.js.map +1 -0
- package/dist/ci/replay.d.ts +17 -0
- package/dist/ci/replay.js +69 -0
- package/dist/ci/replay.js.map +1 -0
- package/dist/cleanup/index.d.ts +86 -0
- package/dist/cleanup/index.js +207 -0
- package/dist/cleanup/index.js.map +1 -0
- package/dist/commands/apply.d.ts +113 -0
- package/dist/commands/apply.js +370 -30
- package/dist/commands/apply.js.map +1 -1
- package/dist/commands/approve.d.ts +13 -0
- package/dist/commands/approve.js +239 -13
- package/dist/commands/approve.js.map +1 -1
- package/dist/commands/checkpoint.d.ts +3 -0
- package/dist/commands/checkpoint.js +78 -0
- package/dist/commands/checkpoint.js.map +1 -0
- package/dist/commands/ci.d.ts +3 -0
- package/dist/commands/ci.js +130 -0
- package/dist/commands/ci.js.map +1 -0
- package/dist/commands/cleanup.d.ts +13 -0
- package/dist/commands/cleanup.js +138 -0
- package/dist/commands/cleanup.js.map +1 -0
- package/dist/commands/config.d.ts +3 -0
- package/dist/commands/config.js +136 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/docs.d.ts +11 -0
- package/dist/commands/docs.js +108 -0
- package/dist/commands/docs.js.map +1 -0
- package/dist/commands/drift.d.ts +13 -1
- package/dist/commands/drift.js +52 -5
- package/dist/commands/drift.js.map +1 -1
- package/dist/commands/index.js +16 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/init.js +1 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/lint.js +39 -7
- package/dist/commands/lint.js.map +1 -1
- package/dist/commands/new.js +133 -34
- package/dist/commands/new.js.map +1 -1
- package/dist/commands/override.js +48 -16
- package/dist/commands/override.js.map +1 -1
- package/dist/commands/plan.js +47 -6
- package/dist/commands/plan.js.map +1 -1
- package/dist/commands/report.d.ts +13 -0
- package/dist/commands/report.js +121 -0
- package/dist/commands/report.js.map +1 -0
- package/dist/commands/revert.d.ts +20 -0
- package/dist/commands/revert.js +246 -0
- package/dist/commands/revert.js.map +1 -0
- package/dist/commands/status.js +32 -5
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/test.d.ts +3 -0
- package/dist/commands/test.js +164 -0
- package/dist/commands/test.js.map +1 -0
- package/dist/config/base.d.ts +69 -0
- package/dist/config/base.js +121 -0
- package/dist/config/base.js.map +1 -0
- package/dist/config/define.d.ts +240 -3
- package/dist/config/define.js +4 -0
- package/dist/config/define.js.map +1 -1
- package/dist/config/index.d.ts +2 -0
- package/dist/config/index.js +2 -0
- package/dist/config/index.js.map +1 -1
- package/dist/config/load.d.ts +1 -1
- package/dist/config/load.js +156 -7
- package/dist/config/load.js.map +1 -1
- package/dist/config/settings.d.ts +22 -1
- package/dist/config/settings.js +34 -2
- package/dist/config/settings.js.map +1 -1
- package/dist/credentials.d.ts +119 -0
- package/dist/credentials.js +119 -0
- package/dist/credentials.js.map +1 -0
- package/dist/exit.js +1 -1
- package/dist/exit.js.map +1 -1
- package/dist/history/postgres/ddl.d.ts +18 -0
- package/dist/history/postgres/ddl.js +27 -2
- package/dist/history/postgres/ddl.js.map +1 -1
- package/dist/history/postgres/store.d.ts +2 -0
- package/dist/history/postgres/store.js +7 -1
- package/dist/history/postgres/store.js.map +1 -1
- package/dist/history/rows.d.ts +16 -3
- package/dist/history/rows.js +30 -1
- package/dist/history/rows.js.map +1 -1
- package/dist/history/store.d.ts +2 -0
- package/dist/history/store.js +2 -2
- package/dist/history/store.js.map +1 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/init/adopt.js +1 -1
- package/dist/init/adopt.js.map +1 -1
- package/dist/init/clickhouse-access.d.ts +64 -0
- package/dist/init/clickhouse-access.js +211 -0
- package/dist/init/clickhouse-access.js.map +1 -0
- package/dist/init/live.d.ts +4 -0
- package/dist/init/live.js +16 -0
- package/dist/init/live.js.map +1 -1
- package/dist/lint/access.d.ts +18 -0
- package/dist/lint/access.js +34 -0
- package/dist/lint/access.js.map +1 -0
- package/dist/lint/check.js +38 -6
- package/dist/lint/check.js.map +1 -1
- package/dist/lint/config.d.ts +7 -1
- package/dist/lint/config.js +11 -5
- package/dist/lint/config.js.map +1 -1
- package/dist/lint/index.d.ts +2 -0
- package/dist/lint/index.js +2 -0
- package/dist/lint/index.js.map +1 -1
- package/dist/lint/naming.d.ts +62 -0
- package/dist/lint/naming.js +138 -0
- package/dist/lint/naming.js.map +1 -0
- package/dist/lint/report.js +1 -1
- package/dist/lint/report.js.map +1 -1
- package/dist/lint/routines.d.ts +26 -0
- package/dist/lint/routines.js +65 -0
- package/dist/lint/routines.js.map +1 -0
- package/dist/lint/rules.d.ts +51 -6
- package/dist/lint/rules.js +23 -6
- package/dist/lint/rules.js.map +1 -1
- package/dist/lint/schema-checks.d.ts +63 -0
- package/dist/lint/schema-checks.js +128 -0
- package/dist/lint/schema-checks.js.map +1 -0
- package/dist/lint/statements.d.ts +22 -1
- package/dist/lint/statements.js +40 -1
- package/dist/lint/statements.js.map +1 -1
- package/dist/mcp/tools.d.ts +1 -1
- package/dist/mcp/tools.js +1 -1
- package/dist/mcp/tools.js.map +1 -1
- package/dist/migrations/checkpoint.d.ts +45 -0
- package/dist/migrations/checkpoint.js +108 -0
- package/dist/migrations/checkpoint.js.map +1 -0
- package/dist/migrations/checks.d.ts +19 -1
- package/dist/migrations/checks.js +15 -0
- package/dist/migrations/checks.js.map +1 -1
- package/dist/migrations/create.d.ts +13 -4
- package/dist/migrations/create.js +24 -7
- package/dist/migrations/create.js.map +1 -1
- package/dist/migrations/document.d.ts +10 -0
- package/dist/migrations/document.js +1 -0
- package/dist/migrations/document.js.map +1 -1
- package/dist/migrations/index.d.ts +2 -0
- package/dist/migrations/index.js +2 -0
- package/dist/migrations/index.js.map +1 -1
- package/dist/migrations/routines.d.ts +21 -0
- package/dist/migrations/routines.js +30 -0
- package/dist/migrations/routines.js.map +1 -0
- package/dist/notify/index.d.ts +124 -0
- package/dist/notify/index.js +210 -0
- package/dist/notify/index.js.map +1 -0
- package/dist/notify/verify.d.ts +53 -0
- package/dist/notify/verify.js +71 -0
- package/dist/notify/verify.js.map +1 -0
- package/dist/pr/model.d.ts +7 -1
- package/dist/pr/model.js +29 -7
- package/dist/pr/model.js.map +1 -1
- package/dist/pr/render.d.ts +4 -1
- package/dist/pr/render.js +49 -9
- package/dist/pr/render.js.map +1 -1
- package/dist/pr/tenants.d.ts +37 -0
- package/dist/pr/tenants.js +138 -0
- package/dist/pr/tenants.js.map +1 -0
- package/dist/probe.d.ts +27 -0
- package/dist/probe.js +106 -0
- package/dist/probe.js.map +1 -0
- package/dist/project.d.ts +35 -2
- package/dist/project.js +62 -2
- package/dist/project.js.map +1 -1
- package/dist/replay/clickhouse.d.ts +31 -0
- package/dist/replay/clickhouse.js +103 -6
- package/dist/replay/clickhouse.js.map +1 -1
- package/dist/replay/replay.d.ts +14 -3
- package/dist/replay/replay.js +62 -31
- package/dist/replay/replay.js.map +1 -1
- package/dist/replay/report.js +1 -1
- package/dist/replay/report.js.map +1 -1
- package/dist/report/audit.d.ts +138 -0
- package/dist/report/audit.js +219 -0
- package/dist/report/audit.js.map +1 -0
- package/dist/report/jsonl.d.ts +21 -0
- package/dist/report/jsonl.js +52 -0
- package/dist/report/jsonl.js.map +1 -0
- package/dist/report/model.d.ts +68 -0
- package/dist/report/model.js +127 -0
- package/dist/report/model.js.map +1 -0
- package/dist/report/render.d.ts +18 -0
- package/dist/report/render.js +127 -0
- package/dist/report/render.js.map +1 -0
- package/dist/schema-docs/render.d.ts +49 -0
- package/dist/schema-docs/render.js +359 -0
- package/dist/schema-docs/render.js.map +1 -0
- package/dist/schemas.d.ts +7 -2
- package/dist/schemas.js +7 -2
- package/dist/schemas.js.map +1 -1
- package/dist/sources/ddl.d.ts +48 -0
- package/dist/sources/ddl.js +53 -0
- package/dist/sources/ddl.js.map +1 -0
- package/dist/sources/index.d.ts +69 -0
- package/dist/sources/index.js +170 -0
- package/dist/sources/index.js.map +1 -0
- package/dist/steps/backfill.d.ts +40 -5
- package/dist/steps/backfill.js +128 -8
- package/dist/steps/backfill.js.map +1 -1
- package/dist/steps/index.d.ts +19 -1
- package/dist/steps/index.js +34 -7
- package/dist/steps/index.js.map +1 -1
- package/dist/steps/kinds.d.ts +42 -4
- package/dist/steps/kinds.js +88 -14
- package/dist/steps/kinds.js.map +1 -1
- package/dist/steps/postgres-migration.d.ts +38 -25
- package/dist/steps/postgres-migration.js +49 -32
- package/dist/steps/postgres-migration.js.map +1 -1
- package/dist/steps/rebuild.d.ts +15 -6
- package/dist/steps/rebuild.js +12 -9
- package/dist/steps/rebuild.js.map +1 -1
- package/dist/tenants/index.d.ts +41 -0
- package/dist/tenants/index.js +121 -0
- package/dist/tenants/index.js.map +1 -0
- package/dist/tenants/target.d.ts +23 -0
- package/dist/tenants/target.js +29 -0
- package/dist/tenants/target.js.map +1 -0
- package/dist/tenants/wave.d.ts +128 -0
- package/dist/tenants/wave.js +254 -0
- package/dist/tenants/wave.js.map +1 -0
- package/dist/testing/define.d.ts +62 -0
- package/dist/testing/define.js +32 -0
- package/dist/testing/define.js.map +1 -0
- package/dist/testing/files.d.ts +5 -0
- package/dist/testing/files.js +18 -0
- package/dist/testing/files.js.map +1 -0
- package/dist/testing/report.d.ts +14 -0
- package/dist/testing/report.js +83 -0
- package/dist/testing/report.js.map +1 -0
- package/dist/testing/run.d.ts +104 -0
- package/dist/testing/run.js +328 -0
- package/dist/testing/run.js.map +1 -0
- package/dist/versioned/approval.d.ts +6 -0
- package/dist/versioned/approval.js +11 -5
- package/dist/versioned/approval.js.map +1 -1
- package/dist/versioned/checks.d.ts +8 -2
- package/dist/versioned/checks.js +34 -13
- package/dist/versioned/checks.js.map +1 -1
- package/dist/versioned/driver.d.ts +2 -2
- package/dist/versioned/engine.d.ts +16 -0
- package/dist/versioned/engine.js +20 -6
- package/dist/versioned/engine.js.map +1 -1
- package/dist/versioned/explain.d.ts +2 -0
- package/dist/versioned/explain.js +3 -1
- package/dist/versioned/explain.js.map +1 -1
- package/dist/versioned/index.d.ts +1 -0
- package/dist/versioned/index.js +1 -0
- package/dist/versioned/index.js.map +1 -1
- package/dist/versioned/op.d.ts +6 -1
- package/dist/versioned/op.js +7 -2
- package/dist/versioned/op.js.map +1 -1
- package/dist/versioned/policy.d.ts +33 -2
- package/dist/versioned/policy.js +59 -8
- package/dist/versioned/policy.js.map +1 -1
- package/dist/versioned/report.js +9 -0
- package/dist/versioned/report.js.map +1 -1
- package/dist/versioned/revert.d.ts +128 -0
- package/dist/versioned/revert.js +251 -0
- package/dist/versioned/revert.js.map +1 -0
- package/dist/versioned/state.d.ts +25 -0
- package/dist/versioned/state.js +37 -4
- package/dist/versioned/state.js.map +1 -1
- package/dist/waves/index.d.ts +224 -0
- package/dist/waves/index.js +353 -0
- package/dist/waves/index.js.map +1 -0
- package/dist/waves/promotion.d.ts +56 -0
- package/dist/waves/promotion.js +108 -0
- package/dist/waves/promotion.js.map +1 -0
- package/dist/waves/record.d.ts +34 -0
- package/dist/waves/record.js +20 -0
- package/dist/waves/record.js.map +1 -0
- package/package.json +11 -7
- package/schemas/apply.schema.json +162 -3
- package/schemas/checkpoint.schema.json +19 -0
- package/schemas/cleanup.schema.json +40 -0
- package/schemas/drift.schema.json +26 -1
- package/schemas/event.schema.json +36 -0
- package/schemas/lint-rules.schema.json +4 -0
- package/schemas/lint.schema.json +4 -0
- package/schemas/new.schema.json +41 -3
- package/schemas/plan.schema.json +157 -0
- package/schemas/report.schema.json +114 -0
- package/schemas/revert.schema.json +69 -0
- package/schemas/status.schema.json +64 -3
- package/schemas/test.schema.json +41 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join, resolve } from "node:path";
|
|
3
|
+
import { guarded } from "../env-args.js";
|
|
4
|
+
import { loadProject, YodelError } from "../project.js";
|
|
5
|
+
const usage = "usage: yodel ci [--check] [--dir <project>]\n yodel ci --replay [--dir <project>] [-- <yodel lint options>]";
|
|
6
|
+
const help = `${usage}
|
|
7
|
+
|
|
8
|
+
Renders the project's CI pipelines for GitHub Actions, GitLab CI and
|
|
9
|
+
Forgejo Actions from chant.config.ts (the environments, in profile order),
|
|
10
|
+
yodel.config.ts (waves, ci) and ops/ (each environment's migrate and watch
|
|
11
|
+
Ops), each declared with chant's lexicons:
|
|
12
|
+
|
|
13
|
+
yodel-pr on a pull request: yodel ci --check, yodel lint, the replay
|
|
14
|
+
check into a throwaway server, and the plan comment per
|
|
15
|
+
environment
|
|
16
|
+
yodel-apply on a push to main: one job per wave (yodel-waves.json)
|
|
17
|
+
yodel-apply-plans
|
|
18
|
+
on a pull request, when a wave's approval is pr-review:
|
|
19
|
+
chant run wave --record-plans records the plan each wave
|
|
20
|
+
makes at the head, for the review to approve (on GitLab, the
|
|
21
|
+
merge request job yodel-apply-record-plans)
|
|
22
|
+
watch-<env> each environment's drift watch, on its schedule
|
|
23
|
+
|
|
24
|
+
The pipelines come from the installed yodel, so upgrading yodel and running
|
|
25
|
+
yodel ci again brings its fixes to the project; yodel ci --check then fails
|
|
26
|
+
until the new files are committed.
|
|
27
|
+
|
|
28
|
+
yodel.config.ts ci:
|
|
29
|
+
forges the forges to render for (default github, gitlab and forgejo)
|
|
30
|
+
jobs a module (such as "ci/jobs.ts") exporting the project's own jobs,
|
|
31
|
+
declared with chant: actions (github lexicon Jobs, for GitHub and
|
|
32
|
+
Forgejo) and gitlab (gitlab lexicon Jobs). They are added to the
|
|
33
|
+
pull request pipeline after yodel's jobs, on every render.
|
|
34
|
+
image the CI image every job runs in, pinned by its digest
|
|
35
|
+
resume { schedule: "<cron>" }: a scheduled yodel-apply-resume job that
|
|
36
|
+
starts again an apply wave whose approval has arrived (chant run
|
|
37
|
+
resume); it approves nothing. GitHub uses the job's token
|
|
38
|
+
(actions: write), Forgejo the CHANT_FORGE_TOKEN secret
|
|
39
|
+
(write:repository), GitLab a pipeline schedule you create, with
|
|
40
|
+
GITLAB_TOKEN (api scope, Developer)
|
|
41
|
+
|
|
42
|
+
Options:
|
|
43
|
+
--check write nothing; exit 1 naming each file that differs from
|
|
44
|
+
what yodel ci renders
|
|
45
|
+
--replay the lint job's replay check on this machine: a throwaway
|
|
46
|
+
server started with Docker from the job's image, the
|
|
47
|
+
replay profile pointed at it, yodel lint --replay replay
|
|
48
|
+
--reset, and the server removed. Options after -- go to
|
|
49
|
+
yodel lint. The exit code is yodel lint's
|
|
50
|
+
-C, --dir <dir> the project directory (default: the working directory)
|
|
51
|
+
|
|
52
|
+
Exit codes:
|
|
53
|
+
0 written, or (--check) every file is up to date
|
|
54
|
+
1 (--check) a file is stale or missing; anything else failed
|
|
55
|
+
`;
|
|
56
|
+
function parseCiArgs(args) {
|
|
57
|
+
const out = { dir: process.cwd(), check: false, replay: false, rest: [] };
|
|
58
|
+
for (let i = 0; i < args.length; i++) {
|
|
59
|
+
const a = args[i];
|
|
60
|
+
if (a === "--") {
|
|
61
|
+
out.rest = args.slice(i + 1);
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
if (a === "--check")
|
|
65
|
+
out.check = true;
|
|
66
|
+
else if (a === "--replay")
|
|
67
|
+
out.replay = true;
|
|
68
|
+
else if (a === "--dir" || a === "-C") {
|
|
69
|
+
const v = args[++i];
|
|
70
|
+
if (v === undefined)
|
|
71
|
+
throw new YodelError(`${a} needs a directory\n${usage}`);
|
|
72
|
+
out.dir = v;
|
|
73
|
+
}
|
|
74
|
+
else if (a?.startsWith("--dir="))
|
|
75
|
+
out.dir = a.slice("--dir=".length);
|
|
76
|
+
else
|
|
77
|
+
throw new YodelError(`unknown argument ${String(a)}\n${usage}`);
|
|
78
|
+
}
|
|
79
|
+
if (out.check && out.replay)
|
|
80
|
+
throw new YodelError(`--check and --replay are two things; give one\n${usage}`);
|
|
81
|
+
if (out.rest.length > 0 && !out.replay)
|
|
82
|
+
throw new YodelError(`options after -- are for --replay\n${usage}`);
|
|
83
|
+
return out;
|
|
84
|
+
}
|
|
85
|
+
/** `yodel ci`; the exit codes are in `help`. */
|
|
86
|
+
export const ci = {
|
|
87
|
+
name: "ci",
|
|
88
|
+
summary: "render the project's CI pipelines (GitHub, GitLab, Forgejo)",
|
|
89
|
+
implemented: true,
|
|
90
|
+
run: (args, io) => guarded("ci", io, args, help, async () => {
|
|
91
|
+
const a = parseCiArgs(args);
|
|
92
|
+
// The project, as every command reads it: chant.config.ts and a checked yodel.config.ts.
|
|
93
|
+
const dir = (await loadProject(resolve(a.dir))).dir;
|
|
94
|
+
if (a.replay) {
|
|
95
|
+
const { replayLocally } = await import("../ci/replay.js");
|
|
96
|
+
return replayLocally(dir, a.rest);
|
|
97
|
+
}
|
|
98
|
+
// Loaded here: the forge lexicons are for this command alone.
|
|
99
|
+
const { render } = await import("../ci/render.js");
|
|
100
|
+
let files;
|
|
101
|
+
try {
|
|
102
|
+
files = await render(dir);
|
|
103
|
+
}
|
|
104
|
+
catch (e) {
|
|
105
|
+
throw new YodelError(e instanceof Error ? e.message : String(e));
|
|
106
|
+
}
|
|
107
|
+
const stale = [];
|
|
108
|
+
for (const file of files) {
|
|
109
|
+
const abs = join(dir, file.path);
|
|
110
|
+
const current = existsSync(abs) ? readFileSync(abs, "utf8") : undefined;
|
|
111
|
+
if (current === file.content)
|
|
112
|
+
continue;
|
|
113
|
+
if (a.check) {
|
|
114
|
+
stale.push(file.path);
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
mkdirSync(dirname(abs), { recursive: true });
|
|
118
|
+
writeFileSync(abs, file.content);
|
|
119
|
+
io.out(`wrote ${file.path}\n`);
|
|
120
|
+
}
|
|
121
|
+
if (a.check && stale.length > 0) {
|
|
122
|
+
io.err(`stale, run yodel ci: ${stale.join(", ")}\n`);
|
|
123
|
+
return 1;
|
|
124
|
+
}
|
|
125
|
+
if (a.check)
|
|
126
|
+
io.out(`${String(files.length)} CI files are up to date\n`);
|
|
127
|
+
return 0;
|
|
128
|
+
}),
|
|
129
|
+
};
|
|
130
|
+
//# sourceMappingURL=ci.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ci.js","sourceRoot":"","sources":["../../src/commands/ci.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Command } from "../command.js";
|
|
2
|
+
import { type Retained } from "../cleanup/index.js";
|
|
3
|
+
/** `yodel cleanup --json` (schemas/cleanup.schema.json). */
|
|
4
|
+
export declare function cleanupJson(r: {
|
|
5
|
+
environment: string;
|
|
6
|
+
now: string;
|
|
7
|
+
retained: readonly Retained[];
|
|
8
|
+
planDigest?: string | undefined;
|
|
9
|
+
approve?: string | undefined;
|
|
10
|
+
dropped: readonly string[];
|
|
11
|
+
}): Record<string, unknown>;
|
|
12
|
+
/** `yodel cleanup <env>`; the exit codes are in `help`. */
|
|
13
|
+
export declare const cleanup: Command;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { parseArgs } from "node:util";
|
|
2
|
+
import { guarded } from "../env-args.js";
|
|
3
|
+
import { loadProject, resolveEnvironment, YodelError } from "../project.js";
|
|
4
|
+
import { appliedBy, withLock } from "../history/index.js";
|
|
5
|
+
import { closeVersioned, findMigrateOp, gitLedger, NOT_APPROVED, openVersioned, verifyApproval } from "../versioned/index.js";
|
|
6
|
+
import { cleanupDigest, describeRetained, dropRetained, findRetained, retainedServer } from "../cleanup/index.js";
|
|
7
|
+
const usage = "usage: yodel cleanup <env> [--list] [--op <name>] [--json] [--dir <project>]";
|
|
8
|
+
const help = `${usage}
|
|
9
|
+
|
|
10
|
+
Lists what steps kept in <env> on purpose, and drops what is past its
|
|
11
|
+
retention date, behind the environment's approval:
|
|
12
|
+
|
|
13
|
+
- a ClickHouse rebuild's old table, <table>__chant_old, kept after the swap
|
|
14
|
+
(7 days, or the step's retain);
|
|
15
|
+
- a Postgres rename's or type change's old column, kept after the switch
|
|
16
|
+
when the step set retain (yodel new --retain), with the trigger and
|
|
17
|
+
function that keep a renamed column written.
|
|
18
|
+
|
|
19
|
+
Each one's date is in its own comment, and the server's clock decides
|
|
20
|
+
whether it has passed. Nothing is dropped before its date.
|
|
21
|
+
|
|
22
|
+
When something is due, the drop is a plan like an apply's: its digest
|
|
23
|
+
covers each due object (a table by its UUID, a column by its table and
|
|
24
|
+
attribute number) and its date. Without an approval of the environment's
|
|
25
|
+
migrations Op gate for that digest, yodel cleanup lists what it would drop,
|
|
26
|
+
prints the digest and the chant approve command, and drops nothing (exit
|
|
27
|
+
3). Approve it, run yodel cleanup <env> again, and it drops them under the
|
|
28
|
+
apply lock, after reading them again: if anything due changed, the digest
|
|
29
|
+
differs and the approval does not count.
|
|
30
|
+
|
|
31
|
+
Options:
|
|
32
|
+
--list list only; never drop, even with an approval
|
|
33
|
+
--op <name> the migrations Op, when more than one applies <env>
|
|
34
|
+
--json print the list (and what was dropped) as JSON
|
|
35
|
+
-C, --dir <dir> the project directory (default: the working directory)
|
|
36
|
+
|
|
37
|
+
Exit codes:
|
|
38
|
+
0 nothing is due (and nothing was dropped), the due objects were dropped,
|
|
39
|
+
or --list
|
|
40
|
+
3 something is due and waits for an approval; nothing was dropped
|
|
41
|
+
5 another apply holds the lock
|
|
42
|
+
1 an error: a bad config, an unknown environment, a server it cannot read
|
|
43
|
+
`;
|
|
44
|
+
function parseCleanupArgs(args) {
|
|
45
|
+
let parsed;
|
|
46
|
+
try {
|
|
47
|
+
parsed = parseArgs({ args, allowPositionals: true, strict: true, options: { list: { type: "boolean" }, op: { type: "string" }, json: { type: "boolean" }, dir: { type: "string", short: "C" } } });
|
|
48
|
+
}
|
|
49
|
+
catch (e) {
|
|
50
|
+
throw new YodelError(`${e instanceof Error ? e.message : String(e)}\n${usage}`);
|
|
51
|
+
}
|
|
52
|
+
const [env, ...rest] = parsed.positionals;
|
|
53
|
+
if (env === undefined || rest.length > 0)
|
|
54
|
+
throw new YodelError(usage);
|
|
55
|
+
const v = parsed.values;
|
|
56
|
+
return { env, list: v.list === true, op: typeof v.op === "string" ? v.op : undefined, json: v.json === true, dir: typeof v.dir === "string" ? v.dir : process.cwd() };
|
|
57
|
+
}
|
|
58
|
+
/** `yodel cleanup --json` (schemas/cleanup.schema.json). */
|
|
59
|
+
export function cleanupJson(r) {
|
|
60
|
+
return {
|
|
61
|
+
environment: r.environment,
|
|
62
|
+
now: r.now,
|
|
63
|
+
retained: r.retained.map((x) => ({ kind: x.kind, name: x.name, of: x.of, ...(x.retainUntil ? { retainUntil: x.retainUntil } : {}), due: x.due, identity: x.identity, ...(x.trigger ? { trigger: x.trigger } : {}) })),
|
|
64
|
+
due: r.retained.filter((x) => x.due).length,
|
|
65
|
+
...(r.planDigest ? { planDigest: r.planDigest } : {}),
|
|
66
|
+
...(r.approve ? { approve: r.approve } : {}),
|
|
67
|
+
dropped: r.dropped,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/** `yodel cleanup <env>`; the exit codes are in `help`. */
|
|
71
|
+
export const cleanup = {
|
|
72
|
+
name: "cleanup",
|
|
73
|
+
summary: "drop the old tables and columns steps kept, once past their date",
|
|
74
|
+
implemented: true,
|
|
75
|
+
run: (args, io) => guarded("cleanup", io, args, help, async () => {
|
|
76
|
+
const a = parseCleanupArgs(args);
|
|
77
|
+
const project = await loadProject(a.dir);
|
|
78
|
+
const env = resolveEnvironment(project, a.env);
|
|
79
|
+
const venv = await openVersioned(project, env);
|
|
80
|
+
try {
|
|
81
|
+
return await cleanupWith(project, env, venv, a, io);
|
|
82
|
+
}
|
|
83
|
+
finally {
|
|
84
|
+
await closeVersioned(venv);
|
|
85
|
+
}
|
|
86
|
+
}),
|
|
87
|
+
};
|
|
88
|
+
async function cleanupWith(project, env, venv, a, io) {
|
|
89
|
+
const server = retainedServer(venv);
|
|
90
|
+
const { now, retained } = await findRetained(server);
|
|
91
|
+
const dueCount = retained.filter((r) => r.due).length;
|
|
92
|
+
const lines = [`Kept by steps in ${env.name} (server time ${now}):`];
|
|
93
|
+
if (retained.length === 0)
|
|
94
|
+
lines[0] = `Nothing kept by steps in ${env.name}: no old table or old column waits for its retention date.`;
|
|
95
|
+
for (const r of retained)
|
|
96
|
+
lines.push(` ${describeRetained(r)}`);
|
|
97
|
+
const report = (extra, tail = []) => {
|
|
98
|
+
if (a.json)
|
|
99
|
+
io.out(`${JSON.stringify(cleanupJson({ environment: env.name, now, retained, dropped: [], ...extra }), null, 2)}\n`);
|
|
100
|
+
else
|
|
101
|
+
io.out(`${[...lines, ...tail].join("\n")}\n`);
|
|
102
|
+
};
|
|
103
|
+
if (dueCount === 0 || a.list) {
|
|
104
|
+
report({}, retained.length > 0 && dueCount === 0 ? ["", "Nothing is due: nothing dropped."] : []);
|
|
105
|
+
return 0;
|
|
106
|
+
}
|
|
107
|
+
const digest = await cleanupDigest(env.name, retained);
|
|
108
|
+
const op = await findMigrateOp(project, env, a.op);
|
|
109
|
+
const ledger = await gitLedger(project.dir);
|
|
110
|
+
const approve = `chant approve ${op.name} ${op.gate} --plan ${digest}`;
|
|
111
|
+
try {
|
|
112
|
+
await verifyApproval(ledger, op, digest);
|
|
113
|
+
}
|
|
114
|
+
catch (e) {
|
|
115
|
+
if (!(e instanceof YodelError) || e.exitCode !== NOT_APPROVED)
|
|
116
|
+
throw e;
|
|
117
|
+
report({ planDigest: digest, approve }, ["", `Plan digest: ${digest}`, `${String(dueCount)} due; nothing dropped without an approval. Approve it with:`, ` ${approve}`, `then run yodel cleanup ${env.name} again.`]);
|
|
118
|
+
return NOT_APPROVED;
|
|
119
|
+
}
|
|
120
|
+
const lock = await venv.driver.acquireLock(appliedBy());
|
|
121
|
+
if (lock.notice && !a.json)
|
|
122
|
+
io.err(`lock: ${lock.notice}\n`);
|
|
123
|
+
const dropped = await withLock(lock, venv.lockTtlMs, async () => {
|
|
124
|
+
// Read again under the lock: the approval counts only for what is due now.
|
|
125
|
+
const again = await findRetained(server);
|
|
126
|
+
const now = await cleanupDigest(env.name, again.retained);
|
|
127
|
+
const by = await verifyApproval(ledger, op, now);
|
|
128
|
+
if (!a.json)
|
|
129
|
+
io.err(`approval: ${op.name} / ${op.gate} for ${now}, by ${by.resolvedBy} at ${by.timestamp}\n`);
|
|
130
|
+
return dropRetained(server, again.retained, (l) => {
|
|
131
|
+
if (!a.json)
|
|
132
|
+
io.err(`${l}\n`);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
report({ planDigest: digest, dropped }, ["", `Dropped ${String(dropped.length)}: ${dropped.join(", ")}`]);
|
|
136
|
+
return 0;
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=cleanup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cleanup.js","sourceRoot":"","sources":["../../src/commands/cleanup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { parseArgs } from "node:util";
|
|
2
|
+
import { environmentSettings } from "../config/settings.js";
|
|
3
|
+
import { CONFIG_FILE } from "../config/load.js";
|
|
4
|
+
import { credentialsOf, describePassword, roleOf, ROLES } from "../credentials.js";
|
|
5
|
+
import { guarded } from "../env-args.js";
|
|
6
|
+
import { EXIT_REFUSED } from "../exit.js";
|
|
7
|
+
import { writeProbe } from "../probe.js";
|
|
8
|
+
import { loadProject, resolveEnvironment, YodelError } from "../project.js";
|
|
9
|
+
import { serverAddress } from "../server.js";
|
|
10
|
+
const USAGE = "usage: yodel config check [<env>...] [--write-probe] [--dir <project>]";
|
|
11
|
+
const help = `${USAGE}
|
|
12
|
+
|
|
13
|
+
Prints each environment's settings and where each came from: the server,
|
|
14
|
+
the role this process connects as (YODEL_CREDENTIALS), the reader's and the
|
|
15
|
+
writer's user and password (the variable each is read from and whether it
|
|
16
|
+
is set here, or the token source that mints it), the history's database,
|
|
17
|
+
the topology, and the lock's TTL and wait. Every environment, or the ones
|
|
18
|
+
named. Never prints a password.
|
|
19
|
+
|
|
20
|
+
A profile made with credentials() in chant.config.ts carries a reader and a
|
|
21
|
+
writer. Every yodel command refuses the project, exit 4, when an
|
|
22
|
+
environment's reader and writer read their user or password from the same
|
|
23
|
+
variable, or their users are the same name.
|
|
24
|
+
|
|
25
|
+
Options:
|
|
26
|
+
--write-probe try a write in each environment with the credentials this
|
|
27
|
+
process holds, and exit 4 when the server lets one
|
|
28
|
+
through: run in a pull request job, it shows the job
|
|
29
|
+
holds no writer. The write is rolled back (Postgres) or
|
|
30
|
+
dropped at once (ClickHouse).
|
|
31
|
+
-C, --dir <dir> the project directory (default: the working directory)
|
|
32
|
+
|
|
33
|
+
Exit codes:
|
|
34
|
+
0 printed; with --write-probe, no environment let the write through
|
|
35
|
+
4 refused: an environment's reader and writer are one identity, or with
|
|
36
|
+
--write-probe, a write went through
|
|
37
|
+
1 an error: a bad config, an unknown environment, a server that does not
|
|
38
|
+
answer, or a probe that could not tell
|
|
39
|
+
`;
|
|
40
|
+
const isEnvRef = (v) => typeof v === "object" && v !== null && typeof v.env === "string";
|
|
41
|
+
function roleView(c, role, env) {
|
|
42
|
+
const r = c[role];
|
|
43
|
+
const value = env[r.user.env];
|
|
44
|
+
const set = value !== undefined && value !== "";
|
|
45
|
+
return {
|
|
46
|
+
user: { variable: r.user.env, set, ...(set ? { value } : {}) },
|
|
47
|
+
password: isEnvRef(r.password) ? { source: r.password.env, set: (env[r.password.env] ?? "") !== "" } : { source: describePassword(r.password) },
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function view(project, name, env) {
|
|
51
|
+
const e = resolveEnvironment(project, name);
|
|
52
|
+
const profile = e.profile;
|
|
53
|
+
const c = credentialsOf(profile);
|
|
54
|
+
const settings = environmentSettings(project, name, env);
|
|
55
|
+
const own = project.yodel?.config.environments?.[name];
|
|
56
|
+
const historySource = own?.history?.database !== undefined ? CONFIG_FILE : env.YODEL_HISTORY_DATABASE ? "YODEL_HISTORY_DATABASE" : "default";
|
|
57
|
+
const ys = env.YODEL_CREDENTIALS;
|
|
58
|
+
const user = profile.user;
|
|
59
|
+
const password = profile.password;
|
|
60
|
+
return {
|
|
61
|
+
environment: name,
|
|
62
|
+
server: serverAddress(project.dialect, String(profile.url)),
|
|
63
|
+
role: roleOf(name, ys),
|
|
64
|
+
roleSource: ys ? `YODEL_CREDENTIALS=${ys}` : "YODEL_CREDENTIALS unset",
|
|
65
|
+
credentials: c
|
|
66
|
+
? { split: true, reader: roleView(c, "reader", env), writer: roleView(c, "writer", env) }
|
|
67
|
+
: { split: false, ...(isEnvRef(user) ? { user: user.env } : {}), ...(password ? { password: describePassword(password) } : {}) },
|
|
68
|
+
history: { database: settings.historyDatabase, source: historySource },
|
|
69
|
+
...(project.dialect === "clickhouse" ? { topology: { value: describeTopology(settings.topology), source: settings.topologySource } } : {}),
|
|
70
|
+
lockTtlSeconds: settings.lockTtlMs / 1000,
|
|
71
|
+
lockWaitSeconds: settings.lockWaitMs / 1000,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
const describeTopology = (t) => (t.cluster ? `${t.kind}:${t.cluster}` : t.kind);
|
|
75
|
+
function render(v) {
|
|
76
|
+
const lines = [`${v.environment} (${v.server})`, ` connects as ${v.role} (${v.roleSource})`];
|
|
77
|
+
const c = v.credentials;
|
|
78
|
+
if (c.split) {
|
|
79
|
+
for (const role of ROLES) {
|
|
80
|
+
const r = c[role];
|
|
81
|
+
const user = `${r.user.variable} (${r.user.set ? `set: ${r.user.value ?? ""}` : "not set here"})`;
|
|
82
|
+
const password = r.password.set === undefined ? r.password.source : `${r.password.source} (${r.password.set ? "set" : "not set here"})`;
|
|
83
|
+
lines.push(` ${role.padEnd(13)} user ${user}, password ${password}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
lines.push(` credentials user ${c.user ?? "none"}, password ${c.password ?? "none"}: one set for every job; credentials() in chant.config.ts gives a reader and a writer`);
|
|
88
|
+
}
|
|
89
|
+
lines.push(` history ${v.history.database} (${v.history.source})`);
|
|
90
|
+
if (v.topology)
|
|
91
|
+
lines.push(` topology ${v.topology.value} (${v.topology.source})`);
|
|
92
|
+
lines.push(` lock ttl ${String(v.lockTtlSeconds)}s, wait ${String(v.lockWaitSeconds)}s`);
|
|
93
|
+
if (v.probe)
|
|
94
|
+
lines.push(` write probe ${v.probe.wrote ? "WROTE" : "cannot write"}: ${v.probe.detail}`);
|
|
95
|
+
return `${lines.join("\n")}\n`;
|
|
96
|
+
}
|
|
97
|
+
async function check(args, io) {
|
|
98
|
+
let parsed;
|
|
99
|
+
try {
|
|
100
|
+
parsed = parseArgs({ args, allowPositionals: true, strict: true, options: { "write-probe": { type: "boolean" }, dir: { type: "string", short: "C" } } });
|
|
101
|
+
}
|
|
102
|
+
catch (e) {
|
|
103
|
+
throw new YodelError(`${e instanceof Error ? e.message : String(e)}\n${USAGE}`);
|
|
104
|
+
}
|
|
105
|
+
const { values, positionals } = parsed;
|
|
106
|
+
const project = await loadProject(typeof values.dir === "string" ? values.dir : process.cwd());
|
|
107
|
+
const names = positionals.length > 0 ? positionals : Object.keys(project.config.sql?.profiles ?? {});
|
|
108
|
+
const views = [];
|
|
109
|
+
for (const name of names) {
|
|
110
|
+
const v = view(project, name, process.env);
|
|
111
|
+
if (values["write-probe"] === true)
|
|
112
|
+
v.probe = await writeProbe(project, resolveEnvironment(project, name));
|
|
113
|
+
views.push(v);
|
|
114
|
+
}
|
|
115
|
+
io.out(views.map(render).join("\n"));
|
|
116
|
+
const wrote = views.filter((v) => v.probe?.wrote);
|
|
117
|
+
if (wrote.length === 0)
|
|
118
|
+
return 0;
|
|
119
|
+
for (const v of wrote) {
|
|
120
|
+
io.err(`yodel config: refused: ${v.environment}: the credentials this process holds can write (${v.probe?.detail ?? ""}). A pull request job must hold the reader only: check which secrets it maps, and the reader's grants.\n`);
|
|
121
|
+
}
|
|
122
|
+
return EXIT_REFUSED;
|
|
123
|
+
}
|
|
124
|
+
/** `yodel config check`; the exit codes are in `help`. */
|
|
125
|
+
export const config = {
|
|
126
|
+
name: "config",
|
|
127
|
+
summary: "print each environment's settings, and prove a job cannot write",
|
|
128
|
+
implemented: true,
|
|
129
|
+
run: (args, io) => guarded("config", io, args, help, async () => {
|
|
130
|
+
const [sub, ...rest] = args;
|
|
131
|
+
if (sub !== "check")
|
|
132
|
+
throw new YodelError(USAGE);
|
|
133
|
+
return check(rest, io);
|
|
134
|
+
}),
|
|
135
|
+
};
|
|
136
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Command } from "../command.js";
|
|
2
|
+
import { type Project } from "../project.js";
|
|
3
|
+
import { type DocsInput } from "../schema-docs/render.js";
|
|
4
|
+
/** Where `yodel docs` writes, relative to the project, without --out. */
|
|
5
|
+
export declare const DOCS_DIR = "schema-docs";
|
|
6
|
+
export declare const DOCS_HTML = "index.html";
|
|
7
|
+
export declare const DOCS_ERD = "erd.md";
|
|
8
|
+
/** What `yodel docs` documents for the project: the build, or a migration's recorded schema. */
|
|
9
|
+
export declare function docsInput(project: Project, migration?: string): Promise<DocsInput>;
|
|
10
|
+
/** `yodel docs`; the exit codes are in `help`. */
|
|
11
|
+
export declare const docs: Command;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { basename, join, relative, resolve } from "node:path";
|
|
3
|
+
import { parseArgs } from "node:util";
|
|
4
|
+
import { guarded } from "../env-args.js";
|
|
5
|
+
import { loadProject, YodelError } from "../project.js";
|
|
6
|
+
import { buildSchema } from "../chant/build.js";
|
|
7
|
+
import { migrationsDir, readChain } from "../versioned/index.js";
|
|
8
|
+
import { erdMarkdown, schemaHtml } from "../schema-docs/render.js";
|
|
9
|
+
/** Where `yodel docs` writes, relative to the project, without --out. */
|
|
10
|
+
export const DOCS_DIR = "schema-docs";
|
|
11
|
+
export const DOCS_HTML = "index.html";
|
|
12
|
+
export const DOCS_ERD = "erd.md";
|
|
13
|
+
const usage = "usage: yodel docs [--out <dir>] [--migration <id>] [--dir <project>]";
|
|
14
|
+
const help = `${usage}
|
|
15
|
+
|
|
16
|
+
Writes a reference of the schema, offline: no server is read.
|
|
17
|
+
|
|
18
|
+
<out>/index.html every table, view, index and database or schema: its
|
|
19
|
+
columns, keys, relations, comments, ClickHouse engine,
|
|
20
|
+
sort key, partition key and TTL, its DDL, and the
|
|
21
|
+
migrations in migrations/ that changed it. One file
|
|
22
|
+
with its styles inline and no scripts.
|
|
23
|
+
<out>/erd.md a Mermaid entity-relationship diagram of the tables and
|
|
24
|
+
views, which GitHub, GitLab and Forgejo render: foreign
|
|
25
|
+
keys, what a view reads, the table a materialized view
|
|
26
|
+
writes to, the table a Distributed table serves.
|
|
27
|
+
|
|
28
|
+
The schema is the build of the declared schema (chant build), or with
|
|
29
|
+
--migration <id> the schema that migration recorded. The same schema gives
|
|
30
|
+
the same files, so they can be committed and reviewed in a pull request.
|
|
31
|
+
|
|
32
|
+
Options:
|
|
33
|
+
--out <dir> where to write (default: ${DOCS_DIR} in the project)
|
|
34
|
+
--migration <id> document the schema migration <id> recorded, and its
|
|
35
|
+
history up to it
|
|
36
|
+
-C, --dir <dir> the project directory (default: the working directory)
|
|
37
|
+
|
|
38
|
+
Exit codes:
|
|
39
|
+
0 written
|
|
40
|
+
1 nothing written: a bad config, a declaration chant cannot build, an
|
|
41
|
+
unknown migration id
|
|
42
|
+
4 refused: the migrations directory is not one chain (a fork, a missing
|
|
43
|
+
parent)
|
|
44
|
+
`;
|
|
45
|
+
function parseDocsArgs(args) {
|
|
46
|
+
let parsed;
|
|
47
|
+
try {
|
|
48
|
+
parsed = parseArgs({ args, strict: true, options: { out: { type: "string" }, migration: { type: "string" }, dir: { type: "string", short: "C" } } });
|
|
49
|
+
}
|
|
50
|
+
catch (e) {
|
|
51
|
+
throw new YodelError(`${e instanceof Error ? e.message : String(e)}\n${usage}`);
|
|
52
|
+
}
|
|
53
|
+
const s = (v) => (typeof v === "string" ? v : undefined);
|
|
54
|
+
return { out: s(parsed.values.out), migration: s(parsed.values.migration), dir: s(parsed.values.dir) ?? process.cwd() };
|
|
55
|
+
}
|
|
56
|
+
/** The project's name for the title: package.json's name, else the directory's. */
|
|
57
|
+
function projectTitle(project) {
|
|
58
|
+
try {
|
|
59
|
+
const pkg = JSON.parse(readFileSync(join(project.dir, "package.json"), "utf8"));
|
|
60
|
+
if (typeof pkg.name === "string" && pkg.name && !pkg.name.includes("{{"))
|
|
61
|
+
return pkg.name;
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// no package.json: the directory's name
|
|
65
|
+
}
|
|
66
|
+
return basename(project.dir);
|
|
67
|
+
}
|
|
68
|
+
/** What `yodel docs` documents for the project: the build, or a migration's recorded schema. */
|
|
69
|
+
export async function docsInput(project, migration) {
|
|
70
|
+
const chain = existsSync(migrationsDir(project)) ? readChain(project) : [];
|
|
71
|
+
const steps = chain.map((m) => ({ id: m.id, steps: m.document.steps }));
|
|
72
|
+
const title = projectTitle(project);
|
|
73
|
+
if (migration !== undefined) {
|
|
74
|
+
const at = chain.findIndex((m) => m.id === migration);
|
|
75
|
+
const found = chain[at];
|
|
76
|
+
if (!found)
|
|
77
|
+
throw new YodelError(`no migration ${migration} in ${relative(process.cwd(), migrationsDir(project)) || migrationsDir(project)}`);
|
|
78
|
+
return { title, output: found.document.schema, source: `the schema migration ${migration} recorded`, migrations: steps.slice(0, at + 1) };
|
|
79
|
+
}
|
|
80
|
+
const build = await buildSchema(project);
|
|
81
|
+
try {
|
|
82
|
+
return { title, output: build.output, source: "chant build of the declared schema", migrations: steps };
|
|
83
|
+
}
|
|
84
|
+
finally {
|
|
85
|
+
build.dispose();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/** `yodel docs`; the exit codes are in `help`. */
|
|
89
|
+
export const docs = {
|
|
90
|
+
name: "docs",
|
|
91
|
+
summary: "write an HTML reference and a Mermaid ERD of the schema",
|
|
92
|
+
implemented: true,
|
|
93
|
+
run: (args, io) => guarded("docs", io, args, help, async () => {
|
|
94
|
+
const { out, migration, dir } = parseDocsArgs(args);
|
|
95
|
+
const project = await loadProject(dir);
|
|
96
|
+
const input = await docsInput(project, migration);
|
|
97
|
+
const outDir = resolve(out ?? join(project.dir, DOCS_DIR));
|
|
98
|
+
mkdirSync(outDir, { recursive: true });
|
|
99
|
+
writeFileSync(join(outDir, DOCS_HTML), schemaHtml(input));
|
|
100
|
+
writeFileSync(join(outDir, DOCS_ERD), erdMarkdown(input));
|
|
101
|
+
const rel = relative(project.dir, outDir);
|
|
102
|
+
const where = rel === "" ? "." : rel.startsWith("..") ? outDir : rel;
|
|
103
|
+
const count = input.output.objects.length;
|
|
104
|
+
io.out(`Wrote ${join(where, DOCS_HTML)} and ${join(where, DOCS_ERD)} (${String(count)} object${count === 1 ? "" : "s"}, from ${input.source})\n`);
|
|
105
|
+
return 0;
|
|
106
|
+
}),
|
|
107
|
+
};
|
|
108
|
+
//# sourceMappingURL=docs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docs.js","sourceRoot":"","sources":["../../src/commands/docs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,UAAU,EAAgB,MAAM,eAAe,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAkB,MAAM,0BAA0B,CAAC;AAEnF,yEAAyE;AACzE,MAAM,CAAC,MAAM,QAAQ,GAAG,aAAa,CAAC;AACtC,MAAM,CAAC,MAAM,SAAS,GAAG,YAAY,CAAC;AACtC,MAAM,CAAC,MAAM,QAAQ,GAAG,QAAQ,CAAC;AAEjC,MAAM,KAAK,GAAG,sEAAsE,CAAC;AAErF,MAAM,IAAI,GAAG,GAAG,KAAK;;;;;;;;;;;;;;;;;;;+CAmB0B,QAAQ;;;;;;;;;;;CAWtD,CAAC;AAQF,SAAS,aAAa,CAAC,IAAc;IACnC,IAAI,MAAoC,CAAC;IACzC,IAAI,CAAC;QACH,MAAM,GAAG,SAAS,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;IACvJ,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,IAAI,UAAU,CAAC,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC;IAClF,CAAC;IACD,MAAM,CAAC,GAAG,CAAC,CAAU,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAClE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC;AAC1H,CAAC;AAED,mFAAmF;AACnF,SAAS,YAAY,CAAC,OAAgB;IACpC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAuB,CAAC;QACtG,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,OAAO,GAAG,CAAC,IAAI,CAAC;IAC5F,CAAC;IAAC,MAAM,CAAC;QACP,wCAAwC;IAC1C,CAAC;IACD,OAAO,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;AAC/B,CAAC;AAED,gGAAgG;AAChG,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAgB,EAAE,SAAkB;IAClE,MAAM,KAAK,GAAG,UAAU,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3E,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACxE,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IACpC,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,MAAM,EAAE,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC;QACtD,MAAM,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC;QACxB,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,UAAU,CAAC,gBAAgB,SAAS,OAAO,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC,IAAI,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC9I,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,wBAAwB,SAAS,WAAW,EAAE,UAAU,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC;IAC5I,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,OAAO,CAAC,CAAC;IACzC,IAAI,CAAC;QACH,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,oCAAoC,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;IAC1G,CAAC;YAAS,CAAC;QACT,KAAK,CAAC,OAAO,EAAE,CAAC;IAClB,CAAC;AACH,CAAC;AAED,kDAAkD;AAClD,MAAM,CAAC,MAAM,IAAI,GAAY;IAC3B,IAAI,EAAE,MAAM;IACZ,OAAO,EAAE,yDAAyD;IAClE,WAAW,EAAE,IAAI;IACjB,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,CAChB,OAAO,CAAC,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,IAAI,EAAE;QACzC,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;QACpD,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;QACvC,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QAClD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;QAC3D,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACvC,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;QAC1D,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;QAC1D,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAC1C,MAAM,KAAK,GAAG,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC;QACrE,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;QAC1C,EAAE,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,KAAK,EAAE,SAAS,CAAC,QAAQ,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,KAAK,MAAM,CAAC,KAAK,CAAC,UAAU,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,UAAU,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC;QAClJ,OAAO,CAAC,CAAC;IACX,CAAC,CAAC;CACL,CAAC"}
|
package/dist/commands/drift.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { Command } from "../command.js";
|
|
2
|
+
import { type Drift } from "../chant/drift.js";
|
|
2
3
|
import { type BuildOutput } from "../chant/build.js";
|
|
3
|
-
import
|
|
4
|
+
import { type ServerInfo } from "../server.js";
|
|
5
|
+
import type { Environment, Project, SqlDialect } from "../project.js";
|
|
6
|
+
import { type IssueAction } from "../pr/issue.js";
|
|
4
7
|
/**
|
|
5
8
|
* The schema the environment's history says it has: the recorded schema
|
|
6
9
|
* of the newest migration, in chain order, that the history records as
|
|
@@ -10,5 +13,14 @@ export declare function recordedSchema(project: Project, env: Environment): Prom
|
|
|
10
13
|
migration: string;
|
|
11
14
|
schema: BuildOutput;
|
|
12
15
|
} | undefined>;
|
|
16
|
+
/** The document `yodel drift --json` prints (schemas/drift.schema.json): the drift, and what the run made of it. */
|
|
17
|
+
export declare function driftJson(result: Drift, parts: {
|
|
18
|
+
dialect: SqlDialect;
|
|
19
|
+
server?: ServerInfo | undefined;
|
|
20
|
+
drifted: boolean;
|
|
21
|
+
fingerprint: string;
|
|
22
|
+
issue?: IssueAction | undefined;
|
|
23
|
+
issueError?: string | undefined;
|
|
24
|
+
}): Record<string, unknown>;
|
|
13
25
|
/** `yodel drift <env>`; the exit codes are in `help`. */
|
|
14
26
|
export declare const drift: Command;
|