@intentius/sql-yodeler 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +112 -2
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +29 -0
- package/dist/bin.js.map +1 -0
- package/dist/chant/apply.d.ts +59 -0
- package/dist/chant/apply.js +116 -0
- package/dist/chant/apply.js.map +1 -0
- package/dist/chant/build.d.ts +34 -0
- package/dist/chant/build.js +48 -0
- package/dist/chant/build.js.map +1 -0
- package/dist/chant/drift.d.ts +112 -0
- package/dist/chant/drift.js +238 -0
- package/dist/chant/drift.js.map +1 -0
- package/dist/chant/plan.d.ts +45 -0
- package/dist/chant/plan.js +61 -0
- package/dist/chant/plan.js.map +1 -0
- package/dist/chant/process.d.ts +41 -0
- package/dist/chant/process.js +87 -0
- package/dist/chant/process.js.map +1 -0
- package/dist/chant/runnable.d.ts +19 -0
- package/dist/chant/runnable.js +47 -0
- package/dist/chant/runnable.js.map +1 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.js +99 -0
- package/dist/cli.js.map +1 -0
- package/dist/command.d.ts +23 -0
- package/dist/command.js +13 -0
- package/dist/command.js.map +1 -0
- package/dist/commands/apply.d.ts +3 -0
- package/dist/commands/apply.js +426 -0
- package/dist/commands/apply.js.map +1 -0
- package/dist/commands/approve.d.ts +5 -0
- package/dist/commands/approve.js +111 -0
- package/dist/commands/approve.js.map +1 -0
- package/dist/commands/drift.d.ts +14 -0
- package/dist/commands/drift.js +267 -0
- package/dist/commands/drift.js.map +1 -0
- package/dist/commands/index.d.ts +3 -0
- package/dist/commands/index.js +28 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/init.d.ts +6 -0
- package/dist/commands/init.js +139 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/lint.d.ts +3 -0
- package/dist/commands/lint.js +202 -0
- package/dist/commands/lint.js.map +1 -0
- package/dist/commands/mcp.d.ts +3 -0
- package/dist/commands/mcp.js +50 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/new.d.ts +5 -0
- package/dist/commands/new.js +292 -0
- package/dist/commands/new.js.map +1 -0
- package/dist/commands/override.d.ts +3 -0
- package/dist/commands/override.js +118 -0
- package/dist/commands/override.js.map +1 -0
- package/dist/commands/plan.d.ts +3 -0
- package/dist/commands/plan.js +183 -0
- package/dist/commands/plan.js.map +1 -0
- package/dist/commands/rebase.d.ts +3 -0
- package/dist/commands/rebase.js +167 -0
- package/dist/commands/rebase.js.map +1 -0
- package/dist/commands/repair.d.ts +14 -0
- package/dist/commands/repair.js +125 -0
- package/dist/commands/repair.js.map +1 -0
- package/dist/commands/status.d.ts +7 -0
- package/dist/commands/status.js +54 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/config/define.d.ts +148 -0
- package/dist/config/define.js +20 -0
- package/dist/config/define.js.map +1 -0
- package/dist/config/index.d.ts +11 -0
- package/dist/config/index.js +12 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/load.d.ts +17 -0
- package/dist/config/load.js +162 -0
- package/dist/config/load.js.map +1 -0
- package/dist/config/settings.d.ts +53 -0
- package/dist/config/settings.js +116 -0
- package/dist/config/settings.js.map +1 -0
- package/dist/env-args.d.ts +24 -0
- package/dist/env-args.js +92 -0
- package/dist/env-args.js.map +1 -0
- package/dist/exit.d.ts +20 -0
- package/dist/exit.js +28 -0
- package/dist/exit.js.map +1 -0
- package/dist/history/client.d.ts +25 -0
- package/dist/history/client.js +42 -0
- package/dist/history/client.js.map +1 -0
- package/dist/history/ddl.d.ts +58 -0
- package/dist/history/ddl.js +100 -0
- package/dist/history/ddl.js.map +1 -0
- package/dist/history/index.d.ts +25 -0
- package/dist/history/index.js +26 -0
- package/dist/history/index.js.map +1 -0
- package/dist/history/lock.d.ts +104 -0
- package/dist/history/lock.js +230 -0
- package/dist/history/lock.js.map +1 -0
- package/dist/history/postgres/ddl.d.ts +22 -0
- package/dist/history/postgres/ddl.js +47 -0
- package/dist/history/postgres/ddl.js.map +1 -0
- package/dist/history/postgres/index.d.ts +12 -0
- package/dist/history/postgres/index.js +13 -0
- package/dist/history/postgres/index.js.map +1 -0
- package/dist/history/postgres/lock.d.ts +48 -0
- package/dist/history/postgres/lock.js +95 -0
- package/dist/history/postgres/lock.js.map +1 -0
- package/dist/history/postgres/store.d.ts +39 -0
- package/dist/history/postgres/store.js +68 -0
- package/dist/history/postgres/store.js.map +1 -0
- package/dist/history/rows.d.ts +96 -0
- package/dist/history/rows.js +73 -0
- package/dist/history/rows.js.map +1 -0
- package/dist/history/store.d.ts +72 -0
- package/dist/history/store.js +134 -0
- package/dist/history/store.js.map +1 -0
- package/dist/history/topology.d.ts +41 -0
- package/dist/history/topology.js +54 -0
- package/dist/history/topology.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/init/adopt.d.ts +70 -0
- package/dist/init/adopt.js +143 -0
- package/dist/init/adopt.js.map +1 -0
- package/dist/init/baseline.d.ts +61 -0
- package/dist/init/baseline.js +88 -0
- package/dist/init/baseline.js.map +1 -0
- package/dist/init/files.d.ts +23 -0
- package/dist/init/files.js +77 -0
- package/dist/init/files.js.map +1 -0
- package/dist/init/index.d.ts +16 -0
- package/dist/init/index.js +17 -0
- package/dist/init/index.js.map +1 -0
- package/dist/init/live.d.ts +39 -0
- package/dist/init/live.js +68 -0
- package/dist/init/live.js.map +1 -0
- package/dist/lint/check.d.ts +88 -0
- package/dist/lint/check.js +227 -0
- package/dist/lint/check.js.map +1 -0
- package/dist/lint/config.d.ts +21 -0
- package/dist/lint/config.js +43 -0
- package/dist/lint/config.js.map +1 -0
- package/dist/lint/index.d.ts +31 -0
- package/dist/lint/index.js +43 -0
- package/dist/lint/index.js.map +1 -0
- package/dist/lint/project-rules.d.ts +19 -0
- package/dist/lint/project-rules.js +32 -0
- package/dist/lint/project-rules.js.map +1 -0
- package/dist/lint/report.d.ts +7 -0
- package/dist/lint/report.js +48 -0
- package/dist/lint/report.js.map +1 -0
- package/dist/lint/rules.d.ts +53 -0
- package/dist/lint/rules.js +42 -0
- package/dist/lint/rules.js.map +1 -0
- package/dist/lint/silences.d.ts +49 -0
- package/dist/lint/silences.js +91 -0
- package/dist/lint/silences.js.map +1 -0
- package/dist/lint/statements.d.ts +38 -0
- package/dist/lint/statements.js +120 -0
- package/dist/lint/statements.js.map +1 -0
- package/dist/mcp/server.d.ts +40 -0
- package/dist/mcp/server.js +106 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools.d.ts +72 -0
- package/dist/mcp/tools.js +178 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/migrations/checks.d.ts +28 -0
- package/dist/migrations/checks.js +97 -0
- package/dist/migrations/checks.js.map +1 -0
- package/dist/migrations/checksum.d.ts +56 -0
- package/dist/migrations/checksum.js +72 -0
- package/dist/migrations/checksum.js.map +1 -0
- package/dist/migrations/create.d.ts +75 -0
- package/dist/migrations/create.js +120 -0
- package/dist/migrations/create.js.map +1 -0
- package/dist/migrations/directory.d.ts +119 -0
- package/dist/migrations/directory.js +229 -0
- package/dist/migrations/directory.js.map +1 -0
- package/dist/migrations/document.d.ts +106 -0
- package/dist/migrations/document.js +83 -0
- package/dist/migrations/document.js.map +1 -0
- package/dist/migrations/index.d.ts +21 -0
- package/dist/migrations/index.js +22 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/pr/comment.d.ts +32 -0
- package/dist/pr/comment.js +99 -0
- package/dist/pr/comment.js.map +1 -0
- package/dist/pr/forge.d.ts +54 -0
- package/dist/pr/forge.js +119 -0
- package/dist/pr/forge.js.map +1 -0
- package/dist/pr/issue.d.ts +68 -0
- package/dist/pr/issue.js +107 -0
- package/dist/pr/issue.js.map +1 -0
- package/dist/pr/model.d.ts +99 -0
- package/dist/pr/model.js +137 -0
- package/dist/pr/model.js.map +1 -0
- package/dist/pr/render.d.ts +29 -0
- package/dist/pr/render.js +279 -0
- package/dist/pr/render.js.map +1 -0
- package/dist/project.d.ts +62 -0
- package/dist/project.js +92 -0
- package/dist/project.js.map +1 -0
- package/dist/rebase/index.d.ts +121 -0
- package/dist/rebase/index.js +390 -0
- package/dist/rebase/index.js.map +1 -0
- package/dist/rebase/repair.d.ts +41 -0
- package/dist/rebase/repair.js +68 -0
- package/dist/rebase/repair.js.map +1 -0
- package/dist/replay/clickhouse.d.ts +33 -0
- package/dist/replay/clickhouse.js +106 -0
- package/dist/replay/clickhouse.js.map +1 -0
- package/dist/replay/index.d.ts +39 -0
- package/dist/replay/index.js +57 -0
- package/dist/replay/index.js.map +1 -0
- package/dist/replay/postgres.d.ts +31 -0
- package/dist/replay/postgres.js +140 -0
- package/dist/replay/postgres.js.map +1 -0
- package/dist/replay/replay.d.ts +114 -0
- package/dist/replay/replay.js +98 -0
- package/dist/replay/replay.js.map +1 -0
- package/dist/replay/report.d.ts +18 -0
- package/dist/replay/report.js +72 -0
- package/dist/replay/report.js.map +1 -0
- package/dist/replay/shared.d.ts +28 -0
- package/dist/replay/shared.js +77 -0
- package/dist/replay/shared.js.map +1 -0
- package/dist/schemas.d.ts +34 -0
- package/dist/schemas.js +38 -0
- package/dist/schemas.js.map +1 -0
- package/dist/server.d.ts +40 -0
- package/dist/server.js +87 -0
- package/dist/server.js.map +1 -0
- package/dist/steps/backfill.d.ts +132 -0
- package/dist/steps/backfill.js +307 -0
- package/dist/steps/backfill.js.map +1 -0
- package/dist/steps/index.d.ts +52 -0
- package/dist/steps/index.js +52 -0
- package/dist/steps/index.js.map +1 -0
- package/dist/steps/kinds.d.ts +101 -0
- package/dist/steps/kinds.js +143 -0
- package/dist/steps/kinds.js.map +1 -0
- package/dist/steps/postgres-migration.d.ts +95 -0
- package/dist/steps/postgres-migration.js +149 -0
- package/dist/steps/postgres-migration.js.map +1 -0
- package/dist/steps/rebuild.d.ts +97 -0
- package/dist/steps/rebuild.js +155 -0
- package/dist/steps/rebuild.js.map +1 -0
- package/dist/steps/run.d.ts +45 -0
- package/dist/steps/run.js +72 -0
- package/dist/steps/run.js.map +1 -0
- package/dist/topology/render.d.ts +17 -0
- package/dist/topology/render.js +17 -0
- package/dist/topology/render.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +11 -0
- package/dist/version.js.map +1 -0
- package/dist/versioned/approval.d.ts +35 -0
- package/dist/versioned/approval.js +53 -0
- package/dist/versioned/approval.js.map +1 -0
- package/dist/versioned/checks.d.ts +29 -0
- package/dist/versioned/checks.js +54 -0
- package/dist/versioned/checks.js.map +1 -0
- package/dist/versioned/clickhouse.d.ts +24 -0
- package/dist/versioned/clickhouse.js +42 -0
- package/dist/versioned/clickhouse.js.map +1 -0
- package/dist/versioned/digest.d.ts +77 -0
- package/dist/versioned/digest.js +69 -0
- package/dist/versioned/digest.js.map +1 -0
- package/dist/versioned/driver.d.ts +51 -0
- package/dist/versioned/driver.js +13 -0
- package/dist/versioned/driver.js.map +1 -0
- package/dist/versioned/engine.d.ts +206 -0
- package/dist/versioned/engine.js +370 -0
- package/dist/versioned/engine.js.map +1 -0
- package/dist/versioned/explain.d.ts +123 -0
- package/dist/versioned/explain.js +294 -0
- package/dist/versioned/explain.js.map +1 -0
- package/dist/versioned/index.d.ts +46 -0
- package/dist/versioned/index.js +77 -0
- package/dist/versioned/index.js.map +1 -0
- package/dist/versioned/op.d.ts +72 -0
- package/dist/versioned/op.js +185 -0
- package/dist/versioned/op.js.map +1 -0
- package/dist/versioned/policy.d.ts +67 -0
- package/dist/versioned/policy.js +161 -0
- package/dist/versioned/policy.js.map +1 -0
- package/dist/versioned/postgres/catalog.d.ts +33 -0
- package/dist/versioned/postgres/catalog.js +34 -0
- package/dist/versioned/postgres/catalog.js.map +1 -0
- package/dist/versioned/postgres/driver.d.ts +71 -0
- package/dist/versioned/postgres/driver.js +140 -0
- package/dist/versioned/postgres/driver.js.map +1 -0
- package/dist/versioned/postgres/executor.d.ts +104 -0
- package/dist/versioned/postgres/executor.js +172 -0
- package/dist/versioned/postgres/executor.js.map +1 -0
- package/dist/versioned/postgres/index.d.ts +11 -0
- package/dist/versioned/postgres/index.js +12 -0
- package/dist/versioned/postgres/index.js.map +1 -0
- package/dist/versioned/postgres/waits.d.ts +46 -0
- package/dist/versioned/postgres/waits.js +78 -0
- package/dist/versioned/postgres/waits.js.map +1 -0
- package/dist/versioned/report.d.ts +25 -0
- package/dist/versioned/report.js +84 -0
- package/dist/versioned/report.js.map +1 -0
- package/dist/versioned/stand-down.d.ts +30 -0
- package/dist/versioned/stand-down.js +56 -0
- package/dist/versioned/stand-down.js.map +1 -0
- package/dist/versioned/state.d.ts +108 -0
- package/dist/versioned/state.js +153 -0
- package/dist/versioned/state.js.map +1 -0
- package/package.json +61 -4
- package/schemas/apply.schema.json +269 -0
- package/schemas/common.schema.json +213 -0
- package/schemas/drift.schema.json +36 -0
- package/schemas/init.schema.json +31 -0
- package/schemas/lint-rules.schema.json +54 -0
- package/schemas/lint.schema.json +290 -0
- package/schemas/mcp.schema.json +70 -0
- package/schemas/new.schema.json +71 -0
- package/schemas/plan.schema.json +371 -0
- package/schemas/rebase.schema.json +54 -0
- package/schemas/repair.schema.json +20 -0
- package/schemas/status.schema.json +310 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drift: the declared objects whose live definition changed out of band, or
|
|
3
|
+
* that are gone from the server. Read from `chant lifecycle diff <env> --live
|
|
4
|
+
* --json`, the sql lexicon's section of it:
|
|
5
|
+
*
|
|
6
|
+
* - `deep.drifted[].changes[]`: a declared object whose live definition
|
|
7
|
+
* differs, property by property, declared against live;
|
|
8
|
+
* - `resources.missing`: a declared object the server does not have;
|
|
9
|
+
* - `resources.unobserved` and `deep.unobserved`: a declared object chant
|
|
10
|
+
* could not read (no credentials, a kind it cannot observe). Not drift, and
|
|
11
|
+
* not clean either: that part of the environment is unknown.
|
|
12
|
+
*
|
|
13
|
+
* An object the project does not declare is never reported: chant only reads
|
|
14
|
+
* what the project declares, and only touches what carries its marker.
|
|
15
|
+
*/
|
|
16
|
+
import type { LiveDiffResult, UnobservedResource } from "@intentius/chant/lifecycle/live-diff";
|
|
17
|
+
import type { DeepDiffResult, DeepEntityDrift } from "@intentius/chant/lifecycle/deep-diff";
|
|
18
|
+
import { type Environment, type Project } from "../project.js";
|
|
19
|
+
import { type ServerInfo } from "../server.js";
|
|
20
|
+
import type { BuildOutput } from "./build.js";
|
|
21
|
+
/** The `lexicons.sql` section of `chant lifecycle diff --live --json`. */
|
|
22
|
+
export interface SqlLiveDiff {
|
|
23
|
+
resources?: LiveDiffResult;
|
|
24
|
+
deep?: DeepDiffResult;
|
|
25
|
+
}
|
|
26
|
+
export interface Drift {
|
|
27
|
+
environment: string;
|
|
28
|
+
/** Declared objects whose live definition differs from the declaration. */
|
|
29
|
+
changed: DeepEntityDrift[];
|
|
30
|
+
/** Declared objects the server does not have. */
|
|
31
|
+
missing: string[];
|
|
32
|
+
/** Declared objects chant could not read. */
|
|
33
|
+
unobserved: UnobservedResource[];
|
|
34
|
+
/** Postgres: a read gave up at the lock timeout, and what it waited on (#18). */
|
|
35
|
+
lockWait?: string | undefined;
|
|
36
|
+
/** Each changed table's declared column names, by position, so `columns[3]` reads as the column's name (#19). */
|
|
37
|
+
columns?: Record<string, string[]>;
|
|
38
|
+
/** What the server was compared with (#49): `src/`, or the schema the newest applied migration records. */
|
|
39
|
+
against?: DriftAgainst;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The declaration drift compares the server with: the project's `src/`,
|
|
43
|
+
* or the recorded schema of the newest migration the environment's history
|
|
44
|
+
* records as applied (`migration` null when none is applied yet).
|
|
45
|
+
*/
|
|
46
|
+
export type DriftAgainst = {
|
|
47
|
+
source: "src";
|
|
48
|
+
} | {
|
|
49
|
+
source: "history";
|
|
50
|
+
migration: string | null;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* A stable fingerprint of the drift: the environment and what drifted
|
|
54
|
+
* (each changed object's changes, declared and live, and the objects gone),
|
|
55
|
+
* order-free, so two reads of the same drift give the same one and a
|
|
56
|
+
* tracking issue updated with it changes only when the drift does. Objects
|
|
57
|
+
* that could not be read are not drift and are left out.
|
|
58
|
+
*/
|
|
59
|
+
export declare function driftFingerprint(drift: Drift): string;
|
|
60
|
+
/**
|
|
61
|
+
* The recorded schema as declarations chant can build: one file, written
|
|
62
|
+
* by the sql lexicon's import generator from each object's DDL, each named
|
|
63
|
+
* by its export as the build named it. Written under the project directory,
|
|
64
|
+
* so the generated imports resolve from the project's node_modules, in a
|
|
65
|
+
* directory {@link RecordedSource.dispose} removes.
|
|
66
|
+
*/
|
|
67
|
+
export interface RecordedSource {
|
|
68
|
+
dir: string;
|
|
69
|
+
dispose: () => void;
|
|
70
|
+
}
|
|
71
|
+
export declare function writeRecordedSource(projectDir: string, schema: BuildOutput): Promise<RecordedSource>;
|
|
72
|
+
/** Exit code: an owned object changed or is gone. */
|
|
73
|
+
export declare const DRIFTED = 2;
|
|
74
|
+
/** `2` on drift; `1` when there is none but part of the environment could not be read; `0` when clean. */
|
|
75
|
+
export declare function driftExitCode(drift: Drift): number;
|
|
76
|
+
/** The drift in a parsed `chant lifecycle diff --live --json` document. */
|
|
77
|
+
export declare function driftFromLifecycle(environment: string, doc: unknown): Drift;
|
|
78
|
+
/** Runs `chant lifecycle diff <env> --live --json` in the project and reads the drift from it. */
|
|
79
|
+
export declare function readDrift(project: Project, env: Environment, options?: {
|
|
80
|
+
env?: NodeJS.ProcessEnv;
|
|
81
|
+
src?: string;
|
|
82
|
+
}): Promise<Drift>;
|
|
83
|
+
/**
|
|
84
|
+
* The declared column names of each changed object whose drift is named by
|
|
85
|
+
* column position (chant's ClickHouse tables keep columns as a list, so a
|
|
86
|
+
* change reads `columns[3].default.expr`). Read from the project's build,
|
|
87
|
+
* with the dialect's own tag, the way chant reads the declaration.
|
|
88
|
+
*/
|
|
89
|
+
export declare function declaredColumns(project: Project, drift: Drift, build: () => Promise<{
|
|
90
|
+
output: {
|
|
91
|
+
objects: Array<{
|
|
92
|
+
export: string;
|
|
93
|
+
ddl: string;
|
|
94
|
+
}>;
|
|
95
|
+
};
|
|
96
|
+
dispose: () => void;
|
|
97
|
+
}>): Promise<Record<string, string[]>>;
|
|
98
|
+
/** `columns[3].default.expr` as `column country: default.expr`, when the declaration names column 3. */
|
|
99
|
+
export declare function describePath(path: string, columns: readonly string[] | undefined): string;
|
|
100
|
+
/** What the server was compared with, in words. */
|
|
101
|
+
export declare function describeAgainst(against: DriftAgainst | undefined): string | undefined;
|
|
102
|
+
/** The drift as text. */
|
|
103
|
+
export declare function renderDrift(drift: Drift, server?: ServerInfo): string;
|
|
104
|
+
/**
|
|
105
|
+
* The drift as markdown, for the tracking issue: the environment and
|
|
106
|
+
* server, what it was compared with, each changed object with its changes,
|
|
107
|
+
* the objects gone, the run that found it, and the fingerprint.
|
|
108
|
+
*/
|
|
109
|
+
export declare function renderDriftMarkdown(drift: Drift, server: ServerInfo | undefined, extra: {
|
|
110
|
+
fingerprint: string;
|
|
111
|
+
run?: string;
|
|
112
|
+
}): string;
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drift: the declared objects whose live definition changed out of band, or
|
|
3
|
+
* that are gone from the server. Read from `chant lifecycle diff <env> --live
|
|
4
|
+
* --json`, the sql lexicon's section of it:
|
|
5
|
+
*
|
|
6
|
+
* - `deep.drifted[].changes[]`: a declared object whose live definition
|
|
7
|
+
* differs, property by property, declared against live;
|
|
8
|
+
* - `resources.missing`: a declared object the server does not have;
|
|
9
|
+
* - `resources.unobserved` and `deep.unobserved`: a declared object chant
|
|
10
|
+
* could not read (no credentials, a kind it cannot observe). Not drift, and
|
|
11
|
+
* not clean either: that part of the environment is unknown.
|
|
12
|
+
*
|
|
13
|
+
* An object the project does not declare is never reported: chant only reads
|
|
14
|
+
* what the project declares, and only touches what carries its marker.
|
|
15
|
+
*/
|
|
16
|
+
import { createHash } from "node:crypto";
|
|
17
|
+
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
18
|
+
import { dirname, join } from "node:path";
|
|
19
|
+
import { YodelError } from "../project.js";
|
|
20
|
+
import { lastJsonLine, runChant } from "./process.js";
|
|
21
|
+
import { describeServer } from "../server.js";
|
|
22
|
+
/**
|
|
23
|
+
* A stable fingerprint of the drift: the environment and what drifted
|
|
24
|
+
* (each changed object's changes, declared and live, and the objects gone),
|
|
25
|
+
* order-free, so two reads of the same drift give the same one and a
|
|
26
|
+
* tracking issue updated with it changes only when the drift does. Objects
|
|
27
|
+
* that could not be read are not drift and are left out.
|
|
28
|
+
*/
|
|
29
|
+
export function driftFingerprint(drift) {
|
|
30
|
+
const changed = drift.changed
|
|
31
|
+
.map((e) => ({
|
|
32
|
+
name: e.name,
|
|
33
|
+
type: e.type,
|
|
34
|
+
changes: e.changes.map((c) => ({ path: c.path, kind: c.kind, declared: c.declared ?? null, live: c.live ?? null })).sort((a, b) => JSON.stringify(a).localeCompare(JSON.stringify(b))),
|
|
35
|
+
}))
|
|
36
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
37
|
+
const subject = JSON.stringify({ environment: drift.environment, changed, missing: [...drift.missing].sort() });
|
|
38
|
+
return `sha256:${createHash("sha256").update(subject, "utf8").digest("hex")}`;
|
|
39
|
+
}
|
|
40
|
+
export async function writeRecordedSource(projectDir, schema) {
|
|
41
|
+
const { sqlTemplateGenerator } = await import("@intentius/chant-lexicon-sql/import-generator");
|
|
42
|
+
const resources = schema.objects.map((o) => {
|
|
43
|
+
const own = o;
|
|
44
|
+
const where = typeof own.database === "string" ? { database: own.database } : typeof own.schema === "string" ? { schema: own.schema } : {};
|
|
45
|
+
return { type: o.type ?? "", logicalId: o.export, properties: { ...where, name: typeof own.name === "string" ? own.name : o.export, ddl: o.ddl } };
|
|
46
|
+
});
|
|
47
|
+
const dir = mkdtempSync(join(projectDir, ".yodel-recorded-"));
|
|
48
|
+
const dispose = () => {
|
|
49
|
+
rmSync(dir, { recursive: true, force: true });
|
|
50
|
+
};
|
|
51
|
+
try {
|
|
52
|
+
for (const f of resources.length === 0 ? [] : sqlTemplateGenerator.generate({ resources, parameters: [] })) {
|
|
53
|
+
const path = join(dir, f.path);
|
|
54
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
55
|
+
writeFileSync(path, f.content);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch (e) {
|
|
59
|
+
dispose();
|
|
60
|
+
throw new YodelError(`the recorded schema could not be written as declarations: ${e instanceof Error ? e.message : String(e)}`);
|
|
61
|
+
}
|
|
62
|
+
return { dir, dispose };
|
|
63
|
+
}
|
|
64
|
+
/** Exit code: an owned object changed or is gone. */
|
|
65
|
+
export const DRIFTED = 2;
|
|
66
|
+
/** `2` on drift; `1` when there is none but part of the environment could not be read; `0` when clean. */
|
|
67
|
+
export function driftExitCode(drift) {
|
|
68
|
+
if (drift.changed.length > 0 || drift.missing.length > 0)
|
|
69
|
+
return DRIFTED;
|
|
70
|
+
return drift.unobserved.length > 0 ? 1 : 0;
|
|
71
|
+
}
|
|
72
|
+
/** The drift in a parsed `chant lifecycle diff --live --json` document. */
|
|
73
|
+
export function driftFromLifecycle(environment, doc) {
|
|
74
|
+
const lexicons = doc?.lexicons;
|
|
75
|
+
if (!lexicons) {
|
|
76
|
+
const stacks = doc?.stacks;
|
|
77
|
+
throw new YodelError(stacks
|
|
78
|
+
? "chant lifecycle diff reported per stack; a yodel project is one database and one stack"
|
|
79
|
+
: "chant lifecycle diff --json printed no lexicons");
|
|
80
|
+
}
|
|
81
|
+
const sql = lexicons.sql ?? {};
|
|
82
|
+
const unobserved = new Map();
|
|
83
|
+
for (const u of [...(sql.resources?.unobserved ?? []), ...(sql.deep?.unobserved ?? [])]) {
|
|
84
|
+
if (!unobserved.has(u.name))
|
|
85
|
+
unobserved.set(u.name, u);
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
environment,
|
|
89
|
+
changed: (sql.deep?.drifted ?? []).filter((d) => d.changes.length > 0),
|
|
90
|
+
missing: [...(sql.resources?.missing ?? [])].sort(),
|
|
91
|
+
unobserved: [...unobserved.values()].sort((a, b) => a.name.localeCompare(b.name)),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/** Runs `chant lifecycle diff <env> --live --json` in the project and reads the drift from it. */
|
|
95
|
+
export async function readDrift(project, env, options = {}) {
|
|
96
|
+
const result = await runChant(["lifecycle", "diff", env.name, "--live", "--json", ...(options.src ? ["--src", options.src] : [])], {
|
|
97
|
+
cwd: project.dir,
|
|
98
|
+
...(options.env ? { env: options.env } : {}),
|
|
99
|
+
});
|
|
100
|
+
const doc = lastJsonLine(result.stdout);
|
|
101
|
+
if (result.code !== 0 || doc === undefined) {
|
|
102
|
+
const detail = (result.stderr || result.stdout).trim();
|
|
103
|
+
throw new YodelError(`chant lifecycle diff ${env.name} --live failed (exit ${String(result.code)})${detail ? `:\n${detail}` : ""}`);
|
|
104
|
+
}
|
|
105
|
+
return driftFromLifecycle(env.name, doc);
|
|
106
|
+
}
|
|
107
|
+
const COLUMN_PATH = /^columns\[(\d+)\]/;
|
|
108
|
+
/**
|
|
109
|
+
* The declared column names of each changed object whose drift is named by
|
|
110
|
+
* column position (chant's ClickHouse tables keep columns as a list, so a
|
|
111
|
+
* change reads `columns[3].default.expr`). Read from the project's build,
|
|
112
|
+
* with the dialect's own tag, the way chant reads the declaration.
|
|
113
|
+
*/
|
|
114
|
+
export async function declaredColumns(project, drift, build) {
|
|
115
|
+
const wanted = new Set(drift.changed.filter((e) => e.changes.some((c) => COLUMN_PATH.test(c.path))).map((e) => e.name));
|
|
116
|
+
if (wanted.size === 0)
|
|
117
|
+
return {};
|
|
118
|
+
const b = await build();
|
|
119
|
+
try {
|
|
120
|
+
const tag = project.dialect === "postgres"
|
|
121
|
+
? (await import("@intentius/chant-lexicon-sql/postgres/entities")).table
|
|
122
|
+
: (await import("@intentius/chant-lexicon-sql/clickhouse/entities")).table;
|
|
123
|
+
const out = {};
|
|
124
|
+
for (const o of b.output.objects) {
|
|
125
|
+
if (!wanted.has(o.export))
|
|
126
|
+
continue;
|
|
127
|
+
try {
|
|
128
|
+
const strings = Object.assign([o.ddl], { raw: [o.ddl] });
|
|
129
|
+
const columns = tag(strings).props.columns;
|
|
130
|
+
if (Array.isArray(columns))
|
|
131
|
+
out[o.export] = columns.map((c) => { const n = c.name; return typeof n === "string" ? n : ""; });
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
// Not a table this tag reads: its paths stay as chant gives them.
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return out;
|
|
138
|
+
}
|
|
139
|
+
finally {
|
|
140
|
+
b.dispose();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/** `columns[3].default.expr` as `column country: default.expr`, when the declaration names column 3. */
|
|
144
|
+
export function describePath(path, columns) {
|
|
145
|
+
const m = COLUMN_PATH.exec(path);
|
|
146
|
+
const name = m && columns ? columns[Number(m[1])] : undefined;
|
|
147
|
+
if (!m || !name)
|
|
148
|
+
return path;
|
|
149
|
+
const rest = path.slice(m[0].length).replace(/^\./, "");
|
|
150
|
+
return `column ${name}${rest ? ` ${rest}` : ""}`;
|
|
151
|
+
}
|
|
152
|
+
const show = (v) => (v === undefined ? "(none)" : typeof v === "string" ? v : JSON.stringify(v));
|
|
153
|
+
/** What the server was compared with, in words. */
|
|
154
|
+
export function describeAgainst(against) {
|
|
155
|
+
if (!against)
|
|
156
|
+
return undefined;
|
|
157
|
+
if (against.source === "src")
|
|
158
|
+
return "Compared with the declared schema in src/.";
|
|
159
|
+
return against.migration
|
|
160
|
+
? `Compared with the schema ${against.migration} records, the newest migration the history records as applied.`
|
|
161
|
+
: "No migration is applied yet, so the history records no schema to compare with.";
|
|
162
|
+
}
|
|
163
|
+
/** The drift as text. */
|
|
164
|
+
export function renderDrift(drift, server) {
|
|
165
|
+
const lines = [`Drift in ${drift.environment}${server ? ` (${describeServer(server)})` : ""}`, ""];
|
|
166
|
+
const against = describeAgainst(drift.against);
|
|
167
|
+
if (against)
|
|
168
|
+
lines.push(against, "");
|
|
169
|
+
if (drift.changed.length === 0 && drift.missing.length === 0) {
|
|
170
|
+
lines.push(drift.unobserved.length > 0 ? "No drift in the declared objects that could be read." : "No drift: every declared object matches the server.");
|
|
171
|
+
}
|
|
172
|
+
if (drift.changed.length > 0) {
|
|
173
|
+
lines.push("Changed out of band:");
|
|
174
|
+
for (const e of drift.changed) {
|
|
175
|
+
lines.push(` ${e.name} (${e.type})`);
|
|
176
|
+
for (const c of e.changes) {
|
|
177
|
+
const path = describePath(c.path, drift.columns?.[e.name]);
|
|
178
|
+
lines.push(c.kind === "absent" ? ` ${path}: declared ${show(c.declared)}, absent live` : ` ${path}: declared ${show(c.declared)}, live ${show(c.live)}`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
if (drift.missing.length > 0) {
|
|
183
|
+
if (drift.changed.length > 0)
|
|
184
|
+
lines.push("");
|
|
185
|
+
lines.push("Gone (declared, not on the server):");
|
|
186
|
+
for (const name of drift.missing)
|
|
187
|
+
lines.push(` ${name}`);
|
|
188
|
+
}
|
|
189
|
+
if (drift.unobserved.length > 0) {
|
|
190
|
+
lines.push("", "Could not be read, so their state is unknown:");
|
|
191
|
+
for (const u of drift.unobserved)
|
|
192
|
+
lines.push(` ${u.name}: ${u.reason}${u.detail ? ` (${u.detail})` : ""}`);
|
|
193
|
+
if (drift.lockWait)
|
|
194
|
+
lines.push("", `The read ${drift.lockWait}.`);
|
|
195
|
+
}
|
|
196
|
+
return `${lines.join("\n")}\n`;
|
|
197
|
+
}
|
|
198
|
+
const code = (v) => `\`${show(v).replace(/`/g, "'")}\``;
|
|
199
|
+
/**
|
|
200
|
+
* The drift as markdown, for the tracking issue: the environment and
|
|
201
|
+
* server, what it was compared with, each changed object with its changes,
|
|
202
|
+
* the objects gone, the run that found it, and the fingerprint.
|
|
203
|
+
*/
|
|
204
|
+
export function renderDriftMarkdown(drift, server, extra) {
|
|
205
|
+
const lines = [`**${drift.environment}**${server ? ` (${describeServer(server)})` : ""} has drifted: declared objects were changed out of band, or are gone.`, ""];
|
|
206
|
+
const against = describeAgainst(drift.against);
|
|
207
|
+
if (against)
|
|
208
|
+
lines.push(against, "");
|
|
209
|
+
if (drift.changed.length > 0) {
|
|
210
|
+
lines.push("Changed out of band:", "");
|
|
211
|
+
for (const e of drift.changed) {
|
|
212
|
+
lines.push(`- \`${e.name}\` (${e.type})`);
|
|
213
|
+
for (const c of e.changes) {
|
|
214
|
+
const path = describePath(c.path, drift.columns?.[e.name]);
|
|
215
|
+
lines.push(c.kind === "absent" ? ` - ${path}: declared ${code(c.declared)}, absent live` : ` - ${path}: declared ${code(c.declared)}, live ${code(c.live)}`);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
lines.push("");
|
|
219
|
+
}
|
|
220
|
+
if (drift.missing.length > 0) {
|
|
221
|
+
lines.push("Gone (declared, not on the server):", "");
|
|
222
|
+
for (const name of drift.missing)
|
|
223
|
+
lines.push(`- \`${name}\``);
|
|
224
|
+
lines.push("");
|
|
225
|
+
}
|
|
226
|
+
if (drift.unobserved.length > 0) {
|
|
227
|
+
lines.push("Could not be read, so their state is unknown:", "");
|
|
228
|
+
for (const u of drift.unobserved)
|
|
229
|
+
lines.push(`- \`${u.name}\`: ${u.reason}`);
|
|
230
|
+
lines.push("");
|
|
231
|
+
}
|
|
232
|
+
lines.push(`Run \`yodel drift ${drift.environment}\` to see it again. yodel closes this issue when the drift is gone.`);
|
|
233
|
+
if (extra.run)
|
|
234
|
+
lines.push("", `Found by ${extra.run}`);
|
|
235
|
+
lines.push("", `<sub>drift fingerprint ${extra.fingerprint}</sub>`);
|
|
236
|
+
return `${lines.join("\n")}\n`;
|
|
237
|
+
}
|
|
238
|
+
//# sourceMappingURL=drift.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drift.js","sourceRoot":"","sources":["../../src/chant/drift.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The plan: the classified change from an environment's live database to the
|
|
3
|
+
* declared schema. This is `chant sql plan <env> <build>`, called as the
|
|
4
|
+
* library functions that command runs (`planAgainstServer` for ClickHouse,
|
|
5
|
+
* `planPgAgainstServer` for Postgres) rather than through the CLI.
|
|
6
|
+
*/
|
|
7
|
+
import type { SchemaDiff } from "@intentius/chant-lexicon-sql/clickhouse/plan/diff";
|
|
8
|
+
import type { PgSchemaDiff } from "@intentius/chant-lexicon-sql/postgres/plan/diff";
|
|
9
|
+
import type { ClassifiedChange } from "@intentius/chant-lexicon-sql/core/classifier";
|
|
10
|
+
import { type Environment, type Project, type SqlDialect } from "../project.js";
|
|
11
|
+
import type { Build } from "./build.js";
|
|
12
|
+
/** A plan for one environment, in either dialect. */
|
|
13
|
+
export interface Plan {
|
|
14
|
+
environment: string;
|
|
15
|
+
dialect: SqlDialect;
|
|
16
|
+
/** chant's own diff, as `chant sql plan --json` prints it. */
|
|
17
|
+
diff: SchemaDiff | PgSchemaDiff;
|
|
18
|
+
/**
|
|
19
|
+
* The changes the plan refuses to make in place, each of which needs its
|
|
20
|
+
* own Op: a ClickHouse rebuild (`rebuilds`, run as `ClickHouseRebuildOp`)
|
|
21
|
+
* or a Postgres expand-and-contract change (`refused`, run as
|
|
22
|
+
* `PostgresMigrationOp`).
|
|
23
|
+
*/
|
|
24
|
+
refused: ClassifiedChange[];
|
|
25
|
+
}
|
|
26
|
+
/** Exit code: the plan has a change that needs a rebuild (or expand-and-contract) Op. */
|
|
27
|
+
export declare const PLAN_NEEDS_OP = 2;
|
|
28
|
+
/** `2` when any change needs its own Op, `0` otherwise. */
|
|
29
|
+
export declare function planExitCode(plan: Plan): number;
|
|
30
|
+
/**
|
|
31
|
+
* The changes to objects the build declares. A plan also lists live objects
|
|
32
|
+
* the project does not declare, as drops; an ApplyOp never touches those
|
|
33
|
+
* (it only prunes objects carrying chant's marker), so they are not work
|
|
34
|
+
* left for apply. chant labels a declared object `<export> (<name>)` and an
|
|
35
|
+
* undeclared one by its name alone.
|
|
36
|
+
*/
|
|
37
|
+
export declare function declaredChanges(plan: Plan, build: Build): ClassifiedChange[];
|
|
38
|
+
/** The plan as `yodel plan --json` prints it: chant's diff, with the environment and dialect it is of. */
|
|
39
|
+
export declare function planJson(plan: Plan): Record<string, unknown>;
|
|
40
|
+
/** Plans `build` against the server `sql.profiles.<env>` binds. */
|
|
41
|
+
export declare function planEnvironment(project: Project, env: Environment, build: Build, options?: {
|
|
42
|
+
env?: NodeJS.ProcessEnv;
|
|
43
|
+
}): Promise<Plan>;
|
|
44
|
+
/** The plan as text, chant's own report for the dialect. */
|
|
45
|
+
export declare function renderPlan(plan: Plan, title: string): Promise<string>;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The plan: the classified change from an environment's live database to the
|
|
3
|
+
* declared schema. This is `chant sql plan <env> <build>`, called as the
|
|
4
|
+
* library functions that command runs (`planAgainstServer` for ClickHouse,
|
|
5
|
+
* `planPgAgainstServer` for Postgres) rather than through the CLI.
|
|
6
|
+
*/
|
|
7
|
+
import { YodelError } from "../project.js";
|
|
8
|
+
/** Exit code: the plan has a change that needs a rebuild (or expand-and-contract) Op. */
|
|
9
|
+
export const PLAN_NEEDS_OP = 2;
|
|
10
|
+
/** `2` when any change needs its own Op, `0` otherwise. */
|
|
11
|
+
export function planExitCode(plan) {
|
|
12
|
+
return plan.refused.length > 0 ? PLAN_NEEDS_OP : 0;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The changes to objects the build declares. A plan also lists live objects
|
|
16
|
+
* the project does not declare, as drops; an ApplyOp never touches those
|
|
17
|
+
* (it only prunes objects carrying chant's marker), so they are not work
|
|
18
|
+
* left for apply. chant labels a declared object `<export> (<name>)` and an
|
|
19
|
+
* undeclared one by its name alone.
|
|
20
|
+
*/
|
|
21
|
+
export function declaredChanges(plan, build) {
|
|
22
|
+
const exports = new Set(build.output.objects.map((o) => o.export));
|
|
23
|
+
return plan.diff.changes.filter((c) => {
|
|
24
|
+
const at = c.object.indexOf(" (");
|
|
25
|
+
return at > 0 && c.object.endsWith(")") && exports.has(c.object.slice(0, at));
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
/** The plan as `yodel plan --json` prints it: chant's diff, with the environment and dialect it is of. */
|
|
29
|
+
export function planJson(plan) {
|
|
30
|
+
return { environment: plan.environment, dialect: plan.dialect, ...plan.diff };
|
|
31
|
+
}
|
|
32
|
+
function bindError(e) {
|
|
33
|
+
return new YodelError(e instanceof Error ? e.message : String(e));
|
|
34
|
+
}
|
|
35
|
+
/** Plans `build` against the server `sql.profiles.<env>` binds. */
|
|
36
|
+
export async function planEnvironment(project, env, build, options = {}) {
|
|
37
|
+
const bind = { config: project.config, cwd: project.dir, ...(options.env ? { env: options.env } : {}) };
|
|
38
|
+
try {
|
|
39
|
+
if (project.dialect === "postgres") {
|
|
40
|
+
const { planPgAgainstServer } = await import("@intentius/chant-lexicon-sql/postgres/plan/commands");
|
|
41
|
+
const diff = await planPgAgainstServer(env.name, build.path, bind);
|
|
42
|
+
return { environment: env.name, dialect: "postgres", diff, refused: diff.refused };
|
|
43
|
+
}
|
|
44
|
+
const { planAgainstServer } = await import("@intentius/chant-lexicon-sql/clickhouse/plan/commands");
|
|
45
|
+
const diff = await planAgainstServer(env.name, build.path, bind);
|
|
46
|
+
return { environment: env.name, dialect: "clickhouse", diff, refused: diff.rebuilds };
|
|
47
|
+
}
|
|
48
|
+
catch (e) {
|
|
49
|
+
throw bindError(e);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/** The plan as text, chant's own report for the dialect. */
|
|
53
|
+
export async function renderPlan(plan, title) {
|
|
54
|
+
if (plan.dialect === "postgres") {
|
|
55
|
+
const { renderPgDiff } = await import("@intentius/chant-lexicon-sql/postgres/plan/report");
|
|
56
|
+
return renderPgDiff(plan.diff, { title });
|
|
57
|
+
}
|
|
58
|
+
const { renderDiff } = await import("@intentius/chant-lexicon-sql/clickhouse/plan/report");
|
|
59
|
+
return renderDiff(plan.diff, { title });
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=plan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../../src/chant/plan.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Running the `chant` CLI that yodel depends on, for the commands that have
|
|
3
|
+
* no library surface (`build`, `run`, `lifecycle diff`).
|
|
4
|
+
*
|
|
5
|
+
* Published chant ships TypeScript source, and its own bin runs
|
|
6
|
+
* `node --import <tsx loader> src/cli/main.ts`. yodel does the same with its
|
|
7
|
+
* own copy of tsx, so the chant it runs is the one in its own dependencies,
|
|
8
|
+
* not whatever `chant` is first on PATH. That chant's `bin/` goes first on the
|
|
9
|
+
* child's PATH, because chant's Op activities shell out to `chant` themselves
|
|
10
|
+
* (`lifecycleDiff` runs `chant lifecycle diff`).
|
|
11
|
+
*/
|
|
12
|
+
export interface ChantInstall {
|
|
13
|
+
/** The `@intentius/chant` package directory. */
|
|
14
|
+
root: string;
|
|
15
|
+
/** Its CLI entry, `src/cli/main.ts`. */
|
|
16
|
+
main: string;
|
|
17
|
+
/** Its `bin/`, which holds the `chant` script. */
|
|
18
|
+
bin: string;
|
|
19
|
+
/** The tsx loader to run it under, as a file URL. */
|
|
20
|
+
loader: string;
|
|
21
|
+
}
|
|
22
|
+
/** Where yodel's chant and tsx are installed. */
|
|
23
|
+
export declare function chantInstall(): ChantInstall;
|
|
24
|
+
export interface ChantResult {
|
|
25
|
+
code: number;
|
|
26
|
+
stdout: string;
|
|
27
|
+
stderr: string;
|
|
28
|
+
}
|
|
29
|
+
export interface RunChantOptions {
|
|
30
|
+
cwd: string;
|
|
31
|
+
env?: NodeJS.ProcessEnv;
|
|
32
|
+
/** Called with each chunk as it arrives, for output a person watches (an Op run). */
|
|
33
|
+
onStdout?: (text: string) => void;
|
|
34
|
+
onStderr?: (text: string) => void;
|
|
35
|
+
}
|
|
36
|
+
/** The environment a chant child runs with: the caller's, with chant's bin first on PATH. */
|
|
37
|
+
export declare function chantEnv(base?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
38
|
+
/** Runs `chant <args>` in `cwd` and resolves with its exit code and output. Never rejects on a non-zero exit. */
|
|
39
|
+
export declare function runChant(args: readonly string[], options: RunChantOptions): Promise<ChantResult>;
|
|
40
|
+
/** The last line of `stdout` that parses as a JSON object: chant prints its `--json` document as one line, after any log lines. */
|
|
41
|
+
export declare function lastJsonLine(stdout: string): unknown;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Running the `chant` CLI that yodel depends on, for the commands that have
|
|
3
|
+
* no library surface (`build`, `run`, `lifecycle diff`).
|
|
4
|
+
*
|
|
5
|
+
* Published chant ships TypeScript source, and its own bin runs
|
|
6
|
+
* `node --import <tsx loader> src/cli/main.ts`. yodel does the same with its
|
|
7
|
+
* own copy of tsx, so the chant it runs is the one in its own dependencies,
|
|
8
|
+
* not whatever `chant` is first on PATH. That chant's `bin/` goes first on the
|
|
9
|
+
* child's PATH, because chant's Op activities shell out to `chant` themselves
|
|
10
|
+
* (`lifecycleDiff` runs `chant lifecycle diff`).
|
|
11
|
+
*/
|
|
12
|
+
import { spawn } from "node:child_process";
|
|
13
|
+
import { createRequire } from "node:module";
|
|
14
|
+
import { dirname, delimiter, join } from "node:path";
|
|
15
|
+
import { pathToFileURL } from "node:url";
|
|
16
|
+
let install;
|
|
17
|
+
/** Where yodel's chant and tsx are installed. */
|
|
18
|
+
export function chantInstall() {
|
|
19
|
+
if (install)
|
|
20
|
+
return install;
|
|
21
|
+
const require = createRequire(import.meta.url);
|
|
22
|
+
// "." resolves to <root>/src/index.ts; package.json is not an export.
|
|
23
|
+
const root = dirname(dirname(require.resolve("@intentius/chant")));
|
|
24
|
+
install = {
|
|
25
|
+
root,
|
|
26
|
+
main: join(root, "src", "cli", "main.ts"),
|
|
27
|
+
bin: join(root, "bin"),
|
|
28
|
+
loader: pathToFileURL(require.resolve("tsx")).href,
|
|
29
|
+
};
|
|
30
|
+
return install;
|
|
31
|
+
}
|
|
32
|
+
/** The environment a chant child runs with: the caller's, with chant's bin first on PATH. */
|
|
33
|
+
export function chantEnv(base = process.env) {
|
|
34
|
+
const { bin } = chantInstall();
|
|
35
|
+
return { ...base, PATH: [bin, base.PATH ?? ""].filter(Boolean).join(delimiter), FORCE_COLOR: "0", NO_COLOR: "1" };
|
|
36
|
+
}
|
|
37
|
+
/** Runs `chant <args>` in `cwd` and resolves with its exit code and output. Never rejects on a non-zero exit. */
|
|
38
|
+
export function runChant(args, options) {
|
|
39
|
+
const { main, loader } = chantInstall();
|
|
40
|
+
return new Promise((resolvePromise, reject) => {
|
|
41
|
+
const child = spawn(process.execPath, ["--import", loader, main, ...args], {
|
|
42
|
+
cwd: options.cwd,
|
|
43
|
+
env: chantEnv(options.env),
|
|
44
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
45
|
+
});
|
|
46
|
+
let stdout = "";
|
|
47
|
+
let stderr = "";
|
|
48
|
+
child.stdout.setEncoding("utf8");
|
|
49
|
+
child.stderr.setEncoding("utf8");
|
|
50
|
+
child.stdout.on("data", (chunk) => {
|
|
51
|
+
stdout += chunk;
|
|
52
|
+
options.onStdout?.(chunk);
|
|
53
|
+
});
|
|
54
|
+
child.stderr.on("data", (chunk) => {
|
|
55
|
+
stderr += chunk;
|
|
56
|
+
options.onStderr?.(chunk);
|
|
57
|
+
});
|
|
58
|
+
child.on("error", reject);
|
|
59
|
+
child.on("close", (code, signal) => {
|
|
60
|
+
resolvePromise({ code: code ?? (signal ? 128 : 1), stdout, stderr });
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/** The last line of `stdout` that parses as a JSON object: chant prints its `--json` document as one line, after any log lines. */
|
|
65
|
+
export function lastJsonLine(stdout) {
|
|
66
|
+
const lines = stdout.split("\n").map((l) => l.trim()).filter((l) => l.startsWith("{"));
|
|
67
|
+
for (const line of lines.reverse()) {
|
|
68
|
+
try {
|
|
69
|
+
return JSON.parse(line);
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// A log line that happens to start with "{"; keep looking.
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// A pretty-printed document spans lines; try the whole of stdout from its first "{".
|
|
76
|
+
const at = stdout.indexOf("{");
|
|
77
|
+
if (at >= 0) {
|
|
78
|
+
try {
|
|
79
|
+
return JSON.parse(stdout.slice(at));
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
// Not JSON.
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=process.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process.js","sourceRoot":"","sources":["../../src/chant/process.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Commands yodel prints for a person to run (#14): `chant approve ...`,
|
|
3
|
+
* `yodel apply ...`. In a project that installs chant and yodel locally,
|
|
4
|
+
* neither is on PATH, only in node_modules/.bin, so a printed `chant approve`
|
|
5
|
+
* fails with "command not found". Such a command is printed as `npx chant
|
|
6
|
+
* ...` instead, which runs the project's own copy. When the tool is on PATH,
|
|
7
|
+
* or the project does not install it (where `npx` would fetch an unrelated
|
|
8
|
+
* package of that name), the command is printed as it is.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Whether `name` is an executable on `PATH`, not counting `node_modules/.bin`
|
|
12
|
+
* directories: `npx yodel` puts the project's on yodel's PATH, but the
|
|
13
|
+
* person's shell does not have it.
|
|
14
|
+
*/
|
|
15
|
+
export declare function onPath(name: string, env?: NodeJS.ProcessEnv): boolean;
|
|
16
|
+
/** Whether `dir` or a directory above it has `node_modules/.bin/<name>`. */
|
|
17
|
+
export declare function installedLocally(name: string, dir: string): boolean;
|
|
18
|
+
/** `command` as a person can run it in `projectDir`: prefixed with `npx ` when its tool is installed there but not on PATH. */
|
|
19
|
+
export declare function runnable(command: string, projectDir: string, env?: NodeJS.ProcessEnv): string;
|