@automattic/vip 2.13.0 → 2.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -2
- package/assets/dev-env.lando.template.yml.ejs +0 -4
- package/dist/bin/vip-dev-env-exec.js +9 -2
- package/dist/bin/vip-dev-env-import-sql.js +1 -1
- package/dist/bin/vip-import-sql.js +6 -4
- package/dist/lib/constants/dev-environment.js +6 -7
- package/dist/lib/dev-environment/dev-environment-cli.js +3 -3
- package/dist/lib/dev-environment/dev-environment-core.js +3 -3
- package/dist/lib/dev-environment/dev-environment-lando.js +8 -5
- package/dist/lib/site-import/db-file-import.js +1 -1
- package/dist/lib/validations/is-multisite-domain-mapped.js +161 -0
- package/dist/lib/validations/line-by-line.js +3 -2
- package/dist/lib/validations/site-type.js +18 -1
- package/dist/lib/validations/sql.js +46 -6
- package/dist/lib/validations/utils.js +45 -0
- package/npm-shrinkwrap.json +6 -6
- package/package.json +3 -3
- package/.circleci/config.yml +0 -67
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ Then, launch the command and follow the prompts:
|
|
|
14
14
|
vip
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
If you need more information, check out our [VIP
|
|
17
|
+
If you need more information, check out our [VIP-CLI documentation](https://docs.wpvip.com/technical-references/vip-cli/).
|
|
18
18
|
|
|
19
19
|
## Contributing
|
|
20
20
|
|
|
@@ -26,6 +26,28 @@ By default, we record information about the usage of this tool using an in-house
|
|
|
26
26
|
|
|
27
27
|
## Changelog
|
|
28
28
|
|
|
29
|
+
### 2.15.0 (3 Aug 2022)
|
|
30
|
+
|
|
31
|
+
- #1067 FORNO-1244: SQL Import: Increase max import size for launched sites to 1GB
|
|
32
|
+
- #1064 FORNO-1254: SQL Import: Add multisite primary domain validation
|
|
33
|
+
- #1062 [dev-env] Change wizard wording
|
|
34
|
+
- #1065 [dev-env] Update default software versions for PHP and Elasticsearch
|
|
35
|
+
- #1063 [dev-env] Remove redundant healthchecks
|
|
36
|
+
- #1061 [dev-env] Fix duplicate shortcuts
|
|
37
|
+
|
|
38
|
+
### 2.14.0 (19 Jul 2022)
|
|
39
|
+
|
|
40
|
+
- #1059 Update engines to show support for npm > 6
|
|
41
|
+
- #1058 [dev-env] switch dev-env error during import to warning
|
|
42
|
+
- #1057 [dev-env] Update debug instruction example
|
|
43
|
+
- #1055 [dev-env] Makes exec attempt to run the task even if env seems to be down
|
|
44
|
+
|
|
45
|
+
### 2.13.1 (20 Jun 2022)
|
|
46
|
+
|
|
47
|
+
- #1052 [dev-env] Update/lando compose version
|
|
48
|
+
- #1045 README: Fix Typo `VIP CLI` => `VIP-CLI`
|
|
49
|
+
- #1048 Switch to GitHub Actions
|
|
50
|
+
|
|
29
51
|
### 2.13.0 (16 Jun 2022)
|
|
30
52
|
|
|
31
53
|
- #1046 Add Cache Purge Command
|
|
@@ -223,7 +245,7 @@ Fixes:
|
|
|
223
245
|
- #844 Expose DB and expose extra services in info table
|
|
224
246
|
- #865 spawn WP-CLI as root to allow for FS operations
|
|
225
247
|
- #895 Fix rmdir deprecation warning
|
|
226
|
-
- #870 Add the VIP
|
|
248
|
+
- #870 Add the VIP-CLI release process and release schedule
|
|
227
249
|
|
|
228
250
|
Dependencies updates:
|
|
229
251
|
|
|
@@ -68,8 +68,6 @@ services:
|
|
|
68
68
|
command: docker-entrypoint.sh mysqld
|
|
69
69
|
ports:
|
|
70
70
|
- ":3306"
|
|
71
|
-
healthcheck:
|
|
72
|
-
test: 'mysql -uroot --silent --execute "SHOW DATABASES;"'
|
|
73
71
|
environment:
|
|
74
72
|
MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: 'true'
|
|
75
73
|
volumes:
|
|
@@ -106,8 +104,6 @@ services:
|
|
|
106
104
|
discovery.type: 'single-node'
|
|
107
105
|
ports:
|
|
108
106
|
- ":9200"
|
|
109
|
-
healthcheck:
|
|
110
|
-
test: "curl --noproxy '*' -XGET localhost:9200"
|
|
111
107
|
volumes:
|
|
112
108
|
- search_data:/usr/share/elasticsearch/data
|
|
113
109
|
volumes:
|
|
@@ -38,7 +38,11 @@ const examples = [{
|
|
|
38
38
|
}];
|
|
39
39
|
(0, _command.default)({
|
|
40
40
|
wildcardCommand: true
|
|
41
|
-
}).option('slug', 'Custom name of the dev environment').
|
|
41
|
+
}).option('slug', 'Custom name of the dev environment').option('force', 'Disabling validations before task execution', undefined, value => {
|
|
42
|
+
var _value$toLowerCase;
|
|
43
|
+
|
|
44
|
+
return 'false' !== (value === null || value === void 0 ? void 0 : (_value$toLowerCase = value.toLowerCase) === null || _value$toLowerCase === void 0 ? void 0 : _value$toLowerCase.call(value));
|
|
45
|
+
}).examples(examples).argv(process.argv, async (unmatchedArgs, opt) => {
|
|
42
46
|
await (0, _devEnvironmentCli.validateDependencies)();
|
|
43
47
|
const slug = (0, _devEnvironmentCli.getEnvironmentName)(opt);
|
|
44
48
|
const trackingInfo = (0, _devEnvironmentCli.getEnvTrackingInfo)(slug);
|
|
@@ -59,7 +63,10 @@ const examples = [{
|
|
|
59
63
|
arg = process.argv.slice(argSplitterIx + 1);
|
|
60
64
|
}
|
|
61
65
|
|
|
62
|
-
|
|
66
|
+
const options = {
|
|
67
|
+
force: opt.force
|
|
68
|
+
};
|
|
69
|
+
await (0, _devEnvironmentCore.exec)(slug, arg, options);
|
|
63
70
|
await (0, _tracker.trackEvent)('dev_env_exec_command_success', trackingInfo);
|
|
64
71
|
} catch (error) {
|
|
65
72
|
(0, _devEnvironmentCli.handleCLIException)(error, 'dev_env_exec_command_error', trackingInfo);
|
|
@@ -44,7 +44,7 @@ const examples = [{
|
|
|
44
44
|
}];
|
|
45
45
|
(0, _command.default)({
|
|
46
46
|
requiredArgs: 1
|
|
47
|
-
}).option('slug', 'Custom name of the dev environment').option('search-replace', 'Perform Search and Replace on the specified SQL file').option('in-place', 'Search and Replace explicitly on the given input file').option('skip-validate', 'Do not perform file validation.').examples(examples).argv(process.argv, async (unmatchedArgs, opt) => {
|
|
47
|
+
}).option('slug', 'Custom name of the dev environment').option(['r', 'search-replace'], 'Perform Search and Replace on the specified SQL file').option('in-place', 'Search and Replace explicitly on the given input file').option('skip-validate', 'Do not perform file validation.').examples(examples).argv(process.argv, async (unmatchedArgs, opt) => {
|
|
48
48
|
await (0, _devEnvironmentCli.validateDependencies)();
|
|
49
49
|
const [fileName] = unmatchedArgs;
|
|
50
50
|
const {
|
|
@@ -249,7 +249,8 @@ async function validateAndGetTableNames({
|
|
|
249
249
|
skipValidate,
|
|
250
250
|
appId,
|
|
251
251
|
envId,
|
|
252
|
-
fileNameToUpload
|
|
252
|
+
fileNameToUpload,
|
|
253
|
+
searchReplace
|
|
253
254
|
}) {
|
|
254
255
|
const validations = [_sql.staticSqlValidations, _siteType.siteTypeValidations];
|
|
255
256
|
|
|
@@ -259,10 +260,10 @@ async function validateAndGetTableNames({
|
|
|
259
260
|
}
|
|
260
261
|
|
|
261
262
|
try {
|
|
262
|
-
await (0, _lineByLine.fileLineValidations)(appId, envId, fileNameToUpload, validations);
|
|
263
|
+
await (0, _lineByLine.fileLineValidations)(appId, envId, fileNameToUpload, validations, searchReplace);
|
|
263
264
|
} catch (validateErr) {
|
|
264
265
|
console.log('');
|
|
265
|
-
exit.withError(`${validateErr.message}
|
|
266
|
+
exit.withError(`${validateErr.message}\n
|
|
266
267
|
If you are confident the file does not contain unsupported statements, you can retry the command with the ${_chalk.default.yellow('--skip-validate')} option.
|
|
267
268
|
`);
|
|
268
269
|
} // this can only be called after static validation of the SQL file
|
|
@@ -407,7 +408,8 @@ const displayPlaybook = ({
|
|
|
407
408
|
skipValidate,
|
|
408
409
|
appId,
|
|
409
410
|
envId,
|
|
410
|
-
fileNameToUpload
|
|
411
|
+
fileNameToUpload,
|
|
412
|
+
searchReplace
|
|
411
413
|
}); // display playbook of what will happen during execution
|
|
412
414
|
|
|
413
415
|
displayPlaybook({
|
|
@@ -11,9 +11,9 @@ exports.DEV_ENVIRONMENT_FULL_COMMAND = DEV_ENVIRONMENT_FULL_COMMAND;
|
|
|
11
11
|
const DEV_ENVIRONMENT_DEFAULTS = {
|
|
12
12
|
title: 'VIP Dev',
|
|
13
13
|
multisite: false,
|
|
14
|
-
elasticsearchVersion: '7.
|
|
14
|
+
elasticsearchVersion: '7.17.2',
|
|
15
15
|
mariadbVersion: '10.3',
|
|
16
|
-
|
|
16
|
+
phpVersion: '8.0'
|
|
17
17
|
};
|
|
18
18
|
exports.DEV_ENVIRONMENT_DEFAULTS = DEV_ENVIRONMENT_DEFAULTS;
|
|
19
19
|
const DEV_ENVIRONMENT_PROMPT_INTRO = 'This is a wizard to help you set up your local dev environment.\n\n' + 'Sensible default values were pre-selected for convenience. ' + 'You may also choose to create multiple environments with different settings using the --slug option.\n\n';
|
|
@@ -32,11 +32,10 @@ const DEV_ENVIRONMENT_WORDPRESS_VERSION_TTL = 86400; // once per day
|
|
|
32
32
|
|
|
33
33
|
exports.DEV_ENVIRONMENT_WORDPRESS_VERSION_TTL = DEV_ENVIRONMENT_WORDPRESS_VERSION_TTL;
|
|
34
34
|
const DEV_ENVIRONMENT_PHP_VERSIONS = {
|
|
35
|
-
default: 'ghcr.io/automattic/vip-container-images/php-fpm:7.4',
|
|
36
|
-
// eslint-disable-next-line quote-props -- flow does nit support non-string keys
|
|
37
|
-
'7.4': 'ghcr.io/automattic/vip-container-images/php-fpm-alt:7.4',
|
|
38
|
-
'8.0': 'ghcr.io/automattic/vip-container-images/php-fpm-alt:8.0',
|
|
39
35
|
// eslint-disable-next-line quote-props
|
|
40
|
-
'8.1': 'ghcr.io/automattic/vip-container-images/php-fpm-alt:8.1'
|
|
36
|
+
'8.1': 'ghcr.io/automattic/vip-container-images/php-fpm-alt:8.1',
|
|
37
|
+
'8.0': 'ghcr.io/automattic/vip-container-images/php-fpm-alt:8.0',
|
|
38
|
+
// eslint-disable-next-line quote-props -- flow does nit support non-string keys
|
|
39
|
+
'7.4': 'ghcr.io/automattic/vip-container-images/php-fpm-alt:7.4'
|
|
41
40
|
};
|
|
42
41
|
exports.DEV_ENVIRONMENT_PHP_VERSIONS = DEV_ENVIRONMENT_PHP_VERSIONS;
|
|
@@ -91,9 +91,9 @@ async function handleCLIException(exception, trackKey, trackBaseInfo = {}) {
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
if (!process.env.DEBUG) {
|
|
94
|
-
console.log(
|
|
94
|
+
console.log(`\nPlease re-run the command with "--debug ${_chalk.default.bold('@automattic/vip:bin:dev-environment')}" appended to it and provide the stack trace on the support ticket.`);
|
|
95
95
|
console.log(_chalk.default.bold('\nExample:\n'));
|
|
96
|
-
console.log('vip dev-env
|
|
96
|
+
console.log('vip dev-env <command> <arguments> --debug @automattic/vip:bin:dev-environment \n');
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
debug(exception);
|
|
@@ -248,7 +248,7 @@ async function promptForArguments(preselectedOptions, defaultOptions) {
|
|
|
248
248
|
instanceData[component] = result;
|
|
249
249
|
}
|
|
250
250
|
|
|
251
|
-
instanceData.enterpriseSearchEnabled = await promptForBoolean('Enable Enterprise Search?', defaultOptions.enterpriseSearchEnabled);
|
|
251
|
+
instanceData.enterpriseSearchEnabled = await promptForBoolean('Enable Elasticsearch (needed by Enterprise Search)?', defaultOptions.enterpriseSearchEnabled);
|
|
252
252
|
|
|
253
253
|
if (instanceData.enterpriseSearchEnabled) {
|
|
254
254
|
instanceData.statsd = preselectedOptions.statsd || defaultOptions.statsd || false;
|
|
@@ -213,8 +213,8 @@ async function printEnvironmentInfo(slug) {
|
|
|
213
213
|
(0, _devEnvironmentCli.printTable)(appInfo);
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
-
async function exec(slug, args) {
|
|
217
|
-
debug('Will run a wp command on env', slug, 'with args', args);
|
|
216
|
+
async function exec(slug, args, options = {}) {
|
|
217
|
+
debug('Will run a wp command on env', slug, 'with args', args, ' and options', options);
|
|
218
218
|
const instancePath = getEnvironmentPath(slug);
|
|
219
219
|
debug('Instance path for', slug, 'is:', instancePath);
|
|
220
220
|
|
|
@@ -231,7 +231,7 @@ async function exec(slug, args) {
|
|
|
231
231
|
commandArgs = [...args.map(argument => argument.replace('--new-site-', '--'))];
|
|
232
232
|
}
|
|
233
233
|
|
|
234
|
-
await (0, _devEnvironmentLando.landoExec)(instancePath, command, commandArgs);
|
|
234
|
+
await (0, _devEnvironmentLando.landoExec)(instancePath, command, commandArgs, options);
|
|
235
235
|
}
|
|
236
236
|
|
|
237
237
|
function doesEnvironmentExist(slug) {
|
|
@@ -140,7 +140,7 @@ async function healthcheckHook(app, lando) {
|
|
|
140
140
|
services: [container.service]
|
|
141
141
|
}
|
|
142
142
|
});
|
|
143
|
-
} catch (
|
|
143
|
+
} catch (exception) {
|
|
144
144
|
debug(`${container.service} Health check failed`);
|
|
145
145
|
notHealthyContainers.push(container);
|
|
146
146
|
}
|
|
@@ -272,15 +272,18 @@ async function isEnvUp(app) {
|
|
|
272
272
|
return (scanResult === null || scanResult === void 0 ? void 0 : scanResult.length) && scanResult.filter(result => result.status).length === scanResult.length;
|
|
273
273
|
}
|
|
274
274
|
|
|
275
|
-
async function landoExec(instancePath, toolName, args) {
|
|
275
|
+
async function landoExec(instancePath, toolName, args, options) {
|
|
276
276
|
const lando = new _lando.default(getLandoConfig());
|
|
277
277
|
await lando.bootstrap();
|
|
278
278
|
const app = lando.getApp(instancePath);
|
|
279
279
|
await app.init();
|
|
280
|
-
const isUp = await isEnvUp(app);
|
|
281
280
|
|
|
282
|
-
if (!
|
|
283
|
-
|
|
281
|
+
if (!options.force) {
|
|
282
|
+
const isUp = await isEnvUp(app);
|
|
283
|
+
|
|
284
|
+
if (!isUp) {
|
|
285
|
+
throw new Error('environment needs to be started before running wp command');
|
|
286
|
+
}
|
|
284
287
|
}
|
|
285
288
|
|
|
286
289
|
const tool = app.config.tooling[toolName];
|
|
@@ -18,7 +18,7 @@ var _fileSize = require("../constants/file-size");
|
|
|
18
18
|
*/
|
|
19
19
|
const SQL_IMPORT_FILE_SIZE_LIMIT = 100 * _fileSize.GB_IN_BYTES;
|
|
20
20
|
exports.SQL_IMPORT_FILE_SIZE_LIMIT = SQL_IMPORT_FILE_SIZE_LIMIT;
|
|
21
|
-
const SQL_IMPORT_FILE_SIZE_LIMIT_LAUNCHED =
|
|
21
|
+
const SQL_IMPORT_FILE_SIZE_LIMIT_LAUNCHED = 1 * _fileSize.GB_IN_BYTES;
|
|
22
22
|
exports.SQL_IMPORT_FILE_SIZE_LIMIT_LAUNCHED = SQL_IMPORT_FILE_SIZE_LIMIT_LAUNCHED;
|
|
23
23
|
|
|
24
24
|
function currentUserCanImportForApp(app) {
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.isMultisitePrimaryDomainMapped = isMultisitePrimaryDomainMapped;
|
|
7
|
+
exports.getPrimaryDomain = exports.maybeSearchReplacePrimaryDomain = exports.getPrimaryDomainFromSQL = void 0;
|
|
8
|
+
|
|
9
|
+
var _graphqlTag = _interopRequireDefault(require("graphql-tag"));
|
|
10
|
+
|
|
11
|
+
var _api = _interopRequireDefault(require("../api"));
|
|
12
|
+
|
|
13
|
+
var _tracker = require("../tracker");
|
|
14
|
+
|
|
15
|
+
var exit = _interopRequireWildcard(require("../cli/exit"));
|
|
16
|
+
|
|
17
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
18
|
+
|
|
19
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
20
|
+
|
|
21
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
*
|
|
25
|
+
* @format
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* External dependencies
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Internal dependencies
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Extracts the domain for site with ID 1 from an INSERT INTO `wp_site` SQL statement
|
|
38
|
+
*
|
|
39
|
+
* @param {array} statements An array of SQL statements
|
|
40
|
+
* @returns {string} The domain
|
|
41
|
+
*/
|
|
42
|
+
const getPrimaryDomainFromSQL = statements => {
|
|
43
|
+
var _statements$;
|
|
44
|
+
|
|
45
|
+
if (!statements.length) {
|
|
46
|
+
return '';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const SQL_WP_SITE_DOMAINS_REGEX = /\(1,'(.*?)'/s;
|
|
50
|
+
const matches = (_statements$ = statements[0]) === null || _statements$ === void 0 ? void 0 : _statements$.join('').replace(/\s/g, '').match(SQL_WP_SITE_DOMAINS_REGEX);
|
|
51
|
+
return matches ? matches[1] : '';
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Apply search-replacements to a domain
|
|
55
|
+
*
|
|
56
|
+
* @param {string} domain The domain to apply replacements to
|
|
57
|
+
* @param {(string|array)} searchReplace The search-replace pairs
|
|
58
|
+
* @returns {string} The processed domain
|
|
59
|
+
*/
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
exports.getPrimaryDomainFromSQL = getPrimaryDomainFromSQL;
|
|
63
|
+
|
|
64
|
+
const maybeSearchReplacePrimaryDomain = function (domain, searchReplace) {
|
|
65
|
+
if (searchReplace) {
|
|
66
|
+
var _primaryDomainReplace;
|
|
67
|
+
|
|
68
|
+
let pairs = searchReplace;
|
|
69
|
+
|
|
70
|
+
if (!Array.isArray(pairs)) {
|
|
71
|
+
pairs = [searchReplace];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const domainReplacements = pairs.map(pair => pair.split(','));
|
|
75
|
+
const primaryDomainReplacement = domainReplacements.find(pair => pair[0] === domain);
|
|
76
|
+
return (_primaryDomainReplace = primaryDomainReplacement === null || primaryDomainReplacement === void 0 ? void 0 : primaryDomainReplacement[1]) !== null && _primaryDomainReplace !== void 0 ? _primaryDomainReplace : domain;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return domain;
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Get the primary domain as it will be imported
|
|
83
|
+
*
|
|
84
|
+
* @param {array} statements An array of SQL statements
|
|
85
|
+
* @param {(string|array)} searchReplace The search-replace pairs
|
|
86
|
+
* @returns {string} The replaced domain, or the domain as found in the SQL dump
|
|
87
|
+
*/
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
exports.maybeSearchReplacePrimaryDomain = maybeSearchReplacePrimaryDomain;
|
|
91
|
+
|
|
92
|
+
const getPrimaryDomain = function (statements, searchReplace) {
|
|
93
|
+
const domainFromSQL = getPrimaryDomainFromSQL(statements);
|
|
94
|
+
return maybeSearchReplacePrimaryDomain(domainFromSQL, searchReplace);
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Gets the mapped domains and checks if the primary domain from the provided SQL dump is one of them
|
|
98
|
+
*
|
|
99
|
+
* @param {number} appId The ID of the app in GOOP
|
|
100
|
+
* @param {number} envId The ID of the enviroment in GOOP
|
|
101
|
+
* @param {string} primaryDomain The primary domain found in the provided SQL file
|
|
102
|
+
* @returns {boolean} Whether the primary domain is mapped
|
|
103
|
+
*/
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
exports.getPrimaryDomain = getPrimaryDomain;
|
|
107
|
+
|
|
108
|
+
async function isMultisitePrimaryDomainMapped(appId, envId, primaryDomain) {
|
|
109
|
+
var _res, _res$data, _res$data$app, _environments$, _environments$$domain, _environments$$domain2;
|
|
110
|
+
|
|
111
|
+
const track = _tracker.trackEventWithEnv.bind(null, appId, envId);
|
|
112
|
+
|
|
113
|
+
const api = await (0, _api.default)();
|
|
114
|
+
let res;
|
|
115
|
+
|
|
116
|
+
try {
|
|
117
|
+
res = await api.query({
|
|
118
|
+
query: (0, _graphqlTag.default)`
|
|
119
|
+
query AppMappedDomains($appId: Int, $envId: Int) {
|
|
120
|
+
app(id: $appId) {
|
|
121
|
+
id
|
|
122
|
+
name
|
|
123
|
+
environments(id: $envId) {
|
|
124
|
+
uniqueLabel
|
|
125
|
+
isMultisite
|
|
126
|
+
domains {
|
|
127
|
+
nodes {
|
|
128
|
+
name
|
|
129
|
+
isPrimary
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
`,
|
|
136
|
+
variables: {
|
|
137
|
+
appId,
|
|
138
|
+
envId
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
} catch (GraphQlError) {
|
|
142
|
+
await track('import_sql_command_error', {
|
|
143
|
+
error_type: 'GraphQL-MappedDomain-Check-failed',
|
|
144
|
+
gql_err: GraphQlError
|
|
145
|
+
});
|
|
146
|
+
exit.withError(`StartImport call failed: ${GraphQlError}`);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (!Array.isArray((_res = res) === null || _res === void 0 ? void 0 : (_res$data = _res.data) === null || _res$data === void 0 ? void 0 : (_res$data$app = _res$data.app) === null || _res$data$app === void 0 ? void 0 : _res$data$app.environments)) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const environments = res.data.app.environments;
|
|
154
|
+
|
|
155
|
+
if (!environments.length) {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const mappedDomains = (_environments$ = environments[0]) === null || _environments$ === void 0 ? void 0 : (_environments$$domain = _environments$.domains) === null || _environments$$domain === void 0 ? void 0 : (_environments$$domain2 = _environments$$domain.nodes) === null || _environments$$domain2 === void 0 ? void 0 : _environments$$domain2.map(domain => domain.name);
|
|
160
|
+
return mappedDomains.includes(primaryDomain);
|
|
161
|
+
}
|
|
@@ -64,7 +64,7 @@ async function getReadInterface(filename) {
|
|
|
64
64
|
});
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
async function fileLineValidations(appId, envId, fileName, validations) {
|
|
67
|
+
async function fileLineValidations(appId, envId, fileName, validations, searchReplace) {
|
|
68
68
|
const isImport = true;
|
|
69
69
|
const readInterface = await getReadInterface(fileName);
|
|
70
70
|
debug('Validations: ', validations);
|
|
@@ -85,7 +85,8 @@ async function fileLineValidations(appId, envId, fileName, validations) {
|
|
|
85
85
|
fileName,
|
|
86
86
|
isImport,
|
|
87
87
|
appId,
|
|
88
|
-
envId
|
|
88
|
+
envId,
|
|
89
|
+
searchReplace
|
|
89
90
|
});
|
|
90
91
|
}
|
|
91
92
|
}));
|
|
@@ -13,6 +13,10 @@ var _isMultiSiteSqlDump = require("./is-multi-site-sql-dump");
|
|
|
13
13
|
|
|
14
14
|
var _isMultiSite = require("./is-multi-site");
|
|
15
15
|
|
|
16
|
+
var _isMultisiteDomainMapped = require("./is-multisite-domain-mapped");
|
|
17
|
+
|
|
18
|
+
var _utils = require("./utils");
|
|
19
|
+
|
|
16
20
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
17
21
|
|
|
18
22
|
/**
|
|
@@ -29,9 +33,12 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
|
|
29
33
|
*/
|
|
30
34
|
const debug = (0, _debug.default)('vip:vip-import-sql');
|
|
31
35
|
let isMultiSiteSqlDump = false;
|
|
36
|
+
let wpSiteInsertStatement;
|
|
37
|
+
const getWpSiteInsertStatement = (0, _utils.getMultilineStatement)(/INSERT INTO `wp_site`/s);
|
|
32
38
|
const siteTypeValidations = {
|
|
33
39
|
execute: line => {
|
|
34
40
|
const lineIsMultiSite = (0, _isMultiSiteSqlDump.sqlDumpLineIsMultiSite)(line);
|
|
41
|
+
wpSiteInsertStatement = getWpSiteInsertStatement(line);
|
|
35
42
|
|
|
36
43
|
if (lineIsMultiSite) {
|
|
37
44
|
isMultiSiteSqlDump = true;
|
|
@@ -39,9 +46,12 @@ const siteTypeValidations = {
|
|
|
39
46
|
},
|
|
40
47
|
postLineExecutionProcessing: async ({
|
|
41
48
|
appId,
|
|
42
|
-
envId
|
|
49
|
+
envId,
|
|
50
|
+
searchReplace
|
|
43
51
|
}) => {
|
|
44
52
|
const isMultiSite = await (0, _isMultiSite.isMultiSiteInSiteMeta)(appId, envId);
|
|
53
|
+
const primaryDomainFromSQL = (0, _isMultisiteDomainMapped.getPrimaryDomain)(wpSiteInsertStatement, searchReplace);
|
|
54
|
+
const isPrimaryDomainMapped = primaryDomainFromSQL && (await (0, _isMultisiteDomainMapped.isMultisitePrimaryDomainMapped)(appId, envId, primaryDomainFromSQL));
|
|
45
55
|
|
|
46
56
|
const track = _tracker.trackEventWithEnv.bind(null, appId, envId);
|
|
47
57
|
|
|
@@ -61,6 +71,13 @@ const siteTypeValidations = {
|
|
|
61
71
|
});
|
|
62
72
|
throw new Error('You have requested a subsite SQL import but have not provided a subsite compatiable SQL dump.');
|
|
63
73
|
}
|
|
74
|
+
|
|
75
|
+
if (isMultiSite && !isPrimaryDomainMapped) {
|
|
76
|
+
await track('import_sql_command_error', {
|
|
77
|
+
error_type: 'multisite-import-where-primary-domain-unmapped'
|
|
78
|
+
});
|
|
79
|
+
throw new Error('This import would set the network\'s main site domain to ' + primaryDomainFromSQL + ', however this domain is not mapped to the target environment. Please replace this domain in your ' + 'import file, or map it to the environment.');
|
|
80
|
+
}
|
|
64
81
|
}
|
|
65
82
|
};
|
|
66
83
|
exports.siteTypeValidations = siteTypeValidations;
|
|
@@ -41,6 +41,10 @@ function formatError(message) {
|
|
|
41
41
|
return `${_chalk.default.red('SQL Error:')} ${message}`;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
function formatWarning(message) {
|
|
45
|
+
return `${_chalk.default.yellow('Warning:')} ${message}`;
|
|
46
|
+
}
|
|
47
|
+
|
|
44
48
|
function formatRecommendation(message) {
|
|
45
49
|
return `${_chalk.default.yellow('Recommendation:')} ${message}`;
|
|
46
50
|
}
|
|
@@ -51,13 +55,24 @@ const generalCheckFormatter = check => {
|
|
|
51
55
|
const validProblems = check.results.filter(result => !result.falsePositive);
|
|
52
56
|
|
|
53
57
|
if (validProblems.length > 0) {
|
|
54
|
-
|
|
58
|
+
if (validProblems.some(result => !result.warning)) {
|
|
59
|
+
problemsFound += 1;
|
|
60
|
+
}
|
|
55
61
|
|
|
56
62
|
for (const problem of validProblems) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
63
|
+
const text = `${problem.text || check.message} on line ${problem.lineNumber || ''}.`;
|
|
64
|
+
|
|
65
|
+
if (problem.warning) {
|
|
66
|
+
errors.push({
|
|
67
|
+
warning: formatWarning(text),
|
|
68
|
+
recommendation: formatRecommendation(problem.recomendation || check.recommendation)
|
|
69
|
+
});
|
|
70
|
+
} else {
|
|
71
|
+
errors.push({
|
|
72
|
+
error: formatError(text),
|
|
73
|
+
recommendation: formatRecommendation(problem.recomendation || check.recommendation)
|
|
74
|
+
});
|
|
75
|
+
}
|
|
61
76
|
}
|
|
62
77
|
} else {
|
|
63
78
|
infos.push(`✅ ${check.message} was found 0 times.`);
|
|
@@ -268,6 +283,7 @@ const checks = {
|
|
|
268
283
|
}
|
|
269
284
|
|
|
270
285
|
return {
|
|
286
|
+
warning: true,
|
|
271
287
|
lineNumber,
|
|
272
288
|
recomendation: `Use '--search-replace="${foundDomain},${expectedDomain}"' switch to replace the domain`
|
|
273
289
|
};
|
|
@@ -304,12 +320,21 @@ const postValidation = async options => {
|
|
|
304
320
|
|
|
305
321
|
const errorSummary = {};
|
|
306
322
|
const checkEntries = Object.entries(checks).filter(([type]) => !options.skipChecks.includes(type));
|
|
323
|
+
const formattedWarnings = [];
|
|
307
324
|
let formattedErrors = [];
|
|
308
325
|
let formattedInfos = [];
|
|
309
326
|
|
|
310
327
|
for (const [type, check] of checkEntries) {
|
|
311
328
|
const formattedOutput = check.outputFormatter(check, type, options.isImport);
|
|
312
|
-
|
|
329
|
+
|
|
330
|
+
for (const error of formattedOutput.errors) {
|
|
331
|
+
if (error.warning) {
|
|
332
|
+
formattedWarnings.push(error);
|
|
333
|
+
} else {
|
|
334
|
+
formattedErrors.push(error);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
313
338
|
formattedInfos = formattedInfos.concat(formattedOutput.infos);
|
|
314
339
|
errorSummary[type] = check.results.length;
|
|
315
340
|
} // eslint-disable-next-line camelcase
|
|
@@ -341,6 +366,21 @@ const postValidation = async options => {
|
|
|
341
366
|
formattedErrors = formattedErrors.concat(errorObject);
|
|
342
367
|
}
|
|
343
368
|
|
|
369
|
+
if (formattedWarnings.length) {
|
|
370
|
+
const warningOutput = [];
|
|
371
|
+
formattedWarnings.forEach(warning => {
|
|
372
|
+
warningOutput.push(warning.warning);
|
|
373
|
+
|
|
374
|
+
if (warning.recommendation) {
|
|
375
|
+
warningOutput.push(warning.recommendation);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
warningOutput.push('');
|
|
379
|
+
});
|
|
380
|
+
console.log(warningOutput.join('\n'));
|
|
381
|
+
console.log('');
|
|
382
|
+
}
|
|
383
|
+
|
|
344
384
|
if (problemsFound > 0) {
|
|
345
385
|
await (0, _tracker.trackEvent)('import_validate_sql_command_failure', {
|
|
346
386
|
is_import: options.isImport,
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.getMultilineStatement = getMultilineStatement;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Get SQL statements matching a supplied pattern from a file stream
|
|
10
|
+
*
|
|
11
|
+
* @param {RegExp} statementRegex A RegExp pattern representing the start of the statement to capture
|
|
12
|
+
* @returns {function} A function which processes individual lines to capture the matching statements
|
|
13
|
+
*/
|
|
14
|
+
function getMultilineStatement(statementRegex) {
|
|
15
|
+
const matchingStatements = [];
|
|
16
|
+
let isCapturing = false;
|
|
17
|
+
let index = 0;
|
|
18
|
+
/**
|
|
19
|
+
* Processes each line of the file stream and builds an array of statements which start with the supplied pattern
|
|
20
|
+
*
|
|
21
|
+
* @param {string} line A line from the file stream
|
|
22
|
+
* @returns {array} An array of matching statements where each statement is presented as an array of lines
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
return line => {
|
|
26
|
+
const shouldStartCapture = statementRegex.test(line);
|
|
27
|
+
const shouldEndCapture = (shouldStartCapture || isCapturing) && /;$/.test(line);
|
|
28
|
+
|
|
29
|
+
if (shouldStartCapture) {
|
|
30
|
+
isCapturing = true;
|
|
31
|
+
matchingStatements[index] = [];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (isCapturing) {
|
|
35
|
+
matchingStatements[index].push(line);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (shouldEndCapture) {
|
|
39
|
+
isCapturing = false;
|
|
40
|
+
index++;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return matchingStatements;
|
|
44
|
+
};
|
|
45
|
+
}
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automattic/vip",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.15.0",
|
|
4
4
|
"lockfileVersion": 1,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"dependencies": {
|
|
@@ -10104,8 +10104,8 @@
|
|
|
10104
10104
|
"dev": true
|
|
10105
10105
|
},
|
|
10106
10106
|
"lando": {
|
|
10107
|
-
"version": "git+https://github.com/Automattic/lando-cli.git#
|
|
10108
|
-
"from": "git+https://github.com/Automattic/lando-cli.git#v3.5.2-
|
|
10107
|
+
"version": "git+https://github.com/Automattic/lando-cli.git#3c74058161e51c9f482e6fa2727f616070853b98",
|
|
10108
|
+
"from": "git+https://github.com/Automattic/lando-cli.git#v3.5.2-patch2022_06_20",
|
|
10109
10109
|
"requires": {
|
|
10110
10110
|
"@lando/platformsh": "^0.6.0",
|
|
10111
10111
|
"axios": "0.21.4",
|
|
@@ -10865,9 +10865,9 @@
|
|
|
10865
10865
|
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
|
|
10866
10866
|
},
|
|
10867
10867
|
"minipass": {
|
|
10868
|
-
"version": "3.
|
|
10869
|
-
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.
|
|
10870
|
-
"integrity": "sha512-
|
|
10868
|
+
"version": "3.3.3",
|
|
10869
|
+
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.3.tgz",
|
|
10870
|
+
"integrity": "sha512-N0BOsdFAlNRfmwMhjAsLVWOk7Ljmeb39iqFlsV1At+jqRhSUP9yeof8FyJu4imaJiSUp8vQebWD/guZwGQC8iA==",
|
|
10871
10871
|
"requires": {
|
|
10872
10872
|
"yallist": "^4.0.0"
|
|
10873
10873
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automattic/vip",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.15.0",
|
|
4
4
|
"description": "The VIP Javascript library & CLI",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"license": "MIT",
|
|
73
73
|
"engines": {
|
|
74
74
|
"node": ">=14.14.0",
|
|
75
|
-
"npm": "
|
|
75
|
+
"npm": ">=6"
|
|
76
76
|
},
|
|
77
77
|
"bugs": {
|
|
78
78
|
"url": "https://github.com/Automattic/vip/issues"
|
|
@@ -124,7 +124,7 @@
|
|
|
124
124
|
"ini": "2.0.0",
|
|
125
125
|
"json2csv": "5.0.6",
|
|
126
126
|
"jwt-decode": "2.2.0",
|
|
127
|
-
"lando": "git+https://github.com/Automattic/lando-cli.git#v3.5.2-
|
|
127
|
+
"lando": "git+https://github.com/Automattic/lando-cli.git#v3.5.2-patch2022_06_20",
|
|
128
128
|
"node-fetch": "^2.6.1",
|
|
129
129
|
"opn": "5.5.0",
|
|
130
130
|
"proxy-from-env": "^1.1.0",
|
package/.circleci/config.yml
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
version: 2.1
|
|
2
|
-
|
|
3
|
-
workflows:
|
|
4
|
-
build:
|
|
5
|
-
jobs:
|
|
6
|
-
- lint
|
|
7
|
-
- flow
|
|
8
|
-
- test:
|
|
9
|
-
version: 14-stretch
|
|
10
|
-
name: 14-stretch
|
|
11
|
-
requires:
|
|
12
|
-
- lint
|
|
13
|
-
- flow
|
|
14
|
-
- test:
|
|
15
|
-
version: lts-stretch
|
|
16
|
-
name: lts-stretch
|
|
17
|
-
requires:
|
|
18
|
-
- lint
|
|
19
|
-
- flow
|
|
20
|
-
- test:
|
|
21
|
-
version: current-stretch
|
|
22
|
-
name: current-stretch
|
|
23
|
-
requires:
|
|
24
|
-
- lint
|
|
25
|
-
- flow
|
|
26
|
-
|
|
27
|
-
jobs:
|
|
28
|
-
lint:
|
|
29
|
-
docker:
|
|
30
|
-
- image: circleci/node:current-stretch
|
|
31
|
-
|
|
32
|
-
working_directory: ~/repo
|
|
33
|
-
|
|
34
|
-
steps:
|
|
35
|
-
- checkout
|
|
36
|
-
- run: npm ci
|
|
37
|
-
- run:
|
|
38
|
-
name: Run lint
|
|
39
|
-
command: npm run lint
|
|
40
|
-
|
|
41
|
-
flow:
|
|
42
|
-
docker:
|
|
43
|
-
- image: circleci/node:current-stretch
|
|
44
|
-
|
|
45
|
-
working_directory: ~/repo
|
|
46
|
-
|
|
47
|
-
steps:
|
|
48
|
-
- checkout
|
|
49
|
-
- run: npm ci
|
|
50
|
-
- run:
|
|
51
|
-
name: Run flow
|
|
52
|
-
command: npm run flow
|
|
53
|
-
|
|
54
|
-
test:
|
|
55
|
-
parameters:
|
|
56
|
-
version:
|
|
57
|
-
type: string
|
|
58
|
-
|
|
59
|
-
docker:
|
|
60
|
-
- image: circleci/node:<< parameters.version >>
|
|
61
|
-
|
|
62
|
-
working_directory: ~/repo
|
|
63
|
-
|
|
64
|
-
steps:
|
|
65
|
-
- checkout
|
|
66
|
-
- run: npm ci
|
|
67
|
-
- run: npm run jest
|