@intentius/sql-yodeler 0.3.0 → 0.5.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 +2 -2
- 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 +84 -0
- package/dist/chant/access.js +155 -0
- package/dist/chant/access.js.map +1 -0
- 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/login.d.ts +78 -0
- package/dist/ci/login.js +199 -0
- package/dist/ci/login.js.map +1 -0
- package/dist/ci/render.d.ts +64 -10
- package/dist/ci/render.js +385 -88
- package/dist/ci/render.js.map +1 -1
- package/dist/cleanup/index.d.ts +92 -0
- package/dist/cleanup/index.js +213 -0
- package/dist/cleanup/index.js.map +1 -0
- package/dist/commands/apply.js +178 -20
- package/dist/commands/apply.js.map +1 -1
- package/dist/commands/approve.d.ts +13 -0
- package/dist/commands/approve.js +206 -24
- package/dist/commands/approve.js.map +1 -1
- package/dist/commands/ci.js +12 -0
- package/dist/commands/ci.js.map +1 -1
- package/dist/commands/cleanup.d.ts +13 -0
- package/dist/commands/cleanup.js +158 -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/drift.js +33 -3
- package/dist/commands/drift.js.map +1 -1
- package/dist/commands/index.js +6 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/init.d.ts +11 -0
- package/dist/commands/init.js +98 -10
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/lint.js +67 -10
- package/dist/commands/lint.js.map +1 -1
- package/dist/commands/new.js +135 -54
- package/dist/commands/new.js.map +1 -1
- package/dist/commands/plan.js +39 -5
- package/dist/commands/plan.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/define.d.ts +175 -2
- package/dist/config/define.js +2 -0
- package/dist/config/define.js.map +1 -1
- package/dist/config/load.js +78 -10
- package/dist/config/load.js.map +1 -1
- package/dist/config/settings.d.ts +20 -0
- package/dist/config/settings.js +28 -0
- 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/index.d.ts +5 -1
- package/dist/index.js +2 -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/index.d.ts +2 -0
- package/dist/init/index.js +2 -0
- package/dist/init/index.js.map +1 -1
- 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/init/second.d.ts +70 -0
- package/dist/init/second.js +149 -0
- package/dist/init/second.js.map +1 -0
- 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/annotations.d.ts +49 -0
- package/dist/lint/annotations.js +82 -0
- package/dist/lint/annotations.js.map +1 -0
- package/dist/lint/check.js +25 -7
- 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 +4 -0
- package/dist/lint/index.js +4 -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/rules.d.ts +37 -4
- package/dist/lint/rules.js +16 -4
- 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.js +0 -2
- package/dist/migrations/checkpoint.js.map +1 -1
- 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 -9
- package/dist/migrations/create.js.map +1 -1
- package/dist/migrations/routines.d.ts +5 -15
- package/dist/migrations/routines.js +5 -30
- package/dist/migrations/routines.js.map +1 -1
- package/dist/pr/model.d.ts +4 -1
- package/dist/pr/model.js +13 -5
- package/dist/pr/model.js.map +1 -1
- package/dist/pr/render.d.ts +4 -1
- package/dist/pr/render.js +22 -8
- 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 +16 -0
- package/dist/project.js +29 -1
- 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 +5 -2
- package/dist/replay/replay.js.map +1 -1
- package/dist/report/audit.d.ts +1 -1
- package/dist/report/audit.js +20 -3
- package/dist/report/audit.js.map +1 -1
- package/dist/schemas.d.ts +3 -1
- package/dist/schemas.js +2 -0
- package/dist/schemas.js.map +1 -1
- package/dist/sources/ddl.d.ts +15 -20
- package/dist/sources/ddl.js +34 -328
- package/dist/sources/ddl.js.map +1 -1
- package/dist/sources/index.js +2 -2
- package/dist/sources/index.js.map +1 -1
- 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 +3 -0
- package/dist/steps/postgres-migration.js +7 -3
- 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 +2 -1
- package/dist/tenants/index.js +3 -4
- package/dist/tenants/index.js.map +1 -1
- 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 +10 -0
- package/dist/versioned/engine.js +8 -4
- 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/op.d.ts +4 -0
- package/dist/versioned/op.js +5 -2
- package/dist/versioned/op.js.map +1 -1
- package/dist/versioned/state.js +1 -1
- package/dist/versioned/state.js.map +1 -1
- package/dist/waves/index.d.ts +58 -13
- package/dist/waves/index.js +109 -24
- package/dist/waves/index.js.map +1 -1
- package/dist/waves/record.d.ts +10 -0
- package/dist/waves/record.js.map +1 -1
- package/package.json +8 -7
- package/schemas/apply.schema.json +1 -1
- package/schemas/cleanup.schema.json +40 -0
- package/schemas/init.schema.json +51 -22
- package/schemas/lint-rules.schema.json +4 -0
- package/schemas/new.schema.json +41 -3
- package/schemas/plan.schema.json +39 -0
- package/schemas/report.schema.json +1 -1
- package/schemas/test.schema.json +41 -0
package/dist/commands/plan.js
CHANGED
|
@@ -2,9 +2,10 @@ import { parseArgs } from "node:util";
|
|
|
2
2
|
import { eventFromRun, sendEvent } from "../notify/index.js";
|
|
3
3
|
import { guarded } from "../env-args.js";
|
|
4
4
|
import { loadProject, resolveEnvironment, YodelError } from "../project.js";
|
|
5
|
-
import {
|
|
5
|
+
import { declarativeRefusal, describeSettingsTopology, environmentSettings } from "../config/settings.js";
|
|
6
6
|
import { buildSchema } from "../chant/build.js";
|
|
7
7
|
import { planEnvironment, planExitCode, planJson, renderPlan } from "../chant/plan.js";
|
|
8
|
+
import { accessReview, renderAccessReview } from "../chant/access.js";
|
|
8
9
|
import { hasMigrations } from "../versioned/index.js";
|
|
9
10
|
import { describeServer, probeServer } from "../server.js";
|
|
10
11
|
import { runnable } from "../chant/runnable.js";
|
|
@@ -13,6 +14,8 @@ import { collectVersionedPlan } from "../pr/model.js";
|
|
|
13
14
|
import { commentMarker, planJsonVersioned, renderPlanMarkdown, renderPlanText, subjectIn } from "../pr/render.js";
|
|
14
15
|
import { resolveForgeTarget } from "../pr/forge.js";
|
|
15
16
|
import { commentClient, findComment, upsertComment } from "../pr/comment.js";
|
|
17
|
+
import { collectTenantSetPlan, renderTenantSetMarkdown, renderTenantSetText, tenantSetExitCode, tenantSetJson } from "../pr/tenants.js";
|
|
18
|
+
import { tenantSetOf } from "../tenants/index.js";
|
|
16
19
|
const usage = "usage: yodel plan <env> [--json] [--dir <project>] [--format text|markdown|json]\n" +
|
|
17
20
|
" [--allow-out-of-order] [--op <name>]\n" +
|
|
18
21
|
" [--comment [--forge github|gitlab|forgejo]\n" +
|
|
@@ -31,6 +34,12 @@ apply asks approval for, with the chant approve command that approves it.
|
|
|
31
34
|
When chant's gate ledger holds an approval of the migrations Op's gate for
|
|
32
35
|
another digest, it says what moved since. Reads only.
|
|
33
36
|
|
|
37
|
+
An environment with a tenant set (yodel.config.ts environments.<env>.tenants)
|
|
38
|
+
is planned tenant by tenant, each against its own history, and shown as one
|
|
39
|
+
plan: tenants with the same migrations pending once, as a group, then the
|
|
40
|
+
wave's one approval of the set digest over every tenant. --comment posts it
|
|
41
|
+
as one comment for the set. <env>/<tenant> plans one tenant.
|
|
42
|
+
|
|
34
43
|
Options:
|
|
35
44
|
--json print the plan as JSON (the same as --format json)
|
|
36
45
|
--format <f> text (default), markdown (the pull request comment),
|
|
@@ -141,7 +150,7 @@ export const plan = {
|
|
|
141
150
|
}),
|
|
142
151
|
};
|
|
143
152
|
async function declarativePlan(project, env, json, io) {
|
|
144
|
-
const refusal =
|
|
153
|
+
const refusal = declarativeRefusal(project, env.name);
|
|
145
154
|
if (refusal)
|
|
146
155
|
throw refusal;
|
|
147
156
|
const topology = project.dialect === "clickhouse" ? `, topology ${describeSettingsTopology(environmentSettings(project, env.name))}` : "";
|
|
@@ -149,10 +158,14 @@ async function declarativePlan(project, env, json, io) {
|
|
|
149
158
|
try {
|
|
150
159
|
const result = await planEnvironment(project, env, build);
|
|
151
160
|
const server = await probeServer(project, env);
|
|
161
|
+
const access = await accessReview(project, env.name, result.diff.changes, build.output);
|
|
152
162
|
if (json)
|
|
153
|
-
io.out(`${JSON.stringify({ ...planJson(result), ...(server ? { server } : {}) }, null, 2)}\n`);
|
|
154
|
-
else
|
|
155
|
-
|
|
163
|
+
io.out(`${JSON.stringify({ ...planJson(result), access, ...(server ? { server } : {}) }, null, 2)}\n`);
|
|
164
|
+
else {
|
|
165
|
+
const text = await renderPlan(result, `Plan for ${env.name} (${server ? describeServer(server) : project.dialect}, sql.profiles.${env.name}${topology})`);
|
|
166
|
+
const review = renderAccessReview(access, env.name);
|
|
167
|
+
io.out(`${text}\n${review.length > 0 ? `\n${review.join("\n")}\n` : ""}`);
|
|
168
|
+
}
|
|
156
169
|
return planExitCode(result);
|
|
157
170
|
}
|
|
158
171
|
finally {
|
|
@@ -160,6 +173,8 @@ async function declarativePlan(project, env, json, io) {
|
|
|
160
173
|
}
|
|
161
174
|
}
|
|
162
175
|
async function versionedPlan(project, env, a, io) {
|
|
176
|
+
if (!env.tenant && tenantSetOf(project, env.name))
|
|
177
|
+
return tenantSetPlan(project, env, a, io);
|
|
163
178
|
const marker = commentMarker(env.name);
|
|
164
179
|
// Resolve the forge first: a job missing its token fails before it reads the server.
|
|
165
180
|
const target = a.comment ? resolveForgeTarget(a.forge, process.env) : undefined;
|
|
@@ -184,4 +199,23 @@ async function versionedPlan(project, env, a, io) {
|
|
|
184
199
|
await sendEvent(project.yodel?.config.notify, eventFromRun("plan", doc), { io, verb: "plan" });
|
|
185
200
|
return code;
|
|
186
201
|
}
|
|
202
|
+
/** `yodel plan <set>` (#56): every tenant, grouped, and one comment for the set. */
|
|
203
|
+
async function tenantSetPlan(project, env, a, io) {
|
|
204
|
+
const target = a.comment ? resolveForgeTarget(a.forge, process.env) : undefined;
|
|
205
|
+
const client = target ? commentClient(target) : undefined;
|
|
206
|
+
const marker = commentMarker(env.name);
|
|
207
|
+
const existing = client ? await findComment(client, marker) : undefined;
|
|
208
|
+
const result = await collectTenantSetPlan(project, env.name, { allowOutOfOrder: a.allowOutOfOrder });
|
|
209
|
+
if (client && target) {
|
|
210
|
+
const posted = await upsertComment(client, marker, renderTenantSetMarkdown(result), existing);
|
|
211
|
+
io.err(`yodel plan: ${posted.action} the plan comment on ${target.forge} ${target.repo}#${String(target.pr)}${posted.comment.url ? ` (${posted.comment.url})` : ` (comment ${String(posted.comment.id)})`}\n`);
|
|
212
|
+
}
|
|
213
|
+
if (a.format === "json")
|
|
214
|
+
io.out(`${JSON.stringify(tenantSetJson(result), null, 2)}\n`);
|
|
215
|
+
else if (a.format === "markdown")
|
|
216
|
+
io.out(renderTenantSetMarkdown(result));
|
|
217
|
+
else
|
|
218
|
+
io.out(renderTenantSetText(result, { runnable: (c) => runnable(c, project.dir) }));
|
|
219
|
+
return tenantSetExitCode(result);
|
|
220
|
+
}
|
|
187
221
|
//# sourceMappingURL=plan.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../../src/commands/plan.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE7D,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,UAAU,EAAkC,MAAM,eAAe,CAAC;AAC5G,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../../src/commands/plan.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
import { parseArgs } from "node:util";
|
|
4
|
+
import { guarded } from "../env-args.js";
|
|
5
|
+
import { loadProject, resolveEnvironment, YodelError } from "../project.js";
|
|
6
|
+
import { readChain } from "../versioned/index.js";
|
|
7
|
+
import { loadTests, runTests, testFiles, TESTS_DIR } from "../testing/run.js";
|
|
8
|
+
import { renderTests, testExitCode, testJson, testJunit } from "../testing/report.js";
|
|
9
|
+
const usage = "usage: yodel test [--env <env>] [--run <regexp>] [--reset] [--reset-shared <profile>]... [--keep] [--json] [--junit <file>] [--dir <project>]";
|
|
10
|
+
const help = `${usage}
|
|
11
|
+
|
|
12
|
+
Runs the cases in tests/*.test.ts against databases built from the
|
|
13
|
+
migrations on a throwaway server: the profile --env names (default: test,
|
|
14
|
+
else replay). A case seeds data at a migration and checks it after the
|
|
15
|
+
migrations that follow (backfills included), or checks the schema the newest
|
|
16
|
+
migration leaves (a view's rows, a function's result, a constraint that
|
|
17
|
+
refuses a row):
|
|
18
|
+
|
|
19
|
+
import { defineTests, expectError, expectRows, expectValue } from "@intentius/sql-yodeler";
|
|
20
|
+
|
|
21
|
+
export default defineTests([
|
|
22
|
+
{
|
|
23
|
+
name: "fill-country fills every country",
|
|
24
|
+
at: "20261010T0530-add-source", // seed after this migration
|
|
25
|
+
seed: ["INSERT INTO shop.events (id, kind, at) VALUES (1, 'view', now())"],
|
|
26
|
+
expect: [expectValue("SELECT count() FROM shop.events WHERE country = ''", 0)],
|
|
27
|
+
},
|
|
28
|
+
]);
|
|
29
|
+
|
|
30
|
+
Per case, the databases (or schemas) the history names are emptied, the
|
|
31
|
+
migrations up to at (default: the newest) are replayed as yodel lint
|
|
32
|
+
--replay replays them (backfills skipped: there are no rows yet), the seed
|
|
33
|
+
runs, the migrations after at up to through (default: the newest) run with
|
|
34
|
+
every step, backfills included, and each expectation is checked. Values
|
|
35
|
+
compare as text. Nothing is written to a history.
|
|
36
|
+
|
|
37
|
+
It never runs against an environment yodel applies to: a target whose
|
|
38
|
+
history table holds a row is refused, and so is one that already holds what
|
|
39
|
+
the history names (unless --reset), or one another profile on the same
|
|
40
|
+
server names (unless --reset-shared <profile>).
|
|
41
|
+
|
|
42
|
+
Options:
|
|
43
|
+
--env <env> the throwaway server's profile (default: test, else
|
|
44
|
+
replay)
|
|
45
|
+
--run <regexp> only the cases whose name matches
|
|
46
|
+
--reset drop what the history names first when it is there.
|
|
47
|
+
Destructive: never against a server whose data
|
|
48
|
+
matters
|
|
49
|
+
--reset-shared <profile>
|
|
50
|
+
run even though <profile> binds the same server and
|
|
51
|
+
names one of those databases or schemas (repeatable)
|
|
52
|
+
--keep leave the last case's database in place
|
|
53
|
+
--json print the outcome as JSON
|
|
54
|
+
--junit <file> also write the outcome as JUnit XML to <file>
|
|
55
|
+
-C, --dir <dir> the project directory (default: the working directory)
|
|
56
|
+
|
|
57
|
+
Exit codes:
|
|
58
|
+
0 every case passed (or there is no case)
|
|
59
|
+
3 a case failed, or could not run (a migration or seed statement failed)
|
|
60
|
+
4 refused, nothing run: the target has a migration history, already holds
|
|
61
|
+
what the history names (no --reset), or another profile names it
|
|
62
|
+
1 anything else: a test file that does not load, a bad config, a server
|
|
63
|
+
that does not answer
|
|
64
|
+
`;
|
|
65
|
+
function parseTestArgs(args) {
|
|
66
|
+
let parsed;
|
|
67
|
+
try {
|
|
68
|
+
parsed = parseArgs({
|
|
69
|
+
args,
|
|
70
|
+
allowPositionals: false,
|
|
71
|
+
strict: true,
|
|
72
|
+
options: {
|
|
73
|
+
env: { type: "string" },
|
|
74
|
+
run: { type: "string" },
|
|
75
|
+
reset: { type: "boolean" },
|
|
76
|
+
"reset-shared": { type: "string", multiple: true },
|
|
77
|
+
keep: { type: "boolean" },
|
|
78
|
+
json: { type: "boolean" },
|
|
79
|
+
junit: { type: "string" },
|
|
80
|
+
dir: { type: "string", short: "C" },
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
catch (e) {
|
|
85
|
+
throw new YodelError(`${e instanceof Error ? e.message : String(e)}\n${usage}`);
|
|
86
|
+
}
|
|
87
|
+
const v = parsed.values;
|
|
88
|
+
let run;
|
|
89
|
+
if (typeof v.run === "string") {
|
|
90
|
+
try {
|
|
91
|
+
run = new RegExp(v.run);
|
|
92
|
+
}
|
|
93
|
+
catch (e) {
|
|
94
|
+
throw new YodelError(`--run ${v.run}: ${e instanceof Error ? e.message : String(e)}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
env: typeof v.env === "string" ? v.env : undefined,
|
|
99
|
+
run,
|
|
100
|
+
reset: v.reset === true,
|
|
101
|
+
resetShared: Array.isArray(v["reset-shared"]) ? v["reset-shared"].filter((r) => typeof r === "string") : [],
|
|
102
|
+
keep: v.keep === true,
|
|
103
|
+
json: v.json === true,
|
|
104
|
+
junit: typeof v.junit === "string" ? v.junit : undefined,
|
|
105
|
+
dir: typeof v.dir === "string" ? v.dir : process.cwd(),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/** The profile a run uses when --env is not given: test, else replay. */
|
|
109
|
+
function defaultEnv(project) {
|
|
110
|
+
const profiles = Object.keys(project.config.sql?.profiles ?? {});
|
|
111
|
+
const found = ["test", "replay"].find((p) => profiles.includes(p));
|
|
112
|
+
if (!found)
|
|
113
|
+
throw new YodelError(`yodel test runs on a throwaway server: name its profile with --env (chant.config.ts declares no sql.profiles.test or sql.profiles.replay)`);
|
|
114
|
+
return found;
|
|
115
|
+
}
|
|
116
|
+
/** `yodel test`; the exit codes are in `help`. */
|
|
117
|
+
export const test = {
|
|
118
|
+
name: "test",
|
|
119
|
+
summary: "run tests/*.test.ts on databases built from the migrations",
|
|
120
|
+
implemented: true,
|
|
121
|
+
run: (args, io) => guarded("test", io, args, help, async () => {
|
|
122
|
+
const a = parseTestArgs(args);
|
|
123
|
+
const project = await loadProject(a.dir);
|
|
124
|
+
const files = testFiles(project.dir);
|
|
125
|
+
if (files.length === 0) {
|
|
126
|
+
if (!a.json)
|
|
127
|
+
io.out(`No test files: ${TESTS_DIR}/*.test.ts holds none.\n`);
|
|
128
|
+
else
|
|
129
|
+
io.out(`${JSON.stringify({ files: [], summary: { passed: 0, failed: 0, errors: 0 }, cases: [] }, null, 2)}\n`);
|
|
130
|
+
return 0;
|
|
131
|
+
}
|
|
132
|
+
const tests = await loadTests(project.dir, files);
|
|
133
|
+
// A directory that is not one chain is refused (exit 4) before anything runs.
|
|
134
|
+
readChain(project);
|
|
135
|
+
const env = resolveEnvironment(project, a.env ?? defaultEnv(project));
|
|
136
|
+
// A rebuild step's executor prints its SQL to stdout: while the cases run, stdout goes to stderr, so --json stays one document.
|
|
137
|
+
const write = process.stdout.write.bind(process.stdout);
|
|
138
|
+
process.stdout.write = process.stderr.write.bind(process.stderr);
|
|
139
|
+
let run;
|
|
140
|
+
try {
|
|
141
|
+
run = await runTests(project, env, tests, {
|
|
142
|
+
...(a.run ? { run: a.run } : {}),
|
|
143
|
+
reset: a.reset,
|
|
144
|
+
resetShared: a.resetShared,
|
|
145
|
+
keep: a.keep,
|
|
146
|
+
log: (l) => { io.err(`test: ${l}\n`); },
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
finally {
|
|
150
|
+
process.stdout.write = write;
|
|
151
|
+
}
|
|
152
|
+
if (a.junit !== undefined) {
|
|
153
|
+
const path = resolve(a.junit);
|
|
154
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
155
|
+
writeFileSync(path, testJunit(run));
|
|
156
|
+
}
|
|
157
|
+
if (a.json)
|
|
158
|
+
io.out(`${JSON.stringify(testJson(run), null, 2)}\n`);
|
|
159
|
+
else
|
|
160
|
+
io.out(renderTests(run));
|
|
161
|
+
return testExitCode(run);
|
|
162
|
+
}),
|
|
163
|
+
};
|
|
164
|
+
//# sourceMappingURL=test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test.js","sourceRoot":"","sources":["../../src/commands/test.ts"],"names":[],"mappings":"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"}
|
package/dist/config/define.d.ts
CHANGED
|
@@ -60,6 +60,96 @@ export interface EnvironmentConfig {
|
|
|
60
60
|
* tenant behind one gate. See {@link TenantSet}.
|
|
61
61
|
*/
|
|
62
62
|
tenants?: TenantSet;
|
|
63
|
+
/**
|
|
64
|
+
* Steps around apply (#64): checks run before the migrations are applied
|
|
65
|
+
* (replication lag, long transactions, disk headroom) and after (smoke
|
|
66
|
+
* queries). Read from yodel.config.ts at the base commit, never from the
|
|
67
|
+
* change, so a pull request cannot add a step that runs with the writer.
|
|
68
|
+
* Each outcome is recorded in the history. See {@link ApplySteps}.
|
|
69
|
+
*/
|
|
70
|
+
steps?: ApplySteps;
|
|
71
|
+
/**
|
|
72
|
+
* Whether yodel plans, applies and compares access control in this
|
|
73
|
+
* environment (chant's `sql.profiles.<env>.access`). On Postgres:
|
|
74
|
+
* row-level security, policies, the roles the schema declares, grants and
|
|
75
|
+
* default privileges. Off, the access declarations are left out of the
|
|
76
|
+
* plan and the server's access is not read. On, the declared privileges
|
|
77
|
+
* are the whole of them: one granted by hand is revoked. Passwords and
|
|
78
|
+
* role memberships are the environment's and are never declared. The
|
|
79
|
+
* declarative apply and drift run chant, which reads chant.config.ts, so
|
|
80
|
+
* there the two must agree. On ClickHouse (#46): users, roles, row
|
|
81
|
+
* policies and grants; chant's apply has no switch, so off, the
|
|
82
|
+
* declarative path is refused when `src/` declares any, and on, `yodel
|
|
83
|
+
* init --from` adopts them. Default: `sql.profiles.<env>.access` in
|
|
84
|
+
* chant.config.ts, then off.
|
|
85
|
+
*/
|
|
86
|
+
access?: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Which approvals of the migrations Op's gate count (#48), for `yodel
|
|
89
|
+
* apply <env>` outside the apply pipeline's waves:
|
|
90
|
+
*
|
|
91
|
+
* - `ledger` (the default): any `chant approve` of the plan digest;
|
|
92
|
+
* - `sealed`: only an approval sealed with `chant approve --sign` (or
|
|
93
|
+
* `yodel approve --sign`) by a key the signers file
|
|
94
|
+
* (`.chant/allowed_signers`) at the base commit lists for the approver.
|
|
95
|
+
*
|
|
96
|
+
* Read from yodel.config.ts at the base commit, never from the change.
|
|
97
|
+
* Default: the environment's wave's `approval` when that is `sealed`, else
|
|
98
|
+
* `ledger`. A wave's `pr-review` is the wave's alone.
|
|
99
|
+
*/
|
|
100
|
+
approval?: EnvironmentApprovalMode;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Which approvals of a gate's plan digest count (#48), chant's wave
|
|
104
|
+
* `approval`:
|
|
105
|
+
*
|
|
106
|
+
* - `ledger`: any `chant approve` of the digest on `chant/lifecycle`;
|
|
107
|
+
* - `pr-review`: also an approving review of the merged pull request's head
|
|
108
|
+
* by a writer other than its author, when that head planned the digest;
|
|
109
|
+
* - `sealed`: only an approval sealed by a key the signers file at the base
|
|
110
|
+
* commit lists for its approver.
|
|
111
|
+
*/
|
|
112
|
+
export type ApprovalMode = "ledger" | "pr-review" | "sealed";
|
|
113
|
+
export declare const APPROVAL_MODES: readonly ApprovalMode[];
|
|
114
|
+
/** The modes the migrations Op's gate takes: `pr-review` needs the pipeline's waves. */
|
|
115
|
+
export type EnvironmentApprovalMode = Exclude<ApprovalMode, "pr-review">;
|
|
116
|
+
export declare const ENVIRONMENT_APPROVAL_MODES: readonly EnvironmentApprovalMode[];
|
|
117
|
+
/** `steps` of an environment: run in order, `before` under the lock before the first migration, `after` after the last. */
|
|
118
|
+
export interface ApplySteps {
|
|
119
|
+
before?: ApplyStep[];
|
|
120
|
+
after?: ApplyStep[];
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* One step: a read-only SQL query on the environment's server, judged like a
|
|
124
|
+
* migration's pre-migration check (`expect`, default `empty`: no rows), or a
|
|
125
|
+
* shell command run in the project directory with `YODEL_ENV` and
|
|
126
|
+
* `YODEL_STEP` (`before` or `after`) set, which passes when it exits 0.
|
|
127
|
+
*
|
|
128
|
+
* ```ts
|
|
129
|
+
* steps: {
|
|
130
|
+
* before: [{ name: "no-long-transactions", sql: "SELECT pid FROM pg_stat_activity WHERE xact_start < now() - interval '5 minutes'", onFailure: "approve" }],
|
|
131
|
+
* after: [{ name: "smoke", command: "./scripts/smoke.sh" }],
|
|
132
|
+
* }
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
export interface ApplyStep {
|
|
136
|
+
/** Names it in output and in the history: lowercase letters, digits, - and _. */
|
|
137
|
+
name: string;
|
|
138
|
+
sql?: string;
|
|
139
|
+
/** What `sql` must return: `empty` (the default), `true`, or a number in `{ min, max }`. */
|
|
140
|
+
expect?: "empty" | "true" | {
|
|
141
|
+
min?: number;
|
|
142
|
+
max?: number;
|
|
143
|
+
};
|
|
144
|
+
command?: string;
|
|
145
|
+
/**
|
|
146
|
+
* A failing `before` step: `fail` (the default) refuses the apply, exit 4;
|
|
147
|
+
* `approve` holds the environment's wave for a person instead, whatever
|
|
148
|
+
* its gate, until someone approves the plan with the step failing. An
|
|
149
|
+
* `after` step that fails fails the run (exit 1); the migrations stay
|
|
150
|
+
* applied.
|
|
151
|
+
*/
|
|
152
|
+
onFailure?: "fail" | "approve";
|
|
63
153
|
}
|
|
64
154
|
/**
|
|
65
155
|
* The tenants of an environment: a list of names, a file of them (one per
|
|
@@ -119,6 +209,14 @@ export interface WaveConfig {
|
|
|
119
209
|
* applies the rest. Default 1: one job plans, decides and applies.
|
|
120
210
|
*/
|
|
121
211
|
shares?: number;
|
|
212
|
+
/**
|
|
213
|
+
* Which approvals of the wave's digest count (#48): `ledger` (the
|
|
214
|
+
* default), `pr-review` or `sealed`; see {@link ApprovalMode}. Read, like
|
|
215
|
+
* `gate`, from the commit a change merges onto. Under `pr-review`, `yodel
|
|
216
|
+
* ci` adds the pull request job that records the plans each head makes
|
|
217
|
+
* (`chant run wave --record-plans`).
|
|
218
|
+
*/
|
|
219
|
+
approval?: ApprovalMode;
|
|
122
220
|
}
|
|
123
221
|
/** A forge `yodel ci` renders pipelines for. */
|
|
124
222
|
export type CiForge = "github" | "gitlab" | "forgejo";
|
|
@@ -142,6 +240,77 @@ export interface CiConfig {
|
|
|
142
240
|
* no `npm ci`. Default: `node:22-bookworm`, and each job runs `npm ci`.
|
|
143
241
|
*/
|
|
144
242
|
image?: string;
|
|
243
|
+
/**
|
|
244
|
+
* A scheduled job that starts again an apply wave whose approval has
|
|
245
|
+
* arrived (#47): `chant run resume --op yodel-apply`, which re-runs the
|
|
246
|
+
* GitHub run, dispatches the Forgejo workflow or retries the GitLab job.
|
|
247
|
+
* It approves nothing. `schedule` is a five-field cron, such as
|
|
248
|
+
* `"*\/10 * * * *"`. GitHub uses the job's token (`actions: write`);
|
|
249
|
+
* Forgejo the `CHANT_FORGE_TOKEN` secret (`write:repository`); GitLab runs
|
|
250
|
+
* it in a pipeline schedule you create, with `GITLAB_TOKEN` (the `api`
|
|
251
|
+
* scope, Developer role). Without it, `yodel approve` resumes the job.
|
|
252
|
+
*/
|
|
253
|
+
resume?: {
|
|
254
|
+
schedule: string;
|
|
255
|
+
};
|
|
256
|
+
/**
|
|
257
|
+
* The cloud login a job runs before yodel when a role it holds has a
|
|
258
|
+
* password minted by a cloud token source (#132): `aws` for `rds-iam`,
|
|
259
|
+
* `gcp` for `cloud-sql-iam`, `azure` for `entra`. `environments.<env>`
|
|
260
|
+
* overrides a cloud's login for that environment's roles. See
|
|
261
|
+
* {@link CiLogin}.
|
|
262
|
+
*/
|
|
263
|
+
login?: CiLogin;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* How a CI job exchanges its OIDC token for a cloud login (#132). On GitHub
|
|
267
|
+
* the job requests the token for the cloud's audience and writes it to
|
|
268
|
+
* `tokenFile`; on GitLab the job's `id_tokens` variable is written there.
|
|
269
|
+
* Forgejo gives a job no OIDC token, so there a login is rendered only when
|
|
270
|
+
* `tokenFile` names a token the runner provides.
|
|
271
|
+
*
|
|
272
|
+
* ```ts
|
|
273
|
+
* ci: {
|
|
274
|
+
* login: {
|
|
275
|
+
* aws: { roleArn: "arn:aws:iam::123456789012:role/yodel-dev" },
|
|
276
|
+
* environments: { prod: { aws: { roleArn: "arn:aws:iam::123456789012:role/yodel-prod" } } },
|
|
277
|
+
* },
|
|
278
|
+
* }
|
|
279
|
+
* ```
|
|
280
|
+
*/
|
|
281
|
+
export interface CiLogin extends CloudLogins {
|
|
282
|
+
/** Per environment: a cloud's login for the roles of that environment, in place of the one above. */
|
|
283
|
+
environments?: Record<string, CloudLogins>;
|
|
284
|
+
}
|
|
285
|
+
export interface CloudLogins {
|
|
286
|
+
/** AWS web identity: `AWS_ROLE_ARN` and `AWS_WEB_IDENTITY_TOKEN_FILE`, which the aws command line assumes the role with. */
|
|
287
|
+
aws?: AwsLogin;
|
|
288
|
+
/** gcloud workload identity federation: a credential configuration over the token, and `gcloud auth login --cred-file`. */
|
|
289
|
+
gcp?: GcpLogin;
|
|
290
|
+
/** `az login --service-principal --federated-token` with the token. */
|
|
291
|
+
azure?: AzureLogin;
|
|
292
|
+
}
|
|
293
|
+
export interface AwsLogin {
|
|
294
|
+
/** The role to assume, `arn:aws:iam::<account>:role/<name>`. */
|
|
295
|
+
roleArn: string;
|
|
296
|
+
/** Where the token is (default: a file in the job's temporary directory). */
|
|
297
|
+
tokenFile?: string;
|
|
298
|
+
/** `AWS_ROLE_SESSION_NAME`. Default: `yodel`. */
|
|
299
|
+
sessionName?: string;
|
|
300
|
+
}
|
|
301
|
+
export interface GcpLogin {
|
|
302
|
+
/** The workload identity provider, `projects/<number>/locations/global/workloadIdentityPools/<pool>/providers/<provider>`. */
|
|
303
|
+
workloadIdentityProvider: string;
|
|
304
|
+
/** The service account to impersonate, `<name>@<project>.iam.gserviceaccount.com`. */
|
|
305
|
+
serviceAccount: string;
|
|
306
|
+
tokenFile?: string;
|
|
307
|
+
}
|
|
308
|
+
export interface AzureLogin {
|
|
309
|
+
/** The application (client) id of the identity with the federated credential. */
|
|
310
|
+
clientId: string;
|
|
311
|
+
/** The directory (tenant) id. */
|
|
312
|
+
tenantId: string;
|
|
313
|
+
tokenFile?: string;
|
|
145
314
|
}
|
|
146
315
|
export interface YodelConfig {
|
|
147
316
|
/** Keyed by the environment's name in `sql.profiles`. */
|
|
@@ -260,11 +429,15 @@ export interface PolicyStep {
|
|
|
260
429
|
/** An Op step's Op. */
|
|
261
430
|
op?: string;
|
|
262
431
|
}
|
|
263
|
-
/** The rules `lint.rules` can set: every lint rule,
|
|
264
|
-
export type LintRuleName = LintRuleId | "replay"
|
|
432
|
+
/** The rules `lint.rules` can set: every lint rule, the replay check's, and the sql lexicon's schema checks (`SQLPG101`, `SQLCH113`). */
|
|
433
|
+
export type LintRuleName = LintRuleId | "replay" | `SQLPG${number}` | `SQLCH${number}`;
|
|
434
|
+
/** A naming rule: a preset, or a regular expression the whole name must match. */
|
|
435
|
+
export type NamingRuleConfig = "snake_case" | "camelCase" | "PascalCase" | (string & {});
|
|
265
436
|
export interface LintConfig {
|
|
266
437
|
/** Each rule's level. The integrity rules (fork, directory, checksum, unreadable-object) are always errors. */
|
|
267
438
|
rules?: Partial<Record<LintRuleName, LevelSetting>>;
|
|
439
|
+
/** The names a migration adds, per kind of object (rule `naming`): `{ table: "snake_case", index: "[a-z_]+_idx" }`. */
|
|
440
|
+
naming?: Partial<Record<"table" | "column" | "index" | "constraint", NamingRuleConfig>>;
|
|
268
441
|
}
|
|
269
442
|
/** Returns `config` as is; it types the default export of `yodel.config.ts`. */
|
|
270
443
|
export declare const defineConfig: (config: YodelConfig) => YodelConfig;
|
package/dist/config/define.js
CHANGED
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
* });
|
|
16
16
|
* ```
|
|
17
17
|
*/
|
|
18
|
+
export const APPROVAL_MODES = ["ledger", "pr-review", "sealed"];
|
|
19
|
+
export const ENVIRONMENT_APPROVAL_MODES = ["ledger", "sealed"];
|
|
18
20
|
export const WAVE_GATES = ["always", "on-destructive", "never"];
|
|
19
21
|
export const CI_FORGES = ["github", "gitlab", "forgejo"];
|
|
20
22
|
/** Returns `config` as is; it types the default export of `yodel.config.ts`. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define.js","sourceRoot":"","sources":["../../src/config/define.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;
|
|
1
|
+
{"version":3,"file":"define.js","sourceRoot":"","sources":["../../src/config/define.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAyGH,MAAM,CAAC,MAAM,cAAc,GAA4B,CAAC,QAAQ,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;AAKzF,MAAM,CAAC,MAAM,0BAA0B,GAAuC,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAuDnG,MAAM,CAAC,MAAM,UAAU,GAAwB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,OAAO,CAAC,CAAC;AAqDrF,MAAM,CAAC,MAAM,SAAS,GAAuB,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;AA4N7E,gFAAgF;AAChF,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,MAAmB,EAAe,EAAE,CAAC,MAAM,CAAC"}
|