@automattic/vip 3.5.1 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -50,7 +50,7 @@ cmd.argv(process.argv, async (arg, opt) => {
50
50
  slug = await (0, _devEnvironmentCli.getEnvironmentName)(environmentNameOptions);
51
51
  }
52
52
  const lando = await (0, _devEnvironmentLando.bootstrapLando)();
53
- await (0, _devEnvironmentCli.validateDependencies)(lando, slug);
53
+ (0, _devEnvironmentCli.validateDependencies)(lando);
54
54
  debug('Args: ', arg, 'Options: ', opt);
55
55
  const trackingInfo = {
56
56
  slug,
@@ -24,7 +24,7 @@ const examples = [{
24
24
  }).option('slug', 'A unique name for a local environment. Default is "vip-local".', undefined, _devEnvironmentCli.processSlug).option('soft', 'Preserve an environment’s configuration files; allows an environment to be regenerated with the start command.').examples(examples).argv(process.argv, async (arg, opt) => {
25
25
  const slug = await (0, _devEnvironmentCli.getEnvironmentName)(opt);
26
26
  const lando = await (0, _devEnvironmentLando.bootstrapLando)();
27
- await (0, _devEnvironmentCli.validateDependencies)(lando, slug);
27
+ (0, _devEnvironmentCli.validateDependencies)(lando);
28
28
  const trackingInfo = (0, _devEnvironmentCli.getEnvTrackingInfo)(slug);
29
29
  await (0, _tracker.trackEvent)('dev_env_destroy_command_execute', trackingInfo);
30
30
  debug('Args: ', arg, 'Options: ', opt);
@@ -26,7 +26,7 @@ const examples = [{
26
26
  }).option('slug', 'A unique name for a local environment. Default is "vip-local".', undefined, _devEnvironmentCli.processSlug).option('force', 'Skip validation for a local environment to be in a running state.', undefined, _devEnvironmentCli.processBooleanOption).option('quiet', 'Suppress informational messages.', undefined, _devEnvironmentCli.processBooleanOption).examples(examples).argv(process.argv, async (unmatchedArgs, opt) => {
27
27
  const slug = await (0, _devEnvironmentCli.getEnvironmentName)(opt);
28
28
  const lando = await (0, _devEnvironmentLando.bootstrapLando)();
29
- await (0, _devEnvironmentCli.validateDependencies)(lando, slug);
29
+ (0, _devEnvironmentCli.validateDependencies)(lando);
30
30
  const trackingInfo = (0, _devEnvironmentCli.getEnvTrackingInfo)(slug);
31
31
  await (0, _tracker.trackEvent)('dev_env_exec_command_execute', trackingInfo);
32
32
  try {
@@ -36,7 +36,7 @@ const examples = [{
36
36
  slug = await (0, _devEnvironmentCli.getEnvironmentName)(opt);
37
37
  trackingInfo = (0, _devEnvironmentCli.getEnvTrackingInfo)(slug);
38
38
  }
39
- await (0, _devEnvironmentCli.validateDependencies)(lando, slug);
39
+ (0, _devEnvironmentCli.validateDependencies)(lando);
40
40
  await (0, _tracker.trackEvent)('dev_env_info_command_execute', trackingInfo);
41
41
  debug('Args: ', arg, 'Options: ', opt);
42
42
  try {
@@ -18,7 +18,7 @@ const examples = [{
18
18
  }).examples(examples).argv(process.argv, async () => {
19
19
  const lando = await (0, _devEnvironmentLando.bootstrapLando)();
20
20
  lando.events.constructor.prototype.setMaxListeners(1024);
21
- await (0, _devEnvironmentCli.validateDependencies)(lando, '');
21
+ (0, _devEnvironmentCli.validateDependencies)(lando);
22
22
  const trackingInfo = {
23
23
  all: true
24
24
  };
@@ -26,7 +26,7 @@ const examples = [{
26
26
  }).option('slug', 'A unique name for a local environment. Default is "vip-local".', undefined, _devEnvironmentCli.processSlug).option(['f', 'follow'], 'Continually output logs as they are generated.').option('service', 'Restrict to a single service.').examples(examples).argv(process.argv, async (arg, opt) => {
27
27
  const slug = await (0, _devEnvironmentCli.getEnvironmentName)(opt);
28
28
  const lando = await (0, _devEnvironmentLando.bootstrapLando)();
29
- await (0, _devEnvironmentCli.validateDependencies)(lando, slug);
29
+ (0, _devEnvironmentCli.validateDependencies)(lando);
30
30
  const trackingInfo = (0, _devEnvironmentCli.getEnvTrackingInfo)(slug);
31
31
  await (0, _tracker.trackEvent)('dev_env_logs_command_execute', trackingInfo);
32
32
  debug('Args: ', arg, 'Options: ', opt);
@@ -49,7 +49,7 @@ const examples = [{
49
49
  all: true
50
50
  };
51
51
  await (0, _tracker.trackEvent)('dev_env_purge_command_execute', trackingInfo);
52
- await (0, _devEnvironmentCli.validateDependencies)(lando, '');
52
+ (0, _devEnvironmentCli.validateDependencies)(lando);
53
53
  const removeFiles = !(opt.soft || false);
54
54
  try {
55
55
  for (const slug of allEnvNames) {
@@ -58,7 +58,7 @@ function getCommand(args) {
58
58
  }).option('slug', 'A unique name for a local environment. Default is "vip-local".', undefined, _devEnvironmentCli.processSlug).option('root', 'Create with root privileges.').option('service', 'Restrict to a single service.').examples(examples).argv(process.argv, async (args, opt) => {
59
59
  const slug = await (0, _devEnvironmentCli.getEnvironmentName)(opt);
60
60
  const lando = await (0, _devEnvironmentLando.bootstrapLando)();
61
- await (0, _devEnvironmentCli.validateDependencies)(lando, '');
61
+ (0, _devEnvironmentCli.validateDependencies)(lando);
62
62
  const trackingInfo = (0, _devEnvironmentCli.getEnvTrackingInfo)(slug);
63
63
  await (0, _tracker.trackEvent)('dev_env_shell_command_execute', trackingInfo);
64
64
  debug('Args: ', args, 'Options: ', opt);
@@ -29,7 +29,7 @@ const examples = [{
29
29
  }).option('slug', 'A unique name for a local environment. Default is "vip-local".', undefined, _devEnvironmentCli.processSlug).option('skip-rebuild', 'Only start services that are not in a running state.').option(['w', 'skip-wp-versions-check'], 'Skip the prompt to update WordPress; occurs if the last major release version is not configured.').option('vscode', 'Generate a Visual Studio Code Workspace file.').examples(examples).argv(process.argv, async (arg, opt) => {
30
30
  const slug = await (0, _devEnvironmentCli.getEnvironmentName)(opt);
31
31
  const lando = await (0, _devEnvironmentLando.bootstrapLando)();
32
- await (0, _devEnvironmentCli.validateDependencies)(lando, slug);
32
+ (0, _devEnvironmentCli.validateDependencies)(lando);
33
33
  const startProcessing = new Date();
34
34
  const trackingInfo = (0, _devEnvironmentCli.getEnvTrackingInfo)(slug);
35
35
  trackingInfo.vscode = Boolean(opt.vscode);
@@ -23,7 +23,7 @@ const examples = [{
23
23
  usage
24
24
  }).option('slug', 'A unique name for a local environment. Default is "vip-local".', undefined, _devEnvironmentCli.processSlug).option('all', 'Stop all local environments.').examples(examples).argv(process.argv, async (arg, opt) => {
25
25
  const lando = await (0, _devEnvironmentLando.bootstrapLando)();
26
- await (0, _devEnvironmentCli.validateDependencies)(lando, '');
26
+ (0, _devEnvironmentCli.validateDependencies)(lando);
27
27
  debug('Args: ', arg, 'Options: ', opt);
28
28
 
29
29
  /** @type {Record< string, unknown >} */
@@ -32,7 +32,7 @@ cmd.examples(examples);
32
32
  cmd.argv(process.argv, async (arg, opt) => {
33
33
  const slug = await (0, _devEnvironmentCli.getEnvironmentName)(opt);
34
34
  const lando = await (0, _devEnvironmentLando.bootstrapLando)();
35
- await (0, _devEnvironmentCli.validateDependencies)(lando, slug);
35
+ (0, _devEnvironmentCli.validateDependencies)(lando);
36
36
  const trackingInfo = (0, _devEnvironmentCli.getEnvTrackingInfo)(slug);
37
37
  await (0, _tracker.trackEvent)('dev_env_update_command_execute', trackingInfo);
38
38
  try {
@@ -1,18 +1,24 @@
1
1
  #!/usr/bin/env node
2
+
3
+ /**
4
+ * External dependencies
5
+ */
2
6
  "use strict";
3
7
 
4
8
  var _chalk = _interopRequireDefault(require("chalk"));
5
- var _fs = _interopRequireDefault(require("fs"));
6
- var _path = _interopRequireDefault(require("path"));
7
9
  var _url = _interopRequireDefault(require("url"));
8
10
  var _command = _interopRequireDefault(require("../lib/cli/command"));
11
+ var _config = require("../lib/media-import/config");
9
12
  var _tracker = require("../lib/tracker");
10
13
  var _vipImportValidateFiles = require("../lib/vip-import-validate-files");
11
14
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
15
+ /**
16
+ * Internal dependencies
17
+ */
12
18
  (0, _command.default)({
13
19
  requiredArgs: 1,
14
20
  format: true
15
- }).example('vip import validate-files <file>', 'Run the import validation against the file').argv(process.argv, async arg => {
21
+ }).example('vip import validate-files <folder_name>', 'Run the import validation against the folder of media files').argv(process.argv, async arg => {
16
22
  await (0, _tracker.trackEvent)('import_validate_files_command_execute');
17
23
  /**
18
24
  * File manipulation
@@ -56,90 +62,64 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
56
62
  }
57
63
 
58
64
  /**
59
- * Media file extension validation
60
- *
61
- * Ensure that prohibited media file types are not used
65
+ * Get Media Import configuration
62
66
  */
63
-
64
- // Collect invalid files for error logging
65
- let intermediateImagesTotal = 0;
66
- const errorFileTypes = [];
67
- const errorFileNames = [];
68
- const intermediateImages = {};
69
-
70
- // Iterate through each file to isolate the extension name
71
- for (const file of files) {
72
- // Check if file is a directory
73
- // eslint-disable-next-line no-await-in-loop
74
- const stats = await _fs.default.promises.stat(file);
75
- const isFolder = stats.isDirectory();
76
- const extension = _path.default.extname(file); // Extract the extension of the file
77
- const ext = extension.substr(1); // We only want the ext name minus the period (e.g- .jpg -> jpg)
78
- const extLowerCase = ext.toLowerCase(); // Change any uppercase extensions to lowercase
79
-
80
- // Check for any invalid file extensions
81
- // Returns true if ext is valid; false if invalid
82
- const validExtensions = _vipImportValidateFiles.acceptedExtensions.includes(extLowerCase);
83
-
84
- // Collect files that have no extension, have invalid extensions,
85
- // or are directories for error logging
86
- if (!extension || !validExtensions || isFolder) {
87
- errorFileTypes.push(file);
88
- }
89
-
90
- /**
91
- * Filename validation
92
- *
93
- * Ensure that filenames don't contain prohibited characters
94
- */
95
-
96
- // Collect files that have invalid file names for error logging
97
- if ((0, _vipImportValidateFiles.isFileSanitized)(file)) {
98
- errorFileNames.push(file);
99
- }
100
-
101
- /**
102
- * Intermediate image validation
103
- *
104
- * Detect any intermediate images.
105
- *
106
- * Intermediate images are copies of images that are resized, so you may have multiples of the same image.
107
- * You can resize an image directly on VIP so intermediate images are not necessary.
108
- */
109
- const original = (0, _vipImportValidateFiles.doesImageHaveExistingSource)(file);
110
-
111
- // If an image is an intermediate image, increment the total number and
112
- // populate key/value pairs of the original image and intermediate image(s)
113
- if (original) {
114
- intermediateImagesTotal++;
115
- if (intermediateImages[original]) {
116
- // Key: original image, value: intermediate image(s)
117
- intermediateImages[original] = `${intermediateImages[original]}, ${file}`;
118
- } else {
119
- intermediateImages[original] = file;
120
- }
121
- }
67
+ const mediaImportConfig = await (0, _config.getMediaImportConfig)();
68
+ if (!mediaImportConfig) {
69
+ console.error(_chalk.default.red('✕ Error:'), 'Could not retrieve validation metadata. Please contact VIP Support.');
70
+ return;
122
71
  }
123
72
 
73
+ /**
74
+ * File Validation
75
+ * Collect all errors from file validation
76
+ */
77
+ const {
78
+ intermediateImagesTotal,
79
+ errorFileTypes,
80
+ errorFileNames,
81
+ errorFileSizes,
82
+ errorFileNamesCharCount,
83
+ intermediateImages
84
+ } = await (0, _vipImportValidateFiles.validateFiles)(files, mediaImportConfig);
85
+
124
86
  /**
125
87
  * Error logging
88
+ * Not sure if the changes made to the error logging better
126
89
  */
127
- if (errorFileTypes.length > 0) {
128
- (0, _vipImportValidateFiles.logErrorsForInvalidFileTypes)(errorFileTypes);
129
- }
130
- if (errorFileNames.length > 0) {
131
- (0, _vipImportValidateFiles.logErrorsForInvalidFilenames)(errorFileNames);
132
- }
133
- if (Object.keys(intermediateImages).length > 0) {
134
- (0, _vipImportValidateFiles.logErrorsForIntermediateImages)(intermediateImages);
135
- }
90
+ (0, _vipImportValidateFiles.logErrors)({
91
+ errorType: _vipImportValidateFiles.ValidateFilesErrors.INVALID_TYPES,
92
+ invalidFiles: errorFileTypes,
93
+ limit: Object.keys(mediaImportConfig.allowedFileTypes)
94
+ });
95
+ (0, _vipImportValidateFiles.logErrors)({
96
+ errorType: _vipImportValidateFiles.ValidateFilesErrors.INVALID_SIZES,
97
+ invalidFiles: errorFileSizes,
98
+ limit: mediaImportConfig.fileSizeLimitInBytes
99
+ });
100
+ (0, _vipImportValidateFiles.logErrors)({
101
+ errorType: _vipImportValidateFiles.ValidateFilesErrors.INVALID_NAME_CHARACTER_COUNTS,
102
+ invalidFiles: errorFileNamesCharCount,
103
+ limit: mediaImportConfig.fileNameCharCount
104
+ });
105
+ (0, _vipImportValidateFiles.logErrors)({
106
+ errorType: _vipImportValidateFiles.ValidateFilesErrors.INVALID_NAMES,
107
+ invalidFiles: errorFileNames
108
+ });
109
+ (0, _vipImportValidateFiles.logErrors)({
110
+ errorType: _vipImportValidateFiles.ValidateFilesErrors.INTERMEDIATE_IMAGES,
111
+ invalidFiles: Object.keys(intermediateImages),
112
+ invalidFilesObj: intermediateImages
113
+ });
136
114
 
137
115
  // Log a summary of all errors
138
116
  (0, _vipImportValidateFiles.summaryLogs)({
139
117
  folderErrorsLength: folderValidation.length,
140
118
  intImagesErrorsLength: intermediateImagesTotal,
141
119
  fileTypeErrorsLength: errorFileTypes.length,
120
+ fileErrorFileSizesLength: errorFileSizes.length,
142
121
  filenameErrorsLength: errorFileNames.length,
122
+ fileNameCharCountErrorsLength: errorFileNamesCharCount.length,
143
123
  totalFiles: files.length,
144
124
  totalFolders: nestedDirectories.length
145
125
  });
@@ -26,7 +26,7 @@ class DevEnvImportSQLCommand {
26
26
  }
27
27
  async run() {
28
28
  const lando = await (0, _devEnvironmentLando.bootstrapLando)();
29
- await (0, _devEnvironmentCli.validateDependencies)(lando, this.slug);
29
+ (0, _devEnvironmentCli.validateDependencies)(lando);
30
30
  (0, _sql.validateImportFileExtension)(this.fileName);
31
31
 
32
32
  // Check if file is compressed and if so, extract the
@@ -33,7 +33,6 @@ var _child_process = require("child_process");
33
33
  var _debug = _interopRequireDefault(require("debug"));
34
34
  var _enquirer = require("enquirer");
35
35
  var _formatters = _interopRequireDefault(require("lando/lib/formatters"));
36
- var _promises = require("node:dns/promises");
37
36
  var _nodeFs = require("node:fs");
38
37
  var _nodeOs = require("node:os");
39
38
  var _path = _interopRequireDefault(require("path"));
@@ -98,38 +97,9 @@ async function handleCLIException(exception, trackKey, trackBaseInfo = {}) {
98
97
  debug(exception);
99
98
  }
100
99
  }
101
- const verifyDNSResolution = async (slug, domain) => {
102
- const expectedIP = '127.0.0.1';
103
- const testDomain = `${slug}.${domain}`;
104
- const advice = `Please add following line to hosts file on your system:\n\n${expectedIP} ${testDomain}\n\nLearn more: https://docs.wpvip.com/vip-local-development-environment/troubleshooting-dev-env/#h-resolve-networking-configuration-issues\n`;
105
- debug(`Verifying DNS resolution for ${testDomain}`);
106
- try {
107
- let address;
108
- try {
109
- address = await (0, _promises.lookup)(testDomain, 4);
110
- debug(`Got DNS response ${address.address}`);
111
- } catch (error) {
112
- throw new _userError.default(`DNS resolution for ${testDomain} failed.`, {
113
- cause: error
114
- });
115
- }
116
- if (address.address !== expectedIP) {
117
- throw new _userError.default(`DNS resolution for ${testDomain} returned unexpected IP ${address.address}. Expected value is ${expectedIP}.`);
118
- }
119
- } catch (error) {
120
- if (error instanceof _userError.default) {
121
- console.warn(_chalk.default.yellow.bold('Warning:'), `${error.message}\n\n${advice}`);
122
- } else {
123
- throw error;
124
- }
125
- }
126
- };
127
- const validateDependencies = async (lando, slug) => {
100
+ const validateDependencies = lando => {
128
101
  const now = new Date();
129
102
  (0, _devEnvironmentLando.validateDockerInstalled)(lando);
130
- if (slug) {
131
- await verifyDNSResolution(slug, lando.config.domain ?? 'vipdev.lndo.site');
132
- }
133
103
  const duration = new Date().getTime() - now.getTime();
134
104
  debug('Validation checks completed in %d ms', duration);
135
105
  };
@@ -390,6 +390,36 @@ async function getExtraServicesConnections(lando, app) {
390
390
  }
391
391
  return extraServices;
392
392
  }
393
+ async function tryResolveDomains(urls) {
394
+ const domains = [...new Set(urls.filter(url => url.toLowerCase().startsWith('http')).map(url => {
395
+ try {
396
+ return new URL(url).hostname;
397
+ } catch (err) {
398
+ return undefined;
399
+ }
400
+ }).filter(domain => domain !== undefined))];
401
+ const domainsToFix = [];
402
+ for (const domain of domains) {
403
+ try {
404
+ // eslint-disable-next-line no-await-in-loop
405
+ const address = await (0, _promises.lookup)(domain, 4);
406
+ debug('%s resolves to %s', domain, address.address);
407
+ if (address.address !== '127.0.0.1') {
408
+ domainsToFix.push(domain);
409
+ console.warn(_chalk.default.yellow.bold('WARNING:'), `${domain} resolves to ${address.address} instead of 127.0.0.1. Things may not work as expected.`);
410
+ }
411
+ } catch (err) {
412
+ const msg = err instanceof Error ? err.message : 'Unknown error';
413
+ domainsToFix.push(domain);
414
+ console.warn(_chalk.default.yellow.bold('WARNING:'), `Failed to resolve ${domain}: ${msg}`);
415
+ }
416
+ }
417
+ if (domainsToFix.length) {
418
+ console.warn(_chalk.default.yellow('Please add the following lines to the hosts file on your system:\n'));
419
+ console.warn(domainsToFix.map(domain => `127.0.0.1 ${domain}`).join('\n'));
420
+ console.warn(_chalk.default.yellow('\nLearn more: https://docs.wpvip.com/vip-local-development-environment/troubleshooting-dev-env/#h-resolve-networking-configuration-issues\n'));
421
+ }
422
+ }
393
423
  async function checkEnvHealth(lando, instancePath) {
394
424
  const urls = {};
395
425
  const now = new Date();
@@ -400,10 +430,17 @@ async function checkEnvHealth(lando, instancePath) {
400
430
  });
401
431
  });
402
432
  const urlsToScan = Object.keys(urls).filter(url => !url.includes('*'));
433
+ await tryResolveDomains(urlsToScan);
403
434
  let scanResults = [];
404
435
  if (Array.isArray(app.urls)) {
405
436
  scanResults = app.urls;
406
- app.urls.forEach(entry => urlsToScan.splice(urlsToScan.indexOf(entry.url), 1));
437
+ app.urls.forEach(entry => {
438
+ // We use different status codes to see if the service is up.
439
+ // We may consider the service is up when Lando considers it is down.
440
+ if (entry.color !== 'red') {
441
+ urlsToScan.splice(urlsToScan.indexOf(entry.url), 1);
442
+ }
443
+ });
407
444
  }
408
445
  if (urlsToScan.length) {
409
446
  scanResults = scanResults.concat(await app.scanUrls(urlsToScan, {
@@ -424,8 +461,10 @@ async function isEnvUp(lando, instancePath) {
424
461
  const app = await getLandoApplication(lando, instancePath);
425
462
  const reachableServices = app.info.filter(service => service.urls.length);
426
463
  const webUrls = reachableServices.map(service => service.urls).flat().filter(url => !/^https?:\/\/(localhost|127\.0\.0\.1):/.exec(url));
464
+ await tryResolveDomains(webUrls);
427
465
  const scanResult = await app.scanUrls(webUrls, {
428
- max: 1
466
+ max: 1,
467
+ waitCodes: [502, 504]
429
468
  });
430
469
  const duration = new Date().getTime() - now.getTime();
431
470
  debug('isEnvUp took %d ms', duration);
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.getMediaImportConfig = getMediaImportConfig;
5
+ var _graphqlTag = _interopRequireDefault(require("graphql-tag"));
6
+ var _api = _interopRequireDefault(require("../api"));
7
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
8
+ const IMPORT_MEDIA_CONFIG_QUERY = (0, _graphqlTag.default)`
9
+ {
10
+ mediaImportConfig {
11
+ fileNameCharCount
12
+ fileSizeLimitInBytes
13
+ allowedFileTypes
14
+ }
15
+ }
16
+ `;
17
+ async function getMediaImportConfig() {
18
+ const api = (0, _api.default)();
19
+ const response = await api.query({
20
+ query: IMPORT_MEDIA_CONFIG_QUERY,
21
+ variables: {},
22
+ fetchPolicy: 'network-only'
23
+ });
24
+ return response?.data?.mediaImportConfig;
25
+ }