@intentius/sql-yodeler 0.2.0 → 0.3.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/chant/build.js +7 -0
- package/dist/chant/build.js.map +1 -1
- package/dist/ci/render.d.ts +289 -0
- package/dist/ci/render.js +688 -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/commands/apply.d.ts +113 -0
- package/dist/commands/apply.js +228 -21
- package/dist/commands/apply.js.map +1 -1
- package/dist/commands/approve.js +44 -0
- 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 +118 -0
- package/dist/commands/ci.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 +18 -2
- package/dist/commands/drift.js.map +1 -1
- package/dist/commands/index.js +10 -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 +11 -3
- package/dist/commands/lint.js.map +1 -1
- package/dist/commands/override.js +48 -16
- package/dist/commands/override.js.map +1 -1
- package/dist/commands/plan.js +5 -1
- 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/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 +123 -1
- package/dist/config/define.js +2 -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 +90 -5
- package/dist/config/load.js.map +1 -1
- package/dist/config/settings.d.ts +4 -1
- package/dist/config/settings.js +8 -2
- package/dist/config/settings.js.map +1 -1
- 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 +4 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lint/check.js +17 -2
- package/dist/lint/check.js.map +1 -1
- 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 +16 -4
- package/dist/lint/rules.js +9 -4
- package/dist/lint/rules.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 +110 -0
- package/dist/migrations/checkpoint.js.map +1 -0
- package/dist/migrations/create.js +2 -0
- 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 +31 -0
- package/dist/migrations/routines.js +55 -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 +3 -0
- package/dist/pr/model.js +16 -2
- package/dist/pr/model.js.map +1 -1
- package/dist/pr/render.js +27 -1
- package/dist/pr/render.js.map +1 -1
- package/dist/project.d.ts +19 -2
- package/dist/project.js +33 -1
- package/dist/project.js.map +1 -1
- package/dist/replay/replay.d.ts +9 -1
- 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 +202 -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 +5 -2
- package/dist/schemas.js +5 -2
- package/dist/schemas.js.map +1 -1
- package/dist/sources/ddl.d.ts +53 -0
- package/dist/sources/ddl.js +347 -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/postgres-migration.d.ts +35 -25
- package/dist/steps/postgres-migration.js +42 -29
- package/dist/steps/postgres-migration.js.map +1 -1
- package/dist/tenants/index.d.ts +40 -0
- package/dist/tenants/index.js +122 -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/versioned/engine.d.ts +6 -0
- package/dist/versioned/engine.js +12 -2
- package/dist/versioned/engine.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 +36 -3
- package/dist/versioned/state.js.map +1 -1
- package/dist/waves/index.d.ts +179 -0
- package/dist/waves/index.js +268 -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 +24 -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/drift.schema.json +26 -1
- package/schemas/event.schema.json +36 -0
- package/schemas/lint.schema.json +4 -0
- package/schemas/plan.schema.json +118 -0
- package/schemas/report.schema.json +114 -0
- package/schemas/revert.schema.json +69 -0
- package/schemas/status.schema.json +64 -3
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import { parseArgs } from "node:util";
|
|
3
|
+
import { guarded } from "../env-args.js";
|
|
4
|
+
import { loadProject, resolveEnvironment, YodelError } from "../project.js";
|
|
5
|
+
import { GATED } from "../chant/apply.js";
|
|
6
|
+
import { runnable } from "../chant/runnable.js";
|
|
7
|
+
import { LOCK_WAIT_ENV, parseDuration } from "../config/settings.js";
|
|
8
|
+
import { MIGRATION_ID } from "../migrations/index.js";
|
|
9
|
+
import { describeServer } from "../server.js";
|
|
10
|
+
import { policyAtBase } from "../config/base.js";
|
|
11
|
+
import { EXIT_REFUSED } from "../exit.js";
|
|
12
|
+
import { destructiveSteps, gateAtBase } from "../waves/index.js";
|
|
13
|
+
import { closeVersioned, currentRevert, describeResults, findMigrateOp, gitLedger, judgeRevert, openVersioned, policyRefusal, readChain, readRevertStep, renderStatus, runMigrateOp, statusReport, } from "../versioned/index.js";
|
|
14
|
+
const usage = "usage: yodel revert <env> <id> [--step <file>] [--dry-run] [--json] [--op <name>] [--lock-wait <duration>] [--dir <project>]";
|
|
15
|
+
const help = `${usage}
|
|
16
|
+
|
|
17
|
+
Undoes migration <id> in <env>: plans the statements that take the schema
|
|
18
|
+
from <id>'s recorded schema back to its parent's (an empty schema for the
|
|
19
|
+
first migration), offline, from migration.json alone. Only the newest
|
|
20
|
+
migration applied in <env> can be reverted; a later one was written against
|
|
21
|
+
it. <env> and <id> may come in either order.
|
|
22
|
+
|
|
23
|
+
The revert runs through the environment's migrations Op, as yodel apply
|
|
24
|
+
does: its Plan step prints the revert's digest (the statements, the history
|
|
25
|
+
and the live schema), its gate binds the approval to that digest, and its
|
|
26
|
+
Apply step plans the revert again under the lock, refuses if the digest
|
|
27
|
+
moved, and runs it. A run that stops at the gate prints the chant approve
|
|
28
|
+
command; approve, then run yodel revert again. The history gets a revert row
|
|
29
|
+
for each statement and a migration row reverted: <id> is then pending
|
|
30
|
+
again, and yodel status shows it reverted. Delete it, or rewrite it with
|
|
31
|
+
yodel new --replace, before the next yodel apply, which would apply it
|
|
32
|
+
again.
|
|
33
|
+
|
|
34
|
+
The policy in yodel.config.ts (policy.rules), as the base commit has it, is
|
|
35
|
+
judged over the revert's statements before the gate, and again under the
|
|
36
|
+
lock: a rule that refuses drops refuses a revert that drops what the
|
|
37
|
+
migration added (exit 4), unless an override is recorded for the revert's
|
|
38
|
+
digest (yodel override <env> --revert <id> --rule <rule> --reason <why>).
|
|
39
|
+
In an environment yodel.config.ts waves names, the revert waits at the
|
|
40
|
+
migrations Op's gate whatever the wave's gate policy: under on-destructive,
|
|
41
|
+
a destructive revert waits for an approval, and so does any other.
|
|
42
|
+
|
|
43
|
+
Statements carry the schema back, never data. A migration with a data step
|
|
44
|
+
(a backfill) is refused unless --step names a file of statements that undo
|
|
45
|
+
it, each ending with ; at the end of a line; they run before the reverse
|
|
46
|
+
statements, and are in the digest. A reverse that needs an Op or a manual
|
|
47
|
+
step is refused: write it as a new migration.
|
|
48
|
+
|
|
49
|
+
Options:
|
|
50
|
+
--step <file> a hand-written revert step: SQL that undoes the
|
|
51
|
+
migration's data step (relative to the project directory)
|
|
52
|
+
--dry-run print the revert's statements and digest; run nothing
|
|
53
|
+
--json print the outcome as JSON
|
|
54
|
+
--op <name> the Op to run, when more than one applies <env>
|
|
55
|
+
--lock-wait <d> when another apply holds the lock, wait up to <d> for it
|
|
56
|
+
-C, --dir <dir> the project directory (default: the working directory)
|
|
57
|
+
|
|
58
|
+
Exit codes:
|
|
59
|
+
0 reverted, or (--dry-run) planned
|
|
60
|
+
2 refused, nothing reverted: the migration has a data step and no --step,
|
|
61
|
+
or the reverse needs an Op or a manual step
|
|
62
|
+
3 stopped at the gate, waiting for approval of this revert
|
|
63
|
+
4 refused, nothing reverted: <id> is not applied in <env>, a migration
|
|
64
|
+
after it is, the history does not match the migrations directory, or
|
|
65
|
+
a policy rule denies the revert and no override is recorded for its
|
|
66
|
+
digest
|
|
67
|
+
5 another apply holds the lock
|
|
68
|
+
1 anything else failed: a statement (the history records where; rerun to
|
|
69
|
+
resume), a revert whose plan moved since approval, a bad config
|
|
70
|
+
`;
|
|
71
|
+
function parseRevertArgs(args) {
|
|
72
|
+
let parsed;
|
|
73
|
+
try {
|
|
74
|
+
parsed = parseArgs({
|
|
75
|
+
args,
|
|
76
|
+
allowPositionals: true,
|
|
77
|
+
strict: true,
|
|
78
|
+
options: {
|
|
79
|
+
step: { type: "string" },
|
|
80
|
+
"dry-run": { type: "boolean" },
|
|
81
|
+
json: { type: "boolean" },
|
|
82
|
+
op: { type: "string" },
|
|
83
|
+
"lock-wait": { type: "string" },
|
|
84
|
+
dir: { type: "string", short: "C" },
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
catch (e) {
|
|
89
|
+
throw new YodelError(`${e instanceof Error ? e.message : String(e)}\n${usage}`);
|
|
90
|
+
}
|
|
91
|
+
const { values, positionals } = parsed;
|
|
92
|
+
if (positionals.length !== 2)
|
|
93
|
+
throw new YodelError(usage);
|
|
94
|
+
const [first = "", second = ""] = positionals;
|
|
95
|
+
// The migration is the one named like an id; the other is the environment.
|
|
96
|
+
const [id, env] = MIGRATION_ID.test(first) && !MIGRATION_ID.test(second) ? [first, second] : [second, first];
|
|
97
|
+
const str = (k) => (typeof values[k] === "string" ? values[k] : undefined);
|
|
98
|
+
return {
|
|
99
|
+
env,
|
|
100
|
+
id,
|
|
101
|
+
step: str("step"),
|
|
102
|
+
dryRun: values["dry-run"] === true,
|
|
103
|
+
json: values.json === true,
|
|
104
|
+
op: str("op"),
|
|
105
|
+
lockWaitMs: typeof values["lock-wait"] === "string" ? parseDuration(values["lock-wait"], "--lock-wait") : undefined,
|
|
106
|
+
dir: str("dir") ?? process.cwd(),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/** What the wave gate `gate` makes of the revert `plan`: the statements it counts as destructive, the way a wave plan counts a migration's steps, and whether it asks for an approval. */
|
|
110
|
+
export function revertWaveOf(gate, base, dialect, plan) {
|
|
111
|
+
const steps = destructiveSteps(dialect, [{ id: plan.migration.id, migration: { document: { ...plan.migration.document, steps: plan.statements.map((s) => s.step) } } }]);
|
|
112
|
+
return { gate, base, destructiveSteps: steps, policyWaits: plan.statements.length > 0 && (gate === "always" || (gate === "on-destructive" && steps.length > 0)) };
|
|
113
|
+
}
|
|
114
|
+
/** `env`'s wave gate at the base commit for the revert `plan`, or undefined when no wave names `env`. */
|
|
115
|
+
async function revertWave(project, env, plan) {
|
|
116
|
+
if (!(project.yodel?.config.waves ?? []).some((w) => w.env === env))
|
|
117
|
+
return undefined;
|
|
118
|
+
const { gate, at } = await gateAtBase(project, env);
|
|
119
|
+
return revertWaveOf(gate, at.sha, project.dialect === "postgres" ? "postgres" : "clickhouse", plan);
|
|
120
|
+
}
|
|
121
|
+
function describeWave(env, wave) {
|
|
122
|
+
const destructive = wave.destructiveSteps.length > 0 ? `destructive (${wave.destructiveSteps.map((d) => `statement ${String(d.step)}: ${d.why}`).join(", ")})` : "not destructive";
|
|
123
|
+
return `wave gate ${wave.gate} for ${env} at ${wave.base.slice(0, 12)}: the revert is ${destructive}; ${wave.policyWaits ? "it waits for an approval" : "the gate policy alone would let it through, and it waits at the migrations Op's gate all the same"}`;
|
|
124
|
+
}
|
|
125
|
+
/** The revert as JSON (schemas/revert.schema.json), with what happened. */
|
|
126
|
+
export function revertJson(plan, digest, outcome) {
|
|
127
|
+
return {
|
|
128
|
+
environment: plan.environment,
|
|
129
|
+
migration: plan.migration.id,
|
|
130
|
+
to: plan.to,
|
|
131
|
+
planDigest: digest,
|
|
132
|
+
statements: plan.statements.map((s, i) => ({ index: i, source: s.source, sql: s.step.sql, rule: s.step.rule, class: s.step.class, ...(s.step.destructive ? { destructive: true } : {}), done: plan.done.includes(i) })),
|
|
133
|
+
dataSteps: plan.dataSteps,
|
|
134
|
+
...(plan.step ? { step: { file: plan.step.file, sha: plan.step.sha, statements: plan.step.statements.length } } : {}),
|
|
135
|
+
...outcome,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function renderPlan(plan, digest) {
|
|
139
|
+
const lines = [`Revert of ${plan.migration.id} in ${plan.environment}, back to ${plan.to ?? "an empty schema"}:`];
|
|
140
|
+
for (const [i, s] of plan.statements.entries()) {
|
|
141
|
+
const what = s.source === "step" ? `the revert step ${plan.step?.file ?? ""}` : `${s.step.rule} ${s.step.class}${s.step.destructive ? ", destructive" : ""}, ${s.step.name}`;
|
|
142
|
+
lines.push(` ${String(i)}: ${what}${plan.done.includes(i) ? " (succeeded in an earlier run; not sent again)" : ""}`, ` ${s.step.sql.split("\n").join("\n ")}`);
|
|
143
|
+
}
|
|
144
|
+
if (plan.statements.length === 0)
|
|
145
|
+
lines.push(" (no statement: the recorded schemas are the same)");
|
|
146
|
+
for (const d of plan.dataSteps)
|
|
147
|
+
lines.push(` data step ${d}: undone by the revert step`);
|
|
148
|
+
lines.push(`Plan digest: ${digest}`);
|
|
149
|
+
return `${lines.join("\n")}\n`;
|
|
150
|
+
}
|
|
151
|
+
/** `yodel revert <env> <id>`; the exit codes are in `help`. */
|
|
152
|
+
export const revert = {
|
|
153
|
+
name: "revert",
|
|
154
|
+
summary: "undo the newest applied migration from its recorded schemas",
|
|
155
|
+
implemented: true,
|
|
156
|
+
run: (args, io) => guarded("revert", io, args, help, () => run(parseRevertArgs(args), io)),
|
|
157
|
+
};
|
|
158
|
+
async function run(a, io) {
|
|
159
|
+
const project = await loadProject(a.dir);
|
|
160
|
+
const env = resolveEnvironment(project, a.env);
|
|
161
|
+
const ordered = readChain(project);
|
|
162
|
+
const step = a.step !== undefined ? readRevertStep(a.step, project.dir) : undefined;
|
|
163
|
+
const venv = await openVersioned(project, env);
|
|
164
|
+
try {
|
|
165
|
+
const { plan, digest } = await currentRevert(venv, ordered, a.id, step);
|
|
166
|
+
// The policy (#53) over the revert (#97), as the base commit has it (#73), with the overrides recorded for this revert's digest.
|
|
167
|
+
const basePolicy = await policyAtBase(project);
|
|
168
|
+
if (basePolicy.note && !a.json)
|
|
169
|
+
io.err(`${basePolicy.note}\n`);
|
|
170
|
+
const op = a.dryRun ? undefined : await findMigrateOp(project, env, a.op);
|
|
171
|
+
const policy = await judgeRevert({
|
|
172
|
+
policy: basePolicy.policy,
|
|
173
|
+
environment: env.name,
|
|
174
|
+
dialect: project.dialect,
|
|
175
|
+
plan,
|
|
176
|
+
digest,
|
|
177
|
+
ledger: async () => {
|
|
178
|
+
try {
|
|
179
|
+
return { port: await gitLedger(project.dir), op: op ?? (await findMigrateOp(project, env, a.op)) };
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
return undefined;
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
});
|
|
186
|
+
const wave = await revertWave(project, env.name, plan);
|
|
187
|
+
const extra = { ...(policy.length > 0 ? { policy } : {}), ...(wave ? { wave } : {}) };
|
|
188
|
+
const emit = (outcome, code) => {
|
|
189
|
+
if (a.json)
|
|
190
|
+
io.out(`${JSON.stringify(revertJson(plan, digest, { ...outcome, ...extra }), null, 2)}\n`);
|
|
191
|
+
return code;
|
|
192
|
+
};
|
|
193
|
+
if (!a.json) {
|
|
194
|
+
io.out(renderPlan(plan, digest));
|
|
195
|
+
for (const line of describeResults(policy))
|
|
196
|
+
io.out(`${line}\n`);
|
|
197
|
+
if (wave)
|
|
198
|
+
io.out(`${describeWave(env.name, wave)}\n`);
|
|
199
|
+
}
|
|
200
|
+
if (a.dryRun || !op)
|
|
201
|
+
return emit({ status: "planned" }, 0);
|
|
202
|
+
const denied = policyRefusal(policy, env.name, digest, "before the gate", { id: plan.migration.id, step: a.step });
|
|
203
|
+
if (denied) {
|
|
204
|
+
if (!a.json)
|
|
205
|
+
io.err(`yodel revert: ${denied.message}\n`);
|
|
206
|
+
return emit({ status: "denied" }, EXIT_REFUSED);
|
|
207
|
+
}
|
|
208
|
+
if (!a.json)
|
|
209
|
+
io.out(`\nRunning ${op.name} (${op.filePath}) to revert ${plan.migration.id}\n`);
|
|
210
|
+
const childEnv = { ...process.env, ...(a.lockWaitMs !== undefined ? { [LOCK_WAIT_ENV]: `${String(a.lockWaitMs)}ms` } : {}) };
|
|
211
|
+
const ran = await runMigrateOp(project, op, {
|
|
212
|
+
allowOutOfOrder: false,
|
|
213
|
+
env: childEnv,
|
|
214
|
+
revert: { id: plan.migration.id, ...(a.step !== undefined ? { step: resolve(project.dir, a.step) } : {}) },
|
|
215
|
+
onOutput: (t) => { io.err(t); },
|
|
216
|
+
});
|
|
217
|
+
if (ran.status === "gated") {
|
|
218
|
+
if (!a.json) {
|
|
219
|
+
io.out(`\n${op.name} is waiting at gate "${op.gate}" for approval of this revert${ran.planDigest ? ` (${ran.planDigest})` : ""}.\n`);
|
|
220
|
+
if (ran.approve)
|
|
221
|
+
io.out(`Approve it with:\n ${runnable(ran.approve, project.dir)}\nthen run ${runnable(`yodel revert ${env.name} ${plan.migration.id}${a.step !== undefined ? ` --step ${a.step}` : ""}`, project.dir)} again.\n`);
|
|
222
|
+
}
|
|
223
|
+
return emit({ status: "gated", op: op.name, gate: op.gate, ...(ran.approve ? { approve: ran.approve } : {}), ...(ran.planDigest ? { gatePlanDigest: ran.planDigest } : {}) }, GATED);
|
|
224
|
+
}
|
|
225
|
+
if (ran.status === "failed") {
|
|
226
|
+
const code = ran.stepExit !== undefined && ran.stepExit !== 0 ? ran.stepExit : 1;
|
|
227
|
+
if (!a.json)
|
|
228
|
+
io.err(`yodel revert: chant run ${op.name} failed (exit ${String(ran.code)})${ran.stepExit ? `: its Apply step exited ${String(ran.stepExit)}` : ""}\n`);
|
|
229
|
+
return emit({ status: "failed", op: op.name, exitCode: code }, code);
|
|
230
|
+
}
|
|
231
|
+
const after = await statusReport(venv, ordered);
|
|
232
|
+
const reverted = after.status.pending.find((p) => p.id === plan.migration.id)?.reverted !== undefined;
|
|
233
|
+
if (!reverted) {
|
|
234
|
+
if (!a.json)
|
|
235
|
+
io.err(`yodel revert: ${op.name} completed, but ${env.name}'s history does not record ${plan.migration.id} reverted\n`);
|
|
236
|
+
return emit({ status: "failed", op: op.name, exitCode: 1 }, 1);
|
|
237
|
+
}
|
|
238
|
+
if (!a.json)
|
|
239
|
+
io.out(`\nReverted ${plan.migration.id} in ${env.name}${after.server ? ` (${describeServer(after.server)})` : ""}, back to ${plan.to ?? "an empty schema"}.\n\n${renderStatus(after)}`);
|
|
240
|
+
return emit({ status: "reverted", op: op.name }, 0);
|
|
241
|
+
}
|
|
242
|
+
finally {
|
|
243
|
+
await closeVersioned(venv);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
//# sourceMappingURL=revert.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"revert.js","sourceRoot":"","sources":["../../src/commands/revert.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC5E,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAwB,MAAM,mBAAmB,CAAC;AACvF,OAAO,EACL,cAAc,EACd,aAAa,EACb,eAAe,EACf,aAAa,EACb,SAAS,EACT,WAAW,EACX,aAAa,EACb,aAAa,EACb,SAAS,EACT,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,YAAY,GAGb,MAAM,uBAAuB,CAAC;AAE/B,MAAM,KAAK,GAAG,8HAA8H,CAAC;AAE7I,MAAM,IAAI,GAAG,GAAG,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuDpB,CAAC;AAaF,SAAS,eAAe,CAAC,IAAc;IACrC,IAAI,MAAoC,CAAC;IACzC,IAAI,CAAC;QACH,MAAM,GAAG,SAAS,CAAC;YACjB,IAAI;YACJ,gBAAgB,EAAE,IAAI;YACtB,MAAM,EAAE,IAAI;YACZ,OAAO,EAAE;gBACP,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBACxB,SAAS,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;gBAC9B,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;gBACzB,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBACtB,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBAC/B,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE;aACpC;SACF,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,IAAI,UAAU,CAAC,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC;IAClF,CAAC;IACD,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC;IACvC,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC;IAC1D,MAAM,CAAC,KAAK,GAAG,EAAE,EAAE,MAAM,GAAG,EAAE,CAAC,GAAG,WAAW,CAAC;IAC9C,2EAA2E;IAC3E,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC7G,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,OAAO,MAAM,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACnF,OAAO;QACL,GAAG;QACH,EAAE;QACF,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC,SAAS,CAAC,KAAK,IAAI;QAClC,IAAI,EAAE,MAAM,CAAC,IAAI,KAAK,IAAI;QAC1B,EAAE,EAAE,GAAG,CAAC,IAAI,CAAC;QACb,UAAU,EAAE,OAAO,MAAM,CAAC,WAAW,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,SAAS;QACnH,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,GAAG,EAAE;KACjC,CAAC;AACJ,CAAC;AAaD,0LAA0L;AAC1L,MAAM,UAAU,YAAY,CAAC,IAAc,EAAE,IAAY,EAAE,OAAkC,EAAE,IAAgB;IAC7G,MAAM,KAAK,GAAG,gBAAgB,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,EAAE,QAAQ,EAAE,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;IACzK,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,gBAAgB,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,IAAI,KAAK,gBAAgB,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;AACpK,CAAC;AAED,yGAAyG;AACzG,KAAK,UAAU,UAAU,CAAC,OAAyC,EAAE,GAAW,EAAE,IAAgB;IAChG,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IACtF,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,MAAM,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IACpD,OAAO,YAAY,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,KAAK,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;AACtG,CAAC;AAED,SAAS,YAAY,CAAC,GAAW,EAAE,IAAgB;IACjD,MAAM,WAAW,GAAG,IAAI,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,gBAAgB,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,iBAAiB,CAAC;IACnL,OAAO,aAAa,IAAI,CAAC,IAAI,QAAQ,GAAG,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,mBAAmB,WAAW,KAAK,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,mGAAmG,EAAE,CAAC;AAChQ,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,UAAU,CAAC,IAAgB,EAAE,MAAc,EAAE,OAAgC;IAC3F,OAAO;QACL,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE;QAC5B,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,UAAU,EAAE,MAAM;QAClB,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACvN,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrH,GAAG,OAAO;KACX,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,IAAgB,EAAE,MAAc;IAClD,MAAM,KAAK,GAAG,CAAC,aAAa,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,IAAI,CAAC,WAAW,aAAa,IAAI,CAAC,EAAE,IAAI,iBAAiB,GAAG,CAAC,CAAC;IAClH,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC;QAC/C,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,mBAAmB,IAAI,CAAC,IAAI,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAC7K,KAAK,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,gDAAgD,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IAC1K,CAAC;IACD,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,qDAAqD,CAAC,CAAC;IACpG,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,6BAA6B,CAAC,CAAC;IAC1F,KAAK,CAAC,IAAI,CAAC,gBAAgB,MAAM,EAAE,CAAC,CAAC;IACrC,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AACjC,CAAC;AAED,+DAA+D;AAC/D,MAAM,CAAC,MAAM,MAAM,GAAY;IAC7B,IAAI,EAAE,QAAQ;IACd,OAAO,EAAE,6DAA6D;IACtE,WAAW,EAAE,IAAI;IACjB,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;CAC3F,CAAC;AAEF,KAAK,UAAU,GAAG,CAAC,CAAa,EAAE,EAAM;IACtC,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACzC,MAAM,GAAG,GAAG,kBAAkB,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;IAC/C,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;IACnC,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACpF,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAC/C,IAAI,CAAC;QACH,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QACxE,iIAAiI;QACjI,MAAM,UAAU,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,CAAC;QAC/C,IAAI,UAAU,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI;YAAE,EAAE,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,IAAI,IAAI,CAAC,CAAC;QAC/D,MAAM,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,aAAa,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;QAC1E,MAAM,MAAM,GAAiB,MAAM,WAAW,CAAC;YAC7C,MAAM,EAAE,UAAU,CAAC,MAAM;YACzB,WAAW,EAAE,GAAG,CAAC,IAAI;YACrB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,IAAI;YACJ,MAAM;YACN,MAAM,EAAE,KAAK,IAAI,EAAE;gBACjB,IAAI,CAAC;oBACH,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,MAAM,aAAa,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;gBACrG,CAAC;gBAAC,MAAM,CAAC;oBACP,OAAO,SAAS,CAAC;gBACnB,CAAC;YACH,CAAC;SACF,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACvD,MAAM,KAAK,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QACtF,MAAM,IAAI,GAAG,CAAC,OAAgC,EAAE,IAAY,EAAE,EAAE;YAC9D,IAAI,CAAC,CAAC,IAAI;gBAAE,EAAE,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,OAAO,EAAE,GAAG,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;YACvG,OAAO,IAAI,CAAC;QACd,CAAC,CAAC;QACF,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACZ,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;YACjC,KAAK,MAAM,IAAI,IAAI,eAAe,CAAC,MAAM,CAAC;gBAAE,EAAE,CAAC,GAAG,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC;YAChE,IAAI,IAAI;gBAAE,EAAE,CAAC,GAAG,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QACxD,CAAC;QACD,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC;QAC3D,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,iBAAiB,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QACnH,IAAI,MAAM,EAAE,CAAC;YACX,IAAI,CAAC,CAAC,CAAC,IAAI;gBAAE,EAAE,CAAC,GAAG,CAAC,iBAAiB,MAAM,CAAC,OAAO,IAAI,CAAC,CAAC;YACzD,OAAO,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,YAAY,CAAC,CAAC;QAClD,CAAC;QAED,IAAI,CAAC,CAAC,CAAC,IAAI;YAAE,EAAE,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC,QAAQ,eAAe,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC,CAAC;QAC9F,MAAM,QAAQ,GAAsB,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAChJ,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,OAAO,EAAE,EAAE,EAAE;YAC1C,eAAe,EAAE,KAAK;YACtB,GAAG,EAAE,QAAQ;YACb,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;YAC1G,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SAChC,CAAC,CAAC;QACH,IAAI,GAAG,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;YAC3B,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBACZ,EAAE,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,IAAI,wBAAwB,EAAE,CAAC,IAAI,gCAAgC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;gBACrI,IAAI,GAAG,CAAC,OAAO;oBAAE,EAAE,CAAC,GAAG,CAAC,uBAAuB,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,QAAQ,CAAC,gBAAgB,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YACtO,CAAC;YACD,OAAO,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QACvL,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC5B,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,KAAK,SAAS,IAAI,GAAG,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;YACjF,IAAI,CAAC,CAAC,CAAC,IAAI;gBAAE,EAAE,CAAC,GAAG,CAAC,2BAA2B,EAAE,CAAC,IAAI,iBAAiB,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,2BAA2B,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;YACtK,OAAO,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,IAAI,CAAC,CAAC;QACvE,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAChD,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,QAAQ,KAAK,SAAS,CAAC;QACtG,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,IAAI,CAAC,CAAC,CAAC,IAAI;gBAAE,EAAE,CAAC,GAAG,CAAC,iBAAiB,EAAE,CAAC,IAAI,mBAAmB,GAAG,CAAC,IAAI,8BAA8B,IAAI,CAAC,SAAS,CAAC,EAAE,aAAa,CAAC,CAAC;YACrI,OAAO,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QACjE,CAAC;QACD,IAAI,CAAC,CAAC,CAAC,IAAI;YAAE,EAAE,CAAC,GAAG,CAAC,cAAc,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,cAAc,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,aAAa,IAAI,CAAC,EAAE,IAAI,iBAAiB,QAAQ,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACrM,OAAO,IAAI,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;IACtD,CAAC;YAAS,CAAC;QACT,MAAM,cAAc,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;AACH,CAAC"}
|
package/dist/commands/status.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { guarded, parseEnvArgs, usage } from "../env-args.js";
|
|
2
2
|
import { loadProject, resolveEnvironment } from "../project.js";
|
|
3
|
+
import { listTenants, tenantTarget } from "../tenants/index.js";
|
|
3
4
|
import { closeVersioned, openVersioned, readChain, renderStatus, statusJson, statusReport } from "../versioned/index.js";
|
|
4
5
|
/** Exit code: migrations are pending, and nothing is wrong. */
|
|
5
6
|
export const STATUS_PENDING = 3;
|
|
@@ -16,6 +17,10 @@ whose files changed, or that is gone from the directory). When yodel apply
|
|
|
16
17
|
would run, prints the plan digest it would ask approval for. Reads only;
|
|
17
18
|
takes no lock.
|
|
18
19
|
|
|
20
|
+
An environment with a tenant set (yodel.config.ts environments.<env>.tenants)
|
|
21
|
+
is listed tenant by tenant, each against its own history, then a line of how
|
|
22
|
+
many tenants are up to date; <env>/<tenant> names one tenant.
|
|
23
|
+
|
|
19
24
|
Options:
|
|
20
25
|
--json print the status as JSON
|
|
21
26
|
-C, --dir <dir> the project directory (default: the working directory)
|
|
@@ -39,16 +44,38 @@ export const status = {
|
|
|
39
44
|
const project = await loadProject(dir);
|
|
40
45
|
const env = resolveEnvironment(project, name);
|
|
41
46
|
const ordered = readChain(project);
|
|
42
|
-
const
|
|
43
|
-
|
|
47
|
+
const tenants = env.tenant ? undefined : await listTenants(project, env.name);
|
|
48
|
+
if (tenants)
|
|
49
|
+
return tenantsStatus(project, env.name, tenants, ordered, json, io);
|
|
50
|
+
const report = await readStatus(project, env.name, ordered);
|
|
44
51
|
if (json)
|
|
45
52
|
io.out(`${JSON.stringify(statusJson(report), null, 2)}\n`);
|
|
46
53
|
// The sections already say what is wrong; the refusal's wording is apply's.
|
|
47
54
|
else
|
|
48
55
|
io.out(renderStatus({ ...report, refusal: undefined }));
|
|
49
|
-
|
|
50
|
-
return report.refusal.exitCode;
|
|
51
|
-
return report.status.pending.length > 0 ? STATUS_PENDING : 0;
|
|
56
|
+
return exitOf(report);
|
|
52
57
|
}),
|
|
53
58
|
};
|
|
59
|
+
async function readStatus(project, name, ordered) {
|
|
60
|
+
const venv = await openVersioned(project, resolveEnvironment(project, name));
|
|
61
|
+
return statusReport(venv, ordered, { sync: false }).finally(() => closeVersioned(venv));
|
|
62
|
+
}
|
|
63
|
+
const exitOf = (report) => report.refusal?.exitCode ?? (report.status.pending.length > 0 ? STATUS_PENDING : 0);
|
|
64
|
+
/** A tenant set's status (#56): each tenant's, then how many are up to date. The exit code is the worst tenant's: a refusal, then pending. */
|
|
65
|
+
async function tenantsStatus(project, env, tenants, ordered, json, io) {
|
|
66
|
+
const reports = [];
|
|
67
|
+
for (const t of tenants) {
|
|
68
|
+
const report = await readStatus(project, tenantTarget(env, t), ordered);
|
|
69
|
+
reports.push(report);
|
|
70
|
+
if (!json)
|
|
71
|
+
io.out(`${renderStatus({ ...report, refusal: undefined })}\n`);
|
|
72
|
+
}
|
|
73
|
+
const upToDate = reports.filter((r) => !r.refusal && r.status.pending.length === 0).length;
|
|
74
|
+
if (json)
|
|
75
|
+
io.out(`${JSON.stringify({ environment: env, tenants: reports.map((r) => statusJson(r)), upToDate, total: reports.length }, null, 2)}\n`);
|
|
76
|
+
else
|
|
77
|
+
io.out(`${env}: ${String(upToDate)} of ${String(reports.length)} tenants up to date${upToDate < reports.length ? `; behind: ${reports.filter((r) => r.refusal || r.status.pending.length > 0).map((r) => r.environment).join(", ")}` : ""}\n`);
|
|
78
|
+
const codes = reports.map(exitOf);
|
|
79
|
+
return codes.find((c) => c !== 0 && c !== STATUS_PENDING) ?? (codes.includes(STATUS_PENDING) ? STATUS_PENDING : 0);
|
|
80
|
+
}
|
|
54
81
|
//# sourceMappingURL=status.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,kBAAkB,
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading the project's config as it is at the base commit: the commit a
|
|
3
|
+
* change merges onto. A setting that decides how a change is gated (a
|
|
4
|
+
* wave's gate policy) is read there, never from the change itself, so a
|
|
5
|
+
* pull request cannot loosen the rule that gates its own merge.
|
|
6
|
+
*
|
|
7
|
+
* The base is, first one that applies:
|
|
8
|
+
*
|
|
9
|
+
* 1. `YODEL_BASE`, a commit-ish;
|
|
10
|
+
* 2. on a pull request, the merge base of `HEAD` and the target branch
|
|
11
|
+
* (`GITHUB_BASE_REF` on GitHub and Forgejo,
|
|
12
|
+
* `CI_MERGE_REQUEST_TARGET_BRANCH_NAME` on GitLab), on `origin`;
|
|
13
|
+
* 3. `HEAD^1`, the first parent: after a merge or a squash onto the
|
|
14
|
+
* branch, the branch as it was before the change.
|
|
15
|
+
*
|
|
16
|
+
* chant's wave runner reads its spec file at the first parent too
|
|
17
|
+
* (`chant run wave`), so the two agree on a push to the branch.
|
|
18
|
+
*/
|
|
19
|
+
import type { PolicyConfig, YodelConfig } from "./define.js";
|
|
20
|
+
export declare const BASE_ENV = "YODEL_BASE";
|
|
21
|
+
/** Where the base was taken from, for messages. */
|
|
22
|
+
export interface BaseRef {
|
|
23
|
+
/** What `git rev-parse` resolves. */
|
|
24
|
+
ref: string;
|
|
25
|
+
/** How it was chosen. */
|
|
26
|
+
source: string;
|
|
27
|
+
}
|
|
28
|
+
/** The base commit to read at, by the rule at the top. */
|
|
29
|
+
export declare function baseRef(cwd: string, env?: NodeJS.ProcessEnv): BaseRef;
|
|
30
|
+
/** The file at `path` (relative to `cwd`) at commit `ref`; text null when that commit has no such file. */
|
|
31
|
+
export declare function fileAtBase(cwd: string, path: string, ref: string): {
|
|
32
|
+
sha: string;
|
|
33
|
+
text: string | null;
|
|
34
|
+
};
|
|
35
|
+
/** yodel.config.ts as the base commit has it. */
|
|
36
|
+
export interface ConfigAtBase {
|
|
37
|
+
base: BaseRef;
|
|
38
|
+
sha: string;
|
|
39
|
+
/** Undefined when the base has no yodel.config.ts. */
|
|
40
|
+
config: YodelConfig | undefined;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Loads `<dir>/yodel.config.ts` as it is at the base. The file is
|
|
44
|
+
* evaluated from a copy beside the project's own, so its imports resolve
|
|
45
|
+
* as they do there, and the copy is removed after.
|
|
46
|
+
*/
|
|
47
|
+
export declare function loadYodelConfigAtBase(dir: string, env?: NodeJS.ProcessEnv): Promise<ConfigAtBase>;
|
|
48
|
+
/** The plan policy (#53) as the base commit has it (#73). */
|
|
49
|
+
export interface PolicyAtBase {
|
|
50
|
+
policy: PolicyConfig | undefined;
|
|
51
|
+
/** The base commit read, when one could be. */
|
|
52
|
+
sha?: string;
|
|
53
|
+
/** Why the working tree's policy is not the one that applies, when it differs; for the plan and apply to say. */
|
|
54
|
+
note?: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* `policy` from yodel.config.ts at the base commit, never the working
|
|
58
|
+
* tree's: a pull request that weakens or deletes a rule is judged by the
|
|
59
|
+
* rule the branch had. A base with no policy (or no yodel.config.ts) applies
|
|
60
|
+
* none, whatever the working tree adds, and the note says so. A checkout
|
|
61
|
+
* with no base to read (no git, a repository's first commit) applies none
|
|
62
|
+
* either.
|
|
63
|
+
*/
|
|
64
|
+
export declare function policyAtBase(project: {
|
|
65
|
+
dir: string;
|
|
66
|
+
yodel?: {
|
|
67
|
+
config: YodelConfig;
|
|
68
|
+
} | undefined;
|
|
69
|
+
}, env?: NodeJS.ProcessEnv): Promise<PolicyAtBase>;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading the project's config as it is at the base commit: the commit a
|
|
3
|
+
* change merges onto. A setting that decides how a change is gated (a
|
|
4
|
+
* wave's gate policy) is read there, never from the change itself, so a
|
|
5
|
+
* pull request cannot loosen the rule that gates its own merge.
|
|
6
|
+
*
|
|
7
|
+
* The base is, first one that applies:
|
|
8
|
+
*
|
|
9
|
+
* 1. `YODEL_BASE`, a commit-ish;
|
|
10
|
+
* 2. on a pull request, the merge base of `HEAD` and the target branch
|
|
11
|
+
* (`GITHUB_BASE_REF` on GitHub and Forgejo,
|
|
12
|
+
* `CI_MERGE_REQUEST_TARGET_BRANCH_NAME` on GitLab), on `origin`;
|
|
13
|
+
* 3. `HEAD^1`, the first parent: after a merge or a squash onto the
|
|
14
|
+
* branch, the branch as it was before the change.
|
|
15
|
+
*
|
|
16
|
+
* chant's wave runner reads its spec file at the first parent too
|
|
17
|
+
* (`chant run wave`), so the two agree on a push to the branch.
|
|
18
|
+
*/
|
|
19
|
+
import { execFileSync } from "node:child_process";
|
|
20
|
+
import { existsSync, unlinkSync, writeFileSync } from "node:fs";
|
|
21
|
+
import { join } from "node:path";
|
|
22
|
+
import { pathToFileURL } from "node:url";
|
|
23
|
+
import { YodelError } from "../project.js";
|
|
24
|
+
import { checkYodelConfig, CONFIG_FILE } from "./load.js";
|
|
25
|
+
export const BASE_ENV = "YODEL_BASE";
|
|
26
|
+
const git = (cwd, args) => execFileSync("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
|
|
27
|
+
/** The base commit to read at, by the rule at the top. */
|
|
28
|
+
export function baseRef(cwd, env = process.env) {
|
|
29
|
+
const set = env[BASE_ENV];
|
|
30
|
+
if (set)
|
|
31
|
+
return { ref: set, source: BASE_ENV };
|
|
32
|
+
const target = env.CI_MERGE_REQUEST_TARGET_BRANCH_NAME || env.GITHUB_BASE_REF;
|
|
33
|
+
if (target) {
|
|
34
|
+
try {
|
|
35
|
+
return { ref: git(cwd, ["merge-base", "HEAD", `origin/${target}`]), source: `the merge base with origin/${target}` };
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// A shallow or partial checkout: fall through to the first parent.
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return { ref: "HEAD^1", source: "HEAD^1, the commit the change merged onto" };
|
|
42
|
+
}
|
|
43
|
+
/** The file at `path` (relative to `cwd`) at commit `ref`; text null when that commit has no such file. */
|
|
44
|
+
export function fileAtBase(cwd, path, ref) {
|
|
45
|
+
let sha;
|
|
46
|
+
try {
|
|
47
|
+
sha = git(cwd, ["rev-parse", "--verify", `${ref}^{commit}`]);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
throw new YodelError(`the config is read at the base commit ${ref}, which this checkout does not have. ` +
|
|
51
|
+
`Check out the full history (fetch-depth: 0 on GitHub and Forgejo, GIT_DEPTH: "0" on GitLab), or set ${BASE_ENV}.`);
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
return { sha, text: execFileSync("git", ["show", `${sha}:./${path.split("\\").join("/")}`], { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }) };
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return { sha, text: null };
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Loads `<dir>/yodel.config.ts` as it is at the base. The file is
|
|
62
|
+
* evaluated from a copy beside the project's own, so its imports resolve
|
|
63
|
+
* as they do there, and the copy is removed after.
|
|
64
|
+
*/
|
|
65
|
+
export async function loadYodelConfigAtBase(dir, env = process.env) {
|
|
66
|
+
const base = baseRef(dir, env);
|
|
67
|
+
const { sha, text } = fileAtBase(dir, CONFIG_FILE, base.ref);
|
|
68
|
+
if (text === null)
|
|
69
|
+
return { base, sha, config: undefined };
|
|
70
|
+
const copy = join(dir, `.yodel.config.base-${sha.slice(0, 12)}-${String(process.pid)}.ts`);
|
|
71
|
+
writeFileSync(copy, text);
|
|
72
|
+
try {
|
|
73
|
+
let mod;
|
|
74
|
+
try {
|
|
75
|
+
mod = (await import(`${pathToFileURL(copy).href}?base=${sha}`));
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
throw new YodelError(`${CONFIG_FILE} at ${sha.slice(0, 12)} (${base.source}): ${e instanceof Error ? e.message : String(e)}`);
|
|
79
|
+
}
|
|
80
|
+
// Not checked against the profiles: the base may name an environment the change removes.
|
|
81
|
+
return { base, sha, config: checkYodelConfig(mod.default, `${CONFIG_FILE} at ${sha.slice(0, 12)}`) };
|
|
82
|
+
}
|
|
83
|
+
finally {
|
|
84
|
+
if (existsSync(copy))
|
|
85
|
+
unlinkSync(copy);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* `policy` from yodel.config.ts at the base commit, never the working
|
|
90
|
+
* tree's: a pull request that weakens or deletes a rule is judged by the
|
|
91
|
+
* rule the branch had. A base with no policy (or no yodel.config.ts) applies
|
|
92
|
+
* none, whatever the working tree adds, and the note says so. A checkout
|
|
93
|
+
* with no base to read (no git, a repository's first commit) applies none
|
|
94
|
+
* either.
|
|
95
|
+
*/
|
|
96
|
+
export async function policyAtBase(project, env = process.env) {
|
|
97
|
+
const tree = project.yodel?.config.policy;
|
|
98
|
+
let at;
|
|
99
|
+
try {
|
|
100
|
+
at = await loadYodelConfigAtBase(project.dir, env);
|
|
101
|
+
}
|
|
102
|
+
catch (e) {
|
|
103
|
+
const why = e instanceof Error ? (e.message.split("\n")[0] ?? "") : String(e);
|
|
104
|
+
return { policy: undefined, ...(tree ? { note: `The policy is read at the base commit, and there is none to read (${why}), so no policy applies.` } : {}) };
|
|
105
|
+
}
|
|
106
|
+
const policy = at.config?.policy;
|
|
107
|
+
const short = at.sha.slice(0, 12);
|
|
108
|
+
if (tree && !policy) {
|
|
109
|
+
return { policy: undefined, sha: at.sha, note: `yodel.config.ts at ${short} (${at.base.source}) declares no policy, so none applies; the working tree's applies once it is on the branch.` };
|
|
110
|
+
}
|
|
111
|
+
if (policy && !samePolicy(tree, policy)) {
|
|
112
|
+
return { policy, sha: at.sha, note: `The policy applied is yodel.config.ts's at ${short} (${at.base.source}), not the working tree's, which applies once it is on the branch.` };
|
|
113
|
+
}
|
|
114
|
+
return { policy, sha: at.sha };
|
|
115
|
+
}
|
|
116
|
+
/** Whether two policies say the same: their rules by id and what each declares (a check by its source), and their overriders. */
|
|
117
|
+
function samePolicy(a, b) {
|
|
118
|
+
const canon = (p) => JSON.stringify(p, (_k, v) => (v instanceof RegExp ? v.toString() : typeof v === "function" ? v.toString() : v));
|
|
119
|
+
return canon(a) === canon(b);
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=base.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.js","sourceRoot":"","sources":["../../src/config/base.ts"],"names":[],"mappings":"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"}
|