@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.
- package/CHANGELOG.md +17 -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 +34 -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/npm-shrinkwrap.json +913 -926
- package/package.json +12 -9
- 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
|
|
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
|
-
|
|
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
|
-
|
|
216
|
-
return (_component$dir = component.dir) !== null && _component$dir !== void 0 ? _component$dir : '';
|
|
217
|
+
return component.dir ?? '';
|
|
217
218
|
}
|
|
218
|
-
return
|
|
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
|
|
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
|
|
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 =
|
|
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$
|
|
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 =
|
|
433
|
-
php: (_envData$softwareSett =
|
|
434
|
-
wordpress: (
|
|
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
|
|
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.
|
|
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 = (
|
|
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<
|
|
50
|
+
* @return {Promise<LandoConfig>} Lando configuration
|
|
50
51
|
*/
|
|
51
52
|
async function getLandoConfig() {
|
|
52
|
-
const nodeModulesPath =
|
|
53
|
-
const landoPath =
|
|
54
|
-
const atLandoPath =
|
|
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
|
-
|
|
67
|
-
|
|
68
|
-
const
|
|
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
|
|
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: [
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
299
|
+
const info = _utils.default.startTable(app);
|
|
289
300
|
const reachableServices = app.info.filter(service => service.urls.length);
|
|
290
|
-
reachableServices.forEach(service =>
|
|
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:
|
|
296
|
-
...
|
|
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
|
-
|
|
360
|
-
|
|
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
|
|
367
|
-
if (containerScan !== null && containerScan !== void 0 &&
|
|
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
|
|
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
|
|
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
|
|
392
|
-
|
|
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 =>
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
531
|
+
const proxyContainer = docker.getContainer(proxyContainerName);
|
|
524
532
|
const status = await proxyContainer.inspect();
|
|
525
|
-
if (status
|
|
533
|
+
if (status.State.Running) {
|
|
526
534
|
return;
|
|
527
535
|
}
|
|
528
536
|
await proxyContainer.remove();
|
|
529
537
|
}
|
|
530
|
-
|
|
538
|
+
function validateDockerInstalled(lando) {
|
|
531
539
|
lando.log.verbose('docker-engine exists: %s', lando.engine.dockerInstalled);
|
|
532
|
-
if (lando.engine.dockerInstalled
|
|
533
|
-
throw
|
|
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
|
|
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
|
|
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 =
|
|
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.
|
|
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 (
|
|
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
|
-
|
|
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 &&
|
|
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.
|
|
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.
|
|
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
|
|
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 (
|
|
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
|
|
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 = (
|
|
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
|
}
|
package/dist/lib/envvar/input.js
CHANGED
|
@@ -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 (
|
|
45
|
+
return (str === null || str === void 0 ? void 0 : str.trim()) ?? '';
|
|
47
46
|
}
|