@raisenow/tamaro-cli 3.0.0-dev.1 → 3.0.0-dev.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -0
- package/dist/cli.js +199 -324
- package/package.json +3 -5
package/README.md
CHANGED
|
@@ -36,6 +36,9 @@ Available commands:
|
|
|
36
36
|
- [`unarchive`](#unarchive)
|
|
37
37
|
- [`update-epms`](#update-epms)
|
|
38
38
|
- [`validate`](#validate)
|
|
39
|
+
- [`typecheck`](#typecheck)
|
|
40
|
+
- [`lint`](#lint)
|
|
41
|
+
- [`format`](#format)
|
|
39
42
|
|
|
40
43
|
## `dev`
|
|
41
44
|
|
|
@@ -288,6 +291,39 @@ cd /path/to/tamaro-configurations/configs/epms-demo
|
|
|
288
291
|
pnpx @raisenow/tamaro-cli validate
|
|
289
292
|
```
|
|
290
293
|
|
|
294
|
+
## `typecheck`
|
|
295
|
+
|
|
296
|
+
Typecheck the current Tamaro configuration.
|
|
297
|
+
|
|
298
|
+
### Example
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
cd /path/to/tamaro-configurations/configs/epms-demo
|
|
302
|
+
pnpx @raisenow/tamaro-cli typecheck
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
## `lint`
|
|
306
|
+
|
|
307
|
+
Lint the current Tamaro configuration with ESLint.
|
|
308
|
+
|
|
309
|
+
### Example
|
|
310
|
+
|
|
311
|
+
```bash
|
|
312
|
+
cd /path/to/tamaro-configurations/configs/epms-demo
|
|
313
|
+
pnpx @raisenow/tamaro-cli lint
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
## `format`
|
|
317
|
+
|
|
318
|
+
Format the current Tamaro configuration with Prettier.
|
|
319
|
+
|
|
320
|
+
### Example
|
|
321
|
+
|
|
322
|
+
```bash
|
|
323
|
+
cd /path/to/tamaro-configurations/configs/epms-demo
|
|
324
|
+
pnpx @raisenow/tamaro-cli format
|
|
325
|
+
```
|
|
326
|
+
|
|
291
327
|
# Development
|
|
292
328
|
|
|
293
329
|
Use the versions declared in `package.json`:
|
package/dist/cli.js
CHANGED
|
@@ -1,73 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
|
+
import { assertAwsProfileValid, assertAwsProfilesPresent, assertCrtExists, assertTagValid, awsAuthenticate, halt, logDataTable, logError, logInfo, logSuccess, logTitle, notify, prepareAwsCliFlags, promptAwsProfile, promptConfirmation, runCommandSync } from "@rnw-npm/cli-helpers";
|
|
3
4
|
import { createCommand } from "commander";
|
|
4
5
|
import fs from "node:fs";
|
|
5
6
|
import path from "node:path";
|
|
6
7
|
import dedent from "dedent";
|
|
7
|
-
import { S3 } from "@aws-sdk/client-s3";
|
|
8
|
-
import { execaCommandSync } from "execa";
|
|
9
|
-
import prompts from "prompts";
|
|
10
|
-
import chalk from "chalk";
|
|
11
|
-
import columnify from "columnify";
|
|
12
|
-
import envPaths from "env-paths";
|
|
13
8
|
import * as yaml from "js-yaml";
|
|
9
|
+
import envPaths from "env-paths";
|
|
14
10
|
import { z } from "zod";
|
|
15
11
|
import ky from "ky";
|
|
16
12
|
import { createServer } from "node:http";
|
|
17
13
|
import open from "open";
|
|
18
|
-
import notifier from "node-notifier";
|
|
19
|
-
import console$1 from "node:console";
|
|
20
14
|
import { globSync } from "glob";
|
|
21
15
|
import Handlebars from "handlebars";
|
|
22
16
|
import helpers from "handlebars-helpers";
|
|
23
17
|
import { config } from "dotenv";
|
|
24
18
|
import { getPortPromise } from "portfinder";
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
};
|
|
29
|
-
const logError = (message) => {
|
|
30
|
-
if (message) console.log(chalk.red(message));
|
|
31
|
-
};
|
|
32
|
-
const logSuccess = (message) => {
|
|
33
|
-
if (message) console.log(chalk.green(message));
|
|
34
|
-
};
|
|
35
|
-
const logInfo = (message) => {
|
|
36
|
-
if (message) console.log(chalk.blue(message));
|
|
37
|
-
};
|
|
38
|
-
const logCommand = (cmd) => {
|
|
39
|
-
console.log(`\n${chalk.dim(dedent(cmd))}\n`);
|
|
40
|
-
};
|
|
41
|
-
const logDataTable = (data) => {
|
|
42
|
-
console.log(columnify(data, { showHeaders: false }));
|
|
43
|
-
console.log("");
|
|
44
|
-
};
|
|
45
|
-
const createTerminalLink = (text, url) => {
|
|
46
|
-
return `\u001B]8;;${url}\u001B\\${text}\u001B]8;;\u001B\\`;
|
|
47
|
-
};
|
|
48
|
-
//#endregion
|
|
49
|
-
//#region src/lib/command.ts
|
|
50
|
-
const halt = (message) => {
|
|
51
|
-
logError(message);
|
|
52
|
-
process.exit(1);
|
|
53
|
-
};
|
|
54
|
-
const prepareCommand = (cmd) => {
|
|
55
|
-
return cmd.replaceAll("\n", " ").replaceAll(/[ \t]{2,}/g, " ").trim();
|
|
56
|
-
};
|
|
57
|
-
const runCommandSync = (cmd, options) => {
|
|
58
|
-
return execaCommandSync(prepareCommand(cmd), options);
|
|
59
|
-
};
|
|
60
|
-
const promptConfirmation = async (message, skipConfirmation) => {
|
|
61
|
-
if (skipConfirmation) return;
|
|
62
|
-
const { confirmed } = await prompts([{
|
|
63
|
-
initial: false,
|
|
64
|
-
message,
|
|
65
|
-
name: "confirmed",
|
|
66
|
-
type: "confirm"
|
|
67
|
-
}], { onCancel: () => halt() });
|
|
68
|
-
if (!confirmed) halt("Operation cancelled.");
|
|
69
|
-
};
|
|
70
|
-
//#endregion
|
|
19
|
+
import prompts from "prompts";
|
|
20
|
+
import columnify from "columnify";
|
|
21
|
+
import { S3 } from "@aws-sdk/client-s3";
|
|
71
22
|
//#region src/lib/constants.ts
|
|
72
23
|
const DEFAULT_TAG = "latest";
|
|
73
24
|
const DEFAULT_PORT = 1234;
|
|
@@ -75,113 +26,16 @@ const DEFAULT_HTTP_TIMEOUT = 1e4;
|
|
|
75
26
|
const AWS_S3_BUCKET_TAMARO = "tamaro.raisenow.com";
|
|
76
27
|
const AWS_S3_BUCKET_TAMARO_EMAIL_CONFIG_STAGE = "rnw-stage-email-service";
|
|
77
28
|
const AWS_S3_BUCKET_TAMARO_EMAIL_CONFIG_PROD = "rnw-email-service";
|
|
29
|
+
const AWS_CLOUDFRONT_DISTRIBUTION_ID = "EHJ1OM458YQ0I";
|
|
78
30
|
const EPMS_API_BASE_URL_STAGE = "https://api.stage.mesos.raisenow.net";
|
|
79
31
|
const EPMS_API_BASE_URL_PROD = "https://api.raisenow.io";
|
|
80
32
|
const EPMS_AUTH_BASE_URL_STAGE = "https://login.stage.mesos.raisenow.net";
|
|
81
33
|
const EPMS_AUTH_BASE_URL_PROD = "https://login.raisenow.com";
|
|
82
34
|
const EPMS_OAUTH_CLIENT_ID = "tamaro-cli";
|
|
83
35
|
const AUTH_PORT = 4571;
|
|
84
|
-
const AWS_CLOUDFRONT_DISTRIBUTION_ID = "EHJ1OM458YQ0I";
|
|
85
|
-
const HTTPS_CRT_FILE = "localhost.crt";
|
|
86
|
-
const HTTPS_KEY_FILE = "localhost.key";
|
|
87
36
|
const CACHE_DIR = envPaths("tamaro-cli", { suffix: "" }).cache;
|
|
88
37
|
const TAMARO_VERSION_IN_URL_REGEX = /tamaro-core\/(.*)\/index.js/;
|
|
89
38
|
//#endregion
|
|
90
|
-
//#region src/lib/aws.ts
|
|
91
|
-
const awsAuthenticate = (options) => {
|
|
92
|
-
if (options.ci)
|
|
93
|
-
/**
|
|
94
|
-
* Don't try to authenticate the user.
|
|
95
|
-
* This is done when CLI is running within an automated system like pipeline,
|
|
96
|
-
* In this case "AWS_ACCESS_KEY_ID" and "AWS_SECRET_ACCESS_KEY" are used instead of "AWS_PROFILE".
|
|
97
|
-
*/
|
|
98
|
-
return;
|
|
99
|
-
try {
|
|
100
|
-
checkIdentity(options);
|
|
101
|
-
} catch {
|
|
102
|
-
login(options);
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
|
-
const assertProfilesPresent = () => {
|
|
106
|
-
if (getAvailableProfiles().length === 0) halt(dedent`
|
|
107
|
-
No AWS profiles found.
|
|
108
|
-
Run "aws configure sso" to set up SSO-enabled profile.
|
|
109
|
-
Check the wiki for more information:
|
|
110
|
-
https://raisenow.atlassian.net/wiki/x/lIrWvg
|
|
111
|
-
`);
|
|
112
|
-
};
|
|
113
|
-
const getAvailableProfiles = () => {
|
|
114
|
-
const { stdout } = execaCommandSync("aws configure list-profiles");
|
|
115
|
-
return stdout.split("\n");
|
|
116
|
-
};
|
|
117
|
-
/**
|
|
118
|
-
* Returns caller identity data (output is ignored here).
|
|
119
|
-
* Fails in case of expired SSO session.
|
|
120
|
-
*/
|
|
121
|
-
const checkIdentity = (options) => {
|
|
122
|
-
execaCommandSync(`aws sts get-caller-identity ${prepareFlags(options)}`);
|
|
123
|
-
};
|
|
124
|
-
/**
|
|
125
|
-
* Opens SSO authentication page in the browser.
|
|
126
|
-
* Fails if user canceled authentication process.
|
|
127
|
-
*/
|
|
128
|
-
const login = (options) => {
|
|
129
|
-
const flags = prepareFlags(options);
|
|
130
|
-
try {
|
|
131
|
-
execaCommandSync(`aws sso login ${flags}`, { stdio: "inherit" });
|
|
132
|
-
console.log("");
|
|
133
|
-
} catch {
|
|
134
|
-
halt("Login failed.");
|
|
135
|
-
}
|
|
136
|
-
};
|
|
137
|
-
const prepareFlags = (options) => {
|
|
138
|
-
const flags = [];
|
|
139
|
-
const { profile } = options;
|
|
140
|
-
if (profile) flags.push(`--profile ${profile}`);
|
|
141
|
-
return flags.join(" ");
|
|
142
|
-
};
|
|
143
|
-
const assertProfileValid = (profile) => {
|
|
144
|
-
const profiles = getAvailableProfiles();
|
|
145
|
-
if (!profiles.includes(profile)) halt(dedent`
|
|
146
|
-
AWS profile "${profile}" is not found.
|
|
147
|
-
Available profiles are: ${profiles.map((v) => `"${v}"`).join(", ")}.
|
|
148
|
-
`);
|
|
149
|
-
};
|
|
150
|
-
const promptProfile = async () => {
|
|
151
|
-
const { profile } = await prompts([{
|
|
152
|
-
choices: getAvailableProfiles().filter((v) => !!v).map((v) => ({
|
|
153
|
-
title: v,
|
|
154
|
-
value: v
|
|
155
|
-
})),
|
|
156
|
-
message: "Select AWS profile",
|
|
157
|
-
name: "profile",
|
|
158
|
-
type: "select"
|
|
159
|
-
}], { onCancel: () => halt() });
|
|
160
|
-
return profile;
|
|
161
|
-
};
|
|
162
|
-
const s3 = new S3({});
|
|
163
|
-
const getConfigDeployments = async (configName) => {
|
|
164
|
-
const widgetJs = (await s3.listObjectsV2({
|
|
165
|
-
Bucket: "tamaro.raisenow.com",
|
|
166
|
-
Prefix: `${configName}/`
|
|
167
|
-
})).Contents?.filter((file) => file.Key?.endsWith(`/index.html`)) ?? [];
|
|
168
|
-
const deployments = [];
|
|
169
|
-
for (const file of widgetJs) {
|
|
170
|
-
const key = file.Key ?? "";
|
|
171
|
-
const parts = key.split("/");
|
|
172
|
-
if (parts.length < 2 || !file.LastModified) continue;
|
|
173
|
-
const tag = parts.at(-2);
|
|
174
|
-
const date = file.LastModified.toISOString();
|
|
175
|
-
const fullUrl = `https://${AWS_S3_BUCKET_TAMARO}/${key}`;
|
|
176
|
-
deployments.push({
|
|
177
|
-
date,
|
|
178
|
-
fullUrl,
|
|
179
|
-
tag
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
return deployments;
|
|
183
|
-
};
|
|
184
|
-
//#endregion
|
|
185
39
|
//#region src/lib/resolve.ts
|
|
186
40
|
const resolveAccountUuidFromConfig = (rawConfig, field) => {
|
|
187
41
|
const epmsConfig = z.object({ [field]: z.record(z.string(), z.unknown()) }).safeParse(rawConfig);
|
|
@@ -292,6 +146,11 @@ const createAuthorizer = (baseUrl, clientId, clientSecret) => {
|
|
|
292
146
|
}] } });
|
|
293
147
|
};
|
|
294
148
|
//#endregion
|
|
149
|
+
//#region src/lib/logging.ts
|
|
150
|
+
const createTerminalLink = (text, url) => {
|
|
151
|
+
return `\u001B]8;;${url}\u001B\\${text}\u001B]8;;\u001B\\`;
|
|
152
|
+
};
|
|
153
|
+
//#endregion
|
|
295
154
|
//#region src/lib/epms/auth/authCallback.html
|
|
296
155
|
var authCallback_default = "<!doctype html>\n<html>\n <head\n ><title>Authenticating</title></head\n >\n <body>\n <p>Authenticating</p>\n <script>\n const hash = window.location.hash.substring(1)\n const params = new URLSearchParams(hash)\n const data = {\n access_token: params.get('access_token'),\n token_type: params.get('token_type'),\n expires_in: parseInt(params.get('expires_in') || '0', 10),\n }\n fetch('/token', {\n method: 'POST',\n headers: {'Content-Type': 'application/json'},\n body: JSON.stringify(data),\n })\n .then(() => {\n document.querySelector('p').textContent =\n 'Authentication successful! You can close this tab.'\n })\n .catch(() => {\n document.querySelector('p').textContent =\n 'Authentication failed. Please try again.'\n })\n <\/script>\n </body>\n</html>\n";
|
|
297
156
|
//#endregion
|
|
@@ -516,17 +375,6 @@ const assertUserIsSuperAdmin = async (epmsClient) => {
|
|
|
516
375
|
}
|
|
517
376
|
};
|
|
518
377
|
//#endregion
|
|
519
|
-
//#region src/lib/notifier.ts
|
|
520
|
-
const notify = (args) => {
|
|
521
|
-
const { message = "", title } = args;
|
|
522
|
-
notifier.notify({
|
|
523
|
-
contentImage: "https://assets.raisenow.io/favicon.png",
|
|
524
|
-
message: dedent(message),
|
|
525
|
-
sound: "Funk",
|
|
526
|
-
title
|
|
527
|
-
});
|
|
528
|
-
};
|
|
529
|
-
//#endregion
|
|
530
378
|
//#region src/commands/archive.ts
|
|
531
379
|
const archive = async (options) => {
|
|
532
380
|
assertIsNotArchived();
|
|
@@ -585,7 +433,7 @@ const archiveEpms = async (configName, dryrun) => {
|
|
|
585
433
|
};
|
|
586
434
|
const assertOptionsValid$7 = (options) => {
|
|
587
435
|
const { profile } = options;
|
|
588
|
-
if (profile)
|
|
436
|
+
if (profile) assertAwsProfileValid(profile);
|
|
589
437
|
};
|
|
590
438
|
const assertIsNotArchived = () => {
|
|
591
439
|
if (path.basename(path.dirname(process.cwd())) === "_archived") halt("This configuration is already archived.");
|
|
@@ -780,21 +628,15 @@ const getOutDir = (configName) => {
|
|
|
780
628
|
return path.resolve(getConfigsPackageRoot(), "dist", configName);
|
|
781
629
|
};
|
|
782
630
|
//#endregion
|
|
783
|
-
//#region src/lib/validators/assertTagValid.ts
|
|
784
|
-
const assertTagValid = (tag) => {
|
|
785
|
-
const regex = /^[\w.-]+$/;
|
|
786
|
-
if (!regex.test(tag)) halt(`Flag "--tag" has forbidden format. Allowed format: ${regex.toString()}.`);
|
|
787
|
-
};
|
|
788
|
-
//#endregion
|
|
789
631
|
//#region src/commands/update-epms.ts
|
|
790
632
|
const updateEpms = async (options) => {
|
|
791
633
|
const configName = getConfigName();
|
|
792
634
|
if (!options.profile && !options.ci) {
|
|
793
|
-
|
|
794
|
-
options.profile = await
|
|
635
|
+
assertAwsProfilesPresent();
|
|
636
|
+
options.profile = await promptAwsProfile();
|
|
795
637
|
}
|
|
796
638
|
if (options.profile) {
|
|
797
|
-
|
|
639
|
+
assertAwsProfileValid(options.profile);
|
|
798
640
|
process.env.AWS_PROFILE = options.profile;
|
|
799
641
|
}
|
|
800
642
|
awsAuthenticate(options);
|
|
@@ -864,13 +706,13 @@ const deploy = async (options) => {
|
|
|
864
706
|
const outDir = getOutDir(configName);
|
|
865
707
|
assertOutDir(configName);
|
|
866
708
|
if (!options.profile && !options.ci) {
|
|
867
|
-
|
|
868
|
-
options.profile = await
|
|
709
|
+
assertAwsProfilesPresent();
|
|
710
|
+
options.profile = await promptAwsProfile();
|
|
869
711
|
}
|
|
870
712
|
assertOptionsValid$6(options);
|
|
871
713
|
await validate();
|
|
872
714
|
awsAuthenticate(options);
|
|
873
|
-
const flags =
|
|
715
|
+
const flags = prepareAwsCliFlags(options);
|
|
874
716
|
const { dryrun, tag } = options;
|
|
875
717
|
const dryRunFlag = dryrun ? `--dryrun` : "";
|
|
876
718
|
const deployUrl = `s3://${AWS_S3_BUCKET_TAMARO}/${configName}/${tag}`;
|
|
@@ -879,54 +721,47 @@ const deploy = async (options) => {
|
|
|
879
721
|
/**
|
|
880
722
|
* Sync all files except entrypoint (without deleting old files)
|
|
881
723
|
*/
|
|
882
|
-
const cmdSyncAll = `
|
|
883
|
-
aws s3 sync ${outDir} ${deployUrl}
|
|
884
|
-
--acl public-read
|
|
885
|
-
--exclude ${outDir}/${entryFilename}
|
|
886
|
-
--cache-control max-age=31536000
|
|
887
|
-
${flags}
|
|
888
|
-
${dryRunFlag}
|
|
889
|
-
`;
|
|
890
|
-
logTitle("Deploying to AWS S3...");
|
|
891
|
-
logCommand(cmdSyncAll);
|
|
892
724
|
try {
|
|
893
|
-
|
|
725
|
+
logTitle("Deploying to AWS S3...");
|
|
726
|
+
runCommandSync(dedent`
|
|
727
|
+
aws s3 sync ${outDir} ${deployUrl}
|
|
728
|
+
--acl public-read
|
|
729
|
+
--exclude ${outDir}/${entryFilename}
|
|
730
|
+
--cache-control max-age=31536000
|
|
731
|
+
${flags}
|
|
732
|
+
${dryRunFlag}
|
|
733
|
+
`, { stdout: "inherit" });
|
|
894
734
|
} catch (error) {
|
|
895
735
|
halt(error.stderr);
|
|
896
736
|
}
|
|
897
737
|
/**
|
|
898
738
|
* Copy entrypoint
|
|
899
739
|
*/
|
|
900
|
-
const cmdCpEntry = `
|
|
901
|
-
aws s3 cp ${outDir}/${entryFilename} ${deployUrl}/${entryFilename}
|
|
902
|
-
--acl public-read
|
|
903
|
-
--cache-control max-age=64800
|
|
904
|
-
${flags}
|
|
905
|
-
${dryRunFlag}
|
|
906
|
-
`;
|
|
907
|
-
logCommand(cmdCpEntry);
|
|
908
740
|
try {
|
|
909
|
-
runCommandSync(
|
|
741
|
+
runCommandSync(dedent`
|
|
742
|
+
aws s3 cp ${outDir}/${entryFilename} ${deployUrl}/${entryFilename}
|
|
743
|
+
--acl public-read
|
|
744
|
+
--cache-control max-age=64800
|
|
745
|
+
${flags}
|
|
746
|
+
${dryRunFlag}
|
|
747
|
+
`, { stdout: "inherit" });
|
|
910
748
|
} catch (error) {
|
|
911
749
|
halt(error.stderr);
|
|
912
750
|
}
|
|
913
|
-
if (!dryRunFlag)
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
aws cloudfront create-invalidation
|
|
919
|
-
--distribution-id ${AWS_CLOUDFRONT_DISTRIBUTION_ID}
|
|
920
|
-
--paths /${configName}/${tag}/*
|
|
921
|
-
${flags}
|
|
922
|
-
`;
|
|
751
|
+
if (!dryRunFlag)
|
|
752
|
+
/**
|
|
753
|
+
* Invalidate cloudfront cache
|
|
754
|
+
*/
|
|
755
|
+
try {
|
|
923
756
|
logTitle("\nInvalidating edge cache...");
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
757
|
+
runCommandSync(dedent`
|
|
758
|
+
aws cloudfront create-invalidation
|
|
759
|
+
--distribution-id ${AWS_CLOUDFRONT_DISTRIBUTION_ID}
|
|
760
|
+
--paths /${configName}/${tag}/*
|
|
761
|
+
${flags}
|
|
762
|
+
`);
|
|
763
|
+
} catch (error) {
|
|
764
|
+
halt(error.stderr);
|
|
930
765
|
}
|
|
931
766
|
if (options.forceSkipEpmsSync) logTitle("⚠️ EPMS sync skipped. You better know what you are doing.");
|
|
932
767
|
else await updateEpms(options);
|
|
@@ -939,7 +774,7 @@ const deploy = async (options) => {
|
|
|
939
774
|
});
|
|
940
775
|
process.on("exit", () => {
|
|
941
776
|
notify({
|
|
942
|
-
message:
|
|
777
|
+
message: `
|
|
943
778
|
Bundle for "${configName}" is deployed with tag "${tag}".
|
|
944
779
|
Demo page: ${demoPage}
|
|
945
780
|
Entry point: ${entryPoint}
|
|
@@ -950,36 +785,20 @@ const deploy = async (options) => {
|
|
|
950
785
|
};
|
|
951
786
|
const assertOptionsValid$6 = (options) => {
|
|
952
787
|
const { profile, tag } = options;
|
|
953
|
-
if (profile)
|
|
788
|
+
if (profile) assertAwsProfileValid(profile);
|
|
954
789
|
assertTagValid(tag);
|
|
955
790
|
};
|
|
956
791
|
//#endregion
|
|
957
|
-
//#region src/lib/https.ts
|
|
958
|
-
const assertCrtExists = () => {
|
|
959
|
-
const configsPackageRoot = getConfigsPackageRoot();
|
|
960
|
-
const certFile = path.resolve(configsPackageRoot, HTTPS_CRT_FILE);
|
|
961
|
-
const keyFile = path.resolve(configsPackageRoot, HTTPS_KEY_FILE);
|
|
962
|
-
if (fs.existsSync(certFile) && fs.existsSync(keyFile)) return;
|
|
963
|
-
halt(dedent`
|
|
964
|
-
Files "${HTTPS_CRT_FILE}" and/or "${HTTPS_KEY_FILE}" are not found.
|
|
965
|
-
You need to generate local certificates first.
|
|
966
|
-
1. Install mkcert:
|
|
967
|
-
brew install mkcert
|
|
968
|
-
2. Generate the certificate and key in the repository root:
|
|
969
|
-
mkcert -install -cert-file ${HTTPS_CRT_FILE} -key-file ${HTTPS_KEY_FILE} localhost 127.0.0.1 0.0.0.0 ::1
|
|
970
|
-
`);
|
|
971
|
-
};
|
|
972
|
-
//#endregion
|
|
973
792
|
//#region src/commands/preview.ts
|
|
974
793
|
const preview = async () => {
|
|
975
794
|
const configName = getConfigName();
|
|
976
795
|
const configsPackageRoot = getConfigsPackageRoot();
|
|
796
|
+
const relativeOutDir = path.relative(configsPackageRoot, getOutDir(configName));
|
|
977
797
|
assertOutDir(configName);
|
|
978
|
-
assertCrtExists();
|
|
979
|
-
const
|
|
980
|
-
logTitle(
|
|
981
|
-
|
|
982
|
-
runCommandSync(cmd, {
|
|
798
|
+
assertCrtExists(configsPackageRoot);
|
|
799
|
+
const port = await getPortPromise({ port: Number(DEFAULT_PORT) });
|
|
800
|
+
logTitle("\nRunning web-server for pre-built bundle...");
|
|
801
|
+
runCommandSync(`pnpm sirv ${relativeOutDir} --cors --http2 --cert localhost.crt --key localhost.key --port ${port}`, {
|
|
983
802
|
cwd: configsPackageRoot,
|
|
984
803
|
stdio: "inherit"
|
|
985
804
|
});
|
|
@@ -991,27 +810,23 @@ const build = async (options) => {
|
|
|
991
810
|
const configsPackageRoot = getConfigsPackageRoot();
|
|
992
811
|
const outDir = getOutDir(configName);
|
|
993
812
|
if (options.deploy && !options.profile && !options.ci) {
|
|
994
|
-
|
|
995
|
-
options.profile = await
|
|
813
|
+
assertAwsProfilesPresent();
|
|
814
|
+
options.profile = await promptAwsProfile();
|
|
996
815
|
}
|
|
997
816
|
assertOptionsValid$5(options);
|
|
998
817
|
await validate();
|
|
999
|
-
const cmd = `pnpm vite build`;
|
|
1000
|
-
const env = {
|
|
1001
|
-
...process.env,
|
|
1002
|
-
BABEL: options.babel ? "true" : "false",
|
|
1003
|
-
CONFIG_NAME: configName,
|
|
1004
|
-
MINIFY: options.minify ? "true" : "false"
|
|
1005
|
-
};
|
|
1006
818
|
logTitle(`Building optimised (minified) bundle of "${configName}" customer configuration...`);
|
|
1007
|
-
|
|
1008
|
-
runCommandSync(cmd, {
|
|
819
|
+
runCommandSync(`pnpm vite build`, {
|
|
1009
820
|
cwd: configsPackageRoot,
|
|
1010
|
-
env
|
|
821
|
+
env: {
|
|
822
|
+
BABEL: options.babel ? "true" : "false",
|
|
823
|
+
CONFIG_NAME: configName,
|
|
824
|
+
MINIFY: options.minify ? "true" : "false"
|
|
825
|
+
},
|
|
1011
826
|
stdio: "inherit"
|
|
1012
827
|
});
|
|
1013
828
|
logTitle(`\nBundle for "${configName}" customer configuration is done.`);
|
|
1014
|
-
console
|
|
829
|
+
console.log(`Path: ${outDir}\n`);
|
|
1015
830
|
process.on("exit", () => {
|
|
1016
831
|
notify({
|
|
1017
832
|
message: `Bundle for "${configName}" customer configuration is done.`,
|
|
@@ -1022,8 +837,9 @@ const build = async (options) => {
|
|
|
1022
837
|
if (options.deploy) await deploy(options);
|
|
1023
838
|
};
|
|
1024
839
|
const assertOptionsValid$5 = (options) => {
|
|
1025
|
-
const { profile } = options;
|
|
1026
|
-
if (
|
|
840
|
+
const { preview, profile } = options;
|
|
841
|
+
if (preview) assertCrtExists(getConfigsPackageRoot());
|
|
842
|
+
if (profile) assertAwsProfileValid(profile);
|
|
1027
843
|
};
|
|
1028
844
|
//#endregion
|
|
1029
845
|
//#region src/commands/deploy-email-config.ts
|
|
@@ -1032,28 +848,26 @@ const deployEmailConfig = async (options) => {
|
|
|
1032
848
|
const emailConfigPath = `${getInputDir(configName)}/email-config`;
|
|
1033
849
|
assertEmailConfigPathExists(emailConfigPath);
|
|
1034
850
|
if (!options.profile && !options.ci) {
|
|
1035
|
-
|
|
1036
|
-
options.profile = await
|
|
851
|
+
assertAwsProfilesPresent();
|
|
852
|
+
options.profile = await promptAwsProfile();
|
|
1037
853
|
}
|
|
1038
854
|
if (!options.bucket) options.bucket = options.ci ? AWS_S3_BUCKET_TAMARO_EMAIL_CONFIG_PROD : await promptBucketTamaroEmailConfig$1();
|
|
1039
855
|
assertOptionsValid$4(options);
|
|
1040
856
|
await validate();
|
|
1041
857
|
awsAuthenticate(options);
|
|
1042
|
-
const flags =
|
|
858
|
+
const flags = prepareAwsCliFlags(options);
|
|
1043
859
|
const dryRunFlag = options.dryrun ? `--dryrun` : "";
|
|
1044
860
|
const deployUrl = `s3://${options.bucket}/${configName}`;
|
|
1045
861
|
if (dryRunFlag) logTitle("🧪 DRY RUN MODE - No actual changes will be made 🧪");
|
|
1046
|
-
const cmd = `
|
|
1047
|
-
aws s3 sync ${emailConfigPath} ${deployUrl}
|
|
1048
|
-
--delete
|
|
1049
|
-
--exact-timestamps
|
|
1050
|
-
${flags}
|
|
1051
|
-
${dryRunFlag}
|
|
1052
|
-
`;
|
|
1053
|
-
logTitle(`Deploying email configuration for "${configName}" customer configuration to AWS S3...`);
|
|
1054
|
-
logCommand(cmd);
|
|
1055
862
|
try {
|
|
1056
|
-
|
|
863
|
+
logTitle(`Deploying email configuration for "${configName}" customer configuration to AWS S3...`);
|
|
864
|
+
runCommandSync(dedent`
|
|
865
|
+
aws s3 sync ${emailConfigPath} ${deployUrl}
|
|
866
|
+
--delete
|
|
867
|
+
--exact-timestamps
|
|
868
|
+
${flags}
|
|
869
|
+
${dryRunFlag}
|
|
870
|
+
`, { stdout: "inherit" });
|
|
1057
871
|
} catch (error) {
|
|
1058
872
|
halt(error.stderr);
|
|
1059
873
|
}
|
|
@@ -1068,7 +882,7 @@ const deployEmailConfig = async (options) => {
|
|
|
1068
882
|
};
|
|
1069
883
|
const assertOptionsValid$4 = (options) => {
|
|
1070
884
|
const { bucket, profile } = options;
|
|
1071
|
-
if (profile)
|
|
885
|
+
if (profile) assertAwsProfileValid(profile);
|
|
1072
886
|
if (bucket) assertBucketValid$1(bucket);
|
|
1073
887
|
};
|
|
1074
888
|
const assertEmailConfigPathExists = (distPath) => {
|
|
@@ -1097,27 +911,87 @@ const promptBucketTamaroEmailConfig$1 = async () => {
|
|
|
1097
911
|
const dev = async (options) => {
|
|
1098
912
|
const configName = getConfigName();
|
|
1099
913
|
const configsPackageRoot = getConfigsPackageRoot();
|
|
1100
|
-
|
|
1101
|
-
const
|
|
1102
|
-
...process.env,
|
|
1103
|
-
CONFIG_NAME: configName,
|
|
1104
|
-
LOCAL_CORE: options.localCore ? "true" : "false"
|
|
1105
|
-
};
|
|
914
|
+
assertCrtExists(configsPackageRoot);
|
|
915
|
+
const port = await getPortPromise({ port: Number(DEFAULT_PORT) });
|
|
1106
916
|
logTitle(`\nStarting Vite dev server for "${configName}" configuration...`);
|
|
1107
|
-
|
|
1108
|
-
|
|
917
|
+
runCommandSync(`pnpm vite dev --port ${port}`, {
|
|
918
|
+
cwd: configsPackageRoot,
|
|
919
|
+
env: {
|
|
920
|
+
CONFIG_NAME: configName,
|
|
921
|
+
LOCAL_CORE: options.localCore ? "true" : "false"
|
|
922
|
+
},
|
|
923
|
+
stdio: "inherit"
|
|
924
|
+
});
|
|
925
|
+
};
|
|
926
|
+
//#endregion
|
|
927
|
+
//#region src/commands/format.ts
|
|
928
|
+
const format = () => {
|
|
929
|
+
const configsPackageRoot = getConfigsPackageRoot();
|
|
930
|
+
const relativeCwd = path.relative(configsPackageRoot, process.cwd());
|
|
931
|
+
logTitle("Formatting root with Prettier...");
|
|
932
|
+
runCommandSync("pnpm prettier --write . \"!configs/**\"", {
|
|
933
|
+
cwd: configsPackageRoot,
|
|
934
|
+
shell: true,
|
|
935
|
+
stdio: "inherit"
|
|
936
|
+
});
|
|
937
|
+
logTitle(`\nFormatting config folder "${relativeCwd}" with Prettier...`);
|
|
938
|
+
runCommandSync(`pnpm prettier --write ${relativeCwd}`, {
|
|
939
|
+
cwd: configsPackageRoot,
|
|
940
|
+
shell: true,
|
|
941
|
+
stdio: "inherit"
|
|
942
|
+
});
|
|
943
|
+
};
|
|
944
|
+
//#endregion
|
|
945
|
+
//#region src/commands/lint.ts
|
|
946
|
+
const lint = () => {
|
|
947
|
+
const configsPackageRoot = getConfigsPackageRoot();
|
|
948
|
+
const relativeCwd = path.relative(configsPackageRoot, process.cwd());
|
|
949
|
+
const env = { DEBUG: "eslint:eslint-helpers" };
|
|
950
|
+
logTitle("Linting root with ESLint...");
|
|
951
|
+
runCommandSync("pnpm eslint --ignore-pattern \"configs/\" .", {
|
|
952
|
+
cwd: configsPackageRoot,
|
|
953
|
+
env,
|
|
954
|
+
shell: true,
|
|
955
|
+
stdio: "inherit"
|
|
956
|
+
});
|
|
957
|
+
logTitle(`\nLinting config folder "${relativeCwd}" with ESLint...`);
|
|
958
|
+
runCommandSync(`pnpm eslint ${relativeCwd}`, {
|
|
1109
959
|
cwd: configsPackageRoot,
|
|
1110
960
|
env,
|
|
961
|
+
shell: true,
|
|
1111
962
|
stdio: "inherit"
|
|
1112
963
|
});
|
|
1113
964
|
};
|
|
1114
965
|
//#endregion
|
|
966
|
+
//#region src/lib/aws.ts
|
|
967
|
+
const getConfigDeployments = async (configName) => {
|
|
968
|
+
const widgetJs = (await new S3({}).listObjectsV2({
|
|
969
|
+
Bucket: "tamaro.raisenow.com",
|
|
970
|
+
Prefix: `${configName}/`
|
|
971
|
+
})).Contents?.filter((file) => file.Key?.endsWith(`/index.html`)) ?? [];
|
|
972
|
+
const deployments = [];
|
|
973
|
+
for (const file of widgetJs) {
|
|
974
|
+
const key = file.Key ?? "";
|
|
975
|
+
const parts = key.split("/");
|
|
976
|
+
if (parts.length < 2 || !file.LastModified) continue;
|
|
977
|
+
const tag = parts.at(-2);
|
|
978
|
+
const date = file.LastModified.toISOString();
|
|
979
|
+
const fullUrl = `https://${AWS_S3_BUCKET_TAMARO}/${key}`;
|
|
980
|
+
deployments.push({
|
|
981
|
+
date,
|
|
982
|
+
fullUrl,
|
|
983
|
+
tag
|
|
984
|
+
});
|
|
985
|
+
}
|
|
986
|
+
return deployments;
|
|
987
|
+
};
|
|
988
|
+
//#endregion
|
|
1115
989
|
//#region src/commands/list-deployed.ts
|
|
1116
990
|
const listDeployed = async (options) => {
|
|
1117
991
|
const configName = getConfigName();
|
|
1118
992
|
if (!options.profile && !options.ci) {
|
|
1119
|
-
|
|
1120
|
-
options.profile = await
|
|
993
|
+
assertAwsProfilesPresent();
|
|
994
|
+
options.profile = await promptAwsProfile();
|
|
1121
995
|
}
|
|
1122
996
|
assertOptionsValid$3(options);
|
|
1123
997
|
awsAuthenticate(options);
|
|
@@ -1148,7 +1022,18 @@ const listDeployed = async (options) => {
|
|
|
1148
1022
|
};
|
|
1149
1023
|
const assertOptionsValid$3 = (options) => {
|
|
1150
1024
|
const { profile } = options;
|
|
1151
|
-
if (profile)
|
|
1025
|
+
if (profile) assertAwsProfileValid(profile);
|
|
1026
|
+
};
|
|
1027
|
+
//#endregion
|
|
1028
|
+
//#region src/commands/typecheck.ts
|
|
1029
|
+
const typecheck = () => {
|
|
1030
|
+
const configsPackageRoot = getConfigsPackageRoot();
|
|
1031
|
+
const relativeCwd = path.relative(configsPackageRoot, process.cwd());
|
|
1032
|
+
logTitle("Running TypeScript type-checking...");
|
|
1033
|
+
runCommandSync(`pnpm tsc --project ${relativeCwd}/tsconfig.json`, {
|
|
1034
|
+
cwd: configsPackageRoot,
|
|
1035
|
+
stdio: "inherit"
|
|
1036
|
+
});
|
|
1152
1037
|
};
|
|
1153
1038
|
//#endregion
|
|
1154
1039
|
//#region src/commands/unarchive.ts
|
|
@@ -1209,7 +1094,7 @@ const unarchiveEpms = async (configName, dryrun) => {
|
|
|
1209
1094
|
};
|
|
1210
1095
|
const assertOptionsValid$2 = (options) => {
|
|
1211
1096
|
const { profile } = options;
|
|
1212
|
-
if (profile)
|
|
1097
|
+
if (profile) assertAwsProfileValid(profile);
|
|
1213
1098
|
};
|
|
1214
1099
|
const assertIsArchived = () => {
|
|
1215
1100
|
if (path.basename(path.dirname(process.cwd())) !== "_archived") halt("This configuration is not archived. Only archived configurations can be unarchived.");
|
|
@@ -1222,42 +1107,39 @@ const assertRestoreTargetDoesNotExist = (restoreTarget) => {
|
|
|
1222
1107
|
const undeploy = async (options) => {
|
|
1223
1108
|
const configName = getConfigName();
|
|
1224
1109
|
if (!options.profile && !options.ci) {
|
|
1225
|
-
|
|
1226
|
-
options.profile = await
|
|
1110
|
+
assertAwsProfilesPresent();
|
|
1111
|
+
options.profile = await promptAwsProfile();
|
|
1227
1112
|
}
|
|
1228
1113
|
assertOptionsValid$1(options);
|
|
1229
1114
|
awsAuthenticate(options);
|
|
1230
|
-
const flags =
|
|
1115
|
+
const flags = prepareAwsCliFlags(options);
|
|
1231
1116
|
const { all, dryrun, tag = DEFAULT_TAG } = options;
|
|
1232
1117
|
const dryRunFlag = dryrun ? `--dryrun` : "";
|
|
1233
1118
|
const deployUrl = all ? `s3://${AWS_S3_BUCKET_TAMARO}/${configName}/` : `s3://${AWS_S3_BUCKET_TAMARO}/${configName}/${tag}/`;
|
|
1234
1119
|
const description = all ? `all tags of "${configName}"` : `tag "${tag}" of "${configName}"`;
|
|
1235
1120
|
if (dryRunFlag) logTitle("🧪 DRY RUN MODE - No actual changes will be made 🧪");
|
|
1236
|
-
await promptConfirmation(`Are you sure you want to undeploy ${description}
|
|
1237
|
-
const cmd = `
|
|
1238
|
-
aws s3 rm ${deployUrl}
|
|
1239
|
-
--recursive
|
|
1240
|
-
${flags}
|
|
1241
|
-
${dryRunFlag}
|
|
1242
|
-
`;
|
|
1243
|
-
logTitle(`Undeploying ${description} from AWS S3...`);
|
|
1244
|
-
logCommand(cmd);
|
|
1121
|
+
if (!options.ci) await promptConfirmation(`Are you sure you want to undeploy ${description}?`);
|
|
1245
1122
|
try {
|
|
1246
|
-
|
|
1123
|
+
logTitle(`Undeploying ${description} from AWS S3...`);
|
|
1124
|
+
runCommandSync(dedent`
|
|
1125
|
+
aws s3 rm ${deployUrl}
|
|
1126
|
+
--recursive
|
|
1127
|
+
${flags}
|
|
1128
|
+
${dryRunFlag}
|
|
1129
|
+
`, { stdout: "inherit" });
|
|
1247
1130
|
} catch (error) {
|
|
1248
1131
|
halt(error.stderr);
|
|
1249
1132
|
}
|
|
1250
1133
|
if (!dryRunFlag) {
|
|
1251
|
-
const
|
|
1252
|
-
aws cloudfront create-invalidation
|
|
1253
|
-
--distribution-id ${AWS_CLOUDFRONT_DISTRIBUTION_ID}
|
|
1254
|
-
--paths ${all ? `/${configName}/*` : `/${configName}/${tag}/*`}
|
|
1255
|
-
${flags}
|
|
1256
|
-
`;
|
|
1257
|
-
logTitle("\nInvalidating edge cache...");
|
|
1258
|
-
logCommand(cmdInvalidateCache);
|
|
1134
|
+
const invalidationPath = all ? `/${configName}/*` : `/${configName}/${tag}/*`;
|
|
1259
1135
|
try {
|
|
1260
|
-
|
|
1136
|
+
logTitle("\nInvalidating edge cache...");
|
|
1137
|
+
runCommandSync(dedent`
|
|
1138
|
+
aws cloudfront create-invalidation
|
|
1139
|
+
--distribution-id ${AWS_CLOUDFRONT_DISTRIBUTION_ID}
|
|
1140
|
+
--paths ${invalidationPath}
|
|
1141
|
+
${flags}
|
|
1142
|
+
`);
|
|
1261
1143
|
} catch (error) {
|
|
1262
1144
|
halt(error.stderr);
|
|
1263
1145
|
}
|
|
@@ -1273,7 +1155,7 @@ const undeploy = async (options) => {
|
|
|
1273
1155
|
};
|
|
1274
1156
|
const assertOptionsValid$1 = (options) => {
|
|
1275
1157
|
const { all, profile, tag } = options;
|
|
1276
|
-
if (profile)
|
|
1158
|
+
if (profile) assertAwsProfileValid(profile);
|
|
1277
1159
|
if (all && tag) halt("Flags \"--tag\" and \"--all\" must not be used together.");
|
|
1278
1160
|
if (!all && tag) assertTagValid(tag);
|
|
1279
1161
|
};
|
|
@@ -1282,8 +1164,8 @@ const assertOptionsValid$1 = (options) => {
|
|
|
1282
1164
|
const undeployEmailConfig = async (options) => {
|
|
1283
1165
|
const configName = getConfigName();
|
|
1284
1166
|
if (!options.profile && !options.ci) {
|
|
1285
|
-
|
|
1286
|
-
options.profile = await
|
|
1167
|
+
assertAwsProfilesPresent();
|
|
1168
|
+
options.profile = await promptAwsProfile();
|
|
1287
1169
|
}
|
|
1288
1170
|
if (options.ci) options.bucket = AWS_S3_BUCKET_TAMARO_EMAIL_CONFIG_PROD;
|
|
1289
1171
|
if (!options.bucket) if (options.ci) options.bucket = AWS_S3_BUCKET_TAMARO_EMAIL_CONFIG_PROD;
|
|
@@ -1292,21 +1174,19 @@ const undeployEmailConfig = async (options) => {
|
|
|
1292
1174
|
else options.bucket = await promptBucketTamaroEmailConfig();
|
|
1293
1175
|
assertOptionsValid(options);
|
|
1294
1176
|
awsAuthenticate(options);
|
|
1295
|
-
const flags =
|
|
1177
|
+
const flags = prepareAwsCliFlags(options);
|
|
1296
1178
|
const dryRunFlag = options.dryrun ? `--dryrun` : "";
|
|
1297
1179
|
const deployUrl = `s3://${options.bucket}/${configName}/`;
|
|
1298
|
-
await promptConfirmation(`Are you sure you want to undeploy the email configuration for "${configName}" from "${options.bucket}"
|
|
1180
|
+
if (!options.ci) await promptConfirmation(`Are you sure you want to undeploy the email configuration for "${configName}" from "${options.bucket}"?`);
|
|
1299
1181
|
if (dryRunFlag) logTitle("🧪 DRY RUN MODE - No actual changes will be made 🧪");
|
|
1300
|
-
const cmd = `
|
|
1301
|
-
aws s3 rm ${deployUrl}
|
|
1302
|
-
--recursive
|
|
1303
|
-
${flags}
|
|
1304
|
-
${dryRunFlag}
|
|
1305
|
-
`;
|
|
1306
|
-
logTitle(`Undeploying email configuration for "${configName}" from AWS S3...`);
|
|
1307
|
-
logCommand(cmd);
|
|
1308
1182
|
try {
|
|
1309
|
-
|
|
1183
|
+
logTitle(`Undeploying email configuration for "${configName}" from AWS S3...`);
|
|
1184
|
+
runCommandSync(dedent`
|
|
1185
|
+
aws s3 rm ${deployUrl}
|
|
1186
|
+
--recursive
|
|
1187
|
+
${flags}
|
|
1188
|
+
${dryRunFlag}
|
|
1189
|
+
`, { stdout: "inherit" });
|
|
1310
1190
|
} catch (error) {
|
|
1311
1191
|
halt(error.stderr);
|
|
1312
1192
|
}
|
|
@@ -1321,7 +1201,7 @@ const undeployEmailConfig = async (options) => {
|
|
|
1321
1201
|
};
|
|
1322
1202
|
const assertOptionsValid = (options) => {
|
|
1323
1203
|
const { bucket, profile } = options;
|
|
1324
|
-
if (profile)
|
|
1204
|
+
if (profile) assertAwsProfileValid(profile);
|
|
1325
1205
|
if (bucket) assertBucketValid(bucket);
|
|
1326
1206
|
};
|
|
1327
1207
|
const assertBucketValid = (bucket) => {
|
|
@@ -1345,30 +1225,25 @@ const promptBucketTamaroEmailConfig = async () => {
|
|
|
1345
1225
|
//#endregion
|
|
1346
1226
|
//#region package.json
|
|
1347
1227
|
var name = "@raisenow/tamaro-cli";
|
|
1348
|
-
var version = "3.0.0-dev.
|
|
1228
|
+
var version = "3.0.0-dev.3";
|
|
1349
1229
|
//#endregion
|
|
1350
1230
|
//#region src/cli.ts
|
|
1351
|
-
/**
|
|
1352
|
-
* Makes the script crash on unhandled rejections instead of silently
|
|
1353
|
-
* ignoring them. In the future, promise rejections that are not handled will
|
|
1354
|
-
* terminate the Node.js process with a non-zero exit code.
|
|
1355
|
-
*/
|
|
1356
|
-
process.on("unhandledRejection", (error) => {
|
|
1357
|
-
throw error;
|
|
1358
|
-
});
|
|
1359
1231
|
const cli = createCommand().name(name).description("CLI for Tamaro Customer Configurations development").version(version, "-v, --version");
|
|
1360
1232
|
cli.command("dev").description("Run the local dev-server").option("--local-core", "Load Tamaro Core from \"https://localhost:1234/src/index.ts\" rather than from CDN", false).action(dev);
|
|
1361
1233
|
cli.command("build").description("Build an optimised (minified) bundle").option("--preview", "Run a local web server for pre-built bundle", false).option("--babel", "Use Babel for transpilation", true).option("--no-babel", "Do not use Babel for transpilation").option("--minify", "Minify the bundle", true).option("--no-minify", "Do not minify the bundle").option("--profile <profile>", "AWS profile").option("--ci", "CI environment", false).option("--deploy", "Deploy customer configuration bundle to AWS S3", false).option("--force-skip-epms-sync", "Skip the EPMS sync entirely. Only use this in emergencies.", false).option("--tag <tag>", "Tag which should be used for the deployment of the bundle", DEFAULT_TAG).action(build);
|
|
1362
1234
|
cli.command("preview").description("Run a local web server for pre-built bundle").action(preview);
|
|
1363
|
-
cli.command("deploy").description("Deploy a pre-built
|
|
1235
|
+
cli.command("deploy").description("Deploy a pre-built customer configuration bundle to AWS S3").option("--profile <profile>", "AWS profile").option("--ci", "CI environment", false).option("--tag <tag>", "Tag which should be used for the deployment of the bundle", DEFAULT_TAG).option("--dryrun", "Displays the operations that would be performed without actually running them", false).option("--force-skip-epms-sync", "Skip the EPMS sync entirely. Only use this in emergencies.", false).action(deploy);
|
|
1364
1236
|
cli.command("list-deployed").description("List deployments of customer configuration").option("--profile <profile>", "AWS profile").option("--ci", "CI environment", false).action(listDeployed);
|
|
1365
1237
|
cli.command("deploy-email-config").description("Deploy a widget's email configuration to AWS S3").option("--profile <profile>", "AWS profile").option("--ci", "CI environment", false).option("--bucket <bucket>", "AWS bucket for email configs").option("--dryrun", "Displays the operations that would be performed without actually running them", false).action(deployEmailConfig);
|
|
1366
|
-
cli.command("undeploy").description("Undeploy a
|
|
1238
|
+
cli.command("undeploy").description("Undeploy a customer configuration bundle from AWS S3").option("--profile <profile>", "AWS profile").option("--ci", "CI environment", false).option("--tag <tag>", "Tag which should be undeployed").option("--all", "Undeploy all tags", false).option("--dryrun", "Displays the operations that would be performed without actually running them", false).action(undeploy);
|
|
1367
1239
|
cli.command("undeploy-email-config").description("Undeploy a widget's email configuration from AWS S3").option("--profile <profile>", "AWS profile").option("--ci", "CI environment", false).option("--bucket <bucket>", "AWS bucket for email configs").option("--stage", "Undeploy from stage environment (alternative to --bucket)").option("--prod", "Undeploy from prod environment (alternative to --bucket)").option("--dryrun", "Displays the operations that would be performed without actually running them", false).action(undeployEmailConfig);
|
|
1368
1240
|
cli.command("archive").description("Archive a customer configuration by moving it to the _archived folder").option("--profile <profile>", "AWS profile").option("--ci", "CI environment", false).option("--dryrun", "Displays the operations that would be performed without actually running them", false).option("--force-skip-epms-sync", "Skip EPMS archive sync (emergency use only)", false).action(archive);
|
|
1369
1241
|
cli.command("unarchive").description("Unarchive a customer configuration by restoring it from the _archived folder").option("--profile <profile>", "AWS profile").option("--ci", "CI environment", false).option("--dryrun", "Displays the operations that would be performed without actually running them", false).option("--force-skip-epms-sync", "Skip EPMS unarchive sync (emergency use only)", false).action(unarchive);
|
|
1370
1242
|
cli.command("update-epms").description("Update EPMS with the currently deployed widget tags.").option("--profile <profile>", "AWS profile").option("--ci", "CI environment", false).option("--dryrun", "Displays the operations that would be performed without actually running them", false).option("--tag <tag>", "Tag which should be set for the deployment", DEFAULT_TAG).action(updateEpms);
|
|
1371
1243
|
cli.command("validate").description("Validate the current Tamaro configuration to avoid common errors").action(validate);
|
|
1244
|
+
cli.command("typecheck").description("Typecheck the current Tamaro configuration").action(typecheck);
|
|
1245
|
+
cli.command("lint").description("Lint the current Tamaro configuration with ESLint").action(lint);
|
|
1246
|
+
cli.command("format").description("Format the current Tamaro configuration with Prettier").action(format);
|
|
1372
1247
|
try {
|
|
1373
1248
|
logTitle(`${name} ${version}\n`);
|
|
1374
1249
|
await cli.parseAsync(process.argv);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@raisenow/tamaro-cli",
|
|
3
|
-
"version": "3.0.0-dev.
|
|
3
|
+
"version": "3.0.0-dev.3",
|
|
4
4
|
"author": {
|
|
5
5
|
"name": "RaiseNow",
|
|
6
6
|
"email": "development@raisenow.com"
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@aws-sdk/client-s3": "^3.1068.0",
|
|
17
|
-
"
|
|
17
|
+
"@rnw-npm/cli-helpers": "^2.0.0-dev.1",
|
|
18
18
|
"columnify": "^1.6.0",
|
|
19
19
|
"commander": "^14.0.3",
|
|
20
20
|
"dedent": "^1.7.2",
|
|
@@ -22,11 +22,10 @@
|
|
|
22
22
|
"env-paths": "^4.0.0",
|
|
23
23
|
"execa": "^9.6.1",
|
|
24
24
|
"glob": "^13.0.6",
|
|
25
|
-
"handlebars-helpers": "^0.10.0",
|
|
26
25
|
"handlebars": "^4.7.9",
|
|
26
|
+
"handlebars-helpers": "^0.10.0",
|
|
27
27
|
"js-yaml": "^4.2.0",
|
|
28
28
|
"ky": "^1.14.3",
|
|
29
|
-
"node-notifier": "^10.0.1",
|
|
30
29
|
"open": "^11.0.0",
|
|
31
30
|
"portfinder": "^1.0.38",
|
|
32
31
|
"prompts": "^2.4.2",
|
|
@@ -38,7 +37,6 @@
|
|
|
38
37
|
"@types/columnify": "^1.5.4",
|
|
39
38
|
"@types/handlebars-helpers": "^0.5.6",
|
|
40
39
|
"@types/js-yaml": "^4.0.9",
|
|
41
|
-
"@types/node-notifier": "^8.0.5",
|
|
42
40
|
"@types/node": "^24.13.2",
|
|
43
41
|
"@types/prompts": "^2.4.9",
|
|
44
42
|
"eslint": "^10.5.0",
|