@ddt-tools/cli 0.2.0 → 0.2.4
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/dist/advise-tests-YNMKVJCD.js +87 -0
- package/dist/advise-tests-YNMKVJCD.js.map +1 -0
- package/dist/ai-NTNPYEKZ.js +86 -0
- package/dist/ai-NTNPYEKZ.js.map +1 -0
- package/dist/anonymize-LERTWUQO.js +139 -0
- package/dist/anonymize-LERTWUQO.js.map +1 -0
- package/dist/approval-GGZGKIU4.js +73 -0
- package/dist/approval-GGZGKIU4.js.map +1 -0
- package/dist/approval-chain-GWJKZHVU.js +118 -0
- package/dist/approval-chain-GWJKZHVU.js.map +1 -0
- package/dist/audit-log-2PH55BU4.js +159 -0
- package/dist/audit-log-2PH55BU4.js.map +1 -0
- package/dist/backlog-QNXGOUF4.js +76 -0
- package/dist/backlog-QNXGOUF4.js.map +1 -0
- package/dist/bisect-W3XKKRWG.js +111 -0
- package/dist/bisect-W3XKKRWG.js.map +1 -0
- package/dist/bookmarks-XVOGXGMC.js +107 -0
- package/dist/bookmarks-XVOGXGMC.js.map +1 -0
- package/dist/branch-S3I2IJGQ.js +103 -0
- package/dist/branch-S3I2IJGQ.js.map +1 -0
- package/dist/build-MP3JQEFO.js +20 -0
- package/dist/build-MP3JQEFO.js.map +1 -0
- package/dist/catalog-3J3NFNXP.js +137 -0
- package/dist/catalog-3J3NFNXP.js.map +1 -0
- package/dist/changelog-ZQAH3ULB.js +216 -0
- package/dist/changelog-ZQAH3ULB.js.map +1 -0
- package/dist/chunk-2FT6HXKS.js +55 -0
- package/dist/chunk-2FT6HXKS.js.map +1 -0
- package/dist/chunk-DGUM43GV.js +11 -0
- package/dist/chunk-DGUM43GV.js.map +1 -0
- package/dist/chunk-DL3V7UJ2.js +25 -0
- package/dist/chunk-DL3V7UJ2.js.map +1 -0
- package/dist/chunk-VM2H4LAO.js +15 -0
- package/dist/chunk-VM2H4LAO.js.map +1 -0
- package/dist/chunk-XFXG347C.js +40 -0
- package/dist/chunk-XFXG347C.js.map +1 -0
- package/dist/cli.js +499 -19402
- package/dist/cli.js.map +1 -1
- package/dist/compare-P7JOV76O.js +379 -0
- package/dist/compare-P7JOV76O.js.map +1 -0
- package/dist/compare-profiles-H33CXZPD.js +219 -0
- package/dist/compare-profiles-H33CXZPD.js.map +1 -0
- package/dist/completion-ZSNCQKJ2.js +89 -0
- package/dist/completion-ZSNCQKJ2.js.map +1 -0
- package/dist/connection-CDGVEFUC.js +148 -0
- package/dist/connection-CDGVEFUC.js.map +1 -0
- package/dist/cost-estimate-S2MKHT2H.js +321 -0
- package/dist/cost-estimate-S2MKHT2H.js.map +1 -0
- package/dist/data-compare-46ZI7KHL.js +128 -0
- package/dist/data-compare-46ZI7KHL.js.map +1 -0
- package/dist/data-fit-WGEPLD5S.js +127 -0
- package/dist/data-fit-WGEPLD5S.js.map +1 -0
- package/dist/deploy-status-4H5KJFRC.js +58 -0
- package/dist/deploy-status-4H5KJFRC.js.map +1 -0
- package/dist/design-ILX3ZSWW.js +135 -0
- package/dist/design-ILX3ZSWW.js.map +1 -0
- package/dist/diagnose-WPUL67E4.js +150 -0
- package/dist/diagnose-WPUL67E4.js.map +1 -0
- package/dist/discover-DEO2R5T6.js +78 -0
- package/dist/discover-DEO2R5T6.js.map +1 -0
- package/dist/docs-QNY3MUVO.js +183 -0
- package/dist/docs-QNY3MUVO.js.map +1 -0
- package/dist/drift-FDRNPWQA.js +233 -0
- package/dist/drift-FDRNPWQA.js.map +1 -0
- package/dist/drift-gate-6BWWWMHW.js +103 -0
- package/dist/drift-gate-6BWWWMHW.js.map +1 -0
- package/dist/error-lookup-4R3Y4RBC.js +56 -0
- package/dist/error-lookup-4R3Y4RBC.js.map +1 -0
- package/dist/errorReporting-3LPE2IJY.js +109 -0
- package/dist/errorReporting-3LPE2IJY.js.map +1 -0
- package/dist/exec-JOLH5LPT.js +122 -0
- package/dist/exec-JOLH5LPT.js.map +1 -0
- package/dist/explain-NS26WE2Y.js +189 -0
- package/dist/explain-NS26WE2Y.js.map +1 -0
- package/dist/explorer-GSYYYOAL.js +58 -0
- package/dist/explorer-GSYYYOAL.js.map +1 -0
- package/dist/extract-4LWEZG4O.js +152 -0
- package/dist/extract-4LWEZG4O.js.map +1 -0
- package/dist/features-KQV4OFIZ.js +54 -0
- package/dist/features-KQV4OFIZ.js.map +1 -0
- package/dist/feedback-CBLGXUEG.js +158 -0
- package/dist/feedback-CBLGXUEG.js.map +1 -0
- package/dist/find-SMXRCZ76.js +176 -0
- package/dist/find-SMXRCZ76.js.map +1 -0
- package/dist/format-HMGG6MY3.js +277 -0
- package/dist/format-HMGG6MY3.js.map +1 -0
- package/dist/generate-W7VLBDLI.js +160 -0
- package/dist/generate-W7VLBDLI.js.map +1 -0
- package/dist/graph-YYL5UYCJ.js +168 -0
- package/dist/graph-YYL5UYCJ.js.map +1 -0
- package/dist/history-GDRFP4PG.js +184 -0
- package/dist/history-GDRFP4PG.js.map +1 -0
- package/dist/hosts-DRFZTMIJ.js +45 -0
- package/dist/hosts-DRFZTMIJ.js.map +1 -0
- package/dist/impact-A4NU6CB2.js +63 -0
- package/dist/impact-A4NU6CB2.js.map +1 -0
- package/dist/import-2RNYDL4E.js +79 -0
- package/dist/import-2RNYDL4E.js.map +1 -0
- package/dist/index.cjs +11 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +8 -2
- package/dist/index.js.map +1 -1
- package/dist/init-EAOGNGXI.js +54 -0
- package/dist/init-EAOGNGXI.js.map +1 -0
- package/dist/install-hooks-G3Y5LVXK.js +109 -0
- package/dist/install-hooks-G3Y5LVXK.js.map +1 -0
- package/dist/license-Z5YSC7XQ.js +43 -0
- package/dist/license-Z5YSC7XQ.js.map +1 -0
- package/dist/lineage-C5CGVP36.js +555 -0
- package/dist/lineage-C5CGVP36.js.map +1 -0
- package/dist/lint-AQFPZ3WG.js +144 -0
- package/dist/lint-AQFPZ3WG.js.map +1 -0
- package/dist/mcp-F7FND5X7.js +343 -0
- package/dist/mcp-F7FND5X7.js.map +1 -0
- package/dist/migrate-from-dbt-K4ELOWUD.js +156 -0
- package/dist/migrate-from-dbt-K4ELOWUD.js.map +1 -0
- package/dist/migrate-platform-E7VZFPO5.js +91 -0
- package/dist/migrate-platform-E7VZFPO5.js.map +1 -0
- package/dist/optimize-WUJ5ZN5Y.js +109 -0
- package/dist/optimize-WUJ5ZN5Y.js.map +1 -0
- package/dist/perf-UULZSREY.js +200 -0
- package/dist/perf-UULZSREY.js.map +1 -0
- package/dist/pii-QHU32VML.js +146 -0
- package/dist/pii-QHU32VML.js.map +1 -0
- package/dist/pilot-BR6GVK32.js +29 -0
- package/dist/pilot-BR6GVK32.js.map +1 -0
- package/dist/pr-comment-2FOA3EXG.js +81 -0
- package/dist/pr-comment-2FOA3EXG.js.map +1 -0
- package/dist/preview-XNY422OU.js +46 -0
- package/dist/preview-XNY422OU.js.map +1 -0
- package/dist/profile-SQTBNKYS.js +98 -0
- package/dist/profile-SQTBNKYS.js.map +1 -0
- package/dist/promote-FSGUPIPD.js +417 -0
- package/dist/promote-FSGUPIPD.js.map +1 -0
- package/dist/publish-AYCRMCE2.js +739 -0
- package/dist/publish-AYCRMCE2.js.map +1 -0
- package/dist/purge-Y5IOTXKA.js +56 -0
- package/dist/purge-Y5IOTXKA.js.map +1 -0
- package/dist/query-log-SDDGMJLJ.js +112 -0
- package/dist/query-log-SDDGMJLJ.js.map +1 -0
- package/dist/refactor-TC7S43F2.js +5809 -0
- package/dist/refactor-TC7S43F2.js.map +1 -0
- package/dist/refresh-MDJYOYV5.js +39 -0
- package/dist/refresh-MDJYOYV5.js.map +1 -0
- package/dist/replay-E4664A5K.js +118 -0
- package/dist/replay-E4664A5K.js.map +1 -0
- package/dist/revert-QWQWCJJB.js +111 -0
- package/dist/revert-QWQWCJJB.js.map +1 -0
- package/dist/review-7CAVLD67.js +164 -0
- package/dist/review-7CAVLD67.js.map +1 -0
- package/dist/rollback-suggest-C6D5YFCA.js +79 -0
- package/dist/rollback-suggest-C6D5YFCA.js.map +1 -0
- package/dist/safer-alternative-QR4QEFUV.js +84 -0
- package/dist/safer-alternative-QR4QEFUV.js.map +1 -0
- package/dist/safety-OFWUFLK4.js +165 -0
- package/dist/safety-OFWUFLK4.js.map +1 -0
- package/dist/savings-MEBE4TXI.js +95 -0
- package/dist/savings-MEBE4TXI.js.map +1 -0
- package/dist/scan-secrets-XCUBMLHL.js +54 -0
- package/dist/scan-secrets-XCUBMLHL.js.map +1 -0
- package/dist/schema-7JZIG6QR.js +447 -0
- package/dist/schema-7JZIG6QR.js.map +1 -0
- package/dist/script-BMYVBHFR.js +167 -0
- package/dist/script-BMYVBHFR.js.map +1 -0
- package/dist/search-TA3C3AZT.js +151 -0
- package/dist/search-TA3C3AZT.js.map +1 -0
- package/dist/seed-W4Q3L2IU.js +101 -0
- package/dist/seed-W4Q3L2IU.js.map +1 -0
- package/dist/sketch-6B2V6FJV.js +83 -0
- package/dist/sketch-6B2V6FJV.js.map +1 -0
- package/dist/snapshot-YMVS322L.js +171 -0
- package/dist/snapshot-YMVS322L.js.map +1 -0
- package/dist/snippets-EVTN63OU.js +74 -0
- package/dist/snippets-EVTN63OU.js.map +1 -0
- package/dist/standards-FGJW3CQL.js +238 -0
- package/dist/standards-FGJW3CQL.js.map +1 -0
- package/dist/suggest-V3LVIFZ5.js +44 -0
- package/dist/suggest-V3LVIFZ5.js.map +1 -0
- package/dist/suggest-constraints-EX2FCWOQ.js +154 -0
- package/dist/suggest-constraints-EX2FCWOQ.js.map +1 -0
- package/dist/suite-YTQ3CNX5.js +85 -0
- package/dist/suite-YTQ3CNX5.js.map +1 -0
- package/dist/telemetry-KOIY3NEQ.js +90 -0
- package/dist/telemetry-KOIY3NEQ.js.map +1 -0
- package/dist/template-MUJ6X6LN.js +396 -0
- package/dist/template-MUJ6X6LN.js.map +1 -0
- package/dist/test-XFSQHR2S.js +169 -0
- package/dist/test-XFSQHR2S.js.map +1 -0
- package/dist/trial-GFTGYCR3.js +31 -0
- package/dist/trial-GFTGYCR3.js.map +1 -0
- package/dist/validate-LFDEZFFH.js +107 -0
- package/dist/validate-LFDEZFFH.js.map +1 -0
- package/dist/verify-KRDYOJCR.js +76 -0
- package/dist/verify-KRDYOJCR.js.map +1 -0
- package/dist/watch-FSG23RR3.js +80 -0
- package/dist/watch-FSG23RR3.js.map +1 -0
- package/dist/xcompare-U4TXTTIR.js +87 -0
- package/dist/xcompare-U4TXTTIR.js.map +1 -0
- package/package.json +2 -2
- package/dist/cli.cjs +0 -19298
- package/dist/cli.cjs.map +0 -1
- package/dist/cli.d.cts +0 -1
- package/dist/cli.d.ts +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/branch.ts"],"sourcesContent":["import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { Command } from 'commander';\nimport { createConnection, DatabricksExecutor, getProfile } from '@ddt-tools/core';\n\n/**\n * `ddt branch` — PlanetScale-style branching for Databricks using\n * Unity Catalog **SHALLOW CLONE**. Unlike Snowflake's database-level\n * zero-copy clone, UC shallow-clone is per-table — so a \"branch\" is\n * a new schema containing shallow clones of every table in a base\n * schema.\n *\n * Subcommands:\n * create <name> --from <catalog.schema> [--connection <profile>]\n * drop <name> --catalog <catalog> [--connection <profile>]\n *\n * The MVP creates the destination schema and one SHALLOW CLONE per\n * source table; views, functions, and other UC objects are emitted\n * as commented-out scaffolds (manual port is needed because UC\n * doesn't shallow-clone non-table objects). The generated SQL is\n * emitted offline by default and executed when `--connection` is\n * supplied.\n */\nexport function branchCommand(): Command {\n const cmd = new Command('branch').description(\n 'PlanetScale-style branching for Databricks via UC SHALLOW CLONE. create / drop.',\n );\n\n cmd\n .command('create <name>')\n .description(\n 'Create a SHALLOW CLONE of every table in <catalog.schema> into a new branch schema named <name>.',\n )\n .requiredOption('--from <catalog.schema>', 'Base schema to clone, in catalog.schema form.')\n .option(\n '--connection <profile>',\n 'Connection profile to execute against. Omit to emit SQL only.',\n )\n .option(\n '-o, --out <path>',\n 'Write generated SQL to a file. Defaults to stdout when --connection is omitted.',\n )\n .action(async (name, opts) => {\n const branchSchema = String(name);\n const fromParts = String(opts.from).split('.');\n if (fromParts.length !== 2)\n throw new Error('--from must be in catalog.schema form (e.g. main.gold).');\n const [catalog, schema] = fromParts;\n const branchFqn = `${catalog}.${branchSchema}`;\n const sql: string[] = [];\n sql.push(`-- Branch ${branchFqn} = shallow clone of ${catalog}.${schema} (table-level).`);\n sql.push(`CREATE SCHEMA IF NOT EXISTS ${branchFqn};`);\n if (opts.connection) {\n // Live mode: list tables in source schema, emit clones.\n const profile = await getProfile(String(opts.connection));\n const conn = createConnection(profile);\n try {\n await conn.connect();\n const rows = await conn.query(`SHOW TABLES IN ${catalog}.${schema}`);\n for (const r of Array.isArray(rows) ? rows : []) {\n const rec = r as Record<string, unknown>;\n const t = String(rec.tableName ?? rec.name ?? '');\n if (!t) continue;\n sql.push(\n `CREATE OR REPLACE TABLE ${branchFqn}.${t} SHALLOW CLONE ${catalog}.${schema}.${t};`,\n );\n }\n const executor = new DatabricksExecutor(conn);\n for (const stmt of sql.filter((s) => !s.startsWith('--'))) {\n console.error(`> ${stmt.split('\\n')[0]}`);\n await executor.execute(stmt);\n }\n console.error('Done.');\n } finally {\n await conn.disconnect();\n }\n return;\n }\n // Offline mode: emit a SQL stub the user can fill in by listing\n // the source schema's tables and running this once-per-table.\n sql.push(\n `-- For each table in ${catalog}.${schema} (run \\`SHOW TABLES IN ${catalog}.${schema}\\` to enumerate):`,\n );\n sql.push(\n `-- CREATE OR REPLACE TABLE ${branchFqn}.<table> SHALLOW CLONE ${catalog}.${schema}.<table>;`,\n );\n sql.push('');\n const out = sql.join('\\n') + '\\n';\n if (opts.out) {\n const p = path.resolve(String(opts.out));\n await fs.mkdir(path.dirname(p), { recursive: true });\n await fs.writeFile(p, out, 'utf8');\n console.error(`Wrote ${p}.`);\n } else {\n process.stdout.write(out);\n }\n });\n\n cmd\n .command('drop <name>')\n .description('Drop a branch schema (CASCADE).')\n .requiredOption('--catalog <catalog>', 'Catalog the branch lives in.')\n .option('--connection <profile>', 'Connection profile. Omit to emit SQL only.')\n .option('-o, --out <path>', 'Write generated SQL to a file.')\n .action(async (name, opts) => {\n const sql = `-- Drop branch schema\\nDROP SCHEMA IF EXISTS ${opts.catalog}.${name} CASCADE;\\n`;\n if (opts.connection) {\n const profile = await getProfile(String(opts.connection));\n const conn = createConnection(profile);\n try {\n await conn.connect();\n const executor = new DatabricksExecutor(conn);\n await executor.execute(sql);\n console.error('Done.');\n } finally {\n await conn.disconnect();\n }\n return;\n }\n if (opts.out) {\n const p = path.resolve(String(opts.out));\n await fs.mkdir(path.dirname(p), { recursive: true });\n await fs.writeFile(p, sql, 'utf8');\n console.error(`Wrote ${p}.`);\n } else {\n process.stdout.write(sql);\n }\n });\n\n return cmd;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import "./chunk-DGUM43GV.js";
|
|
2
|
+
|
|
3
|
+
// src/commands/build.ts
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
import { pac } from "@ddt-tools/core";
|
|
6
|
+
function buildCommand() {
|
|
7
|
+
const cmd = new Command("build");
|
|
8
|
+
cmd.description("Build a .ddtpac from a .ddtproj project.").requiredOption("-p, --project <path>", "Path to the .ddtproj file").option("-o, --out <path>", "Output .ddtpac path (default: <projectRoot>/bin/<name>.ddtpac)").action(async (opts) => {
|
|
9
|
+
const result = await pac.buildProject(String(opts.project), {
|
|
10
|
+
outputPath: opts.out ? String(opts.out) : void 0
|
|
11
|
+
});
|
|
12
|
+
console.log(`Built ${result.outputPath}`);
|
|
13
|
+
console.log(` ${result.fileCount} source file(s), ${result.objectCount} object(s) in model`);
|
|
14
|
+
});
|
|
15
|
+
return cmd;
|
|
16
|
+
}
|
|
17
|
+
export {
|
|
18
|
+
buildCommand
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=build-MP3JQEFO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/build.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { pac } from '@ddt-tools/core';\n\nexport function buildCommand(): Command {\n const cmd = new Command('build');\n cmd\n .description('Build a .ddtpac from a .ddtproj project.')\n .requiredOption('-p, --project <path>', 'Path to the .ddtproj file')\n .option('-o, --out <path>', 'Output .ddtpac path (default: <projectRoot>/bin/<name>.ddtpac)')\n .action(async (opts) => {\n const result = await pac.buildProject(String(opts.project), {\n outputPath: opts.out ? String(opts.out) : undefined,\n });\n console.log(`Built ${result.outputPath}`);\n console.log(` ${result.fileCount} source file(s), ${result.objectCount} object(s) in model`);\n });\n return cmd;\n}\n"],"mappings":";;;AAAA,SAAS,eAAe;AACxB,SAAS,WAAW;AAEb,SAAS,eAAwB;AACtC,QAAM,MAAM,IAAI,QAAQ,OAAO;AAC/B,MACG,YAAY,0CAA0C,EACtD,eAAe,wBAAwB,2BAA2B,EAClE,OAAO,oBAAoB,gEAAgE,EAC3F,OAAO,OAAO,SAAS;AACtB,UAAM,SAAS,MAAM,IAAI,aAAa,OAAO,KAAK,OAAO,GAAG;AAAA,MAC1D,YAAY,KAAK,MAAM,OAAO,KAAK,GAAG,IAAI;AAAA,IAC5C,CAAC;AACD,YAAQ,IAAI,SAAS,OAAO,UAAU,EAAE;AACxC,YAAQ,IAAI,KAAK,OAAO,SAAS,oBAAoB,OAAO,WAAW,qBAAqB;AAAA,EAC9F,CAAC;AACH,SAAO;AACT;","names":[]}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import "./chunk-DGUM43GV.js";
|
|
2
|
+
|
|
3
|
+
// src/commands/catalog.ts
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
import { catalog, createConnection, getProfile } from "@ddt-tools/core";
|
|
6
|
+
var BUILTIN_CATALOGS = /* @__PURE__ */ new Set(["system", "samples", "__databricks_internal"]);
|
|
7
|
+
function catalogCommand() {
|
|
8
|
+
const cmd = new Command("catalog");
|
|
9
|
+
cmd.description(
|
|
10
|
+
"Manage the per-connection catalog cache used by the Object Explorer + EE2 intellisense."
|
|
11
|
+
);
|
|
12
|
+
cmd.command("refresh").description("Open the connection, scan every (non-builtin) catalog, write the catalog cache.").requiredOption("-c, --connection <name>", "Connection profile name.").option("--root <path>", "Project root. Default cwd.", process.cwd()).option("--catalogs <csv>", "Comma-separated list. Default: every non-builtin catalog.").option("--include-builtins", "Include system / samples / __databricks_internal.", false).option(
|
|
13
|
+
"--concurrency <n>",
|
|
14
|
+
"Bounded-concurrency cap for the bulk-scan pool. Default 10.",
|
|
15
|
+
"10"
|
|
16
|
+
).option("--no-fingerprint-skip", "Force a full scan even when fingerprints are unchanged.").action(async (opts) => {
|
|
17
|
+
const profile = await getProfile(String(opts.connection));
|
|
18
|
+
const conn = createConnection(profile);
|
|
19
|
+
const cache = new catalog.CatalogCache({
|
|
20
|
+
root: String(opts.root),
|
|
21
|
+
connection: profile.name
|
|
22
|
+
});
|
|
23
|
+
console.log(`Connecting to ${profile.auth.host}\u2026`);
|
|
24
|
+
await conn.connect();
|
|
25
|
+
try {
|
|
26
|
+
const cats = await resolveCatalogs(conn, opts);
|
|
27
|
+
if (cats.length === 0) {
|
|
28
|
+
console.warn("No catalogs to scan. Pass --catalogs or --include-builtins.");
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
console.log(
|
|
32
|
+
`Scanning ${cats.length} catalog(s) with concurrency ${Number(opts.concurrency)}.`
|
|
33
|
+
);
|
|
34
|
+
const cached = await cache.get();
|
|
35
|
+
const cachedByCat = new Map(cached.catalogs.map((c) => [c.catalog, c]));
|
|
36
|
+
const concurrency = Math.max(1, Number(opts.concurrency) || 10);
|
|
37
|
+
const fingerprintSkip = opts.fingerprintSkip !== false;
|
|
38
|
+
const { results, errors } = await catalog.mapPool(
|
|
39
|
+
cats,
|
|
40
|
+
async (cat) => {
|
|
41
|
+
let freshFingerprint = null;
|
|
42
|
+
try {
|
|
43
|
+
const fpRes = await conn.query(
|
|
44
|
+
catalog.fingerprintSqlForCatalog(cat)
|
|
45
|
+
);
|
|
46
|
+
freshFingerprint = catalog.parseFingerprintRow(fpRes.rows);
|
|
47
|
+
} catch (err) {
|
|
48
|
+
console.warn(
|
|
49
|
+
`fingerprint(${cat}) failed; falling through to full scan: ${err.message}`
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
const cachedCat = cachedByCat.get(cat);
|
|
53
|
+
if (fingerprintSkip && cachedCat && cachedCat.fingerprint != null && freshFingerprint != null && catalog.isFresh(cachedCat.fingerprint, freshFingerprint)) {
|
|
54
|
+
console.log(` ${cat}: fresh; reusing cache`);
|
|
55
|
+
return {
|
|
56
|
+
catalog: cat,
|
|
57
|
+
fingerprint: cachedCat.fingerprint,
|
|
58
|
+
schemas: cachedCat.schemas
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
const scanRes = await conn.query(catalog.bulkScanSqlForCatalog(cat));
|
|
62
|
+
const schemas = catalog.parseBulkScanRows(cat, scanRes.rows);
|
|
63
|
+
const fingerprint = freshFingerprint ?? null;
|
|
64
|
+
console.log(
|
|
65
|
+
` ${cat}: ${schemas.length} schemas / ${schemas.reduce((sum, s) => sum + s.objects.length, 0)} objects`
|
|
66
|
+
);
|
|
67
|
+
return { catalog: cat, fingerprint, schemas };
|
|
68
|
+
},
|
|
69
|
+
{ concurrency }
|
|
70
|
+
);
|
|
71
|
+
for (const e of errors) {
|
|
72
|
+
console.warn(`scan failed for "${cats[e.index]}": ${e.error.message}`);
|
|
73
|
+
}
|
|
74
|
+
const snapshot = catalog.refreshFingerprints({
|
|
75
|
+
version: catalog.CATALOG_SNAPSHOT_VERSION,
|
|
76
|
+
connection: profile.name,
|
|
77
|
+
snapshotAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
78
|
+
fingerprint: null,
|
|
79
|
+
catalogs: results.filter((r) => !!r)
|
|
80
|
+
});
|
|
81
|
+
await cache.set(snapshot);
|
|
82
|
+
console.log(`Wrote ${snapshot.catalogs.length} catalogs to ${cache.path}`);
|
|
83
|
+
} finally {
|
|
84
|
+
await conn.disconnect();
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
cmd.command("show").description("Pretty-print or JSON-dump the cached snapshot for a connection.").requiredOption("-c, --connection <name>", "Connection profile name.").option("--root <path>", "Project root. Default cwd.", process.cwd()).option("--json", "Emit JSON instead of summary.").action(async (opts) => {
|
|
88
|
+
const cache = new catalog.CatalogCache({
|
|
89
|
+
root: String(opts.root),
|
|
90
|
+
connection: String(opts.connection)
|
|
91
|
+
});
|
|
92
|
+
const snapshot = await cache.get();
|
|
93
|
+
if (opts.json) {
|
|
94
|
+
console.log(JSON.stringify(snapshot, null, 2));
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (snapshot.catalogs.length === 0) {
|
|
98
|
+
console.warn(`Catalog cache is empty for "${opts.connection}".`);
|
|
99
|
+
console.warn(` Cache file: ${cache.path}`);
|
|
100
|
+
console.warn(` Run \`ddt catalog refresh --connection ${opts.connection}\` to populate.`);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
console.log(`Snapshot for "${snapshot.connection}" \u2014 ${snapshot.snapshotAt}`);
|
|
104
|
+
console.log(
|
|
105
|
+
` Top-level fingerprint: ${snapshot.fingerprint != null ? new Date(snapshot.fingerprint).toISOString() : "(none)"}`
|
|
106
|
+
);
|
|
107
|
+
for (const cat of snapshot.catalogs) {
|
|
108
|
+
const objCount = cat.schemas.reduce((sum, s) => sum + s.objects.length, 0);
|
|
109
|
+
console.log(
|
|
110
|
+
` ${cat.catalog.padEnd(32)} ${cat.schemas.length} schemas / ${objCount} objects`
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
cmd.command("clear").description("Delete the cached snapshot for a connection.").requiredOption("-c, --connection <name>", "Connection profile name.").option("--root <path>", "Project root. Default cwd.", process.cwd()).action(async (opts) => {
|
|
115
|
+
const cache = new catalog.CatalogCache({
|
|
116
|
+
root: String(opts.root),
|
|
117
|
+
connection: String(opts.connection)
|
|
118
|
+
});
|
|
119
|
+
await cache.clear();
|
|
120
|
+
console.log(`Cleared cache for "${opts.connection}".`);
|
|
121
|
+
console.log(` was: ${cache.path}`);
|
|
122
|
+
});
|
|
123
|
+
return cmd;
|
|
124
|
+
}
|
|
125
|
+
async function resolveCatalogs(conn, opts) {
|
|
126
|
+
if (opts.catalogs) {
|
|
127
|
+
return String(opts.catalogs).split(",").map((s) => s.trim()).filter(Boolean);
|
|
128
|
+
}
|
|
129
|
+
const res = await conn.query("SHOW CATALOGS");
|
|
130
|
+
const names = res.rows.map((r) => String(r.catalog ?? r.catalog_name ?? r.CATALOG ?? r.CATALOG_NAME ?? "")).filter(Boolean);
|
|
131
|
+
if (opts.includeBuiltins) return names;
|
|
132
|
+
return names.filter((n) => !BUILTIN_CATALOGS.has(n.toLowerCase()));
|
|
133
|
+
}
|
|
134
|
+
export {
|
|
135
|
+
catalogCommand
|
|
136
|
+
};
|
|
137
|
+
//# sourceMappingURL=catalog-3J3NFNXP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/catalog.ts"],"sourcesContent":["/**\n * `ddt catalog` — manage the per-connection catalog cache (EE1 substrate).\n *\n * ddt catalog refresh --connection <name> [--catalogs <csv>] [--concurrency <n>]\n * ddt catalog show --connection <name> [--json]\n * ddt catalog clear --connection <name>\n *\n * `refresh` opens a live Databricks SQL warehouse connection, discovers\n * catalogs via `SHOW CATALOGS`, runs the bulk-scan SQL per catalog via\n * the bounded promise pool, and writes the assembled snapshot to\n * `<root>/.ddt/cache/<conn>/catalog.msgpack` (RES.1 — was `catalog.json`\n * before 2026-05-16; the cache reader still accepts the legacy form for\n * one major version). Schema fingerprints (`MAX(LAST_ALTERED)`) are\n * checked first; catalogs that haven't changed since the last refresh\n * are skipped.\n *\n * `show` reads the cache file and pretty-prints (or emits JSON).\n * `clear` deletes the cache file (and its parent dir if empty).\n *\n * Object Explorer (`ddt explorer`) and the eventual EE2 intellisense\n * provider both consume this cache.\n */\nimport { Command } from 'commander';\nimport { catalog, createConnection, getProfile, type DatabricksConnection } from '@ddt-tools/core';\n\n/**\n * Built-in catalogs that almost no one wants in their cache. Pass\n * `--include-builtins` to keep them. `system` is intentionally excluded\n * because the bulk-scan SQL filters out `information_schema` already.\n */\nconst BUILTIN_CATALOGS = new Set(['system', 'samples', '__databricks_internal']);\n\ninterface ShowCatalogsRow {\n catalog?: string;\n catalog_name?: string;\n CATALOG?: string;\n CATALOG_NAME?: string;\n}\n\nexport function catalogCommand(): Command {\n const cmd = new Command('catalog');\n cmd.description(\n 'Manage the per-connection catalog cache used by the Object Explorer + EE2 intellisense.',\n );\n\n cmd\n .command('refresh')\n .description('Open the connection, scan every (non-builtin) catalog, write the catalog cache.')\n .requiredOption('-c, --connection <name>', 'Connection profile name.')\n .option('--root <path>', 'Project root. Default cwd.', process.cwd())\n .option('--catalogs <csv>', 'Comma-separated list. Default: every non-builtin catalog.')\n .option('--include-builtins', 'Include system / samples / __databricks_internal.', false)\n .option(\n '--concurrency <n>',\n 'Bounded-concurrency cap for the bulk-scan pool. Default 10.',\n '10',\n )\n .option('--no-fingerprint-skip', 'Force a full scan even when fingerprints are unchanged.')\n .action(async (opts) => {\n const profile = await getProfile(String(opts.connection));\n const conn = createConnection(profile);\n const cache = new catalog.CatalogCache({\n root: String(opts.root),\n connection: profile.name,\n });\n\n console.log(`Connecting to ${profile.auth.host}…`);\n await conn.connect();\n try {\n const cats = await resolveCatalogs(conn, opts);\n if (cats.length === 0) {\n console.warn('No catalogs to scan. Pass --catalogs or --include-builtins.');\n return;\n }\n console.log(\n `Scanning ${cats.length} catalog(s) with concurrency ${Number(opts.concurrency)}.`,\n );\n\n const cached = await cache.get();\n const cachedByCat = new Map(cached.catalogs.map((c) => [c.catalog, c] as const));\n\n const concurrency = Math.max(1, Number(opts.concurrency) || 10);\n const fingerprintSkip = opts.fingerprintSkip !== false;\n\n const { results, errors } = await catalog.mapPool(\n cats,\n async (cat) => {\n let freshFingerprint: number | null = null;\n try {\n const fpRes = await conn.query<{ MAX_LAST_ALTERED: unknown }>(\n catalog.fingerprintSqlForCatalog(cat),\n );\n freshFingerprint = catalog.parseFingerprintRow(fpRes.rows);\n } catch (err) {\n console.warn(\n `fingerprint(${cat}) failed; falling through to full scan: ${(err as Error).message}`,\n );\n }\n\n const cachedCat = cachedByCat.get(cat);\n if (\n fingerprintSkip &&\n cachedCat &&\n cachedCat.fingerprint != null &&\n freshFingerprint != null &&\n catalog.isFresh(cachedCat.fingerprint, freshFingerprint)\n ) {\n console.log(` ${cat}: fresh; reusing cache`);\n return {\n catalog: cat,\n fingerprint: cachedCat.fingerprint,\n schemas: cachedCat.schemas,\n };\n }\n\n const scanRes = await conn.query(catalog.bulkScanSqlForCatalog(cat));\n const schemas = catalog.parseBulkScanRows(cat, scanRes.rows);\n const fingerprint = freshFingerprint ?? null;\n console.log(\n ` ${cat}: ${schemas.length} schemas / ${schemas.reduce((sum, s) => sum + s.objects.length, 0)} objects`,\n );\n return { catalog: cat, fingerprint, schemas };\n },\n { concurrency },\n );\n\n for (const e of errors) {\n console.warn(`scan failed for \"${cats[e.index]}\": ${(e.error as Error).message}`);\n }\n\n const snapshot = catalog.refreshFingerprints({\n version: catalog.CATALOG_SNAPSHOT_VERSION,\n connection: profile.name,\n snapshotAt: new Date().toISOString(),\n fingerprint: null,\n catalogs: results.filter((r): r is NonNullable<typeof r> => !!r),\n });\n await cache.set(snapshot);\n\n console.log(`Wrote ${snapshot.catalogs.length} catalogs to ${cache.path}`);\n } finally {\n await conn.disconnect();\n }\n });\n\n cmd\n .command('show')\n .description('Pretty-print or JSON-dump the cached snapshot for a connection.')\n .requiredOption('-c, --connection <name>', 'Connection profile name.')\n .option('--root <path>', 'Project root. Default cwd.', process.cwd())\n .option('--json', 'Emit JSON instead of summary.')\n .action(async (opts) => {\n const cache = new catalog.CatalogCache({\n root: String(opts.root),\n connection: String(opts.connection),\n });\n const snapshot = await cache.get();\n if (opts.json) {\n console.log(JSON.stringify(snapshot, null, 2));\n return;\n }\n if (snapshot.catalogs.length === 0) {\n console.warn(`Catalog cache is empty for \"${opts.connection}\".`);\n console.warn(` Cache file: ${cache.path}`);\n console.warn(` Run \\`ddt catalog refresh --connection ${opts.connection}\\` to populate.`);\n return;\n }\n console.log(`Snapshot for \"${snapshot.connection}\" — ${snapshot.snapshotAt}`);\n console.log(\n ` Top-level fingerprint: ${snapshot.fingerprint != null ? new Date(snapshot.fingerprint).toISOString() : '(none)'}`,\n );\n for (const cat of snapshot.catalogs) {\n const objCount = cat.schemas.reduce((sum, s) => sum + s.objects.length, 0);\n console.log(\n ` ${cat.catalog.padEnd(32)} ${cat.schemas.length} schemas / ${objCount} objects`,\n );\n }\n });\n\n cmd\n .command('clear')\n .description('Delete the cached snapshot for a connection.')\n .requiredOption('-c, --connection <name>', 'Connection profile name.')\n .option('--root <path>', 'Project root. Default cwd.', process.cwd())\n .action(async (opts) => {\n const cache = new catalog.CatalogCache({\n root: String(opts.root),\n connection: String(opts.connection),\n });\n await cache.clear();\n console.log(`Cleared cache for \"${opts.connection}\".`);\n console.log(` was: ${cache.path}`);\n });\n\n return cmd;\n}\n\nasync function resolveCatalogs(\n conn: DatabricksConnection,\n opts: { catalogs?: unknown; includeBuiltins?: unknown },\n): Promise<string[]> {\n if (opts.catalogs) {\n return String(opts.catalogs)\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean);\n }\n const res = await conn.query<ShowCatalogsRow>('SHOW CATALOGS');\n const names = res.rows\n .map((r) => String(r.catalog ?? r.catalog_name ?? r.CATALOG ?? r.CATALOG_NAME ?? ''))\n .filter(Boolean);\n if (opts.includeBuiltins) return names;\n return names.filter((n) => !BUILTIN_CATALOGS.has(n.toLowerCase()));\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import "./chunk-DGUM43GV.js";
|
|
2
|
+
|
|
3
|
+
// src/commands/changelog.ts
|
|
4
|
+
import { promises as fs } from "fs";
|
|
5
|
+
import path from "path";
|
|
6
|
+
import { execFile } from "child_process";
|
|
7
|
+
import { promisify } from "util";
|
|
8
|
+
import { Command } from "commander";
|
|
9
|
+
var execFileP = promisify(execFile);
|
|
10
|
+
var CATEGORY_ORDER = [
|
|
11
|
+
{ type: "feat", heading: "\u2728 Features" },
|
|
12
|
+
{ type: "fix", heading: "\u{1F41B} Bug fixes" },
|
|
13
|
+
{ type: "perf", heading: "\u26A1 Performance" },
|
|
14
|
+
{ type: "refactor", heading: "\u267B\uFE0F Refactoring" },
|
|
15
|
+
{ type: "docs", heading: "\u{1F4DA} Documentation" },
|
|
16
|
+
{ type: "test", heading: "\u{1F9EA} Tests" },
|
|
17
|
+
{ type: "build", heading: "\u{1F527} Build / CI" },
|
|
18
|
+
{ type: "ci", heading: "\u{1F527} Build / CI" },
|
|
19
|
+
{ type: "chore", heading: "\u{1F9F9} Chores" },
|
|
20
|
+
{ type: "style", heading: "\u{1F3A8} Style" }
|
|
21
|
+
];
|
|
22
|
+
function changelogCommand() {
|
|
23
|
+
const cmd = new Command("changelog");
|
|
24
|
+
cmd.description(
|
|
25
|
+
"Generate a Markdown CHANGELOG section from git commits between two refs (Conventional Commits parser)."
|
|
26
|
+
).option("--from <ref>", "Starting git ref (exclusive). Default: previous tag.", "").option("--to <ref>", "Ending git ref (inclusive). Default: HEAD.", "HEAD").option("--repo <path>", "Path to the git repository. Default: current directory.", ".").option("--version <name>", "Version heading for the section. Default: --to ref.").option(
|
|
27
|
+
"--scope <pathspec>",
|
|
28
|
+
"Restrict to commits touching paths matching this git-pathspec (e.g. `Databricks/packages/cli/**`). Default: all paths."
|
|
29
|
+
).option("-o, --out <path>", "Append/write to file. Default: stdout.").option("--append", "When --out is set, prepend to existing file.", false).option(
|
|
30
|
+
"--manifest-dir <path>",
|
|
31
|
+
'Directory containing deploy manifests (default: .ddt/history). When set, the changelog appends a "\u{1F680} Deploys" addendum: one row per manifest with step-status counts + safety summary. Manifest reads are best-effort \u2014 corrupt files are skipped silently.'
|
|
32
|
+
).action(async (opts) => {
|
|
33
|
+
const repo = path.resolve(String(opts.repo));
|
|
34
|
+
const to = String(opts.to);
|
|
35
|
+
let from = String(opts.from);
|
|
36
|
+
if (!from) {
|
|
37
|
+
from = await previousTag(repo, to);
|
|
38
|
+
}
|
|
39
|
+
const commits = await collectCommits(
|
|
40
|
+
repo,
|
|
41
|
+
from,
|
|
42
|
+
to,
|
|
43
|
+
opts.scope ? String(opts.scope) : void 0
|
|
44
|
+
);
|
|
45
|
+
const grouped = groupByType(commits);
|
|
46
|
+
const version = String(opts.version ?? to);
|
|
47
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
48
|
+
const manifestDir = opts.manifestDir ? path.resolve(String(opts.manifestDir)) : path.join(repo, ".ddt", "history");
|
|
49
|
+
const deploys = await readDeploySummaries(manifestDir);
|
|
50
|
+
const md = renderMarkdown(version, today, from, to, grouped, deploys);
|
|
51
|
+
if (opts.out) {
|
|
52
|
+
const out = path.resolve(String(opts.out));
|
|
53
|
+
let body = md;
|
|
54
|
+
if (opts.append) {
|
|
55
|
+
try {
|
|
56
|
+
const existing = await fs.readFile(out, "utf8");
|
|
57
|
+
body = `${md}
|
|
58
|
+
${existing}`;
|
|
59
|
+
} catch {
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
await fs.mkdir(path.dirname(out), { recursive: true });
|
|
63
|
+
await fs.writeFile(out, body, "utf8");
|
|
64
|
+
console.error(`Wrote ${out} (${commits.length} commit(s)).`);
|
|
65
|
+
} else {
|
|
66
|
+
process.stdout.write(md);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
return cmd;
|
|
70
|
+
}
|
|
71
|
+
async function previousTag(repo, ref) {
|
|
72
|
+
try {
|
|
73
|
+
const { stdout } = await execFileP("git", ["describe", "--tags", "--abbrev=0", `${ref}^`], {
|
|
74
|
+
cwd: repo
|
|
75
|
+
});
|
|
76
|
+
return stdout.trim();
|
|
77
|
+
} catch {
|
|
78
|
+
const { stdout } = await execFileP("git", ["rev-list", "--max-parents=0", "HEAD"], {
|
|
79
|
+
cwd: repo
|
|
80
|
+
});
|
|
81
|
+
return stdout.trim().split("\n")[0] ?? "";
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
async function collectCommits(repo, from, to, scope) {
|
|
85
|
+
const range = from ? `${from}..${to}` : to;
|
|
86
|
+
const args = ["log", "--no-merges", "--pretty=format:%H%x01%s", range];
|
|
87
|
+
if (scope) {
|
|
88
|
+
args.push("--", scope);
|
|
89
|
+
}
|
|
90
|
+
const { stdout } = await execFileP("git", args, {
|
|
91
|
+
cwd: repo,
|
|
92
|
+
maxBuffer: 64 * 1024 * 1024
|
|
93
|
+
});
|
|
94
|
+
const lines = stdout.split("\n").filter(Boolean);
|
|
95
|
+
return lines.map((line) => {
|
|
96
|
+
const [sha, subject] = line.split("");
|
|
97
|
+
return parseCommit(sha, subject);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
function parseCommit(sha, subject) {
|
|
101
|
+
const m = subject.match(/^([a-z]+)(\(([^)]+)\))?(!)?:\s*(.+)$/i);
|
|
102
|
+
if (!m) {
|
|
103
|
+
return { sha, type: "chore", scope: void 0, subject, isBreaking: false };
|
|
104
|
+
}
|
|
105
|
+
const type = m[1].toLowerCase();
|
|
106
|
+
const scope = m[3];
|
|
107
|
+
const isBreaking = !!m[4];
|
|
108
|
+
const text = m[5].trim();
|
|
109
|
+
return { sha, type, scope, subject: text, isBreaking };
|
|
110
|
+
}
|
|
111
|
+
function groupByType(commits) {
|
|
112
|
+
const out = /* @__PURE__ */ new Map();
|
|
113
|
+
for (const c of commits) {
|
|
114
|
+
const canonical = CATEGORY_ORDER.find((cat) => cat.type === c.type)?.type ?? "chore";
|
|
115
|
+
const arr = out.get(canonical) ?? [];
|
|
116
|
+
arr.push(c);
|
|
117
|
+
out.set(canonical, arr);
|
|
118
|
+
}
|
|
119
|
+
return out;
|
|
120
|
+
}
|
|
121
|
+
function renderMarkdown(version, date, from, to, grouped, deploys) {
|
|
122
|
+
const lines = [];
|
|
123
|
+
lines.push(`## ${version} \u2014 ${date}`);
|
|
124
|
+
lines.push("");
|
|
125
|
+
lines.push(`_Range: \`${from || "(initial)"}\`..\`${to}\`_`);
|
|
126
|
+
lines.push("");
|
|
127
|
+
const breaking = [...grouped.values()].flat().filter((c) => c.isBreaking);
|
|
128
|
+
if (breaking.length > 0) {
|
|
129
|
+
lines.push("### \u26A0\uFE0F BREAKING CHANGES");
|
|
130
|
+
lines.push("");
|
|
131
|
+
for (const c of breaking) {
|
|
132
|
+
lines.push(`- ${formatCommitLine(c)}`);
|
|
133
|
+
}
|
|
134
|
+
lines.push("");
|
|
135
|
+
}
|
|
136
|
+
const headingsSeen = /* @__PURE__ */ new Set();
|
|
137
|
+
for (const { heading } of CATEGORY_ORDER) {
|
|
138
|
+
if (headingsSeen.has(heading)) continue;
|
|
139
|
+
headingsSeen.add(heading);
|
|
140
|
+
const types = CATEGORY_ORDER.filter((c) => c.heading === heading).map((c) => c.type);
|
|
141
|
+
const commits = types.flatMap((t) => grouped.get(t) ?? []);
|
|
142
|
+
if (commits.length === 0) continue;
|
|
143
|
+
lines.push(`### ${heading}`);
|
|
144
|
+
lines.push("");
|
|
145
|
+
for (const c of commits) {
|
|
146
|
+
if (c.isBreaking) continue;
|
|
147
|
+
lines.push(`- ${formatCommitLine(c)}`);
|
|
148
|
+
}
|
|
149
|
+
lines.push("");
|
|
150
|
+
}
|
|
151
|
+
if (deploys.length > 0) {
|
|
152
|
+
lines.push("### \u{1F680} Deploys");
|
|
153
|
+
lines.push("");
|
|
154
|
+
for (const d of deploys) {
|
|
155
|
+
lines.push(`- ${formatDeploySummaryLine(d)}`);
|
|
156
|
+
}
|
|
157
|
+
lines.push("");
|
|
158
|
+
}
|
|
159
|
+
return lines.join("\n");
|
|
160
|
+
}
|
|
161
|
+
function formatCommitLine(c) {
|
|
162
|
+
const scope = c.scope ? `**${c.scope}**: ` : "";
|
|
163
|
+
return `${scope}${c.subject} (\`${c.sha.slice(0, 7)}\`)`;
|
|
164
|
+
}
|
|
165
|
+
async function readDeploySummaries(dir) {
|
|
166
|
+
let entries;
|
|
167
|
+
try {
|
|
168
|
+
entries = await fs.readdir(dir);
|
|
169
|
+
} catch {
|
|
170
|
+
return [];
|
|
171
|
+
}
|
|
172
|
+
const out = [];
|
|
173
|
+
for (const name of entries.sort()) {
|
|
174
|
+
if (!name.endsWith(".json")) continue;
|
|
175
|
+
try {
|
|
176
|
+
const body = await fs.readFile(path.join(dir, name), "utf8");
|
|
177
|
+
const parsed = JSON.parse(body);
|
|
178
|
+
if (parsed.version !== 1) continue;
|
|
179
|
+
const steps = Array.isArray(parsed.steps) ? parsed.steps : [];
|
|
180
|
+
const stepCounts = {};
|
|
181
|
+
for (const s of steps) {
|
|
182
|
+
const status = typeof s.status === "string" ? s.status : "unknown";
|
|
183
|
+
stepCounts[status] = (stepCounts[status] ?? 0) + 1;
|
|
184
|
+
}
|
|
185
|
+
out.push({
|
|
186
|
+
filename: name,
|
|
187
|
+
...typeof parsed.deployedAt === "string" ? { deployedAt: parsed.deployedAt } : {},
|
|
188
|
+
...typeof parsed.workspaceHost === "string" ? { workspaceHost: parsed.workspaceHost } : {},
|
|
189
|
+
...typeof parsed.finalState === "string" ? { finalState: parsed.finalState } : {},
|
|
190
|
+
failedStepId: parsed.failedStepId ?? null,
|
|
191
|
+
stepCounts,
|
|
192
|
+
totalSteps: steps.length
|
|
193
|
+
});
|
|
194
|
+
} catch {
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return out;
|
|
198
|
+
}
|
|
199
|
+
function formatDeploySummaryLine(d) {
|
|
200
|
+
const parts = [];
|
|
201
|
+
parts.push(`\`${d.filename}\``);
|
|
202
|
+
if (d.deployedAt) parts.push(d.deployedAt);
|
|
203
|
+
if (d.workspaceHost) parts.push(d.workspaceHost);
|
|
204
|
+
const stateGlyph = d.finalState === "clean-success" ? "\u2705" : d.finalState === "clean-skipped" ? "\u23ED\uFE0F" : d.finalState === "dirty" ? "\u{1F6D1}" : d.finalState === "clean-partial" ? "\u26A0\uFE0F" : "\xB7";
|
|
205
|
+
parts.push(`${stateGlyph} ${d.finalState ?? "unknown"}`);
|
|
206
|
+
parts.push(`${d.totalSteps} step(s)`);
|
|
207
|
+
const statusTags = Object.entries(d.stepCounts).sort(([a], [b]) => a.localeCompare(b)).map(([s, n]) => `${s}:${n}`).join(", ");
|
|
208
|
+
if (statusTags) parts.push(`(${statusTags})`);
|
|
209
|
+
if (d.failedStepId) parts.push(`failed: ${d.failedStepId}`);
|
|
210
|
+
return parts.join(" \xB7 ");
|
|
211
|
+
}
|
|
212
|
+
export {
|
|
213
|
+
changelogCommand,
|
|
214
|
+
parseCommit
|
|
215
|
+
};
|
|
216
|
+
//# sourceMappingURL=changelog-ZQAH3ULB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/changelog.ts"],"sourcesContent":["/**\n * `ddt changelog --from <ref> --to <ref>` — auto-generate a\n * Markdown CHANGELOG section from git commits between two refs.\n *\n * Mirrors `sdt changelog`. Parses Conventional Commits, groups by\n * category, emits a release section. Deterministic — no AI.\n */\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { Command } from 'commander';\n\nconst execFileP = promisify(execFile);\n\ninterface Commit {\n sha: string;\n type: string;\n scope: string | undefined;\n subject: string;\n isBreaking: boolean;\n}\n\nconst CATEGORY_ORDER: Array<{ type: string; heading: string }> = [\n { type: 'feat', heading: '✨ Features' },\n { type: 'fix', heading: '🐛 Bug fixes' },\n { type: 'perf', heading: '⚡ Performance' },\n { type: 'refactor', heading: '♻️ Refactoring' },\n { type: 'docs', heading: '📚 Documentation' },\n { type: 'test', heading: '🧪 Tests' },\n { type: 'build', heading: '🔧 Build / CI' },\n { type: 'ci', heading: '🔧 Build / CI' },\n { type: 'chore', heading: '🧹 Chores' },\n { type: 'style', heading: '🎨 Style' },\n];\n\nexport function changelogCommand(): Command {\n const cmd = new Command('changelog');\n cmd\n .description(\n 'Generate a Markdown CHANGELOG section from git commits between two refs (Conventional Commits parser).',\n )\n .option('--from <ref>', 'Starting git ref (exclusive). Default: previous tag.', '')\n .option('--to <ref>', 'Ending git ref (inclusive). Default: HEAD.', 'HEAD')\n .option('--repo <path>', 'Path to the git repository. Default: current directory.', '.')\n .option('--version <name>', 'Version heading for the section. Default: --to ref.')\n .option(\n '--scope <pathspec>',\n 'Restrict to commits touching paths matching this git-pathspec (e.g. `Databricks/packages/cli/**`). Default: all paths.',\n )\n .option('-o, --out <path>', 'Append/write to file. Default: stdout.')\n .option('--append', 'When --out is set, prepend to existing file.', false)\n .option(\n '--manifest-dir <path>',\n 'Directory containing deploy manifests (default: .ddt/history). When set, the changelog appends a \"🚀 Deploys\" addendum: one row per manifest with step-status counts + safety summary. Manifest reads are best-effort — corrupt files are skipped silently.',\n )\n .action(async (opts) => {\n const repo = path.resolve(String(opts.repo));\n const to = String(opts.to);\n let from = String(opts.from);\n if (!from) {\n from = await previousTag(repo, to);\n }\n const commits = await collectCommits(\n repo,\n from,\n to,\n opts.scope ? String(opts.scope) : undefined,\n );\n const grouped = groupByType(commits);\n const version = String(opts.version ?? to);\n const today = new Date().toISOString().slice(0, 10);\n const manifestDir = opts.manifestDir\n ? path.resolve(String(opts.manifestDir))\n : path.join(repo, '.ddt', 'history');\n const deploys = await readDeploySummaries(manifestDir);\n const md = renderMarkdown(version, today, from, to, grouped, deploys);\n\n if (opts.out) {\n const out = path.resolve(String(opts.out));\n let body = md;\n if (opts.append) {\n try {\n const existing = await fs.readFile(out, 'utf8');\n body = `${md}\\n${existing}`;\n } catch {\n // file doesn't exist — write fresh.\n }\n }\n await fs.mkdir(path.dirname(out), { recursive: true });\n await fs.writeFile(out, body, 'utf8');\n console.error(`Wrote ${out} (${commits.length} commit(s)).`);\n } else {\n process.stdout.write(md);\n }\n });\n return cmd;\n}\n\nasync function previousTag(repo: string, ref: string): Promise<string> {\n try {\n const { stdout } = await execFileP('git', ['describe', '--tags', '--abbrev=0', `${ref}^`], {\n cwd: repo,\n });\n return stdout.trim();\n } catch {\n const { stdout } = await execFileP('git', ['rev-list', '--max-parents=0', 'HEAD'], {\n cwd: repo,\n });\n return stdout.trim().split('\\n')[0] ?? '';\n }\n}\n\nasync function collectCommits(\n repo: string,\n from: string,\n to: string,\n scope?: string,\n): Promise<Commit[]> {\n const range = from ? `${from}..${to}` : to;\n const args = ['log', '--no-merges', '--pretty=format:%H%x01%s', range];\n if (scope) {\n args.push('--', scope);\n }\n const { stdout } = await execFileP('git', args, {\n cwd: repo,\n maxBuffer: 64 * 1024 * 1024,\n });\n const lines = stdout.split('\\n').filter(Boolean);\n return lines.map((line) => {\n const [sha, subject] = line.split('\\x01');\n return parseCommit(sha!, subject!);\n });\n}\n\nexport function parseCommit(sha: string, subject: string): Commit {\n const m = subject.match(/^([a-z]+)(\\(([^)]+)\\))?(!)?:\\s*(.+)$/i);\n if (!m) {\n return { sha, type: 'chore', scope: undefined, subject, isBreaking: false };\n }\n const type = m[1]!.toLowerCase();\n const scope = m[3];\n const isBreaking = !!m[4];\n const text = m[5]!.trim();\n return { sha, type, scope, subject: text, isBreaking };\n}\n\nfunction groupByType(commits: Commit[]): Map<string, Commit[]> {\n const out = new Map<string, Commit[]>();\n for (const c of commits) {\n const canonical = CATEGORY_ORDER.find((cat) => cat.type === c.type)?.type ?? 'chore';\n const arr = out.get(canonical) ?? [];\n arr.push(c);\n out.set(canonical, arr);\n }\n return out;\n}\n\nfunction renderMarkdown(\n version: string,\n date: string,\n from: string,\n to: string,\n grouped: Map<string, Commit[]>,\n deploys: DeploySummary[],\n): string {\n const lines: string[] = [];\n lines.push(`## ${version} — ${date}`);\n lines.push('');\n lines.push(`_Range: \\`${from || '(initial)'}\\`..\\`${to}\\`_`);\n lines.push('');\n\n const breaking = [...grouped.values()].flat().filter((c) => c.isBreaking);\n if (breaking.length > 0) {\n lines.push('### ⚠️ BREAKING CHANGES');\n lines.push('');\n for (const c of breaking) {\n lines.push(`- ${formatCommitLine(c)}`);\n }\n lines.push('');\n }\n\n const headingsSeen = new Set<string>();\n for (const { heading } of CATEGORY_ORDER) {\n if (headingsSeen.has(heading)) continue;\n headingsSeen.add(heading);\n const types = CATEGORY_ORDER.filter((c) => c.heading === heading).map((c) => c.type);\n const commits = types.flatMap((t) => grouped.get(t) ?? []);\n if (commits.length === 0) continue;\n lines.push(`### ${heading}`);\n lines.push('');\n for (const c of commits) {\n if (c.isBreaking) continue;\n lines.push(`- ${formatCommitLine(c)}`);\n }\n lines.push('');\n }\n\n if (deploys.length > 0) {\n lines.push('### 🚀 Deploys');\n lines.push('');\n for (const d of deploys) {\n lines.push(`- ${formatDeploySummaryLine(d)}`);\n }\n lines.push('');\n }\n return lines.join('\\n');\n}\n\nfunction formatCommitLine(c: Commit): string {\n const scope = c.scope ? `**${c.scope}**: ` : '';\n return `${scope}${c.subject} (\\`${c.sha.slice(0, 7)}\\`)`;\n}\n\n/** One deploy-manifest summary row for the changelog's 🚀 addendum. */\nexport interface DeploySummary {\n filename: string;\n deployedAt?: string;\n workspaceHost?: string;\n finalState?: string;\n failedStepId?: string | null;\n stepCounts: Record<string, number>;\n totalSteps: number;\n}\n\nasync function readDeploySummaries(dir: string): Promise<DeploySummary[]> {\n let entries: string[];\n try {\n entries = await fs.readdir(dir);\n } catch {\n return [];\n }\n const out: DeploySummary[] = [];\n for (const name of entries.sort()) {\n if (!name.endsWith('.json')) continue;\n try {\n const body = await fs.readFile(path.join(dir, name), 'utf8');\n const parsed = JSON.parse(body) as {\n version?: number;\n deployedAt?: string;\n workspaceHost?: string;\n finalState?: string;\n failedStepId?: string | null;\n steps?: Array<{ status?: string }>;\n };\n if (parsed.version !== 1) continue;\n const steps = Array.isArray(parsed.steps) ? parsed.steps : [];\n const stepCounts: Record<string, number> = {};\n for (const s of steps) {\n const status = typeof s.status === 'string' ? s.status : 'unknown';\n stepCounts[status] = (stepCounts[status] ?? 0) + 1;\n }\n out.push({\n filename: name,\n ...(typeof parsed.deployedAt === 'string' ? { deployedAt: parsed.deployedAt } : {}),\n ...(typeof parsed.workspaceHost === 'string'\n ? { workspaceHost: parsed.workspaceHost }\n : {}),\n ...(typeof parsed.finalState === 'string' ? { finalState: parsed.finalState } : {}),\n failedStepId: parsed.failedStepId ?? null,\n stepCounts,\n totalSteps: steps.length,\n });\n } catch {\n // skip\n }\n }\n return out;\n}\n\nfunction formatDeploySummaryLine(d: DeploySummary): string {\n const parts: string[] = [];\n parts.push(`\\`${d.filename}\\``);\n if (d.deployedAt) parts.push(d.deployedAt);\n if (d.workspaceHost) parts.push(d.workspaceHost);\n const stateGlyph =\n d.finalState === 'clean-success'\n ? '✅'\n : d.finalState === 'clean-skipped'\n ? '⏭️'\n : d.finalState === 'dirty'\n ? '🛑'\n : d.finalState === 'clean-partial'\n ? '⚠️'\n : '·';\n parts.push(`${stateGlyph} ${d.finalState ?? 'unknown'}`);\n parts.push(`${d.totalSteps} step(s)`);\n const statusTags = Object.entries(d.stepCounts)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([s, n]) => `${s}:${n}`)\n .join(', ');\n if (statusTags) parts.push(`(${statusTags})`);\n if (d.failedStepId) parts.push(`failed: ${d.failedStepId}`);\n return parts.join(' · ');\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// src/util/mapping.ts
|
|
2
|
+
import { promises as fs } from "fs";
|
|
3
|
+
import { Option } from "commander";
|
|
4
|
+
import { mappingFromArgs, mappingFromFile } from "@ddt-tools/core";
|
|
5
|
+
function addMappingFlags(cmd) {
|
|
6
|
+
return cmd.option(
|
|
7
|
+
"--map <src=tgt>",
|
|
8
|
+
"Logical-name mapping (repeatable). Examples: DB_A=DB_B, DB_A.STAGING=DB_B.RAW. Rewrites source-side FQNs and DDL body refs.",
|
|
9
|
+
(value, previous) => [...previous, value],
|
|
10
|
+
[]
|
|
11
|
+
).option("--map-file <path>", "JSON file of mappings.").addOption(
|
|
12
|
+
new Option(
|
|
13
|
+
"--map-case-sensitive",
|
|
14
|
+
"Match identifiers case-sensitively. Default: insensitive."
|
|
15
|
+
).default(false)
|
|
16
|
+
).addOption(
|
|
17
|
+
new Option(
|
|
18
|
+
"--map-rewrite-standalone",
|
|
19
|
+
"Rewrite standalone one-part refs (e.g. USE DATABASE DB_A). Default: off (safer)."
|
|
20
|
+
).default(false)
|
|
21
|
+
).addOption(
|
|
22
|
+
new Option(
|
|
23
|
+
"--map-rewrite-strings",
|
|
24
|
+
"Phase 3: also rewrite FQN-shaped tokens inside string literals (best-effort, may produce false positives in legitimate string content). Default: off."
|
|
25
|
+
).default(false)
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
async function buildMappingFromOptions(opts) {
|
|
29
|
+
const flagMappings = Array.isArray(opts.map) ? opts.map : [];
|
|
30
|
+
let mapping = { entries: [] };
|
|
31
|
+
if (opts.mapFile) {
|
|
32
|
+
const raw = await fs.readFile(String(opts.mapFile), "utf8");
|
|
33
|
+
mapping = mappingFromFile(JSON.parse(raw));
|
|
34
|
+
}
|
|
35
|
+
if (flagMappings.length > 0) {
|
|
36
|
+
const fromArgs = mappingFromArgs(flagMappings);
|
|
37
|
+
mapping = { entries: [...mapping.entries, ...fromArgs.entries] };
|
|
38
|
+
}
|
|
39
|
+
if (mapping.entries.length === 0) return void 0;
|
|
40
|
+
if (opts.mapCaseSensitive) mapping.caseSensitive = true;
|
|
41
|
+
if (opts.mapRewriteStandalone) mapping.rewriteStandaloneRefs = true;
|
|
42
|
+
if (opts.mapRewriteStrings) mapping.rewriteInsideStrings = true;
|
|
43
|
+
return mapping;
|
|
44
|
+
}
|
|
45
|
+
function describeMapping(mapping) {
|
|
46
|
+
if (!mapping || mapping.entries.length === 0) return "";
|
|
47
|
+
return mapping.entries.map((e) => `${e.source}\u2192${e.target}`).join(", ");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export {
|
|
51
|
+
addMappingFlags,
|
|
52
|
+
buildMappingFromOptions,
|
|
53
|
+
describeMapping
|
|
54
|
+
};
|
|
55
|
+
//# sourceMappingURL=chunk-2FT6HXKS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/util/mapping.ts"],"sourcesContent":["import { promises as fs } from 'node:fs';\nimport { Option, type Command } from 'commander';\nimport { mappingFromArgs, mappingFromFile, type NameMapping } from '@ddt-tools/core';\n\nexport interface MappingOptions {\n map?: string[];\n mapFile?: string;\n mapCaseSensitive?: boolean;\n mapRewriteStandalone?: boolean;\n mapRewriteStrings?: boolean;\n}\n\n/** Attach `--map`, `--map-file`, `--map-case-sensitive`, `--map-rewrite-standalone`, `--map-rewrite-strings` to a command. */\nexport function addMappingFlags(cmd: Command): Command {\n return cmd\n .option(\n '--map <src=tgt>',\n 'Logical-name mapping (repeatable). Examples: DB_A=DB_B, DB_A.STAGING=DB_B.RAW. Rewrites source-side FQNs and DDL body refs.',\n (value: string, previous: string[]) => [...previous, value],\n [] as string[],\n )\n .option('--map-file <path>', 'JSON file of mappings.')\n .addOption(\n new Option(\n '--map-case-sensitive',\n 'Match identifiers case-sensitively. Default: insensitive.',\n ).default(false),\n )\n .addOption(\n new Option(\n '--map-rewrite-standalone',\n 'Rewrite standalone one-part refs (e.g. USE DATABASE DB_A). Default: off (safer).',\n ).default(false),\n )\n .addOption(\n new Option(\n '--map-rewrite-strings',\n 'Phase 3: also rewrite FQN-shaped tokens inside string literals (best-effort, may produce false positives in legitimate string content). Default: off.',\n ).default(false),\n );\n}\n\n/** Build a `NameMapping` from `--map`/`--map-file` flag values. Returns undefined when no mappings supplied. */\nexport async function buildMappingFromOptions(\n opts: MappingOptions,\n): Promise<NameMapping | undefined> {\n const flagMappings = Array.isArray(opts.map) ? opts.map : [];\n let mapping: NameMapping = { entries: [] };\n if (opts.mapFile) {\n const raw = await fs.readFile(String(opts.mapFile), 'utf8');\n mapping = mappingFromFile(JSON.parse(raw));\n }\n if (flagMappings.length > 0) {\n const fromArgs = mappingFromArgs(flagMappings);\n mapping = { entries: [...mapping.entries, ...fromArgs.entries] };\n }\n if (mapping.entries.length === 0) return undefined;\n if (opts.mapCaseSensitive) mapping.caseSensitive = true;\n if (opts.mapRewriteStandalone) mapping.rewriteStandaloneRefs = true;\n if (opts.mapRewriteStrings) mapping.rewriteInsideStrings = true;\n return mapping;\n}\n\n/** Render a one-line summary of a NameMapping for the operator's log output. */\nexport function describeMapping(mapping: NameMapping | undefined): string {\n if (!mapping || mapping.entries.length === 0) return '';\n return mapping.entries.map((e) => `${e.source}→${e.target}`).join(', ');\n}\n"],"mappings":";AAAA,SAAS,YAAY,UAAU;AAC/B,SAAS,cAA4B;AACrC,SAAS,iBAAiB,uBAAyC;AAW5D,SAAS,gBAAgB,KAAuB;AACrD,SAAO,IACJ;AAAA,IACC;AAAA,IACA;AAAA,IACA,CAAC,OAAe,aAAuB,CAAC,GAAG,UAAU,KAAK;AAAA,IAC1D,CAAC;AAAA,EACH,EACC,OAAO,qBAAqB,wBAAwB,EACpD;AAAA,IACC,IAAI;AAAA,MACF;AAAA,MACA;AAAA,IACF,EAAE,QAAQ,KAAK;AAAA,EACjB,EACC;AAAA,IACC,IAAI;AAAA,MACF;AAAA,MACA;AAAA,IACF,EAAE,QAAQ,KAAK;AAAA,EACjB,EACC;AAAA,IACC,IAAI;AAAA,MACF;AAAA,MACA;AAAA,IACF,EAAE,QAAQ,KAAK;AAAA,EACjB;AACJ;AAGA,eAAsB,wBACpB,MACkC;AAClC,QAAM,eAAe,MAAM,QAAQ,KAAK,GAAG,IAAI,KAAK,MAAM,CAAC;AAC3D,MAAI,UAAuB,EAAE,SAAS,CAAC,EAAE;AACzC,MAAI,KAAK,SAAS;AAChB,UAAM,MAAM,MAAM,GAAG,SAAS,OAAO,KAAK,OAAO,GAAG,MAAM;AAC1D,cAAU,gBAAgB,KAAK,MAAM,GAAG,CAAC;AAAA,EAC3C;AACA,MAAI,aAAa,SAAS,GAAG;AAC3B,UAAM,WAAW,gBAAgB,YAAY;AAC7C,cAAU,EAAE,SAAS,CAAC,GAAG,QAAQ,SAAS,GAAG,SAAS,OAAO,EAAE;AAAA,EACjE;AACA,MAAI,QAAQ,QAAQ,WAAW,EAAG,QAAO;AACzC,MAAI,KAAK,iBAAkB,SAAQ,gBAAgB;AACnD,MAAI,KAAK,qBAAsB,SAAQ,wBAAwB;AAC/D,MAAI,KAAK,kBAAmB,SAAQ,uBAAuB;AAC3D,SAAO;AACT;AAGO,SAAS,gBAAgB,SAA0C;AACxE,MAAI,CAAC,WAAW,QAAQ,QAAQ,WAAW,EAAG,QAAO;AACrD,SAAO,QAAQ,QAAQ,IAAI,CAAC,MAAM,GAAG,EAAE,MAAM,SAAI,EAAE,MAAM,EAAE,EAAE,KAAK,IAAI;AACxE;","names":[]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
export {
|
|
9
|
+
__require
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=chunk-DGUM43GV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// src/util/help-catalog.ts
|
|
2
|
+
import { DEPLOY_OPTIONS_CATALOG } from "@ddt-tools/core/options";
|
|
3
|
+
var CATALOG_BY_NAME = new Map(
|
|
4
|
+
DEPLOY_OPTIONS_CATALOG.map((entry) => [entry.name, entry])
|
|
5
|
+
);
|
|
6
|
+
function attachRelatedOptions(cmd, names) {
|
|
7
|
+
const entries = [];
|
|
8
|
+
for (const n of names) {
|
|
9
|
+
const e = CATALOG_BY_NAME.get(n);
|
|
10
|
+
if (e) entries.push(e);
|
|
11
|
+
}
|
|
12
|
+
if (entries.length === 0) return;
|
|
13
|
+
const maxName = entries.reduce((m, e) => Math.max(m, e.name.length), 0);
|
|
14
|
+
const lines = [
|
|
15
|
+
"",
|
|
16
|
+
"Related options (run `ddt explain <name>` for safety tier, default, and example):",
|
|
17
|
+
...entries.map((e) => ` ${e.name.padEnd(maxName)} ${e.summary}`)
|
|
18
|
+
];
|
|
19
|
+
cmd.addHelpText("after", lines.join("\n"));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export {
|
|
23
|
+
attachRelatedOptions
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=chunk-DL3V7UJ2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/util/help-catalog.ts"],"sourcesContent":["/**\n * Per-command --help enrichments — show 3-5 related catalog entries\n * under each command's help screen, with a one-line summary and a\n * pointer to `ddt explain <name>` for the full entry.\n *\n * Free-tier discoverability: a user who opens `ddt publish --help`\n * lands on a clear list of the deployment options that govern the\n * command's safety behaviour, without needing to know they exist or\n * read the project format reference first.\n *\n * Mirrors `Snowflake/packages/cli/src/util/help-catalog.ts`.\n */\nimport type { Command } from 'commander';\nimport { DEPLOY_OPTIONS_CATALOG, type OptionEntry } from '@ddt-tools/core/options';\n\nconst CATALOG_BY_NAME: Map<string, OptionEntry> = new Map(\n DEPLOY_OPTIONS_CATALOG.map((entry) => [entry.name, entry]),\n);\n\n/**\n * Attach an \"After\" help block listing the named catalog entries with\n * one-line summaries. Unknown keys are silently skipped so a stale\n * mapping never breaks --help.\n */\nexport function attachRelatedOptions(cmd: Command, names: readonly string[]): void {\n const entries: OptionEntry[] = [];\n for (const n of names) {\n const e = CATALOG_BY_NAME.get(n);\n if (e) entries.push(e);\n }\n if (entries.length === 0) return;\n const maxName = entries.reduce((m, e) => Math.max(m, e.name.length), 0);\n const lines = [\n '',\n 'Related options (run `ddt explain <name>` for safety tier, default, and example):',\n ...entries.map((e) => ` ${e.name.padEnd(maxName)} ${e.summary}`),\n ];\n cmd.addHelpText('after', lines.join('\\n'));\n}\n"],"mappings":";AAaA,SAAS,8BAAgD;AAEzD,IAAM,kBAA4C,IAAI;AAAA,EACpD,uBAAuB,IAAI,CAAC,UAAU,CAAC,MAAM,MAAM,KAAK,CAAC;AAC3D;AAOO,SAAS,qBAAqB,KAAc,OAAgC;AACjF,QAAM,UAAyB,CAAC;AAChC,aAAW,KAAK,OAAO;AACrB,UAAM,IAAI,gBAAgB,IAAI,CAAC;AAC/B,QAAI,EAAG,SAAQ,KAAK,CAAC;AAAA,EACvB;AACA,MAAI,QAAQ,WAAW,EAAG;AAC1B,QAAM,UAAU,QAAQ,OAAO,CAAC,GAAG,MAAM,KAAK,IAAI,GAAG,EAAE,KAAK,MAAM,GAAG,CAAC;AACtE,QAAM,QAAQ;AAAA,IACZ;AAAA,IACA;AAAA,IACA,GAAG,QAAQ,IAAI,CAAC,MAAM,KAAK,EAAE,KAAK,OAAO,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE;AAAA,EACnE;AACA,MAAI,YAAY,SAAS,MAAM,KAAK,IAAI,CAAC;AAC3C;","names":[]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// src/util/logger.ts
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
var logger = {
|
|
4
|
+
info: (msg) => console.log(msg),
|
|
5
|
+
success: (msg) => console.log(chalk.green("\u2714"), msg),
|
|
6
|
+
warn: (msg) => console.warn(chalk.yellow("!"), msg),
|
|
7
|
+
error: (msg) => console.error(chalk.red("\u2716"), msg),
|
|
8
|
+
step: (msg) => console.log(chalk.cyan("\u2192"), msg),
|
|
9
|
+
dim: (msg) => console.log(chalk.gray(msg))
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export {
|
|
13
|
+
logger
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=chunk-VM2H4LAO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/util/logger.ts"],"sourcesContent":["/**\n * Minimal logger used by the CLI. Wraps chalk/ora so a future move to a\n * non-tty mode is centralised.\n */\nimport chalk from 'chalk';\n\nexport const logger = {\n info: (msg: string) => console.log(msg),\n success: (msg: string) => console.log(chalk.green('✔'), msg),\n warn: (msg: string) => console.warn(chalk.yellow('!'), msg),\n error: (msg: string) => console.error(chalk.red('✖'), msg),\n step: (msg: string) => console.log(chalk.cyan('→'), msg),\n dim: (msg: string) => console.log(chalk.gray(msg)),\n};\n"],"mappings":";AAIA,OAAO,WAAW;AAEX,IAAM,SAAS;AAAA,EACpB,MAAM,CAAC,QAAgB,QAAQ,IAAI,GAAG;AAAA,EACtC,SAAS,CAAC,QAAgB,QAAQ,IAAI,MAAM,MAAM,QAAG,GAAG,GAAG;AAAA,EAC3D,MAAM,CAAC,QAAgB,QAAQ,KAAK,MAAM,OAAO,GAAG,GAAG,GAAG;AAAA,EAC1D,OAAO,CAAC,QAAgB,QAAQ,MAAM,MAAM,IAAI,QAAG,GAAG,GAAG;AAAA,EACzD,MAAM,CAAC,QAAgB,QAAQ,IAAI,MAAM,KAAK,QAAG,GAAG,GAAG;AAAA,EACvD,KAAK,CAAC,QAAgB,QAAQ,IAAI,MAAM,KAAK,GAAG,CAAC;AACnD;","names":[]}
|