@automattic/vip 2.32.2 → 2.32.4
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/CHANGELOG.md +22 -0
- package/assets/dev-env.lando.template.yml.ejs +10 -2
- package/dist/bin/vip-dev-env-exec.js +1 -7
- package/dist/bin/vip-dev-env-shell.js +0 -4
- package/dist/bin/vip-dev-env-start.js +1 -1
- package/dist/bin/vip-dev-env-sync-sql.js +8 -6
- package/dist/bin/vip-dev-env-update.js +1 -2
- package/dist/bin/vip-import-sql.js +2 -2
- package/dist/bin/vip-logout.js +23 -0
- package/dist/bin/vip-slowlogs.js +192 -0
- package/dist/bin/vip-validate-preflight.js +8 -10
- package/dist/bin/vip-whoami.js +1 -2
- package/dist/bin/vip.js +1 -5
- package/dist/commands/backup-db.js +8 -9
- package/dist/lib/api/app.js +2 -2
- package/dist/lib/api/cache-purge.js +2 -2
- package/dist/lib/api/http.js +2 -3
- package/dist/lib/app-logs/app-logs.js +2 -2
- package/dist/lib/app-slowlogs/app-slowlogs.js +63 -0
- package/dist/lib/app-slowlogs/types.js +1 -0
- package/dist/lib/cli/apiConfig.js +1 -1
- package/dist/lib/client-file-uploader.js +19 -4
- package/dist/lib/config/software.js +4 -4
- package/dist/lib/constants/dev-environment.js +7 -3
- package/dist/lib/dev-environment/dev-environment-cli.js +110 -117
- package/dist/lib/dev-environment/dev-environment-configuration-file.js +35 -36
- package/dist/lib/dev-environment/dev-environment-core.js +36 -19
- package/dist/lib/dev-environment/dev-environment-lando.js +80 -72
- package/dist/lib/dev-environment/docker-utils.js +8 -9
- package/dist/lib/envvar/api-get-all.js +2 -2
- package/dist/lib/envvar/api-list.js +3 -6
- package/dist/lib/envvar/input.js +1 -2
- package/dist/lib/site-import/status.js +5 -5
- package/dist/lib/token.js +3 -6
- package/dist/lib/validations/is-multi-site-sql-dump.js +0 -1
- package/dist/lib/validations/is-multi-site.js +14 -12
- package/dist/lib/validations/is-multisite-domain-mapped.js +5 -10
- package/dist/lib/validations/line-by-line.js +9 -13
- package/dist/lib/validations/site-type.js +2 -7
- package/dist/lib/validations/sql.js +14 -19
- package/dist/lib/validations/utils.js +1 -1
- package/export.sql +627 -0
- package/npm-shrinkwrap.json +913 -926
- package/package.json +12 -9
- package/tsconfig.json +3 -1
|
@@ -24,18 +24,19 @@ exports.promptForComponent = promptForComponent;
|
|
|
24
24
|
exports.promptForMultisite = promptForMultisite;
|
|
25
25
|
exports.promptForPhpVersion = promptForPhpVersion;
|
|
26
26
|
exports.promptForText = promptForText;
|
|
27
|
+
exports.promptForWordPress = promptForWordPress;
|
|
27
28
|
exports.resolvePath = resolvePath;
|
|
28
29
|
exports.resolvePhpVersion = resolvePhpVersion;
|
|
29
30
|
exports.setIsTTY = setIsTTY;
|
|
30
31
|
exports.validateDependencies = void 0;
|
|
32
|
+
var _nodeFs = require("node:fs");
|
|
33
|
+
var _path = _interopRequireDefault(require("path"));
|
|
34
|
+
var _nodeOs = require("node:os");
|
|
35
|
+
var _promises = require("node:dns/promises");
|
|
31
36
|
var _chalk = _interopRequireDefault(require("chalk"));
|
|
32
37
|
var _formatters = _interopRequireDefault(require("lando/lib/formatters"));
|
|
33
38
|
var _enquirer = require("enquirer");
|
|
34
39
|
var _debug = _interopRequireDefault(require("debug"));
|
|
35
|
-
var _fs = _interopRequireDefault(require("fs"));
|
|
36
|
-
var _path = _interopRequireDefault(require("path"));
|
|
37
|
-
var _os = _interopRequireDefault(require("os"));
|
|
38
|
-
var _dns = _interopRequireDefault(require("dns"));
|
|
39
40
|
var _child_process = require("child_process");
|
|
40
41
|
var _shelljs = require("shelljs");
|
|
41
42
|
var _progress = require("../../lib/cli/progress");
|
|
@@ -46,11 +47,6 @@ var _devEnvironmentLando = require("./dev-environment-lando");
|
|
|
46
47
|
var _userError = _interopRequireDefault(require("../user-error"));
|
|
47
48
|
var _devEnvironmentConfigurationFile = require("./dev-environment-configuration-file");
|
|
48
49
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
49
|
-
/**
|
|
50
|
-
*
|
|
51
|
-
* @format
|
|
52
|
-
*/
|
|
53
|
-
|
|
54
50
|
/**
|
|
55
51
|
* External dependencies
|
|
56
52
|
*/
|
|
@@ -81,11 +77,6 @@ const componentDemoNames = {
|
|
|
81
77
|
muPlugins: 'vip-go-mu-plugins',
|
|
82
78
|
appCode: 'vip-go-skeleton'
|
|
83
79
|
};
|
|
84
|
-
|
|
85
|
-
// Forward declaration to avoid no-use-before-define
|
|
86
|
-
|
|
87
|
-
// eslint-disable-next-line no-redeclare
|
|
88
|
-
|
|
89
80
|
async function handleCLIException(exception, trackKey, trackBaseInfo = {}) {
|
|
90
81
|
const errorPrefix = _chalk.default.red('Error:');
|
|
91
82
|
if (_devEnvironment.DEV_ENVIRONMENT_NOT_FOUND === exception.message) {
|
|
@@ -101,16 +92,13 @@ async function handleCLIException(exception, trackKey, trackBaseInfo = {}) {
|
|
|
101
92
|
message = message.replace('ERROR: ', '');
|
|
102
93
|
console.error(errorPrefix, message);
|
|
103
94
|
if (trackKey) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
} catch (trackException) {
|
|
112
|
-
console.warn(errorPrefix, `Failed to record track event ${trackKey}`, trackException.message);
|
|
113
|
-
}
|
|
95
|
+
const errorTrackingInfo = {
|
|
96
|
+
...trackBaseInfo,
|
|
97
|
+
failure: message,
|
|
98
|
+
stack: exception.stack
|
|
99
|
+
};
|
|
100
|
+
// trackEvent does not throw
|
|
101
|
+
await (0, _tracker.trackEvent)(trackKey, errorTrackingInfo);
|
|
114
102
|
}
|
|
115
103
|
if (!process.env.DEBUG) {
|
|
116
104
|
console.error(`\nPlease re-run the command with "--debug ${_chalk.default.bold('@automattic/vip:bin:dev-environment')}" appended to it and provide the stack trace on the support ticket.`);
|
|
@@ -127,7 +115,7 @@ const verifyDNSResolution = async slug => {
|
|
|
127
115
|
debug(`Verifying DNS resolution for ${testDomain}`);
|
|
128
116
|
let address;
|
|
129
117
|
try {
|
|
130
|
-
address = await
|
|
118
|
+
address = await (0, _promises.lookup)(testDomain, 4);
|
|
131
119
|
debug(`Got DNS response ${address.address}`);
|
|
132
120
|
} catch (error) {
|
|
133
121
|
throw new _userError.default(`DNS resolution for ${testDomain} failed. ${advice}`);
|
|
@@ -158,21 +146,13 @@ const validateDependencies = async (lando, slug, quiet) => {
|
|
|
158
146
|
progressTracker.startPrinting();
|
|
159
147
|
progressTracker.stepRunning('docker');
|
|
160
148
|
}
|
|
161
|
-
|
|
162
|
-
await (0, _devEnvironmentLando.validateDockerInstalled)(lando);
|
|
163
|
-
} catch (exception) {
|
|
164
|
-
throw new _userError.default(exception.message);
|
|
165
|
-
}
|
|
149
|
+
(0, _devEnvironmentLando.validateDockerInstalled)(lando);
|
|
166
150
|
if (!quiet) {
|
|
167
151
|
progressTracker.stepSuccess('docker');
|
|
168
152
|
progressTracker.stepSuccess('compose');
|
|
169
153
|
progressTracker.print();
|
|
170
154
|
}
|
|
171
|
-
|
|
172
|
-
await (0, _devEnvironmentLando.validateDockerAccess)(lando);
|
|
173
|
-
} catch (exception) {
|
|
174
|
-
throw new _userError.default(exception.message);
|
|
175
|
-
}
|
|
155
|
+
await (0, _devEnvironmentLando.validateDockerAccess)(lando);
|
|
176
156
|
if (!quiet) {
|
|
177
157
|
progressTracker.stepSuccess('access');
|
|
178
158
|
progressTracker.print();
|
|
@@ -254,11 +234,13 @@ function processComponentOptionInput(passedParam, allowLocal) {
|
|
|
254
234
|
function getOptionsFromAppInfo(appInfo) {
|
|
255
235
|
var _appInfo$environment, _appInfo$environment2, _appInfo$environment3, _appInfo$environment4, _appInfo$environment5;
|
|
256
236
|
return {
|
|
237
|
+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
257
238
|
title: ((_appInfo$environment = appInfo.environment) === null || _appInfo$environment === void 0 ? void 0 : _appInfo$environment.name) || appInfo.name || '',
|
|
258
|
-
|
|
239
|
+
// NOSONAR
|
|
240
|
+
multisite: !!((_appInfo$environment2 = appInfo.environment) !== null && _appInfo$environment2 !== void 0 && _appInfo$environment2.isMultisite),
|
|
259
241
|
mediaRedirectDomain: (_appInfo$environment3 = appInfo.environment) === null || _appInfo$environment3 === void 0 ? void 0 : _appInfo$environment3.primaryDomain,
|
|
260
|
-
php: ((_appInfo$environment4 = appInfo.environment) === null || _appInfo$environment4 === void 0 ? void 0 : _appInfo$environment4.php)
|
|
261
|
-
wordpress: ((_appInfo$environment5 = appInfo.environment) === null || _appInfo$environment5 === void 0 ? void 0 : _appInfo$environment5.wordpress)
|
|
242
|
+
php: ((_appInfo$environment4 = appInfo.environment) === null || _appInfo$environment4 === void 0 ? void 0 : _appInfo$environment4.php) ?? '',
|
|
243
|
+
wordpress: ((_appInfo$environment5 = appInfo.environment) === null || _appInfo$environment5 === void 0 ? void 0 : _appInfo$environment5.wordpress) ?? ''
|
|
262
244
|
};
|
|
263
245
|
}
|
|
264
246
|
|
|
@@ -272,7 +254,6 @@ function getOptionsFromAppInfo(appInfo) {
|
|
|
272
254
|
*/
|
|
273
255
|
// eslint-disable-next-line complexity
|
|
274
256
|
async function promptForArguments(preselectedOptions, defaultOptions, suppressPrompts = false) {
|
|
275
|
-
var _preselectedOptions$m;
|
|
276
257
|
debug('Provided preselected', preselectedOptions, 'and default', defaultOptions);
|
|
277
258
|
if (suppressPrompts) {
|
|
278
259
|
preselectedOptions = {
|
|
@@ -287,12 +268,12 @@ async function promptForArguments(preselectedOptions, defaultOptions, suppressPr
|
|
|
287
268
|
multisiteText += ` (${defaultOptions.title} ${defaultOptions.multisite ? 'IS' : 'is NOT'} multisite)`;
|
|
288
269
|
}
|
|
289
270
|
const instanceData = {
|
|
290
|
-
wpTitle: preselectedOptions.title
|
|
291
|
-
multisite: resolveMultisite(
|
|
271
|
+
wpTitle: preselectedOptions.title ?? (await promptForText('WordPress site title', defaultOptions.title ?? _devEnvironment.DEV_ENVIRONMENT_DEFAULTS.title)),
|
|
272
|
+
multisite: resolveMultisite(preselectedOptions.multisite ?? (await promptForMultisite(multisiteText, defaultOptions.multisite ?? _devEnvironment.DEV_ENVIRONMENT_DEFAULTS.multisite))),
|
|
292
273
|
elasticsearch: false,
|
|
293
|
-
php: preselectedOptions.php ? resolvePhpVersion(preselectedOptions.php) : await promptForPhpVersion(resolvePhpVersion(defaultOptions.php
|
|
294
|
-
mariadb: preselectedOptions.mariadb
|
|
295
|
-
mediaRedirectDomain: preselectedOptions.mediaRedirectDomain
|
|
274
|
+
php: preselectedOptions.php ? resolvePhpVersion(preselectedOptions.php) : await promptForPhpVersion(resolvePhpVersion(defaultOptions.php ?? _devEnvironment.DEV_ENVIRONMENT_DEFAULTS.phpVersion)),
|
|
275
|
+
mariadb: preselectedOptions.mariadb ?? defaultOptions.mariadb,
|
|
276
|
+
mediaRedirectDomain: preselectedOptions.mediaRedirectDomain ?? '',
|
|
296
277
|
wordpress: {
|
|
297
278
|
mode: 'image',
|
|
298
279
|
tag: ''
|
|
@@ -320,58 +301,68 @@ async function promptForArguments(preselectedOptions, defaultOptions, suppressPr
|
|
|
320
301
|
const mediaRedirectPromptText = `Would you like to redirect to ${defaultOptions.mediaRedirectDomain} for missing media files?`;
|
|
321
302
|
const setMediaRedirectDomain = await promptForBoolean(mediaRedirectPromptText, true);
|
|
322
303
|
if (setMediaRedirectDomain) {
|
|
323
|
-
|
|
324
|
-
instanceData.mediaRedirectDomain = (_defaultOptions$media = defaultOptions.mediaRedirectDomain) !== null && _defaultOptions$media !== void 0 ? _defaultOptions$media : '';
|
|
304
|
+
instanceData.mediaRedirectDomain = defaultOptions.mediaRedirectDomain;
|
|
325
305
|
}
|
|
326
306
|
}
|
|
307
|
+
instanceData.wordpress = await processWordPress((preselectedOptions.wordpress ?? '').toString(), (defaultOptions.wordpress ?? '').toString());
|
|
327
308
|
for (const component of _devEnvironment.DEV_ENVIRONMENT_COMPONENTS) {
|
|
328
|
-
|
|
329
|
-
const
|
|
330
|
-
const defaultValue = ((_defaultOptions$compo = defaultOptions[component]) !== null && _defaultOptions$compo !== void 0 ? _defaultOptions$compo : '').toString();
|
|
309
|
+
const option = (preselectedOptions[component] ?? '').toString();
|
|
310
|
+
const defaultValue = (defaultOptions[component] ?? '').toString();
|
|
331
311
|
|
|
332
312
|
// eslint-disable-next-line no-await-in-loop
|
|
333
313
|
const result = await processComponent(component, option, defaultValue, suppressPrompts);
|
|
334
|
-
if (null === result) {
|
|
335
|
-
throw new Error('processComponent() returned null');
|
|
336
|
-
}
|
|
337
314
|
instanceData[component] = result;
|
|
338
315
|
}
|
|
339
|
-
debug(`Processing elasticsearch with preselected "
|
|
316
|
+
debug(`Processing elasticsearch with preselected "%s"`, preselectedOptions.elasticsearch);
|
|
340
317
|
if ('elasticsearch' in preselectedOptions) {
|
|
341
318
|
instanceData.elasticsearch = !!preselectedOptions.elasticsearch;
|
|
342
319
|
} else {
|
|
343
320
|
instanceData.elasticsearch = await promptForBoolean('Enable Elasticsearch (needed by Enterprise Search)?', !!defaultOptions.elasticsearch);
|
|
344
321
|
}
|
|
345
|
-
|
|
322
|
+
const services = ['phpmyadmin', 'xdebug', 'mailpit', 'photon'];
|
|
323
|
+
for (const service of services) {
|
|
346
324
|
if (service in instanceData) {
|
|
347
|
-
|
|
348
|
-
|
|
325
|
+
const preselected = preselectedOptions[service];
|
|
326
|
+
if (preselected !== undefined) {
|
|
327
|
+
instanceData[service] = preselected;
|
|
349
328
|
} else {
|
|
350
329
|
// eslint-disable-next-line no-await-in-loop
|
|
351
|
-
instanceData[service] = await promptForBoolean(`Enable ${promptLabels[service] || service}`, defaultOptions[service]);
|
|
330
|
+
instanceData[service] = await promptForBoolean(`Enable ${promptLabels[service] || service}`, !!defaultOptions[service]);
|
|
352
331
|
}
|
|
353
332
|
}
|
|
354
333
|
}
|
|
355
334
|
debug('Instance data after prompts', instanceData);
|
|
356
335
|
return instanceData;
|
|
357
336
|
}
|
|
337
|
+
async function processWordPress(preselectedValue, defaultValue) {
|
|
338
|
+
debug(`processing 'WordPress', with preselected/default - ${preselectedValue}/${defaultValue}`);
|
|
339
|
+
let result;
|
|
340
|
+
const allowLocal = false;
|
|
341
|
+
const defaultObject = defaultValue ? processComponentOptionInput(defaultValue, allowLocal) : null;
|
|
342
|
+
if (preselectedValue) {
|
|
343
|
+
result = processComponentOptionInput(preselectedValue, allowLocal);
|
|
344
|
+
} else {
|
|
345
|
+
result = await promptForWordPress(defaultObject);
|
|
346
|
+
}
|
|
347
|
+
debug(result);
|
|
348
|
+
return result;
|
|
349
|
+
}
|
|
358
350
|
async function processComponent(component, preselectedValue, defaultValue, suppressPrompts = false) {
|
|
359
351
|
debug(`processing a component '${component}', with preselected/default - ${preselectedValue}/${defaultValue}`);
|
|
360
|
-
let result
|
|
361
|
-
const allowLocal =
|
|
352
|
+
let result;
|
|
353
|
+
const allowLocal = true;
|
|
362
354
|
const defaultObject = defaultValue ? processComponentOptionInput(defaultValue, allowLocal) : null;
|
|
363
355
|
if (preselectedValue) {
|
|
364
356
|
result = processComponentOptionInput(preselectedValue, allowLocal);
|
|
365
|
-
if (
|
|
357
|
+
if (!suppressPrompts) {
|
|
366
358
|
console.log(`${_chalk.default.green('✓')} Path to your local ${componentDisplayNames[component]}: ${preselectedValue}`);
|
|
367
359
|
}
|
|
368
360
|
} else {
|
|
369
361
|
result = await promptForComponent(component, allowLocal, defaultObject);
|
|
370
362
|
}
|
|
371
363
|
debug(result);
|
|
372
|
-
while ('local' ===
|
|
373
|
-
|
|
374
|
-
const resolvedPath = resolvePath(result.dir || '');
|
|
364
|
+
while ('local' === result.mode) {
|
|
365
|
+
const resolvedPath = resolvePath(result.dir ?? '');
|
|
375
366
|
result.dir = resolvedPath;
|
|
376
367
|
const {
|
|
377
368
|
result: isPathValid,
|
|
@@ -402,7 +393,7 @@ function validateLocalPath(component, providedPath) {
|
|
|
402
393
|
const missingFiles = [];
|
|
403
394
|
for (const file of files) {
|
|
404
395
|
const filePath = _path.default.resolve(providedPath, file);
|
|
405
|
-
if (!
|
|
396
|
+
if (!(0, _nodeFs.existsSync)(filePath)) {
|
|
406
397
|
missingFiles.push(file);
|
|
407
398
|
}
|
|
408
399
|
}
|
|
@@ -421,18 +412,17 @@ function validateLocalPath(component, providedPath) {
|
|
|
421
412
|
};
|
|
422
413
|
}
|
|
423
414
|
function isNonEmptyDirectory(directoryPath) {
|
|
424
|
-
const isDirectory = directoryPath &&
|
|
425
|
-
const isEmpty = isDirectory ?
|
|
415
|
+
const isDirectory = directoryPath && (0, _nodeFs.existsSync)(directoryPath) && (0, _nodeFs.lstatSync)(directoryPath).isDirectory();
|
|
416
|
+
const isEmpty = isDirectory ? (0, _nodeFs.readdirSync)(directoryPath).length === 0 : true;
|
|
426
417
|
return !isEmpty && isDirectory;
|
|
427
418
|
}
|
|
428
419
|
function resolvePath(input) {
|
|
429
420
|
// Resolve does not do ~ reliably
|
|
430
|
-
const resolvedPath = input.replace(/^~/,
|
|
421
|
+
const resolvedPath = input.replace(/^~/, (0, _nodeOs.homedir)());
|
|
431
422
|
// And resolve to handle relative paths
|
|
432
423
|
return _path.default.resolve(resolvedPath);
|
|
433
424
|
}
|
|
434
425
|
async function promptForText(message, initial) {
|
|
435
|
-
var _result2;
|
|
436
426
|
let result = {
|
|
437
427
|
input: initial
|
|
438
428
|
};
|
|
@@ -451,10 +441,12 @@ async function promptForText(message, initial) {
|
|
|
451
441
|
validate: nonEmptyValidator
|
|
452
442
|
});
|
|
453
443
|
}
|
|
454
|
-
return (
|
|
444
|
+
return (result.input || '').trim();
|
|
455
445
|
}
|
|
446
|
+
const multisiteOptions = ['subdomain', 'subdirectory'];
|
|
456
447
|
async function promptForMultisite(message, initial) {
|
|
457
|
-
var
|
|
448
|
+
var _result;
|
|
449
|
+
// `undefined` is used here only because our tests need overhauling
|
|
458
450
|
let result = {
|
|
459
451
|
input: initial
|
|
460
452
|
};
|
|
@@ -466,8 +458,7 @@ async function promptForMultisite(message, initial) {
|
|
|
466
458
|
initial
|
|
467
459
|
});
|
|
468
460
|
}
|
|
469
|
-
let input = (((
|
|
470
|
-
const multisiteOptions = ['subdomain', 'subdirectory'];
|
|
461
|
+
let input = (((_result = result) === null || _result === void 0 ? void 0 : _result.input) ?? initial).toString().trim();
|
|
471
462
|
const allowedOptions = [...FALSE_OPTIONS, ...TRUE_OPTIONS, ...multisiteOptions, 'none'];
|
|
472
463
|
if (!allowedOptions.includes(input) && isStdinTTY) {
|
|
473
464
|
const select = new _enquirer.Select({
|
|
@@ -482,18 +473,15 @@ function promptForBoolean(message, initial) {
|
|
|
482
473
|
if (isStdinTTY) {
|
|
483
474
|
const confirm = new _enquirer.Confirm({
|
|
484
475
|
message,
|
|
485
|
-
initial
|
|
476
|
+
initial: initial.toString()
|
|
486
477
|
});
|
|
487
478
|
return confirm.run();
|
|
488
479
|
}
|
|
489
480
|
return Promise.resolve(initial);
|
|
490
481
|
}
|
|
491
482
|
function resolveMultisite(value) {
|
|
492
|
-
const
|
|
493
|
-
|
|
494
|
-
return _devEnvironment.DEV_ENVIRONMENT_DEFAULTS.multisite;
|
|
495
|
-
}
|
|
496
|
-
return value;
|
|
483
|
+
const isMultisiteOption = val => typeof val === 'string' && multisiteOptions.includes(val) || typeof val === 'boolean';
|
|
484
|
+
return isMultisiteOption(value) ? value : _devEnvironment.DEV_ENVIRONMENT_DEFAULTS.multisite;
|
|
497
485
|
}
|
|
498
486
|
function resolvePhpVersion(version) {
|
|
499
487
|
debug(`Resolving PHP version %j`, version);
|
|
@@ -506,7 +494,7 @@ function resolvePhpVersion(version) {
|
|
|
506
494
|
const image = images.find(value => value === version);
|
|
507
495
|
if (image) {
|
|
508
496
|
result = image;
|
|
509
|
-
} else if (version.
|
|
497
|
+
} else if (version.includes('/')) {
|
|
510
498
|
// Assuming this is a Docker image
|
|
511
499
|
// This can happen when we first called `vip dev-env update -P image:ghcr.io/...`
|
|
512
500
|
// and then called `vip dev-env update` again. The custom image won't match our images
|
|
@@ -541,12 +529,32 @@ async function promptForPhpVersion(initialValue) {
|
|
|
541
529
|
}
|
|
542
530
|
return resolvePhpVersion(answer);
|
|
543
531
|
}
|
|
532
|
+
async function promptForWordPress(defaultObject) {
|
|
533
|
+
debug(`Prompting for wordpress with default:`, defaultObject);
|
|
534
|
+
const componentDisplayName = componentDisplayNames.wordpress;
|
|
535
|
+
const messagePrefix = `${componentDisplayName} - `;
|
|
544
536
|
|
|
545
|
-
//
|
|
537
|
+
// image with selection
|
|
538
|
+
const tagChoices = await getTagChoices();
|
|
539
|
+
let option = (defaultObject === null || defaultObject === void 0 ? void 0 : defaultObject.tag) ?? tagChoices[0].value;
|
|
540
|
+
if (isStdinTTY) {
|
|
541
|
+
const message = `${messagePrefix}Which version would you like`;
|
|
542
|
+
const selectTag = new _enquirer.Select({
|
|
543
|
+
message,
|
|
544
|
+
choices: tagChoices,
|
|
545
|
+
initial: option
|
|
546
|
+
});
|
|
547
|
+
option = await selectTag.run();
|
|
548
|
+
}
|
|
549
|
+
return {
|
|
550
|
+
mode: 'image',
|
|
551
|
+
tag: option
|
|
552
|
+
};
|
|
553
|
+
}
|
|
546
554
|
async function promptForComponent(component, allowLocal, defaultObject) {
|
|
547
555
|
debug(`Prompting for ${component} with default:`, defaultObject);
|
|
548
556
|
const componentDisplayName = componentDisplayNames[component] || component;
|
|
549
|
-
const componentDemoName = componentDemoNames[component]
|
|
557
|
+
const componentDemoName = componentDemoNames[component];
|
|
550
558
|
const modChoices = [];
|
|
551
559
|
if (allowLocal) {
|
|
552
560
|
modChoices.push({
|
|
@@ -579,62 +587,48 @@ async function promptForComponent(component, allowLocal, defaultObject) {
|
|
|
579
587
|
debug(modeResult);
|
|
580
588
|
const messagePrefix = selectMode ? '\t' : `${componentDisplayName} - `;
|
|
581
589
|
if ('local' === modeResult) {
|
|
582
|
-
const directoryPath = await promptForText(`${messagePrefix}What is a path to your local ${componentDisplayName}`, (defaultObject === null || defaultObject === void 0 ? void 0 : defaultObject.dir)
|
|
590
|
+
const directoryPath = await promptForText(`${messagePrefix}What is a path to your local ${componentDisplayName}`, (defaultObject === null || defaultObject === void 0 ? void 0 : defaultObject.dir) ?? '');
|
|
583
591
|
return {
|
|
584
592
|
mode: modeResult,
|
|
585
593
|
dir: directoryPath
|
|
586
594
|
};
|
|
587
595
|
}
|
|
588
596
|
|
|
589
|
-
// image with selection
|
|
590
|
-
if (component === 'wordpress') {
|
|
591
|
-
const tagChoices = await getTagChoices();
|
|
592
|
-
let option = (defaultObject === null || defaultObject === void 0 ? void 0 : defaultObject.tag) || tagChoices[0].value;
|
|
593
|
-
if (isStdinTTY) {
|
|
594
|
-
const message = `${messagePrefix}Which version would you like`;
|
|
595
|
-
const selectTag = new _enquirer.Select({
|
|
596
|
-
message,
|
|
597
|
-
choices: tagChoices,
|
|
598
|
-
initial: option
|
|
599
|
-
});
|
|
600
|
-
option = await selectTag.run();
|
|
601
|
-
}
|
|
602
|
-
return {
|
|
603
|
-
mode: 'image',
|
|
604
|
-
tag: option
|
|
605
|
-
};
|
|
606
|
-
}
|
|
607
|
-
|
|
608
597
|
// image
|
|
609
598
|
return {
|
|
610
599
|
mode: modeResult
|
|
611
600
|
};
|
|
612
601
|
}
|
|
613
602
|
const FALSE_OPTIONS = ['false', 'no', 'n', '0'];
|
|
603
|
+
const TRUE_OPTIONS = ['true', 'yes', 'y', '1'];
|
|
614
604
|
function processBooleanOption(value) {
|
|
615
|
-
var _value$toLowerCase;
|
|
616
605
|
if (!value) {
|
|
617
606
|
return false;
|
|
618
607
|
}
|
|
619
|
-
|
|
608
|
+
|
|
609
|
+
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
610
|
+
return !FALSE_OPTIONS.includes(value.toString().toLowerCase()); // NOSONAR
|
|
620
611
|
}
|
|
621
|
-
|
|
612
|
+
|
|
622
613
|
function processStringOrBooleanOption(value) {
|
|
623
|
-
|
|
624
|
-
|
|
614
|
+
if (typeof value === 'boolean') {
|
|
615
|
+
return value;
|
|
616
|
+
}
|
|
617
|
+
if (!value || FALSE_OPTIONS.includes(value.toLowerCase())) {
|
|
625
618
|
return false;
|
|
626
619
|
}
|
|
627
|
-
if (TRUE_OPTIONS.includes(
|
|
620
|
+
if (TRUE_OPTIONS.includes(value.toLowerCase())) {
|
|
628
621
|
return true;
|
|
629
622
|
}
|
|
630
623
|
return value;
|
|
631
624
|
}
|
|
632
625
|
function processVersionOption(value) {
|
|
633
|
-
if (
|
|
634
|
-
|
|
635
|
-
|
|
626
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
627
|
+
if (!isNaN(value) && +value % 1 === 0) {
|
|
628
|
+
return parseFloat(value).toFixed(1);
|
|
629
|
+
}
|
|
636
630
|
}
|
|
637
|
-
return value
|
|
631
|
+
return (value === null || value === void 0 ? void 0 : value.toString()) ?? '';
|
|
638
632
|
}
|
|
639
633
|
function addDevEnvConfigurationOptions(command) {
|
|
640
634
|
// We leave the third parameter to undefined on some because the defaults are handled in preProcessInstanceData()
|
|
@@ -685,18 +679,17 @@ async function getTagChoices() {
|
|
|
685
679
|
}
|
|
686
680
|
function getEnvTrackingInfo(slug) {
|
|
687
681
|
try {
|
|
688
|
-
var _result$php;
|
|
689
682
|
const envData = (0, _devEnvironmentCore.readEnvironmentData)(slug);
|
|
690
683
|
const result = {
|
|
691
684
|
slug
|
|
692
685
|
};
|
|
693
686
|
for (const key of Object.keys(envData)) {
|
|
694
|
-
// track
|
|
687
|
+
// track doesn't like camelCase
|
|
695
688
|
const snakeCasedKey = key.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);
|
|
696
|
-
const value = _devEnvironment.
|
|
689
|
+
const value = _devEnvironment.DEV_ENVIRONMENT_COMPONENTS_WITH_WP.includes(key) ? JSON.stringify(envData[key]) : envData[key];
|
|
697
690
|
result[snakeCasedKey] = value;
|
|
698
691
|
}
|
|
699
|
-
result.php =
|
|
692
|
+
result.php = result.php.replace(/.*:/, '');
|
|
700
693
|
return result;
|
|
701
694
|
} catch (err) {
|
|
702
695
|
return {
|
|
@@ -704,14 +697,14 @@ function getEnvTrackingInfo(slug) {
|
|
|
704
697
|
};
|
|
705
698
|
}
|
|
706
699
|
}
|
|
707
|
-
|
|
700
|
+
function postStart(slug, options) {
|
|
708
701
|
if (options.openVSCode) {
|
|
709
702
|
launchVSCode(slug);
|
|
710
703
|
}
|
|
711
704
|
}
|
|
712
705
|
const launchVSCode = slug => {
|
|
713
706
|
const workspacePath = (0, _devEnvironmentCore.getVSCodeWorkspacePath)(slug);
|
|
714
|
-
if (
|
|
707
|
+
if ((0, _nodeFs.existsSync)(workspacePath)) {
|
|
715
708
|
console.log('VS Code workspace already exists, skipping creation.');
|
|
716
709
|
} else {
|
|
717
710
|
(0, _devEnvironmentCore.generateVSCodeWorkspace)(slug);
|
|
@@ -7,20 +7,16 @@ exports.CONFIGURATION_FILE_NAME = void 0;
|
|
|
7
7
|
exports.getConfigurationFileOptions = getConfigurationFileOptions;
|
|
8
8
|
exports.mergeConfigurationFileOptions = mergeConfigurationFileOptions;
|
|
9
9
|
exports.printConfigurationFile = printConfigurationFile;
|
|
10
|
+
var _promises = require("node:fs/promises");
|
|
11
|
+
var _fs = require("fs");
|
|
12
|
+
var _nodePath = _interopRequireDefault(require("node:path"));
|
|
10
13
|
var _debug = _interopRequireDefault(require("debug"));
|
|
11
|
-
var _fs = _interopRequireDefault(require("fs"));
|
|
12
|
-
var _path = _interopRequireDefault(require("path"));
|
|
13
14
|
var _chalk = _interopRequireDefault(require("chalk"));
|
|
14
15
|
var _jsYaml = _interopRequireWildcard(require("js-yaml"));
|
|
15
16
|
var exit = _interopRequireWildcard(require("../cli/exit"));
|
|
16
17
|
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
17
18
|
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
18
19
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
19
|
-
/**
|
|
20
|
-
*
|
|
21
|
-
* @format
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
20
|
/**
|
|
25
21
|
* External dependencies
|
|
26
22
|
*/
|
|
@@ -33,12 +29,12 @@ const debug = (0, _debug.default)('@automattic/vip:bin:dev-environment');
|
|
|
33
29
|
const CONFIGURATION_FILE_NAME = '.vip-dev-env.yml';
|
|
34
30
|
exports.CONFIGURATION_FILE_NAME = CONFIGURATION_FILE_NAME;
|
|
35
31
|
async function getConfigurationFileOptions() {
|
|
36
|
-
const configurationFilePath =
|
|
32
|
+
const configurationFilePath = _nodePath.default.join(process.cwd(), CONFIGURATION_FILE_NAME);
|
|
37
33
|
let configurationFileContents = '';
|
|
38
|
-
const fileExists = await
|
|
34
|
+
const fileExists = await (0, _promises.access)(configurationFilePath, _fs.constants.R_OK).then(() => true).catch(() => false);
|
|
39
35
|
if (fileExists) {
|
|
40
36
|
debug('Reading configuration file from:', configurationFilePath);
|
|
41
|
-
configurationFileContents = await
|
|
37
|
+
configurationFileContents = await (0, _promises.readFile)(configurationFilePath, 'utf8');
|
|
42
38
|
} else {
|
|
43
39
|
return {};
|
|
44
40
|
}
|
|
@@ -53,57 +49,60 @@ async function getConfigurationFileOptions() {
|
|
|
53
49
|
const messageToShow = `Configuration file ${_chalk.default.grey(CONFIGURATION_FILE_NAME)} could not be loaded:\n` + err.toString();
|
|
54
50
|
exit.withError(messageToShow);
|
|
55
51
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
return configuration;
|
|
52
|
+
try {
|
|
53
|
+
const configuration = sanitizeConfiguration(configurationFromFile);
|
|
54
|
+
debug('Sanitized configuration from file:', configuration);
|
|
55
|
+
return configuration;
|
|
56
|
+
} catch (err) {
|
|
57
|
+
exit.withError(err instanceof Error ? err : new Error('Unknown error'));
|
|
58
|
+
}
|
|
64
59
|
}
|
|
65
|
-
|
|
66
|
-
var _configuration$
|
|
60
|
+
function sanitizeConfiguration(configuration) {
|
|
61
|
+
var _configuration$title, _configuration$php, _configuration$wordpr, _configuration$muPlu, _configuration$appCo, _configuration$media;
|
|
67
62
|
const genericConfigurationError = `Configuration file ${_chalk.default.grey(CONFIGURATION_FILE_NAME)} is available but ` + `couldn't be loaded. Ensure there is a ${_chalk.default.cyan('configuration-version')} and ${_chalk.default.cyan('slug')} ` + `configured. For example:\n\n${_chalk.default.grey(getConfigurationFileExample())}`;
|
|
68
63
|
if (Array.isArray(configuration) || typeof configuration !== 'object') {
|
|
69
64
|
throw new Error(genericConfigurationError);
|
|
70
65
|
}
|
|
71
|
-
|
|
66
|
+
const version = configuration['configuration-version'];
|
|
67
|
+
if (typeof version !== 'string' && typeof version !== 'number' || configuration.slug === undefined || configuration.slug === null) {
|
|
72
68
|
throw new Error(genericConfigurationError);
|
|
73
69
|
}
|
|
74
|
-
const validVersions = getAllConfigurationFileVersions().map(
|
|
75
|
-
if (!isValidConfigurationFileVersion(
|
|
70
|
+
const validVersions = getAllConfigurationFileVersions().map(ver => _chalk.default.cyan(ver)).join(', ');
|
|
71
|
+
if (!isValidConfigurationFileVersion(version.toString())) {
|
|
76
72
|
throw new Error(`Configuration file ${_chalk.default.grey(CONFIGURATION_FILE_NAME)} has an invalid ` + `${_chalk.default.cyan('configuration-version')} key. Update to a supported version. For example:\n\n` + _chalk.default.grey(getConfigurationFileExample()) + `\nSupported configuration versions: ${validVersions}.\n`);
|
|
77
73
|
}
|
|
78
74
|
const stringToBooleanIfDefined = value => {
|
|
79
|
-
if (value
|
|
75
|
+
if (typeof value !== 'string' || !['true', 'false'].includes(value)) {
|
|
80
76
|
return undefined;
|
|
81
77
|
}
|
|
82
78
|
return value === 'true';
|
|
83
79
|
};
|
|
84
80
|
const sanitizedConfiguration = {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
81
|
+
version: version.toString(),
|
|
82
|
+
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
83
|
+
slug: configuration.slug.toString(),
|
|
84
|
+
// NOSONAR
|
|
85
|
+
title: (_configuration$title = configuration.title) === null || _configuration$title === void 0 ? void 0 : _configuration$title.toString(),
|
|
88
86
|
multisite: stringToBooleanIfDefined(configuration.multisite),
|
|
89
|
-
php: configuration.php,
|
|
90
|
-
wordpress: configuration.wordpress,
|
|
91
|
-
'mu-plugins': configuration['mu-plugins'],
|
|
92
|
-
'app-code': configuration['app-code'],
|
|
87
|
+
php: (_configuration$php = configuration.php) === null || _configuration$php === void 0 ? void 0 : _configuration$php.toString(),
|
|
88
|
+
wordpress: (_configuration$wordpr = configuration.wordpress) === null || _configuration$wordpr === void 0 ? void 0 : _configuration$wordpr.toString(),
|
|
89
|
+
'mu-plugins': (_configuration$muPlu = configuration['mu-plugins']) === null || _configuration$muPlu === void 0 ? void 0 : _configuration$muPlu.toString(),
|
|
90
|
+
'app-code': (_configuration$appCo = configuration['app-code']) === null || _configuration$appCo === void 0 ? void 0 : _configuration$appCo.toString(),
|
|
93
91
|
elasticsearch: stringToBooleanIfDefined(configuration.elasticsearch),
|
|
94
92
|
phpmyadmin: stringToBooleanIfDefined(configuration.phpmyadmin),
|
|
95
93
|
xdebug: stringToBooleanIfDefined(configuration.xdebug),
|
|
96
|
-
mailpit: stringToBooleanIfDefined(
|
|
97
|
-
'media-redirect-domain': configuration['media-redirect-domain'],
|
|
94
|
+
mailpit: stringToBooleanIfDefined(configuration.mailpit ?? configuration.mailhog),
|
|
95
|
+
'media-redirect-domain': (_configuration$media = configuration['media-redirect-domain']) === null || _configuration$media === void 0 ? void 0 : _configuration$media.toString(),
|
|
98
96
|
photon: stringToBooleanIfDefined(configuration.photon)
|
|
99
97
|
};
|
|
100
98
|
|
|
101
99
|
// Remove undefined values
|
|
102
|
-
Object.keys(sanitizedConfiguration).forEach(
|
|
100
|
+
Object.keys(sanitizedConfiguration).forEach(
|
|
101
|
+
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
|
102
|
+
key => sanitizedConfiguration[key] === undefined && delete sanitizedConfiguration[key]);
|
|
103
103
|
return sanitizedConfiguration;
|
|
104
104
|
}
|
|
105
105
|
function mergeConfigurationFileOptions(preselectedOptions, configurationFileOptions) {
|
|
106
|
-
var _configurationFileOpt;
|
|
107
106
|
// configurationFileOptions holds different parameters than present in
|
|
108
107
|
// preselectedOptions like "slug", and friendly-named parameters (e.g.
|
|
109
108
|
// 'app-code' vs 'appCode'). Selectively merge configurationFileOptions
|
|
@@ -119,7 +118,7 @@ function mergeConfigurationFileOptions(preselectedOptions, configurationFileOpti
|
|
|
119
118
|
phpmyadmin: configurationFileOptions.phpmyadmin,
|
|
120
119
|
xdebug: configurationFileOptions.xdebug,
|
|
121
120
|
xdebugConfig: configurationFileOptions['xdebug-config'],
|
|
122
|
-
mailpit:
|
|
121
|
+
mailpit: configurationFileOptions.mailpit ?? configurationFileOptions.mailhog,
|
|
123
122
|
mediaRedirectDomain: configurationFileOptions['media-redirect-domain'],
|
|
124
123
|
photon: configurationFileOptions.photon
|
|
125
124
|
};
|