@intentius/sql-yodeler 0.0.0-stage → 0.1.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/LICENSE +202 -0
- package/README.md +110 -2
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +14 -0
- package/dist/bin.js.map +1 -0
- package/dist/chant/apply.d.ts +51 -0
- package/dist/chant/apply.js +104 -0
- package/dist/chant/apply.js.map +1 -0
- package/dist/chant/build.d.ts +34 -0
- package/dist/chant/build.js +48 -0
- package/dist/chant/build.js.map +1 -0
- package/dist/chant/drift.d.ts +44 -0
- package/dist/chant/drift.js +91 -0
- package/dist/chant/drift.js.map +1 -0
- package/dist/chant/plan.d.ts +45 -0
- package/dist/chant/plan.js +61 -0
- package/dist/chant/plan.js.map +1 -0
- package/dist/chant/process.d.ts +41 -0
- package/dist/chant/process.js +87 -0
- package/dist/chant/process.js.map +1 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.js +59 -0
- package/dist/cli.js.map +1 -0
- package/dist/command.d.ts +17 -0
- package/dist/command.js +13 -0
- package/dist/command.js.map +1 -0
- package/dist/commands/apply.d.ts +3 -0
- package/dist/commands/apply.js +306 -0
- package/dist/commands/apply.js.map +1 -0
- package/dist/commands/drift.d.ts +3 -0
- package/dist/commands/drift.js +38 -0
- package/dist/commands/drift.js.map +1 -0
- package/dist/commands/index.d.ts +3 -0
- package/dist/commands/index.js +22 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.js +135 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/lint.d.ts +3 -0
- package/dist/commands/lint.js +193 -0
- package/dist/commands/lint.js.map +1 -0
- package/dist/commands/new.d.ts +3 -0
- package/dist/commands/new.js +168 -0
- package/dist/commands/new.js.map +1 -0
- package/dist/commands/plan.d.ts +3 -0
- package/dist/commands/plan.js +171 -0
- package/dist/commands/plan.js.map +1 -0
- package/dist/commands/rebase.d.ts +3 -0
- package/dist/commands/rebase.js +167 -0
- package/dist/commands/rebase.js.map +1 -0
- package/dist/commands/repair.d.ts +3 -0
- package/dist/commands/repair.js +117 -0
- package/dist/commands/repair.js.map +1 -0
- package/dist/commands/status.d.ts +7 -0
- package/dist/commands/status.js +54 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/config/define.d.ts +50 -0
- package/dist/config/define.js +20 -0
- package/dist/config/define.js.map +1 -0
- package/dist/config/index.d.ts +11 -0
- package/dist/config/index.js +12 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/load.d.ts +17 -0
- package/dist/config/load.js +102 -0
- package/dist/config/load.js.map +1 -0
- package/dist/config/settings.d.ts +40 -0
- package/dist/config/settings.js +88 -0
- package/dist/config/settings.js.map +1 -0
- package/dist/env-args.d.ts +18 -0
- package/dist/env-args.js +62 -0
- package/dist/env-args.js.map +1 -0
- package/dist/history/client.d.ts +17 -0
- package/dist/history/client.js +19 -0
- package/dist/history/client.js.map +1 -0
- package/dist/history/ddl.d.ts +58 -0
- package/dist/history/ddl.js +100 -0
- package/dist/history/ddl.js.map +1 -0
- package/dist/history/index.d.ts +25 -0
- package/dist/history/index.js +26 -0
- package/dist/history/index.js.map +1 -0
- package/dist/history/lock.d.ts +100 -0
- package/dist/history/lock.js +224 -0
- package/dist/history/lock.js.map +1 -0
- package/dist/history/postgres/ddl.d.ts +22 -0
- package/dist/history/postgres/ddl.js +47 -0
- package/dist/history/postgres/ddl.js.map +1 -0
- package/dist/history/postgres/index.d.ts +12 -0
- package/dist/history/postgres/index.js +13 -0
- package/dist/history/postgres/index.js.map +1 -0
- package/dist/history/postgres/lock.d.ts +48 -0
- package/dist/history/postgres/lock.js +95 -0
- package/dist/history/postgres/lock.js.map +1 -0
- package/dist/history/postgres/store.d.ts +39 -0
- package/dist/history/postgres/store.js +68 -0
- package/dist/history/postgres/store.js.map +1 -0
- package/dist/history/rows.d.ts +96 -0
- package/dist/history/rows.js +73 -0
- package/dist/history/rows.js.map +1 -0
- package/dist/history/store.d.ts +72 -0
- package/dist/history/store.js +134 -0
- package/dist/history/store.js.map +1 -0
- package/dist/history/topology.d.ts +41 -0
- package/dist/history/topology.js +54 -0
- package/dist/history/topology.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/init/adopt.d.ts +70 -0
- package/dist/init/adopt.js +138 -0
- package/dist/init/adopt.js.map +1 -0
- package/dist/init/baseline.d.ts +61 -0
- package/dist/init/baseline.js +88 -0
- package/dist/init/baseline.js.map +1 -0
- package/dist/init/files.d.ts +23 -0
- package/dist/init/files.js +77 -0
- package/dist/init/files.js.map +1 -0
- package/dist/init/index.d.ts +16 -0
- package/dist/init/index.js +17 -0
- package/dist/init/index.js.map +1 -0
- package/dist/init/live.d.ts +28 -0
- package/dist/init/live.js +45 -0
- package/dist/init/live.js.map +1 -0
- package/dist/lint/check.d.ts +81 -0
- package/dist/lint/check.js +208 -0
- package/dist/lint/check.js.map +1 -0
- package/dist/lint/config.d.ts +21 -0
- package/dist/lint/config.js +43 -0
- package/dist/lint/config.js.map +1 -0
- package/dist/lint/index.d.ts +31 -0
- package/dist/lint/index.js +43 -0
- package/dist/lint/index.js.map +1 -0
- package/dist/lint/project-rules.d.ts +19 -0
- package/dist/lint/project-rules.js +32 -0
- package/dist/lint/project-rules.js.map +1 -0
- package/dist/lint/report.d.ts +7 -0
- package/dist/lint/report.js +48 -0
- package/dist/lint/report.js.map +1 -0
- package/dist/lint/rules.d.ts +53 -0
- package/dist/lint/rules.js +42 -0
- package/dist/lint/rules.js.map +1 -0
- package/dist/lint/silences.d.ts +49 -0
- package/dist/lint/silences.js +91 -0
- package/dist/lint/silences.js.map +1 -0
- package/dist/lint/statements.d.ts +38 -0
- package/dist/lint/statements.js +120 -0
- package/dist/lint/statements.js.map +1 -0
- package/dist/migrations/checksum.d.ts +56 -0
- package/dist/migrations/checksum.js +72 -0
- package/dist/migrations/checksum.js.map +1 -0
- package/dist/migrations/create.d.ts +73 -0
- package/dist/migrations/create.js +119 -0
- package/dist/migrations/create.js.map +1 -0
- package/dist/migrations/directory.d.ts +119 -0
- package/dist/migrations/directory.js +225 -0
- package/dist/migrations/directory.js.map +1 -0
- package/dist/migrations/document.d.ts +83 -0
- package/dist/migrations/document.js +82 -0
- package/dist/migrations/document.js.map +1 -0
- package/dist/migrations/index.d.ts +20 -0
- package/dist/migrations/index.js +21 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/pr/comment.d.ts +32 -0
- package/dist/pr/comment.js +99 -0
- package/dist/pr/comment.js.map +1 -0
- package/dist/pr/forge.d.ts +50 -0
- package/dist/pr/forge.js +105 -0
- package/dist/pr/forge.js.map +1 -0
- package/dist/pr/model.d.ts +91 -0
- package/dist/pr/model.js +113 -0
- package/dist/pr/model.js.map +1 -0
- package/dist/pr/render.d.ts +27 -0
- package/dist/pr/render.js +246 -0
- package/dist/pr/render.js.map +1 -0
- package/dist/project.d.ts +62 -0
- package/dist/project.js +92 -0
- package/dist/project.js.map +1 -0
- package/dist/rebase/index.d.ts +121 -0
- package/dist/rebase/index.js +390 -0
- package/dist/rebase/index.js.map +1 -0
- package/dist/rebase/repair.d.ts +41 -0
- package/dist/rebase/repair.js +68 -0
- package/dist/rebase/repair.js.map +1 -0
- package/dist/replay/clickhouse.d.ts +33 -0
- package/dist/replay/clickhouse.js +106 -0
- package/dist/replay/clickhouse.js.map +1 -0
- package/dist/replay/index.d.ts +36 -0
- package/dist/replay/index.js +54 -0
- package/dist/replay/index.js.map +1 -0
- package/dist/replay/postgres.d.ts +31 -0
- package/dist/replay/postgres.js +140 -0
- package/dist/replay/postgres.js.map +1 -0
- package/dist/replay/replay.d.ts +114 -0
- package/dist/replay/replay.js +98 -0
- package/dist/replay/replay.js.map +1 -0
- package/dist/replay/report.d.ts +18 -0
- package/dist/replay/report.js +72 -0
- package/dist/replay/report.js.map +1 -0
- package/dist/steps/backfill.d.ts +128 -0
- package/dist/steps/backfill.js +307 -0
- package/dist/steps/backfill.js.map +1 -0
- package/dist/steps/index.d.ts +52 -0
- package/dist/steps/index.js +52 -0
- package/dist/steps/index.js.map +1 -0
- package/dist/steps/kinds.d.ts +101 -0
- package/dist/steps/kinds.js +143 -0
- package/dist/steps/kinds.js.map +1 -0
- package/dist/steps/postgres-migration.d.ts +95 -0
- package/dist/steps/postgres-migration.js +149 -0
- package/dist/steps/postgres-migration.js.map +1 -0
- package/dist/steps/rebuild.d.ts +97 -0
- package/dist/steps/rebuild.js +162 -0
- package/dist/steps/rebuild.js.map +1 -0
- package/dist/steps/run.d.ts +45 -0
- package/dist/steps/run.js +72 -0
- package/dist/steps/run.js.map +1 -0
- package/dist/topology/render.d.ts +17 -0
- package/dist/topology/render.js +17 -0
- package/dist/topology/render.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +11 -0
- package/dist/version.js.map +1 -0
- package/dist/versioned/approval.d.ts +35 -0
- package/dist/versioned/approval.js +53 -0
- package/dist/versioned/approval.js.map +1 -0
- package/dist/versioned/clickhouse.d.ts +24 -0
- package/dist/versioned/clickhouse.js +34 -0
- package/dist/versioned/clickhouse.js.map +1 -0
- package/dist/versioned/digest.d.ts +77 -0
- package/dist/versioned/digest.js +69 -0
- package/dist/versioned/digest.js.map +1 -0
- package/dist/versioned/driver.d.ts +41 -0
- package/dist/versioned/driver.js +13 -0
- package/dist/versioned/driver.js.map +1 -0
- package/dist/versioned/engine.d.ts +152 -0
- package/dist/versioned/engine.js +277 -0
- package/dist/versioned/engine.js.map +1 -0
- package/dist/versioned/explain.d.ts +123 -0
- package/dist/versioned/explain.js +289 -0
- package/dist/versioned/explain.js.map +1 -0
- package/dist/versioned/index.d.ts +37 -0
- package/dist/versioned/index.js +54 -0
- package/dist/versioned/index.js.map +1 -0
- package/dist/versioned/op.d.ts +62 -0
- package/dist/versioned/op.js +153 -0
- package/dist/versioned/op.js.map +1 -0
- package/dist/versioned/postgres/catalog.d.ts +33 -0
- package/dist/versioned/postgres/catalog.js +34 -0
- package/dist/versioned/postgres/catalog.js.map +1 -0
- package/dist/versioned/postgres/driver.d.ts +69 -0
- package/dist/versioned/postgres/driver.js +113 -0
- package/dist/versioned/postgres/driver.js.map +1 -0
- package/dist/versioned/postgres/executor.d.ts +104 -0
- package/dist/versioned/postgres/executor.js +172 -0
- package/dist/versioned/postgres/executor.js.map +1 -0
- package/dist/versioned/postgres/index.d.ts +11 -0
- package/dist/versioned/postgres/index.js +12 -0
- package/dist/versioned/postgres/index.js.map +1 -0
- package/dist/versioned/report.d.ts +22 -0
- package/dist/versioned/report.js +81 -0
- package/dist/versioned/report.js.map +1 -0
- package/dist/versioned/state.d.ts +108 -0
- package/dist/versioned/state.js +153 -0
- package/dist/versioned/state.js.map +1 -0
- package/package.json +51 -4
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `yodel lint` over a migrations directory: every rule in `./rules.ts`,
|
|
3
|
+
* offline, with no server. Optionally against one environment's history
|
|
4
|
+
* (`--env`), which turns the checksum rule from "the files changed since
|
|
5
|
+
* yodel wrote them" into "an applied migration changed since it ran".
|
|
6
|
+
*
|
|
7
|
+
* Rules that need more than the directory, such as the replay check (#11),
|
|
8
|
+
* plug in as {@link ProjectRule}s through {@link LintOptions.rules}.
|
|
9
|
+
*/
|
|
10
|
+
import { diffStatements } from "@intentius/chant-lexicon-sql/migration-statements";
|
|
11
|
+
import { emptyBuild, scanMigrations } from "../migrations/index.js";
|
|
12
|
+
import { levelOf } from "./config.js";
|
|
13
|
+
import { LINT_RULES } from "./rules.js";
|
|
14
|
+
import { mapMigrationSql } from "./silences.js";
|
|
15
|
+
import { refusedStep, stepFindings, unreadableStep } from "./statements.js";
|
|
16
|
+
const message = (e) => (e instanceof Error ? e.message : String(e)).split("\n")[0] ?? "";
|
|
17
|
+
const UPDATE = "if it is not applied in any environment, record its new checksum with yodel lint --update-checksum <id>; if it is, undo the edit, or record it with yodel repair <id> --reason ... <env>";
|
|
18
|
+
function directoryFindings(problems, history) {
|
|
19
|
+
const out = [];
|
|
20
|
+
for (const p of problems) {
|
|
21
|
+
switch (p.kind) {
|
|
22
|
+
case "fork":
|
|
23
|
+
out.push({ rule: "fork", message: p.message });
|
|
24
|
+
break;
|
|
25
|
+
case "checksum": {
|
|
26
|
+
if (history) {
|
|
27
|
+
const applied = history.status.applied.find((a) => a.id === p.id && a.index !== undefined);
|
|
28
|
+
// Applied: the history decides (below). Pending: an edit before it runs is allowed; say so.
|
|
29
|
+
if (!applied) {
|
|
30
|
+
out.push({
|
|
31
|
+
rule: "checksum",
|
|
32
|
+
level: "warning",
|
|
33
|
+
migration: p.id,
|
|
34
|
+
message: `${p.message}. It is not applied in ${history.environment}, so the edit is allowed there; record the new checksum with yodel lint --update-checksum ${p.id}`,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
out.push({ rule: "checksum", migration: p.id, message: `${p.message}; ${UPDATE.replaceAll("<id>", p.id)}` });
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
case "missing-parent":
|
|
43
|
+
case "id-mismatch":
|
|
44
|
+
out.push({ rule: "directory", migration: p.id, message: p.message });
|
|
45
|
+
break;
|
|
46
|
+
case "unreachable":
|
|
47
|
+
out.push({ rule: "directory", message: p.message });
|
|
48
|
+
break;
|
|
49
|
+
case "unreadable":
|
|
50
|
+
out.push({ rule: "directory", message: p.message });
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (history) {
|
|
55
|
+
for (const mm of history.status.mismatches) {
|
|
56
|
+
out.push({ rule: "checksum", migration: mm.id, ...(mm.kind === "part-way" ? { step: mm.statement } : {}), message: `${history.environment}: ${mm.message}` });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return out;
|
|
60
|
+
}
|
|
61
|
+
/** The objects of a build that the lexicon cannot read, each alone; `[]` when it reads them all. */
|
|
62
|
+
function unreadableObjects(schema, options) {
|
|
63
|
+
const empty = emptyBuild(schema);
|
|
64
|
+
const out = [];
|
|
65
|
+
for (const o of schema.objects) {
|
|
66
|
+
try {
|
|
67
|
+
diffStatements(empty, { ...schema, objects: [{ ...o, dependsOn: [] }] }, options);
|
|
68
|
+
}
|
|
69
|
+
catch (e) {
|
|
70
|
+
out.push({ export: o.export, type: o.type ?? "", ddl: o.ddl, error: message(e) });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return out;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* The lexicon reads every migration's recorded schema: the diff from its
|
|
77
|
+
* parent's schema to its own is made again, as `yodel new` made it. An
|
|
78
|
+
* object it cannot read is reported once, in the first migration that
|
|
79
|
+
* records it; a failure no single object explains is reported whole.
|
|
80
|
+
*/
|
|
81
|
+
function schemaFindings(migrations, dialect) {
|
|
82
|
+
const out = [];
|
|
83
|
+
const byId = new Map(migrations.map((m) => [m.id, m]));
|
|
84
|
+
const reported = new Set();
|
|
85
|
+
for (const m of migrations) {
|
|
86
|
+
const doc = m.document;
|
|
87
|
+
const schema = doc.schema;
|
|
88
|
+
const recorded = doc.dialect;
|
|
89
|
+
if (recorded !== "clickhouse" && recorded !== "postgres") {
|
|
90
|
+
out.push({ rule: "directory", migration: m.id, message: `${m.id}/migration.json: dialect ${JSON.stringify(recorded)} is neither clickhouse nor postgres` });
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (dialect !== undefined && recorded !== dialect) {
|
|
94
|
+
out.push({ rule: "directory", migration: m.id, message: `${m.id} is a ${recorded} migration, but the project's dialect is ${dialect}` });
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
if (!Array.isArray(schema.objects) || schema.dialect !== recorded) {
|
|
98
|
+
out.push({ rule: "unreadable-object", migration: m.id, message: `${m.id}: its recorded schema is not a ${recorded} build output (a dialect and a list of objects)` });
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
const parent = m.parent === null ? undefined : byId.get(m.parent)?.document.schema;
|
|
102
|
+
const before = parent && Array.isArray(parent.objects) && parent.dialect === schema.dialect ? parent : emptyBuild(schema);
|
|
103
|
+
const options = {
|
|
104
|
+
...(doc.defaultDatabase !== undefined ? { defaultDatabase: doc.defaultDatabase } : {}),
|
|
105
|
+
...(doc.defaultSchema !== undefined ? { defaultSchema: doc.defaultSchema } : {}),
|
|
106
|
+
};
|
|
107
|
+
try {
|
|
108
|
+
diffStatements(before, schema, options);
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
catch (e) {
|
|
112
|
+
const bad = unreadableObjects(schema, options);
|
|
113
|
+
for (const o of bad) {
|
|
114
|
+
const key = `${o.export}\u0000${o.type}\u0000${o.ddl}`;
|
|
115
|
+
if (reported.has(key))
|
|
116
|
+
continue;
|
|
117
|
+
reported.add(key);
|
|
118
|
+
out.push({ rule: "unreadable-object", migration: m.id, object: o.export, message: `${o.export} (${o.type || "no type"}) in ${m.id}'s recorded schema: the sql lexicon cannot read it: ${o.error}` });
|
|
119
|
+
}
|
|
120
|
+
if (bad.length === 0)
|
|
121
|
+
out.push({ rule: "unreadable-object", migration: m.id, message: `${m.id}: the sql lexicon cannot read its recorded schema against its parent's: ${message(e)}` });
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return out;
|
|
125
|
+
}
|
|
126
|
+
const stepName = (s) => (typeof s.name === "string" ? s.name : undefined);
|
|
127
|
+
/** Lints the migrations in `dir`. Never throws on what it finds; a finding is a result. */
|
|
128
|
+
export async function lintMigrations(dir, options = {}) {
|
|
129
|
+
const scan = scanMigrations(dir);
|
|
130
|
+
const extra = options.rules ?? [];
|
|
131
|
+
const rules = { ...LINT_RULES, ...Object.fromEntries(extra.map((r) => [r.rule.id, r.rule])) };
|
|
132
|
+
const dialect = options.dialect;
|
|
133
|
+
const raw = [...directoryFindings(scan.problems, options.history), ...schemaFindings(scan.migrations, dialect)];
|
|
134
|
+
const silenceable = new Set(Object.values(rules).filter((r) => r.silenceable).map((r) => r.id));
|
|
135
|
+
const silences = {};
|
|
136
|
+
const used = new Set();
|
|
137
|
+
const statementRaw = [];
|
|
138
|
+
for (const m of scan.migrations) {
|
|
139
|
+
const d = m.document.dialect;
|
|
140
|
+
if (d !== "clickhouse" && d !== "postgres")
|
|
141
|
+
continue; // reported above
|
|
142
|
+
const steps = m.document.steps;
|
|
143
|
+
const map = mapMigrationSql(m.files.sql, steps, silenceable);
|
|
144
|
+
silences[m.id] = map.silences;
|
|
145
|
+
for (const p of map.problems)
|
|
146
|
+
raw.push({ rule: p.rule, migration: m.id, message: p.message, ...(p.step !== undefined ? { step: p.step } : {}), ...(p.line !== undefined ? { line: p.line } : {}) });
|
|
147
|
+
steps.forEach((step, i) => {
|
|
148
|
+
const name = stepName(step);
|
|
149
|
+
const where = { migration: m.id, step: i, ...(name !== undefined ? { object: name } : {}) };
|
|
150
|
+
const unreadable = unreadableStep(d, step);
|
|
151
|
+
if (unreadable) {
|
|
152
|
+
raw.push({ rule: "unreadable-object", ...where, message: `step ${String(i)}: ${unreadable}` });
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
const refused = refusedStep(step);
|
|
156
|
+
if (refused)
|
|
157
|
+
raw.push({ rule: "refused-step", ...where, message: `step ${String(i)}: yodel apply refuses ${refused}` });
|
|
158
|
+
for (const f of stepFindings(d, step)) {
|
|
159
|
+
const rule = rules[f.rule];
|
|
160
|
+
if (rule?.dialect !== undefined && rule.dialect !== d)
|
|
161
|
+
continue;
|
|
162
|
+
const silence = map.silences.find((s) => s.step === i && s.rule === f.rule);
|
|
163
|
+
if (silence)
|
|
164
|
+
used.add(silence);
|
|
165
|
+
statementRaw.push({ rule: f.rule, ...where, message: `step ${String(i)}: ${f.message}`, ...(silence ? { silence } : {}) });
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
for (const s of map.silences) {
|
|
169
|
+
if (used.has(s))
|
|
170
|
+
continue;
|
|
171
|
+
raw.push({ rule: "silence", level: "warning", migration: m.id, step: s.step, line: s.line, message: `migration.sql line ${String(s.line)}: yodel:allow ${s.rule} silences nothing: step ${String(s.step)} breaks no ${s.rule} rule` });
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
for (const r of extra) {
|
|
175
|
+
try {
|
|
176
|
+
raw.push(...(await r.check({ dir: scan.dir, scan, dialect, project: options.project })));
|
|
177
|
+
}
|
|
178
|
+
catch (e) {
|
|
179
|
+
raw.push({ rule: r.rule.id, message: `${r.rule.id} could not run: ${message(e)}` });
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
const findings = [];
|
|
183
|
+
for (const f of [...raw, ...statementRaw]) {
|
|
184
|
+
const rule = rules[f.rule];
|
|
185
|
+
const setting = rule ? levelOf(rule, options.settings) : "error";
|
|
186
|
+
if (setting === "off")
|
|
187
|
+
continue;
|
|
188
|
+
const { silence, level, ...rest } = f;
|
|
189
|
+
findings.push({ ...rest, level: level ?? setting, ...(silence ? { silenced: silence.reason } : {}) });
|
|
190
|
+
}
|
|
191
|
+
findings.sort((a, b) => (a.migration ?? "").localeCompare(b.migration ?? "") ||
|
|
192
|
+
(a.step ?? -1) - (b.step ?? -1) ||
|
|
193
|
+
(a.line ?? 0) - (b.line ?? 0) ||
|
|
194
|
+
a.rule.localeCompare(b.rule));
|
|
195
|
+
const live = findings.filter((f) => f.silenced === undefined);
|
|
196
|
+
return {
|
|
197
|
+
dir: scan.dir,
|
|
198
|
+
dialect,
|
|
199
|
+
environment: options.history?.environment,
|
|
200
|
+
migrations: scan.migrations.map((m) => m.id),
|
|
201
|
+
findings,
|
|
202
|
+
silences,
|
|
203
|
+
errors: live.filter((f) => f.level === "error").length,
|
|
204
|
+
warnings: live.filter((f) => f.level === "warning").length,
|
|
205
|
+
silenced: findings.length - live.length,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
//# sourceMappingURL=check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.js","sourceRoot":"","sources":["../../src/lint/check.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule levels from `yodel.config.ts`:
|
|
3
|
+
*
|
|
4
|
+
* ```ts
|
|
5
|
+
* export default defineConfig({
|
|
6
|
+
* lint: { rules: { "ch-mutation": "warning", "pg-lock": "off" } },
|
|
7
|
+
* });
|
|
8
|
+
* ```
|
|
9
|
+
*
|
|
10
|
+
* A level is `error` (fails the run), `warning` (reported, does not fail)
|
|
11
|
+
* or `off`. The integrity rules (`fork`, `directory`, `checksum`,
|
|
12
|
+
* `unreadable-object`) are always errors and cannot be set.
|
|
13
|
+
*/
|
|
14
|
+
import type { LevelSetting, LintRule } from "./rules.js";
|
|
15
|
+
export interface LintSettings {
|
|
16
|
+
levels: Record<string, LevelSetting>;
|
|
17
|
+
}
|
|
18
|
+
/** Checks `lint` from `yodel.config.ts` against the rules there are. `where` names the file in errors. */
|
|
19
|
+
export declare function lintSettings(raw: Record<string, unknown> | undefined, rules: Readonly<Record<string, LintRule>>, where?: string): LintSettings;
|
|
20
|
+
/** The level a rule runs at. */
|
|
21
|
+
export declare const levelOf: (rule: LintRule, settings: LintSettings | undefined) => LevelSetting;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule levels from `yodel.config.ts`:
|
|
3
|
+
*
|
|
4
|
+
* ```ts
|
|
5
|
+
* export default defineConfig({
|
|
6
|
+
* lint: { rules: { "ch-mutation": "warning", "pg-lock": "off" } },
|
|
7
|
+
* });
|
|
8
|
+
* ```
|
|
9
|
+
*
|
|
10
|
+
* A level is `error` (fails the run), `warning` (reported, does not fail)
|
|
11
|
+
* or `off`. The integrity rules (`fork`, `directory`, `checksum`,
|
|
12
|
+
* `unreadable-object`) are always errors and cannot be set.
|
|
13
|
+
*/
|
|
14
|
+
import { YodelError } from "../project.js";
|
|
15
|
+
const isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
16
|
+
const LEVELS = ["error", "warning", "off"];
|
|
17
|
+
/** Checks `lint` from `yodel.config.ts` against the rules there are. `where` names the file in errors. */
|
|
18
|
+
export function lintSettings(raw, rules, where = "yodel.config.ts") {
|
|
19
|
+
const levels = {};
|
|
20
|
+
if (raw === undefined)
|
|
21
|
+
return { levels };
|
|
22
|
+
for (const k of Object.keys(raw))
|
|
23
|
+
if (k !== "rules")
|
|
24
|
+
throw new YodelError(`${where}: lint.${k}: unknown setting (expected rules)`);
|
|
25
|
+
if (raw.rules === undefined)
|
|
26
|
+
return { levels };
|
|
27
|
+
if (!isRecord(raw.rules))
|
|
28
|
+
throw new YodelError(`${where}: lint.rules: expected an object of rule: "error" | "warning" | "off"`);
|
|
29
|
+
for (const [id, level] of Object.entries(raw.rules)) {
|
|
30
|
+
const rule = rules[id];
|
|
31
|
+
if (!rule)
|
|
32
|
+
throw new YodelError(`${where}: lint.rules.${id}: no such rule (the rules: ${Object.keys(rules).join(", ")})`);
|
|
33
|
+
if (typeof level !== "string" || !LEVELS.includes(level))
|
|
34
|
+
throw new YodelError(`${where}: lint.rules.${id}: expected "error", "warning" or "off"`);
|
|
35
|
+
if (!rule.configurable && level !== "error")
|
|
36
|
+
throw new YodelError(`${where}: lint.rules.${id}: ${id} is an integrity rule and is always an error`);
|
|
37
|
+
levels[id] = level;
|
|
38
|
+
}
|
|
39
|
+
return { levels };
|
|
40
|
+
}
|
|
41
|
+
/** The level a rule runs at. */
|
|
42
|
+
export const levelOf = (rule, settings) => settings?.levels[rule.id] ?? rule.level;
|
|
43
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lint/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAO3C,MAAM,QAAQ,GAAG,CAAC,CAAU,EAAgC,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACxH,MAAM,MAAM,GAAsB,CAAC,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;AAE9D,0GAA0G;AAC1G,MAAM,UAAU,YAAY,CAAC,GAAwC,EAAE,KAAyC,EAAE,KAAK,GAAG,iBAAiB;IACzI,MAAM,MAAM,GAAiC,EAAE,CAAC;IAChD,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IACzC,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,IAAI,CAAC,KAAK,OAAO;YAAE,MAAM,IAAI,UAAU,CAAC,GAAG,KAAK,UAAU,CAAC,oCAAoC,CAAC,CAAC;IACnI,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS;QAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAC/C,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,GAAG,KAAK,uEAAuE,CAAC,CAAC;IAChI,KAAK,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QACpD,MAAM,IAAI,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC;QACvB,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,UAAU,CAAC,GAAG,KAAK,gBAAgB,EAAE,8BAA8B,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC1H,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,MAAM,IAAI,UAAU,CAAC,GAAG,KAAK,gBAAgB,EAAE,wCAAwC,CAAC,CAAC;QACnJ,IAAI,CAAC,IAAI,CAAC,YAAY,IAAI,KAAK,KAAK,OAAO;YAAE,MAAM,IAAI,UAAU,CAAC,GAAG,KAAK,gBAAgB,EAAE,KAAK,EAAE,8CAA8C,CAAC,CAAC;QACnJ,MAAM,CAAC,EAAE,CAAC,GAAG,KAAqB,CAAC;IACrC,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,CAAC;AACpB,CAAC;AAED,gCAAgC;AAChC,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,IAAc,EAAE,QAAkC,EAAgB,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `yodel lint` (#14): rules over a migrations directory, free, for CI.
|
|
3
|
+
*
|
|
4
|
+
* lintMigrations(dir, options) every finding, with levels and silences applied
|
|
5
|
+
* migrationSilences(m) a migration's `-- yodel:allow` lines, as the history records them
|
|
6
|
+
* updateChecksum(m) writes migration.json's checksum to match its files
|
|
7
|
+
* renderLint / lintJson the output; lintExitCode the exit code
|
|
8
|
+
*
|
|
9
|
+
* The rules are in `./rules.ts`, how a silence is read in `./silences.ts`.
|
|
10
|
+
*/
|
|
11
|
+
import { type Migration } from "../migrations/index.js";
|
|
12
|
+
import { type Silence } from "./silences.js";
|
|
13
|
+
export * from "./check.js";
|
|
14
|
+
export * from "./config.js";
|
|
15
|
+
export * from "./report.js";
|
|
16
|
+
export * from "./rules.js";
|
|
17
|
+
export * from "./silences.js";
|
|
18
|
+
export * from "./statements.js";
|
|
19
|
+
/** The well-formed `-- yodel:allow` lines of a migration, each with the step it is above. */
|
|
20
|
+
export declare function silencesOf(m: Pick<Migration, "files" | "document">): Silence[];
|
|
21
|
+
/** {@link silencesOf} as the history's `silences` field holds it: a JSON array of `{ step, rule, reason }`. */
|
|
22
|
+
export declare const migrationSilences: (m: Pick<Migration, "files" | "document">) => string;
|
|
23
|
+
/**
|
|
24
|
+
* Writes `migration.json` again with its `checksum` matching the files, for
|
|
25
|
+
* a migration edited before it was applied anywhere (a silence added, say).
|
|
26
|
+
* Returns the old and new checksum, or `undefined` when they already match.
|
|
27
|
+
*/
|
|
28
|
+
export declare function updateChecksum(m: Migration): {
|
|
29
|
+
from: string;
|
|
30
|
+
to: string;
|
|
31
|
+
} | undefined;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `yodel lint` (#14): rules over a migrations directory, free, for CI.
|
|
3
|
+
*
|
|
4
|
+
* lintMigrations(dir, options) every finding, with levels and silences applied
|
|
5
|
+
* migrationSilences(m) a migration's `-- yodel:allow` lines, as the history records them
|
|
6
|
+
* updateChecksum(m) writes migration.json's checksum to match its files
|
|
7
|
+
* renderLint / lintJson the output; lintExitCode the exit code
|
|
8
|
+
*
|
|
9
|
+
* The rules are in `./rules.ts`, how a silence is read in `./silences.ts`.
|
|
10
|
+
*/
|
|
11
|
+
import { renameSync, writeFileSync } from "node:fs";
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
import { MIGRATION_JSON, serializeDocument, verifyChecksum } from "../migrations/index.js";
|
|
14
|
+
import { silenceableRules } from "./rules.js";
|
|
15
|
+
import { mapMigrationSql, silencesJson } from "./silences.js";
|
|
16
|
+
export * from "./check.js";
|
|
17
|
+
export * from "./config.js";
|
|
18
|
+
export * from "./report.js";
|
|
19
|
+
export * from "./rules.js";
|
|
20
|
+
export * from "./silences.js";
|
|
21
|
+
export * from "./statements.js";
|
|
22
|
+
/** The well-formed `-- yodel:allow` lines of a migration, each with the step it is above. */
|
|
23
|
+
export function silencesOf(m) {
|
|
24
|
+
return mapMigrationSql(m.files.sql, m.document.steps, new Set(silenceableRules())).silences;
|
|
25
|
+
}
|
|
26
|
+
/** {@link silencesOf} as the history's `silences` field holds it: a JSON array of `{ step, rule, reason }`. */
|
|
27
|
+
export const migrationSilences = (m) => silencesJson(silencesOf(m));
|
|
28
|
+
/**
|
|
29
|
+
* Writes `migration.json` again with its `checksum` matching the files, for
|
|
30
|
+
* a migration edited before it was applied anywhere (a silence added, say).
|
|
31
|
+
* Returns the old and new checksum, or `undefined` when they already match.
|
|
32
|
+
*/
|
|
33
|
+
export function updateChecksum(m) {
|
|
34
|
+
const check = verifyChecksum(m);
|
|
35
|
+
if (check.ok)
|
|
36
|
+
return undefined;
|
|
37
|
+
const path = join(m.dir, MIGRATION_JSON);
|
|
38
|
+
const tmp = join(m.dir, `.${MIGRATION_JSON}.updating`);
|
|
39
|
+
writeFileSync(tmp, serializeDocument({ ...JSON.parse(m.files.json), checksum: check.actual }));
|
|
40
|
+
renameSync(tmp, path);
|
|
41
|
+
return { from: check.recorded, to: check.actual };
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/lint/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,cAAc,EAAkB,MAAM,wBAAwB,CAAC;AAC3G,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,YAAY,EAAgB,MAAM,eAAe,CAAC;AAE5E,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAEhC,6FAA6F;AAC7F,MAAM,UAAU,UAAU,CAAC,CAAwC;IACjE,OAAO,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,EAAE,IAAI,GAAG,CAAS,gBAAgB,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;AACtG,CAAC;AAED,+GAA+G;AAC/G,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAwC,EAAU,EAAE,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAEnH;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,CAAY;IACzC,MAAM,KAAK,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;IAChC,IAAI,KAAK,CAAC,EAAE;QAAE,OAAO,SAAS,CAAC;IAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;IACzC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,cAAc,WAAW,CAAC,CAAC;IACvD,aAAa,CAAC,GAAG,EAAE,iBAAiB,CAAC,EAAE,GAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAA6B,EAAE,QAAQ,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC5H,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACtB,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,QAAQ,EAAE,EAAE,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC;AACpD,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The project-wide rules `yodel lint` runs after its own: rules that need
|
|
3
|
+
* more than the migrations directory, such as a server or the emulator.
|
|
4
|
+
*
|
|
5
|
+
* {@link projectRules} run on every lint. The replay check (#11,
|
|
6
|
+
* `../replay/`) runs only with `yodel lint --replay <env>`, because it needs
|
|
7
|
+
* a throwaway server: the command replays the history first (so a target
|
|
8
|
+
* that is not fresh refuses with the replay's own exit code, 4) and hands
|
|
9
|
+
* the result to {@link replayRule}, which turns a failure into a finding of
|
|
10
|
+
* rule `replay`. Its level comes from `yodel.config.ts` (`lint.rules.replay`)
|
|
11
|
+
* like a built-in rule's.
|
|
12
|
+
*/
|
|
13
|
+
import { type ReplayResult } from "../replay/index.js";
|
|
14
|
+
import type { ProjectRule } from "./check.js";
|
|
15
|
+
import type { LintRule } from "./rules.js";
|
|
16
|
+
export declare const projectRules: readonly ProjectRule[];
|
|
17
|
+
export declare const REPLAY_RULE: LintRule;
|
|
18
|
+
/** The replay's result as a rule: one finding naming the first migration that fails, or none. */
|
|
19
|
+
export declare function replayRule(result: ReplayResult): ProjectRule;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The project-wide rules `yodel lint` runs after its own: rules that need
|
|
3
|
+
* more than the migrations directory, such as a server or the emulator.
|
|
4
|
+
*
|
|
5
|
+
* {@link projectRules} run on every lint. The replay check (#11,
|
|
6
|
+
* `../replay/`) runs only with `yodel lint --replay <env>`, because it needs
|
|
7
|
+
* a throwaway server: the command replays the history first (so a target
|
|
8
|
+
* that is not fresh refuses with the replay's own exit code, 4) and hands
|
|
9
|
+
* the result to {@link replayRule}, which turns a failure into a finding of
|
|
10
|
+
* rule `replay`. Its level comes from `yodel.config.ts` (`lint.rules.replay`)
|
|
11
|
+
* like a built-in rule's.
|
|
12
|
+
*/
|
|
13
|
+
import { replayFailure } from "../replay/index.js";
|
|
14
|
+
export const projectRules = [];
|
|
15
|
+
export const REPLAY_RULE = {
|
|
16
|
+
id: "replay",
|
|
17
|
+
summary: "with --replay <env>: the history, replayed into a fresh database, does not give each migration's recorded schema",
|
|
18
|
+
level: "error",
|
|
19
|
+
silenceable: false,
|
|
20
|
+
configurable: true,
|
|
21
|
+
};
|
|
22
|
+
/** The replay's result as a rule: one finding naming the first migration that fails, or none. */
|
|
23
|
+
export function replayRule(result) {
|
|
24
|
+
return {
|
|
25
|
+
rule: REPLAY_RULE,
|
|
26
|
+
check: () => {
|
|
27
|
+
const failure = replayFailure(result);
|
|
28
|
+
return Promise.resolve(failure ? [{ rule: REPLAY_RULE.id, migration: failure.migration, message: failure.message }] : []);
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=project-rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-rules.js","sourceRoot":"","sources":["../../src/lint/project-rules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,aAAa,EAAqB,MAAM,oBAAoB,CAAC;AAItE,MAAM,CAAC,MAAM,YAAY,GAA2B,EAAE,CAAC;AAEvD,MAAM,CAAC,MAAM,WAAW,GAAa;IACnC,EAAE,EAAE,QAAQ;IACZ,OAAO,EAAE,kHAAkH;IAC3H,KAAK,EAAE,OAAO;IACd,WAAW,EAAE,KAAK;IAClB,YAAY,EAAE,IAAI;CACnB,CAAC;AAEF,iGAAiG;AACjG,MAAM,UAAU,UAAU,CAAC,MAAoB;IAC7C,OAAO;QACL,IAAI,EAAE,WAAW;QACjB,KAAK,EAAE,GAAG,EAAE;YACV,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;YACtC,OAAO,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC5H,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** `yodel lint`'s output: text for people, JSON for a CI job, and the exit code. */
|
|
2
|
+
import type { LintReport } from "./check.js";
|
|
3
|
+
/** Exit code: at least one finding at level error that no silence covers. */
|
|
4
|
+
export declare const LINT_FAILED = 3;
|
|
5
|
+
export declare const lintExitCode: (report: LintReport) => number;
|
|
6
|
+
export declare function renderLint(report: LintReport): string;
|
|
7
|
+
export declare function lintJson(report: LintReport): Record<string, unknown>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/** `yodel lint`'s output: text for people, JSON for a CI job, and the exit code. */
|
|
2
|
+
/** Exit code: at least one finding at level error that no silence covers. */
|
|
3
|
+
export const LINT_FAILED = 3;
|
|
4
|
+
export const lintExitCode = (report) => (report.errors > 0 ? LINT_FAILED : 0);
|
|
5
|
+
const plural = (n, one, many = `${one}s`) => `${String(n)} ${n === 1 ? one : many}`;
|
|
6
|
+
function line(f) {
|
|
7
|
+
const head = f.silenced !== undefined ? "silenced" : f.level;
|
|
8
|
+
const out = [` ${head.padEnd(8)} ${f.rule}: ${f.message}`];
|
|
9
|
+
if (f.silenced !== undefined)
|
|
10
|
+
out.push(` reason: ${f.silenced}`);
|
|
11
|
+
return out;
|
|
12
|
+
}
|
|
13
|
+
export function renderLint(report) {
|
|
14
|
+
const where = report.environment ? `, against ${report.environment}'s history` : "";
|
|
15
|
+
const out = [];
|
|
16
|
+
const groups = new Map();
|
|
17
|
+
for (const f of report.findings) {
|
|
18
|
+
const key = f.migration ?? "";
|
|
19
|
+
groups.set(key, [...(groups.get(key) ?? []), f]);
|
|
20
|
+
}
|
|
21
|
+
for (const [id, list] of groups) {
|
|
22
|
+
out.push(id === "" ? "migrations/" : id);
|
|
23
|
+
for (const f of list)
|
|
24
|
+
out.push(...line(f));
|
|
25
|
+
out.push("");
|
|
26
|
+
}
|
|
27
|
+
const silenceHint = report.findings.some((f) => f.silenced === undefined && f.level === "error" && ["destructive", "pg-rewrite", "pg-lock", "ch-mutation", "ch-rebuild"].includes(f.rule));
|
|
28
|
+
if (silenceHint) {
|
|
29
|
+
out.push("A statement rule can be silenced for one statement, with a reason the history records when it applies:", " a line `-- yodel:allow <rule> <reason>` above the statement in migration.sql", "");
|
|
30
|
+
}
|
|
31
|
+
const counts = [plural(report.errors, "error"), plural(report.warnings, "warning"), `${String(report.silenced)} silenced`].join(", ");
|
|
32
|
+
out.push(`${plural(report.migrations.length, "migration")}${where}: ${counts}.`);
|
|
33
|
+
return `${out.join("\n")}\n`;
|
|
34
|
+
}
|
|
35
|
+
export function lintJson(report) {
|
|
36
|
+
return {
|
|
37
|
+
status: report.errors > 0 ? "failed" : "passed",
|
|
38
|
+
...(report.environment ? { environment: report.environment } : {}),
|
|
39
|
+
dialect: report.dialect ?? null,
|
|
40
|
+
migrations: report.migrations,
|
|
41
|
+
errors: report.errors,
|
|
42
|
+
warnings: report.warnings,
|
|
43
|
+
silenced: report.silenced,
|
|
44
|
+
findings: report.findings,
|
|
45
|
+
silences: report.silences,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/lint/report.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `yodel lint`'s rules: what each checks, its level unless `yodel.config.ts`
|
|
3
|
+
* sets another, and whether a statement can silence it.
|
|
4
|
+
*
|
|
5
|
+
* Two kinds:
|
|
6
|
+
*
|
|
7
|
+
* - Integrity rules, over the directory and each migration as a whole:
|
|
8
|
+
* `fork`, `directory`, `checksum`, `unreadable-object`. Always errors; no
|
|
9
|
+
* config lowers them and nothing silences them, because a migration that
|
|
10
|
+
* breaks one cannot be applied safely or cannot be checked at all.
|
|
11
|
+
* - Statement rules, from the classes chant's classifier gives each step:
|
|
12
|
+
* `destructive`, `pg-rewrite`, `pg-lock`, `ch-mutation`, `ch-rebuild`.
|
|
13
|
+
* Errors by default; a line `-- yodel:allow <rule> <reason>` above the
|
|
14
|
+
* statement in `migration.sql` silences one for that statement, and the
|
|
15
|
+
* reason is recorded in the history when the migration applies.
|
|
16
|
+
*
|
|
17
|
+
* The rest (`refused-step`, `migration-sql`, `silence`) say a migration
|
|
18
|
+
* will not apply as written or a silence is wrong. Their level can be
|
|
19
|
+
* changed in `yodel.config.ts`, but they cannot be silenced.
|
|
20
|
+
*/
|
|
21
|
+
export type LintLevel = "error" | "warning";
|
|
22
|
+
export type LevelSetting = LintLevel | "off";
|
|
23
|
+
export interface LintRule {
|
|
24
|
+
id: string;
|
|
25
|
+
/** One line, for `yodel lint --rules` and the docs. */
|
|
26
|
+
summary: string;
|
|
27
|
+
level: LintLevel;
|
|
28
|
+
/** A `-- yodel:allow <id> <reason>` line can silence it for one statement. */
|
|
29
|
+
silenceable: boolean;
|
|
30
|
+
/** `yodel.config.ts` `lint.rules` may change its level. */
|
|
31
|
+
configurable: boolean;
|
|
32
|
+
/** The dialect it applies to; both when absent. */
|
|
33
|
+
dialect?: "clickhouse" | "postgres";
|
|
34
|
+
}
|
|
35
|
+
export declare const LINT_RULES: {
|
|
36
|
+
readonly fork: LintRule;
|
|
37
|
+
readonly directory: LintRule;
|
|
38
|
+
readonly checksum: LintRule;
|
|
39
|
+
readonly "unreadable-object": LintRule;
|
|
40
|
+
readonly destructive: LintRule;
|
|
41
|
+
readonly "pg-rewrite": LintRule;
|
|
42
|
+
readonly "pg-lock": LintRule;
|
|
43
|
+
readonly "ch-mutation": LintRule;
|
|
44
|
+
readonly "ch-rebuild": LintRule;
|
|
45
|
+
readonly "refused-step": LintRule;
|
|
46
|
+
readonly "migration-sql": LintRule;
|
|
47
|
+
readonly silence: LintRule;
|
|
48
|
+
};
|
|
49
|
+
export type LintRuleId = keyof typeof LINT_RULES;
|
|
50
|
+
export declare const ruleIds: LintRuleId[];
|
|
51
|
+
export declare const isRuleId: (id: string) => id is LintRuleId;
|
|
52
|
+
/** The rules a `-- yodel:allow` line can name. */
|
|
53
|
+
export declare const silenceableRules: () => LintRuleId[];
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `yodel lint`'s rules: what each checks, its level unless `yodel.config.ts`
|
|
3
|
+
* sets another, and whether a statement can silence it.
|
|
4
|
+
*
|
|
5
|
+
* Two kinds:
|
|
6
|
+
*
|
|
7
|
+
* - Integrity rules, over the directory and each migration as a whole:
|
|
8
|
+
* `fork`, `directory`, `checksum`, `unreadable-object`. Always errors; no
|
|
9
|
+
* config lowers them and nothing silences them, because a migration that
|
|
10
|
+
* breaks one cannot be applied safely or cannot be checked at all.
|
|
11
|
+
* - Statement rules, from the classes chant's classifier gives each step:
|
|
12
|
+
* `destructive`, `pg-rewrite`, `pg-lock`, `ch-mutation`, `ch-rebuild`.
|
|
13
|
+
* Errors by default; a line `-- yodel:allow <rule> <reason>` above the
|
|
14
|
+
* statement in `migration.sql` silences one for that statement, and the
|
|
15
|
+
* reason is recorded in the history when the migration applies.
|
|
16
|
+
*
|
|
17
|
+
* The rest (`refused-step`, `migration-sql`, `silence`) say a migration
|
|
18
|
+
* will not apply as written or a silence is wrong. Their level can be
|
|
19
|
+
* changed in `yodel.config.ts`, but they cannot be silenced.
|
|
20
|
+
*/
|
|
21
|
+
const integrity = (id, summary) => ({ id, summary, level: "error", silenceable: false, configurable: false });
|
|
22
|
+
const statement = (id, summary, dialect) => ({ id, summary, level: "error", silenceable: true, configurable: true, ...(dialect ? { dialect } : {}) });
|
|
23
|
+
const shape = (id, summary, level = "error") => ({ id, summary, level, silenceable: false, configurable: true });
|
|
24
|
+
export const LINT_RULES = {
|
|
25
|
+
fork: integrity("fork", "two migrations follow the same parent; rebase one onto the other (yodel rebase)"),
|
|
26
|
+
directory: integrity("directory", "the migrations directory is not one readable chain: a bad name or file, a missing parent, a cycle, another dialect"),
|
|
27
|
+
checksum: integrity("checksum", "a migration's files no longer hash to its checksum: an edit after it was written, or (with --env) after it was applied"),
|
|
28
|
+
"unreadable-object": integrity("unreadable-object", "an object in a recorded schema, or a step, the sql lexicon cannot read or classify; never skipped"),
|
|
29
|
+
destructive: statement("destructive", "a statement or Op step removes data that cannot be recovered (a table or column drop)"),
|
|
30
|
+
"pg-rewrite": statement("pg-rewrite", "Postgres: rewrites or scans the whole table under ACCESS EXCLUSIVE, blocking reads and writes while it runs", "postgres"),
|
|
31
|
+
"pg-lock": statement("pg-lock", "Postgres: holds a lock that blocks writes for a whole scan or index build (an index without CONCURRENTLY, a constraint validated in place)", "postgres"),
|
|
32
|
+
"ch-mutation": statement("ch-mutation", "ClickHouse: starts a mutation that rewrites existing parts in the background, with no rollback", "clickhouse"),
|
|
33
|
+
"ch-rebuild": statement("ch-rebuild", "ClickHouse: a rebuild, every row copied into a new table and swapped in (ClickHouseRebuildOp)", "clickhouse"),
|
|
34
|
+
"refused-step": shape("refused-step", "a step yodel apply refuses to run: a manual step, or an Op step it does not run"),
|
|
35
|
+
"migration-sql": shape("migration-sql", "migration.sql does not hold a statement as migration.json records it; apply runs migration.json's"),
|
|
36
|
+
silence: shape("silence", "a yodel:allow line that is malformed, names a rule no statement can silence, has no reason, or silences nothing"),
|
|
37
|
+
};
|
|
38
|
+
export const ruleIds = Object.keys(LINT_RULES);
|
|
39
|
+
export const isRuleId = (id) => Object.hasOwn(LINT_RULES, id);
|
|
40
|
+
/** The rules a `-- yodel:allow` line can name. */
|
|
41
|
+
export const silenceableRules = () => ruleIds.filter((id) => LINT_RULES[id].silenceable);
|
|
42
|
+
//# sourceMappingURL=rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules.js","sourceRoot":"","sources":["../../src/lint/rules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAkBH,MAAM,SAAS,GAAG,CAAC,EAAU,EAAE,OAAe,EAAY,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,CAAC;AACxI,MAAM,SAAS,GAAG,CAAC,EAAU,EAAE,OAAe,EAAE,OAA6B,EAAY,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AACtM,MAAM,KAAK,GAAG,CAAC,EAAU,EAAE,OAAe,EAAE,QAAmB,OAAO,EAAY,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;AAEtJ,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,IAAI,EAAE,SAAS,CAAC,MAAM,EAAE,iFAAiF,CAAC;IAC1G,SAAS,EAAE,SAAS,CAAC,WAAW,EAAE,oHAAoH,CAAC;IACvJ,QAAQ,EAAE,SAAS,CAAC,UAAU,EAAE,wHAAwH,CAAC;IACzJ,mBAAmB,EAAE,SAAS,CAAC,mBAAmB,EAAE,mGAAmG,CAAC;IACxJ,WAAW,EAAE,SAAS,CAAC,aAAa,EAAE,uFAAuF,CAAC;IAC9H,YAAY,EAAE,SAAS,CAAC,YAAY,EAAE,6GAA6G,EAAE,UAAU,CAAC;IAChK,SAAS,EAAE,SAAS,CAAC,SAAS,EAAE,4IAA4I,EAAE,UAAU,CAAC;IACzL,aAAa,EAAE,SAAS,CAAC,aAAa,EAAE,gGAAgG,EAAE,YAAY,CAAC;IACvJ,YAAY,EAAE,SAAS,CAAC,YAAY,EAAE,+FAA+F,EAAE,YAAY,CAAC;IACpJ,cAAc,EAAE,KAAK,CAAC,cAAc,EAAE,iFAAiF,CAAC;IACxH,eAAe,EAAE,KAAK,CAAC,eAAe,EAAE,mGAAmG,CAAC;IAC5I,OAAO,EAAE,KAAK,CAAC,SAAS,EAAE,iHAAiH,CAAC;CACjG,CAAC;AAI9C,MAAM,CAAC,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,CAAiB,CAAC;AAE/D,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,EAAU,EAAoB,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;AAExF,kDAAkD;AAClD,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAiB,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC"}
|