@automattic/vip 3.8.4 → 3.8.6
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/dist/bin/vip-import-media-abort.js +13 -5
- package/dist/bin/vip-import-media-status.js +14 -3
- package/dist/bin/vip-import-media.js +16 -9
- package/dist/bin/vip-import-sql-status.js +10 -2
- package/dist/bin/vip-import-sql.js +29 -27
- package/dist/bin/vip-import-validate-files.js +6 -5
- package/dist/bin/vip-import-validate-sql.js +5 -3
- package/dist/bin/vip-import.js +1 -1
- package/dist/bin/vip-logs.js +27 -4
- package/dist/bin/vip-search-replace.js +1 -1
- package/dist/bin/vip-sync.js +22 -22
- package/dist/bin/vip-validate-preflight.js +7 -7
- package/dist/bin/vip-wp.js +27 -8
- package/dist/bin/vip.js +1 -1
- package/dist/commands/dev-env-import-sql.js +1 -1
- package/dist/commands/dev-env-sync-sql.js +59 -12
- package/dist/lib/cli/command.js +1 -1
- package/dist/lib/cli/format.js +1 -1
- package/dist/lib/config/software.js +8 -5
- package/dist/lib/dev-environment/dev-environment-lando.js +36 -28
- package/docs/CHANGELOG.md +41 -0
- package/npm-shrinkwrap.json +1461 -1527
- package/package.json +9 -10
|
@@ -15,6 +15,7 @@ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e;
|
|
|
15
15
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
16
16
|
// eslint-disable-next-line no-duplicate-imports
|
|
17
17
|
|
|
18
|
+
const usage = 'vip import media abort';
|
|
18
19
|
const appQuery = `
|
|
19
20
|
id,
|
|
20
21
|
name,
|
|
@@ -44,16 +45,23 @@ const ABORT_IMPORT_MUTATION = (0, _graphqlTag.default)`
|
|
|
44
45
|
}
|
|
45
46
|
}
|
|
46
47
|
`;
|
|
48
|
+
|
|
49
|
+
// Command examples
|
|
50
|
+
const examples = [{
|
|
51
|
+
usage: `vip @example-app.production import media abort`,
|
|
52
|
+
description: 'Abort the media file import that is currently in progress on the production environment of the "example-app" application.'
|
|
53
|
+
}];
|
|
47
54
|
(0, _command.default)({
|
|
48
55
|
appContext: true,
|
|
49
56
|
appQuery,
|
|
50
57
|
envContext: true,
|
|
51
58
|
requiredArgs: 0,
|
|
59
|
+
usage,
|
|
52
60
|
requireConfirm: `
|
|
53
|
-
${_chalk.default.red.bold(
|
|
54
|
-
${_chalk.default.red.bold('Are you sure you want to abort this
|
|
61
|
+
${_chalk.default.red.bold('Running this command will stop the currently running media import. The import process cannot be resumed.')}
|
|
62
|
+
${_chalk.default.red.bold('Are you sure you want to abort this media import?')}
|
|
55
63
|
`
|
|
56
|
-
}).argv(process.argv, async (arg, {
|
|
64
|
+
}).examples(examples).argv(process.argv, async (arg, {
|
|
57
65
|
app,
|
|
58
66
|
env
|
|
59
67
|
}) => {
|
|
@@ -66,14 +74,14 @@ ${_chalk.default.red.bold('Are you sure you want to abort this Media Import?')}
|
|
|
66
74
|
await track('import_media_command_error', {
|
|
67
75
|
errorType: 'unsupported-app'
|
|
68
76
|
});
|
|
69
|
-
exit.withError('The type of application you specified does not currently support
|
|
77
|
+
exit.withError('The type of application you specified does not currently support media file imports.');
|
|
70
78
|
}
|
|
71
79
|
const api = (0, _api.default)();
|
|
72
80
|
await track('import_media_abort_execute');
|
|
73
81
|
const progressTracker = new _progress.MediaImportProgressTracker([]);
|
|
74
82
|
progressTracker.prefix = `
|
|
75
83
|
=============================================================
|
|
76
|
-
Aborting
|
|
84
|
+
Aborting this media import.
|
|
77
85
|
`;
|
|
78
86
|
try {
|
|
79
87
|
await api.mutate({
|
|
@@ -25,12 +25,23 @@ const appQuery = `
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
`;
|
|
28
|
+
const usage = 'vip import media status';
|
|
29
|
+
|
|
30
|
+
// Command examples
|
|
31
|
+
const examples = [{
|
|
32
|
+
usage: 'vip @example-app.production import media status',
|
|
33
|
+
description: 'Check the status of the most recent media import.\n' + ' * If the import is still in progress, the command will poll until the import is complete.\n' + ' * If the import is already complete, the command will download an error log for the most recent import.'
|
|
34
|
+
}, {
|
|
35
|
+
usage: 'vip @example-app.production import media status --saveErrorLog --exportFileErrorsToJson',
|
|
36
|
+
description: 'Check the status of the most recent media import and automatically download the error log in JSON format.'
|
|
37
|
+
}];
|
|
28
38
|
(0, _command.default)({
|
|
29
39
|
appContext: true,
|
|
30
40
|
appQuery,
|
|
31
41
|
envContext: true,
|
|
32
|
-
requiredArgs: 0
|
|
33
|
-
|
|
42
|
+
requiredArgs: 0,
|
|
43
|
+
usage
|
|
44
|
+
}).option('exportFileErrorsToJson', 'Format an error log in JSON. Default is TXT.').option('saveErrorLog', 'Skip the confirmation prompt and download an error log automatically.', 'prompt').examples(examples).argv(process.argv, async (arg, {
|
|
34
45
|
app,
|
|
35
46
|
env,
|
|
36
47
|
exportFileErrorsToJson,
|
|
@@ -45,7 +56,7 @@ const appQuery = `
|
|
|
45
56
|
await track('import_media_command_error', {
|
|
46
57
|
errorType: 'unsupported-app'
|
|
47
58
|
});
|
|
48
|
-
exit.withError('The type of application you specified does not currently support this feature');
|
|
59
|
+
exit.withError('The type of application you specified does not currently support this feature.');
|
|
49
60
|
}
|
|
50
61
|
await track('import_media_check_status_command_execute');
|
|
51
62
|
const progressTracker = new _progress.MediaImportProgressTracker([]);
|
|
@@ -40,22 +40,28 @@ const START_IMPORT_MUTATION = (0, _graphqlTag.default)`
|
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
`;
|
|
43
|
+
const usage = 'vip import media';
|
|
43
44
|
const debug = (0, _debug.default)('vip:vip-import-media');
|
|
44
45
|
|
|
45
46
|
// Command examples for the `vip import media` help prompt
|
|
46
47
|
const examples = [{
|
|
47
|
-
usage: 'vip import media
|
|
48
|
-
description: '
|
|
48
|
+
usage: 'vip @example-app.production import media https://example.com/uploads.tar.gz',
|
|
49
|
+
description: 'Import the archived file "uploads.tar.gz" from a publicly accessible URL to a production environment.'
|
|
50
|
+
},
|
|
51
|
+
// Format error logs
|
|
52
|
+
{
|
|
53
|
+
usage: 'vip @example-app.production import media https://example.com/uploads.tar.gz --overwriteExistingFiles --exportFileErrorsToJson',
|
|
54
|
+
description: 'Overwrite existing files with the imported files if they have the same file path and name, and format the error log for the import in JSON.'
|
|
49
55
|
},
|
|
50
56
|
// `media status` subcommand
|
|
51
57
|
{
|
|
52
|
-
usage: 'vip import media status
|
|
53
|
-
description: 'Check the status of the most recent
|
|
58
|
+
usage: 'vip @example-app.production import media status',
|
|
59
|
+
description: 'Check the status of the most recent media import.'
|
|
54
60
|
},
|
|
55
61
|
// `media abort` subcommand
|
|
56
62
|
{
|
|
57
|
-
usage: 'vip import media abort
|
|
58
|
-
description: 'Abort
|
|
63
|
+
usage: 'vip @example-app.production import media abort',
|
|
64
|
+
description: 'Abort the currently running media import.'
|
|
59
65
|
}];
|
|
60
66
|
function isSupportedUrl(urlToTest) {
|
|
61
67
|
let url;
|
|
@@ -72,14 +78,15 @@ function isSupportedUrl(urlToTest) {
|
|
|
72
78
|
envContext: true,
|
|
73
79
|
module: 'import-media',
|
|
74
80
|
requiredArgs: 1,
|
|
81
|
+
usage,
|
|
75
82
|
requireConfirm: `
|
|
76
83
|
${_chalk.default.red.bold("NOTE: If the provided archive's directory structure contains an `uploads/` directory,")}
|
|
77
84
|
${_chalk.default.red.bold('only the files present inside that directory will be imported and the rest will be ignored.')}
|
|
78
85
|
${_chalk.default.red.bold('If no `uploads/` directory is found, all files will be imported, as is.')}
|
|
79
86
|
|
|
80
|
-
Are you sure you want to import the contents of the
|
|
87
|
+
Are you sure you want to import the contents of the URL?
|
|
81
88
|
`
|
|
82
|
-
}).command('status', 'Check the status of the
|
|
89
|
+
}).command('status', 'Check the status of a currently running media import or retrieve an error log of the most recent media import.').command('abort', 'Abort the media import currently in progress.').option('exportFileErrorsToJson', 'Format the error log in JSON. Default is TXT.').option('saveErrorLog', 'Skip the confirmation prompt and download an error log for the import automatically.').option('overwriteExistingFiles', 'Overwrite existing files with the imported files if they have the same path and file name.', false).option('importIntermediateImages', 'Include intermediate image files in the import.', false).examples(examples).argv(process.argv, async (args, opts) => {
|
|
83
90
|
const {
|
|
84
91
|
app,
|
|
85
92
|
env,
|
|
@@ -93,7 +100,7 @@ Are you sure you want to import the contents of the url?
|
|
|
93
100
|
console.log(_chalk.default.red(`
|
|
94
101
|
Error:
|
|
95
102
|
Invalid URL provided: ${url}
|
|
96
|
-
Please make sure that it is a publicly accessible web URL containing an archive of the media files to import
|
|
103
|
+
Please make sure that it is a publicly accessible web URL containing an archive of the media files to import.`));
|
|
97
104
|
return;
|
|
98
105
|
}
|
|
99
106
|
const track = _tracker.trackEventWithEnv.bind(null, app.id, env.id);
|
|
@@ -27,12 +27,20 @@ environments{
|
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
`;
|
|
30
|
+
const usage = 'vip import sql status';
|
|
31
|
+
|
|
32
|
+
// Command examples
|
|
33
|
+
const examples = [{
|
|
34
|
+
usage: 'vip @example-app.develop import sql status',
|
|
35
|
+
description: 'Check the status of the most recent SQL database import to the develop environment of the "example-app" application.\n' + ' * If the import is still in progress, the command will poll until the import is complete.'
|
|
36
|
+
}];
|
|
30
37
|
(0, _command.default)({
|
|
31
38
|
appContext: true,
|
|
32
39
|
appQuery,
|
|
33
40
|
envContext: true,
|
|
34
|
-
requiredArgs: 0
|
|
35
|
-
|
|
41
|
+
requiredArgs: 0,
|
|
42
|
+
usage
|
|
43
|
+
}).examples(examples).argv(process.argv, async (arg, {
|
|
36
44
|
app,
|
|
37
45
|
env
|
|
38
46
|
}) => {
|
|
@@ -66,16 +66,17 @@ const START_IMPORT_MUTATION = (0, _graphqlTag.default)`
|
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
`;
|
|
69
|
+
const usage = 'vip import sql';
|
|
69
70
|
const debug = (0, _debug.default)('@automattic/vip:bin:vip-import-sql');
|
|
70
71
|
const SQL_IMPORT_PREFLIGHT_PROGRESS_STEPS = [{
|
|
71
72
|
id: 'replace',
|
|
72
|
-
name: 'Performing
|
|
73
|
+
name: 'Performing search and replace'
|
|
73
74
|
}, {
|
|
74
75
|
id: 'upload',
|
|
75
76
|
name: 'Uploading file'
|
|
76
77
|
}, {
|
|
77
78
|
id: 'queue_import',
|
|
78
|
-
name: 'Queueing
|
|
79
|
+
name: 'Queueing import'
|
|
79
80
|
}];
|
|
80
81
|
|
|
81
82
|
/**
|
|
@@ -156,7 +157,7 @@ async function gates(app, env, fileMeta) {
|
|
|
156
157
|
await track('import_sql_command_error', {
|
|
157
158
|
error_type: 'empty-import-status'
|
|
158
159
|
});
|
|
159
|
-
exit.withError('Could not determine the import status for this environment. Check the app/environment and if the problem persists, contact support for assistance');
|
|
160
|
+
exit.withError('Could not determine the import status for this environment. Check the app/environment and if the problem persists, contact support for assistance.');
|
|
160
161
|
}
|
|
161
162
|
const {
|
|
162
163
|
importStatus: {
|
|
@@ -182,33 +183,33 @@ async function gates(app, env, fileMeta) {
|
|
|
182
183
|
const examples = [
|
|
183
184
|
// `sql` subcommand
|
|
184
185
|
{
|
|
185
|
-
usage: 'vip import sql
|
|
186
|
-
description: 'Import the
|
|
186
|
+
usage: 'vip @example-app.develop import sql file.sql',
|
|
187
|
+
description: 'Import the local SQL database backup file "file.sql" to the develop environment of the "example-app" application.'
|
|
187
188
|
},
|
|
188
189
|
// `search-replace` flag
|
|
189
190
|
{
|
|
190
|
-
usage: 'vip import sql
|
|
191
|
-
description: 'Perform a
|
|
191
|
+
usage: 'vip @example-app.develop import sql file.sql --search-replace="https://from.example.com,https://to.example.com"',
|
|
192
|
+
description: 'Perform a search and replace operation on the SQL database file during the import process.'
|
|
192
193
|
},
|
|
193
194
|
// `search-replace` flag
|
|
194
195
|
{
|
|
195
|
-
usage: 'vip import sql
|
|
196
|
-
description: 'Perform multiple search and replace
|
|
196
|
+
usage: 'vip @example-app.develop import sql file.sql --search-replace="from.example.com,to.example.com" --search-replace="example.com/from,example.com/to"',
|
|
197
|
+
description: 'Perform multiple search and replace operations on the SQL database file during the import process.'
|
|
197
198
|
},
|
|
198
199
|
// `in-place` flag
|
|
199
200
|
{
|
|
200
|
-
usage: 'vip import sql
|
|
201
|
-
description: '
|
|
201
|
+
usage: 'vip @example-app.develop import sql file.sql --search-replace="https://from.example.com,https://to.example.com" --in-place',
|
|
202
|
+
description: 'Perform a search and replace operation on "file.sql" locally, save the changes, then import the updated file.'
|
|
202
203
|
},
|
|
203
204
|
// `output` flag
|
|
204
205
|
{
|
|
205
|
-
usage: 'vip import sql
|
|
206
|
-
description: '
|
|
206
|
+
usage: 'vip @example-app.develop import sql file.sql --search-replace="https://from.example.com,https://to.example.com" --output="updated-file.sql"',
|
|
207
|
+
description: 'Create a copy of the imported file with the completed search and replace operations and save it locally to a file named "updated-file.sql".'
|
|
207
208
|
},
|
|
208
209
|
// `sql status` subcommand
|
|
209
210
|
{
|
|
210
|
-
usage: 'vip import sql status
|
|
211
|
-
description: 'Check the status of the most recent import
|
|
211
|
+
usage: 'vip @example-app.develop import sql status',
|
|
212
|
+
description: 'Check the status of the most recent SQL database import to the develop environment of the "example-app" application.\n' + ' * This will continue to poll until the import is complete.'
|
|
212
213
|
}];
|
|
213
214
|
const promptToContinue = async ({
|
|
214
215
|
launched,
|
|
@@ -224,7 +225,7 @@ const promptToContinue = async ({
|
|
|
224
225
|
const promptResponse = await (0, _enquirer.prompt)({
|
|
225
226
|
type: 'input',
|
|
226
227
|
name: 'confirmedDomain',
|
|
227
|
-
message: `You are about to import ${source} into
|
|
228
|
+
message: `You are about to import ${source} into the ${launched ? 'launched' : 'unlaunched'} ${formattedEnvironment} environment ${_chalk.default.yellow(domain)}.\nType '${_chalk.default.yellow(promptToMatch)}' (without the quotes) to continue:\n`
|
|
228
229
|
});
|
|
229
230
|
if (promptResponse.confirmedDomain.toUpperCase() !== promptToMatch) {
|
|
230
231
|
await track('import_sql_unexpected_tables');
|
|
@@ -253,7 +254,7 @@ async function validateAndGetTableNames({
|
|
|
253
254
|
} catch (validateErr) {
|
|
254
255
|
console.log('');
|
|
255
256
|
exit.withError(`${validateErr.message}\n
|
|
256
|
-
If you are confident the file does not contain unsupported statements, you can retry the command with the ${_chalk.default.yellow('--skip-validate')} option.
|
|
257
|
+
If you are confident that the file does not contain unsupported statements, you can retry the command with the ${_chalk.default.yellow('--skip-validate')} option.
|
|
257
258
|
`);
|
|
258
259
|
}
|
|
259
260
|
// this can only be called after static validation of the SQL file
|
|
@@ -289,20 +290,20 @@ const displayPlaybook = ({
|
|
|
289
290
|
siteArray = selectedEnvironmentObj?.wpSitesSDS?.nodes;
|
|
290
291
|
}
|
|
291
292
|
if (!tableNames.length) {
|
|
292
|
-
debug('Validation was skipped
|
|
293
|
+
debug('Validation was skipped. No playbook information will be displayed.');
|
|
293
294
|
} else {
|
|
294
295
|
// output the table names
|
|
295
296
|
console.log();
|
|
296
297
|
if (!isMultiSite) {
|
|
297
|
-
console.log('
|
|
298
|
+
console.log('Tables that will be imported by this process:');
|
|
298
299
|
console.log((0, _cliColumns.default)(tableNames));
|
|
299
300
|
} else {
|
|
300
301
|
// we have siteArray from the API, use it and the table names together
|
|
301
302
|
if (siteArray === 'undefined' || !siteArray) {
|
|
302
|
-
console.log(_chalk.default.yellowBright('Unable to determine the
|
|
303
|
+
console.log(_chalk.default.yellowBright('Unable to determine the network sites affected by this import. Please proceed only if you are confident that the contents of the file are valid for import.'));
|
|
303
304
|
return;
|
|
304
305
|
} else if (!siteArray?.length) {
|
|
305
|
-
throw new Error('There were no sites in your multisite installation');
|
|
306
|
+
throw new Error('There were no sites in your multisite installation.');
|
|
306
307
|
}
|
|
307
308
|
const multiSiteBreakdown = siteArray.map(wpSite => {
|
|
308
309
|
let siteRegex;
|
|
@@ -320,7 +321,7 @@ const displayPlaybook = ({
|
|
|
320
321
|
};
|
|
321
322
|
});
|
|
322
323
|
if (launched) {
|
|
323
|
-
console.log(_chalk.default.yellowBright('You are updating tables in a launched
|
|
324
|
+
console.log(_chalk.default.yellowBright('You are updating tables in a launched multisite environment. The performance of sites on the network might be impacted by this operation.'));
|
|
324
325
|
}
|
|
325
326
|
console.log(_chalk.default.yellow('The following sites will be affected by the import:'));
|
|
326
327
|
multiSiteBreakdown.forEach(siteObject => {
|
|
@@ -336,8 +337,9 @@ void (0, _command.default)({
|
|
|
336
337
|
appQuery,
|
|
337
338
|
envContext: true,
|
|
338
339
|
requiredArgs: 1,
|
|
339
|
-
module: 'import-sql'
|
|
340
|
-
|
|
340
|
+
module: 'import-sql',
|
|
341
|
+
usage
|
|
342
|
+
}).command('status', 'Check the status of a SQL database import currently in progress.').option('skip-validate', 'Do not perform file validation prior to import. If the file contains unsupported entries, the import is likely to fail.').option('search-replace', 'Search for a string in the SQL file and replace it with a new string. Separate the values by a comma only; no spaces (e.g. --search-replace=“from,to”).').option('in-place', 'Perform a search and replace operation on a local SQL file, save the results to the file, then import the updated file.').option('output', 'Create a local copy of the imported file with the completed search and replace operations. Ignored if the command includes --in-place, or excludes a --search-replace operation. Accepts a local file path.').examples(examples).argv(process.argv, async (arg, opts) => {
|
|
341
343
|
const {
|
|
342
344
|
app,
|
|
343
345
|
env
|
|
@@ -354,7 +356,7 @@ void (0, _command.default)({
|
|
|
354
356
|
const isMultiSite = await (0, _isMultiSite.isMultiSiteInSiteMeta)(appId, envId);
|
|
355
357
|
let fileMeta = await (0, _clientFileUploader.getFileMeta)(fileName);
|
|
356
358
|
if (fileMeta.isCompressed) {
|
|
357
|
-
console.log(_chalk.default.yellowBright('You are importing a compressed file. Validation and search-replace
|
|
359
|
+
console.log(_chalk.default.yellowBright('You are importing a compressed file. Validation and search-replace operations will be skipped.'));
|
|
358
360
|
skipValidate = true;
|
|
359
361
|
searchReplace = undefined;
|
|
360
362
|
}
|
|
@@ -441,11 +443,11 @@ Processing the SQL import for your environment...
|
|
|
441
443
|
} = await (0, _searchAndReplace.searchAndReplace)(fileName, searchReplace, {
|
|
442
444
|
isImport: true,
|
|
443
445
|
inPlace: opts.inPlace,
|
|
444
|
-
output: true
|
|
446
|
+
output: opts.output ?? true // "true" creates a temp output file instead of printing to stdout, as we need to upload the output to S3.
|
|
445
447
|
});
|
|
446
448
|
if (typeof outputFileName !== 'string') {
|
|
447
449
|
progressTracker.stepFailed('replace');
|
|
448
|
-
return failWithError('Unable to determine location of the intermediate search
|
|
450
|
+
return failWithError('Unable to determine location of the intermediate search and replace file.');
|
|
449
451
|
}
|
|
450
452
|
fileNameToUpload = outputFileName;
|
|
451
453
|
fileMeta = await (0, _clientFileUploader.getFileMeta)(fileNameToUpload);
|
|
@@ -29,7 +29,7 @@ async function vipImportValidateFilesCmd(arg = []) {
|
|
|
29
29
|
const filePath = arg.path; // Extract the path of the file
|
|
30
30
|
|
|
31
31
|
if (!(await (0, _vipImportValidateFiles.isDirectory)(filePath))) {
|
|
32
|
-
console.error(_chalk.default.red('✕ Error:'), 'The given path is not a directory
|
|
32
|
+
console.error(_chalk.default.red('✕ Error:'), 'The given path is not a directory. Provide a valid directory path.');
|
|
33
33
|
return;
|
|
34
34
|
}
|
|
35
35
|
let folderValidation = [];
|
|
@@ -66,7 +66,7 @@ async function vipImportValidateFilesCmd(arg = []) {
|
|
|
66
66
|
* - Intermediate image validation
|
|
67
67
|
*/
|
|
68
68
|
if (!files || !files.length || files.length <= 0) {
|
|
69
|
-
console.error(_chalk.default.red('✕ Error:'), '
|
|
69
|
+
console.error(_chalk.default.red('✕ Error:'), 'The media files directory cannot be empty.');
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
/**
|
|
@@ -147,10 +147,11 @@ async function vipImportValidateFilesCmd(arg = []) {
|
|
|
147
147
|
|
|
148
148
|
await (0, _tracker.trackEvent)('import_validate_files_command_success', allErrors);
|
|
149
149
|
}
|
|
150
|
+
const usage = 'vip import validate-files';
|
|
150
151
|
(0, _command.default)({
|
|
151
152
|
requiredArgs: 1,
|
|
152
|
-
|
|
153
|
+
usage
|
|
153
154
|
}).examples([{
|
|
154
|
-
usage: 'vip import validate-files
|
|
155
|
-
description: '
|
|
155
|
+
usage: 'vip import validate-files /Users/user-name/Desktop/uploads',
|
|
156
|
+
description: 'Validate the directory structure and contents of the local directory "uploads/".'
|
|
156
157
|
}]).argv(process.argv, vipImportValidateFilesCmd);
|
|
@@ -7,12 +7,14 @@ var _sql = require("../lib/validations/sql");
|
|
|
7
7
|
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
8
8
|
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
9
9
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
|
+
const usage = 'vip import validate-sql';
|
|
10
11
|
(0, _command.default)({
|
|
11
|
-
requiredArgs: 1
|
|
12
|
-
|
|
12
|
+
requiredArgs: 1,
|
|
13
|
+
usage
|
|
14
|
+
}).example('vip import validate-sql file.sql', 'Scan the local file named "file.sql" for SQL validation errors and potential incompatibilities with platform databases.').argv(process.argv, async arg => {
|
|
13
15
|
const filename = arg[0];
|
|
14
16
|
if (!filename) {
|
|
15
|
-
exit.withError('You must pass in a filename');
|
|
17
|
+
exit.withError('You must pass in a filename.');
|
|
16
18
|
}
|
|
17
19
|
await (0, _sql.validate)(filename);
|
|
18
20
|
});
|
package/dist/bin/vip-import.js
CHANGED
|
@@ -4,6 +4,6 @@
|
|
|
4
4
|
var _command = _interopRequireDefault(require("../lib/cli/command"));
|
|
5
5
|
var _tracker = require("../lib/tracker");
|
|
6
6
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
7
|
-
(0, _command.default)().command('sql', 'Import SQL
|
|
7
|
+
(0, _command.default)().command('sql', 'Import a SQL database file to an environment.').command('validate-sql', 'Validate a local SQL database file prior to import.').command('validate-files', 'Validate the directory structure and contents of a local media file directory prior to archiving and uploading it to a publicly accessible URL.').command('media', 'Import media files to an environment from an archived file located at a publicly accessible URL.').example('vip @example-app.develop import sql example-file.sql', 'Import the local SQL database file "example-file.sql" to the develop environment.').example('vip @example-app.production import media https://www.example.com/uploads.tar.gz', 'Import an archived file from a publicly accessible URL to the production environment.').argv(process.argv, async () => {
|
|
8
8
|
await (0, _tracker.trackEvent)('vip_import_command_execute');
|
|
9
9
|
});
|
package/dist/bin/vip-logs.js
CHANGED
|
@@ -7,6 +7,7 @@ exports.followLogs = followLogs;
|
|
|
7
7
|
exports.getLogs = getLogs;
|
|
8
8
|
exports.validateInputs = validateInputs;
|
|
9
9
|
var _chalk = _interopRequireDefault(require("chalk"));
|
|
10
|
+
var _cliTable = _interopRequireDefault(require("cli-table3"));
|
|
10
11
|
var _promises = require("timers/promises");
|
|
11
12
|
var logsLib = _interopRequireWildcard(require("../lib/app-logs/app-logs"));
|
|
12
13
|
var _command = _interopRequireDefault(require("../lib/cli/command"));
|
|
@@ -18,6 +19,7 @@ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e;
|
|
|
18
19
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
19
20
|
const LIMIT_MIN = 1;
|
|
20
21
|
const LIMIT_MAX = 5000;
|
|
22
|
+
const LIMIT_DEFAULT = 500;
|
|
21
23
|
const ALLOWED_TYPES = ['app', 'batch'];
|
|
22
24
|
const ALLOWED_FORMATS = ['csv', 'json', 'table'];
|
|
23
25
|
const DEFAULT_POLLING_DELAY_IN_SECONDS = 30;
|
|
@@ -139,14 +141,30 @@ function printLogs(logs, format) {
|
|
|
139
141
|
});
|
|
140
142
|
let output = '';
|
|
141
143
|
if (format && 'table' === format) {
|
|
142
|
-
const
|
|
144
|
+
const options = {
|
|
145
|
+
wordWrap: true,
|
|
146
|
+
wrapOnWordBoundary: true,
|
|
147
|
+
head: ['Timestamp', 'Message'],
|
|
148
|
+
style: {
|
|
149
|
+
head: ['cyan'],
|
|
150
|
+
border: ['grey']
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
if (process.stdout.isTTY && process.stdout.columns) {
|
|
154
|
+
options.colWidths = ['YYYY-MM-DDTHH:MM:SS.nnnnnnnnnZ'.length + 2 /* padding */, Math.max(process.stdout.columns - '│ │ │'.length - 'YYYY-MM-DDTHH:MM:SS.nnnnnnnnnZ'.length, 20)];
|
|
155
|
+
} else {
|
|
156
|
+
options.style.head = [];
|
|
157
|
+
options.style.border = [];
|
|
158
|
+
}
|
|
159
|
+
const table = new _cliTable.default(options);
|
|
143
160
|
for (const {
|
|
144
161
|
timestamp,
|
|
145
162
|
message
|
|
146
163
|
} of logs) {
|
|
147
|
-
|
|
148
|
-
|
|
164
|
+
const msg = message.trimRight().replace(/\t/g, ' ');
|
|
165
|
+
table.push([timestamp, msg]);
|
|
149
166
|
}
|
|
167
|
+
output = table.toString();
|
|
150
168
|
} else {
|
|
151
169
|
output = (0, _format.formatData)(logs, format);
|
|
152
170
|
}
|
|
@@ -159,6 +177,9 @@ function printLogs(logs, format) {
|
|
|
159
177
|
* @param {string} format
|
|
160
178
|
*/
|
|
161
179
|
function validateInputs(type, limit, format) {
|
|
180
|
+
if (limit === undefined) {
|
|
181
|
+
limit = LIMIT_DEFAULT;
|
|
182
|
+
}
|
|
162
183
|
if (!ALLOWED_TYPES.includes(type)) {
|
|
163
184
|
exit.withError(`Invalid type: ${type}. The supported types are: ${ALLOWED_TYPES.join(', ')}.`);
|
|
164
185
|
}
|
|
@@ -188,7 +209,9 @@ const appQuery = exports.appQuery = `
|
|
|
188
209
|
appQuery,
|
|
189
210
|
envContext: true,
|
|
190
211
|
module: 'logs'
|
|
191
|
-
}).option('type', 'The type of logs to be returned: "app" or "batch"', 'app')
|
|
212
|
+
}).option('type', 'The type of logs to be returned: "app" or "batch"', 'app')
|
|
213
|
+
// The default limit is set manually in the validateInputs function to address validation issues, avoiding incorrect replacement of the default value.
|
|
214
|
+
.option('limit', `The maximum number of log lines (defaults to ${LIMIT_DEFAULT})`).option('follow', 'Keep fetching new logs as they are generated').option('format', 'Output the log lines in CSV or JSON format', 'table').examples([{
|
|
192
215
|
usage: 'vip @mysite.production logs',
|
|
193
216
|
description: 'Get the most recent app logs'
|
|
194
217
|
}, {
|
|
@@ -29,7 +29,7 @@ const examples = [
|
|
|
29
29
|
}];
|
|
30
30
|
(0, _command.default)({
|
|
31
31
|
requiredArgs: 1
|
|
32
|
-
}).option('search-replace', 'Specify the <from> and <to> pairs to be replaced').option('in-place', 'Perform the search and replace explicitly on the input file').option('output', '
|
|
32
|
+
}).option('search-replace', 'Specify the <from> and <to> pairs to be replaced').option('in-place', 'Perform the search and replace explicitly on the input file').option('output', 'Create a local copy of the file with the completed search and replace operations. Ignored if the command includes --in-place. Accepts a local file path. Defaults to STDOUT.').examples(examples).argv(process.argv, async (arg, opt) => {
|
|
33
33
|
// TODO: tracks event for usage of this command stand alone
|
|
34
34
|
const {
|
|
35
35
|
searchReplace,
|
package/dist/bin/vip-sync.js
CHANGED
|
@@ -21,21 +21,21 @@ const appQuery = `id,name,environments{
|
|
|
21
21
|
childEnvContext: true,
|
|
22
22
|
module: 'sync',
|
|
23
23
|
requireConfirm: 'Are you sure you want to sync from production?'
|
|
24
|
-
}).argv(process.argv, async (arg, opts) => {
|
|
24
|
+
}).example('vip @example-app.develop sync', 'Sync the production environment database of the "example-app" application to the develop environment.').argv(process.argv, async (arg, opts) => {
|
|
25
25
|
const api = (0, _api.default)();
|
|
26
26
|
let syncing = false;
|
|
27
27
|
await (0, _tracker.trackEvent)('sync_command_execute');
|
|
28
28
|
try {
|
|
29
29
|
await api.mutate({
|
|
30
30
|
mutation: (0, _graphqlTag.default)`
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
mutation SyncEnvironmentMutation($input: AppEnvironmentSyncInput) {
|
|
32
|
+
syncEnvironment(input: $input) {
|
|
33
|
+
environment {
|
|
34
|
+
id
|
|
35
|
+
}
|
|
35
36
|
}
|
|
36
37
|
}
|
|
37
|
-
|
|
38
|
-
`,
|
|
38
|
+
`,
|
|
39
39
|
variables: {
|
|
40
40
|
input: {
|
|
41
41
|
id: opts.app.id,
|
|
@@ -99,28 +99,28 @@ const appQuery = `id,name,environments{
|
|
|
99
99
|
// The rest of the iterations are just for moving the spinner
|
|
100
100
|
api.query({
|
|
101
101
|
query: (0, _graphqlTag.default)`
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
id
|
|
105
|
-
name
|
|
106
|
-
environments {
|
|
102
|
+
query App($id: Int, $sync: Int) {
|
|
103
|
+
app(id: $id) {
|
|
107
104
|
id
|
|
108
105
|
name
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
name
|
|
106
|
+
environments {
|
|
107
|
+
id
|
|
108
|
+
name
|
|
109
|
+
defaultDomain
|
|
110
|
+
branch
|
|
111
|
+
datacenter
|
|
112
|
+
syncProgress(sync: $sync) {
|
|
117
113
|
status
|
|
114
|
+
sync
|
|
115
|
+
steps {
|
|
116
|
+
name
|
|
117
|
+
status
|
|
118
|
+
}
|
|
118
119
|
}
|
|
119
120
|
}
|
|
120
121
|
}
|
|
121
122
|
}
|
|
122
|
-
|
|
123
|
-
`,
|
|
123
|
+
`,
|
|
124
124
|
fetchPolicy: 'network-only',
|
|
125
125
|
variables: {
|
|
126
126
|
id: opts.app.id,
|
|
@@ -19,7 +19,7 @@ var _tracker = require("../lib/tracker");
|
|
|
19
19
|
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
20
20
|
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
21
21
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
22
|
-
const ALLOWED_NODEJS_VERSIONS = ['
|
|
22
|
+
const ALLOWED_NODEJS_VERSIONS = ['18', '20', '22'];
|
|
23
23
|
const appQuery = exports.appQuery = `
|
|
24
24
|
id
|
|
25
25
|
name
|
|
@@ -42,7 +42,7 @@ const appQuery = exports.appQuery = `
|
|
|
42
42
|
}
|
|
43
43
|
`;
|
|
44
44
|
let suppressOutput = false;
|
|
45
|
-
let
|
|
45
|
+
let outputFormat = 'table';
|
|
46
46
|
let harmoniaArgs = [];
|
|
47
47
|
|
|
48
48
|
/**
|
|
@@ -321,7 +321,7 @@ async function handleResults(harmonia, results) {
|
|
|
321
321
|
});
|
|
322
322
|
|
|
323
323
|
// If the output is JSON, reenable the logToConsole output and print-out the json format.
|
|
324
|
-
if (
|
|
324
|
+
if (outputFormat === 'json') {
|
|
325
325
|
suppressOutput = false;
|
|
326
326
|
logToConsole(harmonia.resultsJSON());
|
|
327
327
|
process.exit(0);
|
|
@@ -383,9 +383,9 @@ async function validateArgs(opt) {
|
|
|
383
383
|
}
|
|
384
384
|
|
|
385
385
|
// If the JSON option is enabled, all the stdout should be suppressed to prevent polluting the output.
|
|
386
|
-
if (opt.json) {
|
|
386
|
+
if (opt.format === 'json') {
|
|
387
387
|
suppressOutput = true;
|
|
388
|
-
|
|
388
|
+
outputFormat = 'json';
|
|
389
389
|
}
|
|
390
390
|
if (opt.app) {
|
|
391
391
|
// Get build information from API and store it in the env object
|
|
@@ -459,10 +459,10 @@ if (parsedAlias.app) {
|
|
|
459
459
|
} else {
|
|
460
460
|
logToConsole(_chalk.default.bold.yellow('Warning: ') + 'The preflight tests are running without a provided application and/or environment.\n' + 'Some app-dependent configurations, such as environment variables, might not defined.');
|
|
461
461
|
}
|
|
462
|
-
(0, _command.default)(commandOpts).option('verbose', 'Increase logging level to include app build and server boot up messages', false).option('node-version',
|
|
462
|
+
(0, _command.default)(commandOpts).option('verbose', 'Increase logging level to include app build and server boot up messages', false).option('node-version', `Select a specific target Node.JS version in semver format (MAJOR.MINOR.PATCH) or a MAJOR (${ALLOWED_NODEJS_VERSIONS.join(', ')})`).option('wait', 'Configure the time to wait in ms for the app to boot up. Do not change unless you have issues', 3000).option(['p', 'port'], 'Configure the port to use for the app (defaults to a random port between 3001 and 3999)').option('format', 'Output the log lines in CSV or JSON format', 'table').option(['P', 'path'], 'Path to the app to be tested', process.cwd()).examples([{
|
|
463
463
|
usage: 'vip @mysite.production validate preflight',
|
|
464
464
|
description: 'Runs the preflight tests to validate if your application is ready to be deployed to VIP Go'
|
|
465
465
|
}, {
|
|
466
|
-
usage: 'vip @mysite.production validate preflight --json > results.json',
|
|
466
|
+
usage: 'vip @mysite.production validate preflight --format json > results.json',
|
|
467
467
|
description: 'Runs the preflight tests, but output the results in JSON format, and redirect the output to a file'
|
|
468
468
|
}]).argv(process.argv, vipValidatePreflightCommand);
|