@raisenow/tamaro-cli 1.7.0-dev.0 → 1.7.0-dev.2
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/.eslintignore +7 -0
- package/.eslintrc.cjs +148 -0
- package/.history/.eslintignore_20220609190420 +4 -0
- package/.history/.eslintignore_20230911190227 +6 -0
- package/.history/.eslintignore_20230911211247 +7 -0
- package/.history/.eslintignore_20230911211250 +7 -0
- package/.history/.eslintrc_20230911201601.js +49 -0
- package/.history/.eslintrc_20230911201643.js +49 -0
- package/.history/.eslintrc_20230911201735.js +49 -0
- package/.history/.eslintrc_20230911201913.js +64 -0
- package/.history/.eslintrc_20230911202002.js +62 -0
- package/.history/.eslintrc_20230911202138.js +133 -0
- package/.history/.eslintrc_20230911202140.js +133 -0
- package/.history/.eslintrc_20230911202145.js +133 -0
- package/.history/.eslintrc_20230911202147.js +133 -0
- package/.history/.eslintrc_20230911202406.js +133 -0
- package/.history/.eslintrc_20230911202447.js +133 -0
- package/.history/.eslintrc_20230911202453.js +133 -0
- package/.history/.eslintrc_20230911202511.js +133 -0
- package/.history/.eslintrc_20230911202527.js +133 -0
- package/.history/.eslintrc_20230911202639.js +125 -0
- package/.history/.eslintrc_20230911202721.js +149 -0
- package/.history/.eslintrc_20230911202746.js +149 -0
- package/.history/.eslintrc_20240423125702.cjs +148 -0
- package/.history/.gitignore_20220609190420 +14 -0
- package/.history/.gitignore_20230911185959 +4 -0
- package/.history/.gitignore_20230911190006 +4 -0
- package/.history/.gitignore_20230911190007 +4 -0
- package/.history/.nmprc_20241004144025 +0 -0
- package/.history/.nmprc_20241004144041 +1 -0
- package/.history/.npmrc_20241004144040 +1 -0
- package/.history/.npmrc_20241004144152 +1 -0
- package/.history/.npmrc_20241004145639 +2 -0
- package/.history/.npmrc_20241004145649 +1 -0
- package/.history/.nvmrc_20250729181039 +1 -0
- package/.history/.prettierignore_20220609190420 +5 -0
- package/.history/.prettierignore_20230911190242 +7 -0
- package/.history/.prettierignore_20230911190245 +7 -0
- package/.history/.prettierignore_20230911211301 +8 -0
- package/.history/CHANGELOG_20250729195139.md +28 -0
- package/.history/CHANGELOG_20250729195148.md +29 -0
- package/.history/CHANGELOG_20250729195156.md +28 -0
- package/.history/CHANGELOG_20250729195218.md +29 -0
- package/.history/CHANGELOG_20250729195223.md +27 -0
- package/.history/CHANGELOG_20250729195506.md +29 -0
- package/.history/CHANGELOG_20250729224404.md +30 -0
- package/.history/CHANGELOG_20250729224411.md +30 -0
- package/.history/CHANGELOG_20250730124538.md +41 -0
- package/.history/CHANGELOG_20250730124603.md +38 -0
- package/.history/CHANGELOG_20250730124627.md +36 -0
- package/.history/CHANGELOG_20250730124638.md +36 -0
- package/.history/CHANGELOG_20250730124640.md +36 -0
- package/.history/README_20230911145033.md +245 -0
- package/.history/README_20230911151749.md +245 -0
- package/.history/README_20230911151844.md +245 -0
- package/.history/README_20230911153040.md +245 -0
- package/.history/README_20230911202959.md +245 -0
- package/.history/bitbucket-pipelines_20250729111540.yml +46 -0
- package/.history/bitbucket-pipelines_20250729210338.yml +46 -0
- package/.history/bitbucket-pipelines_20250729210340.yml +46 -0
- package/.history/bitbucket-pipelines_20250729210342.yml +46 -0
- package/.history/bitbucket-pipelines_20250729222234.yml +47 -0
- package/.history/bitbucket-pipelines_20250729222554.yml +47 -0
- package/.history/bitbucket-pipelines_20250729222555.yml +47 -0
- package/.history/bitbucket-pipelines_20250729223022.yml +46 -0
- package/.history/bitbucket-pipelines_20250729223024.yml +46 -0
- package/.history/cli_20241005014539 +3 -0
- package/.history/cli_20241005014542 +3 -0
- package/.history/cli_20241005014848 +3 -0
- package/.history/dist/chunk-FICM3HUI_20230912183408.js +302 -0
- package/{dist/chunk-ALQDGTID.js → .history/dist/chunk-FICM3HUI_20230912201610.js} +45 -150
- package/.history/package_20250729182417.json +111 -0
- package/.history/package_20250729182419.json +111 -0
- package/.history/package_20250729182618.json +110 -0
- package/.history/package_20250729182834.json +110 -0
- package/.history/package_20250729183032.json +110 -0
- package/.history/package_20250729183033.json +110 -0
- package/.history/package_20250729185750.json +110 -0
- package/.history/package_20250729185815.json +110 -0
- package/.history/package_20250729185846.json +110 -0
- package/.history/package_20250729185854.json +110 -0
- package/.history/package_20250729185943.json +110 -0
- package/.history/package_20250729190645.json +110 -0
- package/.history/package_20250729195934.json +110 -0
- package/.history/package_20250729200013.json +110 -0
- package/.history/package_20250729200056.json +110 -0
- package/.history/package_20250729200434.json +110 -0
- package/.history/package_20250729200808.json +110 -0
- package/.history/package_20250729200944.json +110 -0
- package/.history/package_20250729214420.json +114 -0
- package/.history/package_20250729223112.json +110 -0
- package/.history/package_20250729223127.json +110 -0
- package/.history/package_20250729223134.json +110 -0
- package/.history/package_20250730124647.json +114 -0
- package/.history/tsconfig_20241005001442.json +34 -0
- package/.history/tsconfig_20241005001500.json +34 -0
- package/.history/tsconfig_20241005001540.json +34 -0
- package/.history/tsconfig_20241005014429.json +42 -0
- package/.history/tsconfig_20241005014436.json +42 -0
- package/.history/tsconfig_20241005014439.json +38 -0
- package/.history/tsconfig_20241005014455.json +38 -0
- package/.history/tsconfig_20241005014521.json +38 -0
- package/.history/vitest.config_20250729214539.ts +0 -0
- package/.history/vitest.config_20250729214659.ts +24 -0
- package/.history/vitest.config_20250729214748.ts +21 -0
- package/.history/vitest.config_20250729214825.ts +21 -0
- package/.history/vitest.config_20250729214902.ts +21 -0
- package/.history/vitest.config_20250729222125.ts +20 -0
- package/.history/vitest.config_20250729222213.ts +20 -0
- package/.idea/codeStyles/Project.xml +131 -0
- package/.idea/codeStyles/codeStyleConfig.xml +5 -0
- package/.idea/inspectionProfiles/Project_Default.xml +6 -0
- package/.idea/misc.xml +17 -0
- package/.idea/modules.xml +8 -0
- package/.idea/prettier.xml +6 -0
- package/.idea/tamaro-cli.iml +12 -0
- package/.idea/vcs.xml +6 -0
- package/.nvmrc +1 -0
- package/.prettierignore +8 -0
- package/.prettierrc.cjs +19 -0
- package/bitbucket-pipelines.yml +47 -0
- package/dist/cli.js +768 -1461
- package/dist/env-Bx5mwt8E.js +254 -0
- package/dist/webpack.config.js +308 -443
- package/package.json +28 -39
- package/renovate.json +3 -0
- package/tsdown.config.ts +13 -0
- package/vitest.config.ts +20 -0
package/dist/cli.js
CHANGED
|
@@ -1,709 +1,352 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
AWS_CLOUDFRONT_DISTRIBUTION_ID,
|
|
4
|
-
AWS_S3_BUCKET_TAMARO,
|
|
5
|
-
AWS_S3_BUCKET_TAMARO_EMAIL_CONFIG_PROD,
|
|
6
|
-
AWS_S3_BUCKET_TAMARO_EMAIL_CONFIG_STAGE,
|
|
7
|
-
CACHE_DIR,
|
|
8
|
-
CORE_CONFIG_NAME,
|
|
9
|
-
DEFAULT_PORT,
|
|
10
|
-
DEFAULT_TAG,
|
|
11
|
-
EPMS_API_BASE_URL_PROD,
|
|
12
|
-
EPMS_API_BASE_URL_STAGE,
|
|
13
|
-
HTTPS_CRT_FILE,
|
|
14
|
-
HTTPS_KEY_FILE,
|
|
15
|
-
applyEnv,
|
|
16
|
-
assertEnvValid,
|
|
17
|
-
getIfCoreFns,
|
|
18
|
-
getPaths,
|
|
19
|
-
getWidgetUuid,
|
|
20
|
-
halt,
|
|
21
|
-
logCommand,
|
|
22
|
-
logDataTable,
|
|
23
|
-
logError,
|
|
24
|
-
logSuccess,
|
|
25
|
-
logTitle,
|
|
26
|
-
promptConfirmation,
|
|
27
|
-
resolveAccountUuidFromConfig,
|
|
28
|
-
resolveBin,
|
|
29
|
-
resolveCoreVersion,
|
|
30
|
-
resolveOwn,
|
|
31
|
-
runCommandSync
|
|
32
|
-
} from "./chunk-ALQDGTID.js";
|
|
33
|
-
|
|
34
|
-
// src/cli.ts
|
|
2
|
+
import { C as promptConfirmation, D as logError, E as logDataTable, O as logSuccess, S as halt, T as logCommand, _ as getWidgetUuid, a as AWS_S3_BUCKET_TAMARO, c as CORE_CONFIG_NAME, d as HTTPS_CRT_FILE, f as HTTPS_KEY_FILE, h as getPaths, i as AWS_CLOUDFRONT_DISTRIBUTION_ID, k as logTitle, l as DEFAULT_PORT, m as getIfCoreFns, n as assertEnvValid, o as AWS_S3_BUCKET_TAMARO_EMAIL_CONFIG_PROD, s as AWS_S3_BUCKET_TAMARO_EMAIL_CONFIG_STAGE, t as applyEnv, u as DEFAULT_TAG, w as runCommandSync, x as resolveOwn, y as resolveBin } from "./env-Bx5mwt8E.js";
|
|
35
3
|
import { createCommand } from "commander";
|
|
36
|
-
|
|
37
|
-
// src/commands/archive.ts
|
|
38
4
|
import { existsSync, mkdirSync, renameSync } from "fs";
|
|
39
5
|
import { basename, dirname, resolve } from "path";
|
|
40
|
-
|
|
41
|
-
// src/lib/aws.ts
|
|
42
6
|
import { execaCommandSync } from "execa";
|
|
43
7
|
import prompts from "prompts";
|
|
44
8
|
import stripIndent from "strip-indent";
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
9
|
+
import notifier from "node-notifier";
|
|
10
|
+
import { globSync } from "glob";
|
|
11
|
+
import fs from "node:fs";
|
|
12
|
+
import Handlebars from "handlebars";
|
|
13
|
+
import helpers from "handlebars-helpers";
|
|
14
|
+
import { getPortPromise } from "portfinder";
|
|
15
|
+
//#region src/lib/aws.ts
|
|
16
|
+
const awsAuthenticate = (options) => {
|
|
17
|
+
if (options.ci)
|
|
18
|
+
/**
|
|
19
|
+
* Don't try to authenticate the user.
|
|
20
|
+
* This is done when CLI is running within an automated system like pipeline,
|
|
21
|
+
* In this case "AWS_ACCESS_KEY_ID" and "AWS_SECRET_ACCESS_KEY" are used instead of "AWS_PROFILE".
|
|
22
|
+
*/
|
|
23
|
+
return;
|
|
24
|
+
try {
|
|
25
|
+
checkIdentity(options);
|
|
26
|
+
} catch (error) {
|
|
27
|
+
login(options);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
const assertProfilesPresent = () => {
|
|
31
|
+
if (getAvailableProfiles().length === 0) halt(stripIndent(`
|
|
60
32
|
No AWS profiles found.
|
|
61
33
|
Run "aws configure sso" to set up SSO-enabled profile.
|
|
62
34
|
Check the wiki for more information:
|
|
63
35
|
https://raisenow.atlassian.net/wiki/x/lIrWvg
|
|
64
|
-
`)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
36
|
+
`));
|
|
37
|
+
};
|
|
38
|
+
const getAvailableProfiles = () => {
|
|
39
|
+
const { stdout } = execaCommandSync("aws configure list-profiles");
|
|
40
|
+
return stdout.split("\n");
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Returns caller identity data (output is ignored here).
|
|
44
|
+
* Fails in case of expired SSO session.
|
|
45
|
+
*/
|
|
46
|
+
const checkIdentity = (options) => {
|
|
47
|
+
execaCommandSync(`aws sts get-caller-identity ${prepareFlags$3(options)}`);
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Opens SSO authentication page in the browser.
|
|
51
|
+
* Fails if user canceled authentication process.
|
|
52
|
+
*/
|
|
53
|
+
const login = (options) => {
|
|
54
|
+
const flags = prepareFlags$3(options);
|
|
55
|
+
try {
|
|
56
|
+
execaCommandSync(`aws sso login ${flags}`, { stdio: "inherit" });
|
|
57
|
+
console.log("");
|
|
58
|
+
} catch (error) {
|
|
59
|
+
halt("Login failed.");
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
const prepareFlags$3 = (options) => {
|
|
63
|
+
const flags = [];
|
|
64
|
+
const { profile } = options;
|
|
65
|
+
if (profile) flags.push(`--profile ${profile}`);
|
|
66
|
+
return flags.join(" ");
|
|
67
|
+
};
|
|
68
|
+
const assertProfileValid = (profile) => {
|
|
69
|
+
const profiles = getAvailableProfiles();
|
|
70
|
+
if (!profiles.includes(profile)) halt(stripIndent(`
|
|
98
71
|
AWS profile "${profile}" is not found.
|
|
99
72
|
Available profiles are: ${profiles.map((v) => `"${v}"`).join(", ")}.
|
|
100
|
-
`)
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
(h) => !supportedHelpers.has(h)
|
|
290
|
-
);
|
|
291
|
-
if (unsupportedHelpers.length > 0) {
|
|
292
|
-
throw new Error(
|
|
293
|
-
`Email template uses unsupported Handlebars helpers: ${unsupportedHelpers.join(", ")}`
|
|
294
|
-
);
|
|
295
|
-
}
|
|
296
|
-
};
|
|
297
|
-
var compileEmailTemplate = (template) => {
|
|
298
|
-
const compiled = Handlebars.compile(template);
|
|
299
|
-
compiled({});
|
|
300
|
-
};
|
|
301
|
-
|
|
302
|
-
// src/commands/validate.ts
|
|
303
|
-
var validate = async () => {
|
|
304
|
-
const errors = validateEmailTemplates(
|
|
305
|
-
globSync("email-config/templates/**/*.hbs").sort()
|
|
306
|
-
);
|
|
307
|
-
if (errors.length) {
|
|
308
|
-
halt(errors.map((el) => el.toString()).join("\n"));
|
|
309
|
-
}
|
|
310
|
-
logTitle("Validated successfully");
|
|
311
|
-
};
|
|
312
|
-
|
|
313
|
-
// src/lib/https.ts
|
|
314
|
-
import { existsSync as existsSync2 } from "fs";
|
|
315
|
-
import { resolve as resolve2 } from "path";
|
|
316
|
-
import stripIndent3 from "strip-indent";
|
|
317
|
-
var assertCrtExists = () => {
|
|
318
|
-
const { ifCore } = getIfCoreFns();
|
|
319
|
-
const paths = getPaths(ifCore);
|
|
320
|
-
const certFile = resolve2(paths.root, HTTPS_CRT_FILE);
|
|
321
|
-
const keyFile = resolve2(paths.root, HTTPS_KEY_FILE);
|
|
322
|
-
if (existsSync2(certFile) && existsSync2(keyFile)) {
|
|
323
|
-
return;
|
|
324
|
-
}
|
|
325
|
-
halt(
|
|
326
|
-
stripIndent3(`
|
|
73
|
+
`));
|
|
74
|
+
};
|
|
75
|
+
const promptProfile = async () => {
|
|
76
|
+
const { profile } = await prompts([{
|
|
77
|
+
type: "select",
|
|
78
|
+
name: "profile",
|
|
79
|
+
message: "Select AWS profile",
|
|
80
|
+
choices: getAvailableProfiles().filter((v) => !!v).map((v) => ({
|
|
81
|
+
title: v,
|
|
82
|
+
value: v
|
|
83
|
+
}))
|
|
84
|
+
}], { onCancel: () => halt() });
|
|
85
|
+
return profile;
|
|
86
|
+
};
|
|
87
|
+
//#endregion
|
|
88
|
+
//#region src/lib/notifier.ts
|
|
89
|
+
const notify = (args) => {
|
|
90
|
+
const { title, message = "" } = args;
|
|
91
|
+
notifier.notify({
|
|
92
|
+
title,
|
|
93
|
+
message: stripIndent(message).trim(),
|
|
94
|
+
contentImage: "https://assets.raisenow.io/favicon.png",
|
|
95
|
+
sound: "Funk"
|
|
96
|
+
});
|
|
97
|
+
};
|
|
98
|
+
//#endregion
|
|
99
|
+
//#region src/commands/archive.ts
|
|
100
|
+
const archive = (options) => {
|
|
101
|
+
const { ifCore } = getIfCoreFns();
|
|
102
|
+
assertIsNotCore$3(ifCore);
|
|
103
|
+
assertIsNotArchived();
|
|
104
|
+
const configName = getWidgetUuid();
|
|
105
|
+
const cwd = process.cwd();
|
|
106
|
+
const archiveDir = resolve(dirname(cwd), "_archived");
|
|
107
|
+
const archiveTarget = resolve(archiveDir, configName);
|
|
108
|
+
assertArchiveTargetDoesNotExist(archiveTarget);
|
|
109
|
+
assertOptionsValid$9(options);
|
|
110
|
+
if (options.dryrun) logTitle("🧪 DRY RUN MODE - No actual changes will be made 🧪");
|
|
111
|
+
if (!options.dryrun) {
|
|
112
|
+
if (!existsSync(archiveDir)) mkdirSync(archiveDir, { recursive: true });
|
|
113
|
+
renameSync(cwd, archiveTarget);
|
|
114
|
+
} else logTitle(`Would move ${cwd} → ${archiveTarget}`);
|
|
115
|
+
logSuccess(`\n✅ "${configName}" has been archived and moved to ${archiveTarget}`);
|
|
116
|
+
process.on("exit", () => {
|
|
117
|
+
notify({
|
|
118
|
+
title: "archive",
|
|
119
|
+
message: `"${configName}" has been archived.`
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
};
|
|
123
|
+
const assertOptionsValid$9 = (options) => {
|
|
124
|
+
const { profile } = options;
|
|
125
|
+
if (profile) assertProfileValid(profile);
|
|
126
|
+
};
|
|
127
|
+
const assertIsNotCore$3 = (ifCore) => {
|
|
128
|
+
if (ifCore()) halt("You cannot archive Tamaro Core.");
|
|
129
|
+
};
|
|
130
|
+
const assertIsNotArchived = () => {
|
|
131
|
+
if (basename(dirname(process.cwd())) === "_archived") halt("This configuration is already archived.");
|
|
132
|
+
};
|
|
133
|
+
const assertArchiveTargetDoesNotExist = (archiveTarget) => {
|
|
134
|
+
if (existsSync(archiveTarget)) halt(`Archive target already exists: ${archiveTarget}. Please remove it first.`);
|
|
135
|
+
};
|
|
136
|
+
//#endregion
|
|
137
|
+
//#region src/lib/validators/validateEmailTemplates.ts
|
|
138
|
+
/**
|
|
139
|
+
* Register custom Handlebars helpers - the same, which are used in the Email Service.
|
|
140
|
+
* Make sure to update it if new helpers are added in the Email Service.
|
|
141
|
+
*/
|
|
142
|
+
helpers.comparison({ handlebars: Handlebars });
|
|
143
|
+
/**
|
|
144
|
+
* Recurse through the expected email templates folder and attempt to parse
|
|
145
|
+
* handlebars template to validate their syntax.
|
|
146
|
+
*/
|
|
147
|
+
const validateEmailTemplates = (templatePaths) => {
|
|
148
|
+
const errors = [];
|
|
149
|
+
for (const templatePath of templatePaths) try {
|
|
150
|
+
const template = fs.readFileSync(templatePath, "utf-8");
|
|
151
|
+
assureOnlySupportedHelpers(template);
|
|
152
|
+
compileEmailTemplate(template);
|
|
153
|
+
console.log(`${templatePath} is a valid email template`);
|
|
154
|
+
} catch (e) {
|
|
155
|
+
errors.push(`${templatePath} is invalid`);
|
|
156
|
+
errors.push(e);
|
|
157
|
+
}
|
|
158
|
+
return errors;
|
|
159
|
+
};
|
|
160
|
+
/**
|
|
161
|
+
* Validate that only supported Handlebars helpers are used in the template.
|
|
162
|
+
* This function extracts helpers from the template AST and checks them
|
|
163
|
+
* against a predefined set of supported helpers.
|
|
164
|
+
*/
|
|
165
|
+
const assureOnlySupportedHelpers = (template) => {
|
|
166
|
+
/**
|
|
167
|
+
* Recursively extract helpers from the AST
|
|
168
|
+
*/
|
|
169
|
+
const extractHelpers = (ast) => {
|
|
170
|
+
const usedHelpers = /* @__PURE__ */ new Set();
|
|
171
|
+
const extractHelperName = (node) => {
|
|
172
|
+
if (node.path?.type === "PathExpression" && (node.params?.length > 0 || node.hash?.pairs?.length > 0)) return node.path?.original;
|
|
173
|
+
};
|
|
174
|
+
const visit = (node) => {
|
|
175
|
+
if (!node) return;
|
|
176
|
+
switch (node.type) {
|
|
177
|
+
case "MustacheStatement":
|
|
178
|
+
case "BlockStatement": {
|
|
179
|
+
const name = extractHelperName(node);
|
|
180
|
+
if (name) usedHelpers.add(name);
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Recursively visit children of the AST node.
|
|
186
|
+
*/
|
|
187
|
+
for (const key in node) {
|
|
188
|
+
const value = node[key];
|
|
189
|
+
if (Array.isArray(value)) value.forEach(visit);
|
|
190
|
+
else if (value && typeof value === "object" && value.type) visit(value);
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
visit(ast);
|
|
194
|
+
return usedHelpers;
|
|
195
|
+
};
|
|
196
|
+
const usedHelpers = extractHelpers(Handlebars.parse(template));
|
|
197
|
+
const supportedHelpers = new Set([
|
|
198
|
+
"if",
|
|
199
|
+
"unless",
|
|
200
|
+
"each",
|
|
201
|
+
"with",
|
|
202
|
+
"log",
|
|
203
|
+
"lookup",
|
|
204
|
+
"and",
|
|
205
|
+
"compare",
|
|
206
|
+
"contains",
|
|
207
|
+
"default",
|
|
208
|
+
"eq",
|
|
209
|
+
"gt",
|
|
210
|
+
"gte",
|
|
211
|
+
"has",
|
|
212
|
+
"isFalsey",
|
|
213
|
+
"isTruthy",
|
|
214
|
+
"ifEven",
|
|
215
|
+
"ifNth",
|
|
216
|
+
"ifOdd",
|
|
217
|
+
"is",
|
|
218
|
+
"isnt",
|
|
219
|
+
"lt",
|
|
220
|
+
"lte",
|
|
221
|
+
"neither",
|
|
222
|
+
"not",
|
|
223
|
+
"or",
|
|
224
|
+
"unlessEq",
|
|
225
|
+
"unlessGt",
|
|
226
|
+
"unlessLt",
|
|
227
|
+
"unlessGteq",
|
|
228
|
+
"unlessLteq"
|
|
229
|
+
]);
|
|
230
|
+
const unsupportedHelpers = Array.from(usedHelpers).filter((h) => !supportedHelpers.has(h));
|
|
231
|
+
if (unsupportedHelpers.length > 0) throw new Error(`Email template uses unsupported Handlebars helpers: ${unsupportedHelpers.join(", ")}`);
|
|
232
|
+
};
|
|
233
|
+
/**
|
|
234
|
+
* Compile Email template and pass an empty context to validate syntax.
|
|
235
|
+
*/
|
|
236
|
+
const compileEmailTemplate = (template) => {
|
|
237
|
+
Handlebars.compile(template)({});
|
|
238
|
+
};
|
|
239
|
+
//#endregion
|
|
240
|
+
//#region src/commands/validate.ts
|
|
241
|
+
/**
|
|
242
|
+
* Validates the current Tamaro configuration to avoid common errors.
|
|
243
|
+
*
|
|
244
|
+
* The command description is kept generic on purpose. We check for a number
|
|
245
|
+
* of mistakes observed when tamaro configurations are manually edited and
|
|
246
|
+
* deployed.
|
|
247
|
+
*/
|
|
248
|
+
const validate = async () => {
|
|
249
|
+
const errors = validateEmailTemplates(globSync("email-config/templates/**/*.hbs").sort());
|
|
250
|
+
if (errors.length) halt(errors.map((el) => el.toString()).join("\n"));
|
|
251
|
+
logTitle("Validated successfully");
|
|
252
|
+
};
|
|
253
|
+
//#endregion
|
|
254
|
+
//#region src/lib/https.ts
|
|
255
|
+
const assertCrtExists = () => {
|
|
256
|
+
const { ifCore } = getIfCoreFns();
|
|
257
|
+
const paths = getPaths(ifCore);
|
|
258
|
+
const certFile = resolve(paths.root, HTTPS_CRT_FILE);
|
|
259
|
+
const keyFile = resolve(paths.root, HTTPS_KEY_FILE);
|
|
260
|
+
if (existsSync(certFile) && existsSync(keyFile)) return;
|
|
261
|
+
halt(stripIndent(`
|
|
327
262
|
Flag "--https" is used, but "${HTTPS_CRT_FILE}" and/or "${HTTPS_KEY_FILE}" files are not found.
|
|
328
263
|
You need to generate certificate first.
|
|
329
264
|
Check docs: https://unpkg.com/@raisenow/tamaro-cli/readme.html#/?id=use-transport-level-security-https
|
|
330
|
-
`)
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
"
|
|
350
|
-
|
|
351
|
-
);
|
|
352
|
-
const wpBin = resolveBin("webpack");
|
|
353
|
-
const wpConfig = resolveOwn("dist/webpack.config.js");
|
|
354
|
-
const cmd = `
|
|
355
|
-
${wpBin}
|
|
356
|
-
--config ${wpConfig}
|
|
265
|
+
`));
|
|
266
|
+
};
|
|
267
|
+
//#endregion
|
|
268
|
+
//#region src/commands/build.ts
|
|
269
|
+
const build = async (options) => {
|
|
270
|
+
const { env } = options;
|
|
271
|
+
applyEnv(env);
|
|
272
|
+
if (options.deploy && !options.profile && !options.ci) {
|
|
273
|
+
assertProfilesPresent();
|
|
274
|
+
options.profile = await promptProfile();
|
|
275
|
+
}
|
|
276
|
+
assertOptionsValid$8(options);
|
|
277
|
+
await validate();
|
|
278
|
+
const flags = prepareFlags$2(options);
|
|
279
|
+
const { ifCore } = getIfCoreFns();
|
|
280
|
+
const paths = getPaths(ifCore);
|
|
281
|
+
const configName = ifCore(CORE_CONFIG_NAME, getWidgetUuid());
|
|
282
|
+
const title = ifCore("Building optimised (minified) bundle of Tamaro Core …", `Building optimised (minified) bundle of "${configName}" customer configuration …`);
|
|
283
|
+
const cmd = `
|
|
284
|
+
${resolveBin("webpack")}
|
|
285
|
+
--config ${resolveOwn("dist/webpack.config.js")}
|
|
357
286
|
--env min
|
|
358
287
|
${flags}
|
|
359
288
|
`;
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
};
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
};
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
};
|
|
422
|
-
|
|
423
|
-
// src/commands/update-epms.ts
|
|
424
|
-
import { readFileSync as readFileSync3 } from "fs";
|
|
425
|
-
import { basename as basename2 } from "path";
|
|
426
|
-
import { config as dotenvConfig } from "dotenv";
|
|
427
|
-
import { globSync as globSync2 } from "glob";
|
|
428
|
-
import yaml2 from "js-yaml";
|
|
429
|
-
|
|
430
|
-
// src/lib/epms/assert.ts
|
|
431
|
-
import { existsSync as existsSync3, readFileSync } from "fs";
|
|
432
|
-
import yaml from "js-yaml";
|
|
433
|
-
import stripIndent4 from "strip-indent";
|
|
434
|
-
var assertEpmsCredentials = (configPath) => {
|
|
435
|
-
if (!existsSync3(configPath)) {
|
|
436
|
-
throw new Error(`Config file not found at path: ${configPath}`);
|
|
437
|
-
}
|
|
438
|
-
try {
|
|
439
|
-
const configContent = yaml.load(readFileSync(configPath, "utf8"));
|
|
440
|
-
assertEpmsCredentialsPresentStage(configContent);
|
|
441
|
-
assertEpmsCredentialsPresentProd(configContent);
|
|
442
|
-
} catch (e) {
|
|
443
|
-
throw new Error(
|
|
444
|
-
`Error parsing config file at path: ${configPath}. Details: ${e}`
|
|
445
|
-
);
|
|
446
|
-
}
|
|
447
|
-
};
|
|
448
|
-
var assertEpmsCredentialsPresentStage = (rawConfig) => {
|
|
449
|
-
const accountsUuidsStage = resolveAccountUuidFromConfig(
|
|
450
|
-
rawConfig,
|
|
451
|
-
"epms_stage"
|
|
452
|
-
);
|
|
453
|
-
if (!accountsUuidsStage) {
|
|
454
|
-
return;
|
|
455
|
-
}
|
|
456
|
-
if (!process.env.EPMS_CLIENT_ID_STAGE || !process.env.EPMS_CLIENT_SECRET_STAGE) {
|
|
457
|
-
halt(
|
|
458
|
-
stripIndent4(
|
|
459
|
-
`EPMS credentials for stage environment are missing.
|
|
460
|
-
- Please set EPMS_CLIENT_ID_STAGE and EPMS_CLIENT_SECRET_STAGE in your environment variables.
|
|
461
|
-
- Alternatively, remove the "epms_stage" fields from your config.yml
|
|
462
|
-
`
|
|
463
|
-
)
|
|
464
|
-
);
|
|
465
|
-
}
|
|
466
|
-
};
|
|
467
|
-
var assertEpmsCredentialsPresentProd = (rawConfig) => {
|
|
468
|
-
const accountsUuidsProd = resolveAccountUuidFromConfig(rawConfig, "epms");
|
|
469
|
-
if (!accountsUuidsProd) {
|
|
470
|
-
return;
|
|
471
|
-
}
|
|
472
|
-
if (!process.env.EPMS_CLIENT_ID || !process.env.EPMS_CLIENT_SECRET) {
|
|
473
|
-
halt(
|
|
474
|
-
stripIndent4(
|
|
475
|
-
`EPMS credentials for prod environment are missing.
|
|
476
|
-
- Please set EPMS_CLIENT_ID and EPMS_CLIENT_SECRET in your environment variables.
|
|
477
|
-
- Alternatively, remove the "epms" fields from your config.yml
|
|
478
|
-
`
|
|
479
|
-
)
|
|
480
|
-
);
|
|
481
|
-
}
|
|
482
|
-
};
|
|
483
|
-
|
|
484
|
-
// src/lib/epms/auth.ts
|
|
485
|
-
import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync } from "fs";
|
|
486
|
-
import { dirname as dirname2, join } from "path";
|
|
487
|
-
import ky from "ky";
|
|
488
|
-
var DEFAULT_TIMEOUT = 1e4;
|
|
489
|
-
function getCacheFilePath() {
|
|
490
|
-
return join(CACHE_DIR, "token.json");
|
|
491
|
-
}
|
|
492
|
-
function readCachedToken() {
|
|
493
|
-
try {
|
|
494
|
-
const filePath = getCacheFilePath();
|
|
495
|
-
if (!existsSync4(filePath)) {
|
|
496
|
-
return void 0;
|
|
497
|
-
}
|
|
498
|
-
const data = JSON.parse(readFileSync2(filePath, "utf-8"));
|
|
499
|
-
if (typeof data.token === "string" && typeof data.expirationTime === "number") {
|
|
500
|
-
return data;
|
|
501
|
-
}
|
|
502
|
-
} catch {
|
|
503
|
-
}
|
|
504
|
-
return void 0;
|
|
505
|
-
}
|
|
506
|
-
function writeCachedToken(cached) {
|
|
507
|
-
try {
|
|
508
|
-
const filePath = getCacheFilePath();
|
|
509
|
-
mkdirSync2(dirname2(filePath), { recursive: true });
|
|
510
|
-
writeFileSync(filePath, JSON.stringify(cached), { mode: 384 });
|
|
511
|
-
} catch {
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
var createAuthorizer = (baseUrl, clientId, clientSecret) => {
|
|
515
|
-
const apiUnauthorized = ky.extend({
|
|
516
|
-
headers: {
|
|
517
|
-
"Access-Control-Allow-Origin": "*"
|
|
518
|
-
},
|
|
519
|
-
prefixUrl: baseUrl,
|
|
520
|
-
timeout: DEFAULT_TIMEOUT
|
|
521
|
-
});
|
|
522
|
-
let expirationTime = void 0;
|
|
523
|
-
let token = void 0;
|
|
524
|
-
const cached = readCachedToken();
|
|
525
|
-
if (cached) {
|
|
526
|
-
token = cached.token;
|
|
527
|
-
expirationTime = cached.expirationTime;
|
|
528
|
-
}
|
|
529
|
-
const authorize = async () => {
|
|
530
|
-
const isExpired = (expirationTime ?? 0) - Date.now() < 5 * 60 * 1e3;
|
|
531
|
-
if (token && !isExpired) {
|
|
532
|
-
return token;
|
|
533
|
-
}
|
|
534
|
-
const data = await apiUnauthorized.post("oauth2/token", {
|
|
535
|
-
json: {
|
|
536
|
-
client_id: clientId,
|
|
537
|
-
client_secret: clientSecret,
|
|
538
|
-
grant_type: "client_credentials"
|
|
539
|
-
}
|
|
540
|
-
}).json();
|
|
541
|
-
token = `${data.token_type} ${data.access_token}`;
|
|
542
|
-
expirationTime = Date.now() + data.expires_in * 1e3;
|
|
543
|
-
writeCachedToken({ token, expirationTime });
|
|
544
|
-
return token;
|
|
545
|
-
};
|
|
546
|
-
return apiUnauthorized.extend({
|
|
547
|
-
hooks: {
|
|
548
|
-
beforeRequest: [
|
|
549
|
-
async (request) => {
|
|
550
|
-
request.headers.set("Authorization", await authorize());
|
|
551
|
-
}
|
|
552
|
-
]
|
|
553
|
-
}
|
|
554
|
-
});
|
|
555
|
-
};
|
|
556
|
-
|
|
557
|
-
// src/lib/epms/client.ts
|
|
558
|
-
var EpmsClient = class {
|
|
559
|
-
#epmsClient;
|
|
560
|
-
constructor(baseUrl, clientId, clientSecret) {
|
|
561
|
-
this.#epmsClient = createAuthorizer(baseUrl, clientId, clientSecret);
|
|
562
|
-
}
|
|
563
|
-
async getOrganisationIdByAccountUuid(accountUuid) {
|
|
564
|
-
const query = {
|
|
565
|
-
query: {
|
|
566
|
-
$and: [
|
|
567
|
-
{ $term: { object_uuid: accountUuid } },
|
|
568
|
-
{ $term: { object: "account" } }
|
|
569
|
-
]
|
|
570
|
-
},
|
|
571
|
-
size: 1,
|
|
572
|
-
from: 0
|
|
573
|
-
};
|
|
574
|
-
const response = await this.#epmsClient.post("search/events", {
|
|
575
|
-
json: query
|
|
576
|
-
}).json();
|
|
577
|
-
if (response.hits.length === 0) {
|
|
578
|
-
throw new Error(`No events found for account UUID: ${accountUuid}`);
|
|
579
|
-
}
|
|
580
|
-
const organisationId = response.hits[0].organisation_uuid;
|
|
581
|
-
if (!organisationId) {
|
|
582
|
-
throw new Error(
|
|
583
|
-
`Organisation UUID not found for account UUID: ${accountUuid}`
|
|
584
|
-
);
|
|
585
|
-
}
|
|
586
|
-
return organisationId;
|
|
587
|
-
}
|
|
588
|
-
async updateTamaro(configName, tag, json) {
|
|
589
|
-
return this.#epmsClient.put(`products/tamaro/${configName}/tags/${tag}`, {
|
|
590
|
-
json
|
|
591
|
-
}).json();
|
|
592
|
-
}
|
|
593
|
-
};
|
|
594
|
-
|
|
595
|
-
// src/commands/update-epms.ts
|
|
596
|
-
var updateEpms = async (options) => {
|
|
597
|
-
const { ifCore } = getIfCoreFns();
|
|
598
|
-
assertIsNotCore2(ifCore);
|
|
599
|
-
const paths = getPaths(ifCore);
|
|
600
|
-
const { tag, dryrun } = options;
|
|
601
|
-
const dryRunFlag = dryrun ? `--dryrun` : "";
|
|
602
|
-
const configName = getWidgetUuid();
|
|
603
|
-
const appEnvFiles = globSync2(paths.appEnv);
|
|
604
|
-
const filePath = appEnvFiles.find((file) => basename2(file) === ".env");
|
|
605
|
-
if (!filePath) {
|
|
606
|
-
halt(
|
|
607
|
-
'No ".env" file found. Please make sure to have a ".env" file with EPMS credentials in the root of your widget project.'
|
|
608
|
-
);
|
|
609
|
-
}
|
|
610
|
-
dotenvConfig({ path: filePath, quiet: true });
|
|
611
|
-
if (!("configYml" in paths)) {
|
|
612
|
-
halt("Fatal error, this should never happen");
|
|
613
|
-
throw new Error();
|
|
614
|
-
}
|
|
615
|
-
if (dryRunFlag) {
|
|
616
|
-
logTitle("\u{1F9EA} DRY RUN MODE - No actual changes will be made \u{1F9EA}");
|
|
617
|
-
}
|
|
618
|
-
assertTagValid(tag);
|
|
619
|
-
assertEpmsCredentials(paths.configYml);
|
|
620
|
-
const configContent = yaml2.load(readFileSync3(paths.configYml, "utf8"));
|
|
621
|
-
const accountUuidStage = resolveAccountUuidFromConfig(
|
|
622
|
-
configContent,
|
|
623
|
-
"epms_stage"
|
|
624
|
-
);
|
|
625
|
-
const accountUuidProd = resolveAccountUuidFromConfig(configContent, "epms");
|
|
626
|
-
if (dryrun) {
|
|
627
|
-
logTitle(
|
|
628
|
-
`[DRY RUN] Would update EPMS for "${configName}" with tag "${tag}"`
|
|
629
|
-
);
|
|
630
|
-
} else {
|
|
631
|
-
if (accountUuidStage) {
|
|
632
|
-
const epmsClient = new EpmsClient(
|
|
633
|
-
EPMS_API_BASE_URL_STAGE,
|
|
634
|
-
process.env.EPMS_CLIENT_ID_STAGE,
|
|
635
|
-
process.env.EPMS_CLIENT_SECRET_STAGE
|
|
636
|
-
);
|
|
637
|
-
const organisationUuid = await epmsClient.getOrganisationIdByAccountUuid(accountUuidStage);
|
|
638
|
-
logTitle("Updating EPMS Stage with the following details:");
|
|
639
|
-
const body = {
|
|
640
|
-
account_uuid: accountUuidStage,
|
|
641
|
-
organisation_uuid: organisationUuid,
|
|
642
|
-
configured_version: resolveCoreVersion() ?? "unknown",
|
|
643
|
-
read_only: false,
|
|
644
|
-
// Unix timestamp in seconds
|
|
645
|
-
last_deployment: Math.floor(Date.now() / 1e3)
|
|
646
|
-
};
|
|
647
|
-
logDataTable({
|
|
648
|
-
name: configName,
|
|
649
|
-
tag,
|
|
650
|
-
...body
|
|
651
|
-
});
|
|
652
|
-
await epmsClient.updateTamaro(configName, tag, body);
|
|
653
|
-
logSuccess("\u2705 EPMS Stage is updated.");
|
|
654
|
-
}
|
|
655
|
-
if (accountUuidProd) {
|
|
656
|
-
const epmsClient = new EpmsClient(
|
|
657
|
-
EPMS_API_BASE_URL_PROD,
|
|
658
|
-
process.env.EPMS_CLIENT_ID,
|
|
659
|
-
process.env.EPMS_CLIENT_SECRET
|
|
660
|
-
);
|
|
661
|
-
const organisationUuid = await epmsClient.getOrganisationIdByAccountUuid(accountUuidProd);
|
|
662
|
-
logTitle("Updating EPMS Prod with the following details:");
|
|
663
|
-
const body = {
|
|
664
|
-
account_uuid: accountUuidProd,
|
|
665
|
-
organisation_uuid: organisationUuid,
|
|
666
|
-
configured_version: resolveCoreVersion() ?? "unknown",
|
|
667
|
-
read_only: false
|
|
668
|
-
};
|
|
669
|
-
logDataTable({
|
|
670
|
-
name: configName,
|
|
671
|
-
tag,
|
|
672
|
-
...body
|
|
673
|
-
});
|
|
674
|
-
await epmsClient.updateTamaro(configName, tag, body);
|
|
675
|
-
logSuccess("\u2705 EPMS Prod is updated.");
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
};
|
|
679
|
-
var assertIsNotCore2 = (ifCore) => {
|
|
680
|
-
if (ifCore()) {
|
|
681
|
-
halt("You cannot update EPMS in the context of Tamaro Core.");
|
|
682
|
-
}
|
|
683
|
-
};
|
|
684
|
-
|
|
685
|
-
// src/commands/deploy.ts
|
|
686
|
-
var deploy = async (options) => {
|
|
687
|
-
const { ifCore } = getIfCoreFns();
|
|
688
|
-
const paths = getPaths(ifCore);
|
|
689
|
-
assertDistPathExists(paths.appDist);
|
|
690
|
-
if (!options.profile && !options.ci) {
|
|
691
|
-
assertProfilesPresent();
|
|
692
|
-
options.profile = await promptProfile();
|
|
693
|
-
}
|
|
694
|
-
assertOptionsValid3(options);
|
|
695
|
-
await validate();
|
|
696
|
-
awsAuthenticate(options);
|
|
697
|
-
const flags = prepareFlags(options);
|
|
698
|
-
const { tag, dryrun } = options;
|
|
699
|
-
const dryRunFlag = dryrun ? `--dryrun` : "";
|
|
700
|
-
const configName = ifCore(CORE_CONFIG_NAME, getWidgetUuid());
|
|
701
|
-
const deployUrl = `s3://${AWS_S3_BUCKET_TAMARO}/${configName}/${tag}`;
|
|
702
|
-
const entryFilename = ifCore("index.js", "widget.js");
|
|
703
|
-
if (dryRunFlag) {
|
|
704
|
-
logTitle("\u{1F9EA} DRY RUN MODE - No actual changes will be made \u{1F9EA}");
|
|
705
|
-
}
|
|
706
|
-
const cmdSyncAll = `
|
|
289
|
+
logTitle(title);
|
|
290
|
+
logCommand(cmd);
|
|
291
|
+
runCommandSync(cmd, { stdio: "inherit" });
|
|
292
|
+
logTitle(`\nBundle for "${configName}" customer configuration is done.`);
|
|
293
|
+
console.log(`Path: ${paths.appDist}\n`);
|
|
294
|
+
process.on("exit", () => {
|
|
295
|
+
notify({
|
|
296
|
+
title: "build",
|
|
297
|
+
message: `Bundle for "${configName}" customer configuration is done.`
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
};
|
|
301
|
+
const assertOptionsValid$8 = (options) => {
|
|
302
|
+
const { localCore, https, deploy, env, profile } = options;
|
|
303
|
+
const { ifCore } = getIfCoreFns();
|
|
304
|
+
if (ifCore() && localCore) halt("Flag \"--local-core\" is redundant if running in Tamaro Core context.");
|
|
305
|
+
if (localCore && deploy) halt("Flags \"--local-core\" and \"--deploy\" must not be used together.");
|
|
306
|
+
if (https) assertCrtExists();
|
|
307
|
+
if (profile) assertProfileValid(profile);
|
|
308
|
+
assertEnvValid(env);
|
|
309
|
+
};
|
|
310
|
+
const prepareFlags$2 = (options) => {
|
|
311
|
+
const flags = [];
|
|
312
|
+
const { localCore, analyze, https, nolint, debug } = options;
|
|
313
|
+
if (localCore) flags.push("--env localCore");
|
|
314
|
+
if (analyze) flags.push("--env analyze");
|
|
315
|
+
if (https) flags.push("--env https");
|
|
316
|
+
if (nolint) flags.push("--env nolint");
|
|
317
|
+
if (debug) flags.push("--env debug");
|
|
318
|
+
return flags.join(" ");
|
|
319
|
+
};
|
|
320
|
+
//#endregion
|
|
321
|
+
//#region src/lib/validators/assertTagValid.ts
|
|
322
|
+
const assertTagValid = (tag) => {
|
|
323
|
+
const regex = /^[a-zA-Z0-9-_.]+$/;
|
|
324
|
+
if (!regex.test(tag)) halt(`Flag "--tag" has forbidden format. Allowed format: ${regex.toString()}.`);
|
|
325
|
+
};
|
|
326
|
+
//#endregion
|
|
327
|
+
//#region src/commands/deploy.ts
|
|
328
|
+
const deploy = async (options) => {
|
|
329
|
+
const { ifCore } = getIfCoreFns();
|
|
330
|
+
const paths = getPaths(ifCore);
|
|
331
|
+
assertDistPathExists(paths.appDist);
|
|
332
|
+
if (!options.profile && !options.ci) {
|
|
333
|
+
assertProfilesPresent();
|
|
334
|
+
options.profile = await promptProfile();
|
|
335
|
+
}
|
|
336
|
+
assertOptionsValid$7(options);
|
|
337
|
+
await validate();
|
|
338
|
+
awsAuthenticate(options);
|
|
339
|
+
const flags = prepareFlags$3(options);
|
|
340
|
+
const { tag, dryrun } = options;
|
|
341
|
+
const dryRunFlag = dryrun ? `--dryrun` : "";
|
|
342
|
+
const configName = ifCore(CORE_CONFIG_NAME, getWidgetUuid());
|
|
343
|
+
const deployUrl = `s3://${AWS_S3_BUCKET_TAMARO}/${configName}/${tag}`;
|
|
344
|
+
const entryFilename = ifCore("index.js", "widget.js");
|
|
345
|
+
if (dryRunFlag) logTitle("🧪 DRY RUN MODE - No actual changes will be made 🧪");
|
|
346
|
+
/**
|
|
347
|
+
* Sync all files except entrypoint (without deleting old files)
|
|
348
|
+
*/
|
|
349
|
+
const cmdSyncAll = `
|
|
707
350
|
aws s3 sync ${paths.appDist} ${deployUrl}
|
|
708
351
|
--acl public-read
|
|
709
352
|
--exclude ${paths.appDist}/${entryFilename}
|
|
@@ -711,838 +354,502 @@ var deploy = async (options) => {
|
|
|
711
354
|
${flags}
|
|
712
355
|
${dryRunFlag}
|
|
713
356
|
`;
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
357
|
+
logTitle("Deploying to AWS S3 …");
|
|
358
|
+
logCommand(cmdSyncAll);
|
|
359
|
+
try {
|
|
360
|
+
runCommandSync(cmdSyncAll, { stdout: "inherit" });
|
|
361
|
+
} catch (error) {
|
|
362
|
+
halt(error.stderr);
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Copy entrypoint
|
|
366
|
+
*/
|
|
367
|
+
const cmdCpEntry = `
|
|
722
368
|
aws s3 cp ${paths.appDist}/${entryFilename} ${deployUrl}/${entryFilename}
|
|
723
369
|
--acl public-read
|
|
724
370
|
--cache-control max-age=64800
|
|
725
371
|
${flags}
|
|
726
372
|
${dryRunFlag}
|
|
727
373
|
`;
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
374
|
+
logCommand(cmdCpEntry);
|
|
375
|
+
try {
|
|
376
|
+
runCommandSync(cmdCpEntry, { stdout: "inherit" });
|
|
377
|
+
} catch (error) {
|
|
378
|
+
halt(error.stderr);
|
|
379
|
+
}
|
|
380
|
+
if (!dryRunFlag) {
|
|
381
|
+
/**
|
|
382
|
+
* Invalidate cloudfront cache
|
|
383
|
+
*/
|
|
384
|
+
const cmdInvalidateCache = `
|
|
736
385
|
aws cloudfront create-invalidation
|
|
737
386
|
--distribution-id ${AWS_CLOUDFRONT_DISTRIBUTION_ID}
|
|
738
387
|
--paths /${configName}/${tag}/*
|
|
739
388
|
${flags}
|
|
740
389
|
`;
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
title: "deploy",
|
|
761
|
-
message: `
|
|
390
|
+
logTitle("\nInvalidating edge cache …");
|
|
391
|
+
logCommand(cmdInvalidateCache);
|
|
392
|
+
try {
|
|
393
|
+
runCommandSync(cmdInvalidateCache);
|
|
394
|
+
} catch (error) {
|
|
395
|
+
halt(error.stderr);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
const demoPage = `https://${AWS_S3_BUCKET_TAMARO}/${configName}/${tag}/index.html`;
|
|
399
|
+
const entryPoint = `https://${AWS_S3_BUCKET_TAMARO}/${configName}/${tag}/${entryFilename}`;
|
|
400
|
+
logTitle(`\nBundle for "${configName}" is deployed with tag "${tag}".`);
|
|
401
|
+
logDataTable({
|
|
402
|
+
"Demo page:": demoPage,
|
|
403
|
+
"Entry point:": entryPoint
|
|
404
|
+
});
|
|
405
|
+
process.on("exit", () => {
|
|
406
|
+
notify({
|
|
407
|
+
title: "deploy",
|
|
408
|
+
message: `
|
|
762
409
|
Bundle for "${configName}" is deployed with tag "${tag}".
|
|
763
410
|
Demo page: ${demoPage}
|
|
764
411
|
Entry point: ${entryPoint}
|
|
765
412
|
`
|
|
766
|
-
|
|
767
|
-
|
|
413
|
+
});
|
|
414
|
+
});
|
|
768
415
|
};
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
}
|
|
774
|
-
assertTagValid(tag);
|
|
416
|
+
const assertOptionsValid$7 = (options) => {
|
|
417
|
+
const { profile, tag } = options;
|
|
418
|
+
if (profile) assertProfileValid(profile);
|
|
419
|
+
assertTagValid(tag);
|
|
775
420
|
};
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
halt(
|
|
779
|
-
stripIndent5(`
|
|
421
|
+
const assertDistPathExists = (distPath) => {
|
|
422
|
+
if (!existsSync(distPath)) halt(stripIndent(`
|
|
780
423
|
Dist folder does not exists.
|
|
781
424
|
Make sure you have built the bundle before trying to deploy it.
|
|
782
|
-
`)
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
awsAuthenticate(options);
|
|
806
|
-
const flags = prepareFlags(options);
|
|
807
|
-
const dryRunFlag = options.dryrun ? `--dryrun` : "";
|
|
808
|
-
const configName = getWidgetUuid();
|
|
809
|
-
const deployUrl = `s3://${options.bucket}/${configName}`;
|
|
810
|
-
if (dryRunFlag) {
|
|
811
|
-
logTitle("\u{1F9EA} DRY RUN MODE - No actual changes will be made \u{1F9EA}");
|
|
812
|
-
}
|
|
813
|
-
const cmd = `
|
|
425
|
+
`));
|
|
426
|
+
};
|
|
427
|
+
//#endregion
|
|
428
|
+
//#region src/commands/deploy-email-config.ts
|
|
429
|
+
const deployEmailConfig = async (options) => {
|
|
430
|
+
const { ifCore } = getIfCoreFns();
|
|
431
|
+
const emailConfigPath = `${getPaths(ifCore).app}/email-config`;
|
|
432
|
+
assertIsNotCore$2();
|
|
433
|
+
assertEmailConfigPathExists(emailConfigPath);
|
|
434
|
+
if (!options.profile && !options.ci) {
|
|
435
|
+
assertProfilesPresent();
|
|
436
|
+
options.profile = await promptProfile();
|
|
437
|
+
}
|
|
438
|
+
if (!options.bucket) options.bucket = options.ci ? AWS_S3_BUCKET_TAMARO_EMAIL_CONFIG_PROD : await promptBucketTamaroEmailConfig$1();
|
|
439
|
+
assertOptionsValid$6(options);
|
|
440
|
+
await validate();
|
|
441
|
+
awsAuthenticate(options);
|
|
442
|
+
const flags = prepareFlags$3(options);
|
|
443
|
+
const dryRunFlag = options.dryrun ? `--dryrun` : "";
|
|
444
|
+
const configName = getWidgetUuid();
|
|
445
|
+
const deployUrl = `s3://${options.bucket}/${configName}`;
|
|
446
|
+
if (dryRunFlag) logTitle("🧪 DRY RUN MODE - No actual changes will be made 🧪");
|
|
447
|
+
const cmd = `
|
|
814
448
|
aws s3 sync ${emailConfigPath} ${deployUrl}
|
|
815
449
|
--delete
|
|
816
450
|
--exact-timestamps
|
|
817
451
|
${flags}
|
|
818
452
|
${dryRunFlag}
|
|
819
453
|
`;
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
}
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
name: "bucket",
|
|
879
|
-
message: "Select environment",
|
|
880
|
-
choices: buckets
|
|
881
|
-
}
|
|
882
|
-
],
|
|
883
|
-
{
|
|
884
|
-
onCancel: () => halt()
|
|
885
|
-
}
|
|
886
|
-
);
|
|
887
|
-
return bucket;
|
|
888
|
-
};
|
|
889
|
-
|
|
890
|
-
// src/commands/dev.ts
|
|
891
|
-
import { getPortPromise } from "portfinder";
|
|
892
|
-
var dev = async (options) => {
|
|
893
|
-
const { env } = options;
|
|
894
|
-
applyEnv(env);
|
|
895
|
-
assertOptionsValid5(options);
|
|
896
|
-
const flags = await prepareFlags3(options);
|
|
897
|
-
const { ifCore } = getIfCoreFns();
|
|
898
|
-
const title = ifCore(
|
|
899
|
-
"Running dev web-server for Tamaro Core \u2026",
|
|
900
|
-
"Running dev web-server for customer configuration \u2026"
|
|
901
|
-
);
|
|
902
|
-
const wpBin = resolveBin("webpack");
|
|
903
|
-
const wpConfig = resolveOwn("dist/webpack.config.js");
|
|
904
|
-
const cmd = `
|
|
905
|
-
${wpBin} serve
|
|
906
|
-
--config ${wpConfig}
|
|
454
|
+
logTitle(`Deploying email configuration for "${configName}" customer configuration to AWS S3 …`);
|
|
455
|
+
logCommand(cmd);
|
|
456
|
+
try {
|
|
457
|
+
runCommandSync(cmd, { stdout: "inherit" });
|
|
458
|
+
} catch (error) {
|
|
459
|
+
halt(error.stderr);
|
|
460
|
+
}
|
|
461
|
+
logTitle(`Email configuration for "${configName}" customer configuration is deployed.`);
|
|
462
|
+
logDataTable({ "Deploy URL:": deployUrl });
|
|
463
|
+
process.on("exit", () => {
|
|
464
|
+
notify({
|
|
465
|
+
title: "deploy-email-config",
|
|
466
|
+
message: `Email configuration for "${configName}" customer configuration is deployed.`
|
|
467
|
+
});
|
|
468
|
+
});
|
|
469
|
+
};
|
|
470
|
+
const assertOptionsValid$6 = (options) => {
|
|
471
|
+
const { profile, bucket } = options;
|
|
472
|
+
if (profile) assertProfileValid(profile);
|
|
473
|
+
if (bucket) assertBucketValid$1(bucket);
|
|
474
|
+
};
|
|
475
|
+
const assertEmailConfigPathExists = (distPath) => {
|
|
476
|
+
if (!existsSync(distPath)) halt("Email config folder does not exists. Nothing to deploy.");
|
|
477
|
+
};
|
|
478
|
+
const assertIsNotCore$2 = () => {
|
|
479
|
+
const { ifCore } = getIfCoreFns();
|
|
480
|
+
if (ifCore()) halt("You cannot deploy widget email configuration for Tamaro Core.");
|
|
481
|
+
};
|
|
482
|
+
const assertBucketValid$1 = (bucket) => {
|
|
483
|
+
if (!["rnw-stage-email-service", "rnw-email-service"].includes(bucket)) halt("Invalid bucket name.");
|
|
484
|
+
};
|
|
485
|
+
const promptBucketTamaroEmailConfig$1 = async () => {
|
|
486
|
+
const { bucket } = await prompts([{
|
|
487
|
+
type: "select",
|
|
488
|
+
name: "bucket",
|
|
489
|
+
message: "Select environment",
|
|
490
|
+
choices: [{
|
|
491
|
+
title: "stage",
|
|
492
|
+
value: AWS_S3_BUCKET_TAMARO_EMAIL_CONFIG_STAGE
|
|
493
|
+
}, {
|
|
494
|
+
title: "prod",
|
|
495
|
+
value: AWS_S3_BUCKET_TAMARO_EMAIL_CONFIG_PROD
|
|
496
|
+
}]
|
|
497
|
+
}], { onCancel: () => halt() });
|
|
498
|
+
return bucket;
|
|
499
|
+
};
|
|
500
|
+
//#endregion
|
|
501
|
+
//#region src/commands/dev.ts
|
|
502
|
+
const dev = async (options) => {
|
|
503
|
+
const { env } = options;
|
|
504
|
+
applyEnv(env);
|
|
505
|
+
assertOptionsValid$5(options);
|
|
506
|
+
const flags = await prepareFlags$1(options);
|
|
507
|
+
const { ifCore } = getIfCoreFns();
|
|
508
|
+
const title = ifCore("Running dev web-server for Tamaro Core …", "Running dev web-server for customer configuration …");
|
|
509
|
+
const cmd = `
|
|
510
|
+
${resolveBin("webpack")} serve
|
|
511
|
+
--config ${resolveOwn("dist/webpack.config.js")}
|
|
907
512
|
${flags}
|
|
908
513
|
`;
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
};
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
};
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
};
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
};
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
assertConfigValid(config);
|
|
987
|
-
if (profile) {
|
|
988
|
-
assertProfileValid(profile);
|
|
989
|
-
}
|
|
990
|
-
};
|
|
991
|
-
var assertConfigValid = (config) => {
|
|
992
|
-
if (!config) {
|
|
993
|
-
return;
|
|
994
|
-
}
|
|
995
|
-
const regex = /^[a-zA-Z0-9-_]+$/;
|
|
996
|
-
if (!regex.test(config)) {
|
|
997
|
-
halt(
|
|
998
|
-
`Flag "--config" has forbidden format. Allowed format: ${regex.toString()}.`
|
|
999
|
-
);
|
|
1000
|
-
}
|
|
1001
|
-
};
|
|
1002
|
-
var parseTags = (lines) => {
|
|
1003
|
-
const regex = /^\s*PRE\s*/;
|
|
1004
|
-
return lines.filter((line) => regex.test(line)).map((line) => line.replace(regex, "").replace(/\/$/, ""));
|
|
1005
|
-
};
|
|
1006
|
-
|
|
1007
|
-
// src/commands/serve.ts
|
|
1008
|
-
import { resolve as resolve3 } from "path";
|
|
1009
|
-
import { getPortPromise as getPortPromise2 } from "portfinder";
|
|
1010
|
-
var serve = async (options) => {
|
|
1011
|
-
assertOptionsValid7(options);
|
|
1012
|
-
const flags = await prepareFlags4(options);
|
|
1013
|
-
const { ifCore } = getIfCoreFns();
|
|
1014
|
-
const paths = getPaths(ifCore);
|
|
1015
|
-
const cmd = `
|
|
1016
|
-
npx -y serve ${paths.appDist}
|
|
514
|
+
logTitle(title);
|
|
515
|
+
logCommand(cmd);
|
|
516
|
+
runCommandSync(cmd, { stdio: "inherit" });
|
|
517
|
+
};
|
|
518
|
+
const assertOptionsValid$5 = (options) => {
|
|
519
|
+
const { localCore, https, port, env } = options;
|
|
520
|
+
const { ifCore } = getIfCoreFns();
|
|
521
|
+
if (ifCore() && localCore) halt("Flag \"--local-core\" is redundant if running in Tamaro Core context.");
|
|
522
|
+
if (isNaN(Number(port))) halt("Flag \"--port\" should be a number.");
|
|
523
|
+
if (https) assertCrtExists();
|
|
524
|
+
assertEnvValid(env);
|
|
525
|
+
};
|
|
526
|
+
const prepareFlags$1 = async (options) => {
|
|
527
|
+
const flags = [];
|
|
528
|
+
const { localCore, port: defaultPort, https, nolint, debug } = options;
|
|
529
|
+
const port = await getPortPromise({ port: Number(defaultPort) });
|
|
530
|
+
if (localCore) flags.push("--env localCore");
|
|
531
|
+
flags.push(`--port ${port}`);
|
|
532
|
+
if (https) flags.push("--env https");
|
|
533
|
+
if (nolint) flags.push("--env nolint");
|
|
534
|
+
if (debug) flags.push("--env debug");
|
|
535
|
+
return flags.join(" ");
|
|
536
|
+
};
|
|
537
|
+
//#endregion
|
|
538
|
+
//#region src/commands/list-deployed.ts
|
|
539
|
+
const listDeployed = async (options) => {
|
|
540
|
+
if (!options.profile && !options.ci) {
|
|
541
|
+
assertProfilesPresent();
|
|
542
|
+
options.profile = await promptProfile();
|
|
543
|
+
}
|
|
544
|
+
assertOptionsValid$4(options);
|
|
545
|
+
awsAuthenticate(options);
|
|
546
|
+
const flags = prepareFlags$3(options);
|
|
547
|
+
const { config } = options;
|
|
548
|
+
const { ifCore } = getIfCoreFns();
|
|
549
|
+
const configName = config ?? ifCore("tamaro-core", getWidgetUuid());
|
|
550
|
+
const title = !config && ifCore() ? `Listing deployments of Tamaro Core …` : `Listing deployments of "${configName}" customer configuration …`;
|
|
551
|
+
const cmd = `aws s3 ls ${`s3://${AWS_S3_BUCKET_TAMARO}/${configName}/`} ${flags}`;
|
|
552
|
+
let out = "";
|
|
553
|
+
logTitle(title);
|
|
554
|
+
logCommand(cmd);
|
|
555
|
+
try {
|
|
556
|
+
out = runCommandSync(cmd).stdout;
|
|
557
|
+
} catch (error) {
|
|
558
|
+
out = error.stdout;
|
|
559
|
+
if (error.stderr) halt(error.stderr);
|
|
560
|
+
}
|
|
561
|
+
const tags = parseTags(out.split("\n"));
|
|
562
|
+
let text = "";
|
|
563
|
+
if (tags.length === 0) text = "No deployments found.";
|
|
564
|
+
else text = tags.map((tag, idx) => {
|
|
565
|
+
return `${idx + 1}. https://${AWS_S3_BUCKET_TAMARO}/${configName}/${tag}/index.html`;
|
|
566
|
+
}).join("\n");
|
|
567
|
+
console.log(`${text}\n`);
|
|
568
|
+
};
|
|
569
|
+
const assertOptionsValid$4 = (options) => {
|
|
570
|
+
const { config, profile } = options;
|
|
571
|
+
assertConfigValid(config);
|
|
572
|
+
if (profile) assertProfileValid(profile);
|
|
573
|
+
};
|
|
574
|
+
const assertConfigValid = (config) => {
|
|
575
|
+
if (!config) return;
|
|
576
|
+
const regex = /^[a-zA-Z0-9-_]+$/;
|
|
577
|
+
if (!regex.test(config)) halt(`Flag "--config" has forbidden format. Allowed format: ${regex.toString()}.`);
|
|
578
|
+
};
|
|
579
|
+
const parseTags = (lines) => {
|
|
580
|
+
const regex = /^\s*PRE\s*/;
|
|
581
|
+
return lines.filter((line) => regex.test(line)).map((line) => line.replace(regex, "").replace(/\/$/, ""));
|
|
582
|
+
};
|
|
583
|
+
//#endregion
|
|
584
|
+
//#region src/commands/serve.ts
|
|
585
|
+
const serve = async (options) => {
|
|
586
|
+
assertOptionsValid$3(options);
|
|
587
|
+
const flags = await prepareFlags(options);
|
|
588
|
+
const { ifCore } = getIfCoreFns();
|
|
589
|
+
const cmd = `
|
|
590
|
+
npx -y serve ${getPaths(ifCore).appDist}
|
|
1017
591
|
--cors
|
|
1018
592
|
${flags}
|
|
1019
593
|
`;
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
};
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
};
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
};
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
};
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
};
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
};
|
|
1099
|
-
|
|
1100
|
-
if (existsSync7(restoreTarget)) {
|
|
1101
|
-
halt(
|
|
1102
|
-
`Restore target already exists: ${restoreTarget}. Please remove it first.`
|
|
1103
|
-
);
|
|
1104
|
-
}
|
|
1105
|
-
};
|
|
1106
|
-
|
|
1107
|
-
// src/commands/undeploy.ts
|
|
1108
|
-
var undeploy = async (options) => {
|
|
1109
|
-
const { ifCore } = getIfCoreFns();
|
|
1110
|
-
const configName = ifCore(CORE_CONFIG_NAME, getWidgetUuid());
|
|
1111
|
-
if (!options.profile && !options.ci) {
|
|
1112
|
-
assertProfilesPresent();
|
|
1113
|
-
options.profile = await promptProfile();
|
|
1114
|
-
}
|
|
1115
|
-
assertOptionsValid9(options);
|
|
1116
|
-
awsAuthenticate(options);
|
|
1117
|
-
const flags = prepareFlags(options);
|
|
1118
|
-
const { tag, all, dryrun } = options;
|
|
1119
|
-
const dryRunFlag = dryrun ? `--dryrun` : "";
|
|
1120
|
-
const deployUrl = all ? `s3://${AWS_S3_BUCKET_TAMARO}/${configName}/` : `s3://${AWS_S3_BUCKET_TAMARO}/${configName}/${tag}/`;
|
|
1121
|
-
const description = all ? `all tags of "${configName}"` : `tag "${tag}" of "${configName}"`;
|
|
1122
|
-
if (dryRunFlag) {
|
|
1123
|
-
logTitle("\u{1F9EA} DRY RUN MODE - No actual changes will be made \u{1F9EA}");
|
|
1124
|
-
}
|
|
1125
|
-
await promptConfirmation(
|
|
1126
|
-
`Are you sure you want to undeploy ${description}?`,
|
|
1127
|
-
options.ci
|
|
1128
|
-
);
|
|
1129
|
-
const cmd = `
|
|
594
|
+
logTitle(`Running web-server for pre-built bundle …`);
|
|
595
|
+
logCommand(cmd);
|
|
596
|
+
runCommandSync(cmd, { stdio: "inherit" });
|
|
597
|
+
};
|
|
598
|
+
const assertOptionsValid$3 = (options) => {
|
|
599
|
+
const { port, https } = options;
|
|
600
|
+
if (isNaN(Number(port))) halt("Flag \"--port\" should be a number.");
|
|
601
|
+
if (https) assertCrtExists();
|
|
602
|
+
};
|
|
603
|
+
const prepareFlags = async (options) => {
|
|
604
|
+
const flags = [];
|
|
605
|
+
const { port: defaultPort, https } = options;
|
|
606
|
+
const port = await getPortPromise({ port: Number(defaultPort) });
|
|
607
|
+
flags.push(`-p ${port}`);
|
|
608
|
+
if (https) {
|
|
609
|
+
const { ifCore } = getIfCoreFns();
|
|
610
|
+
const paths = getPaths(ifCore);
|
|
611
|
+
const certFile = resolve(paths.root, HTTPS_CRT_FILE);
|
|
612
|
+
const keyFile = resolve(paths.root, HTTPS_KEY_FILE);
|
|
613
|
+
flags.push(`--ssl-cert ${certFile}`);
|
|
614
|
+
flags.push(`--ssl-key ${keyFile}`);
|
|
615
|
+
}
|
|
616
|
+
return flags.join(" ");
|
|
617
|
+
};
|
|
618
|
+
//#endregion
|
|
619
|
+
//#region src/commands/unarchive.ts
|
|
620
|
+
const unarchive = (options) => {
|
|
621
|
+
const { ifCore } = getIfCoreFns({ allowArchived: true });
|
|
622
|
+
assertIsNotCore$1(ifCore);
|
|
623
|
+
assertIsArchived();
|
|
624
|
+
const configName = getWidgetUuid();
|
|
625
|
+
const cwd = process.cwd();
|
|
626
|
+
const restoreTarget = resolve(dirname(dirname(cwd)), configName);
|
|
627
|
+
assertRestoreTargetDoesNotExist(restoreTarget);
|
|
628
|
+
assertOptionsValid$2(options);
|
|
629
|
+
if (options.dryrun) logTitle("🧪 DRY RUN MODE - No actual changes will be made 🧪");
|
|
630
|
+
if (!options.dryrun) {
|
|
631
|
+
renameSync(cwd, restoreTarget);
|
|
632
|
+
process.chdir(restoreTarget);
|
|
633
|
+
} else logTitle(`Would move ${cwd} → ${restoreTarget}`);
|
|
634
|
+
logTitle(`✅ "${configName}" has been unarchived and moved to ${restoreTarget}`);
|
|
635
|
+
process.on("exit", () => {
|
|
636
|
+
notify({
|
|
637
|
+
title: "unarchive",
|
|
638
|
+
message: `"${configName}" has been unarchived.`
|
|
639
|
+
});
|
|
640
|
+
});
|
|
641
|
+
};
|
|
642
|
+
const assertOptionsValid$2 = (options) => {
|
|
643
|
+
const { profile } = options;
|
|
644
|
+
if (profile) assertProfileValid(profile);
|
|
645
|
+
};
|
|
646
|
+
const assertIsArchived = () => {
|
|
647
|
+
if (basename(dirname(process.cwd())) !== "_archived") halt("This configuration is not archived. Only archived configurations can be unarchived.");
|
|
648
|
+
};
|
|
649
|
+
const assertIsNotCore$1 = (ifCore) => {
|
|
650
|
+
if (ifCore()) halt("You cannot unarchive Tamaro Core.");
|
|
651
|
+
};
|
|
652
|
+
const assertRestoreTargetDoesNotExist = (restoreTarget) => {
|
|
653
|
+
if (existsSync(restoreTarget)) halt(`Restore target already exists: ${restoreTarget}. Please remove it first.`);
|
|
654
|
+
};
|
|
655
|
+
//#endregion
|
|
656
|
+
//#region src/commands/undeploy.ts
|
|
657
|
+
const undeploy = async (options) => {
|
|
658
|
+
const { ifCore } = getIfCoreFns();
|
|
659
|
+
const configName = ifCore(CORE_CONFIG_NAME, getWidgetUuid());
|
|
660
|
+
if (!options.profile && !options.ci) {
|
|
661
|
+
assertProfilesPresent();
|
|
662
|
+
options.profile = await promptProfile();
|
|
663
|
+
}
|
|
664
|
+
assertOptionsValid$1(options);
|
|
665
|
+
awsAuthenticate(options);
|
|
666
|
+
const flags = prepareFlags$3(options);
|
|
667
|
+
const { tag = DEFAULT_TAG, all, dryrun } = options;
|
|
668
|
+
const dryRunFlag = dryrun ? `--dryrun` : "";
|
|
669
|
+
const deployUrl = all ? `s3://${AWS_S3_BUCKET_TAMARO}/${configName}/` : `s3://${AWS_S3_BUCKET_TAMARO}/${configName}/${tag}/`;
|
|
670
|
+
const description = all ? `all tags of "${configName}"` : `tag "${tag}" of "${configName}"`;
|
|
671
|
+
if (dryRunFlag) logTitle("🧪 DRY RUN MODE - No actual changes will be made 🧪");
|
|
672
|
+
await promptConfirmation(`Are you sure you want to undeploy ${description}?`, options.yes);
|
|
673
|
+
const cmd = `
|
|
1130
674
|
aws s3 rm ${deployUrl}
|
|
1131
675
|
--recursive
|
|
1132
676
|
${flags}
|
|
1133
677
|
${dryRunFlag}
|
|
1134
678
|
`;
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
const cmdInvalidateCache = `
|
|
679
|
+
logTitle(`Undeploying ${description} from AWS S3 …`);
|
|
680
|
+
logCommand(cmd);
|
|
681
|
+
try {
|
|
682
|
+
runCommandSync(cmd, { stdout: "inherit" });
|
|
683
|
+
} catch (error) {
|
|
684
|
+
halt(error.stderr);
|
|
685
|
+
}
|
|
686
|
+
if (!dryRunFlag) {
|
|
687
|
+
const cmdInvalidateCache = `
|
|
1145
688
|
aws cloudfront create-invalidation
|
|
1146
689
|
--distribution-id ${AWS_CLOUDFRONT_DISTRIBUTION_ID}
|
|
1147
|
-
--paths ${
|
|
690
|
+
--paths ${all ? `/${configName}/*` : `/${configName}/${tag}/*`}
|
|
1148
691
|
${flags}
|
|
1149
692
|
`;
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
}
|
|
1200
|
-
assertOptionsValid10(options);
|
|
1201
|
-
awsAuthenticate(options);
|
|
1202
|
-
const flags = prepareFlags(options);
|
|
1203
|
-
const dryRunFlag = options.dryrun ? `--dryrun` : "";
|
|
1204
|
-
const configName = getWidgetUuid();
|
|
1205
|
-
const deployUrl = `s3://${options.bucket}/${configName}/`;
|
|
1206
|
-
await promptConfirmation(
|
|
1207
|
-
`Are you sure you want to undeploy the email configuration for "${configName}" from "${options.bucket}"?`,
|
|
1208
|
-
options.ci
|
|
1209
|
-
);
|
|
1210
|
-
if (dryRunFlag) {
|
|
1211
|
-
logTitle("\u{1F9EA} DRY RUN MODE - No actual changes will be made \u{1F9EA}");
|
|
1212
|
-
}
|
|
1213
|
-
const cmd = `
|
|
693
|
+
logTitle("\nInvalidating edge cache …");
|
|
694
|
+
logCommand(cmdInvalidateCache);
|
|
695
|
+
try {
|
|
696
|
+
runCommandSync(cmdInvalidateCache);
|
|
697
|
+
} catch (error) {
|
|
698
|
+
halt(error.stderr);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
logTitle(`\n${description} has been undeployed.`);
|
|
702
|
+
logDataTable({ "Removed URL:": deployUrl });
|
|
703
|
+
process.on("exit", () => {
|
|
704
|
+
notify({
|
|
705
|
+
title: "undeploy",
|
|
706
|
+
message: `${description} has been undeployed.`
|
|
707
|
+
});
|
|
708
|
+
});
|
|
709
|
+
};
|
|
710
|
+
const assertOptionsValid$1 = (options) => {
|
|
711
|
+
const { profile, tag, all } = options;
|
|
712
|
+
const { ifCore } = getIfCoreFns();
|
|
713
|
+
if (ifCore() && all) halt("Flag \"--all\" must not be used in Tamaro Core context.");
|
|
714
|
+
if (ifCore() && tag === "latest") halt("You cannot undeploy the default tag for Tamaro Core.");
|
|
715
|
+
if (profile) assertProfileValid(profile);
|
|
716
|
+
if (all && tag) halt("Flags \"--tag\" and \"--all\" must not be used together.");
|
|
717
|
+
if (!all && tag) assertTagValid(tag);
|
|
718
|
+
};
|
|
719
|
+
//#endregion
|
|
720
|
+
//#region src/commands/undeploy-email-config.ts
|
|
721
|
+
const undeployEmailConfig = async (options) => {
|
|
722
|
+
const { ifCore } = getIfCoreFns();
|
|
723
|
+
assertIsNotCore(ifCore);
|
|
724
|
+
if (!options.profile && !options.ci) {
|
|
725
|
+
assertProfilesPresent();
|
|
726
|
+
options.profile = await promptProfile();
|
|
727
|
+
}
|
|
728
|
+
if (options.ci) options.bucket = AWS_S3_BUCKET_TAMARO_EMAIL_CONFIG_PROD;
|
|
729
|
+
if (!options.bucket) if (options.ci) options.bucket = AWS_S3_BUCKET_TAMARO_EMAIL_CONFIG_PROD;
|
|
730
|
+
else if (options.prod) options.bucket = AWS_S3_BUCKET_TAMARO_EMAIL_CONFIG_PROD;
|
|
731
|
+
else if (options.stage) options.bucket = AWS_S3_BUCKET_TAMARO_EMAIL_CONFIG_STAGE;
|
|
732
|
+
else options.bucket = await promptBucketTamaroEmailConfig();
|
|
733
|
+
assertOptionsValid(options);
|
|
734
|
+
awsAuthenticate(options);
|
|
735
|
+
const flags = prepareFlags$3(options);
|
|
736
|
+
const dryRunFlag = options.dryrun ? `--dryrun` : "";
|
|
737
|
+
const configName = getWidgetUuid();
|
|
738
|
+
const deployUrl = `s3://${options.bucket}/${configName}/`;
|
|
739
|
+
await promptConfirmation(`Are you sure you want to undeploy the email configuration for "${configName}" from "${options.bucket}"?`, options.ci);
|
|
740
|
+
if (dryRunFlag) logTitle("🧪 DRY RUN MODE - No actual changes will be made 🧪");
|
|
741
|
+
const cmd = `
|
|
1214
742
|
aws s3 rm ${deployUrl}
|
|
1215
743
|
--recursive
|
|
1216
744
|
${flags}
|
|
1217
745
|
${dryRunFlag}
|
|
1218
746
|
`;
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
};
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
};
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
}
|
|
1273
|
-
],
|
|
1274
|
-
{
|
|
1275
|
-
onCancel: () => halt()
|
|
1276
|
-
}
|
|
1277
|
-
);
|
|
1278
|
-
return bucket;
|
|
1279
|
-
};
|
|
1280
|
-
|
|
1281
|
-
// package.json
|
|
1282
|
-
var package_default = {
|
|
1283
|
-
name: "@raisenow/tamaro-cli",
|
|
1284
|
-
version: "1.7.0-dev.0",
|
|
1285
|
-
author: {
|
|
1286
|
-
name: "RaiseNow",
|
|
1287
|
-
email: "development@raisenow.com"
|
|
1288
|
-
},
|
|
1289
|
-
type: "module",
|
|
1290
|
-
bin: "dist/cli.js",
|
|
1291
|
-
packageManager: "pnpm@10.28.2",
|
|
1292
|
-
engines: {
|
|
1293
|
-
node: ">=22.22.0",
|
|
1294
|
-
pnpm: ">=10.28.2",
|
|
1295
|
-
npm: "please-use-pnpm",
|
|
1296
|
-
yarn: "please-use-pnpm"
|
|
1297
|
-
},
|
|
1298
|
-
scripts: {
|
|
1299
|
-
prepare: "pnpm build",
|
|
1300
|
-
typecheck: "tsc --noEmit",
|
|
1301
|
-
build: "tsup src/cli.ts src/webpack.config.ts --clean --shims --format esm",
|
|
1302
|
-
"build:watch": "pnpm build --watch --ignore-watch .history --ignore-watch .idea",
|
|
1303
|
-
dev: "pnpm build:watch",
|
|
1304
|
-
readme: "pnpx http-server . --cors -o /readme.html",
|
|
1305
|
-
lint: "DEBUG=eslint:cli-engine eslint .",
|
|
1306
|
-
"lint:fix": "DEBUG=eslint:cli-engine eslint --fix .",
|
|
1307
|
-
format: "prettier --write .",
|
|
1308
|
-
test: "vitest",
|
|
1309
|
-
"test:watch": "vitest --watch",
|
|
1310
|
-
"test:coverage": "vitest --coverage"
|
|
1311
|
-
},
|
|
1312
|
-
dependencies: {
|
|
1313
|
-
"@babel/cli": "^7.28.6",
|
|
1314
|
-
"@babel/core": "^7.29.0",
|
|
1315
|
-
"@babel/plugin-proposal-decorators": "^7.29.0",
|
|
1316
|
-
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
|
1317
|
-
"@babel/plugin-transform-runtime": "^7.29.0",
|
|
1318
|
-
"@babel/preset-env": "^7.29.0",
|
|
1319
|
-
"@babel/preset-react": "^7.28.5",
|
|
1320
|
-
"@babel/preset-typescript": "^7.28.5",
|
|
1321
|
-
"@babel/runtime-corejs3": "^7.29.0",
|
|
1322
|
-
"@pmmmwh/react-refresh-webpack-plugin": "^0.6.2",
|
|
1323
|
-
"@statoscope/webpack-plugin": "^5.29.0",
|
|
1324
|
-
"@types/columnify": "^1.5.4",
|
|
1325
|
-
"@types/handlebars-helpers": "^0.5.6",
|
|
1326
|
-
"@types/lodash": "^4.17.23",
|
|
1327
|
-
"@types/node": "^22.19.8",
|
|
1328
|
-
"@types/node-notifier": "^8.0.5",
|
|
1329
|
-
"@types/prompts": "^2.4.9",
|
|
1330
|
-
"@types/resolve-bin": "^0.4.3",
|
|
1331
|
-
"@types/webpack-config-utils": "^2.3.4",
|
|
1332
|
-
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
|
1333
|
-
"@typescript-eslint/parser": "^7.18.0",
|
|
1334
|
-
autoprefixer: "^10.4.24",
|
|
1335
|
-
"babel-loader": "^10.0.0",
|
|
1336
|
-
"babel-plugin-istanbul": "^7.0.1",
|
|
1337
|
-
"babel-plugin-lodash": "^3.3.4",
|
|
1338
|
-
chalk: "^5.6.2",
|
|
1339
|
-
"clean-webpack-plugin": "^4.0.0",
|
|
1340
|
-
columnify: "^1.6.0",
|
|
1341
|
-
commander: "^14.0.3",
|
|
1342
|
-
"copy-webpack-plugin": "^13.0.1",
|
|
1343
|
-
"core-js": "^3.48.0",
|
|
1344
|
-
"css-loader": "^7.1.3",
|
|
1345
|
-
"css-minimizer-webpack-plugin": "^7.0.4",
|
|
1346
|
-
dotenv: "^17.2.3",
|
|
1347
|
-
"env-paths": "^4.0.0",
|
|
1348
|
-
"escape-string-regexp": "^5.0.0",
|
|
1349
|
-
eslint: "^8.57.1",
|
|
1350
|
-
"eslint-config-prettier": "^10.1.8",
|
|
1351
|
-
"eslint-import-resolver-typescript": "^3.10.1",
|
|
1352
|
-
"eslint-plugin-deprecation": "^3.0.0",
|
|
1353
|
-
"eslint-plugin-import": "^2.32.0",
|
|
1354
|
-
"eslint-plugin-markdownlint": "^0.9.0",
|
|
1355
|
-
"eslint-plugin-promise": "^7.2.1",
|
|
1356
|
-
"eslint-plugin-unused-imports": "^3.2.0",
|
|
1357
|
-
"eslint-plugin-yml": "^1.19.1",
|
|
1358
|
-
"eslint-webpack-plugin": "^5.0.2",
|
|
1359
|
-
execa: "^9.6.1",
|
|
1360
|
-
"file-loader": "^6.2.0",
|
|
1361
|
-
"fork-ts-checker-webpack-plugin": "^9.1.0",
|
|
1362
|
-
glob: "^13.0.1",
|
|
1363
|
-
handlebars: "^4.7.8",
|
|
1364
|
-
"handlebars-helpers": "^0.10.0",
|
|
1365
|
-
"html-loader": "^5.1.0",
|
|
1366
|
-
"html-webpack-plugin": "^5.6.6",
|
|
1367
|
-
"js-yaml": "^4.1.1",
|
|
1368
|
-
"json-loader": "^0.5.7",
|
|
1369
|
-
ky: "^1.14.3",
|
|
1370
|
-
lodash: "^4.17.23",
|
|
1371
|
-
"mini-css-extract-plugin": "^2.10.0",
|
|
1372
|
-
"node-notifier": "^10.0.1",
|
|
1373
|
-
portfinder: "^1.0.38",
|
|
1374
|
-
postcss: "^8.5.6",
|
|
1375
|
-
"postcss-custom-properties": "^14.0.6",
|
|
1376
|
-
"postcss-import": "^16.1.1",
|
|
1377
|
-
"postcss-loader": "^8.2.0",
|
|
1378
|
-
"postcss-nested": "^7.0.2",
|
|
1379
|
-
prettier: "^3.8.1",
|
|
1380
|
-
prompts: "^2.4.2",
|
|
1381
|
-
"react-refresh": "^0.18.0",
|
|
1382
|
-
"resolve-url-loader": "^5.0.0",
|
|
1383
|
-
sass: "^1.97.3",
|
|
1384
|
-
"sass-loader": "^16.0.6",
|
|
1385
|
-
"strip-indent": "^4.1.1",
|
|
1386
|
-
"style-loader": "^4.0.0",
|
|
1387
|
-
"terser-webpack-plugin": "^5.3.16",
|
|
1388
|
-
"tsconfig-paths-webpack-plugin": "^4.2.0",
|
|
1389
|
-
tsup: "^8.5.1",
|
|
1390
|
-
typescript: "^5.9.3",
|
|
1391
|
-
"url-loader": "^4.1.1",
|
|
1392
|
-
vitest: "^4.0.18",
|
|
1393
|
-
webpack: "^5.105.0",
|
|
1394
|
-
"webpack-cli": "^6.0.1",
|
|
1395
|
-
"webpack-config-utils": "^2.3.1",
|
|
1396
|
-
"webpack-dev-server": "^5.2.3",
|
|
1397
|
-
"yaml-loader": "^0.9.0",
|
|
1398
|
-
zod: "^4.3.6"
|
|
1399
|
-
},
|
|
1400
|
-
devDependencies: {
|
|
1401
|
-
"@types/js-yaml": "^4.0.9"
|
|
1402
|
-
}
|
|
1403
|
-
};
|
|
1404
|
-
|
|
1405
|
-
// src/cli.ts
|
|
747
|
+
logTitle(`Undeploying email configuration for "${configName}" from AWS S3 …`);
|
|
748
|
+
logCommand(cmd);
|
|
749
|
+
try {
|
|
750
|
+
runCommandSync(cmd, { stdout: "inherit" });
|
|
751
|
+
} catch (error) {
|
|
752
|
+
halt(error.stderr);
|
|
753
|
+
}
|
|
754
|
+
logTitle(`Email configuration for "${configName}" has been undeployed from "${options.bucket}".`);
|
|
755
|
+
logDataTable({ "Removed URL:": deployUrl });
|
|
756
|
+
process.on("exit", () => {
|
|
757
|
+
notify({
|
|
758
|
+
title: "undeploy-email-config",
|
|
759
|
+
message: `Email configuration for "${configName}" has been undeployed.`
|
|
760
|
+
});
|
|
761
|
+
});
|
|
762
|
+
};
|
|
763
|
+
const assertOptionsValid = (options) => {
|
|
764
|
+
const { profile, bucket } = options;
|
|
765
|
+
if (profile) assertProfileValid(profile);
|
|
766
|
+
if (bucket) assertBucketValid(bucket);
|
|
767
|
+
};
|
|
768
|
+
const assertIsNotCore = (ifCore) => {
|
|
769
|
+
if (ifCore()) halt("You cannot undeploy widget email configuration for Tamaro Core.");
|
|
770
|
+
};
|
|
771
|
+
const assertBucketValid = (bucket) => {
|
|
772
|
+
if (!["rnw-stage-email-service", "rnw-email-service"].includes(bucket)) halt("Invalid bucket name.");
|
|
773
|
+
};
|
|
774
|
+
const promptBucketTamaroEmailConfig = async () => {
|
|
775
|
+
const { bucket } = await prompts([{
|
|
776
|
+
type: "select",
|
|
777
|
+
name: "bucket",
|
|
778
|
+
message: "Select environment",
|
|
779
|
+
choices: [{
|
|
780
|
+
title: "stage",
|
|
781
|
+
value: AWS_S3_BUCKET_TAMARO_EMAIL_CONFIG_STAGE
|
|
782
|
+
}, {
|
|
783
|
+
title: "prod",
|
|
784
|
+
value: AWS_S3_BUCKET_TAMARO_EMAIL_CONFIG_PROD
|
|
785
|
+
}]
|
|
786
|
+
}], { onCancel: () => halt() });
|
|
787
|
+
return bucket;
|
|
788
|
+
};
|
|
789
|
+
//#endregion
|
|
790
|
+
//#region package.json
|
|
791
|
+
var name = "@raisenow/tamaro-cli";
|
|
792
|
+
var version = "1.7.0-dev.2";
|
|
793
|
+
//#endregion
|
|
794
|
+
//#region src/cli.ts
|
|
795
|
+
/**
|
|
796
|
+
* Makes the script crash on unhandled rejections instead of silently
|
|
797
|
+
* ignoring them. In the future, promise rejections that are not handled will
|
|
798
|
+
* terminate the Node.js process with a non-zero exit code.
|
|
799
|
+
*/
|
|
1406
800
|
process.on("unhandledRejection", (error) => {
|
|
1407
|
-
|
|
801
|
+
throw error;
|
|
1408
802
|
});
|
|
1409
803
|
process.on("SIGINT", () => {
|
|
1410
|
-
|
|
1411
|
-
});
|
|
1412
|
-
var cli = createCommand().name(package_default.name).version(package_default.version, "-v, --version");
|
|
1413
|
-
cli.command("dev").description(
|
|
1414
|
-
"Run the local development server for Tamaro Core or a particular customer configuration"
|
|
1415
|
-
).option(
|
|
1416
|
-
"--local-core",
|
|
1417
|
-
"Load Tamaro Core from localhost:1234 instead of the CDN",
|
|
1418
|
-
false
|
|
1419
|
-
).option(
|
|
1420
|
-
"--https",
|
|
1421
|
-
"Let local web server serve Tamaro with SSL encryption",
|
|
1422
|
-
false
|
|
1423
|
-
).option("--port <port>", "Web server port", `${DEFAULT_PORT}`).option("--env <env>", "Environment (dev, stage, prod)").option("--nolint", "Disable ESLint", false).action(async (options) => {
|
|
1424
|
-
await dev(options);
|
|
804
|
+
halt();
|
|
1425
805
|
});
|
|
1426
|
-
cli.
|
|
1427
|
-
|
|
1428
|
-
)
|
|
1429
|
-
"--local-core",
|
|
1430
|
-
"Load Tamaro Core from localhost:1234 instead of the CDN",
|
|
1431
|
-
false
|
|
1432
|
-
).option("--analyze", 'Generate bundle statistics to "reports" folder', false).option("--serve", "Run the generated bundle with a local web server", false).option(
|
|
1433
|
-
"--https",
|
|
1434
|
-
"Let local web server serve Tamaro with SSL encryption",
|
|
1435
|
-
false
|
|
1436
|
-
).option("--port <port>", "Web server port", `${DEFAULT_PORT}`).option("--env <env>", "Environment (dev, stage, prod)").option("--profile <profile>", "AWS profile").option("--ci", "CI environment", false).option(
|
|
1437
|
-
"--deploy",
|
|
1438
|
-
"Deploy Tamaro Core or a customer configuration bundle to AWS S3",
|
|
1439
|
-
false
|
|
1440
|
-
).option(
|
|
1441
|
-
"--tag <tag>",
|
|
1442
|
-
"Tag which should be used for the deployment of the bundle",
|
|
1443
|
-
DEFAULT_TAG
|
|
1444
|
-
).option("--nolint", "Disable ESLint", false).action(async (options) => {
|
|
1445
|
-
await build(options);
|
|
1446
|
-
if (options.serve) {
|
|
1447
|
-
await serve(options);
|
|
1448
|
-
}
|
|
1449
|
-
if (options.deploy) {
|
|
1450
|
-
await deploy(options);
|
|
1451
|
-
}
|
|
806
|
+
const cli = createCommand().name(name).version(version, "-v, --version");
|
|
807
|
+
cli.command("dev").description("Run the local development server for Tamaro Core or a particular customer configuration").option("--local-core", "Load Tamaro Core from localhost:1234 instead of the CDN", false).option("--https", "Let local web server serve Tamaro with SSL encryption", false).option("--port <port>", "Web server port", `${DEFAULT_PORT}`).option("--env <env>", "Environment (dev, stage, prod)").option("--nolint", "Disable ESLint", false).option("--debug", "Enable debug mode", false).action(async (options) => {
|
|
808
|
+
await dev(options);
|
|
1452
809
|
});
|
|
1453
|
-
cli.command("
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
).action(async (options) => {
|
|
1458
|
-
await serve(options);
|
|
810
|
+
cli.command("build").description("Build an optimised (minified) bundle of Tamaro Core or a customer configuration").option("--local-core", "Load Tamaro Core from localhost:1234 instead of the CDN", false).option("--analyze", "Generate bundle statistics to \"reports\" folder", false).option("--serve", "Run the generated bundle with a local web server", false).option("--https", "Let local web server serve Tamaro with SSL encryption", false).option("--port <port>", "Web server port", `${DEFAULT_PORT}`).option("--env <env>", "Environment (dev, stage, prod)").option("--profile <profile>", "AWS profile").option("--ci", "CI environment", false).option("--deploy", "Deploy Tamaro Core or a customer configuration bundle to AWS S3", false).option("--tag <tag>", "Tag which should be used for the deployment of the bundle", DEFAULT_TAG).option("--nolint", "Disable ESLint", false).option("--debug", "Enable debug mode", false).action(async (options) => {
|
|
811
|
+
await build(options);
|
|
812
|
+
if (options.serve) await serve(options);
|
|
813
|
+
if (options.deploy) await deploy(options);
|
|
1459
814
|
});
|
|
1460
|
-
cli.command("
|
|
1461
|
-
|
|
1462
|
-
).option("--profile <profile>", "AWS profile").option("--ci", "CI environment", false).option(
|
|
1463
|
-
"--tag <tag>",
|
|
1464
|
-
"Tag which should be used for the deployment of the bundle",
|
|
1465
|
-
DEFAULT_TAG
|
|
1466
|
-
).option(
|
|
1467
|
-
"--dryrun",
|
|
1468
|
-
"Displays the operations that would be performed without actually running them",
|
|
1469
|
-
false
|
|
1470
|
-
).action(async (options) => {
|
|
1471
|
-
await deploy(options);
|
|
815
|
+
cli.command("serve").description("Run a local web server for pre-built bundle").option("--port <port>", "Web server port", `${DEFAULT_PORT}`).option("--https", "Let local web server serve Tamaro with SSL encryption", false).action(async (options) => {
|
|
816
|
+
await serve(options);
|
|
1472
817
|
});
|
|
1473
|
-
cli.command("
|
|
1474
|
-
|
|
1475
|
-
).option("--profile <profile>", "AWS profile").option("--ci", "CI environment", false).option(
|
|
1476
|
-
"--config <config>",
|
|
1477
|
-
"Configuration name (default: current customer configuration)"
|
|
1478
|
-
).action(async (options) => {
|
|
1479
|
-
await listDeployed(options);
|
|
818
|
+
cli.command("deploy").description("Deploy a pre-built Tamaro Core or 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).action(async (options) => {
|
|
819
|
+
await deploy(options);
|
|
1480
820
|
});
|
|
1481
|
-
cli.command("
|
|
1482
|
-
|
|
1483
|
-
"Displays the operations that would be performed without actually running them",
|
|
1484
|
-
false
|
|
1485
|
-
).action(async (options) => {
|
|
1486
|
-
await deployEmailConfig(options);
|
|
821
|
+
cli.command("list-deployed").description("List deployments of Tamaro Core or a particular customer configuration").option("--profile <profile>", "AWS profile").option("--ci", "CI environment", false).option("--config <config>", "Configuration name (default: current customer configuration)").action(async (options) => {
|
|
822
|
+
await listDeployed(options);
|
|
1487
823
|
});
|
|
1488
|
-
cli.command("
|
|
1489
|
-
|
|
1490
|
-
).option("--profile <profile>", "AWS profile").option("--ci", "CI environment", false).option("--tag <tag>", "Tag which should be undeployed", DEFAULT_TAG).option("--all", "Undeploy all tags", false).option(
|
|
1491
|
-
"--dryrun",
|
|
1492
|
-
"Displays the operations that would be performed without actually running them",
|
|
1493
|
-
false
|
|
1494
|
-
).action(async (options) => {
|
|
1495
|
-
await undeploy(options);
|
|
824
|
+
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(async (options) => {
|
|
825
|
+
await deployEmailConfig(options);
|
|
1496
826
|
});
|
|
1497
|
-
cli.command("undeploy
|
|
1498
|
-
|
|
1499
|
-
"Displays the operations that would be performed without actually running them",
|
|
1500
|
-
false
|
|
1501
|
-
).action(async (options) => {
|
|
1502
|
-
await undeployEmailConfig(options);
|
|
827
|
+
cli.command("undeploy").description("Undeploy a Tamaro Core or 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(async (options) => {
|
|
828
|
+
await undeploy(options);
|
|
1503
829
|
});
|
|
1504
|
-
cli.command("
|
|
1505
|
-
|
|
1506
|
-
).option("--profile <profile>", "AWS profile").option("--ci", "CI environment", false).option(
|
|
1507
|
-
"--dryrun",
|
|
1508
|
-
"Displays the operations that would be performed without actually running them",
|
|
1509
|
-
false
|
|
1510
|
-
).action((options) => {
|
|
1511
|
-
archive(options);
|
|
830
|
+
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(async (options) => {
|
|
831
|
+
await undeployEmailConfig(options);
|
|
1512
832
|
});
|
|
1513
|
-
cli.command("
|
|
1514
|
-
|
|
1515
|
-
).option("--profile <profile>", "AWS profile").option("--ci", "CI environment", false).option(
|
|
1516
|
-
"--dryrun",
|
|
1517
|
-
"Displays the operations that would be performed without actually running them",
|
|
1518
|
-
false
|
|
1519
|
-
).action((options) => {
|
|
1520
|
-
unarchive(options);
|
|
833
|
+
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).action((options) => {
|
|
834
|
+
archive(options);
|
|
1521
835
|
});
|
|
1522
|
-
cli.command("
|
|
1523
|
-
|
|
1524
|
-
"Displays the operations that would be performed without actually running them",
|
|
1525
|
-
false
|
|
1526
|
-
).action(async (options) => {
|
|
1527
|
-
await updateEpms(options);
|
|
836
|
+
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).action((options) => {
|
|
837
|
+
unarchive(options);
|
|
1528
838
|
});
|
|
1529
|
-
cli.command("validate").description(
|
|
1530
|
-
|
|
1531
|
-
).action(async () => {
|
|
1532
|
-
await validate();
|
|
839
|
+
cli.command("validate").description("Validate the current Tamaro configuration to avoid common errors").action(async () => {
|
|
840
|
+
await validate();
|
|
1533
841
|
});
|
|
1534
842
|
(async () => {
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
logError(error.stack);
|
|
1546
|
-
}
|
|
1547
|
-
}
|
|
843
|
+
try {
|
|
844
|
+
logTitle(`${name} ${version}\n`);
|
|
845
|
+
await cli.parseAsync(process.argv);
|
|
846
|
+
} catch (error) {
|
|
847
|
+
if (error.signal === "SIGINT" && error.signalDescription) logError(`\n${error.signalDescription}`);
|
|
848
|
+
else {
|
|
849
|
+
console.log("");
|
|
850
|
+
logError(error.stack);
|
|
851
|
+
}
|
|
852
|
+
}
|
|
1548
853
|
})();
|
|
854
|
+
//#endregion
|
|
855
|
+
export {};
|