@automattic/vip 2.28.0-dev7 → 2.28.1
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 +52 -0
- package/assets/dev-env.lando.template.yml.ejs +15 -3
- package/dist/bin/vip-dev-env-create.js +1 -0
- package/dist/bin/vip-dev-env-shell.js +2 -1
- package/dist/bin/vip-dev-env-start.js +4 -1
- package/dist/bin/vip-dev-env-update.js +11 -17
- package/dist/bin/vip-dev-env.js +1 -1
- package/dist/bin/vip-import-sql.js +11 -6
- package/dist/commands/dev-env-sync-sql.js +15 -30
- package/dist/commands/export-sql.js +22 -29
- package/dist/lib/dev-environment/dev-environment-cli.js +53 -4
- package/dist/lib/dev-environment/dev-environment-configuration-file.js +5 -2
- package/dist/lib/dev-environment/dev-environment-core.js +80 -5
- package/dist/lib/dev-environment/dev-environment-lando.js +188 -108
- package/dist/lib/dev-environment/docker-utils.js +114 -0
- package/dist/lib/keychain/browser.js +1 -0
- package/dist/lib/keychain/secure.js +3 -0
- package/dist/lib/keychain.js +1 -0
- package/dist/lib/site-import/status.js +2 -2
- package/dist/lib/tracker.js +0 -10
- package/dist/lib/validations/sql.js +5 -3
- package/dist/lib/vip-import-validate-files.js +4 -1
- package/npm-shrinkwrap.json +11462 -17508
- package/package.json +34 -21
- package/automattic-vip-2.28.0-dev7.tgz +0 -0
- package/dist/bin/vip-dev-env-sync-sql.js +0 -71
- package/dist/bin/vip-dev-env-sync.js +0 -21
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,57 @@
|
|
|
1
1
|
## Changelog
|
|
2
2
|
|
|
3
|
+
### 2.28.1
|
|
4
|
+
|
|
5
|
+
- #1123 [dev-env] Add VSCode workspace config on start
|
|
6
|
+
|
|
7
|
+
### 2.28.0
|
|
8
|
+
|
|
9
|
+
- #1343 fix(dev-env): Force image pulling after recovering Landofile
|
|
10
|
+
- #1342 fix(dev-env): Do not fail when lando_bridge_network does not exist
|
|
11
|
+
- #1329 feat(dev-env)!: Replace MailHog with Mailpit
|
|
12
|
+
- #1340 feat(dev-env): Kill lando proxy when last env stops
|
|
13
|
+
- #1324 feat(dev-env): Better detection of a Docker socket
|
|
14
|
+
- #1332 Update inline search-replace help for import sql command
|
|
15
|
+
- #1338 chore(dev-deps): Update @automattic/eslint-plugin-wpvip from 0.4.0 to 0.5.2
|
|
16
|
+
- #1337 chore(dev-deps): Update flow-bin from 0.203.1 to 0.204.0
|
|
17
|
+
- #1336 chore(dev-deps): Update eslint from 8.37.0 to 8.38.0
|
|
18
|
+
- #1325 tests: Fix timing out tests on Windows
|
|
19
|
+
- #1333 [dev-env] Readds xdebug_config to vip dev-env update
|
|
20
|
+
- #1328 feat(dev-env): Profile Lando-related functions
|
|
21
|
+
- #1326 tests(e2e): Force Jest to exit after all tests have completed running
|
|
22
|
+
- #1327 ci: Set `DO_NOT_TRACK=1` for E2E tests
|
|
23
|
+
- #1323 Revert "feat(dev-env): Better detection of a Docker socket"
|
|
24
|
+
- #1316 feat(dev-env): Better detection of a Docker socket
|
|
25
|
+
- #1321 chore(dev-deps): Update Babel-related packages
|
|
26
|
+
- #1320 chore(dev-deps): Update flow-bin from 0.202.1 to 0.203.1
|
|
27
|
+
- #1319 chore(dev-deps): Update eslint from 8.36.0 to 8.37.0
|
|
28
|
+
- #1318 chore(deps): Update lando to d75a4e8
|
|
29
|
+
- #1315 Fix preselected options on update
|
|
30
|
+
- #1314 chore(deps): Update socket.io-client to 4.6.1
|
|
31
|
+
- #1311 chore(dev-deps): Update eslint to 8.36.0
|
|
32
|
+
- #1310 chore(deps): Update ejs to 3.1.9
|
|
33
|
+
- #1312 chore(dev-deps): Update prettier to 2.8.7
|
|
34
|
+
- #1309 chore(dev-deps): Update flow-bin to 0.202.1
|
|
35
|
+
- #1308 chore(dev-deps): Update dockerode to 3.3.5
|
|
36
|
+
- #1307 chore(dev-deps): Update nock to 13.3.0
|
|
37
|
+
- #1306 chore(dev-deps): Forcefully update lodash for publish-please to 4.17.21
|
|
38
|
+
- #1305 chore(deps): Update Lando
|
|
39
|
+
- #1303 chore(deps): Replace socket.io-stream with @wearemothership/socket.io-stream
|
|
40
|
+
- #1301 chore(deps): Update lando-cli
|
|
41
|
+
- #1302 fix(ci): Do not prompt for WP update
|
|
42
|
+
- #1297 chore(dev-deps): Update Jest-related packages to 29.5.0
|
|
43
|
+
- #1299 chore(dev-deps): Update eslint-related stuff
|
|
44
|
+
- #1298 chore(dev-deps): Update flow-bin from 0.196.3 to 0.201.0
|
|
45
|
+
- #1293 chore(dev-deps): Update Babel-related packages
|
|
46
|
+
- #1300 chore(deps): Update Lando
|
|
47
|
+
- #1294 chore(dev-deps): Update Jest-related packages to 29.4.3
|
|
48
|
+
- #1296 Add trackers to capture execute, success and error events
|
|
49
|
+
- #1292 Fix requiredArgs for other vip commands
|
|
50
|
+
- #1290 Fail with a msg if an export job with a different backup is running
|
|
51
|
+
- #1254 refactor(dev-env): Remove healthcheck hook
|
|
52
|
+
- #1291 Dev-env: Fix silent failing when passing invalid subcommand
|
|
53
|
+
- #1282 Prefix urls with // to fix the search-replace problem
|
|
54
|
+
|
|
3
55
|
### 2.27.0
|
|
4
56
|
|
|
5
57
|
- #1287 fix(dev-env): Pull fresh images for new environments
|
|
@@ -9,6 +9,8 @@ proxy:
|
|
|
9
9
|
<% } %>
|
|
10
10
|
phpmyadmin:
|
|
11
11
|
- <%= siteSlug %>-pma.vipdev.lndo.site
|
|
12
|
+
mailpit:
|
|
13
|
+
- <%= siteSlug %>-mailpit.vipdev.lndo.site:8025
|
|
12
14
|
|
|
13
15
|
services:
|
|
14
16
|
devtools:
|
|
@@ -197,9 +199,19 @@ services:
|
|
|
197
199
|
clientcode_vipconfig: {}
|
|
198
200
|
<% } %>
|
|
199
201
|
|
|
200
|
-
<% if (
|
|
201
|
-
|
|
202
|
-
type:
|
|
202
|
+
<% if ( mailpit ) { %>
|
|
203
|
+
mailpit:
|
|
204
|
+
type: compose
|
|
205
|
+
services:
|
|
206
|
+
image: axllent/mailpit:latest
|
|
207
|
+
command: /mailpit
|
|
208
|
+
ports:
|
|
209
|
+
- ":1025"
|
|
210
|
+
- ":8025"
|
|
211
|
+
environment:
|
|
212
|
+
LANDO_NO_USER_PERMS: 1
|
|
213
|
+
LANDO_NO_SCRIPTS: 1
|
|
214
|
+
LANDO_NEEDS_EXEC: 1
|
|
203
215
|
<% } %>
|
|
204
216
|
|
|
205
217
|
tooling:
|
|
@@ -62,6 +62,7 @@ cmd.argv(process.argv, async (arg, opt) => {
|
|
|
62
62
|
const lando = await (0, _devEnvironmentLando.bootstrapLando)();
|
|
63
63
|
await (0, _devEnvironmentCli.validateDependencies)(lando, slug);
|
|
64
64
|
debug('Args: ', arg, 'Options: ', opt);
|
|
65
|
+
(0, _devEnvironmentCli.handleDeprecatedOptions)(opt);
|
|
65
66
|
const trackingInfo = {
|
|
66
67
|
slug,
|
|
67
68
|
app: opt.app,
|
|
@@ -28,7 +28,8 @@ const userMap = {
|
|
|
28
28
|
'demo-app-code': 'www-data',
|
|
29
29
|
elasticsearch: 'elasticsearch',
|
|
30
30
|
phpmyadmin: 'www-data',
|
|
31
|
-
mailhog: 'mailhog'
|
|
31
|
+
mailhog: 'mailhog',
|
|
32
|
+
mailpit: 'root'
|
|
32
33
|
};
|
|
33
34
|
const examples = [{
|
|
34
35
|
usage: `${_devEnvironment.DEV_ENVIRONMENT_FULL_COMMAND} shell`,
|
|
@@ -31,7 +31,7 @@ const examples = [{
|
|
|
31
31
|
usage: `${_devEnvironment.DEV_ENVIRONMENT_FULL_COMMAND} start`,
|
|
32
32
|
description: 'Starts a local dev environment'
|
|
33
33
|
}];
|
|
34
|
-
(0, _command.default)().option('slug', 'Custom name of the dev environment').option('skip-rebuild', 'Only start stopped services').option(['w', 'skip-wp-versions-check'], 'Skip
|
|
34
|
+
(0, _command.default)().option('slug', 'Custom name of the dev environment').option('skip-rebuild', 'Only start stopped services').option(['w', 'skip-wp-versions-check'], 'Skip propting for wordpress update if non latest').option('vscode', 'Open environment workspace in VSCode').examples(examples).argv(process.argv, async (arg, opt) => {
|
|
35
35
|
const slug = await (0, _devEnvironmentCli.getEnvironmentName)(opt);
|
|
36
36
|
const lando = await (0, _devEnvironmentLando.bootstrapLando)();
|
|
37
37
|
await (0, _devEnvironmentCli.validateDependencies)(lando, slug);
|
|
@@ -69,4 +69,7 @@ const examples = [{
|
|
|
69
69
|
await (0, _devEnvironmentCli.handleCLIException)(error, 'dev_env_start_command_error', trackingInfo);
|
|
70
70
|
process.exitCode = 1;
|
|
71
71
|
}
|
|
72
|
+
await (0, _devEnvironmentCli.postStart)(slug, {
|
|
73
|
+
openVSCode: !!opt.vscode
|
|
74
|
+
});
|
|
72
75
|
});
|
|
@@ -33,33 +33,27 @@ const cmd = (0, _command.default)().option('slug', 'Custom name of the dev envir
|
|
|
33
33
|
cmd.examples(examples);
|
|
34
34
|
cmd.argv(process.argv, async (arg, opt) => {
|
|
35
35
|
const slug = await (0, _devEnvironmentCli.getEnvironmentName)(opt);
|
|
36
|
+
(0, _devEnvironmentCli.handleDeprecatedOptions)(opt);
|
|
36
37
|
const lando = await (0, _devEnvironmentLando.bootstrapLando)();
|
|
37
38
|
await (0, _devEnvironmentCli.validateDependencies)(lando, slug);
|
|
38
39
|
const trackingInfo = (0, _devEnvironmentCli.getEnvTrackingInfo)(slug);
|
|
39
40
|
await (0, _tracker.trackEvent)('dev_env_update_command_execute', trackingInfo);
|
|
40
41
|
try {
|
|
42
|
+
var _currentInstanceData$;
|
|
41
43
|
const environmentAlreadyExists = await (0, _devEnvironmentCore.doesEnvironmentExist)((0, _devEnvironmentCore.getEnvironmentPath)(slug));
|
|
42
44
|
if (!environmentAlreadyExists) {
|
|
43
45
|
throw new Error(_devEnvironment.DEV_ENVIRONMENT_NOT_FOUND);
|
|
44
46
|
}
|
|
45
47
|
const currentInstanceData = (0, _devEnvironmentCore.readEnvironmentData)(slug);
|
|
46
48
|
debug('Read instance data', currentInstanceData);
|
|
47
|
-
const
|
|
48
|
-
let preselectedOptions = Object.assign({}, opt);
|
|
49
|
-
if (Object.keys(configurationFileOptions).length > 0) {
|
|
50
|
-
preselectedOptions = (0, _devEnvironmentConfigurationFile.mergeConfigurationFileOptions)(opt, configurationFileOptions);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Title and multisite can't be changed during update
|
|
54
|
-
const selectedOptions = {
|
|
49
|
+
const preselectedOptions = {
|
|
55
50
|
title: currentInstanceData.wpTitle,
|
|
56
|
-
multisite: currentInstanceData.multisite
|
|
51
|
+
multisite: currentInstanceData.multisite,
|
|
52
|
+
...opt
|
|
57
53
|
};
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
});
|
|
54
|
+
const configurationFileOptions = await (0, _devEnvironmentConfigurationFile.getConfigurationFileOptions)();
|
|
55
|
+
const thereAreOptionsFromConfigFile = Object.keys(configurationFileOptions).length > 0;
|
|
56
|
+
const finalPreselectedOptions = (0, _devEnvironmentConfigurationFile.mergeConfigurationFileOptions)(preselectedOptions, configurationFileOptions);
|
|
63
57
|
const defaultOptions = {
|
|
64
58
|
appCode: currentInstanceData.appCode.dir || currentInstanceData.appCode.tag || 'latest',
|
|
65
59
|
muPlugins: currentInstanceData.muPlugins.dir || currentInstanceData.muPlugins.tag || 'latest',
|
|
@@ -69,7 +63,7 @@ cmd.argv(process.argv, async (arg, opt) => {
|
|
|
69
63
|
mariadb: currentInstanceData.mariadb,
|
|
70
64
|
phpmyadmin: currentInstanceData.phpmyadmin,
|
|
71
65
|
xdebug: currentInstanceData.xdebug,
|
|
72
|
-
|
|
66
|
+
mailpit: (_currentInstanceData$ = currentInstanceData.mailpit) !== null && _currentInstanceData$ !== void 0 ? _currentInstanceData$ : currentInstanceData.mailhog,
|
|
73
67
|
mediaRedirectDomain: currentInstanceData.mediaRedirectDomain,
|
|
74
68
|
multisite: false,
|
|
75
69
|
title: ''
|
|
@@ -77,8 +71,8 @@ cmd.argv(process.argv, async (arg, opt) => {
|
|
|
77
71
|
const providedOptions = Object.keys(opt).filter(option => option.length > 1) // Filter out single letter aliases
|
|
78
72
|
.filter(option => !['debug', 'help', 'slug'].includes(option)); // Filter out options that are not related to instance configuration
|
|
79
73
|
|
|
80
|
-
const suppressPrompts = providedOptions.length > 0 ||
|
|
81
|
-
const instanceData = await (0, _devEnvironmentCli.promptForArguments)(
|
|
74
|
+
const suppressPrompts = providedOptions.length > 0 || thereAreOptionsFromConfigFile;
|
|
75
|
+
const instanceData = await (0, _devEnvironmentCli.promptForArguments)(finalPreselectedOptions, defaultOptions, suppressPrompts);
|
|
82
76
|
instanceData.siteSlug = slug;
|
|
83
77
|
await (0, _devEnvironmentCore.updateEnvironment)(instanceData);
|
|
84
78
|
const message = '\n' + _chalk.default.green('✓') + ' environment updated. Restart environment for changes to take an affect.';
|
package/dist/bin/vip-dev-env.js
CHANGED
|
@@ -18,4 +18,4 @@ 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
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').
|
|
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);
|
|
@@ -168,22 +168,27 @@ async function gates(app, env, fileName) {
|
|
|
168
168
|
const examples = [
|
|
169
169
|
// `sql` subcommand
|
|
170
170
|
{
|
|
171
|
-
usage: 'vip import sql @mysite.develop
|
|
171
|
+
usage: 'vip import sql @mysite.develop file.sql',
|
|
172
172
|
description: 'Import the given SQL file to your site'
|
|
173
173
|
},
|
|
174
174
|
// `search-replace` flag
|
|
175
175
|
{
|
|
176
|
-
usage: 'vip import sql @mysite.develop
|
|
176
|
+
usage: 'vip import sql @mysite.develop file.sql --search-replace="https://from.example.com,https://to.example.com"',
|
|
177
177
|
description: 'Perform a Search and Replace, then import the replaced file to your site.\n' + ' * Ensure there are no spaces between your search-replace parameters'
|
|
178
178
|
},
|
|
179
|
+
// `search-replace` flag
|
|
180
|
+
{
|
|
181
|
+
usage: 'vip import sql @mysite.develop file.sql --search-replace="https://from.example.com,https://to.example.com" --search-replace="example.com/from,example.com/to"',
|
|
182
|
+
description: 'Perform multiple search and replace tasks, then import the updated file to your site.'
|
|
183
|
+
},
|
|
179
184
|
// `in-place` flag
|
|
180
185
|
{
|
|
181
|
-
usage: 'vip import sql @mysite.develop
|
|
182
|
-
description: 'Search and Replace on the input
|
|
186
|
+
usage: 'vip import sql @mysite.develop file.sql --search-replace="https://from.example.com,https://to.example.com" --in-place',
|
|
187
|
+
description: 'Search and Replace on the input `file.sql`, then import the updated file to your site'
|
|
183
188
|
},
|
|
184
189
|
// `output` flag
|
|
185
190
|
{
|
|
186
|
-
usage: 'vip import sql @mysite.develop
|
|
191
|
+
usage: 'vip import sql @mysite.develop file.sql --search-replace="https://from.example.com,https://to.example.com" --output="output.sql"',
|
|
187
192
|
description: 'Output the performed Search and Replace to the specified output file, then import the replaced file to your site\n' + ' * Has no effect when the `in-place` flag is used'
|
|
188
193
|
},
|
|
189
194
|
// `sql status` subcommand
|
|
@@ -319,7 +324,7 @@ const displayPlaybook = ({
|
|
|
319
324
|
envContext: true,
|
|
320
325
|
requiredArgs: 1,
|
|
321
326
|
module: 'import-sql'
|
|
322
|
-
}).command('status', 'Check the status of the current running import').option('skip-validate', 'Do not perform pre-upload file validation. If unsupported entries are present, the import is likely to fail').option('search-replace', '
|
|
327
|
+
}).command('status', 'Check the status of the current running import').option('skip-validate', 'Do not perform pre-upload file validation. If unsupported entries are present, the import is likely to fail').option('search-replace', 'Search for a given URL in the SQL file and replace it with another. The format for the value is `<from-url>,<to-url>` (e.g. --search-replace="https://from.com,https://to.com"').option('in-place', 'Search and Replace explicitly on the given input file').option('output', 'Specify the replacement output file for Search and Replace', 'process.stdout').examples(examples).argv(process.argv, async (arg, opts) => {
|
|
323
328
|
var _env$primaryDomain;
|
|
324
329
|
const {
|
|
325
330
|
app,
|
|
@@ -16,7 +16,6 @@ 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"));
|
|
20
19
|
var _vipSearchReplace = require("@automattic/vip-search-replace");
|
|
21
20
|
var _clientFileUploader = require("../lib/client-file-uploader");
|
|
22
21
|
var _exportSql = require("./export-sql");
|
|
@@ -40,8 +39,8 @@ function findSiteHomeUrl(sql) {
|
|
|
40
39
|
const regex = "'(siteurl|home)',\\s?'(.*?)'";
|
|
41
40
|
const results = sql.match(regex);
|
|
42
41
|
if (results) {
|
|
43
|
-
const
|
|
44
|
-
return
|
|
42
|
+
const domain = results[2].replace(/https?:\/\//, '');
|
|
43
|
+
return domain;
|
|
45
44
|
}
|
|
46
45
|
return null;
|
|
47
46
|
}
|
|
@@ -56,15 +55,15 @@ function findSiteHomeUrl(sql) {
|
|
|
56
55
|
async function extractSiteUrls(sqlFile) {
|
|
57
56
|
const readInterface = await (0, _lineByLine.getReadInterface)(sqlFile);
|
|
58
57
|
return new Promise((resolve, reject) => {
|
|
59
|
-
const domains =
|
|
58
|
+
const domains = [];
|
|
60
59
|
readInterface.on('line', line => {
|
|
61
60
|
const domain = findSiteHomeUrl(line);
|
|
62
61
|
if (domain) {
|
|
63
|
-
domains.
|
|
62
|
+
domains.push(domain);
|
|
64
63
|
}
|
|
65
64
|
});
|
|
66
65
|
readInterface.on('close', () => {
|
|
67
|
-
resolve(
|
|
66
|
+
resolve(domains);
|
|
68
67
|
});
|
|
69
68
|
readInterface.on('error', reject);
|
|
70
69
|
});
|
|
@@ -73,20 +72,18 @@ class DevEnvSyncSQLCommand {
|
|
|
73
72
|
/**
|
|
74
73
|
* Creates a new instance of the command
|
|
75
74
|
*
|
|
76
|
-
* @param {string}
|
|
77
|
-
* @param {string}
|
|
78
|
-
* @param {string}
|
|
79
|
-
* @param {Function} trackerFn Function to call for tracking
|
|
75
|
+
* @param {string} app The app object
|
|
76
|
+
* @param {string} env The environment object
|
|
77
|
+
* @param {string} slug The site slug
|
|
80
78
|
*/
|
|
81
|
-
constructor(app, env, slug
|
|
79
|
+
constructor(app, env, slug) {
|
|
82
80
|
this.app = app;
|
|
83
81
|
this.env = env;
|
|
84
82
|
this.slug = slug;
|
|
85
|
-
this.track = trackerFn;
|
|
86
83
|
this.tmpDir = (0, _utils.makeTempDir)();
|
|
87
84
|
}
|
|
88
85
|
get landoDomain() {
|
|
89
|
-
return
|
|
86
|
+
return `${this.slug}.vipdev.lndo.site`;
|
|
90
87
|
}
|
|
91
88
|
get sqlFile() {
|
|
92
89
|
return `${this.tmpDir}/sql-export.sql`;
|
|
@@ -102,7 +99,7 @@ class DevEnvSyncSQLCommand {
|
|
|
102
99
|
* @return {Promise<void>} Promise that resolves when the export is complete
|
|
103
100
|
*/
|
|
104
101
|
async generateExport() {
|
|
105
|
-
const exportCommand = new _exportSql.ExportSQLCommand(this.app, this.env, this.gzFile
|
|
102
|
+
const exportCommand = new _exportSql.ExportSQLCommand(this.app, this.env, this.gzFile);
|
|
106
103
|
await exportCommand.run();
|
|
107
104
|
}
|
|
108
105
|
|
|
@@ -117,13 +114,9 @@ class DevEnvSyncSQLCommand {
|
|
|
117
114
|
const replacements = this.siteUrls.reduce((acc, url) => [...acc, url, this.landoDomain], []);
|
|
118
115
|
const readStream = _fs.default.createReadStream(this.sqlFile);
|
|
119
116
|
const replacedStream = await (0, _vipSearchReplace.replace)(readStream, replacements);
|
|
120
|
-
|
|
121
|
-
replacedStream.pipe(_fs.default.createWriteStream(outputFile));
|
|
117
|
+
replacedStream.pipe(_fs.default.createWriteStream(this.sqlFile));
|
|
122
118
|
return new Promise((resolve, reject) => {
|
|
123
|
-
replacedStream.on('finish',
|
|
124
|
-
_fs.default.renameSync(outputFile, this.sqlFile);
|
|
125
|
-
resolve();
|
|
126
|
-
});
|
|
119
|
+
replacedStream.on('finish', resolve);
|
|
127
120
|
replacedStream.on('error', reject);
|
|
128
121
|
});
|
|
129
122
|
}
|
|
@@ -136,10 +129,11 @@ class DevEnvSyncSQLCommand {
|
|
|
136
129
|
*/
|
|
137
130
|
async runImport() {
|
|
138
131
|
const importOptions = {
|
|
132
|
+
slug: this.slug,
|
|
139
133
|
inPlace: true,
|
|
140
134
|
skipValidate: true
|
|
141
135
|
};
|
|
142
|
-
const importCommand = new _devEnvImportSql.DevEnvImportSQLCommand(this.sqlFile, importOptions
|
|
136
|
+
const importCommand = new _devEnvImportSql.DevEnvImportSQLCommand(this.sqlFile, importOptions);
|
|
143
137
|
await importCommand.run(true);
|
|
144
138
|
}
|
|
145
139
|
|
|
@@ -160,9 +154,6 @@ class DevEnvSyncSQLCommand {
|
|
|
160
154
|
await (0, _clientFileUploader.unzipFile)(this.gzFile, this.sqlFile);
|
|
161
155
|
console.log(`${_chalk.default.green('✓')} Extracted to ${this.sqlFile}`);
|
|
162
156
|
} catch (err) {
|
|
163
|
-
await this.track('archive_extraction_error', {
|
|
164
|
-
errorMessage: err === null || err === void 0 ? void 0 : err.message
|
|
165
|
-
});
|
|
166
157
|
exit.withError(`Error extracting the SQL export: ${err === null || err === void 0 ? void 0 : err.message}`);
|
|
167
158
|
}
|
|
168
159
|
try {
|
|
@@ -179,9 +170,6 @@ class DevEnvSyncSQLCommand {
|
|
|
179
170
|
await this.runSearchReplace();
|
|
180
171
|
console.log(`${_chalk.default.green('✓')} Search-replace operation is complete`);
|
|
181
172
|
} catch (err) {
|
|
182
|
-
await this.track('search_replace_error', {
|
|
183
|
-
errorMessage: err === null || err === void 0 ? void 0 : err.message
|
|
184
|
-
});
|
|
185
173
|
exit.withError(`Error replacing domains: ${err === null || err === void 0 ? void 0 : err.message}`);
|
|
186
174
|
}
|
|
187
175
|
try {
|
|
@@ -189,9 +177,6 @@ class DevEnvSyncSQLCommand {
|
|
|
189
177
|
await this.runImport();
|
|
190
178
|
console.log(`${_chalk.default.green('✓')} SQL file imported`);
|
|
191
179
|
} catch (err) {
|
|
192
|
-
await this.track('import_error', {
|
|
193
|
-
errorMessage: err === null || err === void 0 ? void 0 : err.message
|
|
194
|
-
});
|
|
195
180
|
exit.withError(`Error importing SQL file: ${err === null || err === void 0 ? void 0 : err.message}`);
|
|
196
181
|
}
|
|
197
182
|
}
|
|
@@ -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 = _interopRequireDefault(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,10 +162,8 @@ 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)();
|
|
167
165
|
const api = await (0, _api.default)();
|
|
168
|
-
await api.mutate({
|
|
166
|
+
const response = await api.mutate({
|
|
169
167
|
mutation: CREATE_EXPORT_JOB_MUTATION,
|
|
170
168
|
variables: {
|
|
171
169
|
input: {
|
|
@@ -175,9 +173,16 @@ async function createExportJob(appId, envId, backupId) {
|
|
|
175
173
|
}
|
|
176
174
|
}
|
|
177
175
|
});
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
176
|
+
const {
|
|
177
|
+
data: {
|
|
178
|
+
startDBBackupCopy: {
|
|
179
|
+
success
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
} = response;
|
|
183
|
+
if (!success) {
|
|
184
|
+
throw new Error();
|
|
185
|
+
}
|
|
181
186
|
}
|
|
182
187
|
|
|
183
188
|
/**
|
|
@@ -190,15 +195,15 @@ class ExportSQLCommand {
|
|
|
190
195
|
DOWNLOAD_LINK: 'downloadLink',
|
|
191
196
|
DOWNLOAD: 'download'
|
|
192
197
|
};
|
|
198
|
+
|
|
193
199
|
/**
|
|
194
200
|
* Creates an instance of SQLExportCommand
|
|
195
201
|
*
|
|
196
|
-
* @param {any}
|
|
197
|
-
* @param {any}
|
|
198
|
-
* @param {string}
|
|
199
|
-
* @param {Function} trackerFn The progress tracker function
|
|
202
|
+
* @param {any} app The application object
|
|
203
|
+
* @param {any} env The environment object
|
|
204
|
+
* @param {string} outputFile The output file path
|
|
200
205
|
*/
|
|
201
|
-
constructor(app, env, outputFile
|
|
206
|
+
constructor(app, env, outputFile) {
|
|
202
207
|
this.app = app;
|
|
203
208
|
this.env = env;
|
|
204
209
|
this.outputFile = outputFile;
|
|
@@ -215,7 +220,6 @@ class ExportSQLCommand {
|
|
|
215
220
|
id: this.steps.DOWNLOAD,
|
|
216
221
|
name: 'Downloading file'
|
|
217
222
|
}]);
|
|
218
|
-
this.track = trackerFn;
|
|
219
223
|
}
|
|
220
224
|
|
|
221
225
|
/**
|
|
@@ -315,29 +319,21 @@ class ExportSQLCommand {
|
|
|
315
319
|
latestBackup
|
|
316
320
|
} = await fetchLatestBackupAndJobStatus(this.app.id, this.env.id);
|
|
317
321
|
if (!latestBackup) {
|
|
318
|
-
await this.track('no_backup_found_error', {
|
|
319
|
-
errorMessage: 'No backup found for the site'
|
|
320
|
-
});
|
|
321
322
|
exit.withError(`No backup found for site ${this.app.name}`);
|
|
322
323
|
} else {
|
|
323
324
|
console.log(`${(0, _format.getGlyphForStatus)('success')} Latest backup found with timestamp ${latestBackup.createdAt}`);
|
|
324
325
|
}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
326
|
+
|
|
327
|
+
// See if there is an existing export job for the latest backup
|
|
328
|
+
if (!(await this.getExportJob())) {
|
|
328
329
|
console.log(`Creating a new export for the backup with timestamp ${latestBackup.createdAt}`);
|
|
329
330
|
try {
|
|
330
331
|
await createExportJob(this.app.id, this.env.id, latestBackup.id);
|
|
331
332
|
} 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
|
-
}
|
|
339
333
|
exit.withError(`Error creating export job: ${err === null || err === void 0 ? void 0 : err.message}`);
|
|
340
334
|
}
|
|
335
|
+
} else {
|
|
336
|
+
console.log(`Attaching to an existing export for the backup with timestamp ${latestBackup.createdAt}`);
|
|
341
337
|
}
|
|
342
338
|
this.progressTracker.stepRunning(this.steps.PREPARE);
|
|
343
339
|
this.progressTracker.startPrinting();
|
|
@@ -357,9 +353,6 @@ class ExportSQLCommand {
|
|
|
357
353
|
} catch (err) {
|
|
358
354
|
this.progressTracker.stepFailed(this.steps.DOWNLOAD);
|
|
359
355
|
this.stopProgressTracker();
|
|
360
|
-
await this.track('download_failed_error', {
|
|
361
|
-
errorMessage: err === null || err === void 0 ? void 0 : err.message
|
|
362
|
-
});
|
|
363
356
|
exit.withError(`Error downloading exported file: ${err === null || err === void 0 ? void 0 : err.message}`);
|
|
364
357
|
}
|
|
365
358
|
}
|
|
@@ -11,6 +11,8 @@ exports.getEnvironmentStartCommand = getEnvironmentStartCommand;
|
|
|
11
11
|
exports.getOptionsFromAppInfo = getOptionsFromAppInfo;
|
|
12
12
|
exports.getTagChoices = getTagChoices;
|
|
13
13
|
exports.handleCLIException = handleCLIException;
|
|
14
|
+
exports.handleDeprecatedOptions = handleDeprecatedOptions;
|
|
15
|
+
exports.postStart = postStart;
|
|
14
16
|
exports.printTable = printTable;
|
|
15
17
|
exports.processBooleanOption = processBooleanOption;
|
|
16
18
|
exports.processComponentOptionInput = processComponentOptionInput;
|
|
@@ -31,6 +33,8 @@ var _fs = _interopRequireDefault(require("fs"));
|
|
|
31
33
|
var _path = _interopRequireDefault(require("path"));
|
|
32
34
|
var _os = _interopRequireDefault(require("os"));
|
|
33
35
|
var _dns = _interopRequireDefault(require("dns"));
|
|
36
|
+
var _child_process = require("child_process");
|
|
37
|
+
var _shelljs = require("shelljs");
|
|
34
38
|
var _progress = require("../../lib/cli/progress");
|
|
35
39
|
var _tracker = require("../tracker");
|
|
36
40
|
var _devEnvironment = require("../constants/dev-environment");
|
|
@@ -77,6 +81,8 @@ const componentDemoNames = {
|
|
|
77
81
|
|
|
78
82
|
// Forward declaration to avoid no-use-before-define
|
|
79
83
|
|
|
84
|
+
// eslint-disable-next-line no-redeclare
|
|
85
|
+
|
|
80
86
|
async function handleCLIException(exception, trackKey, trackBaseInfo = {}) {
|
|
81
87
|
const errorPrefix = _chalk.default.red('Error:');
|
|
82
88
|
if (_devEnvironment.DEV_ENVIRONMENT_NOT_FOUND === exception.message) {
|
|
@@ -299,12 +305,12 @@ async function promptForArguments(preselectedOptions, defaultOptions, suppressPr
|
|
|
299
305
|
xdebug: false,
|
|
300
306
|
xdebugConfig: preselectedOptions.xdebugConfig,
|
|
301
307
|
siteSlug: '',
|
|
302
|
-
|
|
308
|
+
mailpit: false
|
|
303
309
|
};
|
|
304
310
|
const promptLabels = {
|
|
305
311
|
xdebug: 'XDebug',
|
|
306
312
|
phpmyadmin: 'phpMyAdmin',
|
|
307
|
-
|
|
313
|
+
mailpit: 'Mailpit'
|
|
308
314
|
};
|
|
309
315
|
if (!instanceData.mediaRedirectDomain && defaultOptions.mediaRedirectDomain) {
|
|
310
316
|
const mediaRedirectPromptText = `Would you like to redirect to ${defaultOptions.mediaRedirectDomain} for missing media files?`;
|
|
@@ -332,7 +338,7 @@ async function promptForArguments(preselectedOptions, defaultOptions, suppressPr
|
|
|
332
338
|
} else {
|
|
333
339
|
instanceData.elasticsearch = await promptForBoolean('Enable Elasticsearch (needed by Enterprise Search)?', !!defaultOptions.elasticsearch);
|
|
334
340
|
}
|
|
335
|
-
for (const service of ['phpmyadmin', 'xdebug', '
|
|
341
|
+
for (const service of ['phpmyadmin', 'xdebug', 'mailpit']) {
|
|
336
342
|
if (service in instanceData) {
|
|
337
343
|
if (service in preselectedOptions) {
|
|
338
344
|
instanceData[service] = preselectedOptions[service];
|
|
@@ -569,7 +575,7 @@ function processVersionOption(value) {
|
|
|
569
575
|
}
|
|
570
576
|
function addDevEnvConfigurationOptions(command) {
|
|
571
577
|
// We leave the third parameter to undefined on some because the defaults are handled in preProcessInstanceData()
|
|
572
|
-
return command.option('wordpress', 'Use a specific WordPress version', undefined, processVersionOption).option(['u', 'mu-plugins'], 'Use a specific mu-plugins changeset or local directory').option('app-code', 'Use the application code from a local directory or use "demo" for VIP skeleton code').option('phpmyadmin', 'Enable PHPMyAdmin component. By default it is disabled', undefined, processBooleanOption).option('xdebug', 'Enable XDebug. By default it is disabled', undefined, processBooleanOption).option('xdebug_config', 'Extra configuration to pass to xdebug via XDEBUG_CONFIG environment variable').option('elasticsearch', 'Enable Elasticsearch (needed by Enterprise Search)', undefined, processBooleanOption).option(['r', 'media-redirect-domain'], 'Domain to redirect for missing media files. This can be used to still have images without the need to import them locally.').option('php', 'Explicitly choose PHP version to use', undefined, processVersionOption).option(['
|
|
578
|
+
return command.option('wordpress', 'Use a specific WordPress version', undefined, processVersionOption).option(['u', 'mu-plugins'], 'Use a specific mu-plugins changeset or local directory').option('app-code', 'Use the application code from a local directory or use "demo" for VIP skeleton code').option('phpmyadmin', 'Enable PHPMyAdmin component. By default it is disabled', undefined, processBooleanOption).option('xdebug', 'Enable XDebug. By default it is disabled', undefined, processBooleanOption).option('xdebug_config', 'Extra configuration to pass to xdebug via XDEBUG_CONFIG environment variable').option('elasticsearch', 'Enable Elasticsearch (needed by Enterprise Search)', undefined, processBooleanOption).option(['r', 'media-redirect-domain'], 'Domain to redirect for missing media files. This can be used to still have images without the need to import them locally.').option('php', 'Explicitly choose PHP version to use', undefined, processVersionOption).option(['G', 'mailhog'], 'Enable Mailpit. By default it is disabled (deprecated option, please use --mailpit instead)', undefined, processBooleanOption).option(['A', 'mailpit'], 'Enable Mailpit. By default it is disabled', undefined, processBooleanOption);
|
|
573
579
|
}
|
|
574
580
|
|
|
575
581
|
/**
|
|
@@ -634,4 +640,47 @@ function getEnvTrackingInfo(slug) {
|
|
|
634
640
|
slug
|
|
635
641
|
};
|
|
636
642
|
}
|
|
643
|
+
}
|
|
644
|
+
async function postStart(slug, options) {
|
|
645
|
+
if (options.openVSCode) {
|
|
646
|
+
launchVSCode(slug);
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
const launchVSCode = slug => {
|
|
650
|
+
const workspacePath = (0, _devEnvironmentCore.getVSCodeWorkspacePath)(slug);
|
|
651
|
+
if (_fs.default.existsSync(workspacePath)) {
|
|
652
|
+
console.log('VSCode workspace already exists, skipping creation.');
|
|
653
|
+
} else {
|
|
654
|
+
(0, _devEnvironmentCore.generateVSCodeWorkspace)(slug);
|
|
655
|
+
console.log('VSCode workspace generated');
|
|
656
|
+
}
|
|
657
|
+
const vsCodeExecutable = getVSCodeExecutable();
|
|
658
|
+
if (vsCodeExecutable) {
|
|
659
|
+
(0, _child_process.spawn)(vsCodeExecutable, [workspacePath], {
|
|
660
|
+
shell: process.platform === 'win32'
|
|
661
|
+
});
|
|
662
|
+
} else {
|
|
663
|
+
console.log(`VSCode not detected in path, please open ${workspacePath} with VSCode`);
|
|
664
|
+
}
|
|
665
|
+
};
|
|
666
|
+
const getVSCodeExecutable = () => {
|
|
667
|
+
const candidates = ['code', 'code-insiders', 'codium'];
|
|
668
|
+
for (const candidate of candidates) {
|
|
669
|
+
const result = (0, _shelljs.which)(candidate);
|
|
670
|
+
if (result) {
|
|
671
|
+
debug(`Found ${candidate} in path`);
|
|
672
|
+
return candidate;
|
|
673
|
+
}
|
|
674
|
+
debug(`Could not find ${candidate} in path`);
|
|
675
|
+
}
|
|
676
|
+
return null;
|
|
677
|
+
};
|
|
678
|
+
function handleDeprecatedOptions(opts) {
|
|
679
|
+
if (opts.mailhog) {
|
|
680
|
+
console.warn(_chalk.default.yellow('Warning: --mailhog is deprecated and will be removed in a future release. Please use --mailpit instead.'));
|
|
681
|
+
if (opts.mailpit === undefined) {
|
|
682
|
+
opts.mailpit = opts.mailhog;
|
|
683
|
+
}
|
|
684
|
+
delete opts.mailhog;
|
|
685
|
+
}
|
|
637
686
|
}
|
|
@@ -63,6 +63,7 @@ async function getConfigurationFileOptions() {
|
|
|
63
63
|
return configuration;
|
|
64
64
|
}
|
|
65
65
|
async function sanitizeConfiguration(configuration) {
|
|
66
|
+
var _configuration$mailpi;
|
|
66
67
|
const genericConfigurationError = `Configuration file ${_chalk.default.grey(CONFIGURATION_FILE_NAME)} is available but ` + `couldn't be loaded. Ensure there is a ${_chalk.default.cyan('configuration-version')} and ${_chalk.default.cyan('slug')} ` + `configured. For example:\n\n${_chalk.default.grey(getConfigurationFileExample())}`;
|
|
67
68
|
if (Array.isArray(configuration) || typeof configuration !== 'object') {
|
|
68
69
|
throw new Error(genericConfigurationError);
|
|
@@ -91,7 +92,7 @@ async function sanitizeConfiguration(configuration) {
|
|
|
91
92
|
elasticsearch: stringToBooleanIfDefined(configuration.elasticsearch),
|
|
92
93
|
phpmyadmin: stringToBooleanIfDefined(configuration.phpmyadmin),
|
|
93
94
|
xdebug: stringToBooleanIfDefined(configuration.xdebug),
|
|
94
|
-
|
|
95
|
+
mailpit: stringToBooleanIfDefined((_configuration$mailpi = configuration.mailpit) !== null && _configuration$mailpi !== void 0 ? _configuration$mailpi : configuration.mailhog)
|
|
95
96
|
};
|
|
96
97
|
|
|
97
98
|
// Remove undefined values
|
|
@@ -99,6 +100,7 @@ async function sanitizeConfiguration(configuration) {
|
|
|
99
100
|
return sanitizedConfiguration;
|
|
100
101
|
}
|
|
101
102
|
function mergeConfigurationFileOptions(preselectedOptions, configurationFileOptions) {
|
|
103
|
+
var _configurationFileOpt;
|
|
102
104
|
// configurationFileOptions holds different parameters than present in
|
|
103
105
|
// preselectedOptions like "slug", and friendly-named parameters (e.g.
|
|
104
106
|
// 'app-code' vs 'appCode'). Selectively merge configurationFileOptions
|
|
@@ -113,7 +115,8 @@ function mergeConfigurationFileOptions(preselectedOptions, configurationFileOpti
|
|
|
113
115
|
elasticsearch: configurationFileOptions.elasticsearch,
|
|
114
116
|
phpmyadmin: configurationFileOptions.phpmyadmin,
|
|
115
117
|
xdebug: configurationFileOptions.xdebug,
|
|
116
|
-
|
|
118
|
+
xdebugConfig: configurationFileOptions['xdebug-config'],
|
|
119
|
+
mailpit: (_configurationFileOpt = configurationFileOptions.mailpit) !== null && _configurationFileOpt !== void 0 ? _configurationFileOpt : configurationFileOptions.mailhog
|
|
117
120
|
};
|
|
118
121
|
const mergedOptions = {};
|
|
119
122
|
Object.keys(configurationFileInstanceOptions).forEach(key => {
|