@automattic/vip 2.32.2 → 2.32.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/assets/dev-env.lando.template.yml.ejs +10 -2
  3. package/dist/bin/vip-dev-env-exec.js +1 -7
  4. package/dist/bin/vip-dev-env-shell.js +0 -4
  5. package/dist/bin/vip-dev-env-start.js +1 -1
  6. package/dist/bin/vip-dev-env-sync-sql.js +8 -6
  7. package/dist/bin/vip-dev-env-update.js +1 -2
  8. package/dist/bin/vip-import-sql.js +2 -2
  9. package/dist/bin/vip-logout.js +23 -0
  10. package/dist/bin/vip-slowlogs.js +192 -0
  11. package/dist/bin/vip-validate-preflight.js +8 -10
  12. package/dist/bin/vip-whoami.js +1 -2
  13. package/dist/bin/vip.js +1 -5
  14. package/dist/commands/backup-db.js +8 -9
  15. package/dist/lib/api/app.js +2 -2
  16. package/dist/lib/api/cache-purge.js +2 -2
  17. package/dist/lib/api/http.js +2 -3
  18. package/dist/lib/app-logs/app-logs.js +2 -2
  19. package/dist/lib/app-slowlogs/app-slowlogs.js +63 -0
  20. package/dist/lib/app-slowlogs/types.js +1 -0
  21. package/dist/lib/cli/apiConfig.js +1 -1
  22. package/dist/lib/client-file-uploader.js +19 -4
  23. package/dist/lib/config/software.js +4 -4
  24. package/dist/lib/constants/dev-environment.js +7 -3
  25. package/dist/lib/dev-environment/dev-environment-cli.js +110 -117
  26. package/dist/lib/dev-environment/dev-environment-configuration-file.js +34 -36
  27. package/dist/lib/dev-environment/dev-environment-core.js +36 -19
  28. package/dist/lib/dev-environment/dev-environment-lando.js +80 -72
  29. package/dist/lib/dev-environment/docker-utils.js +8 -9
  30. package/dist/lib/envvar/api-get-all.js +2 -2
  31. package/dist/lib/envvar/api-list.js +3 -6
  32. package/dist/lib/envvar/input.js +1 -2
  33. package/dist/lib/site-import/status.js +5 -5
  34. package/dist/lib/token.js +3 -6
  35. package/dist/lib/validations/is-multi-site-sql-dump.js +0 -1
  36. package/dist/lib/validations/is-multi-site.js +14 -12
  37. package/dist/lib/validations/is-multisite-domain-mapped.js +5 -10
  38. package/dist/lib/validations/line-by-line.js +9 -13
  39. package/dist/lib/validations/site-type.js +2 -7
  40. package/dist/lib/validations/sql.js +14 -19
  41. package/dist/lib/validations/utils.js +1 -1
  42. package/npm-shrinkwrap.json +913 -926
  43. package/package.json +12 -9
  44. package/tsconfig.json +3 -1
@@ -35,6 +35,7 @@ var _chalk = _interopRequireDefault(require("chalk"));
35
35
  var _enquirer = require("enquirer");
36
36
  var _copyDir = _interopRequireDefault(require("copy-dir"));
37
37
  var _uuid = require("uuid");
38
+ var _semver = _interopRequireDefault(require("semver"));
38
39
  var _devEnvironmentLando = require("./dev-environment-lando");
39
40
  var _searchAndReplace = require("../search-and-replace");
40
41
  var _devEnvironmentCli = require("./dev-environment-cli");
@@ -55,6 +56,7 @@ const debug = (0, _debug.default)('@automattic/vip:bin:dev-environment');
55
56
  const landoFileTemplatePath = _path.default.join(__dirname, '..', '..', '..', 'assets', 'dev-env.lando.template.yml.ejs');
56
57
  const nginxFileTemplatePath = _path.default.join(__dirname, '..', '..', '..', 'assets', 'dev-env.nginx.template.conf.ejs');
57
58
  const landoFileName = '.lando.yml';
59
+ const landoBackupFileName = '.lando.backup.yml';
58
60
  const nginxFileName = 'extra.conf';
59
61
  const instanceDataFileName = 'instance_data.json';
60
62
  const uploadPathString = 'uploads';
@@ -73,8 +75,9 @@ async function startEnvironment(lando, slug, options) {
73
75
  }
74
76
  let updated = false;
75
77
  if (!options.skipWpVersionsCheck) {
76
- updated = await updateWordPressImage(slug);
78
+ updated = await maybeUpdateWordPressImage(slug);
77
79
  }
80
+ updated = updated || (await maybeUpdateVersion(slug));
78
81
  if (options.skipRebuild && !updated) {
79
82
  await (0, _devEnvironmentLando.landoStart)(lando, instancePath);
80
83
  } else {
@@ -156,8 +159,7 @@ function preProcessInstanceData(instanceData) {
156
159
 
157
160
  // Mailpit migration
158
161
  if (!newInstanceData.mailpit) {
159
- var _newInstanceData$mail;
160
- newInstanceData.mailpit = (_newInstanceData$mail = newInstanceData.mailhog) !== null && _newInstanceData$mail !== void 0 ? _newInstanceData$mail : false;
162
+ newInstanceData.mailpit = newInstanceData.mailhog ?? false;
161
163
  }
162
164
 
163
165
  // MariaDB migration
@@ -167,6 +169,7 @@ function preProcessInstanceData(instanceData) {
167
169
 
168
170
  // newInstanceData
169
171
  newInstanceData.autologinKey = (0, _uuid.v4)();
172
+ newInstanceData.version = _devEnvironment.DEV_ENVIRONMENT_VERSION;
170
173
  return newInstanceData;
171
174
  }
172
175
  async function destroyEnvironment(lando, slug, removeFiles) {
@@ -210,21 +213,19 @@ async function printAllEnvironmentsInfo(lando, options) {
210
213
  }
211
214
  }
212
215
  function parseComponentForInfo(component) {
213
- var _component$tag;
214
216
  if (component.mode === 'local') {
215
- var _component$dir;
216
- return (_component$dir = component.dir) !== null && _component$dir !== void 0 ? _component$dir : '';
217
+ return component.dir ?? '';
217
218
  }
218
- return (_component$tag = component.tag) !== null && _component$tag !== void 0 ? _component$tag : '[demo-image]';
219
+ return component.tag ?? '[demo-image]';
219
220
  }
220
221
  async function showLogs(lando, slug, options = {}) {
221
222
  debug('Will display logs command on env', slug, 'with options', options);
222
223
  const instancePath = getEnvironmentPath(slug);
223
224
  debug('Instance path for', slug, 'is:', instancePath);
224
225
  if (options.service) {
225
- const appInfo = await (0, _devEnvironmentLando.landoInfo)(lando, instancePath, false);
226
+ const appInfo = await (0, _devEnvironmentLando.landoInfo)(lando, instancePath);
226
227
  if (!appInfo.services.includes(options.service)) {
227
- throw new _userError.default(`Service '${options.service}' not found. Please choose from one: ${appInfo.services}`);
228
+ throw new _userError.default(`Service '${options.service}' not found. Please choose from one: ${appInfo.services.toString()}`);
228
229
  }
229
230
  }
230
231
  return (0, _devEnvironmentLando.landoLogs)(lando, instancePath, options);
@@ -333,6 +334,7 @@ async function prepareLandoEnv(instanceData, instancePath) {
333
334
  const nginxFile = await _ejs.default.renderFile(nginxFileTemplatePath, instanceData);
334
335
  const instanceDataFile = JSON.stringify(instanceData);
335
336
  const landoFileTargetPath = _path.default.join(instancePath, landoFileName);
337
+ const landoBackupFileTargetPath = _path.default.join(instancePath, landoBackupFileName);
336
338
  const nginxFolderPath = _path.default.join(instancePath, nginxPathString);
337
339
  const nginxFileTargetPath = _path.default.join(nginxFolderPath, nginxFileName);
338
340
  const instanceDataTargetPath = _path.default.join(instancePath, instanceDataFileName);
@@ -342,6 +344,11 @@ async function prepareLandoEnv(instanceData, instancePath) {
342
344
  await _fs.default.promises.mkdir(nginxFolderPath, {
343
345
  recursive: true
344
346
  });
347
+ const landoFileExists = await _fs.default.promises.stat(landoFileTargetPath).catch(() => false);
348
+ if (landoFileExists) {
349
+ await _fs.default.promises.copyFile(landoFileTargetPath, landoBackupFileTargetPath);
350
+ console.log(`Backup of ${landoFileName} was created in ${landoBackupFileTargetPath}`);
351
+ }
345
352
  await Promise.all([_fs.default.promises.writeFile(landoFileTargetPath, landoFile), _fs.default.promises.writeFile(nginxFileTargetPath, nginxFile), _fs.default.promises.writeFile(instanceDataTargetPath, instanceDataFile)]);
346
353
  debug(`Lando file created in ${landoFileTargetPath}`);
347
354
  debug(`Nginx file created in ${nginxFileTargetPath}`);
@@ -398,13 +405,13 @@ async function getApplicationInformation(appId, envType) {
398
405
  const queryResult = await (0, _app.default)(appId, fieldsQuery, _software.appQueryFragments);
399
406
  const appData = {};
400
407
  if (queryResult.id) {
401
- var _queryResult$reposito, _queryResult$environm;
408
+ var _queryResult$reposito;
402
409
  appData.id = queryResult.id;
403
410
  appData.name = queryResult.name;
404
411
  appData.repository = (_queryResult$reposito = queryResult.repository) === null || _queryResult$reposito === void 0 ? void 0 : _queryResult$reposito.htmlUrl;
405
412
 
406
413
  // FIXME: This is casted as AppEnvironment[] but pedantically, Parker's schema made it so that the array may contain nullable. Code-wise though, that doesn't actually happen.
407
- const environments = (_queryResult$environm = queryResult.environments) !== null && _queryResult$environm !== void 0 ? _queryResult$environm : [];
414
+ const environments = queryResult.environments ?? [];
408
415
  let envData;
409
416
  if (envType) {
410
417
  envData = environments.find(candidateEnv => candidateEnv.type === envType);
@@ -423,15 +430,15 @@ async function getApplicationInformation(appId, envType) {
423
430
  envData = environments.find(candidateEnv => candidateEnv.type === env);
424
431
  }
425
432
  if (envData) {
426
- var _envData$primaryDomai, _envData$primaryDomai2, _envData$softwareSett, _envData$softwareSett2, _envData$softwareSett3, _envData$softwareSett4, _envData$softwareSett5, _envData$softwareSett6;
433
+ var _envData$primaryDomai, _envData$softwareSett, _envData$softwareSett2;
427
434
  appData.environment = {
428
435
  name: envData.name,
429
436
  branch: envData.branch,
430
437
  type: envData.type,
431
438
  isMultisite: envData.isMultisite,
432
- primaryDomain: (_envData$primaryDomai = (_envData$primaryDomai2 = envData.primaryDomain) === null || _envData$primaryDomai2 === void 0 ? void 0 : _envData$primaryDomai2.name) !== null && _envData$primaryDomai !== void 0 ? _envData$primaryDomai : '',
433
- php: (_envData$softwareSett = (_envData$softwareSett2 = envData.softwareSettings) === null || _envData$softwareSett2 === void 0 ? void 0 : (_envData$softwareSett3 = _envData$softwareSett2.php) === null || _envData$softwareSett3 === void 0 ? void 0 : _envData$softwareSett3.current.version) !== null && _envData$softwareSett !== void 0 ? _envData$softwareSett : '',
434
- wordpress: (_envData$softwareSett4 = (_envData$softwareSett5 = envData.softwareSettings) === null || _envData$softwareSett5 === void 0 ? void 0 : (_envData$softwareSett6 = _envData$softwareSett5.wordpress) === null || _envData$softwareSett6 === void 0 ? void 0 : _envData$softwareSett6.current.version) !== null && _envData$softwareSett4 !== void 0 ? _envData$softwareSett4 : ''
439
+ primaryDomain: ((_envData$primaryDomai = envData.primaryDomain) === null || _envData$primaryDomai === void 0 ? void 0 : _envData$primaryDomai.name) ?? '',
440
+ php: ((_envData$softwareSett = envData.softwareSettings) === null || _envData$softwareSett === void 0 || (_envData$softwareSett = _envData$softwareSett.php) === null || _envData$softwareSett === void 0 ? void 0 : _envData$softwareSett.current.version) ?? '',
441
+ wordpress: ((_envData$softwareSett2 = envData.softwareSettings) === null || _envData$softwareSett2 === void 0 || (_envData$softwareSett2 = _envData$softwareSett2.wordpress) === null || _envData$softwareSett2 === void 0 ? void 0 : _envData$softwareSett2.current.version) ?? ''
435
442
  };
436
443
  }
437
444
  }
@@ -500,7 +507,7 @@ async function importMediaPath(slug, filePath) {
500
507
  * @param {string} slug slug
501
508
  * @return {boolean} boolean
502
509
  */
503
- async function updateWordPressImage(slug) {
510
+ async function maybeUpdateWordPressImage(slug) {
504
511
  const versions = await getVersionList();
505
512
  if (!versions.length) {
506
513
  return false;
@@ -569,18 +576,17 @@ async function updateWordPressImage(slug) {
569
576
 
570
577
  // If the user takes the new WP version path
571
578
  if (confirm.upgrade === 'yes') {
572
- var _version$tag;
573
579
  console.log('Upgrading from: ' + _chalk.default.yellow(currentWordPressTag) + ' to:');
574
580
 
575
581
  // Select a new image
576
- const choice = await (0, _devEnvironmentCli.promptForComponent)('wordpress', false, null);
582
+ const choice = await (0, _devEnvironmentCli.promptForWordPress)(null);
577
583
  const version = versions.find(({
578
584
  tag
579
585
  }) => tag.trim() === choice.tag.trim());
580
586
 
581
587
  // Write new data and stage for rebuild
582
588
  // FIXME: version?.tag is possibly null. Should we throw if we can't find a version somehow?
583
- envData.wordpress.tag = (_version$tag = version === null || version === void 0 ? void 0 : version.tag) !== null && _version$tag !== void 0 ? _version$tag : '';
589
+ envData.wordpress.tag = (version === null || version === void 0 ? void 0 : version.tag) ?? '';
584
590
  envData.wordpress.ref = version === null || version === void 0 ? void 0 : version.ref;
585
591
  await updateEnvironment(envData);
586
592
  return true;
@@ -594,6 +600,17 @@ async function updateWordPressImage(slug) {
594
600
  }
595
601
  return false;
596
602
  }
603
+ async function maybeUpdateVersion(slug) {
604
+ const envData = readEnvironmentData(slug);
605
+ const currentVersion = envData.version;
606
+ console.log('Current local environment version is: ' + _chalk.default.yellow(currentVersion));
607
+ if (!currentVersion || _semver.default.lt(currentVersion, _devEnvironment.DEV_ENVIRONMENT_VERSION)) {
608
+ await updateEnvironment(envData);
609
+ console.log('Local environment version updated to: ' + _chalk.default.green(_devEnvironment.DEV_ENVIRONMENT_VERSION));
610
+ return true;
611
+ }
612
+ return false;
613
+ }
597
614
 
598
615
  /**
599
616
  * Makes a web call to raw.githubusercontent.com
@@ -16,42 +16,43 @@ exports.landoStart = landoStart;
16
16
  exports.landoStop = landoStop;
17
17
  exports.validateDockerAccess = validateDockerAccess;
18
18
  exports.validateDockerInstalled = validateDockerInstalled;
19
+ var _nodeOs = require("node:os");
20
+ var _promises = require("node:fs/promises");
21
+ var _promises2 = require("node:dns/promises");
22
+ var _nodePath = _interopRequireDefault(require("node:path"));
19
23
  var _debug = _interopRequireDefault(require("debug"));
20
- var _os = _interopRequireDefault(require("os"));
21
- var _fs = _interopRequireDefault(require("fs"));
22
- var _path = _interopRequireDefault(require("path"));
23
24
  var _lando = _interopRequireDefault(require("lando/lib/lando"));
24
25
  var _bootstrap = require("lando/lib/bootstrap");
25
26
  var _utils = _interopRequireDefault(require("lando/plugins/lando-core/lib/utils"));
26
27
  var _build = _interopRequireDefault(require("lando/plugins/lando-tooling/lib/build"));
27
28
  var _chalk = _interopRequireDefault(require("chalk"));
28
- var _app = _interopRequireDefault(require("lando/lib/app"));
29
- var _dns = _interopRequireDefault(require("dns"));
30
29
  var _xdgBasedir = _interopRequireDefault(require("xdg-basedir"));
31
30
  var _devEnvironmentCore = require("./dev-environment-core");
32
31
  var _devEnvironment = require("../constants/dev-environment");
33
32
  var _dockerUtils = require("./docker-utils");
34
33
  var _userError = _interopRequireDefault(require("../user-error"));
35
34
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
36
- // @format
37
35
  /**
38
36
  * External dependencies
39
37
  */
38
+
40
39
  /**
41
40
  * Internal dependencies
42
41
  */
42
+
43
43
  /**
44
44
  * This file will hold all the interactions with lando library
45
45
  */
46
46
  const DEBUG_KEY = '@automattic/vip:bin:dev-environment';
47
47
  const debug = (0, _debug.default)(DEBUG_KEY);
48
+
48
49
  /**
49
- * @return {Promise<object>} Lando configuration
50
+ * @return {Promise<LandoConfig>} Lando configuration
50
51
  */
51
52
  async function getLandoConfig() {
52
- const nodeModulesPath = _path.default.join(__dirname, '..', '..', '..', 'node_modules');
53
- const landoPath = _path.default.join(nodeModulesPath, 'lando');
54
- const atLandoPath = _path.default.join(nodeModulesPath, '@lando');
53
+ const nodeModulesPath = _nodePath.default.join(__dirname, '..', '..', '..', 'node_modules');
54
+ const landoPath = _nodePath.default.join(nodeModulesPath, 'lando');
55
+ const atLandoPath = _nodePath.default.join(nodeModulesPath, '@lando');
55
56
  debug(`Getting Lando config, using paths '${landoPath}' and '${atLandoPath}' for plugins`);
56
57
  const isLandoDebugSelected = _debug.default.enabled(DEBUG_KEY);
57
58
  const isAllDebugSelected = _debug.default.enabled('"*"');
@@ -63,11 +64,13 @@ async function getLandoConfig() {
63
64
  } else {
64
65
  logLevelConsole = 'warn';
65
66
  }
66
- const vipDir = _path.default.join(_xdgBasedir.default.data || _os.default.tmpdir(), 'vip');
67
- const landoDir = _path.default.join(vipDir, 'lando');
68
- const fakeHomeDir = _path.default.join(landoDir, 'home');
67
+
68
+ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
69
+ const vipDir = _nodePath.default.join(_xdgBasedir.default.data || (0, _nodeOs.tmpdir)(), 'vip'); // NOSONAR
70
+ const landoDir = _nodePath.default.join(vipDir, 'lando');
71
+ const fakeHomeDir = _nodePath.default.join(landoDir, 'home');
69
72
  try {
70
- await _fs.default.promises.mkdir(fakeHomeDir, {
73
+ await (0, _promises.mkdir)(fakeHomeDir, {
71
74
  recursive: true
72
75
  });
73
76
  } catch (err) {
@@ -75,7 +78,7 @@ async function getLandoConfig() {
75
78
  }
76
79
  const config = {
77
80
  logLevelConsole,
78
- configSources: [_path.default.join(landoDir, 'config.yml')],
81
+ configSources: [_nodePath.default.join(landoDir, 'config.yml')],
79
82
  landoFile: '.lando.yml',
80
83
  preLandoFiles: ['.lando.base.yml', '.lando.dist.yml', '.lando.upstream.yml'],
81
84
  postLandoFiles: ['.lando.local.yml'],
@@ -94,17 +97,32 @@ async function getLandoConfig() {
94
97
  return (0, _bootstrap.buildConfig)(config);
95
98
  }
96
99
  const appMap = new Map();
100
+ async function initLandoApplication(lando, instancePath) {
101
+ const app = lando.getApp(instancePath);
102
+ app.events.on('post-init', 1, () => {
103
+ const initOnly = [];
104
+ Object.keys(app.config.services).forEach(serviceName => {
105
+ if (app.config.services[serviceName].initOnly) {
106
+ initOnly.push(serviceName);
107
+ app.config.services[serviceName].scanner = false;
108
+ }
109
+ });
110
+ app.services = app.services.filter(service => !initOnly.includes(service));
111
+ });
112
+ await app.init();
113
+ return app;
114
+ }
97
115
  async function regenerateLandofile(instancePath) {
98
- const landoFile = _path.default.join(instancePath, '.lando.yml');
116
+ const landoFile = _nodePath.default.join(instancePath, '.lando.yml');
99
117
  try {
100
118
  const now = new Date().toISOString().replace(/[^\d]/g, '').slice(0, -3);
101
119
  const backup = `${landoFile}.${now}`;
102
- await _fs.default.promises.rename(landoFile, backup);
120
+ await (0, _promises.rename)(landoFile, backup);
103
121
  console.warn(_chalk.default.yellow('Backed up %s to %s'), landoFile, backup);
104
122
  } catch (err) {
105
123
  // Rename failed - possibly the file does not exist. Silently ignoring.
106
124
  }
107
- const slug = _path.default.basename(instancePath);
125
+ const slug = _nodePath.default.basename(instancePath);
108
126
  const currentInstanceData = (0, _devEnvironmentCore.readEnvironmentData)(slug);
109
127
  currentInstanceData.pullAfter = 0;
110
128
  await (0, _devEnvironmentCore.updateEnvironment)(currentInstanceData);
@@ -120,9 +138,7 @@ async function landoRecovery(lando, instancePath, error) {
120
138
  }
121
139
  console.error(_chalk.default.green('Recovery successful, trying to initialize again...'));
122
140
  try {
123
- const app = lando.getApp(instancePath);
124
- await app.init();
125
- return app;
141
+ return await initLandoApplication(lando, instancePath);
126
142
  } catch (initError) {
127
143
  console.error(`${_chalk.default.bold.red('Initialization failed, aborting.')} Please recreate the environment or contact support.`);
128
144
  throw initError;
@@ -139,8 +155,7 @@ async function getLandoApplication(lando, instancePath) {
139
155
  }
140
156
  let app;
141
157
  try {
142
- app = lando.getApp(instancePath);
143
- await app.init();
158
+ app = await initLandoApplication(lando, instancePath);
144
159
  } catch (error) {
145
160
  app = await landoRecovery(lando, instancePath, error);
146
161
  }
@@ -164,13 +179,13 @@ async function bootstrapLando() {
164
179
  const instanceData = (0, _devEnvironmentCore.readEnvironmentData)(data.name);
165
180
  let registryResolvable = false;
166
181
  try {
167
- registryResolvable = (await _dns.default.promises.lookup('ghcr.io')).address || false;
182
+ registryResolvable = (await (0, _promises2.lookup)('ghcr.io')).address.length > 0 || false;
168
183
  debug('Registry ghcr.io is resolvable');
169
184
  } catch (err) {
170
185
  debug('Registry ghcr.io is not resolvable, image pull might be broken.');
171
186
  registryResolvable = false;
172
187
  }
173
- const pull = registryResolvable && (instanceData.pullAfter || 0) < Date.now();
188
+ const pull = registryResolvable && (instanceData.pullAfter ?? 0) < Date.now();
174
189
  if (Array.isArray(data.opts.pullable) && Array.isArray(data.opts.local) && data.opts.local.length === 0 && !pull) {
175
190
  // Setting `data.opts.pullable` to an empty array prevents Lando from pulling images with `docker pull`.
176
191
  // Note that if some of the images are not available, they will still be pulled by `docker-compose`.
@@ -206,12 +221,12 @@ async function landoLogs(lando, instancePath, options) {
206
221
  debug('Will show lando logs on path:', instancePath, ' with options: ', options);
207
222
  const app = await getLandoApplication(lando, instancePath);
208
223
  const logTask = lando.tasks.find(task => task.command === 'logs');
209
- await logTask.run({
224
+ await (logTask === null || logTask === void 0 ? void 0 : logTask.run({
210
225
  follow: options.follow,
211
226
  service: options.service,
212
227
  timestamps: options.timestamps,
213
228
  _app: app
214
- });
229
+ }));
215
230
  } finally {
216
231
  const duration = new Date().getTime() - started.getTime();
217
232
  debug('landoLogs() took %d ms', duration);
@@ -230,12 +245,8 @@ async function landoRebuild(lando, instancePath) {
230
245
  debug('landoRebuild() took %d ms', duration);
231
246
  }
232
247
  }
233
-
234
- /**
235
- * @return {Promise<import('dockerode').NetworkInspectInfo | null>}
236
- */
237
248
  async function getBridgeNetwork(lando) {
238
- const networkName = lando.config.networkBridge || 'lando_bridge_network';
249
+ const networkName = lando.config.networkBridge ?? 'lando_bridge_network';
239
250
  try {
240
251
  return await lando.engine.getNetwork(networkName).inspect();
241
252
  } catch (err) {
@@ -285,15 +296,15 @@ async function landoInfo(lando, instancePath, options = {}) {
285
296
  try {
286
297
  var _app$info$find;
287
298
  const app = await getLandoApplication(lando, instancePath);
288
- let appInfo = _utils.default.startTable(app);
299
+ const info = _utils.default.startTable(app);
289
300
  const reachableServices = app.info.filter(service => service.urls.length);
290
- reachableServices.forEach(service => appInfo[`${service.service} urls`] = service.urls);
301
+ reachableServices.forEach(service => info[`${service.service} urls`] = service.urls);
291
302
  const health = await checkEnvHealth(lando, instancePath);
292
- const frontEndUrl = (_app$info$find = app.info.find(service => 'nginx' === service.service)) === null || _app$info$find === void 0 ? void 0 : _app$info$find.urls[0];
303
+ const frontEndUrl = ((_app$info$find = app.info.find(service => 'nginx' === service.service)) === null || _app$info$find === void 0 ? void 0 : _app$info$find.urls[0]) ?? '';
293
304
  const extraService = await getExtraServicesConnections(lando, app);
294
- appInfo = {
295
- slug: appInfo.name.replace(/^vipdev/, ''),
296
- ...appInfo,
305
+ const appInfo = {
306
+ slug: info.name.replace(/^vipdev/, ''),
307
+ ...info,
297
308
  ...extraService
298
309
  };
299
310
  delete appInfo.name;
@@ -356,22 +367,21 @@ async function getExtraServicesConnections(lando, app) {
356
367
  project: app.project
357
368
  });
358
369
  for (const service of allServices) {
359
- var _containerScan$Networ;
360
- const displayConfiguration = extraServiceDisplayConfiguration.find(conf => conf.name === service.service) || {};
361
- if (displayConfiguration.skip) {
370
+ const displayConfiguration = extraServiceDisplayConfiguration.find(conf => conf.name === service.service);
371
+ if (!displayConfiguration || displayConfiguration.skip) {
362
372
  continue;
363
373
  }
364
374
 
365
375
  // eslint-disable-next-line no-await-in-loop
366
- const containerScan = service !== null && service !== void 0 && service.id ? await lando.engine.docker.scan(service === null || service === void 0 ? void 0 : service.id) : null;
367
- if (containerScan !== null && containerScan !== void 0 && (_containerScan$Networ = containerScan.NetworkSettings) !== null && _containerScan$Networ !== void 0 && _containerScan$Networ.Ports) {
376
+ const containerScan = service.id ? await lando.engine.docker.scan(service.id) : null;
377
+ if (containerScan !== null && containerScan !== void 0 && containerScan.NetworkSettings.Ports) {
368
378
  const mappings = Object.keys(containerScan.NetworkSettings.Ports).map(internalPort => containerScan.NetworkSettings.Ports[internalPort]).filter(externalMapping => externalMapping === null || externalMapping === void 0 ? void 0 : externalMapping.length);
369
- if (mappings !== null && mappings !== void 0 && mappings.length) {
379
+ if (mappings.length) {
370
380
  const {
371
381
  HostIp: host,
372
382
  HostPort: port
373
383
  } = mappings[0][0];
374
- const label = displayConfiguration.label || service.service;
384
+ const label = displayConfiguration.label ?? service.service;
375
385
  const value = (displayConfiguration.protocol ? `${displayConfiguration.protocol}://` : '') + `${host}:${port}`;
376
386
  extraServices[label] = value;
377
387
  }
@@ -388,9 +398,17 @@ async function checkEnvHealth(lando, instancePath) {
388
398
  urls[url] = service.service;
389
399
  });
390
400
  });
391
- const scanResults = await app.scanUrls(Object.keys(urls), {
392
- max: 1
393
- });
401
+ const urlsToScan = Object.keys(urls);
402
+ let scanResults = [];
403
+ if (Array.isArray(app.urls)) {
404
+ scanResults = app.urls;
405
+ app.urls.forEach(entry => urlsToScan.splice(urlsToScan.indexOf(entry.url), 1));
406
+ }
407
+ if (urlsToScan.length) {
408
+ scanResults = scanResults.concat(await app.scanUrls(urlsToScan, {
409
+ max: 1
410
+ }));
411
+ }
394
412
  const result = {};
395
413
  scanResults.forEach(scanResult => {
396
414
  result[urls[scanResult.url]] = scanResult.status;
@@ -403,7 +421,7 @@ async function isEnvUp(lando, instancePath) {
403
421
  const now = new Date();
404
422
  const app = await getLandoApplication(lando, instancePath);
405
423
  const reachableServices = app.info.filter(service => service.urls.length);
406
- const webUrls = reachableServices.map(service => service.urls).flat().filter(url => !url.match(/^https?:\/\/(localhost|127\.0\.0\.1):/));
424
+ const webUrls = reachableServices.map(service => service.urls).flat().filter(url => !/^https?:\/\/(localhost|127\.0\.0\.1):/.exec(url));
407
425
  const scanResult = await app.scanUrls(webUrls, {
408
426
  max: 1
409
427
  });
@@ -411,7 +429,7 @@ async function isEnvUp(lando, instancePath) {
411
429
  debug('isEnvUp took %d ms', duration);
412
430
 
413
431
  // If all the URLs are reachable then the app is considered 'up'
414
- return scanResult.length && scanResult.filter(result => result.status).length === scanResult.length;
432
+ return scanResult.length > 0 && scanResult.filter(result => result.status).length === scanResult.length;
415
433
  }
416
434
  async function landoExec(lando, instancePath, toolName, args, options) {
417
435
  const app = await getLandoApplication(lando, instancePath);
@@ -451,12 +469,12 @@ async function landoShell(lando, instancePath, service, user, command) {
451
469
  command = ['/bin/sh', '-c', `if [ -x /bin/bash ]; then /bin/bash ${interactive}; else /bin/sh ${interactive}; fi; exit 0`];
452
470
  }
453
471
  debug('Running command "%o" in service "%s" as user "%s"', command, service, user);
454
- await shellTask.run({
472
+ await (shellTask === null || shellTask === void 0 ? void 0 : shellTask.run({
455
473
  command,
456
474
  service,
457
475
  user,
458
476
  _app: app
459
- });
477
+ }));
460
478
  }
461
479
 
462
480
  /**
@@ -470,7 +488,7 @@ async function landoShell(lando, instancePath, service, user, command) {
470
488
  async function removeDevToolsVolumes(lando, app) {
471
489
  debug('Attempting to removing dev-tools volumes');
472
490
  const scanResult = await lando.engine.docker.listVolumes();
473
- const devToolsVolumeNames = ((scanResult === null || scanResult === void 0 ? void 0 : scanResult.Volumes) || []).map(volume => volume.Name)
491
+ const devToolsVolumeNames = scanResult.Volumes.map(volume => volume.Name)
474
492
  // eslint-disable-next-line security/detect-non-literal-regexp
475
493
  .filter(volumeName => new RegExp(`${app.project}.*devtools`).test(volumeName));
476
494
  debug('Will remove', devToolsVolumeNames);
@@ -480,17 +498,10 @@ async function removeDevToolsVolumes(lando, app) {
480
498
 
481
499
  /**
482
500
  * Remove volume
483
- *
484
- * @param {Lando} lando
485
- * @param {string} volumeName
486
501
  */
487
502
  async function removeVolume(lando, volumeName) {
488
503
  debug(`Removing devtools volume ${volumeName}`);
489
- const devToolsVolume = await lando.engine.docker.getVolume(volumeName);
490
- if (!devToolsVolume) {
491
- debug(`Volume ${volumeName} not found`);
492
- return;
493
- }
504
+ const devToolsVolume = lando.engine.docker.getVolume(volumeName);
494
505
  try {
495
506
  await devToolsVolume.remove();
496
507
  debug(`${volumeName} volume removed`);
@@ -505,12 +516,9 @@ async function removeVolume(lando, volumeName) {
505
516
  * to start due to missing network.
506
517
  *
507
518
  * This function tries to detect such scenario and remove the orphant. So that regular flow
508
- * can safelly add a network and a new proxy container.
509
- *
510
- * @param {Object} lando Bootstrapped Lando object
519
+ * can safely add a network and a new proxy container.
511
520
  */
512
521
  async function ensureNoOrphantProxyContainer(lando) {
513
- var _status$State;
514
522
  const proxyContainerName = lando.config.proxyContainer;
515
523
  const docker = lando.engine.docker;
516
524
  const containers = await docker.listContainers({
@@ -520,20 +528,20 @@ async function ensureNoOrphantProxyContainer(lando) {
520
528
  if (!proxyContainerExists) {
521
529
  return;
522
530
  }
523
- const proxyContainer = await docker.getContainer(proxyContainerName);
531
+ const proxyContainer = docker.getContainer(proxyContainerName);
524
532
  const status = await proxyContainer.inspect();
525
- if (status !== null && status !== void 0 && (_status$State = status.State) !== null && _status$State !== void 0 && _status$State.Running) {
533
+ if (status.State.Running) {
526
534
  return;
527
535
  }
528
536
  await proxyContainer.remove();
529
537
  }
530
- async function validateDockerInstalled(lando) {
538
+ function validateDockerInstalled(lando) {
531
539
  lando.log.verbose('docker-engine exists: %s', lando.engine.dockerInstalled);
532
- if (lando.engine.dockerInstalled === false) {
533
- throw Error('docker could not be located! Please follow the following instructions to install it - https://docs.docker.com/engine/install/');
540
+ if (!lando.engine.dockerInstalled) {
541
+ throw new _userError.default('docker could not be located! Please follow the following instructions to install it - https://docs.docker.com/engine/install/');
534
542
  }
535
543
  lando.log.verbose('docker-compose exists: %s', lando.engine.composeInstalled);
536
- if (lando.engine.composeInstalled === false) {
544
+ if (!lando.engine.composeInstalled) {
537
545
  throw Error('docker-compose could not be located! Please follow the following instructions to install it - https://docs.docker.com/compose/install/');
538
546
  }
539
547
  }
@@ -543,6 +551,6 @@ async function validateDockerAccess(lando) {
543
551
  try {
544
552
  await docker.info();
545
553
  } catch (error) {
546
- throw Error('Failed to connect to Docker. Please verify that Docker engine (service) is running and follow the troubleshooting instructions for your platform.');
554
+ throw new _userError.default('Failed to connect to Docker. Please verify that Docker engine (service) is running and follow the troubleshooting instructions for your platform.');
547
555
  }
548
556
  }
@@ -9,12 +9,12 @@ exports.splitca = splitca;
9
9
  var _nodeFs = require("node:fs");
10
10
  var _promises = require("node:fs/promises");
11
11
  var _nodeOs = require("node:os");
12
- var _nodePath = _interopRequireDefault(require("node:path"));
13
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
12
+ var _nodePath = require("node:path");
14
13
  /* eslint-disable no-await-in-loop */
15
14
  /**
16
15
  * External dependencies
17
16
  */
17
+
18
18
  /**
19
19
  * Reads a Certificate Authority file and returns it as an array of certificates
20
20
  *
@@ -24,7 +24,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
24
24
  async function splitca(filepath) {
25
25
  const ca = [];
26
26
  const data = await (0, _promises.readFile)(filepath, 'utf-8');
27
- if (data.indexOf('-END CERTIFICATE-') < 0 || data.indexOf('-BEGIN CERTIFICATE-') < 0) {
27
+ if (!data.includes('-END CERTIFICATE-') || !data.includes('-BEGIN CERTIFICATE-')) {
28
28
  throw new Error("File does not contain 'BEGIN CERTIFICATE' or 'END CERTIFICATE'");
29
29
  }
30
30
  const chain = data.split('\n');
@@ -32,7 +32,7 @@ async function splitca(filepath) {
32
32
  for (const line of chain) {
33
33
  if (line) {
34
34
  cert.push(line);
35
- if (line.match(/-END CERTIFICATE-/)) {
35
+ if (/-END CERTIFICATE-/.exec(line)) {
36
36
  ca.push(cert.join('\n'));
37
37
  cert = [];
38
38
  }
@@ -51,10 +51,9 @@ async function canReadWrite(what) {
51
51
  }
52
52
  async function getDockerSocket() {
53
53
  if ((0, _nodeOs.platform)() !== 'win32') {
54
- var _process$env$DOCKER_H;
55
- const possibleSocket = (_process$env$DOCKER_H = process.env.DOCKER_HOST) !== null && _process$env$DOCKER_H !== void 0 ? _process$env$DOCKER_H : '';
54
+ const possibleSocket = process.env.DOCKER_HOST ?? '';
56
55
  // If `DOCKER_HOST` is set and not empty, and if it does not point to a unix socket, return - not much that we can do here.
57
- if (possibleSocket && !/^unix:\/\//.test(possibleSocket)) {
56
+ if (possibleSocket && !possibleSocket.startsWith('unix://')) {
58
57
  return possibleSocket;
59
58
  }
60
59
  const paths = [];
@@ -67,7 +66,7 @@ async function getDockerSocket() {
67
66
  // Try the default location
68
67
  paths.push('/var/run/docker.sock');
69
68
  // Try an alternative location
70
- paths.push(_nodePath.default.join((0, _nodeOs.homedir)(), '.docker', 'run', 'docker.sock'));
69
+ paths.push((0, _nodePath.join)((0, _nodeOs.homedir)(), '.docker', 'run', 'docker.sock'));
71
70
  for (const socketPath of paths) {
72
71
  try {
73
72
  const stats = await (0, _promises.stat)(socketPath);
@@ -102,7 +101,7 @@ async function getEngineConfig(dockerHost) {
102
101
  }
103
102
  const certPath = process.env.DOCKER_CERT_PATH;
104
103
  if (certPath) {
105
- const [ca, cert, key] = await Promise.all([splitca(_nodePath.default.join(certPath, 'ca.pem')), (0, _promises.readFile)(_nodePath.default.join(certPath, 'cert.pem'), 'utf-8'), (0, _promises.readFile)(_nodePath.default.join(certPath, 'key.pem'), 'utf-8')]);
104
+ const [ca, cert, key] = await Promise.all([splitca((0, _nodePath.join)(certPath, 'ca.pem')), (0, _promises.readFile)((0, _nodePath.join)(certPath, 'cert.pem'), 'utf-8'), (0, _promises.readFile)((0, _nodePath.join)(certPath, 'key.pem'), 'utf-8')]);
106
105
  opts.ca = ca;
107
106
  opts.cert = cert;
108
107
  opts.key = key;
@@ -33,7 +33,7 @@ const query = (0, _graphqlTag.default)`
33
33
  }
34
34
  `;
35
35
  async function getEnvVars(appId, envId) {
36
- var _ref, _data$app, _data$app$environment, _data$app$environment2, _data$app$environment3;
36
+ var _data$app;
37
37
  const api = await (0, _api.default)();
38
38
  const variables = {
39
39
  appId,
@@ -45,5 +45,5 @@ async function getEnvVars(appId, envId) {
45
45
  query,
46
46
  variables
47
47
  });
48
- return (_ref = (_data$app = data.app) === null || _data$app === void 0 ? void 0 : (_data$app$environment = _data$app.environments) === null || _data$app$environment === void 0 ? void 0 : (_data$app$environment2 = _data$app$environment[0]) === null || _data$app$environment2 === void 0 ? void 0 : (_data$app$environment3 = _data$app$environment2.environmentVariables) === null || _data$app$environment3 === void 0 ? void 0 : _data$app$environment3.nodes) !== null && _ref !== void 0 ? _ref : null;
48
+ return ((_data$app = data.app) === null || _data$app === void 0 || (_data$app = _data$app.environments) === null || _data$app === void 0 || (_data$app = _data$app[0]) === null || _data$app === void 0 || (_data$app = _data$app.environmentVariables) === null || _data$app === void 0 ? void 0 : _data$app.nodes) ?? null;
49
49
  }
@@ -34,7 +34,7 @@ const query = (0, _graphqlTag.default)`
34
34
 
35
35
  // List the names (but not values) of environment variables.
36
36
  async function listEnvVars(appId, envId) {
37
- var _data$app$environment, _data$app, _data$app$environment2, _data$app$environment3, _data$app$environment4;
37
+ var _data$app;
38
38
  const api = await (0, _api.default)();
39
39
  const variables = {
40
40
  appId,
@@ -46,9 +46,6 @@ async function listEnvVars(appId, envId) {
46
46
  query,
47
47
  variables
48
48
  });
49
- const nodes = (_data$app$environment = (_data$app = data.app) === null || _data$app === void 0 ? void 0 : (_data$app$environment2 = _data$app.environments) === null || _data$app$environment2 === void 0 ? void 0 : (_data$app$environment3 = _data$app$environment2[0]) === null || _data$app$environment3 === void 0 ? void 0 : (_data$app$environment4 = _data$app$environment3.environmentVariables) === null || _data$app$environment4 === void 0 ? void 0 : _data$app$environment4.nodes) !== null && _data$app$environment !== void 0 ? _data$app$environment : [];
50
- return nodes.map(entry => {
51
- var _entry$name;
52
- return (_entry$name = entry === null || entry === void 0 ? void 0 : entry.name) !== null && _entry$name !== void 0 ? _entry$name : '';
53
- });
49
+ const nodes = ((_data$app = data.app) === null || _data$app === void 0 || (_data$app = _data$app.environments) === null || _data$app === void 0 || (_data$app = _data$app[0]) === null || _data$app === void 0 || (_data$app = _data$app.environmentVariables) === null || _data$app === void 0 ? void 0 : _data$app.nodes) ?? [];
50
+ return nodes.map(entry => (entry === null || entry === void 0 ? void 0 : entry.name) ?? '');
54
51
  }
@@ -29,7 +29,6 @@ function confirm(message) {
29
29
  }).run().catch(() => false);
30
30
  }
31
31
  async function promptForValue(message, mustMatch) {
32
- var _str$trim;
33
32
  const {
34
33
  str
35
34
  } = await (0, _enquirer.prompt)({
@@ -43,5 +42,5 @@ async function promptForValue(message, mustMatch) {
43
42
  return true;
44
43
  }
45
44
  });
46
- return (_str$trim = str === null || str === void 0 ? void 0 : str.trim()) !== null && _str$trim !== void 0 ? _str$trim : '';
45
+ return (str === null || str === void 0 ? void 0 : str.trim()) ?? '';
47
46
  }