@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,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Promotion (#43): an environment applies only migrations the environment
|
|
3
|
+
* before it recorded as applied.
|
|
4
|
+
*
|
|
5
|
+
* `waves[].requires` names that environment; it defaults to the wave
|
|
6
|
+
* before, and `false` turns it off. Before anything is applied (and before
|
|
7
|
+
* the gate), `yodel apply <env>` reads each required environment's history
|
|
8
|
+
* with that environment's own profile, which outside an apply job is its
|
|
9
|
+
* reader, and refuses (exit 4) any pending migration the history does not
|
|
10
|
+
* record as applied with the checksum its files have now. The requirement
|
|
11
|
+
* is read from the working tree's yodel.config.ts and from the base
|
|
12
|
+
* commit's, and both are enforced, so a change that drops its own
|
|
13
|
+
* requirement is still held to the base's.
|
|
14
|
+
*/
|
|
15
|
+
import type { YodelConfig } from "../config/define.js";
|
|
16
|
+
import type { Migration } from "../migrations/index.js";
|
|
17
|
+
import { YodelError, type Project } from "../project.js";
|
|
18
|
+
import type { PendingMigration } from "../versioned/state.js";
|
|
19
|
+
/** The environment `env` requires in `config`: `requires`, else the wave before; undefined for none. */
|
|
20
|
+
export declare function requiredIn(config: YodelConfig | undefined, env: string): string | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* Each required environment and where the requirement comes from: the
|
|
23
|
+
* working tree, the base commit, or both. A tenant (#56) requires what its
|
|
24
|
+
* environment requires: the same tenant when that environment has a tenant
|
|
25
|
+
* set too, else the environment.
|
|
26
|
+
*/
|
|
27
|
+
export declare function requiredEnvironments(project: Project, env: string): Promise<Array<{
|
|
28
|
+
env: string;
|
|
29
|
+
from: string;
|
|
30
|
+
}>>;
|
|
31
|
+
/** What one required environment's history says of each pending migration. */
|
|
32
|
+
export interface Promotion {
|
|
33
|
+
/** The required environment. */
|
|
34
|
+
env: string;
|
|
35
|
+
from: string;
|
|
36
|
+
migrations: Array<{
|
|
37
|
+
id: string;
|
|
38
|
+
checksum: string;
|
|
39
|
+
ran: "applied" | "not applied" | "applied with another checksum";
|
|
40
|
+
recorded?: string;
|
|
41
|
+
}>;
|
|
42
|
+
}
|
|
43
|
+
/** Reads each required environment's history for `pending`. */
|
|
44
|
+
export declare function readPromotions(project: Project, env: string, ordered: readonly Migration[], pending: ReadonlyArray<Pick<PendingMigration, "id" | "checksum">>): Promise<Promotion[]>;
|
|
45
|
+
/** The refusal for the promotions, or undefined when every pending migration ran where it had to. */
|
|
46
|
+
export declare function promotionRefusal(env: string, promotions: readonly Promotion[]): YodelError | undefined;
|
|
47
|
+
/** Reads the required environments and throws the refusal when a pending migration has not run there. */
|
|
48
|
+
export declare function enforcePromotion(project: Project, env: string, ordered: readonly Migration[], pending: ReadonlyArray<Pick<PendingMigration, "id" | "checksum">>): Promise<Promotion[]>;
|
|
49
|
+
/** What the wave plan digest takes of the promotions: each required environment and the pending migrations' checksums it recorded. */
|
|
50
|
+
export declare const promotionEvidence: (promotions: readonly Promotion[]) => {
|
|
51
|
+
env: string;
|
|
52
|
+
applied: {
|
|
53
|
+
id: string;
|
|
54
|
+
checksum: string;
|
|
55
|
+
}[];
|
|
56
|
+
}[];
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Promotion (#43): an environment applies only migrations the environment
|
|
3
|
+
* before it recorded as applied.
|
|
4
|
+
*
|
|
5
|
+
* `waves[].requires` names that environment; it defaults to the wave
|
|
6
|
+
* before, and `false` turns it off. Before anything is applied (and before
|
|
7
|
+
* the gate), `yodel apply <env>` reads each required environment's history
|
|
8
|
+
* with that environment's own profile, which outside an apply job is its
|
|
9
|
+
* reader, and refuses (exit 4) any pending migration the history does not
|
|
10
|
+
* record as applied with the checksum its files have now. The requirement
|
|
11
|
+
* is read from the working tree's yodel.config.ts and from the base
|
|
12
|
+
* commit's, and both are enforced, so a change that drops its own
|
|
13
|
+
* requirement is still held to the base's.
|
|
14
|
+
*/
|
|
15
|
+
import { loadYodelConfigAtBase } from "../config/base.js";
|
|
16
|
+
import { EXIT_REFUSED } from "../exit.js";
|
|
17
|
+
import { resolveEnvironment, YodelError } from "../project.js";
|
|
18
|
+
import { closeVersioned, inspect, openVersioned } from "../versioned/engine.js";
|
|
19
|
+
import { splitTarget, tenantTarget } from "../tenants/target.js";
|
|
20
|
+
/** The environment `env` requires in `config`: `requires`, else the wave before; undefined for none. */
|
|
21
|
+
export function requiredIn(config, env) {
|
|
22
|
+
const waves = config?.waves ?? [];
|
|
23
|
+
const i = waves.findIndex((w) => w.env === env);
|
|
24
|
+
const wave = waves[i];
|
|
25
|
+
if (!wave || wave.requires === false)
|
|
26
|
+
return undefined;
|
|
27
|
+
return wave.requires ?? waves[i - 1]?.env;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Each required environment and where the requirement comes from: the
|
|
31
|
+
* working tree, the base commit, or both. A tenant (#56) requires what its
|
|
32
|
+
* environment requires: the same tenant when that environment has a tenant
|
|
33
|
+
* set too, else the environment.
|
|
34
|
+
*/
|
|
35
|
+
export async function requiredEnvironments(project, env) {
|
|
36
|
+
const out = new Map();
|
|
37
|
+
const { env: base, tenant } = splitTarget(env);
|
|
38
|
+
const add = (e, from) => {
|
|
39
|
+
const target = e && tenant !== undefined && project.yodel?.config.environments?.[e]?.tenants ? tenantTarget(e, tenant) : e;
|
|
40
|
+
if (target && target !== env)
|
|
41
|
+
out.set(target, [...(out.get(target) ?? []), from]);
|
|
42
|
+
};
|
|
43
|
+
add(requiredIn(project.yodel?.config, base), "yodel.config.ts");
|
|
44
|
+
try {
|
|
45
|
+
const at = await loadYodelConfigAtBase(project.dir);
|
|
46
|
+
add(requiredIn(at.config, base), `yodel.config.ts at ${at.sha.slice(0, 12)}`);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// No git, or no base commit (a repository's first commit): the working tree's requirement alone.
|
|
50
|
+
}
|
|
51
|
+
return [...out].map(([e, from]) => ({ env: e, from: from.join(" and ") }));
|
|
52
|
+
}
|
|
53
|
+
/** Reads each required environment's history for `pending`. */
|
|
54
|
+
export async function readPromotions(project, env, ordered, pending) {
|
|
55
|
+
const out = [];
|
|
56
|
+
for (const req of await requiredEnvironments(project, env)) {
|
|
57
|
+
let environment;
|
|
58
|
+
try {
|
|
59
|
+
environment = resolveEnvironment(project, req.env);
|
|
60
|
+
}
|
|
61
|
+
catch (e) {
|
|
62
|
+
throw new YodelError(`refused: ${env} requires ${req.env} (${req.from}), and ${e instanceof Error ? e.message : String(e)}; nothing was applied`, EXIT_REFUSED);
|
|
63
|
+
}
|
|
64
|
+
const venv = await openVersioned(project, environment);
|
|
65
|
+
try {
|
|
66
|
+
const { status } = await inspect(venv, ordered, { sync: false });
|
|
67
|
+
const applied = new Map(status.applied.map((a) => [a.id, a.checksum]));
|
|
68
|
+
out.push({
|
|
69
|
+
env: req.env,
|
|
70
|
+
from: req.from,
|
|
71
|
+
migrations: pending.map((p) => {
|
|
72
|
+
const recorded = applied.get(p.id);
|
|
73
|
+
if (recorded === undefined)
|
|
74
|
+
return { id: p.id, checksum: p.checksum, ran: "not applied" };
|
|
75
|
+
return recorded === p.checksum ? { id: p.id, checksum: p.checksum, ran: "applied" } : { id: p.id, checksum: p.checksum, ran: "applied with another checksum", recorded };
|
|
76
|
+
}),
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
finally {
|
|
80
|
+
await closeVersioned(venv);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return out;
|
|
84
|
+
}
|
|
85
|
+
/** The refusal for the promotions, or undefined when every pending migration ran where it had to. */
|
|
86
|
+
export function promotionRefusal(env, promotions) {
|
|
87
|
+
const lines = promotions.flatMap((p) => p.migrations
|
|
88
|
+
.filter((m) => m.ran !== "applied")
|
|
89
|
+
.map((m) => ` ${m.id}: ${m.ran === "not applied" ? `${p.env}'s history does not record it applied` : `${p.env} applied it with checksum ${m.recorded ?? "?"}, and its files now hash to ${m.checksum}`} (required by ${p.from})`));
|
|
90
|
+
if (lines.length === 0)
|
|
91
|
+
return undefined;
|
|
92
|
+
const envs = [...new Set(promotions.filter((p) => p.migrations.some((m) => m.ran !== "applied")).map((p) => p.env))];
|
|
93
|
+
return new YodelError(`refused: ${env} applies only migrations ${envs.join(" and ")} applied first, and ${String(lines.length)} pending ${lines.length === 1 ? "one has" : "ones have"} not run there:\n${lines.join("\n")}\n` +
|
|
94
|
+
`Nothing was applied. Apply ${lines.length === 1 ? "it" : "them"} to ${envs.join(" and ")} first.`, EXIT_REFUSED);
|
|
95
|
+
}
|
|
96
|
+
/** Reads the required environments and throws the refusal when a pending migration has not run there. */
|
|
97
|
+
export async function enforcePromotion(project, env, ordered, pending) {
|
|
98
|
+
if (pending.length === 0)
|
|
99
|
+
return [];
|
|
100
|
+
const promotions = await readPromotions(project, env, ordered, pending);
|
|
101
|
+
const refusal = promotionRefusal(env, promotions);
|
|
102
|
+
if (refusal)
|
|
103
|
+
throw refusal;
|
|
104
|
+
return promotions;
|
|
105
|
+
}
|
|
106
|
+
/** What the wave plan digest takes of the promotions: each required environment and the pending migrations' checksums it recorded. */
|
|
107
|
+
export const promotionEvidence = (promotions) => promotions.map((p) => ({ env: p.env, applied: p.migrations.filter((m) => m.ran === "applied").map((m) => ({ id: m.id, checksum: m.checksum })) }));
|
|
108
|
+
//# sourceMappingURL=promotion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"promotion.js","sourceRoot":"","sources":["../../src/waves/promotion.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** A wave's decision as the history records it (#87). Pure, for ../report/audit.ts. */
|
|
2
|
+
/** The pipeline's name, and the op chant records the wave gates under. */
|
|
3
|
+
export declare const WAVES_PIPELINE = "yodel-apply";
|
|
4
|
+
/**
|
|
5
|
+
* What a wave's apply records of chant's decision, in each migration's
|
|
6
|
+
* `started` history row (`note.wave`): the gate and the set digest it was
|
|
7
|
+
* let through on, so `yodel report` finds the approval on the wave's gate
|
|
8
|
+
* (`<op>-wave-<k>`) and not the migrations Op's, and knows a wave whose
|
|
9
|
+
* policy at the base needed none.
|
|
10
|
+
*/
|
|
11
|
+
export interface WaveRecord {
|
|
12
|
+
wave: number;
|
|
13
|
+
/** chant's op the wave gates are recorded under (the spec's name), and the wave's gate. */
|
|
14
|
+
op: string;
|
|
15
|
+
gate: string;
|
|
16
|
+
/** The wave's set digest. */
|
|
17
|
+
digest: string;
|
|
18
|
+
status: "approved" | "not-required";
|
|
19
|
+
/** For `not-required`: the policy and the commit it was read at. */
|
|
20
|
+
policy?: string;
|
|
21
|
+
base?: string;
|
|
22
|
+
/** Which approvals counted (#48), when not `ledger`. */
|
|
23
|
+
approval?: string;
|
|
24
|
+
/** Under `pr-review`, the review that approved the wave: the pull request, the head it approved and its approvers. */
|
|
25
|
+
review?: {
|
|
26
|
+
pr: number;
|
|
27
|
+
head: string;
|
|
28
|
+
approvers: string[];
|
|
29
|
+
};
|
|
30
|
+
/** Under `sealed`, the signer whose seal verified. */
|
|
31
|
+
signer?: string;
|
|
32
|
+
}
|
|
33
|
+
/** Reads `note.wave` from a history row's note, or undefined. */
|
|
34
|
+
export declare function waveRecordOf(note: string): WaveRecord | undefined;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** A wave's decision as the history records it (#87). Pure, for ../report/audit.ts. */
|
|
2
|
+
/** The pipeline's name, and the op chant records the wave gates under. */
|
|
3
|
+
export const WAVES_PIPELINE = "yodel-apply";
|
|
4
|
+
/** Reads `note.wave` from a history row's note, or undefined. */
|
|
5
|
+
export function waveRecordOf(note) {
|
|
6
|
+
if (!note.startsWith("{"))
|
|
7
|
+
return undefined;
|
|
8
|
+
try {
|
|
9
|
+
const w = JSON.parse(note).wave;
|
|
10
|
+
if (!w || typeof w.gate !== "string" || typeof w.digest !== "string" || typeof w.op !== "string")
|
|
11
|
+
return undefined;
|
|
12
|
+
if (w.status !== "approved" && w.status !== "not-required")
|
|
13
|
+
return undefined;
|
|
14
|
+
return w;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=record.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record.js","sourceRoot":"","sources":["../../src/waves/record.ts"],"names":[],"mappings":"AAAA,uFAAuF;AAEvF,0EAA0E;AAC1E,MAAM,CAAC,MAAM,cAAc,GAAG,aAAa,CAAC;AA4B5C,iEAAiE;AACjE,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IAC5C,IAAI,CAAC;QACH,MAAM,CAAC,GAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAoC,CAAC,IAAI,CAAC;QACpE,IAAI,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,EAAE,KAAK,QAAQ;YAAE,OAAO,SAAS,CAAC;QACnH,IAAI,CAAC,CAAC,MAAM,KAAK,UAAU,IAAI,CAAC,CAAC,MAAM,KAAK,cAAc;YAAE,OAAO,SAAS,CAAC;QAC7E,OAAO,CAAe,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intentius/sql-yodeler",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Schema management and migrations for ClickHouse and Postgres, on chant's sql lexicon",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -12,6 +12,10 @@
|
|
|
12
12
|
".": {
|
|
13
13
|
"types": "./dist/index.d.ts",
|
|
14
14
|
"default": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./webhook": {
|
|
17
|
+
"types": "./dist/notify/verify.d.ts",
|
|
18
|
+
"default": "./dist/notify/verify.js"
|
|
15
19
|
}
|
|
16
20
|
},
|
|
17
21
|
"bin": {
|
|
@@ -41,16 +45,16 @@
|
|
|
41
45
|
"bench": "npm run build && tsx bench/run.ts"
|
|
42
46
|
},
|
|
43
47
|
"dependencies": {
|
|
44
|
-
"@intentius/chant": "^0.
|
|
45
|
-
"@intentius/chant-lexicon-
|
|
48
|
+
"@intentius/chant": "^0.118.1",
|
|
49
|
+
"@intentius/chant-lexicon-forgejo": "^0.118.1",
|
|
50
|
+
"@intentius/chant-lexicon-github": "^0.118.1",
|
|
51
|
+
"@intentius/chant-lexicon-gitlab": "^0.118.1",
|
|
52
|
+
"@intentius/chant-lexicon-sql": "^0.118.1",
|
|
46
53
|
"tsx": "^4.23.15"
|
|
47
54
|
},
|
|
48
55
|
"devDependencies": {
|
|
49
56
|
"@eslint/js": "^10.0.1",
|
|
50
|
-
"@intentius/chant-lexicon-docker": "^0.
|
|
51
|
-
"@intentius/chant-lexicon-forgejo": "^0.115.0",
|
|
52
|
-
"@intentius/chant-lexicon-github": "^0.115.0",
|
|
53
|
-
"@intentius/chant-lexicon-gitlab": "^0.115.0",
|
|
57
|
+
"@intentius/chant-lexicon-docker": "^0.118.1",
|
|
54
58
|
"@types/node": "^22.20.5",
|
|
55
59
|
"@types/pg": "^8.23.1",
|
|
56
60
|
"ajv": "^8.20.0",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://intentius.io/sql-yodeler/schemas/v1/apply.schema.json",
|
|
4
4
|
"title": "yodel apply <env> --json",
|
|
5
|
-
"description": "Version 1. On a project with migrations, the status (status.schema.json) with mode \"versioned\" and what apply did; with --execute (the migrations Op's Apply step), what the step applied; on a project without migrations, the declarative outcome with chant's plan. Within a version, fields are only added; a reader ignores fields it does not know.",
|
|
5
|
+
"description": "Version 1. On a project with migrations, the status (status.schema.json) with mode \"versioned\" and what apply did; with --execute (the migrations Op's Apply step) or --wave-apply (a wave job's apply), what the step applied; with --wave-plan, the wave plan it wrote; on a project without migrations, the declarative outcome with chant's plan. Within a version, fields are only added; a reader ignores fields it does not know.",
|
|
6
6
|
"oneOf": [
|
|
7
7
|
{
|
|
8
8
|
"$ref": "#/$defs/versioned"
|
|
@@ -10,6 +10,9 @@
|
|
|
10
10
|
{
|
|
11
11
|
"$ref": "#/$defs/execute"
|
|
12
12
|
},
|
|
13
|
+
{
|
|
14
|
+
"$ref": "#/$defs/wavePlan"
|
|
15
|
+
},
|
|
13
16
|
{
|
|
14
17
|
"$ref": "#/$defs/declarative"
|
|
15
18
|
}
|
|
@@ -35,6 +38,27 @@
|
|
|
35
38
|
},
|
|
36
39
|
"notice": {
|
|
37
40
|
"type": "string"
|
|
41
|
+
},
|
|
42
|
+
"waited": {
|
|
43
|
+
"description": "The run waited for another apply's lock (--lock-wait): for how long, who held it when the run first found it held, and where.",
|
|
44
|
+
"type": "object",
|
|
45
|
+
"additionalProperties": false,
|
|
46
|
+
"required": [
|
|
47
|
+
"ms",
|
|
48
|
+
"heldBy",
|
|
49
|
+
"where"
|
|
50
|
+
],
|
|
51
|
+
"properties": {
|
|
52
|
+
"ms": {
|
|
53
|
+
"type": "integer"
|
|
54
|
+
},
|
|
55
|
+
"heldBy": {
|
|
56
|
+
"type": "string"
|
|
57
|
+
},
|
|
58
|
+
"where": {
|
|
59
|
+
"type": "string"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
38
62
|
}
|
|
39
63
|
}
|
|
40
64
|
},
|
|
@@ -51,17 +75,22 @@
|
|
|
51
75
|
"const": "versioned"
|
|
52
76
|
},
|
|
53
77
|
"status": {
|
|
54
|
-
"description": "planned (--plan, something pending), unchanged, refused, denied (a policy rule denies the plan, with no override), gated (waiting at the Op's gate for a person's approval), failed, applied.",
|
|
78
|
+
"description": "planned (--plan, something pending), unchanged, refused, denied (a policy rule denies the plan, with no override), stood-down (--stand-down: a newer commit's apply applies this environment, so this one applied nothing), gated (waiting at the Op's gate for a person's approval), failed, applied.",
|
|
55
79
|
"enum": [
|
|
56
80
|
"planned",
|
|
57
81
|
"unchanged",
|
|
58
82
|
"refused",
|
|
59
83
|
"denied",
|
|
84
|
+
"stood-down",
|
|
60
85
|
"gated",
|
|
61
86
|
"failed",
|
|
62
87
|
"applied"
|
|
63
88
|
]
|
|
64
89
|
},
|
|
90
|
+
"stoodDown": {
|
|
91
|
+
"description": "stood-down: why, in one line.",
|
|
92
|
+
"type": "string"
|
|
93
|
+
},
|
|
65
94
|
"preChecks": {
|
|
66
95
|
"description": "The first pending migration's checks, when one failed before the gate.",
|
|
67
96
|
"type": "object",
|
|
@@ -173,7 +202,15 @@
|
|
|
173
202
|
"type": "string"
|
|
174
203
|
},
|
|
175
204
|
"status": {
|
|
176
|
-
"
|
|
205
|
+
"description": "applied, or stood-down (--stand-down: a newer commit came while the step waited for the lock, and it applied nothing).",
|
|
206
|
+
"enum": [
|
|
207
|
+
"applied",
|
|
208
|
+
"stood-down"
|
|
209
|
+
]
|
|
210
|
+
},
|
|
211
|
+
"stoodDown": {
|
|
212
|
+
"description": "stood-down: why, in one line.",
|
|
213
|
+
"type": "string"
|
|
177
214
|
},
|
|
178
215
|
"planDigest": {
|
|
179
216
|
"description": "The digest the gate approved.",
|
|
@@ -204,6 +241,10 @@
|
|
|
204
241
|
},
|
|
205
242
|
"lock": {
|
|
206
243
|
"$ref": "#/$defs/lock"
|
|
244
|
+
},
|
|
245
|
+
"wavePlanDigest": {
|
|
246
|
+
"description": "--wave-apply: the wave plan digest chant's wave decision named.",
|
|
247
|
+
"type": "string"
|
|
207
248
|
}
|
|
208
249
|
}
|
|
209
250
|
},
|
|
@@ -264,6 +305,124 @@
|
|
|
264
305
|
"$ref": "plan.schema.json#/$defs/declarative"
|
|
265
306
|
}
|
|
266
307
|
}
|
|
308
|
+
},
|
|
309
|
+
"wavePlan": {
|
|
310
|
+
"description": "--wave-plan: the plan file chant run wave reads, as written.",
|
|
311
|
+
"type": "object",
|
|
312
|
+
"additionalProperties": false,
|
|
313
|
+
"required": [
|
|
314
|
+
"planDigest",
|
|
315
|
+
"destructive",
|
|
316
|
+
"empty",
|
|
317
|
+
"environment",
|
|
318
|
+
"migrations",
|
|
319
|
+
"gate",
|
|
320
|
+
"base",
|
|
321
|
+
"pending",
|
|
322
|
+
"destructiveSteps",
|
|
323
|
+
"requires"
|
|
324
|
+
],
|
|
325
|
+
"properties": {
|
|
326
|
+
"planDigest": {
|
|
327
|
+
"description": "The wave plan digest: over the migrations' digest, the gate policy at the base commit and whether a pending step is destructive.",
|
|
328
|
+
"type": "string"
|
|
329
|
+
},
|
|
330
|
+
"destructive": {
|
|
331
|
+
"type": "boolean"
|
|
332
|
+
},
|
|
333
|
+
"empty": {
|
|
334
|
+
"description": "Nothing is pending.",
|
|
335
|
+
"type": "boolean"
|
|
336
|
+
},
|
|
337
|
+
"environment": {
|
|
338
|
+
"type": "string"
|
|
339
|
+
},
|
|
340
|
+
"migrations": {
|
|
341
|
+
"description": "The migrations' plan digest, as yodel apply --digest prints it.",
|
|
342
|
+
"type": "string"
|
|
343
|
+
},
|
|
344
|
+
"gate": {
|
|
345
|
+
"enum": [
|
|
346
|
+
"always",
|
|
347
|
+
"on-destructive",
|
|
348
|
+
"never"
|
|
349
|
+
]
|
|
350
|
+
},
|
|
351
|
+
"base": {
|
|
352
|
+
"description": "The base commit the gate was read at.",
|
|
353
|
+
"type": "string"
|
|
354
|
+
},
|
|
355
|
+
"pending": {
|
|
356
|
+
"$ref": "common.schema.json#/$defs/stringList"
|
|
357
|
+
},
|
|
358
|
+
"destructiveSteps": {
|
|
359
|
+
"type": "array",
|
|
360
|
+
"items": {
|
|
361
|
+
"$ref": "#/$defs/destructiveStep"
|
|
362
|
+
}
|
|
363
|
+
},
|
|
364
|
+
"requires": {
|
|
365
|
+
"description": "Each environment this one requires, and the pending migrations its history records applied; part of the plan digest.",
|
|
366
|
+
"type": "array",
|
|
367
|
+
"items": {
|
|
368
|
+
"type": "object",
|
|
369
|
+
"additionalProperties": false,
|
|
370
|
+
"required": [
|
|
371
|
+
"env",
|
|
372
|
+
"applied"
|
|
373
|
+
],
|
|
374
|
+
"properties": {
|
|
375
|
+
"env": {
|
|
376
|
+
"type": "string"
|
|
377
|
+
},
|
|
378
|
+
"applied": {
|
|
379
|
+
"type": "array",
|
|
380
|
+
"items": {
|
|
381
|
+
"type": "object",
|
|
382
|
+
"additionalProperties": false,
|
|
383
|
+
"required": [
|
|
384
|
+
"id",
|
|
385
|
+
"checksum"
|
|
386
|
+
],
|
|
387
|
+
"properties": {
|
|
388
|
+
"id": {
|
|
389
|
+
"type": "string"
|
|
390
|
+
},
|
|
391
|
+
"checksum": {
|
|
392
|
+
"type": "string"
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
},
|
|
402
|
+
"destructiveStep": {
|
|
403
|
+
"type": "object",
|
|
404
|
+
"additionalProperties": false,
|
|
405
|
+
"required": [
|
|
406
|
+
"migration",
|
|
407
|
+
"step",
|
|
408
|
+
"what",
|
|
409
|
+
"why"
|
|
410
|
+
],
|
|
411
|
+
"properties": {
|
|
412
|
+
"migration": {
|
|
413
|
+
"type": "string"
|
|
414
|
+
},
|
|
415
|
+
"step": {
|
|
416
|
+
"type": "integer"
|
|
417
|
+
},
|
|
418
|
+
"what": {
|
|
419
|
+
"type": "string"
|
|
420
|
+
},
|
|
421
|
+
"why": {
|
|
422
|
+
"description": "The lint rules that class it (destructive, pg-rewrite, pg-lock, pg-access, ch-mutation, ch-rebuild, ch-access), or op-step, manual-step.",
|
|
423
|
+
"type": "string"
|
|
424
|
+
}
|
|
425
|
+
}
|
|
267
426
|
}
|
|
268
427
|
}
|
|
269
428
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://intentius.io/sql-yodeler/schemas/v1/checkpoint.schema.json",
|
|
4
|
+
"title": "yodel checkpoint <name> --json",
|
|
5
|
+
"description": "Version 1. The checkpoint written: its id and directory, the migration whose recorded schema it creates (its parent), its checksum, how many statements it holds, and the SHA-256 of the recorded schema it was written from. Within a version, fields are only added; a reader ignores fields it does not know.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": ["written", "id", "path", "parent", "checksum", "dialect", "statements", "schema"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"written": { "const": true },
|
|
11
|
+
"id": { "type": "string" },
|
|
12
|
+
"path": { "type": "string" },
|
|
13
|
+
"parent": { "type": "string" },
|
|
14
|
+
"checksum": { "type": "string" },
|
|
15
|
+
"dialect": { "$ref": "common.schema.json#/$defs/dialect" },
|
|
16
|
+
"statements": { "type": "integer", "minimum": 1 },
|
|
17
|
+
"schema": { "type": "string" }
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://intentius.io/sql-yodeler/schemas/v1/cleanup.schema.json",
|
|
4
|
+
"title": "yodel cleanup <env> --json",
|
|
5
|
+
"description": "Version 1. What steps kept in the environment (a rebuild's old table, a column migration's old column), each with its retention date and whether it is due, the digest an approval of the drop binds when something is due, and what was dropped. Within a version, fields are only added; a reader ignores fields it does not know.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": ["environment", "now", "retained", "due", "dropped"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"environment": { "type": "string" },
|
|
11
|
+
"now": { "description": "The server's clock when it was read (ISO 8601).", "type": "string" },
|
|
12
|
+
"retained": {
|
|
13
|
+
"type": "array",
|
|
14
|
+
"items": {
|
|
15
|
+
"type": "object",
|
|
16
|
+
"additionalProperties": false,
|
|
17
|
+
"required": ["kind", "name", "of", "due", "identity"],
|
|
18
|
+
"properties": {
|
|
19
|
+
"kind": { "enum": ["table", "column"] },
|
|
20
|
+
"name": { "description": "db.table__chant_old, or schema.table.column.", "type": "string" },
|
|
21
|
+
"of": { "description": "The rebuild (db.table) or column migration (schema.table.column) that kept it.", "type": "string" },
|
|
22
|
+
"retainUntil": { "description": "Its retention date (ISO 8601), from its comment; absent when its comment has none, and then it is never due.", "type": "string" },
|
|
23
|
+
"due": { "type": "boolean" },
|
|
24
|
+
"identity": { "description": "The table's UUID, or the column's table oid and attribute number.", "type": "string" },
|
|
25
|
+
"trigger": {
|
|
26
|
+
"description": "Postgres: the dual-write trigger and function dropped with the column.",
|
|
27
|
+
"type": "object",
|
|
28
|
+
"additionalProperties": false,
|
|
29
|
+
"required": ["name", "fn"],
|
|
30
|
+
"properties": { "name": { "type": "string" }, "fn": { "type": "string" } }
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"due": { "type": "integer", "minimum": 0 },
|
|
36
|
+
"planDigest": { "description": "When something is due: the digest an approval of the drop binds.", "type": "string" },
|
|
37
|
+
"approve": { "description": "When something is due and not approved: the command that approves it.", "type": "string" },
|
|
38
|
+
"dropped": { "$ref": "common.schema.json#/$defs/stringList" }
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -31,6 +31,31 @@
|
|
|
31
31
|
"type": "object",
|
|
32
32
|
"additionalProperties": { "$ref": "common.schema.json#/$defs/stringList" }
|
|
33
33
|
},
|
|
34
|
-
"
|
|
34
|
+
"against": {
|
|
35
|
+
"description": "What the server was compared with: src, the project's declarations; or history, the schema the newest applied migration records (migration null when none is applied yet).",
|
|
36
|
+
"oneOf": [
|
|
37
|
+
{ "type": "object", "additionalProperties": false, "required": ["source"], "properties": { "source": { "const": "src" } } },
|
|
38
|
+
{
|
|
39
|
+
"type": "object",
|
|
40
|
+
"additionalProperties": false,
|
|
41
|
+
"required": ["source", "migration"],
|
|
42
|
+
"properties": { "source": { "const": "history" }, "migration": { "type": ["string", "null"] } }
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
},
|
|
46
|
+
"drifted": { "description": "A declared object changed or is gone: the command exits 2.", "type": "boolean" },
|
|
47
|
+
"fingerprint": { "description": "A hash of the environment and what drifted: the same for the same drift, run after run.", "type": "string" },
|
|
48
|
+
"issue": {
|
|
49
|
+
"description": "--issue: what yodel did with the environment's tracking issue, and the issue when there is one.",
|
|
50
|
+
"type": "object",
|
|
51
|
+
"additionalProperties": false,
|
|
52
|
+
"required": ["action"],
|
|
53
|
+
"properties": {
|
|
54
|
+
"action": { "enum": ["opened", "updated", "unchanged", "closed", "left", "none"] },
|
|
55
|
+
"number": { "type": "integer" },
|
|
56
|
+
"url": { "type": "string" }
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"issueError": { "description": "--issue: the tracking issue could not be written, and why.", "type": "string" }
|
|
35
60
|
}
|
|
36
61
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://intentius.io/sql-yodeler/schemas/v1/event.schema.json",
|
|
4
|
+
"title": "a yodel webhook event",
|
|
5
|
+
"description": "Version 1. The body yodel apply, yodel plan and yodel drift post to the webhook yodel.config.ts notify names, signed with HMAC-SHA256 over '<x-yodel-timestamp>.<body>' in the x-yodel-signature header. Within a version, fields are only added; a receiver ignores fields it does not know.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": ["version", "id", "event", "at", "environment", "command", "status", "summary", "migrations"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"version": { "const": 1 },
|
|
11
|
+
"id": { "type": "string", "description": "Unique per event; also the x-yodel-delivery header." },
|
|
12
|
+
"event": { "enum": ["waiting", "refused", "failed", "drift"] },
|
|
13
|
+
"at": { "type": "string", "format": "date-time" },
|
|
14
|
+
"environment": { "type": "string" },
|
|
15
|
+
"command": { "enum": ["apply", "plan", "drift"] },
|
|
16
|
+
"status": { "type": "string", "description": "The command's own word for the outcome: gated, refused, denied, failed, incomplete, drifted." },
|
|
17
|
+
"summary": { "type": "string" },
|
|
18
|
+
"migrations": { "type": "array", "items": { "type": "string" }, "description": "The pending migrations, for apply and plan." },
|
|
19
|
+
"digest": { "type": "string", "description": "The plan digest the run computed." },
|
|
20
|
+
"approve": { "type": "string", "description": "On waiting: the command that approves the plan." },
|
|
21
|
+
"reason": { "type": "string" },
|
|
22
|
+
"drift": {
|
|
23
|
+
"type": "object",
|
|
24
|
+
"additionalProperties": false,
|
|
25
|
+
"required": ["changed", "missing"],
|
|
26
|
+
"properties": {
|
|
27
|
+
"changed": { "type": "array", "items": { "type": "string" } },
|
|
28
|
+
"missing": { "type": "array", "items": { "type": "string" } },
|
|
29
|
+
"fingerprint": { "type": "string", "description": "The same drift has the same fingerprint run after run, so a receiver can tell a repeat from new drift." }
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"runUrl": { "type": "string" },
|
|
33
|
+
"repository": { "type": "string" },
|
|
34
|
+
"commit": { "type": "string" }
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -41,6 +41,10 @@
|
|
|
41
41
|
"description": "The dialect it applies to; both when absent.",
|
|
42
42
|
"$ref": "common.schema.json#/$defs/dialect"
|
|
43
43
|
},
|
|
44
|
+
"schema": {
|
|
45
|
+
"description": "One of the sql lexicon's schema checks, run on each migration's recorded schema.",
|
|
46
|
+
"type": "boolean"
|
|
47
|
+
},
|
|
44
48
|
"configured": {
|
|
45
49
|
"description": "The level in this project.",
|
|
46
50
|
"enum": [
|