@raisenow/tamaro-cli 3.0.0-dev.2 → 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/dist/cli.js +154 -344
- package/package.json +3 -5
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,17 +911,15 @@ 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
|
-
runCommandSync(cmd, {
|
|
917
|
+
runCommandSync(`pnpm vite dev --port ${port}`, {
|
|
1109
918
|
cwd: configsPackageRoot,
|
|
1110
|
-
env
|
|
919
|
+
env: {
|
|
920
|
+
CONFIG_NAME: configName,
|
|
921
|
+
LOCAL_CORE: options.localCore ? "true" : "false"
|
|
922
|
+
},
|
|
1111
923
|
stdio: "inherit"
|
|
1112
924
|
});
|
|
1113
925
|
};
|
|
@@ -1116,18 +928,14 @@ const dev = async (options) => {
|
|
|
1116
928
|
const format = () => {
|
|
1117
929
|
const configsPackageRoot = getConfigsPackageRoot();
|
|
1118
930
|
const relativeCwd = path.relative(configsPackageRoot, process.cwd());
|
|
1119
|
-
const cmd1 = "pnpm prettier --write . \"!configs/**\"";
|
|
1120
931
|
logTitle("Formatting root with Prettier...");
|
|
1121
|
-
|
|
1122
|
-
runCommandSync(cmd1, {
|
|
932
|
+
runCommandSync("pnpm prettier --write . \"!configs/**\"", {
|
|
1123
933
|
cwd: configsPackageRoot,
|
|
1124
934
|
shell: true,
|
|
1125
935
|
stdio: "inherit"
|
|
1126
936
|
});
|
|
1127
|
-
const cmd2 = `pnpm prettier --write ${relativeCwd}`;
|
|
1128
937
|
logTitle(`\nFormatting config folder "${relativeCwd}" with Prettier...`);
|
|
1129
|
-
|
|
1130
|
-
runCommandSync(cmd2, {
|
|
938
|
+
runCommandSync(`pnpm prettier --write ${relativeCwd}`, {
|
|
1131
939
|
cwd: configsPackageRoot,
|
|
1132
940
|
shell: true,
|
|
1133
941
|
stdio: "inherit"
|
|
@@ -1138,23 +946,16 @@ const format = () => {
|
|
|
1138
946
|
const lint = () => {
|
|
1139
947
|
const configsPackageRoot = getConfigsPackageRoot();
|
|
1140
948
|
const relativeCwd = path.relative(configsPackageRoot, process.cwd());
|
|
1141
|
-
const env = {
|
|
1142
|
-
...process.env,
|
|
1143
|
-
DEBUG: "eslint:eslint-helpers"
|
|
1144
|
-
};
|
|
1145
|
-
const cmd1 = "pnpm eslint --ignore-pattern \"configs/\" .";
|
|
949
|
+
const env = { DEBUG: "eslint:eslint-helpers" };
|
|
1146
950
|
logTitle("Linting root with ESLint...");
|
|
1147
|
-
|
|
1148
|
-
runCommandSync(cmd1, {
|
|
951
|
+
runCommandSync("pnpm eslint --ignore-pattern \"configs/\" .", {
|
|
1149
952
|
cwd: configsPackageRoot,
|
|
1150
953
|
env,
|
|
1151
954
|
shell: true,
|
|
1152
955
|
stdio: "inherit"
|
|
1153
956
|
});
|
|
1154
|
-
const cmd2 = `pnpm eslint ${relativeCwd}`;
|
|
1155
957
|
logTitle(`\nLinting config folder "${relativeCwd}" with ESLint...`);
|
|
1156
|
-
|
|
1157
|
-
runCommandSync(cmd2, {
|
|
958
|
+
runCommandSync(`pnpm eslint ${relativeCwd}`, {
|
|
1158
959
|
cwd: configsPackageRoot,
|
|
1159
960
|
env,
|
|
1160
961
|
shell: true,
|
|
@@ -1162,12 +963,35 @@ const lint = () => {
|
|
|
1162
963
|
});
|
|
1163
964
|
};
|
|
1164
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
|
|
1165
989
|
//#region src/commands/list-deployed.ts
|
|
1166
990
|
const listDeployed = async (options) => {
|
|
1167
991
|
const configName = getConfigName();
|
|
1168
992
|
if (!options.profile && !options.ci) {
|
|
1169
|
-
|
|
1170
|
-
options.profile = await
|
|
993
|
+
assertAwsProfilesPresent();
|
|
994
|
+
options.profile = await promptAwsProfile();
|
|
1171
995
|
}
|
|
1172
996
|
assertOptionsValid$3(options);
|
|
1173
997
|
awsAuthenticate(options);
|
|
@@ -1198,16 +1022,15 @@ const listDeployed = async (options) => {
|
|
|
1198
1022
|
};
|
|
1199
1023
|
const assertOptionsValid$3 = (options) => {
|
|
1200
1024
|
const { profile } = options;
|
|
1201
|
-
if (profile)
|
|
1025
|
+
if (profile) assertAwsProfileValid(profile);
|
|
1202
1026
|
};
|
|
1203
1027
|
//#endregion
|
|
1204
1028
|
//#region src/commands/typecheck.ts
|
|
1205
1029
|
const typecheck = () => {
|
|
1206
1030
|
const configsPackageRoot = getConfigsPackageRoot();
|
|
1207
|
-
const
|
|
1031
|
+
const relativeCwd = path.relative(configsPackageRoot, process.cwd());
|
|
1208
1032
|
logTitle("Running TypeScript type-checking...");
|
|
1209
|
-
|
|
1210
|
-
runCommandSync(cmd, {
|
|
1033
|
+
runCommandSync(`pnpm tsc --project ${relativeCwd}/tsconfig.json`, {
|
|
1211
1034
|
cwd: configsPackageRoot,
|
|
1212
1035
|
stdio: "inherit"
|
|
1213
1036
|
});
|
|
@@ -1271,7 +1094,7 @@ const unarchiveEpms = async (configName, dryrun) => {
|
|
|
1271
1094
|
};
|
|
1272
1095
|
const assertOptionsValid$2 = (options) => {
|
|
1273
1096
|
const { profile } = options;
|
|
1274
|
-
if (profile)
|
|
1097
|
+
if (profile) assertAwsProfileValid(profile);
|
|
1275
1098
|
};
|
|
1276
1099
|
const assertIsArchived = () => {
|
|
1277
1100
|
if (path.basename(path.dirname(process.cwd())) !== "_archived") halt("This configuration is not archived. Only archived configurations can be unarchived.");
|
|
@@ -1284,42 +1107,39 @@ const assertRestoreTargetDoesNotExist = (restoreTarget) => {
|
|
|
1284
1107
|
const undeploy = async (options) => {
|
|
1285
1108
|
const configName = getConfigName();
|
|
1286
1109
|
if (!options.profile && !options.ci) {
|
|
1287
|
-
|
|
1288
|
-
options.profile = await
|
|
1110
|
+
assertAwsProfilesPresent();
|
|
1111
|
+
options.profile = await promptAwsProfile();
|
|
1289
1112
|
}
|
|
1290
1113
|
assertOptionsValid$1(options);
|
|
1291
1114
|
awsAuthenticate(options);
|
|
1292
|
-
const flags =
|
|
1115
|
+
const flags = prepareAwsCliFlags(options);
|
|
1293
1116
|
const { all, dryrun, tag = DEFAULT_TAG } = options;
|
|
1294
1117
|
const dryRunFlag = dryrun ? `--dryrun` : "";
|
|
1295
1118
|
const deployUrl = all ? `s3://${AWS_S3_BUCKET_TAMARO}/${configName}/` : `s3://${AWS_S3_BUCKET_TAMARO}/${configName}/${tag}/`;
|
|
1296
1119
|
const description = all ? `all tags of "${configName}"` : `tag "${tag}" of "${configName}"`;
|
|
1297
1120
|
if (dryRunFlag) logTitle("🧪 DRY RUN MODE - No actual changes will be made 🧪");
|
|
1298
|
-
await promptConfirmation(`Are you sure you want to undeploy ${description}
|
|
1299
|
-
const cmd = `
|
|
1300
|
-
aws s3 rm ${deployUrl}
|
|
1301
|
-
--recursive
|
|
1302
|
-
${flags}
|
|
1303
|
-
${dryRunFlag}
|
|
1304
|
-
`;
|
|
1305
|
-
logTitle(`Undeploying ${description} from AWS S3...`);
|
|
1306
|
-
logCommand(cmd);
|
|
1121
|
+
if (!options.ci) await promptConfirmation(`Are you sure you want to undeploy ${description}?`);
|
|
1307
1122
|
try {
|
|
1308
|
-
|
|
1123
|
+
logTitle(`Undeploying ${description} from AWS S3...`);
|
|
1124
|
+
runCommandSync(dedent`
|
|
1125
|
+
aws s3 rm ${deployUrl}
|
|
1126
|
+
--recursive
|
|
1127
|
+
${flags}
|
|
1128
|
+
${dryRunFlag}
|
|
1129
|
+
`, { stdout: "inherit" });
|
|
1309
1130
|
} catch (error) {
|
|
1310
1131
|
halt(error.stderr);
|
|
1311
1132
|
}
|
|
1312
1133
|
if (!dryRunFlag) {
|
|
1313
|
-
const
|
|
1314
|
-
aws cloudfront create-invalidation
|
|
1315
|
-
--distribution-id ${AWS_CLOUDFRONT_DISTRIBUTION_ID}
|
|
1316
|
-
--paths ${all ? `/${configName}/*` : `/${configName}/${tag}/*`}
|
|
1317
|
-
${flags}
|
|
1318
|
-
`;
|
|
1319
|
-
logTitle("\nInvalidating edge cache...");
|
|
1320
|
-
logCommand(cmdInvalidateCache);
|
|
1134
|
+
const invalidationPath = all ? `/${configName}/*` : `/${configName}/${tag}/*`;
|
|
1321
1135
|
try {
|
|
1322
|
-
|
|
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
|
+
`);
|
|
1323
1143
|
} catch (error) {
|
|
1324
1144
|
halt(error.stderr);
|
|
1325
1145
|
}
|
|
@@ -1335,7 +1155,7 @@ const undeploy = async (options) => {
|
|
|
1335
1155
|
};
|
|
1336
1156
|
const assertOptionsValid$1 = (options) => {
|
|
1337
1157
|
const { all, profile, tag } = options;
|
|
1338
|
-
if (profile)
|
|
1158
|
+
if (profile) assertAwsProfileValid(profile);
|
|
1339
1159
|
if (all && tag) halt("Flags \"--tag\" and \"--all\" must not be used together.");
|
|
1340
1160
|
if (!all && tag) assertTagValid(tag);
|
|
1341
1161
|
};
|
|
@@ -1344,8 +1164,8 @@ const assertOptionsValid$1 = (options) => {
|
|
|
1344
1164
|
const undeployEmailConfig = async (options) => {
|
|
1345
1165
|
const configName = getConfigName();
|
|
1346
1166
|
if (!options.profile && !options.ci) {
|
|
1347
|
-
|
|
1348
|
-
options.profile = await
|
|
1167
|
+
assertAwsProfilesPresent();
|
|
1168
|
+
options.profile = await promptAwsProfile();
|
|
1349
1169
|
}
|
|
1350
1170
|
if (options.ci) options.bucket = AWS_S3_BUCKET_TAMARO_EMAIL_CONFIG_PROD;
|
|
1351
1171
|
if (!options.bucket) if (options.ci) options.bucket = AWS_S3_BUCKET_TAMARO_EMAIL_CONFIG_PROD;
|
|
@@ -1354,21 +1174,19 @@ const undeployEmailConfig = async (options) => {
|
|
|
1354
1174
|
else options.bucket = await promptBucketTamaroEmailConfig();
|
|
1355
1175
|
assertOptionsValid(options);
|
|
1356
1176
|
awsAuthenticate(options);
|
|
1357
|
-
const flags =
|
|
1177
|
+
const flags = prepareAwsCliFlags(options);
|
|
1358
1178
|
const dryRunFlag = options.dryrun ? `--dryrun` : "";
|
|
1359
1179
|
const deployUrl = `s3://${options.bucket}/${configName}/`;
|
|
1360
|
-
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}"?`);
|
|
1361
1181
|
if (dryRunFlag) logTitle("🧪 DRY RUN MODE - No actual changes will be made 🧪");
|
|
1362
|
-
const cmd = `
|
|
1363
|
-
aws s3 rm ${deployUrl}
|
|
1364
|
-
--recursive
|
|
1365
|
-
${flags}
|
|
1366
|
-
${dryRunFlag}
|
|
1367
|
-
`;
|
|
1368
|
-
logTitle(`Undeploying email configuration for "${configName}" from AWS S3...`);
|
|
1369
|
-
logCommand(cmd);
|
|
1370
1182
|
try {
|
|
1371
|
-
|
|
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" });
|
|
1372
1190
|
} catch (error) {
|
|
1373
1191
|
halt(error.stderr);
|
|
1374
1192
|
}
|
|
@@ -1383,7 +1201,7 @@ const undeployEmailConfig = async (options) => {
|
|
|
1383
1201
|
};
|
|
1384
1202
|
const assertOptionsValid = (options) => {
|
|
1385
1203
|
const { bucket, profile } = options;
|
|
1386
|
-
if (profile)
|
|
1204
|
+
if (profile) assertAwsProfileValid(profile);
|
|
1387
1205
|
if (bucket) assertBucketValid(bucket);
|
|
1388
1206
|
};
|
|
1389
1207
|
const assertBucketValid = (bucket) => {
|
|
@@ -1407,25 +1225,17 @@ const promptBucketTamaroEmailConfig = async () => {
|
|
|
1407
1225
|
//#endregion
|
|
1408
1226
|
//#region package.json
|
|
1409
1227
|
var name = "@raisenow/tamaro-cli";
|
|
1410
|
-
var version = "3.0.0-dev.
|
|
1228
|
+
var version = "3.0.0-dev.3";
|
|
1411
1229
|
//#endregion
|
|
1412
1230
|
//#region src/cli.ts
|
|
1413
|
-
/**
|
|
1414
|
-
* Makes the script crash on unhandled rejections instead of silently
|
|
1415
|
-
* ignoring them. In the future, promise rejections that are not handled will
|
|
1416
|
-
* terminate the Node.js process with a non-zero exit code.
|
|
1417
|
-
*/
|
|
1418
|
-
process.on("unhandledRejection", (error) => {
|
|
1419
|
-
throw error;
|
|
1420
|
-
});
|
|
1421
1231
|
const cli = createCommand().name(name).description("CLI for Tamaro Customer Configurations development").version(version, "-v, --version");
|
|
1422
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);
|
|
1423
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);
|
|
1424
1234
|
cli.command("preview").description("Run a local web server for pre-built bundle").action(preview);
|
|
1425
|
-
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);
|
|
1426
1236
|
cli.command("list-deployed").description("List deployments of customer configuration").option("--profile <profile>", "AWS profile").option("--ci", "CI environment", false).action(listDeployed);
|
|
1427
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);
|
|
1428
|
-
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);
|
|
1429
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);
|
|
1430
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);
|
|
1431
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);
|
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",
|