@ingestron/cli 0.0.0-stage → 1.0.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/NOTICE +4 -0
- package/README.md +44 -2
- package/dist/args.d.ts +105 -0
- package/dist/args.d.ts.map +1 -0
- package/dist/args.js +161 -0
- package/dist/args.js.map +1 -0
- package/dist/ask.d.ts +5 -0
- package/dist/ask.d.ts.map +1 -0
- package/dist/ask.js +17 -0
- package/dist/ask.js.map +1 -0
- package/dist/compare.d.ts +13 -0
- package/dist/compare.d.ts.map +1 -0
- package/dist/compare.js +90 -0
- package/dist/compare.js.map +1 -0
- package/dist/environments.d.ts +6 -0
- package/dist/environments.d.ts.map +1 -0
- package/dist/environments.js +25 -0
- package/dist/environments.js.map +1 -0
- package/dist/generate.d.ts +16 -0
- package/dist/generate.d.ts.map +1 -0
- package/dist/generate.js +118 -0
- package/dist/generate.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +46 -0
- package/dist/index.js.map +1 -0
- package/dist/init-choice.d.ts +10 -0
- package/dist/init-choice.d.ts.map +1 -0
- package/dist/init-choice.js +36 -0
- package/dist/init-choice.js.map +1 -0
- package/dist/init-preflight.d.ts +4 -0
- package/dist/init-preflight.d.ts.map +1 -0
- package/dist/init-preflight.js +18 -0
- package/dist/init-preflight.js.map +1 -0
- package/dist/init.d.ts +5 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +136 -0
- package/dist/init.js.map +1 -0
- package/dist/io.d.ts +8 -0
- package/dist/io.d.ts.map +1 -0
- package/dist/io.js +3 -0
- package/dist/io.js.map +1 -0
- package/dist/main.d.ts +3 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +11 -0
- package/dist/main.js.map +1 -0
- package/dist/outputs.d.ts +12 -0
- package/dist/outputs.d.ts.map +1 -0
- package/dist/outputs.js +53 -0
- package/dist/outputs.js.map +1 -0
- package/dist/packs.d.ts +4 -0
- package/dist/packs.d.ts.map +1 -0
- package/dist/packs.js +5 -0
- package/dist/packs.js.map +1 -0
- package/dist/project-choices.d.ts +27 -0
- package/dist/project-choices.d.ts.map +1 -0
- package/dist/project-choices.js +44 -0
- package/dist/project-choices.js.map +1 -0
- package/dist/project-questions.d.ts +5 -0
- package/dist/project-questions.d.ts.map +1 -0
- package/dist/project-questions.js +43 -0
- package/dist/project-questions.js.map +1 -0
- package/dist/project-recipes.d.ts +14 -0
- package/dist/project-recipes.d.ts.map +1 -0
- package/dist/project-recipes.js +115 -0
- package/dist/project-recipes.js.map +1 -0
- package/dist/request.d.ts +13 -0
- package/dist/request.d.ts.map +1 -0
- package/dist/request.js +110 -0
- package/dist/request.js.map +1 -0
- package/dist/sample-contract.d.ts +11 -0
- package/dist/sample-contract.d.ts.map +1 -0
- package/dist/sample-contract.js +91 -0
- package/dist/sample-contract.js.map +1 -0
- package/dist/sample-read.d.ts +8 -0
- package/dist/sample-read.d.ts.map +1 -0
- package/dist/sample-read.js +89 -0
- package/dist/sample-read.js.map +1 -0
- package/dist/samples.d.ts +33 -0
- package/dist/samples.d.ts.map +1 -0
- package/dist/samples.js +108 -0
- package/dist/samples.js.map +1 -0
- package/dist/scaffold.d.ts +34 -0
- package/dist/scaffold.d.ts.map +1 -0
- package/dist/scaffold.js +106 -0
- package/dist/scaffold.js.map +1 -0
- package/dist/schemas.d.ts +5 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/schemas.js +39 -0
- package/dist/schemas.js.map +1 -0
- package/dist/sources.d.ts +17 -0
- package/dist/sources.d.ts.map +1 -0
- package/dist/sources.js +103 -0
- package/dist/sources.js.map +1 -0
- package/dist/templates.d.ts +64 -0
- package/dist/templates.d.ts.map +1 -0
- package/dist/templates.js +88 -0
- package/dist/templates.js.map +1 -0
- package/package.json +68 -3
- package/project-templates/kafka/README.md +12 -0
- package/project-templates/kafka/connections/events.yaml +8 -0
- package/project-templates/kafka/contracts/page_views.yaml +13 -0
- package/project-templates/kafka/contracts/purchases.yaml +13 -0
- package/project-templates/kafka/flows/events.yaml +10 -0
- package/project-templates/kafka/project.yaml +10 -0
- package/project-templates/kafka/standard.yaml +4 -0
- package/project-templates/kafka/template.yaml +3 -0
- package/project-templates/minimal/README.md +10 -0
- package/project-templates/minimal/connections/shop.yaml +7 -0
- package/project-templates/minimal/contracts/orders.yaml +14 -0
- package/project-templates/minimal/flows/orders.yaml +6 -0
- package/project-templates/minimal/project.yaml +11 -0
- package/project-templates/minimal/standard.yaml +4 -0
- package/project-templates/minimal/template.yaml +7 -0
- package/project-templates/private-files/README.md +29 -0
- package/project-templates/private-files/connections/share.yaml +10 -0
- package/project-templates/private-files/contracts/sales.yaml +14 -0
- package/project-templates/private-files/contracts/stock.yaml +14 -0
- package/project-templates/private-files/flows/stores.yaml +9 -0
- package/project-templates/private-files/platform.yaml +11 -0
- package/project-templates/private-files/project.yaml +19 -0
- package/project-templates/private-files/standard.yaml +11 -0
- package/project-templates/private-files/template.yaml +10 -0
- package/project-templates/private-sql-server/README.md +25 -0
- package/project-templates/private-sql-server/connections/erp.yaml +10 -0
- package/project-templates/private-sql-server/contracts/customers.yaml +14 -0
- package/project-templates/private-sql-server/contracts/invoices.yaml +15 -0
- package/project-templates/private-sql-server/flows/erp.yaml +13 -0
- package/project-templates/private-sql-server/platform.yaml +11 -0
- package/project-templates/private-sql-server/project.yaml +19 -0
- package/project-templates/private-sql-server/standard.yaml +17 -0
- package/project-templates/private-sql-server/template.yaml +10 -0
- package/project-templates/pyspark/README.md +12 -0
- package/project-templates/pyspark/connections/billing.yaml +7 -0
- package/project-templates/pyspark/contracts/invoices.yaml +16 -0
- package/project-templates/pyspark/contracts/monthly_revenue.yaml +14 -0
- package/project-templates/pyspark/flows/billing.yaml +6 -0
- package/project-templates/pyspark/project.yaml +11 -0
- package/project-templates/pyspark/standard.yaml +4 -0
- package/project-templates/pyspark/template.yaml +3 -0
- package/project-templates/pyspark/transforms/monthly_revenue.py +10 -0
- package/project-templates/pyspark/transforms/monthly_revenue.yaml +10 -0
- package/project-templates/retail/README.md +22 -0
- package/project-templates/retail/connections/shop.yaml +8 -0
- package/project-templates/retail/contracts/customers.yaml +12 -0
- package/project-templates/retail/contracts/daily_sales.yaml +19 -0
- package/project-templates/retail/contracts/orders.yaml +16 -0
- package/project-templates/retail/flows/shop.yaml +18 -0
- package/project-templates/retail/platform.yaml +21 -0
- package/project-templates/retail/project.yaml +18 -0
- package/project-templates/retail/standard.yaml +15 -0
- package/project-templates/retail/template.yaml +10 -0
- package/project-templates/retail/transforms/daily_sales.sql +7 -0
- package/project-templates/retail/transforms/daily_sales.yaml +7 -0
- package/project-templates/salesforce/README.md +6 -0
- package/project-templates/salesforce/connections/salesforce.yaml +7 -0
- package/project-templates/salesforce/contracts/accounts.yaml +13 -0
- package/project-templates/salesforce/contracts/opportunities.yaml +14 -0
- package/project-templates/salesforce/flows/salesforce.yaml +7 -0
- package/project-templates/salesforce/project.yaml +9 -0
- package/project-templates/salesforce/standard.yaml +4 -0
- package/project-templates/salesforce/template.yaml +3 -0
- package/project-templates/sql-server/README.md +17 -0
- package/project-templates/sql-server/connections/erp.yaml +8 -0
- package/project-templates/sql-server/contracts/customer_balances.yaml +13 -0
- package/project-templates/sql-server/contracts/customers.yaml +13 -0
- package/project-templates/sql-server/contracts/invoices.yaml +14 -0
- package/project-templates/sql-server/flows/erp.yaml +13 -0
- package/project-templates/sql-server/platform.yaml +6 -0
- package/project-templates/sql-server/project.yaml +13 -0
- package/project-templates/sql-server/standard.yaml +9 -0
- package/project-templates/sql-server/template.yaml +3 -0
- package/project-templates/sql-server/transforms/customer_balances.sql +5 -0
- package/project-templates/sql-server/transforms/customer_balances.yaml +6 -0
package/dist/sources.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// Where templates and standards come from: a built-in name, a folder, or a
|
|
2
|
+
// Git URL cloned with the user's own git. Nothing from a source is run.
|
|
3
|
+
import { execFileSync } from "node:child_process";
|
|
4
|
+
import { existsSync, lstatSync, mkdtempSync, realpathSync, rmSync } from "node:fs";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import { basename, join, relative, resolve } from "node:path";
|
|
7
|
+
import { builtInTemplates, readTemplate } from "./templates.js";
|
|
8
|
+
/** The URL without `user:password@`, for messages and the standard's "From" line. */
|
|
9
|
+
export function withoutCredentials(text) {
|
|
10
|
+
return text.replace(/(\/\/)[^/@\s]+@/g, "$1");
|
|
11
|
+
}
|
|
12
|
+
/** Sources come from the user's command line; one starting with "-" could pass for a git option. */
|
|
13
|
+
function refuseOption(spec) {
|
|
14
|
+
if (spec.startsWith("-"))
|
|
15
|
+
throw new Error(`A template or standard cannot start with "-": ${spec}.`);
|
|
16
|
+
}
|
|
17
|
+
/** A Git URL rather than a path or a name. */
|
|
18
|
+
export function isGitUrl(spec) {
|
|
19
|
+
return (/^(https?|ssh|file|git):\/\//.test(spec) ||
|
|
20
|
+
/^[\w.-]+@[\w.-]+:/.test(spec) ||
|
|
21
|
+
/\.git(#|$)/.test(spec));
|
|
22
|
+
}
|
|
23
|
+
/** A template from a built-in name, a folder or a Git URL (`#` names a sub-folder). Call `done()` when finished. */
|
|
24
|
+
export function templateSource(spec, cwd) {
|
|
25
|
+
refuseOption(spec);
|
|
26
|
+
if (isGitUrl(spec)) {
|
|
27
|
+
const { path, done } = cloned(spec, "folder");
|
|
28
|
+
try {
|
|
29
|
+
return { template: readTemplate(path, basename(path)), done };
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
done();
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const folder = resolve(cwd, spec);
|
|
37
|
+
if (spec.includes("/") || spec.startsWith(".")) {
|
|
38
|
+
if (!existsSync(folder))
|
|
39
|
+
throw new Error(`No template folder ${spec}.`);
|
|
40
|
+
return { template: readTemplate(folder, basename(folder)), done: () => undefined };
|
|
41
|
+
}
|
|
42
|
+
const builtIns = builtInTemplates();
|
|
43
|
+
const template = builtIns.find((item) => item.name === spec);
|
|
44
|
+
if (!template) {
|
|
45
|
+
const names = builtIns.map((item) => item.name).join(", ");
|
|
46
|
+
throw new Error(`No template "${spec}". Built-in templates: ${names}.`);
|
|
47
|
+
}
|
|
48
|
+
return { template, done: () => undefined };
|
|
49
|
+
}
|
|
50
|
+
/** A standard file from a path or a Git URL with `#path/to/standard.yaml`. */
|
|
51
|
+
export function standardSource(spec, cwd) {
|
|
52
|
+
if (!isGitUrl(spec)) {
|
|
53
|
+
const file = resolve(cwd, spec);
|
|
54
|
+
if (!existsSync(file))
|
|
55
|
+
throw new Error(`No standard file ${spec}.`);
|
|
56
|
+
return { file, source: spec, done: () => undefined };
|
|
57
|
+
}
|
|
58
|
+
const { path, done } = cloned(spec, "file");
|
|
59
|
+
return { file: path, source: withoutCredentials(spec), done };
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Clones the URL before `#` into a temporary folder and returns the entry
|
|
63
|
+
* after `#`, which must really be inside the clone (no links) and be a
|
|
64
|
+
* regular file or folder as asked.
|
|
65
|
+
*/
|
|
66
|
+
function cloned(spec, kind) {
|
|
67
|
+
const [url = "", inside = ""] = spec.split("#");
|
|
68
|
+
if (inside.split("/").includes("..") || inside.startsWith("/"))
|
|
69
|
+
throw new Error(`The part after "#" must stay inside the repository: ${inside}.`);
|
|
70
|
+
const folder = mkdtempSync(join(tmpdir(), "ingestron-template-"));
|
|
71
|
+
const done = () => rmSync(folder, { recursive: true, force: true });
|
|
72
|
+
try {
|
|
73
|
+
clone(url, folder);
|
|
74
|
+
return { path: checkedEntry(folder, inside, kind), done };
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
done();
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function clone(url, folder) {
|
|
82
|
+
// No hooks, no submodules; "--" so the URL can never be read as an option.
|
|
83
|
+
const args = ["-c", "core.hooksPath=/dev/null", "clone", "--depth", "1", "--quiet"];
|
|
84
|
+
try {
|
|
85
|
+
execFileSync("git", [...args, "--no-recurse-submodules", "--", url, folder], { stdio: "pipe" });
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
const reason = error.stderr?.toString().trim() ?? String(error);
|
|
89
|
+
throw new Error(withoutCredentials(`Could not clone ${url}: ${reason}`));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function checkedEntry(folder, inside, kind) {
|
|
93
|
+
const path = join(folder, inside);
|
|
94
|
+
const stat = lstatSync(path, { throwIfNoEntry: false });
|
|
95
|
+
if (!stat)
|
|
96
|
+
throw new Error(`The repository has no "${inside}".`);
|
|
97
|
+
const real = relative(realpathSync(folder), realpathSync(path));
|
|
98
|
+
const isKind = kind === "file" ? stat.isFile() : stat.isDirectory();
|
|
99
|
+
if (!isKind || real.startsWith(".."))
|
|
100
|
+
throw new Error(`"${inside || "."}" in the repository is not a ${kind === "file" ? "regular file" : "folder"}.`);
|
|
101
|
+
return path;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=sources.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sources.js","sourceRoot":"","sources":["../src/sources.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/** One question; the answer becomes `values.<value>` in project.yaml. */
|
|
2
|
+
export interface Question {
|
|
3
|
+
value: string;
|
|
4
|
+
ask: string;
|
|
5
|
+
default: string;
|
|
6
|
+
}
|
|
7
|
+
/** A template folder and what it asks. */
|
|
8
|
+
export interface Template {
|
|
9
|
+
name: string;
|
|
10
|
+
folder: string;
|
|
11
|
+
title: string;
|
|
12
|
+
summary: string;
|
|
13
|
+
questions: Question[];
|
|
14
|
+
}
|
|
15
|
+
/** template.yaml's schema, for editors; `readTemplate` checks the same rules. */
|
|
16
|
+
export declare const templateSchema: {
|
|
17
|
+
title: string;
|
|
18
|
+
type: string;
|
|
19
|
+
additionalProperties: boolean;
|
|
20
|
+
required: string[];
|
|
21
|
+
properties: {
|
|
22
|
+
title: {
|
|
23
|
+
type: string;
|
|
24
|
+
description: string;
|
|
25
|
+
};
|
|
26
|
+
summary: {
|
|
27
|
+
type: string;
|
|
28
|
+
description: string;
|
|
29
|
+
};
|
|
30
|
+
questions: {
|
|
31
|
+
type: string;
|
|
32
|
+
description: string;
|
|
33
|
+
items: {
|
|
34
|
+
type: string;
|
|
35
|
+
additionalProperties: boolean;
|
|
36
|
+
required: string[];
|
|
37
|
+
properties: {
|
|
38
|
+
value: {
|
|
39
|
+
type: string;
|
|
40
|
+
pattern: string;
|
|
41
|
+
description: string;
|
|
42
|
+
};
|
|
43
|
+
ask: {
|
|
44
|
+
type: string;
|
|
45
|
+
description: string;
|
|
46
|
+
};
|
|
47
|
+
default: {
|
|
48
|
+
type: string;
|
|
49
|
+
description: string;
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
/** Where this package's built-ins are. */
|
|
57
|
+
export declare const builtInFolder: string;
|
|
58
|
+
/** Built-in templates: the starters, each named by its folder. */
|
|
59
|
+
export declare function builtInTemplates(): Template[];
|
|
60
|
+
/** Reads and checks `<folder>/template.yaml`; throws an Error with the reason. */
|
|
61
|
+
export declare function readTemplate(folder: string, name: string): Template;
|
|
62
|
+
/** Checks template.yaml's text; throws an Error with the reason. */
|
|
63
|
+
export declare function parseTemplate(text: string, name: string, folder: string): Template;
|
|
64
|
+
//# sourceMappingURL=templates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../src/templates.ts"],"names":[],"mappings":"AAOA,yEAAyE;AACzE,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,0CAA0C;AAC1C,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,QAAQ,EAAE,CAAC;CACvB;AAED,iFAAiF;AACjF,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+B1B,CAAC;AAEF,0CAA0C;AAC1C,eAAO,MAAM,aAAa,QAAkB,CAAC;AAE7C,kEAAkE;AAClE,wBAAgB,gBAAgB,IAAI,QAAQ,EAAE,CAM7C;AAED,kFAAkF;AAClF,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,CAOnE;AAED,oEAAoE;AACpE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,QAAQ,CAalF"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// Project templates: an ordinary project folder plus template.yaml, which
|
|
2
|
+
// says what to ask. Built-in templates are the samples' starters.
|
|
3
|
+
import { existsSync, lstatSync, readdirSync, readFileSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { parse } from "yaml";
|
|
6
|
+
import { templatesFolder } from "./samples.js";
|
|
7
|
+
/** template.yaml's schema, for editors; `readTemplate` checks the same rules. */
|
|
8
|
+
export const templateSchema = {
|
|
9
|
+
title: "Ingestron template",
|
|
10
|
+
type: "object",
|
|
11
|
+
additionalProperties: false,
|
|
12
|
+
required: ["title", "summary"],
|
|
13
|
+
properties: {
|
|
14
|
+
title: { type: "string", description: "The template's name, as `ingestron init` lists it." },
|
|
15
|
+
summary: { type: "string", description: "One sentence on what the template sets up." },
|
|
16
|
+
questions: {
|
|
17
|
+
type: "array",
|
|
18
|
+
description: "What `ingestron init` asks; each answer becomes values.<value> in project.yaml.",
|
|
19
|
+
items: {
|
|
20
|
+
type: "object",
|
|
21
|
+
additionalProperties: false,
|
|
22
|
+
required: ["value", "ask", "default"],
|
|
23
|
+
properties: {
|
|
24
|
+
value: {
|
|
25
|
+
type: "string",
|
|
26
|
+
pattern: "^[a-z_][a-z0-9_]*$",
|
|
27
|
+
description: "The key in project.yaml values.",
|
|
28
|
+
},
|
|
29
|
+
ask: { type: "string", description: "The question, as the user sees it." },
|
|
30
|
+
default: {
|
|
31
|
+
type: "string",
|
|
32
|
+
description: "The answer used with --yes or an empty answer.",
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
/** Where this package's built-ins are. */
|
|
40
|
+
export const builtInFolder = templatesFolder;
|
|
41
|
+
/** Built-in templates: the starters, each named by its folder. */
|
|
42
|
+
export function builtInTemplates() {
|
|
43
|
+
return readdirSync(builtInFolder, { withFileTypes: true })
|
|
44
|
+
.filter((entry) => entry.isDirectory())
|
|
45
|
+
.filter((entry) => existsSync(join(builtInFolder, entry.name, "template.yaml")))
|
|
46
|
+
.map((entry) => readTemplate(join(builtInFolder, entry.name), entry.name))
|
|
47
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
48
|
+
}
|
|
49
|
+
/** Reads and checks `<folder>/template.yaml`; throws an Error with the reason. */
|
|
50
|
+
export function readTemplate(folder, name) {
|
|
51
|
+
for (const required of ["template.yaml", "project.yaml"]) {
|
|
52
|
+
const stat = lstatSync(join(folder, required), { throwIfNoEntry: false });
|
|
53
|
+
if (!stat)
|
|
54
|
+
throw new Error(`Template "${name}" has no ${required}.`);
|
|
55
|
+
if (!stat.isFile())
|
|
56
|
+
throw new Error(`Template "${name}": ${required} is not a regular file.`);
|
|
57
|
+
}
|
|
58
|
+
return parseTemplate(readFileSync(join(folder, "template.yaml"), "utf8"), name, folder);
|
|
59
|
+
}
|
|
60
|
+
/** Checks template.yaml's text; throws an Error with the reason. */
|
|
61
|
+
export function parseTemplate(text, name, folder) {
|
|
62
|
+
const data = parse(text);
|
|
63
|
+
const unknown = Object.keys(data ?? {}).find((key) => !["title", "summary", "questions"].includes(key));
|
|
64
|
+
if (unknown)
|
|
65
|
+
throw new Error(`template.yaml: unknown key "${unknown}".`);
|
|
66
|
+
return {
|
|
67
|
+
name,
|
|
68
|
+
folder,
|
|
69
|
+
title: String(data.title ?? name),
|
|
70
|
+
summary: String(data.summary ?? ""),
|
|
71
|
+
questions: questionsOf(data.questions),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function questionsOf(value) {
|
|
75
|
+
if (value === undefined)
|
|
76
|
+
return [];
|
|
77
|
+
if (!Array.isArray(value))
|
|
78
|
+
throw new Error("template.yaml: questions must be a list.");
|
|
79
|
+
return value.map((item, index) => {
|
|
80
|
+
const keys = ["value", "ask", "default"];
|
|
81
|
+
if (!keys.every((key) => typeof item?.[key] === "string"))
|
|
82
|
+
throw new Error(`template.yaml: question ${index + 1} needs "value", "ask" and "default".`);
|
|
83
|
+
if (!/^[a-z_][a-z0-9_]*$/.test(String(item.value)))
|
|
84
|
+
throw new Error(`template.yaml: question ${index + 1}'s value "${String(item.value)}" is not a valid name.`);
|
|
85
|
+
return { value: String(item.value), ask: String(item.ask), default: String(item.default) };
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=templates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../src/templates.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,71 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ingestron/cli",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "ingestron plan | apply | check | schemas: generate platform assets from definitions.",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"author": "IntentLabs <hello@ingestron.io>",
|
|
7
|
+
"homepage": "https://docs.ingestron.io",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/ingestron/ingestron.git",
|
|
11
|
+
"directory": "packages/cli"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/ingestron/ingestron/issues",
|
|
15
|
+
"email": "hello@ingestron.io"
|
|
16
|
+
},
|
|
17
|
+
"type": "module",
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=22.13.0"
|
|
20
|
+
},
|
|
21
|
+
"bin": {
|
|
22
|
+
"ingestron": "./dist/main.js"
|
|
23
|
+
},
|
|
24
|
+
"exports": {
|
|
25
|
+
".": {
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"import": "./dist/index.js"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist",
|
|
32
|
+
"README.md",
|
|
33
|
+
"project-templates",
|
|
34
|
+
"NOTICE"
|
|
35
|
+
],
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@ingestron/pack-adf": "^1.0.0",
|
|
38
|
+
"@ingestron/pack-databricks": "^1.0.0",
|
|
39
|
+
"yaml": "2.9.1",
|
|
40
|
+
"@ingestron/config": "1.0.0",
|
|
41
|
+
"@ingestron/definitions": "1.0.0",
|
|
42
|
+
"@ingestron/generate": "1.0.0"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@microsoft/api-extractor": "7.59.4",
|
|
46
|
+
"@types/node": "22.20.5",
|
|
47
|
+
"ajv": "8.20.0",
|
|
48
|
+
"eslint": "10.13.0",
|
|
49
|
+
"eslint-plugin-jsdoc": "65.4.2",
|
|
50
|
+
"tsx": "4.23.15",
|
|
51
|
+
"typescript": "6.0.3",
|
|
52
|
+
"typescript-eslint": "8.72.0",
|
|
53
|
+
"vitest": "5.0.5",
|
|
54
|
+
"vscode-languageserver-textdocument": "1.0.12",
|
|
55
|
+
"yaml-language-server": "1.25.0"
|
|
56
|
+
},
|
|
57
|
+
"publishConfig": {
|
|
58
|
+
"access": "public"
|
|
59
|
+
},
|
|
60
|
+
"scripts": {
|
|
61
|
+
"build": "tsc -p tsconfig.build.json",
|
|
62
|
+
"typecheck": "pnpm build && tsc -p tsconfig.json --noEmit",
|
|
63
|
+
"lint": "eslint .",
|
|
64
|
+
"test": "vitest run",
|
|
65
|
+
"check:docs": "tsx scripts/check-docs.ts",
|
|
66
|
+
"validate": "pnpm lint && pnpm typecheck && pnpm test && pnpm check:docs && pnpm check:api",
|
|
67
|
+
"check:bundle": "tsx scripts/check-bundle-schema.ts",
|
|
68
|
+
"api": "api-extractor run --local",
|
|
69
|
+
"check:api": "api-extractor run"
|
|
70
|
+
}
|
|
6
71
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Kafka
|
|
2
|
+
|
|
3
|
+
Two topics of an Event Hubs namespace, read through its Kafka endpoint.
|
|
4
|
+
[The ingestion pipeline](build/dev/resources/clickstream_events_ingestion.pipeline.yml)
|
|
5
|
+
runs on the `PREVIEW` channel, appends every message, and parses JSON values
|
|
6
|
+
with the contract's column types. In production it runs continuously; in
|
|
7
|
+
`dev` it runs when started (`databricks bundle run`), which costs less. Set
|
|
8
|
+
`continuous: true` to change that. The pack chose `mode: append`
|
|
9
|
+
for Kafka by its own rule.
|
|
10
|
+
|
|
11
|
+
Lakeflow Connect for Kafka is in Beta on Databricks (checked 2026-10-25); the
|
|
12
|
+
generated file says so.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
apiVersion: v3.1.0
|
|
2
|
+
kind: DataContract
|
|
3
|
+
id: web.page_views
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
status: active
|
|
6
|
+
schema:
|
|
7
|
+
- name: page_views
|
|
8
|
+
logicalType: object
|
|
9
|
+
description: One event per page view.
|
|
10
|
+
properties:
|
|
11
|
+
- { name: session_id, logicalType: string, required: true }
|
|
12
|
+
- { name: url, logicalType: string }
|
|
13
|
+
- { name: viewed_at, logicalType: timestamp }
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
apiVersion: v3.1.0
|
|
2
|
+
kind: DataContract
|
|
3
|
+
id: web.purchases
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
status: active
|
|
6
|
+
schema:
|
|
7
|
+
- name: purchases
|
|
8
|
+
logicalType: object
|
|
9
|
+
description: One event per purchase.
|
|
10
|
+
properties:
|
|
11
|
+
- { name: order_id, logicalType: string, required: true }
|
|
12
|
+
- { name: amount, logicalType: number, physicalType: "DECIMAL(18,2)" }
|
|
13
|
+
- { name: purchased_at, logicalType: timestamp }
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
apiVersion: ingestron.io/v1
|
|
2
|
+
kind: Flow
|
|
3
|
+
id: events
|
|
4
|
+
source: events
|
|
5
|
+
ingest:
|
|
6
|
+
# Keep append explicit when this flow is composed with a chosen ingestion method.
|
|
7
|
+
with: { starting_offset: earliest, mode: append }
|
|
8
|
+
tables:
|
|
9
|
+
page_views: { object: web.page-views, contract: web.page_views }
|
|
10
|
+
purchases: { object: web.purchases, contract: web.purchases }
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Minimal
|
|
2
|
+
|
|
3
|
+
The standard only names the pack, so every choice is a pack default.
|
|
4
|
+
|
|
5
|
+
| Definition | Becomes |
|
|
6
|
+
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
7
|
+
| `flows/orders.yaml` | [a streaming table](build/dev/src/shop/bronze/orders.sql) reading new files once each |
|
|
8
|
+
| `contracts/orders.yaml` | `schemaHints` from the column types, `COMMENT`, and a not-null check on the required `id` |
|
|
9
|
+
| pack defaults | catalog `dev` (the environment), schema `bronze` (the first layer), `CLUSTER BY AUTO`, parquet |
|
|
10
|
+
| `project.yaml` | [a bundle](build/dev/databricks.yml) with one `dev` target in development mode, and [a serverless pipeline](build/dev/resources/shop.pipeline.yml) |
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
apiVersion: v3.1.0
|
|
2
|
+
kind: DataContract
|
|
3
|
+
id: shop.orders
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
status: active
|
|
6
|
+
schema:
|
|
7
|
+
- name: orders
|
|
8
|
+
logicalType: object
|
|
9
|
+
description: One row per order.
|
|
10
|
+
properties:
|
|
11
|
+
- { name: id, logicalType: integer, required: true, primaryKey: true }
|
|
12
|
+
- { name: customer_id, logicalType: integer }
|
|
13
|
+
- { name: total, logicalType: number, physicalType: "DECIMAL(18,2)" }
|
|
14
|
+
- { name: ordered_at, logicalType: timestamp }
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# The smallest project: everything not written here comes from the pack's defaults.
|
|
2
|
+
id: shop
|
|
3
|
+
values:
|
|
4
|
+
landing: /Volumes/dev/landing/shop
|
|
5
|
+
environments:
|
|
6
|
+
dev: {}
|
|
7
|
+
imports:
|
|
8
|
+
- standard.yaml
|
|
9
|
+
- connections/*.yaml
|
|
10
|
+
- flows/*.yaml
|
|
11
|
+
- contracts/*.yaml
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Used by `ingestron init --template minimal`.
|
|
2
|
+
title: Minimal project
|
|
3
|
+
summary: "Pack defaults only: an Auto Loader streaming table with schema hints and clustering."
|
|
4
|
+
questions:
|
|
5
|
+
- value: landing
|
|
6
|
+
ask: "Where do the source files land?"
|
|
7
|
+
default: /Volumes/dev/landing/shop
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Private file share
|
|
2
|
+
|
|
3
|
+
Each store exports its sales and stock as CSV files to a share inside the
|
|
4
|
+
corporate network, `\\fs01\exports`, which the workspace cannot reach
|
|
5
|
+
(`connectivity: private`). The standard uses two packs,
|
|
6
|
+
`[databricks@1, adf@1]`. Databricks' `files` method cannot reach a private
|
|
7
|
+
source, so the ADF pack's rule chooses `adf-files`:
|
|
8
|
+
|
|
9
|
+
- **ADF** ([build/prod/adf](build/prod/adf/)), in the folder layout ADF
|
|
10
|
+
keeps in Git:
|
|
11
|
+
- a [file server linked service](build/prod/adf/linkedService/ls_stores_share.json)
|
|
12
|
+
through the self-hosted integration runtime `shir-stores`, with the
|
|
13
|
+
password from Key Vault;
|
|
14
|
+
- a [pipeline](build/prod/adf/pipeline/pl_stores_share.json) with one
|
|
15
|
+
binary copy per table: the files changed in the window, from
|
|
16
|
+
`\\fs01\exports\sales` to `<landing>/sales/`, keeping their names and
|
|
17
|
+
folders;
|
|
18
|
+
- an hourly [tumbling window trigger](build/prod/adf/trigger/tr_stores_share.json),
|
|
19
|
+
started in production and stopped elsewhere.
|
|
20
|
+
- **Databricks** ([build/prod/databricks](build/prod/databricks/)): streaming
|
|
21
|
+
tables that read the landing folders with Auto Loader, as CSV with a
|
|
22
|
+
header, typed by the contracts' columns.
|
|
23
|
+
|
|
24
|
+
The files are copied as they are, so the flow says their format
|
|
25
|
+
(`format: csv`). To copy every file each window instead of the changed ones,
|
|
26
|
+
set `mode: all`; to copy only some, set `files`, such as `"*.csv"`.
|
|
27
|
+
|
|
28
|
+
The integration runtime and Key Vault are shared infrastructure: they must
|
|
29
|
+
exist and are only referenced.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
apiVersion: ingestron.io/v1
|
|
2
|
+
kind: Connection
|
|
3
|
+
id: share
|
|
4
|
+
description: The stores' export share, inside the corporate network only.
|
|
5
|
+
connector: files
|
|
6
|
+
connectivity: private
|
|
7
|
+
settings:
|
|
8
|
+
path: '\\fs01\exports'
|
|
9
|
+
user: corp\ingest
|
|
10
|
+
password: ${secret:fs01-password} # a Key Vault secret name
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
apiVersion: v3.1.0
|
|
2
|
+
kind: DataContract
|
|
3
|
+
id: stores.sales
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
status: active
|
|
6
|
+
schema:
|
|
7
|
+
- name: sales
|
|
8
|
+
logicalType: object
|
|
9
|
+
description: One row per sale, exported by each store every hour.
|
|
10
|
+
properties:
|
|
11
|
+
- { name: sale_id, logicalType: string, required: true, primaryKey: true }
|
|
12
|
+
- { name: store_id, logicalType: integer, required: true }
|
|
13
|
+
- { name: amount, logicalType: number, physicalType: "DECIMAL(18,2)" }
|
|
14
|
+
- { name: sold_at, logicalType: timestamp, required: true }
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
apiVersion: v3.1.0
|
|
2
|
+
kind: DataContract
|
|
3
|
+
id: stores.stock
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
status: active
|
|
6
|
+
schema:
|
|
7
|
+
- name: stock
|
|
8
|
+
logicalType: object
|
|
9
|
+
description: Stock on hand per store and product, exported every hour.
|
|
10
|
+
properties:
|
|
11
|
+
- { name: store_id, logicalType: integer, required: true }
|
|
12
|
+
- { name: product_id, logicalType: integer, required: true }
|
|
13
|
+
- { name: on_hand, logicalType: integer }
|
|
14
|
+
- { name: counted_at, logicalType: timestamp, required: true }
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
apiVersion: ingestron.io/v1
|
|
2
|
+
kind: Flow
|
|
3
|
+
id: stores
|
|
4
|
+
source: share
|
|
5
|
+
ingest:
|
|
6
|
+
with: { format: csv, options: { header: true } } # the files' own format
|
|
7
|
+
tables:
|
|
8
|
+
sales: { object: sales, contract: stores.sales }
|
|
9
|
+
stock: { object: stock, contract: stores.stock }
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
apiVersion: ingestron.io/v1
|
|
2
|
+
kind: Platform
|
|
3
|
+
id: lakehouse
|
|
4
|
+
schedule:
|
|
5
|
+
cron: 0 15 * * * ?
|
|
6
|
+
timezone: Pacific/Auckland
|
|
7
|
+
settings:
|
|
8
|
+
adf-files: # shared infrastructure, referenced by name
|
|
9
|
+
landing: ${values.landing}
|
|
10
|
+
key_vault: ${values.key_vault}
|
|
11
|
+
integration_runtime: shir-stores
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Store exports on a file share inside the corporate network. ADF copies new
|
|
2
|
+
# files through a self-hosted integration runtime into a landing folder as
|
|
3
|
+
# they are; Databricks reads them there with Auto Loader.
|
|
4
|
+
id: stores
|
|
5
|
+
environments:
|
|
6
|
+
dev: {}
|
|
7
|
+
prod:
|
|
8
|
+
values:
|
|
9
|
+
landing: abfss://landing@storeslakeprod.dfs.core.windows.net/stores
|
|
10
|
+
key_vault: https://kv-stores-prod.vault.azure.net
|
|
11
|
+
values:
|
|
12
|
+
landing: abfss://landing@storeslakedev.dfs.core.windows.net/stores
|
|
13
|
+
key_vault: https://kv-stores-dev.vault.azure.net
|
|
14
|
+
imports:
|
|
15
|
+
- standard.yaml
|
|
16
|
+
- platform.yaml
|
|
17
|
+
- connections/*.yaml
|
|
18
|
+
- flows/*.yaml
|
|
19
|
+
- contracts/*.yaml
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
apiVersion: ingestron.io/v1
|
|
2
|
+
kind: Standard
|
|
3
|
+
id: stores
|
|
4
|
+
packs: [databricks@1, adf@1] # Databricks first: it provides the defaults
|
|
5
|
+
naming:
|
|
6
|
+
catalog: stores_{{ environment }}
|
|
7
|
+
ingest:
|
|
8
|
+
settings:
|
|
9
|
+
adf-files: # the schedule; where it lands is the platform's
|
|
10
|
+
every: { frequency: Hour, interval: 1 }
|
|
11
|
+
start: 2026-10-01T00:00:00Z
|