@automattic/vip 2.27.0 → 2.28.0-dev7
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/automattic-vip-2.28.0-dev7.tgz +0 -0
- package/dist/bin/vip-cache.js +1 -1
- package/dist/bin/vip-config-envvar.js +1 -1
- package/dist/bin/vip-dev-env-sync-sql.js +71 -0
- package/dist/bin/vip-dev-env-sync.js +21 -0
- package/dist/bin/vip-dev-env.js +2 -2
- package/dist/bin/vip-validate.js +1 -1
- package/dist/commands/dev-env-sync-sql.js +30 -15
- package/dist/commands/export-sql.js +29 -22
- package/dist/lib/dev-environment/dev-environment-lando.js +22 -81
- package/dist/lib/tracker.js +10 -0
- package/npm-shrinkwrap.json +2 -0
- package/package.json +3 -1
|
Binary file
|
package/dist/bin/vip-cache.js
CHANGED
|
@@ -17,5 +17,5 @@
|
|
|
17
17
|
var _command = _interopRequireDefault(require("../lib/cli/command"));
|
|
18
18
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
19
19
|
(0, _command.default)({
|
|
20
|
-
requiredArgs:
|
|
20
|
+
requiredArgs: 1
|
|
21
21
|
}).command('purge-url', 'Purge page cache').argv(process.argv);
|
|
@@ -17,5 +17,5 @@
|
|
|
17
17
|
var _command = _interopRequireDefault(require("../lib/cli/command"));
|
|
18
18
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
19
19
|
(0, _command.default)({
|
|
20
|
-
requiredArgs:
|
|
20
|
+
requiredArgs: 0
|
|
21
21
|
}).command('delete', 'Permanently delete an environment variable').command('get', 'Get the value of an environment variable').command('get-all', 'Get the values of all environment variable').command('list', 'List the names of all environment variables').command('set', 'Add or update an environment variable').argv(process.argv);
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* @format
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* External dependencies
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Internal dependencies
|
|
14
|
+
*/
|
|
15
|
+
"use strict";
|
|
16
|
+
|
|
17
|
+
var _command = _interopRequireDefault(require("../lib/cli/command"));
|
|
18
|
+
var _devEnvironmentCore = require("../lib/dev-environment/dev-environment-core");
|
|
19
|
+
var _devEnvironmentLando = require("../lib/dev-environment/dev-environment-lando");
|
|
20
|
+
var _userError = _interopRequireDefault(require("../lib/user-error"));
|
|
21
|
+
var _devEnvSyncSql = require("../commands/dev-env-sync-sql");
|
|
22
|
+
var _devEnvironment = require("../lib/constants/dev-environment");
|
|
23
|
+
var _tracker = require("../lib/tracker");
|
|
24
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
25
|
+
const examples = [{
|
|
26
|
+
usage: `${_devEnvironment.DEV_ENVIRONMENT_FULL_COMMAND} sync sql @my-test.develop --slug=my_site`,
|
|
27
|
+
description: 'Syncs with the `my-test` site\'s `develop` environment database into `my_site`'
|
|
28
|
+
}];
|
|
29
|
+
const appQuery = `
|
|
30
|
+
id,
|
|
31
|
+
name,
|
|
32
|
+
type,
|
|
33
|
+
organization { id, name },
|
|
34
|
+
environments{
|
|
35
|
+
id
|
|
36
|
+
appId
|
|
37
|
+
type
|
|
38
|
+
name
|
|
39
|
+
primaryDomain { name }
|
|
40
|
+
uniqueLabel
|
|
41
|
+
}
|
|
42
|
+
`;
|
|
43
|
+
(0, _command.default)({
|
|
44
|
+
appContext: true,
|
|
45
|
+
appQuery,
|
|
46
|
+
envContext: true,
|
|
47
|
+
requiredArgs: 0,
|
|
48
|
+
module: 'dev-env-sync-sql'
|
|
49
|
+
}).option('slug', 'Custom name of the dev environment').examples(examples).argv(process.argv, async (arg, {
|
|
50
|
+
app,
|
|
51
|
+
env,
|
|
52
|
+
slug
|
|
53
|
+
}) => {
|
|
54
|
+
const trackerFn = (0, _tracker.makeCommandTracker)('dev_env_sync_sql', {
|
|
55
|
+
app: app.id,
|
|
56
|
+
env: env.uniqueLabel,
|
|
57
|
+
slug
|
|
58
|
+
});
|
|
59
|
+
await trackerFn('execute');
|
|
60
|
+
const lando = await (0, _devEnvironmentLando.bootstrapLando)();
|
|
61
|
+
const envPath = (0, _devEnvironmentCore.getEnvironmentPath)(slug);
|
|
62
|
+
if (!(await (0, _devEnvironmentLando.isEnvUp)(lando, envPath))) {
|
|
63
|
+
await trackerFn('env_not_running_error', {
|
|
64
|
+
errorMessage: 'Environment was not running'
|
|
65
|
+
});
|
|
66
|
+
throw new _userError.default('Environment needs to be started first');
|
|
67
|
+
}
|
|
68
|
+
const cmd = new _devEnvSyncSql.DevEnvSyncSQLCommand(app, env, slug, trackerFn);
|
|
69
|
+
await cmd.run();
|
|
70
|
+
await trackerFn('success');
|
|
71
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* @format
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* External dependencies
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Internal dependencies
|
|
14
|
+
*/
|
|
15
|
+
"use strict";
|
|
16
|
+
|
|
17
|
+
var _command = _interopRequireDefault(require("../lib/cli/command"));
|
|
18
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
19
|
+
(0, _command.default)({
|
|
20
|
+
requiredArgs: 1
|
|
21
|
+
}).command('sql', 'Sync local database with a production environment').argv(process.argv);
|
package/dist/bin/vip-dev-env.js
CHANGED
|
@@ -17,5 +17,5 @@
|
|
|
17
17
|
var _command = _interopRequireDefault(require("../lib/cli/command"));
|
|
18
18
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
19
19
|
(0, _command.default)({
|
|
20
|
-
requiredArgs:
|
|
21
|
-
}).command('create', 'Create a new local dev environment').command('update', 'Update an already created local dev environment').command('start', 'Start a local dev environment').command('stop', 'Stop a local dev environment').command('destroy', 'Remove containers, networks, volumes and configuration files of a local dev environment').command('info', 'Provides basic info about one or multiple local dev environments').command('list', 'Provides basic info about all local dev environments').command('exec', 'Execute a WP-CLI command in local dev environment').command('import', 'Import data into a local WordPress environment').command('shell', 'Spawns a shell in a dev environment').command('logs', 'View logs from a local WordPress environment').argv(process.argv);
|
|
20
|
+
requiredArgs: 0
|
|
21
|
+
}).command('create', 'Create a new local dev environment').command('update', 'Update an already created local dev environment').command('start', 'Start a local dev environment').command('stop', 'Stop a local dev environment').command('destroy', 'Remove containers, networks, volumes and configuration files of a local dev environment').command('info', 'Provides basic info about one or multiple local dev environments').command('list', 'Provides basic info about all local dev environments').command('exec', 'Execute a WP-CLI command in local dev environment').command('import', 'Import data into a local WordPress environment').command('shell', 'Spawns a shell in a dev environment').command('logs', 'View logs from a local WordPress environment').command('sync', 'Pull data from production to local development environment').argv(process.argv);
|
package/dist/bin/vip-validate.js
CHANGED
|
@@ -13,7 +13,7 @@ var _command = _interopRequireDefault(require("../lib/cli/command"));
|
|
|
13
13
|
var _tracker = require("../lib/tracker");
|
|
14
14
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
15
15
|
(0, _command.default)({
|
|
16
|
-
requiredArgs:
|
|
16
|
+
requiredArgs: 0
|
|
17
17
|
}).command('preflight', 'Runs preflight tests to validate if your application is ready to be deployed').argv(process.argv, async () => {
|
|
18
18
|
await (0, _tracker.trackEvent)('vip_validate_command_execute');
|
|
19
19
|
});
|
|
@@ -16,6 +16,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
16
16
|
exports.DevEnvSyncSQLCommand = void 0;
|
|
17
17
|
var _fs = _interopRequireDefault(require("fs"));
|
|
18
18
|
var _chalk = _interopRequireDefault(require("chalk"));
|
|
19
|
+
var _url = _interopRequireDefault(require("url"));
|
|
19
20
|
var _vipSearchReplace = require("@automattic/vip-search-replace");
|
|
20
21
|
var _clientFileUploader = require("../lib/client-file-uploader");
|
|
21
22
|
var _exportSql = require("./export-sql");
|
|
@@ -39,8 +40,8 @@ function findSiteHomeUrl(sql) {
|
|
|
39
40
|
const regex = "'(siteurl|home)',\\s?'(.*?)'";
|
|
40
41
|
const results = sql.match(regex);
|
|
41
42
|
if (results) {
|
|
42
|
-
const
|
|
43
|
-
return
|
|
43
|
+
const url = results[2];
|
|
44
|
+
return _url.default.parse(url).hostname;
|
|
44
45
|
}
|
|
45
46
|
return null;
|
|
46
47
|
}
|
|
@@ -55,15 +56,15 @@ function findSiteHomeUrl(sql) {
|
|
|
55
56
|
async function extractSiteUrls(sqlFile) {
|
|
56
57
|
const readInterface = await (0, _lineByLine.getReadInterface)(sqlFile);
|
|
57
58
|
return new Promise((resolve, reject) => {
|
|
58
|
-
const domains =
|
|
59
|
+
const domains = new Set();
|
|
59
60
|
readInterface.on('line', line => {
|
|
60
61
|
const domain = findSiteHomeUrl(line);
|
|
61
62
|
if (domain) {
|
|
62
|
-
domains.
|
|
63
|
+
domains.add('//' + domain);
|
|
63
64
|
}
|
|
64
65
|
});
|
|
65
66
|
readInterface.on('close', () => {
|
|
66
|
-
resolve(domains);
|
|
67
|
+
resolve(Array.from(domains));
|
|
67
68
|
});
|
|
68
69
|
readInterface.on('error', reject);
|
|
69
70
|
});
|
|
@@ -72,18 +73,20 @@ class DevEnvSyncSQLCommand {
|
|
|
72
73
|
/**
|
|
73
74
|
* Creates a new instance of the command
|
|
74
75
|
*
|
|
75
|
-
* @param {string}
|
|
76
|
-
* @param {string}
|
|
77
|
-
* @param {string}
|
|
76
|
+
* @param {string} app The app object
|
|
77
|
+
* @param {string} env The environment object
|
|
78
|
+
* @param {string} slug The site slug
|
|
79
|
+
* @param {Function} trackerFn Function to call for tracking
|
|
78
80
|
*/
|
|
79
|
-
constructor(app, env, slug) {
|
|
81
|
+
constructor(app, env, slug, trackerFn = () => {}) {
|
|
80
82
|
this.app = app;
|
|
81
83
|
this.env = env;
|
|
82
84
|
this.slug = slug;
|
|
85
|
+
this.track = trackerFn;
|
|
83
86
|
this.tmpDir = (0, _utils.makeTempDir)();
|
|
84
87
|
}
|
|
85
88
|
get landoDomain() {
|
|
86
|
-
return
|
|
89
|
+
return `//${this.slug}.vipdev.lndo.site`;
|
|
87
90
|
}
|
|
88
91
|
get sqlFile() {
|
|
89
92
|
return `${this.tmpDir}/sql-export.sql`;
|
|
@@ -99,7 +102,7 @@ class DevEnvSyncSQLCommand {
|
|
|
99
102
|
* @return {Promise<void>} Promise that resolves when the export is complete
|
|
100
103
|
*/
|
|
101
104
|
async generateExport() {
|
|
102
|
-
const exportCommand = new _exportSql.ExportSQLCommand(this.app, this.env, this.gzFile);
|
|
105
|
+
const exportCommand = new _exportSql.ExportSQLCommand(this.app, this.env, this.gzFile, this.track);
|
|
103
106
|
await exportCommand.run();
|
|
104
107
|
}
|
|
105
108
|
|
|
@@ -114,9 +117,13 @@ class DevEnvSyncSQLCommand {
|
|
|
114
117
|
const replacements = this.siteUrls.reduce((acc, url) => [...acc, url, this.landoDomain], []);
|
|
115
118
|
const readStream = _fs.default.createReadStream(this.sqlFile);
|
|
116
119
|
const replacedStream = await (0, _vipSearchReplace.replace)(readStream, replacements);
|
|
117
|
-
|
|
120
|
+
const outputFile = `${this.tmpDir}/sql-export-sr.sql`;
|
|
121
|
+
replacedStream.pipe(_fs.default.createWriteStream(outputFile));
|
|
118
122
|
return new Promise((resolve, reject) => {
|
|
119
|
-
replacedStream.on('finish',
|
|
123
|
+
replacedStream.on('finish', () => {
|
|
124
|
+
_fs.default.renameSync(outputFile, this.sqlFile);
|
|
125
|
+
resolve();
|
|
126
|
+
});
|
|
120
127
|
replacedStream.on('error', reject);
|
|
121
128
|
});
|
|
122
129
|
}
|
|
@@ -129,11 +136,10 @@ class DevEnvSyncSQLCommand {
|
|
|
129
136
|
*/
|
|
130
137
|
async runImport() {
|
|
131
138
|
const importOptions = {
|
|
132
|
-
slug: this.slug,
|
|
133
139
|
inPlace: true,
|
|
134
140
|
skipValidate: true
|
|
135
141
|
};
|
|
136
|
-
const importCommand = new _devEnvImportSql.DevEnvImportSQLCommand(this.sqlFile, importOptions);
|
|
142
|
+
const importCommand = new _devEnvImportSql.DevEnvImportSQLCommand(this.sqlFile, importOptions, this.slug);
|
|
137
143
|
await importCommand.run(true);
|
|
138
144
|
}
|
|
139
145
|
|
|
@@ -154,6 +160,9 @@ class DevEnvSyncSQLCommand {
|
|
|
154
160
|
await (0, _clientFileUploader.unzipFile)(this.gzFile, this.sqlFile);
|
|
155
161
|
console.log(`${_chalk.default.green('✓')} Extracted to ${this.sqlFile}`);
|
|
156
162
|
} catch (err) {
|
|
163
|
+
await this.track('archive_extraction_error', {
|
|
164
|
+
errorMessage: err === null || err === void 0 ? void 0 : err.message
|
|
165
|
+
});
|
|
157
166
|
exit.withError(`Error extracting the SQL export: ${err === null || err === void 0 ? void 0 : err.message}`);
|
|
158
167
|
}
|
|
159
168
|
try {
|
|
@@ -170,6 +179,9 @@ class DevEnvSyncSQLCommand {
|
|
|
170
179
|
await this.runSearchReplace();
|
|
171
180
|
console.log(`${_chalk.default.green('✓')} Search-replace operation is complete`);
|
|
172
181
|
} catch (err) {
|
|
182
|
+
await this.track('search_replace_error', {
|
|
183
|
+
errorMessage: err === null || err === void 0 ? void 0 : err.message
|
|
184
|
+
});
|
|
173
185
|
exit.withError(`Error replacing domains: ${err === null || err === void 0 ? void 0 : err.message}`);
|
|
174
186
|
}
|
|
175
187
|
try {
|
|
@@ -177,6 +189,9 @@ class DevEnvSyncSQLCommand {
|
|
|
177
189
|
await this.runImport();
|
|
178
190
|
console.log(`${_chalk.default.green('✓')} SQL file imported`);
|
|
179
191
|
} catch (err) {
|
|
192
|
+
await this.track('import_error', {
|
|
193
|
+
errorMessage: err === null || err === void 0 ? void 0 : err.message
|
|
194
|
+
});
|
|
180
195
|
exit.withError(`Error importing SQL file: ${err === null || err === void 0 ? void 0 : err.message}`);
|
|
181
196
|
}
|
|
182
197
|
}
|
|
@@ -8,7 +8,7 @@ var _graphqlTag = _interopRequireDefault(require("graphql-tag"));
|
|
|
8
8
|
var _fs = _interopRequireDefault(require("fs"));
|
|
9
9
|
var _https = _interopRequireDefault(require("https"));
|
|
10
10
|
var _path = _interopRequireDefault(require("path"));
|
|
11
|
-
var _api =
|
|
11
|
+
var _api = _interopRequireWildcard(require("../lib/api"));
|
|
12
12
|
var _format = require("../lib/cli/format");
|
|
13
13
|
var _progress = require("../lib/cli/progress");
|
|
14
14
|
var exit = _interopRequireWildcard(require("../lib/cli/exit"));
|
|
@@ -162,8 +162,10 @@ async function generateDownloadLink(appId, envId, backupId) {
|
|
|
162
162
|
* @throws {Error} Throws an error if the job creation fails
|
|
163
163
|
*/
|
|
164
164
|
async function createExportJob(appId, envId, backupId) {
|
|
165
|
+
// Disable global error handling so that we can handle errors ourselves
|
|
166
|
+
(0, _api.disableGlobalGraphQLErrorHandling)();
|
|
165
167
|
const api = await (0, _api.default)();
|
|
166
|
-
|
|
168
|
+
await api.mutate({
|
|
167
169
|
mutation: CREATE_EXPORT_JOB_MUTATION,
|
|
168
170
|
variables: {
|
|
169
171
|
input: {
|
|
@@ -173,16 +175,9 @@ async function createExportJob(appId, envId, backupId) {
|
|
|
173
175
|
}
|
|
174
176
|
}
|
|
175
177
|
});
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
success
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
} = response;
|
|
183
|
-
if (!success) {
|
|
184
|
-
throw new Error();
|
|
185
|
-
}
|
|
178
|
+
|
|
179
|
+
// Re-enable global error handling
|
|
180
|
+
(0, _api.enableGlobalGraphQLErrorHandling)();
|
|
186
181
|
}
|
|
187
182
|
|
|
188
183
|
/**
|
|
@@ -195,15 +190,15 @@ class ExportSQLCommand {
|
|
|
195
190
|
DOWNLOAD_LINK: 'downloadLink',
|
|
196
191
|
DOWNLOAD: 'download'
|
|
197
192
|
};
|
|
198
|
-
|
|
199
193
|
/**
|
|
200
194
|
* Creates an instance of SQLExportCommand
|
|
201
195
|
*
|
|
202
|
-
* @param {any}
|
|
203
|
-
* @param {any}
|
|
204
|
-
* @param {string}
|
|
196
|
+
* @param {any} app The application object
|
|
197
|
+
* @param {any} env The environment object
|
|
198
|
+
* @param {string} outputFile The output file path
|
|
199
|
+
* @param {Function} trackerFn The progress tracker function
|
|
205
200
|
*/
|
|
206
|
-
constructor(app, env, outputFile) {
|
|
201
|
+
constructor(app, env, outputFile, trackerFn = () => {}) {
|
|
207
202
|
this.app = app;
|
|
208
203
|
this.env = env;
|
|
209
204
|
this.outputFile = outputFile;
|
|
@@ -220,6 +215,7 @@ class ExportSQLCommand {
|
|
|
220
215
|
id: this.steps.DOWNLOAD,
|
|
221
216
|
name: 'Downloading file'
|
|
222
217
|
}]);
|
|
218
|
+
this.track = trackerFn;
|
|
223
219
|
}
|
|
224
220
|
|
|
225
221
|
/**
|
|
@@ -319,21 +315,29 @@ class ExportSQLCommand {
|
|
|
319
315
|
latestBackup
|
|
320
316
|
} = await fetchLatestBackupAndJobStatus(this.app.id, this.env.id);
|
|
321
317
|
if (!latestBackup) {
|
|
318
|
+
await this.track('no_backup_found_error', {
|
|
319
|
+
errorMessage: 'No backup found for the site'
|
|
320
|
+
});
|
|
322
321
|
exit.withError(`No backup found for site ${this.app.name}`);
|
|
323
322
|
} else {
|
|
324
323
|
console.log(`${(0, _format.getGlyphForStatus)('success')} Latest backup found with timestamp ${latestBackup.createdAt}`);
|
|
325
324
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
325
|
+
if (await this.getExportJob()) {
|
|
326
|
+
console.log(`Attaching to an existing export for the backup with timestamp ${latestBackup.createdAt}`);
|
|
327
|
+
} else {
|
|
329
328
|
console.log(`Creating a new export for the backup with timestamp ${latestBackup.createdAt}`);
|
|
330
329
|
try {
|
|
331
330
|
await createExportJob(this.app.id, this.env.id, latestBackup.id);
|
|
332
331
|
} catch (err) {
|
|
332
|
+
// Todo: match error code instead of message substring
|
|
333
|
+
if (err !== null && err !== void 0 && err.message.includes('Backup Copy already in progress')) {
|
|
334
|
+
await this.track('export_job_already_running_error', {
|
|
335
|
+
errorMessage: err === null || err === void 0 ? void 0 : err.message
|
|
336
|
+
});
|
|
337
|
+
exit.withError('There is an export job already running for this site: ' + `https://dashboard.wpvip.com/apps/${this.app.id}/${this.env.uniqueLabel}/data/database/backups\n` + 'Currently, we allow only one export job per site. Please try again later.');
|
|
338
|
+
}
|
|
333
339
|
exit.withError(`Error creating export job: ${err === null || err === void 0 ? void 0 : err.message}`);
|
|
334
340
|
}
|
|
335
|
-
} else {
|
|
336
|
-
console.log(`Attaching to an existing export for the backup with timestamp ${latestBackup.createdAt}`);
|
|
337
341
|
}
|
|
338
342
|
this.progressTracker.stepRunning(this.steps.PREPARE);
|
|
339
343
|
this.progressTracker.startPrinting();
|
|
@@ -353,6 +357,9 @@ class ExportSQLCommand {
|
|
|
353
357
|
} catch (err) {
|
|
354
358
|
this.progressTracker.stepFailed(this.steps.DOWNLOAD);
|
|
355
359
|
this.stopProgressTracker();
|
|
360
|
+
await this.track('download_failed_error', {
|
|
361
|
+
errorMessage: err === null || err === void 0 ? void 0 : err.message
|
|
362
|
+
});
|
|
356
363
|
exit.withError(`Error downloading exported file: ${err === null || err === void 0 ? void 0 : err.message}`);
|
|
357
364
|
}
|
|
358
365
|
}
|
|
@@ -125,7 +125,6 @@ async function landoRecovery(lando, instancePath, error) {
|
|
|
125
125
|
console.error(_chalk.default.green('Recovery successful, trying to initialize again...'));
|
|
126
126
|
try {
|
|
127
127
|
const app = lando.getApp(instancePath);
|
|
128
|
-
addHooks(app, lando);
|
|
129
128
|
await app.init();
|
|
130
129
|
return app;
|
|
131
130
|
} catch (initError) {
|
|
@@ -143,7 +142,6 @@ async function getLandoApplication(lando, instancePath) {
|
|
|
143
142
|
let app;
|
|
144
143
|
try {
|
|
145
144
|
app = lando.getApp(instancePath);
|
|
146
|
-
await addHooks(app, lando);
|
|
147
145
|
await app.init();
|
|
148
146
|
} catch (error) {
|
|
149
147
|
app = await landoRecovery(lando, instancePath, error);
|
|
@@ -153,6 +151,28 @@ async function getLandoApplication(lando, instancePath) {
|
|
|
153
151
|
}
|
|
154
152
|
async function bootstrapLando() {
|
|
155
153
|
const lando = new _lando.default(await getLandoConfig());
|
|
154
|
+
lando.events.once('pre-engine-build', async data => {
|
|
155
|
+
const instanceData = (0, _devEnvironmentCore.readEnvironmentData)(data.name);
|
|
156
|
+
let registryResolvable = false;
|
|
157
|
+
try {
|
|
158
|
+
registryResolvable = (await _dns.default.promises.lookup('ghcr.io')).address || false;
|
|
159
|
+
debug('Registry ghcr.io is resolvable');
|
|
160
|
+
} catch (err) {
|
|
161
|
+
debug('Registry ghcr.io is not resolvable, image pull might be broken.');
|
|
162
|
+
registryResolvable = false;
|
|
163
|
+
}
|
|
164
|
+
const pull = registryResolvable && (instanceData.pullAfter || 0) < Date.now();
|
|
165
|
+
if (Array.isArray(data.opts.pullable) && Array.isArray(data.opts.local) && data.opts.local.length === 0 && !pull) {
|
|
166
|
+
// Setting `data.opts.pullable` to an empty array prevents Lando from pulling images with `docker pull`.
|
|
167
|
+
// Note that if some of the images are not available, they will still be pulled by `docker-compose`.
|
|
168
|
+
data.opts.local = data.opts.pullable;
|
|
169
|
+
data.opts.pullable = [];
|
|
170
|
+
}
|
|
171
|
+
if (pull || !instanceData.pullAfter) {
|
|
172
|
+
instanceData.pullAfter = Date.now() + 7 * 24 * 60 * 60 * 1000;
|
|
173
|
+
(0, _devEnvironmentCore.writeEnvironmentData)(data.name, instanceData);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
156
176
|
await lando.bootstrap();
|
|
157
177
|
return lando;
|
|
158
178
|
}
|
|
@@ -178,85 +198,6 @@ async function landoRebuild(lando, instancePath) {
|
|
|
178
198
|
await ensureNoOrphantProxyContainer(lando);
|
|
179
199
|
await app.rebuild();
|
|
180
200
|
}
|
|
181
|
-
async function addHooks(app, lando) {
|
|
182
|
-
app.events.on('post-start', 1, () => healthcheckHook(app, lando));
|
|
183
|
-
lando.events.once('pre-engine-build', async data => {
|
|
184
|
-
const instanceData = (0, _devEnvironmentCore.readEnvironmentData)(app._name);
|
|
185
|
-
let registryResolvable = false;
|
|
186
|
-
try {
|
|
187
|
-
registryResolvable = (await _dns.default.promises.lookup('ghcr.io')).address || false;
|
|
188
|
-
debug('Registry ghcr.io is resolvable');
|
|
189
|
-
} catch (err) {
|
|
190
|
-
debug('Registry ghcr.io is not resolvable, image pull might be broken.');
|
|
191
|
-
registryResolvable = false;
|
|
192
|
-
}
|
|
193
|
-
const pull = registryResolvable && (instanceData.pullAfter || 0) < Date.now();
|
|
194
|
-
if (Array.isArray(data.opts.pullable) && Array.isArray(data.opts.local) && data.opts.local.length === 0 && !pull) {
|
|
195
|
-
// Settigs `data.opts.pullable` to an empty array prevents Lando from pulling images with `docker pull`.
|
|
196
|
-
// Note that if some of the images are not available, they will still be pulled by `docker-compose`.
|
|
197
|
-
data.opts.local = data.opts.pullable;
|
|
198
|
-
data.opts.pullable = [];
|
|
199
|
-
}
|
|
200
|
-
if (pull || !instanceData.pullAfter) {
|
|
201
|
-
instanceData.pullAfter = Date.now() + 7 * 24 * 60 * 60 * 1000;
|
|
202
|
-
(0, _devEnvironmentCore.writeEnvironmentData)(app._name, instanceData);
|
|
203
|
-
}
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
const healthChecks = {
|
|
207
|
-
database: 'mysql -uroot --silent --execute "SHOW DATABASES;"',
|
|
208
|
-
elasticsearch: "curl -s --noproxy '*' -XGET localhost:9200",
|
|
209
|
-
php: '[[ -f /wp/wp-includes/pomo/mo.php ]]'
|
|
210
|
-
};
|
|
211
|
-
async function healthcheckHook(app, lando) {
|
|
212
|
-
const now = new Date();
|
|
213
|
-
try {
|
|
214
|
-
await lando.Promise.retry(async () => {
|
|
215
|
-
const list = await lando.engine.list({
|
|
216
|
-
project: app.project
|
|
217
|
-
});
|
|
218
|
-
const notHealthyContainers = [];
|
|
219
|
-
const checkPromises = [];
|
|
220
|
-
const containerOrder = [];
|
|
221
|
-
for (const container of list) {
|
|
222
|
-
if (healthChecks[container.service]) {
|
|
223
|
-
debug(`Testing ${container.service}: ${healthChecks[container.service]}`);
|
|
224
|
-
containerOrder.push(container);
|
|
225
|
-
checkPromises.push(app.engine.run({
|
|
226
|
-
id: container.id,
|
|
227
|
-
cmd: healthChecks[container.service],
|
|
228
|
-
compose: app.compose,
|
|
229
|
-
project: app.project,
|
|
230
|
-
opts: {
|
|
231
|
-
silent: true,
|
|
232
|
-
noTTY: true,
|
|
233
|
-
cstdio: 'pipe',
|
|
234
|
-
services: [container.service]
|
|
235
|
-
}
|
|
236
|
-
}));
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
const results = await Promise.allSettled(checkPromises);
|
|
240
|
-
results.forEach((result, index) => {
|
|
241
|
-
if (result.status === 'rejected') {
|
|
242
|
-
debug(`${containerOrder[index].service} Health check failed`);
|
|
243
|
-
notHealthyContainers.push(containerOrder[index]);
|
|
244
|
-
}
|
|
245
|
-
});
|
|
246
|
-
if (notHealthyContainers.length) {
|
|
247
|
-
notHealthyContainers.forEach(container => console.log(`Waiting for service ${container.service} ...`));
|
|
248
|
-
return Promise.reject(notHealthyContainers);
|
|
249
|
-
}
|
|
250
|
-
}, {
|
|
251
|
-
max: 20,
|
|
252
|
-
backoff: 1000
|
|
253
|
-
});
|
|
254
|
-
} catch (containersWithFailingHealthCheck) {
|
|
255
|
-
containersWithFailingHealthCheck.forEach(container => console.log(_chalk.default.yellow('WARNING:') + ` Service ${container.service} failed healthcheck`));
|
|
256
|
-
}
|
|
257
|
-
const duration = new Date().getTime() - now.getTime();
|
|
258
|
-
debug(`Healthcheck completed in ${duration}ms`);
|
|
259
|
-
}
|
|
260
201
|
async function landoStop(lando, instancePath) {
|
|
261
202
|
debug('Will stop lando app on path:', instancePath);
|
|
262
203
|
const app = await getLandoApplication(lando, instancePath);
|
package/dist/lib/tracker.js
CHANGED
|
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.aliasUser = aliasUser;
|
|
7
|
+
exports.makeCommandTracker = makeCommandTracker;
|
|
7
8
|
exports.trackEvent = trackEvent;
|
|
8
9
|
exports.trackEventWithEnv = trackEventWithEnv;
|
|
9
10
|
var _index = _interopRequireDefault(require("./analytics/index"));
|
|
@@ -77,4 +78,13 @@ async function trackEventWithEnv(appId, envId, eventName, eventProps = {}) {
|
|
|
77
78
|
app_id: appId,
|
|
78
79
|
env_id: envId
|
|
79
80
|
});
|
|
81
|
+
}
|
|
82
|
+
function makeCommandTracker(command, trackingInfo = {}) {
|
|
83
|
+
const trackerFn = async (type, data = {}) => {
|
|
84
|
+
await trackEvent(`${command}_command_${type}`, {
|
|
85
|
+
...trackingInfo,
|
|
86
|
+
...data
|
|
87
|
+
});
|
|
88
|
+
};
|
|
89
|
+
return trackerFn;
|
|
80
90
|
}
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -72,6 +72,8 @@
|
|
|
72
72
|
"vip-dev-env-shell": "dist/bin/vip-dev-env-shell.js",
|
|
73
73
|
"vip-dev-env-start": "dist/bin/vip-dev-env-start.js",
|
|
74
74
|
"vip-dev-env-stop": "dist/bin/vip-dev-env-stop.js",
|
|
75
|
+
"vip-dev-env-sync": "dist/bin/vip-dev-env-sync.js",
|
|
76
|
+
"vip-dev-env-sync-sql": "dist/bin/vip-dev-env-sync-sql.js",
|
|
75
77
|
"vip-dev-env-update": "dist/bin/vip-dev-env-update.js",
|
|
76
78
|
"vip-import": "dist/bin/vip-import.js",
|
|
77
79
|
"vip-import-media": "dist/bin/vip-import-media.js",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automattic/vip",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.28.0-dev7",
|
|
4
4
|
"description": "The VIP Javascript library & CLI",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -33,6 +33,8 @@
|
|
|
33
33
|
"vip-dev-env-start": "dist/bin/vip-dev-env-start.js",
|
|
34
34
|
"vip-dev-env-stop": "dist/bin/vip-dev-env-stop.js",
|
|
35
35
|
"vip-dev-env-logs": "dist/bin/vip-dev-env-logs.js",
|
|
36
|
+
"vip-dev-env-sync": "dist/bin/vip-dev-env-sync.js",
|
|
37
|
+
"vip-dev-env-sync-sql": "dist/bin/vip-dev-env-sync-sql.js",
|
|
36
38
|
"vip-import": "dist/bin/vip-import.js",
|
|
37
39
|
"vip-import-media": "dist/bin/vip-import-media.js",
|
|
38
40
|
"vip-import-media-abort": "dist/bin/vip-import-media-abort.js",
|