@automattic/vip 2.11.0 → 2.11.2
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 +8 -0
- package/config/config.json +2 -2
- package/npm-shrinkwrap.json +1 -1
- package/package/dist/bin/vip-app-list.js +73 -0
- package/package/dist/bin/vip-app.js +76 -0
- package/package/dist/bin/vip-config-envvar-delete.js +97 -0
- package/package/dist/bin/vip-config-envvar-get-all.js +94 -0
- package/package/dist/bin/vip-config-envvar-get.js +79 -0
- package/package/dist/bin/vip-config-envvar-list.js +91 -0
- package/package/dist/bin/vip-config-envvar-set.js +123 -0
- package/package/dist/bin/vip-config-envvar.js +23 -0
- package/package/dist/bin/vip-config.js +20 -0
- package/package/dist/bin/vip-dev-env-create.js +105 -0
- package/package/dist/bin/vip-dev-env-destroy.js +56 -0
- package/package/dist/bin/vip-dev-env-exec.js +67 -0
- package/package/dist/bin/vip-dev-env-import-media.js +51 -0
- package/package/dist/bin/vip-dev-env-import-sql.js +83 -0
- package/package/dist/bin/vip-dev-env-import.js +32 -0
- package/package/dist/bin/vip-dev-env-info.js +61 -0
- package/package/dist/bin/vip-dev-env-list.js +46 -0
- package/package/dist/bin/vip-dev-env-start.js +77 -0
- package/package/dist/bin/vip-dev-env-stop.js +52 -0
- package/package/dist/bin/vip-dev-env-update.js +89 -0
- package/package/dist/bin/vip-dev-env.js +23 -0
- package/package/dist/bin/vip-import-media-abort.js +132 -0
- package/package/dist/bin/vip-import-media-status.js +84 -0
- package/package/dist/bin/vip-import-media.js +168 -0
- package/package/dist/bin/vip-import-sql-status.js +83 -0
- package/package/dist/bin/vip-import-sql.js +580 -0
- package/package/dist/bin/vip-import-validate-files.js +191 -0
- package/package/dist/bin/vip-import-validate-sql.js +34 -0
- package/package/dist/bin/vip-import.js +20 -0
- package/package/dist/bin/vip-logs.js +232 -0
- package/package/dist/bin/vip-search-replace.js +71 -0
- package/package/dist/bin/vip-sync.js +191 -0
- package/package/dist/bin/vip-whoami.js +67 -0
- package/package/dist/bin/vip-wp.js +555 -0
- package/package/dist/bin/vip.js +149 -0
- package/package/dist/lib/analytics/clients/client.js +1 -0
- package/package/dist/lib/analytics/clients/pendo.js +92 -0
- package/package/dist/lib/analytics/clients/stub.js +19 -0
- package/package/dist/lib/analytics/clients/tracks.js +128 -0
- package/package/dist/lib/analytics/index.js +45 -0
- package/package/dist/lib/api/app.js +70 -0
- package/package/dist/lib/api/feature-flags.js +39 -0
- package/package/dist/lib/api/user.js +58 -0
- package/package/dist/lib/api.js +136 -0
- package/package/dist/lib/app-logs/app-logs.js +70 -0
- package/package/dist/lib/cli/apiConfig.js +90 -0
- package/package/dist/lib/cli/command.js +606 -0
- package/package/dist/lib/cli/envAlias.js +60 -0
- package/package/dist/lib/cli/exit.js +33 -0
- package/package/dist/lib/cli/format.js +213 -0
- package/package/dist/lib/cli/pager.js +52 -0
- package/package/dist/lib/cli/progress.js +208 -0
- package/package/dist/lib/cli/prompt.js +37 -0
- package/package/dist/lib/cli/repo.js +77 -0
- package/package/dist/lib/client-file-uploader.js +602 -0
- package/package/dist/lib/constants/dev-environment.js +42 -0
- package/package/dist/lib/constants/file-size.js +14 -0
- package/package/dist/lib/dev-environment/dev-environment-cli.js +508 -0
- package/package/dist/lib/dev-environment/dev-environment-core.js +620 -0
- package/package/dist/lib/dev-environment/dev-environment-lando.js +330 -0
- package/package/dist/lib/dev-environment/types.js +1 -0
- package/package/dist/lib/env.js +36 -0
- package/package/dist/lib/envvar/api-delete.js +56 -0
- package/package/dist/lib/envvar/api-get-all.js +59 -0
- package/package/dist/lib/envvar/api-get.js +24 -0
- package/package/dist/lib/envvar/api-list.js +60 -0
- package/package/dist/lib/envvar/api-set.js +58 -0
- package/package/dist/lib/envvar/api.js +104 -0
- package/package/dist/lib/envvar/input.js +55 -0
- package/package/dist/lib/envvar/logging.js +33 -0
- package/package/dist/lib/envvar/read-file.js +43 -0
- package/package/dist/lib/http/socks-proxy-agent.js +25 -0
- package/package/dist/lib/keychain/browser.js +35 -0
- package/package/dist/lib/keychain/insecure.js +63 -0
- package/package/dist/lib/keychain/keychain.js +1 -0
- package/package/dist/lib/keychain/secure.js +36 -0
- package/package/dist/lib/keychain.js +36 -0
- package/package/dist/lib/media-import/media-file-import.js +34 -0
- package/package/dist/lib/media-import/progress.js +86 -0
- package/package/dist/lib/media-import/status.js +335 -0
- package/package/dist/lib/rollbar.js +35 -0
- package/package/dist/lib/search-and-replace.js +203 -0
- package/package/dist/lib/site-import/db-file-import.js +46 -0
- package/package/dist/lib/site-import/status.js +444 -0
- package/package/dist/lib/token.js +132 -0
- package/package/dist/lib/tracker.js +96 -0
- package/package/dist/lib/validations/is-multi-site-sql-dump.js +59 -0
- package/package/dist/lib/validations/is-multi-site.js +99 -0
- package/package/dist/lib/validations/line-by-line.js +92 -0
- package/package/dist/lib/validations/site-type.js +66 -0
- package/package/dist/lib/validations/sql.js +371 -0
- package/package/dist/lib/vip-import-validate-files.js +548 -0
- package/package/vip.iml +11 -0
- package/package.json +1 -1
- package/vip.iml +11 -0
- package/automattic-vip-2.11.0.tgz +0 -0
|
@@ -0,0 +1,580 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* @format
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* External dependencies
|
|
10
|
+
*/
|
|
11
|
+
"use strict";
|
|
12
|
+
|
|
13
|
+
Object.defineProperty(exports, "__esModule", {
|
|
14
|
+
value: true
|
|
15
|
+
});
|
|
16
|
+
exports.gates = gates;
|
|
17
|
+
exports.validateAndGetTableNames = validateAndGetTableNames;
|
|
18
|
+
|
|
19
|
+
var _graphqlTag = _interopRequireDefault(require("graphql-tag"));
|
|
20
|
+
|
|
21
|
+
var _cliColumns = _interopRequireDefault(require("cli-columns"));
|
|
22
|
+
|
|
23
|
+
var _chalk = _interopRequireDefault(require("chalk"));
|
|
24
|
+
|
|
25
|
+
var _debug = _interopRequireDefault(require("debug"));
|
|
26
|
+
|
|
27
|
+
var _enquirer = require("enquirer");
|
|
28
|
+
|
|
29
|
+
var _command = _interopRequireDefault(require("../lib/cli/command"));
|
|
30
|
+
|
|
31
|
+
var _dbFileImport = require("../lib/site-import/db-file-import");
|
|
32
|
+
|
|
33
|
+
var _status = require("../lib/site-import/status");
|
|
34
|
+
|
|
35
|
+
var _clientFileUploader = require("../lib/client-file-uploader");
|
|
36
|
+
|
|
37
|
+
var _tracker = require("../lib/tracker");
|
|
38
|
+
|
|
39
|
+
var _sql = require("../lib/validations/sql");
|
|
40
|
+
|
|
41
|
+
var _siteType = require("../lib/validations/site-type");
|
|
42
|
+
|
|
43
|
+
var _searchAndReplace = require("../lib/search-and-replace");
|
|
44
|
+
|
|
45
|
+
var _api = _interopRequireDefault(require("../lib/api"));
|
|
46
|
+
|
|
47
|
+
var exit = _interopRequireWildcard(require("../lib/cli/exit"));
|
|
48
|
+
|
|
49
|
+
var _lineByLine = require("../lib/validations/line-by-line");
|
|
50
|
+
|
|
51
|
+
var _format = require("../lib/cli/format");
|
|
52
|
+
|
|
53
|
+
var _progress = require("../lib/cli/progress");
|
|
54
|
+
|
|
55
|
+
var _isMultiSite = require("../lib/validations/is-multi-site");
|
|
56
|
+
|
|
57
|
+
var _rollbar = require("../lib/rollbar");
|
|
58
|
+
|
|
59
|
+
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); }
|
|
60
|
+
|
|
61
|
+
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; }
|
|
62
|
+
|
|
63
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Internal dependencies
|
|
67
|
+
*/
|
|
68
|
+
const appQuery = `
|
|
69
|
+
id,
|
|
70
|
+
name,
|
|
71
|
+
type,
|
|
72
|
+
organization { id, name },
|
|
73
|
+
environments{
|
|
74
|
+
id
|
|
75
|
+
appId
|
|
76
|
+
type
|
|
77
|
+
name
|
|
78
|
+
launched
|
|
79
|
+
isK8sResident
|
|
80
|
+
syncProgress { status }
|
|
81
|
+
primaryDomain { name }
|
|
82
|
+
importStatus {
|
|
83
|
+
dbOperationInProgress
|
|
84
|
+
importInProgress
|
|
85
|
+
}
|
|
86
|
+
wpSites {
|
|
87
|
+
nodes {
|
|
88
|
+
homeUrl
|
|
89
|
+
id
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
`;
|
|
94
|
+
const START_IMPORT_MUTATION = (0, _graphqlTag.default)`
|
|
95
|
+
mutation StartImport($input: AppEnvironmentImportInput) {
|
|
96
|
+
startImport(input: $input) {
|
|
97
|
+
app {
|
|
98
|
+
id
|
|
99
|
+
name
|
|
100
|
+
}
|
|
101
|
+
message
|
|
102
|
+
success
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
`;
|
|
106
|
+
const debug = (0, _debug.default)('@automattic/vip:bin:vip-import-sql');
|
|
107
|
+
const SQL_IMPORT_PREFLIGHT_PROGRESS_STEPS = [{
|
|
108
|
+
id: 'replace',
|
|
109
|
+
name: 'Performing Search and Replace'
|
|
110
|
+
}, {
|
|
111
|
+
id: 'upload',
|
|
112
|
+
name: 'Uploading file'
|
|
113
|
+
}, {
|
|
114
|
+
id: 'queue_import',
|
|
115
|
+
name: 'Queueing Import'
|
|
116
|
+
}];
|
|
117
|
+
|
|
118
|
+
async function gates(app, env, fileName) {
|
|
119
|
+
const {
|
|
120
|
+
id: envId,
|
|
121
|
+
appId
|
|
122
|
+
} = env;
|
|
123
|
+
|
|
124
|
+
const track = _tracker.trackEventWithEnv.bind(null, appId, envId);
|
|
125
|
+
|
|
126
|
+
if (!(0, _dbFileImport.currentUserCanImportForApp)(app)) {
|
|
127
|
+
await track('import_sql_command_error', {
|
|
128
|
+
error_type: 'unauthorized'
|
|
129
|
+
});
|
|
130
|
+
exit.withError('The currently authenticated account does not have permission to perform a SQL import.');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (!(0, _dbFileImport.isSupportedApp)(app)) {
|
|
134
|
+
await track('import_sql_command_error', {
|
|
135
|
+
error_type: 'unsupported-app'
|
|
136
|
+
});
|
|
137
|
+
exit.withError('The type of application you specified does not currently support SQL imports.');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
try {
|
|
141
|
+
await (0, _clientFileUploader.checkFileAccess)(fileName);
|
|
142
|
+
} catch (err) {
|
|
143
|
+
await track('import_sql_command_error', {
|
|
144
|
+
error_type: 'sqlfile-unreadable'
|
|
145
|
+
});
|
|
146
|
+
exit.withError(`File '${fileName}' does not exist or is not readable.`);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (!(await (0, _clientFileUploader.isFile)(fileName))) {
|
|
150
|
+
await track('import_sql_command_error', {
|
|
151
|
+
error_type: 'sqlfile-notfile'
|
|
152
|
+
});
|
|
153
|
+
exit.withError(`Path '${fileName}' is not a file.`);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const fileSize = await (0, _clientFileUploader.getFileSize)(fileName);
|
|
157
|
+
|
|
158
|
+
if (!fileSize) {
|
|
159
|
+
await track('import_sql_command_error', {
|
|
160
|
+
error_type: 'sqlfile-empty'
|
|
161
|
+
});
|
|
162
|
+
exit.withError(`File '${fileName}' is empty.`);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const maxFileSize = env !== null && env !== void 0 && env.launched ? _dbFileImport.SQL_IMPORT_FILE_SIZE_LIMIT_LAUNCHED : _dbFileImport.SQL_IMPORT_FILE_SIZE_LIMIT;
|
|
166
|
+
|
|
167
|
+
if (fileSize > maxFileSize) {
|
|
168
|
+
await track('import_sql_command_error', {
|
|
169
|
+
error_type: 'sqlfile-toobig',
|
|
170
|
+
file_size: fileSize,
|
|
171
|
+
launched: !!(env !== null && env !== void 0 && env.launched)
|
|
172
|
+
});
|
|
173
|
+
exit.withError(`The sql import file size (${fileSize} bytes) exceeds the limit (${maxFileSize} bytes).` + (env.launched ? ' Note: This limit is lower for launched environments to maintain site stability.' : '') + '\n\nPlease split it into multiple files or contact support for assistance.');
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (!(env !== null && env !== void 0 && env.importStatus)) {
|
|
177
|
+
await track('import_sql_command_error', {
|
|
178
|
+
error_type: 'empty-import-status'
|
|
179
|
+
});
|
|
180
|
+
exit.withError('Could not determine the import status for this environment. Check the app/environment and if the problem persists, contact support for assistance');
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const {
|
|
184
|
+
importStatus: {
|
|
185
|
+
dbOperationInProgress,
|
|
186
|
+
importInProgress
|
|
187
|
+
}
|
|
188
|
+
} = env;
|
|
189
|
+
|
|
190
|
+
if (importInProgress) {
|
|
191
|
+
await track('import_sql_command_error', {
|
|
192
|
+
error_type: 'existing-import'
|
|
193
|
+
});
|
|
194
|
+
exit.withError('There is already an import in progress.\n\nYou can view the status with command:\n vip import sql status');
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (dbOperationInProgress) {
|
|
198
|
+
await track('import_sql_command_error', {
|
|
199
|
+
error_type: 'existing-dbop'
|
|
200
|
+
});
|
|
201
|
+
exit.withError('There is already a database operation in progress. Please try again later.');
|
|
202
|
+
}
|
|
203
|
+
} // Command examples for the `vip import sql` help prompt
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
const examples = [// `sql` subcommand
|
|
207
|
+
{
|
|
208
|
+
usage: 'vip import sql @mysite.develop <file.sql>',
|
|
209
|
+
description: 'Import the given SQL file to your site'
|
|
210
|
+
}, // `search-replace` flag
|
|
211
|
+
{
|
|
212
|
+
usage: 'vip import sql @mysite.develop <file.sql> --search-replace="from,to"',
|
|
213
|
+
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'
|
|
214
|
+
}, // `in-place` flag
|
|
215
|
+
{
|
|
216
|
+
usage: 'vip import sql @mysite.develop <file.sql> --search-replace="from,to" --in-place',
|
|
217
|
+
description: 'Search and Replace on the input <file.sql>, then import the replaced file to your site'
|
|
218
|
+
}, // `output` flag
|
|
219
|
+
{
|
|
220
|
+
usage: 'vip import sql @mysite.develop <file.sql> --search-replace="from,to" --output="<output.sql>"',
|
|
221
|
+
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'
|
|
222
|
+
}, // `sql status` subcommand
|
|
223
|
+
{
|
|
224
|
+
usage: 'vip import sql status @mysite.develop',
|
|
225
|
+
description: 'Check the status of the most recent import. If an import is running, this will poll until it is complete.'
|
|
226
|
+
}];
|
|
227
|
+
|
|
228
|
+
const promptToContinue = async ({
|
|
229
|
+
launched,
|
|
230
|
+
formattedEnvironment,
|
|
231
|
+
track,
|
|
232
|
+
domain
|
|
233
|
+
}) => {
|
|
234
|
+
console.log();
|
|
235
|
+
const promptToMatch = domain.toUpperCase();
|
|
236
|
+
const promptResponse = await (0, _enquirer.prompt)({
|
|
237
|
+
type: 'input',
|
|
238
|
+
name: 'confirmedDomain',
|
|
239
|
+
message: `You are about to import the above tables into a ${launched ? 'launched' : 'un-launched'} ${formattedEnvironment} site ${_chalk.default.yellow(domain)}.\nType '${_chalk.default.yellow(promptToMatch)}' (without the quotes) to continue:\n`
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
if (promptResponse.confirmedDomain !== promptToMatch) {
|
|
243
|
+
await track('import_sql_unexpected_tables');
|
|
244
|
+
exit.withError('The input did not match the expected environment label. Import aborted.');
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
async function validateAndGetTableNames({
|
|
249
|
+
skipValidate,
|
|
250
|
+
appId,
|
|
251
|
+
envId,
|
|
252
|
+
fileNameToUpload
|
|
253
|
+
}) {
|
|
254
|
+
const validations = [_sql.staticSqlValidations, _siteType.siteTypeValidations];
|
|
255
|
+
|
|
256
|
+
if (skipValidate) {
|
|
257
|
+
console.log('Skipping SQL file validation.');
|
|
258
|
+
return [];
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
try {
|
|
262
|
+
await (0, _lineByLine.fileLineValidations)(appId, envId, fileNameToUpload, validations);
|
|
263
|
+
} catch (validateErr) {
|
|
264
|
+
console.log('');
|
|
265
|
+
exit.withError(`${validateErr.message}
|
|
266
|
+
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
|
+
} // this can only be called after static validation of the SQL file
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
return (0, _sql.getTableNames)();
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const displayPlaybook = ({
|
|
275
|
+
launched,
|
|
276
|
+
tableNames,
|
|
277
|
+
searchReplace,
|
|
278
|
+
fileName,
|
|
279
|
+
domain,
|
|
280
|
+
formattedEnvironment,
|
|
281
|
+
isMultiSite,
|
|
282
|
+
app
|
|
283
|
+
}) => {
|
|
284
|
+
console.log();
|
|
285
|
+
console.log(` importing: ${_chalk.default.blueBright(fileName)}`);
|
|
286
|
+
console.log(` to: ${_chalk.default.cyan(domain)}`);
|
|
287
|
+
console.log(` site: ${app.name} (${formattedEnvironment})`);
|
|
288
|
+
|
|
289
|
+
if (searchReplace !== null && searchReplace !== void 0 && searchReplace.length) {
|
|
290
|
+
const output = (from, to) => {
|
|
291
|
+
const message = ` s-r: ${_chalk.default.blue(from)} -> ${_chalk.default.blue(to)}`;
|
|
292
|
+
console.log(message);
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
(0, _format.formatSearchReplaceValues)(searchReplace, output);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
let siteArray = [];
|
|
299
|
+
|
|
300
|
+
if (isMultiSite) {
|
|
301
|
+
var _app$environments$, _app$environments$$wp;
|
|
302
|
+
|
|
303
|
+
// eslint-disable-next-line no-multi-spaces
|
|
304
|
+
console.log(` multisite: ${isMultiSite.toString()}`);
|
|
305
|
+
siteArray = app === null || app === void 0 ? void 0 : (_app$environments$ = app.environments[0]) === null || _app$environments$ === void 0 ? void 0 : (_app$environments$$wp = _app$environments$.wpSites) === null || _app$environments$$wp === void 0 ? void 0 : _app$environments$$wp.nodes;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (!tableNames.length) {
|
|
309
|
+
debug('Validation was skipped, no playbook information will be displayed');
|
|
310
|
+
} else {
|
|
311
|
+
// output the table names
|
|
312
|
+
console.log();
|
|
313
|
+
|
|
314
|
+
if (!isMultiSite) {
|
|
315
|
+
console.log('Below are a list of Tables that will be imported by this process:');
|
|
316
|
+
console.log((0, _cliColumns.default)(tableNames));
|
|
317
|
+
} else {
|
|
318
|
+
var _siteArray;
|
|
319
|
+
|
|
320
|
+
// we have siteArray from the API, use it and the table names together
|
|
321
|
+
if (siteArray === 'undefined' || !siteArray) {
|
|
322
|
+
console.log(_chalk.default.yellowBright('Unable to determine the subsites affected by this import, please proceed only if you are confident on the contents in the import file.'));
|
|
323
|
+
return;
|
|
324
|
+
} else if (!((_siteArray = siteArray) !== null && _siteArray !== void 0 && _siteArray.length)) {
|
|
325
|
+
throw new Error('There were no sites in your multisite installation');
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const multiSiteBreakdown = siteArray.map(wpSite => {
|
|
329
|
+
let siteRegex;
|
|
330
|
+
|
|
331
|
+
if (wpSite.id === 1) {
|
|
332
|
+
siteRegex = /wp_[a-z]+/i;
|
|
333
|
+
} else {
|
|
334
|
+
siteRegex = new RegExp(`wp_${wpSite.id}_[a-z]+`, 'i');
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const tableNamesInGroup = tableNames.filter(name => siteRegex.test(name));
|
|
338
|
+
return {
|
|
339
|
+
id: wpSite.id,
|
|
340
|
+
url: wpSite.homeUrl,
|
|
341
|
+
tables: tableNamesInGroup
|
|
342
|
+
};
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
if (launched) {
|
|
346
|
+
console.log(_chalk.default.yellowBright('You are updating tables in a launched multi site installation. Sites in the same network may have their performance impacted by this operation.'));
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
console.log(_chalk.default.yellow('The following sites will be affected by the import:'));
|
|
350
|
+
multiSiteBreakdown.map(siteObject => {
|
|
351
|
+
console.log();
|
|
352
|
+
console.log(_chalk.default.blueBright(`Blog with ID ${siteObject.id} and URL ${siteObject.url} will import the following tables:`));
|
|
353
|
+
console.log((0, _cliColumns.default)(siteObject.tables));
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
(0, _command.default)({
|
|
360
|
+
appContext: true,
|
|
361
|
+
appQuery,
|
|
362
|
+
envContext: true,
|
|
363
|
+
requiredArgs: 1,
|
|
364
|
+
module: 'import-sql',
|
|
365
|
+
requireConfirm: 'Are you sure you want to import the contents of the provided SQL file?',
|
|
366
|
+
skipConfirmPrompt: true
|
|
367
|
+
}).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', 'Perform Search and Replace on the specified SQL file').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) => {
|
|
368
|
+
var _env$primaryDomain;
|
|
369
|
+
|
|
370
|
+
const {
|
|
371
|
+
app,
|
|
372
|
+
env
|
|
373
|
+
} = opts;
|
|
374
|
+
let {
|
|
375
|
+
skipValidate,
|
|
376
|
+
searchReplace
|
|
377
|
+
} = opts;
|
|
378
|
+
const {
|
|
379
|
+
id: envId,
|
|
380
|
+
appId
|
|
381
|
+
} = env;
|
|
382
|
+
const [fileName] = arg;
|
|
383
|
+
const isMultiSite = await (0, _isMultiSite.isMultiSiteInSiteMeta)(appId, envId);
|
|
384
|
+
let fileMeta = await (0, _clientFileUploader.getFileMeta)(fileName);
|
|
385
|
+
|
|
386
|
+
if (fileMeta.isCompressed) {
|
|
387
|
+
console.log(_chalk.default.yellowBright('You are importing a compressed file. Validation and search-replace operation will be skipped.'));
|
|
388
|
+
skipValidate = true;
|
|
389
|
+
searchReplace = undefined;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
debug('Options: ', opts);
|
|
393
|
+
debug('Args: ', arg);
|
|
394
|
+
|
|
395
|
+
const track = _tracker.trackEventWithEnv.bind(null, appId, envId);
|
|
396
|
+
|
|
397
|
+
await track('import_sql_command_execute'); // // halt operation of the import based on some rules
|
|
398
|
+
|
|
399
|
+
await gates(app, env, fileName); // Log summary of import details
|
|
400
|
+
|
|
401
|
+
const domain = env !== null && env !== void 0 && (_env$primaryDomain = env.primaryDomain) !== null && _env$primaryDomain !== void 0 && _env$primaryDomain.name ? env.primaryDomain.name : `#${env.id}`;
|
|
402
|
+
const formattedEnvironment = (0, _format.formatEnvironment)(opts.env.type);
|
|
403
|
+
const launched = opts.env.launched;
|
|
404
|
+
let fileNameToUpload = fileName; // SQL file validations
|
|
405
|
+
|
|
406
|
+
const tableNames = await validateAndGetTableNames({
|
|
407
|
+
skipValidate,
|
|
408
|
+
appId,
|
|
409
|
+
envId,
|
|
410
|
+
fileNameToUpload
|
|
411
|
+
}); // display playbook of what will happen during execution
|
|
412
|
+
|
|
413
|
+
displayPlaybook({
|
|
414
|
+
launched,
|
|
415
|
+
tableNames,
|
|
416
|
+
searchReplace,
|
|
417
|
+
fileName,
|
|
418
|
+
domain,
|
|
419
|
+
formattedEnvironment,
|
|
420
|
+
isMultiSite,
|
|
421
|
+
app
|
|
422
|
+
}); // PROMPT TO PROCEED WITH THE IMPORT
|
|
423
|
+
|
|
424
|
+
await promptToContinue({
|
|
425
|
+
launched,
|
|
426
|
+
formattedEnvironment,
|
|
427
|
+
track,
|
|
428
|
+
domain
|
|
429
|
+
});
|
|
430
|
+
/**
|
|
431
|
+
* =========== WARNING =============
|
|
432
|
+
*
|
|
433
|
+
* NO `console.log` after this point!
|
|
434
|
+
* Yes, even inside called functions.
|
|
435
|
+
* It will break the progress printing.
|
|
436
|
+
*
|
|
437
|
+
* =========== WARNING =============
|
|
438
|
+
*/
|
|
439
|
+
|
|
440
|
+
const progressTracker = new _progress.ProgressTracker(SQL_IMPORT_PREFLIGHT_PROGRESS_STEPS);
|
|
441
|
+
let status = 'running';
|
|
442
|
+
|
|
443
|
+
const setProgressTrackerPrefixAndSuffix = () => {
|
|
444
|
+
progressTracker.prefix = `
|
|
445
|
+
=============================================================
|
|
446
|
+
Processing the SQL import for your environment...
|
|
447
|
+
`;
|
|
448
|
+
progressTracker.suffix = `\n${(0, _format.getGlyphForStatus)(status, progressTracker.runningSprite)} ${status === 'running' ? 'Loading remaining steps' : ''}`; // TODO: maybe use progress tracker status
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
const failWithError = failureError => {
|
|
452
|
+
status = 'failed';
|
|
453
|
+
setProgressTrackerPrefixAndSuffix();
|
|
454
|
+
progressTracker.stopPrinting();
|
|
455
|
+
progressTracker.print({
|
|
456
|
+
clearAfter: true
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
_rollbar.rollbar.error(failureError);
|
|
460
|
+
|
|
461
|
+
exit.withError(failureError);
|
|
462
|
+
};
|
|
463
|
+
|
|
464
|
+
progressTracker.startPrinting(setProgressTrackerPrefixAndSuffix); // Run Search and Replace if the --search-replace flag was provided
|
|
465
|
+
|
|
466
|
+
if (searchReplace && searchReplace.length) {
|
|
467
|
+
progressTracker.stepRunning('replace');
|
|
468
|
+
const {
|
|
469
|
+
outputFileName
|
|
470
|
+
} = await (0, _searchAndReplace.searchAndReplace)(fileName, searchReplace, {
|
|
471
|
+
isImport: true,
|
|
472
|
+
inPlace: opts.inPlace,
|
|
473
|
+
output: true
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
if (typeof outputFileName !== 'string') {
|
|
477
|
+
progressTracker.stepFailed('replace');
|
|
478
|
+
return failWithError('Unable to determine location of the intermediate search & replace file.');
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
fileNameToUpload = outputFileName;
|
|
482
|
+
fileMeta = await (0, _clientFileUploader.getFileMeta)(fileNameToUpload);
|
|
483
|
+
progressTracker.stepSuccess('replace');
|
|
484
|
+
} else {
|
|
485
|
+
progressTracker.stepSkipped('replace');
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
progressTracker.stepRunning('upload'); // Call the Public API
|
|
489
|
+
|
|
490
|
+
const api = await (0, _api.default)();
|
|
491
|
+
const startImportVariables = {};
|
|
492
|
+
|
|
493
|
+
const progressCallback = percentage => {
|
|
494
|
+
progressTracker.setUploadPercentage(percentage);
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
fileMeta.fileName = fileNameToUpload;
|
|
498
|
+
|
|
499
|
+
try {
|
|
500
|
+
const {
|
|
501
|
+
fileMeta: {
|
|
502
|
+
basename
|
|
503
|
+
},
|
|
504
|
+
md5,
|
|
505
|
+
result
|
|
506
|
+
} = await (0, _clientFileUploader.uploadImportSqlFileToS3)({
|
|
507
|
+
app,
|
|
508
|
+
env,
|
|
509
|
+
fileMeta,
|
|
510
|
+
progressCallback
|
|
511
|
+
});
|
|
512
|
+
startImportVariables.input = {
|
|
513
|
+
id: app.id,
|
|
514
|
+
environmentId: env.id,
|
|
515
|
+
basename: basename,
|
|
516
|
+
md5: md5,
|
|
517
|
+
searchReplace: []
|
|
518
|
+
};
|
|
519
|
+
|
|
520
|
+
if (searchReplace) {
|
|
521
|
+
let pairs = searchReplace;
|
|
522
|
+
|
|
523
|
+
if (!Array.isArray(pairs)) {
|
|
524
|
+
pairs = [searchReplace];
|
|
525
|
+
} // determine all the replacements required
|
|
526
|
+
|
|
527
|
+
|
|
528
|
+
const replacementsArr = pairs.map(pair => pair.split(',').map(str => str.trim()));
|
|
529
|
+
startImportVariables.input.searchReplace = replacementsArr.map(arr => {
|
|
530
|
+
return {
|
|
531
|
+
from: arr[0],
|
|
532
|
+
to: arr[1]
|
|
533
|
+
};
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
debug({
|
|
538
|
+
basename,
|
|
539
|
+
md5,
|
|
540
|
+
result,
|
|
541
|
+
startImportVariables
|
|
542
|
+
});
|
|
543
|
+
debug('Upload complete. Initiating the import.');
|
|
544
|
+
progressTracker.stepSuccess('upload');
|
|
545
|
+
await track('import_sql_upload_complete');
|
|
546
|
+
} catch (uploadError) {
|
|
547
|
+
await track('import_sql_command_error', {
|
|
548
|
+
error_type: 'upload_failed',
|
|
549
|
+
upload_error: uploadError
|
|
550
|
+
});
|
|
551
|
+
progressTracker.stepFailed('upload');
|
|
552
|
+
return failWithError(uploadError);
|
|
553
|
+
} // Start the import
|
|
554
|
+
|
|
555
|
+
|
|
556
|
+
try {
|
|
557
|
+
const startImportResults = await api.mutate({
|
|
558
|
+
mutation: START_IMPORT_MUTATION,
|
|
559
|
+
variables: startImportVariables
|
|
560
|
+
});
|
|
561
|
+
debug({
|
|
562
|
+
startImportResults
|
|
563
|
+
});
|
|
564
|
+
} catch (gqlErr) {
|
|
565
|
+
progressTracker.stepFailed('queue_import');
|
|
566
|
+
await track('import_sql_command_error', {
|
|
567
|
+
error_type: 'StartImport-failed',
|
|
568
|
+
gql_err: gqlErr
|
|
569
|
+
});
|
|
570
|
+
progressTracker.stepFailed('queue_import');
|
|
571
|
+
return failWithError(`StartImport call failed: ${gqlErr}`);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
progressTracker.stepSuccess('queue_import');
|
|
575
|
+
await (0, _status.importSqlCheckStatus)({
|
|
576
|
+
app,
|
|
577
|
+
env,
|
|
578
|
+
progressTracker
|
|
579
|
+
});
|
|
580
|
+
});
|