@raisenow/tamaro-cli 3.0.0 → 3.1.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/dist/cli.js +103 -4
- package/package.json +3 -2
- package/.idea/inspectionProfiles/Project_Default.xml +0 -6
- package/.idea/modules.xml +0 -8
- package/.idea/tamaro-cli.iml +0 -12
- package/.idea/vcs.xml +0 -6
- package/.idea/workspace.xml +0 -62
package/dist/cli.js
CHANGED
|
@@ -14,7 +14,8 @@ import open from "open";
|
|
|
14
14
|
import { globSync } from "glob";
|
|
15
15
|
import Handlebars from "handlebars";
|
|
16
16
|
import helpers from "handlebars-helpers";
|
|
17
|
-
import {
|
|
17
|
+
import { codeFrameColumns } from "@babel/code-frame";
|
|
18
|
+
import { config, parse } from "dotenv";
|
|
18
19
|
import { getPortPromise } from "portfinder";
|
|
19
20
|
import prompts from "prompts";
|
|
20
21
|
import columnify from "columnify";
|
|
@@ -545,6 +546,98 @@ const compileEmailTemplate = (template) => {
|
|
|
545
546
|
Handlebars.compile(template)({});
|
|
546
547
|
};
|
|
547
548
|
//#endregion
|
|
549
|
+
//#region src/lib/validators/validateEnv.ts
|
|
550
|
+
const envSchema = z.strictObject({
|
|
551
|
+
CORE_URL: z.url().optional(),
|
|
552
|
+
CORE_URL_PATTERN: z.string().includes("{{version}}", { message: "Must contain the \"{{version}}\" placeholder" }).optional(),
|
|
553
|
+
CORE_VERSION: z.string().refine((version) => version === version.trim(), { message: "There must be no leading or trailing whitespace in the version string" }).refine((version) => version === version.toLowerCase(), { message: "The version string must be lowercase" }).optional(),
|
|
554
|
+
DISABLE_URL_VERSION_OVERRIDE: z.enum([
|
|
555
|
+
"true",
|
|
556
|
+
"false",
|
|
557
|
+
"1",
|
|
558
|
+
"0"
|
|
559
|
+
]).optional(),
|
|
560
|
+
LOCAL_CORE: z.enum(["true", "false"]).optional()
|
|
561
|
+
});
|
|
562
|
+
const TAMARO_CORE_REGISTRY_URL = "https://registry.npmjs.org/@raisenow/tamaro-core";
|
|
563
|
+
/**
|
|
564
|
+
* Check that the configured version exists for "@raisenow/tamaro-core" on npm:
|
|
565
|
+
* as a dist-tag (e.g. "latest", "lts_2026"), an exact version, or a partial
|
|
566
|
+
* version ("2", "2.15") matching at least one published version.
|
|
567
|
+
*/
|
|
568
|
+
const coreVersionExists = async (version) => {
|
|
569
|
+
const metadata = await ky.get(TAMARO_CORE_REGISTRY_URL, {
|
|
570
|
+
headers: { accept: "application/vnd.npm.install-v1+json" },
|
|
571
|
+
retry: 0,
|
|
572
|
+
timeout: DEFAULT_HTTP_TIMEOUT
|
|
573
|
+
}).json();
|
|
574
|
+
const distTags = Object.keys(metadata["dist-tags"] ?? {});
|
|
575
|
+
const versions = Object.keys(metadata.versions ?? {});
|
|
576
|
+
return distTags.includes(version) || versions.includes(version) || versions.some((existing) => existing.startsWith(`${version}.`));
|
|
577
|
+
};
|
|
578
|
+
/**
|
|
579
|
+
* Locate the line of a `KEY=` assignment in the .env source, so the error can
|
|
580
|
+
* be rendered as a code frame pointing at the value.
|
|
581
|
+
*/
|
|
582
|
+
const findKeyLocation = (source, key) => {
|
|
583
|
+
const lines = source.split("\n");
|
|
584
|
+
const assignment = new RegExp(String.raw`^\s*${key}\s*=`);
|
|
585
|
+
const index = lines.findIndex((line) => assignment.test(line));
|
|
586
|
+
if (index === -1) return;
|
|
587
|
+
const line = index + 1;
|
|
588
|
+
const valueStart = lines[index].indexOf("=") + 1;
|
|
589
|
+
return {
|
|
590
|
+
end: {
|
|
591
|
+
column: lines[index].length,
|
|
592
|
+
line
|
|
593
|
+
},
|
|
594
|
+
start: {
|
|
595
|
+
column: valueStart,
|
|
596
|
+
line
|
|
597
|
+
}
|
|
598
|
+
};
|
|
599
|
+
};
|
|
600
|
+
/**
|
|
601
|
+
* Format an error for a `KEY=` assignment as a code frame pointing at the
|
|
602
|
+
* value, so it looks fancy like this:
|
|
603
|
+
*
|
|
604
|
+
* .env:2
|
|
605
|
+
* 1 | CORE_VERSION=LTS_2026
|
|
606
|
+
* 2 | CORE_URL_PATTERN=adsf
|
|
607
|
+
* | ^^^^ Must contain the "{{version}}" placeholder
|
|
608
|
+
*/
|
|
609
|
+
const formatError = (dotEnvPath, source, key, message) => {
|
|
610
|
+
const location = findKeyLocation(source, key);
|
|
611
|
+
if (!location) return `${dotEnvPath}: ${key}: ${message}`;
|
|
612
|
+
const frame = codeFrameColumns(source, location, {
|
|
613
|
+
forceColor: true,
|
|
614
|
+
highlightCode: true,
|
|
615
|
+
message
|
|
616
|
+
});
|
|
617
|
+
return `\n${dotEnvPath}:${location.start.line}\n${frame}`;
|
|
618
|
+
};
|
|
619
|
+
/**
|
|
620
|
+
* Validate the environment variables in the config's .env file.
|
|
621
|
+
*/
|
|
622
|
+
const validateEnv = async (dotEnvPath) => {
|
|
623
|
+
if (!fs.existsSync(dotEnvPath)) return [];
|
|
624
|
+
const source = fs.readFileSync(dotEnvPath, "utf8");
|
|
625
|
+
const parsed = parse(source);
|
|
626
|
+
const result = envSchema.safeParse(parsed);
|
|
627
|
+
if (!result.success) {
|
|
628
|
+
const errors = [];
|
|
629
|
+
for (const issue of result.error.issues) {
|
|
630
|
+
const keys = issue.code === "unrecognized_keys" ? issue.keys : [String(issue.path[0] ?? "")];
|
|
631
|
+
for (const key of keys) errors.push(formatError(dotEnvPath, source, key, issue.message));
|
|
632
|
+
}
|
|
633
|
+
return errors;
|
|
634
|
+
}
|
|
635
|
+
if (parsed.CORE_VERSION) {
|
|
636
|
+
if (await coreVersionExists(parsed.CORE_VERSION) === false) return [formatError(dotEnvPath, source, "CORE_VERSION", `Version "${parsed.CORE_VERSION}" does not exist. See all versions at https://www.npmjs.com/package/@raisenow/tamaro-core?activeTab=versions`)];
|
|
637
|
+
}
|
|
638
|
+
return [];
|
|
639
|
+
};
|
|
640
|
+
//#endregion
|
|
548
641
|
//#region src/commands/validate.ts
|
|
549
642
|
/**
|
|
550
643
|
* Validates the current Tamaro configuration to avoid common errors.
|
|
@@ -554,8 +647,12 @@ const compileEmailTemplate = (template) => {
|
|
|
554
647
|
* deployed.
|
|
555
648
|
*/
|
|
556
649
|
const validate = async () => {
|
|
557
|
-
const errors = validateEmailTemplates(globSync("email-config/templates/**/*.hbs").toSorted());
|
|
558
|
-
if (errors.length > 0)
|
|
650
|
+
const errors = [...await validateEnv(".env"), ...validateEmailTemplates(globSync("email-config/templates/**/*.hbs").toSorted())];
|
|
651
|
+
if (errors.length > 0) {
|
|
652
|
+
logError("❌ Validation failed with the following errors:");
|
|
653
|
+
console.log(errors.map((el) => el.toString()).join("\n"));
|
|
654
|
+
halt();
|
|
655
|
+
}
|
|
559
656
|
logTitle("Validated successfully");
|
|
560
657
|
};
|
|
561
658
|
//#endregion
|
|
@@ -631,6 +728,7 @@ const getOutDir = (configName) => {
|
|
|
631
728
|
//#region src/commands/update-epms.ts
|
|
632
729
|
const updateEpms = async (options) => {
|
|
633
730
|
const configName = getConfigName();
|
|
731
|
+
await validate();
|
|
634
732
|
if (!options.profile && !options.ci) {
|
|
635
733
|
assertAwsProfilesPresent();
|
|
636
734
|
options.profile = await promptAwsProfile();
|
|
@@ -912,6 +1010,7 @@ const dev = async (options) => {
|
|
|
912
1010
|
const configName = getConfigName();
|
|
913
1011
|
const configsPackageRoot = getConfigsPackageRoot();
|
|
914
1012
|
assertCrtExists(configsPackageRoot);
|
|
1013
|
+
await validate();
|
|
915
1014
|
const port = await getPortPromise({ port: Number(DEFAULT_PORT) });
|
|
916
1015
|
logTitle(`\nStarting Vite dev server for "${configName}" configuration...`);
|
|
917
1016
|
runCommandSync(`pnpm vite dev --port ${port}`, {
|
|
@@ -1225,7 +1324,7 @@ const promptBucketTamaroEmailConfig = async () => {
|
|
|
1225
1324
|
//#endregion
|
|
1226
1325
|
//#region package.json
|
|
1227
1326
|
var name = "@raisenow/tamaro-cli";
|
|
1228
|
-
var version = "3.
|
|
1327
|
+
var version = "3.1.0";
|
|
1229
1328
|
//#endregion
|
|
1230
1329
|
//#region src/cli.ts
|
|
1231
1330
|
const cli = createCommand().name(name).description("CLI for Tamaro Customer Configurations development").version(version, "-v, --version");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@raisenow/tamaro-cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"author": {
|
|
5
5
|
"name": "RaiseNow",
|
|
6
6
|
"email": "development@raisenow.com"
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
"yarn": "please-use-pnpm"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@aws-sdk/client-s3": "^3.
|
|
16
|
+
"@aws-sdk/client-s3": "^3.1081.0",
|
|
17
|
+
"@babel/code-frame": "^8.0.0",
|
|
17
18
|
"@rnw-npm/cli-helpers": "^2.0.1",
|
|
18
19
|
"columnify": "^1.6.0",
|
|
19
20
|
"commander": "^15.0.0",
|
package/.idea/modules.xml
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<project version="4">
|
|
3
|
-
<component name="ProjectModuleManager">
|
|
4
|
-
<modules>
|
|
5
|
-
<module fileurl="file://$PROJECT_DIR$/.idea/tamaro-cli.iml" filepath="$PROJECT_DIR$/.idea/tamaro-cli.iml" />
|
|
6
|
-
</modules>
|
|
7
|
-
</component>
|
|
8
|
-
</project>
|
package/.idea/tamaro-cli.iml
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<module type="WEB_MODULE" version="4">
|
|
3
|
-
<component name="NewModuleRootManager">
|
|
4
|
-
<content url="file://$MODULE_DIR$">
|
|
5
|
-
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
|
6
|
-
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
|
7
|
-
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
|
8
|
-
</content>
|
|
9
|
-
<orderEntry type="inheritedJdk" />
|
|
10
|
-
<orderEntry type="sourceFolder" forTests="false" />
|
|
11
|
-
</component>
|
|
12
|
-
</module>
|
package/.idea/vcs.xml
DELETED
package/.idea/workspace.xml
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<project version="4">
|
|
3
|
-
<component name="ChangeListManager">
|
|
4
|
-
<list default="true" id="03cc3f97-55ca-4737-9fe2-779ac8457ab2" name="Changes" comment="" />
|
|
5
|
-
<option name="SHOW_DIALOG" value="false" />
|
|
6
|
-
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
|
7
|
-
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
|
8
|
-
<option name="LAST_RESOLUTION" value="IGNORE" />
|
|
9
|
-
</component>
|
|
10
|
-
<component name="Git.Settings">
|
|
11
|
-
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
|
12
|
-
</component>
|
|
13
|
-
<component name="MarkdownSettingsMigration">
|
|
14
|
-
<option name="stateVersion" value="1" />
|
|
15
|
-
</component>
|
|
16
|
-
<component name="ProjectId" id="3BwvHZOW2N4A0f0JXo7q8qDzYwY" />
|
|
17
|
-
<component name="ProjectViewState">
|
|
18
|
-
<option name="autoscrollFromSource" value="true" />
|
|
19
|
-
<option name="autoscrollToSource" value="true" />
|
|
20
|
-
<option name="hideEmptyMiddlePackages" value="true" />
|
|
21
|
-
<option name="showLibraryContents" value="true" />
|
|
22
|
-
<option name="showMembers" value="true" />
|
|
23
|
-
</component>
|
|
24
|
-
<component name="PropertiesComponent">{
|
|
25
|
-
"keyToString": {
|
|
26
|
-
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
|
27
|
-
"RunOnceActivity.ShowReadmeOnStart": "true",
|
|
28
|
-
"WebServerToolWindowFactoryState": "false",
|
|
29
|
-
"node.js.detected.package.eslint": "true",
|
|
30
|
-
"node.js.selected.package.eslint": "(autodetect)",
|
|
31
|
-
"nodejs_package_manager_path": "pnpm",
|
|
32
|
-
"prettierjs.PrettierConfiguration.Package": "/Users/sigerello/dev/_raisenow/tools/tamaro-cli/node_modules/prettier",
|
|
33
|
-
"ts.external.directory.path": "/Users/sigerello/dev/_raisenow/tools/tamaro-cli/node_modules/typescript/lib",
|
|
34
|
-
"vue.rearranger.settings.migration": "true"
|
|
35
|
-
}
|
|
36
|
-
}</component>
|
|
37
|
-
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
|
38
|
-
<component name="TaskManager">
|
|
39
|
-
<task active="true" id="Default" summary="Default task">
|
|
40
|
-
<changelist id="03cc3f97-55ca-4737-9fe2-779ac8457ab2" name="Changes" comment="" />
|
|
41
|
-
<created>1775412859839</created>
|
|
42
|
-
<option name="number" value="Default" />
|
|
43
|
-
<option name="presentableId" value="Default" />
|
|
44
|
-
<updated>1775412859839</updated>
|
|
45
|
-
<workItem from="1775412861312" duration="2060000" />
|
|
46
|
-
<workItem from="1776174639969" duration="1525000" />
|
|
47
|
-
<workItem from="1776736351878" duration="598000" />
|
|
48
|
-
<workItem from="1777934504965" duration="82000" />
|
|
49
|
-
<workItem from="1777936008103" duration="88000" />
|
|
50
|
-
<workItem from="1778477038620" duration="2530000" />
|
|
51
|
-
<workItem from="1780398242165" duration="1962000" />
|
|
52
|
-
<workItem from="1781661280180" duration="2828000" />
|
|
53
|
-
<workItem from="1782699840335" duration="599000" />
|
|
54
|
-
<workItem from="1782869357470" duration="598000" />
|
|
55
|
-
<workItem from="1783270034892" duration="1197000" />
|
|
56
|
-
</task>
|
|
57
|
-
<servers />
|
|
58
|
-
</component>
|
|
59
|
-
<component name="TypeScriptGeneratedFilesManager">
|
|
60
|
-
<option name="version" value="3" />
|
|
61
|
-
</component>
|
|
62
|
-
</project>
|