@automattic/vip 3.7.0 → 3.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/dev-env.lando.template.yml.ejs +2 -0
- package/dist/bin/vip-import-validate-files.js +21 -6
- package/dist/commands/dev-env-import-sql.js +2 -4
- package/dist/commands/dev-env-sync-sql.js +36 -35
- package/dist/commands/export-sql.js +60 -56
- package/dist/lib/constants/dev-environment.js +1 -1
- package/dist/lib/vip-import-validate-files.js +2 -1
- package/docs/CHANGELOG.md +14 -0
- package/npm-shrinkwrap.json +33 -33
- package/package.json +2 -2
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
*/
|
|
6
6
|
"use strict";
|
|
7
7
|
|
|
8
|
+
exports.__esModule = true;
|
|
9
|
+
exports.vipImportValidateFilesCmd = vipImportValidateFilesCmd;
|
|
8
10
|
var _chalk = _interopRequireDefault(require("chalk"));
|
|
9
11
|
var _url = _interopRequireDefault(require("url"));
|
|
10
12
|
var _command = _interopRequireDefault(require("../lib/cli/command"));
|
|
@@ -15,10 +17,7 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
|
|
|
15
17
|
/**
|
|
16
18
|
* Internal dependencies
|
|
17
19
|
*/
|
|
18
|
-
(
|
|
19
|
-
requiredArgs: 1,
|
|
20
|
-
format: true
|
|
21
|
-
}).example('vip import validate-files <folder_name>', 'Run the import validation against the folder of media files').argv(process.argv, async arg => {
|
|
20
|
+
async function vipImportValidateFilesCmd(arg = []) {
|
|
22
21
|
await (0, _tracker.trackEvent)('import_validate_files_command_execute');
|
|
23
22
|
/**
|
|
24
23
|
* File manipulation
|
|
@@ -29,7 +28,11 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
|
|
|
29
28
|
arg = _url.default.parse(folder); // Then parse the file to its URL parts
|
|
30
29
|
const filePath = arg.path; // Extract the path of the file
|
|
31
30
|
|
|
32
|
-
|
|
31
|
+
if (!(await (0, _vipImportValidateFiles.isDirectory)(filePath))) {
|
|
32
|
+
console.error(_chalk.default.red('✕ Error:'), 'The given path is not a directory, please provide a valid directory path.');
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
let folderValidation = [];
|
|
33
36
|
|
|
34
37
|
/**
|
|
35
38
|
* Folder structure validation
|
|
@@ -39,6 +42,11 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
|
|
|
39
42
|
* Recommended structure: `uploads/year/month` (Single sites)
|
|
40
43
|
*/
|
|
41
44
|
const nestedFiles = (0, _vipImportValidateFiles.findNestedDirectories)(filePath);
|
|
45
|
+
|
|
46
|
+
// Terminates the command here if no nested files found
|
|
47
|
+
if (!nestedFiles) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
42
50
|
const {
|
|
43
51
|
files,
|
|
44
52
|
folderStructureObj
|
|
@@ -138,4 +146,11 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
|
|
|
138
146
|
/* eslint-enable camelcase */
|
|
139
147
|
|
|
140
148
|
await (0, _tracker.trackEvent)('import_validate_files_command_success', allErrors);
|
|
141
|
-
}
|
|
149
|
+
}
|
|
150
|
+
(0, _command.default)({
|
|
151
|
+
requiredArgs: 1,
|
|
152
|
+
format: true
|
|
153
|
+
}).examples([{
|
|
154
|
+
usage: 'vip import validate-files <folder_name>',
|
|
155
|
+
description: 'Run the import validation against the folder of media files'
|
|
156
|
+
}]).argv(process.argv, vipImportValidateFilesCmd);
|
|
@@ -16,9 +16,6 @@ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return
|
|
|
16
16
|
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; }
|
|
17
17
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
18
18
|
class DevEnvImportSQLCommand {
|
|
19
|
-
fileName;
|
|
20
|
-
options;
|
|
21
|
-
slug;
|
|
22
19
|
constructor(fileName, options, slug) {
|
|
23
20
|
this.fileName = fileName;
|
|
24
21
|
this.options = options;
|
|
@@ -43,7 +40,8 @@ class DevEnvImportSQLCommand {
|
|
|
43
40
|
console.log(`${_chalk.default.green('✓')} Extracted to ${sqlFile}`);
|
|
44
41
|
}
|
|
45
42
|
this.fileName = sqlFile;
|
|
46
|
-
} catch (
|
|
43
|
+
} catch (error) {
|
|
44
|
+
const err = error;
|
|
47
45
|
exit.withError(`Error extracting the SQL file: ${err.message}`);
|
|
48
46
|
}
|
|
49
47
|
}
|
|
@@ -20,8 +20,8 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
|
|
|
20
20
|
/**
|
|
21
21
|
* Finds the site home url from the SQL line
|
|
22
22
|
*
|
|
23
|
-
* @param
|
|
24
|
-
* @return
|
|
23
|
+
* @param sql A line in a SQL file
|
|
24
|
+
* @return Site home url. null if not found
|
|
25
25
|
*/
|
|
26
26
|
function findSiteHomeUrl(sql) {
|
|
27
27
|
const regex = "'(siteurl|home)',\\s?'(.*?)'";
|
|
@@ -32,8 +32,8 @@ function findSiteHomeUrl(sql) {
|
|
|
32
32
|
/**
|
|
33
33
|
* Extracts a list of site urls from the SQL file
|
|
34
34
|
*
|
|
35
|
-
* @param
|
|
36
|
-
* @return
|
|
35
|
+
* @param sqlFile Path to the SQL file
|
|
36
|
+
* @return List of site urls
|
|
37
37
|
* @throws {Error} If there is an error reading the file
|
|
38
38
|
*/
|
|
39
39
|
async function extractSiteUrls(sqlFile) {
|
|
@@ -54,23 +54,19 @@ async function extractSiteUrls(sqlFile) {
|
|
|
54
54
|
});
|
|
55
55
|
}
|
|
56
56
|
class DevEnvSyncSQLCommand {
|
|
57
|
-
app;
|
|
58
|
-
env;
|
|
59
|
-
slug;
|
|
60
|
-
lando;
|
|
61
57
|
tmpDir;
|
|
62
|
-
siteUrls;
|
|
63
|
-
searchReplaceMap;
|
|
58
|
+
siteUrls = [];
|
|
59
|
+
searchReplaceMap = {};
|
|
64
60
|
track;
|
|
65
61
|
|
|
66
62
|
/**
|
|
67
63
|
* Creates a new instance of the command
|
|
68
64
|
*
|
|
69
|
-
* @param
|
|
70
|
-
* @param
|
|
71
|
-
* @param
|
|
72
|
-
* @param
|
|
73
|
-
* @param
|
|
65
|
+
* @param app The app object
|
|
66
|
+
* @param env The environment object
|
|
67
|
+
* @param slug The site slug
|
|
68
|
+
* @param lando The lando object
|
|
69
|
+
* @param trackerFn Function to call for tracking
|
|
74
70
|
*/
|
|
75
71
|
constructor(app, env, slug, lando, trackerFn = () => {}) {
|
|
76
72
|
this.app = app;
|
|
@@ -132,12 +128,12 @@ class DevEnvSyncSQLCommand {
|
|
|
132
128
|
for (const url of this.siteUrls) {
|
|
133
129
|
this.searchReplaceMap[url] = this.landoDomain;
|
|
134
130
|
}
|
|
135
|
-
const networkSites = this.env.wpSitesSDS
|
|
131
|
+
const networkSites = this.env.wpSitesSDS?.nodes;
|
|
136
132
|
if (!networkSites) return;
|
|
137
133
|
for (const site of networkSites) {
|
|
138
|
-
if (!site
|
|
139
|
-
const url = site
|
|
140
|
-
if (!this.searchReplaceMap[url]) continue;
|
|
134
|
+
if (!site?.blogId || site.blogId === 1) continue;
|
|
135
|
+
const url = site?.homeUrl?.replace(/https?:\/\//, '');
|
|
136
|
+
if (!url || !this.searchReplaceMap[url]) continue;
|
|
141
137
|
this.searchReplaceMap[url] = `${this.slugifyDomain(url)}-${site.blogId}.${this.landoDomain}`;
|
|
142
138
|
}
|
|
143
139
|
}
|
|
@@ -171,44 +167,47 @@ class DevEnvSyncSQLCommand {
|
|
|
171
167
|
* Sequentially runs the commands to export, search-replace, and import the SQL file
|
|
172
168
|
* to the local environment
|
|
173
169
|
*
|
|
174
|
-
* @return
|
|
170
|
+
* @return Promise that resolves to true when the commands are complete. It will return false if the user did not continue during validation prompts.
|
|
175
171
|
*/
|
|
176
172
|
async run() {
|
|
177
173
|
try {
|
|
178
174
|
await this.generateExport();
|
|
179
175
|
} catch (err) {
|
|
176
|
+
const error = err;
|
|
180
177
|
// this.generateExport probably catches all exceptions, track the event and runs exit.withError() but if things go really wrong
|
|
181
178
|
// and we have no tracking data, we would at least have it logged here.
|
|
182
179
|
// the following will not get executed if this.generateExport() calls exit.withError() on all exception
|
|
183
180
|
await this.track('error', {
|
|
184
181
|
error_type: 'export_sql_backup',
|
|
185
|
-
error_message:
|
|
186
|
-
stack:
|
|
182
|
+
error_message: error.message,
|
|
183
|
+
stack: error.stack
|
|
187
184
|
});
|
|
188
|
-
exit.withError(`Error exporting SQL backup: ${
|
|
185
|
+
exit.withError(`Error exporting SQL backup: ${error.message}`);
|
|
189
186
|
}
|
|
190
187
|
try {
|
|
191
188
|
console.log(`Extracting the exported file ${this.gzFile}...`);
|
|
192
189
|
await (0, _clientFileUploader.unzipFile)(this.gzFile, this.sqlFile);
|
|
193
190
|
console.log(`${_chalk.default.green('✓')} Extracted to ${this.sqlFile}`);
|
|
194
191
|
} catch (err) {
|
|
192
|
+
const error = err;
|
|
195
193
|
await this.track('error', {
|
|
196
194
|
error_type: 'archive_extraction',
|
|
197
|
-
error_message:
|
|
198
|
-
stack:
|
|
195
|
+
error_message: error.message,
|
|
196
|
+
stack: error.stack
|
|
199
197
|
});
|
|
200
|
-
exit.withError(`Error extracting the SQL export: ${
|
|
198
|
+
exit.withError(`Error extracting the SQL export: ${error.message}`);
|
|
201
199
|
}
|
|
202
200
|
try {
|
|
203
201
|
console.log('Extracting site urls from the SQL file...');
|
|
204
202
|
this.siteUrls = await extractSiteUrls(this.sqlFile);
|
|
205
203
|
} catch (err) {
|
|
204
|
+
const error = err;
|
|
206
205
|
await this.track('error', {
|
|
207
206
|
error_type: 'extract_site_urls',
|
|
208
|
-
error_message:
|
|
209
|
-
stack:
|
|
207
|
+
error_message: error.message,
|
|
208
|
+
stack: error.stack
|
|
210
209
|
});
|
|
211
|
-
exit.withError(`Error extracting site URLs: ${
|
|
210
|
+
exit.withError(`Error extracting site URLs: ${error.message}`);
|
|
212
211
|
}
|
|
213
212
|
console.log('Generating search-replace configuration...');
|
|
214
213
|
this.generateSearchReplaceMap();
|
|
@@ -220,12 +219,13 @@ class DevEnvSyncSQLCommand {
|
|
|
220
219
|
await this.runSearchReplace();
|
|
221
220
|
console.log(`${_chalk.default.green('✓')} Search-replace operation is complete`);
|
|
222
221
|
} catch (err) {
|
|
222
|
+
const error = err;
|
|
223
223
|
await this.track('error', {
|
|
224
224
|
error_type: 'search_replace',
|
|
225
|
-
error_message:
|
|
226
|
-
stack:
|
|
225
|
+
error_message: error.message,
|
|
226
|
+
stack: error.stack
|
|
227
227
|
});
|
|
228
|
-
exit.withError(`Error replacing domains: ${
|
|
228
|
+
exit.withError(`Error replacing domains: ${error.message}`);
|
|
229
229
|
}
|
|
230
230
|
try {
|
|
231
231
|
console.log('Importing the SQL file...');
|
|
@@ -233,12 +233,13 @@ class DevEnvSyncSQLCommand {
|
|
|
233
233
|
console.log(`${_chalk.default.green('✓')} SQL file imported`);
|
|
234
234
|
return true;
|
|
235
235
|
} catch (err) {
|
|
236
|
+
const error = err;
|
|
236
237
|
await this.track('error', {
|
|
237
238
|
error_type: 'import_sql_file',
|
|
238
|
-
error_message:
|
|
239
|
-
stack:
|
|
239
|
+
error_message: error.message,
|
|
240
|
+
stack: error.stack
|
|
240
241
|
});
|
|
241
|
-
exit.withError(`Error importing SQL file: ${
|
|
242
|
+
exit.withError(`Error importing SQL file: ${error.message}`);
|
|
242
243
|
}
|
|
243
244
|
}
|
|
244
245
|
}
|
|
@@ -94,21 +94,18 @@ async function fetchLatestBackupAndJobStatusBase(appId, envId) {
|
|
|
94
94
|
},
|
|
95
95
|
fetchPolicy: 'network-only'
|
|
96
96
|
});
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
environments
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
} = response;
|
|
104
|
-
const latestBackup = environments[0].latestBackup;
|
|
105
|
-
const jobs = environments[0].jobs;
|
|
97
|
+
const environments = response.data.app?.environments;
|
|
98
|
+
const latestBackup = environments?.[0]?.latestBackup;
|
|
99
|
+
const jobs = environments?.[0]?.jobs || [];
|
|
106
100
|
return {
|
|
107
101
|
latestBackup,
|
|
108
102
|
jobs
|
|
109
103
|
};
|
|
110
104
|
}
|
|
111
105
|
async function fetchLatestBackupAndJobStatus(appId, envId) {
|
|
106
|
+
if (!appId || !envId) {
|
|
107
|
+
throw new Error('App ID and Env ID missing');
|
|
108
|
+
}
|
|
112
109
|
return await (0, _retry.retry)({
|
|
113
110
|
retryOnlyIf: options => {
|
|
114
111
|
return (options.error.message || '').indexOf('Unexpected token < in JSON at position 0') !== -1;
|
|
@@ -125,6 +122,9 @@ async function fetchLatestBackupAndJobStatus(appId, envId) {
|
|
|
125
122
|
* @return {Promise} A promise which resolves to the download link
|
|
126
123
|
*/
|
|
127
124
|
async function generateDownloadLink(appId, envId, backupId) {
|
|
125
|
+
if (!appId || !envId || !backupId) {
|
|
126
|
+
throw new Error('generateDownloadLink: A parameter is missing');
|
|
127
|
+
}
|
|
128
128
|
const api = (0, _api.default)();
|
|
129
129
|
const response = await api.mutate({
|
|
130
130
|
mutation: GENERATE_DOWNLOAD_LINK_MUTATION,
|
|
@@ -136,14 +136,7 @@ async function generateDownloadLink(appId, envId, backupId) {
|
|
|
136
136
|
}
|
|
137
137
|
}
|
|
138
138
|
});
|
|
139
|
-
|
|
140
|
-
data: {
|
|
141
|
-
generateDBBackupCopyUrl: {
|
|
142
|
-
url
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
} = response;
|
|
146
|
-
return url;
|
|
139
|
+
return response.data?.generateDBBackupCopyUrl?.url;
|
|
147
140
|
}
|
|
148
141
|
|
|
149
142
|
/**
|
|
@@ -152,10 +145,14 @@ async function generateDownloadLink(appId, envId, backupId) {
|
|
|
152
145
|
* @param {number} appId Application ID
|
|
153
146
|
* @param {number} envId Environment ID
|
|
154
147
|
* @param {number} backupId Backup ID
|
|
155
|
-
* @return {Promise} A promise which resolves to
|
|
148
|
+
* @return {Promise} A promise which resolves to undefined if job creation succeeds
|
|
156
149
|
* @throws {Error} Throws an error if the job creation fails
|
|
157
150
|
*/
|
|
158
151
|
async function createExportJob(appId, envId, backupId) {
|
|
152
|
+
if (!appId || !envId || !backupId) {
|
|
153
|
+
throw new Error('createExportJob: Some fields are undefined');
|
|
154
|
+
}
|
|
155
|
+
|
|
159
156
|
// Disable global error handling so that we can handle errors ourselves
|
|
160
157
|
(0, _api.disableGlobalGraphQLErrorHandling)();
|
|
161
158
|
const api = (0, _api.default)();
|
|
@@ -173,14 +170,10 @@ async function createExportJob(appId, envId, backupId) {
|
|
|
173
170
|
// Re-enable global error handling
|
|
174
171
|
(0, _api.enableGlobalGraphQLErrorHandling)();
|
|
175
172
|
}
|
|
176
|
-
|
|
177
173
|
/**
|
|
178
174
|
* Class representing an export command workflow
|
|
179
175
|
*/
|
|
180
176
|
class ExportSQLCommand {
|
|
181
|
-
app;
|
|
182
|
-
env;
|
|
183
|
-
downloadLink;
|
|
184
177
|
progressTracker;
|
|
185
178
|
outputFile;
|
|
186
179
|
generateBackup;
|
|
@@ -237,10 +230,13 @@ class ExportSQLCommand {
|
|
|
237
230
|
latestBackup,
|
|
238
231
|
jobs
|
|
239
232
|
} = await fetchLatestBackupAndJobStatus(this.app.id, this.env.id);
|
|
233
|
+
if (!latestBackup) {
|
|
234
|
+
return undefined;
|
|
235
|
+
}
|
|
240
236
|
|
|
241
237
|
// Find the job that generates the export for the latest backup
|
|
242
238
|
return jobs.find(job => {
|
|
243
|
-
const metadata = job.metadata.find(md => md
|
|
239
|
+
const metadata = (job.metadata || []).find(md => md?.name === 'backupId');
|
|
244
240
|
return metadata && parseInt(metadata.value, 10) === latestBackup.id;
|
|
245
241
|
});
|
|
246
242
|
}
|
|
@@ -248,12 +244,15 @@ class ExportSQLCommand {
|
|
|
248
244
|
/**
|
|
249
245
|
* Fetches the S3 filename of the exported backup
|
|
250
246
|
*
|
|
251
|
-
* @return
|
|
247
|
+
* @return A promise which resolves to the filename
|
|
252
248
|
*/
|
|
253
249
|
async getExportedFileName() {
|
|
254
250
|
const job = await this.getExportJob();
|
|
255
|
-
|
|
256
|
-
|
|
251
|
+
if (!job) {
|
|
252
|
+
throw new Error('Job not found');
|
|
253
|
+
}
|
|
254
|
+
const metadata = job.metadata?.find(md => md?.name === 'uploadPath');
|
|
255
|
+
return metadata?.value?.split('/')[1];
|
|
257
256
|
}
|
|
258
257
|
|
|
259
258
|
/**
|
|
@@ -276,7 +275,9 @@ class ExportSQLCommand {
|
|
|
276
275
|
resolve(_path.default.resolve(file.path));
|
|
277
276
|
});
|
|
278
277
|
file.on('error', err => {
|
|
279
|
-
|
|
278
|
+
// TODO: fs.unlink runs in the background so there's a chance that the app dies before it finishes.
|
|
279
|
+
// This needs fixing.
|
|
280
|
+
_fs.default.unlink(filename, () => null);
|
|
280
281
|
reject(err);
|
|
281
282
|
});
|
|
282
283
|
response.on('data', chunk => {
|
|
@@ -290,29 +291,27 @@ class ExportSQLCommand {
|
|
|
290
291
|
/**
|
|
291
292
|
* Checks if the export job's preflight step is successful
|
|
292
293
|
*
|
|
293
|
-
* @param
|
|
294
|
-
* @return
|
|
294
|
+
* @param job The export job
|
|
295
|
+
* @return True if the preflight step is successful
|
|
295
296
|
*/
|
|
296
297
|
isPrepared(job) {
|
|
297
|
-
const step = job?.progress
|
|
298
|
+
const step = job?.progress?.steps?.find(st => st?.id === 'preflight');
|
|
298
299
|
return step?.status === 'success';
|
|
299
300
|
}
|
|
300
301
|
|
|
301
302
|
/**
|
|
302
303
|
* Checks if the export job's S3 upload step is successful
|
|
303
304
|
*
|
|
304
|
-
* @param
|
|
305
|
-
* @return
|
|
305
|
+
* @param job The export job
|
|
306
|
+
* @return True if the upload step is successful
|
|
306
307
|
*/
|
|
307
308
|
isCreated(job) {
|
|
308
|
-
const step = job?.progress
|
|
309
|
+
const step = job?.progress?.steps?.find(st => st?.id === 'upload_backup');
|
|
309
310
|
return step?.status === 'success';
|
|
310
311
|
}
|
|
311
312
|
|
|
312
313
|
/**
|
|
313
314
|
* Stops the progress tracker
|
|
314
|
-
*
|
|
315
|
-
* @return {void}
|
|
316
315
|
*/
|
|
317
316
|
stopProgressTracker() {
|
|
318
317
|
this.progressTracker.print();
|
|
@@ -327,6 +326,9 @@ class ExportSQLCommand {
|
|
|
327
326
|
await cmd.run(false);
|
|
328
327
|
}
|
|
329
328
|
async confirmEnoughStorage(job) {
|
|
329
|
+
if (!job) {
|
|
330
|
+
throw new Error('confirmEnoughStorage: job is missing');
|
|
331
|
+
}
|
|
330
332
|
if (this.confirmEnoughStorageHook) {
|
|
331
333
|
return await this.confirmEnoughStorageHook(job);
|
|
332
334
|
}
|
|
@@ -343,12 +345,13 @@ class ExportSQLCommand {
|
|
|
343
345
|
try {
|
|
344
346
|
_fs.default.accessSync(_path.default.parse(this.outputFile).dir, _fs.default.constants.W_OK);
|
|
345
347
|
} catch (err) {
|
|
348
|
+
const error = err;
|
|
346
349
|
await this.track('error', {
|
|
347
350
|
error_type: 'cannot_write_to_path',
|
|
348
|
-
error_message: `Cannot write to the specified path: ${
|
|
349
|
-
stack:
|
|
351
|
+
error_message: `Cannot write to the specified path: ${error?.message}`,
|
|
352
|
+
stack: error?.stack
|
|
350
353
|
});
|
|
351
|
-
exit.withError(`Cannot write to the specified path: ${
|
|
354
|
+
exit.withError(`Cannot write to the specified path: ${error?.message}`);
|
|
352
355
|
}
|
|
353
356
|
}
|
|
354
357
|
if (this.generateBackup) {
|
|
@@ -357,16 +360,15 @@ class ExportSQLCommand {
|
|
|
357
360
|
const {
|
|
358
361
|
latestBackup
|
|
359
362
|
} = await fetchLatestBackupAndJobStatus(this.app.id, this.env.id);
|
|
363
|
+
if (!latestBackup) {
|
|
364
|
+
await this.track('error', {
|
|
365
|
+
error_type: 'no_backup_found',
|
|
366
|
+
error_message: 'No backup found for the site'
|
|
367
|
+
});
|
|
368
|
+
exit.withError(`No backup found for site ${this.app.name}`);
|
|
369
|
+
}
|
|
360
370
|
if (!this.generateBackup) {
|
|
361
|
-
|
|
362
|
-
await this.track('error', {
|
|
363
|
-
error_type: 'no_backup_found',
|
|
364
|
-
error_message: 'No backup found for the site'
|
|
365
|
-
});
|
|
366
|
-
exit.withError(`No backup found for site ${this.app.name}`);
|
|
367
|
-
} else {
|
|
368
|
-
console.log(`${(0, _format.getGlyphForStatus)('success')} Latest backup found with timestamp ${latestBackup.createdAt}`);
|
|
369
|
-
}
|
|
371
|
+
console.log(`${(0, _format.getGlyphForStatus)('success')} Latest backup found with timestamp ${latestBackup.createdAt}`);
|
|
370
372
|
} else {
|
|
371
373
|
console.log(`${(0, _format.getGlyphForStatus)('success')} Backup created with timestamp ${latestBackup.createdAt}`);
|
|
372
374
|
}
|
|
@@ -377,22 +379,23 @@ class ExportSQLCommand {
|
|
|
377
379
|
try {
|
|
378
380
|
await createExportJob(this.app.id, this.env.id, latestBackup.id);
|
|
379
381
|
} catch (err) {
|
|
382
|
+
const error = err;
|
|
380
383
|
// Todo: match error code instead of message substring
|
|
381
|
-
if (
|
|
384
|
+
if (error.message.includes('Backup Copy already in progress')) {
|
|
382
385
|
await this.track('error', {
|
|
383
386
|
error_type: 'job_already_running',
|
|
384
|
-
error_message:
|
|
385
|
-
stack:
|
|
387
|
+
error_message: error.message,
|
|
388
|
+
stack: error.stack
|
|
386
389
|
});
|
|
387
390
|
exit.withError('There is an export job already running for this environment: ' + `https://dashboard.wpvip.com/apps/${this.app.id}/${this.env.uniqueLabel}/database/backups\n` + 'Currently, we allow only one export job at a time, per site. Please try again later.');
|
|
388
391
|
} else {
|
|
389
392
|
await this.track('error', {
|
|
390
393
|
error_type: 'create_export_job',
|
|
391
|
-
error_message:
|
|
392
|
-
stack:
|
|
394
|
+
error_message: error.message,
|
|
395
|
+
stack: error.stack
|
|
393
396
|
});
|
|
394
397
|
}
|
|
395
|
-
exit.withError(`Error creating export job: ${
|
|
398
|
+
exit.withError(`Error creating export job: ${error.message}`);
|
|
396
399
|
}
|
|
397
400
|
}
|
|
398
401
|
this.progressTracker.stepRunning(this.steps.PREPARE);
|
|
@@ -425,14 +428,15 @@ class ExportSQLCommand {
|
|
|
425
428
|
this.stopProgressTracker();
|
|
426
429
|
console.log(`File saved to ${filepath}`);
|
|
427
430
|
} catch (err) {
|
|
431
|
+
const error = err;
|
|
428
432
|
this.progressTracker.stepFailed(this.steps.DOWNLOAD);
|
|
429
433
|
this.stopProgressTracker();
|
|
430
434
|
await this.track('error', {
|
|
431
435
|
error_type: 'download_failed',
|
|
432
|
-
error_message:
|
|
433
|
-
stack:
|
|
436
|
+
error_message: error.message,
|
|
437
|
+
stack: error.stack
|
|
434
438
|
});
|
|
435
|
-
exit.withError(`Error downloading exported file: ${
|
|
439
|
+
exit.withError(`Error downloading exported file: ${error.message}`);
|
|
436
440
|
}
|
|
437
441
|
}
|
|
438
442
|
}
|
|
@@ -32,4 +32,4 @@ const DEV_ENVIRONMENT_DEFAULTS = exports.DEV_ENVIRONMENT_DEFAULTS = {
|
|
|
32
32
|
multisite: false,
|
|
33
33
|
phpVersion: Object.keys(DEV_ENVIRONMENT_PHP_VERSIONS)[0]
|
|
34
34
|
};
|
|
35
|
-
const DEV_ENVIRONMENT_VERSION = exports.DEV_ENVIRONMENT_VERSION = '2.1.
|
|
35
|
+
const DEV_ENVIRONMENT_VERSION = exports.DEV_ENVIRONMENT_VERSION = '2.1.1';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
exports.__esModule = true;
|
|
4
|
-
exports.summaryLogs = exports.logErrors = exports.isFileSanitized = exports.folderStructureValidation = exports.findNestedDirectories = exports.doesImageHaveExistingSource = exports.ValidateFilesErrors = void 0;
|
|
4
|
+
exports.summaryLogs = exports.logErrors = exports.isFileSanitized = exports.isDirectory = exports.folderStructureValidation = exports.findNestedDirectories = exports.doesImageHaveExistingSource = exports.ValidateFilesErrors = void 0;
|
|
5
5
|
exports.validateFiles = validateFiles;
|
|
6
6
|
var _chalk = _interopRequireDefault(require("chalk"));
|
|
7
7
|
var _fs = _interopRequireDefault(require("fs"));
|
|
@@ -73,6 +73,7 @@ const isDirectory = async file => {
|
|
|
73
73
|
const stats = await _fs.default.promises.stat(file);
|
|
74
74
|
return stats.isDirectory();
|
|
75
75
|
};
|
|
76
|
+
exports.isDirectory = isDirectory;
|
|
76
77
|
const getFileExtType = (file, allowedFileTypes) => {
|
|
77
78
|
if (!allowedFileTypes) return {
|
|
78
79
|
ext: null,
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
## Changelog
|
|
2
2
|
|
|
3
|
+
## 3.7.0
|
|
4
|
+
|
|
5
|
+
* New develop release: 3.6.1-dev.0 by @github-actions in #1931
|
|
6
|
+
* build(deps-dev): bump @automattic/eslint-plugin-wpvip from 0.12.0 to 0.13.0 by @dependabot in #1932
|
|
7
|
+
* build(deps-dev): bump the babel group with 3 updates by @dependabot in #1936
|
|
8
|
+
* build(deps): bump update-notifier from 7.0.0 to 7.1.0 by @dependabot in #1937
|
|
9
|
+
* build(deps): bump actions/dependency-review-action from 4.3.3 to 4.3.4 by @dependabot in #1938
|
|
10
|
+
* build(deps-dev): bump @babel/core from 7.24.8 to 7.24.9 in the babel group by @dependabot in #1939
|
|
11
|
+
* build(deps-dev): bump @types/dockerode from 3.3.29 to 3.3.30 by @dependabot in #1941
|
|
12
|
+
* update: media import validate-files by @ariskataoka in #1919
|
|
13
|
+
* New package release: v3.7.0 by @github-actions in #1943
|
|
14
|
+
|
|
15
|
+
**Full Changelog**: https://github.com/Automattic/vip-cli/compare/3.6.0...3.7.0
|
|
16
|
+
|
|
3
17
|
## 3.6.0
|
|
4
18
|
|
|
5
19
|
* build(deps-dev): bump rimraf from 5.0.7 to 5.0.8
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automattic/vip",
|
|
3
|
-
"version": "3.7.
|
|
3
|
+
"version": "3.7.1",
|
|
4
4
|
"lockfileVersion": 2,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@automattic/vip",
|
|
9
|
-
"version": "3.7.
|
|
9
|
+
"version": "3.7.1",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"dependencies": {
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"node-fetch": "^2.6.1",
|
|
37
37
|
"open": "^10.0.0",
|
|
38
38
|
"proxy-from-env": "^1.1.0",
|
|
39
|
-
"semver": "7.6.
|
|
39
|
+
"semver": "7.6.3",
|
|
40
40
|
"shelljs": "^0.8.5",
|
|
41
41
|
"single-line-log": "1.1.2",
|
|
42
42
|
"socket.io-client": "^4.5.3",
|
|
@@ -3759,9 +3759,9 @@
|
|
|
3759
3759
|
}
|
|
3760
3760
|
},
|
|
3761
3761
|
"node_modules/@types/dockerode": {
|
|
3762
|
-
"version": "3.3.
|
|
3763
|
-
"resolved": "https://registry.npmjs.org/@types/dockerode/-/dockerode-3.3.
|
|
3764
|
-
"integrity": "sha512-
|
|
3762
|
+
"version": "3.3.31",
|
|
3763
|
+
"resolved": "https://registry.npmjs.org/@types/dockerode/-/dockerode-3.3.31.tgz",
|
|
3764
|
+
"integrity": "sha512-42R9eoVqJDSvVspV89g7RwRqfNExgievLNWoHkg7NoWIqAmavIbgQBb4oc0qRtHkxE+I3Xxvqv7qVXFABKPBTg==",
|
|
3765
3765
|
"dev": true,
|
|
3766
3766
|
"dependencies": {
|
|
3767
3767
|
"@types/docker-modem": "*",
|
|
@@ -3851,9 +3851,9 @@
|
|
|
3851
3851
|
"dev": true
|
|
3852
3852
|
},
|
|
3853
3853
|
"node_modules/@types/node": {
|
|
3854
|
-
"version": "18.19.
|
|
3855
|
-
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.
|
|
3856
|
-
"integrity": "sha512-
|
|
3854
|
+
"version": "18.19.42",
|
|
3855
|
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.42.tgz",
|
|
3856
|
+
"integrity": "sha512-d2ZFc/3lnK2YCYhos8iaNIYu9Vfhr92nHiyJHRltXWjXUBjEE+A4I58Tdbnw4VhggSW+2j5y5gTrLs4biNnubg==",
|
|
3857
3857
|
"dependencies": {
|
|
3858
3858
|
"undici-types": "~5.26.4"
|
|
3859
3859
|
}
|
|
@@ -11502,9 +11502,9 @@
|
|
|
11502
11502
|
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
|
|
11503
11503
|
},
|
|
11504
11504
|
"node_modules/semver": {
|
|
11505
|
-
"version": "7.6.
|
|
11506
|
-
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.
|
|
11507
|
-
"integrity": "sha512-
|
|
11505
|
+
"version": "7.6.3",
|
|
11506
|
+
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
|
|
11507
|
+
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
|
|
11508
11508
|
"bin": {
|
|
11509
11509
|
"semver": "bin/semver.js"
|
|
11510
11510
|
},
|
|
@@ -12145,9 +12145,9 @@
|
|
|
12145
12145
|
}
|
|
12146
12146
|
},
|
|
12147
12147
|
"node_modules/tar": {
|
|
12148
|
-
"version": "7.4.
|
|
12149
|
-
"resolved": "https://registry.npmjs.org/tar/-/tar-7.4.
|
|
12150
|
-
"integrity": "sha512-
|
|
12148
|
+
"version": "7.4.3",
|
|
12149
|
+
"resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz",
|
|
12150
|
+
"integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==",
|
|
12151
12151
|
"dependencies": {
|
|
12152
12152
|
"@isaacs/fs-minipass": "^4.0.0",
|
|
12153
12153
|
"chownr": "^3.0.0",
|
|
@@ -12464,9 +12464,9 @@
|
|
|
12464
12464
|
}
|
|
12465
12465
|
},
|
|
12466
12466
|
"node_modules/typescript": {
|
|
12467
|
-
"version": "5.5.
|
|
12468
|
-
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.
|
|
12469
|
-
"integrity": "sha512
|
|
12467
|
+
"version": "5.5.4",
|
|
12468
|
+
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz",
|
|
12469
|
+
"integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==",
|
|
12470
12470
|
"dev": true,
|
|
12471
12471
|
"bin": {
|
|
12472
12472
|
"tsc": "bin/tsc",
|
|
@@ -16011,9 +16011,9 @@
|
|
|
16011
16011
|
}
|
|
16012
16012
|
},
|
|
16013
16013
|
"@types/dockerode": {
|
|
16014
|
-
"version": "3.3.
|
|
16015
|
-
"resolved": "https://registry.npmjs.org/@types/dockerode/-/dockerode-3.3.
|
|
16016
|
-
"integrity": "sha512-
|
|
16014
|
+
"version": "3.3.31",
|
|
16015
|
+
"resolved": "https://registry.npmjs.org/@types/dockerode/-/dockerode-3.3.31.tgz",
|
|
16016
|
+
"integrity": "sha512-42R9eoVqJDSvVspV89g7RwRqfNExgievLNWoHkg7NoWIqAmavIbgQBb4oc0qRtHkxE+I3Xxvqv7qVXFABKPBTg==",
|
|
16017
16017
|
"dev": true,
|
|
16018
16018
|
"requires": {
|
|
16019
16019
|
"@types/docker-modem": "*",
|
|
@@ -16103,9 +16103,9 @@
|
|
|
16103
16103
|
"dev": true
|
|
16104
16104
|
},
|
|
16105
16105
|
"@types/node": {
|
|
16106
|
-
"version": "18.19.
|
|
16107
|
-
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.
|
|
16108
|
-
"integrity": "sha512-
|
|
16106
|
+
"version": "18.19.42",
|
|
16107
|
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.42.tgz",
|
|
16108
|
+
"integrity": "sha512-d2ZFc/3lnK2YCYhos8iaNIYu9Vfhr92nHiyJHRltXWjXUBjEE+A4I58Tdbnw4VhggSW+2j5y5gTrLs4biNnubg==",
|
|
16109
16109
|
"requires": {
|
|
16110
16110
|
"undici-types": "~5.26.4"
|
|
16111
16111
|
}
|
|
@@ -21641,9 +21641,9 @@
|
|
|
21641
21641
|
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
|
|
21642
21642
|
},
|
|
21643
21643
|
"semver": {
|
|
21644
|
-
"version": "7.6.
|
|
21645
|
-
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.
|
|
21646
|
-
"integrity": "sha512-
|
|
21644
|
+
"version": "7.6.3",
|
|
21645
|
+
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
|
|
21646
|
+
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="
|
|
21647
21647
|
},
|
|
21648
21648
|
"semver-diff": {
|
|
21649
21649
|
"version": "4.0.0",
|
|
@@ -22101,9 +22101,9 @@
|
|
|
22101
22101
|
"dev": true
|
|
22102
22102
|
},
|
|
22103
22103
|
"tar": {
|
|
22104
|
-
"version": "7.4.
|
|
22105
|
-
"resolved": "https://registry.npmjs.org/tar/-/tar-7.4.
|
|
22106
|
-
"integrity": "sha512-
|
|
22104
|
+
"version": "7.4.3",
|
|
22105
|
+
"resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz",
|
|
22106
|
+
"integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==",
|
|
22107
22107
|
"requires": {
|
|
22108
22108
|
"@isaacs/fs-minipass": "^4.0.0",
|
|
22109
22109
|
"chownr": "^3.0.0",
|
|
@@ -22348,9 +22348,9 @@
|
|
|
22348
22348
|
}
|
|
22349
22349
|
},
|
|
22350
22350
|
"typescript": {
|
|
22351
|
-
"version": "5.5.
|
|
22352
|
-
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.
|
|
22353
|
-
"integrity": "sha512
|
|
22351
|
+
"version": "5.5.4",
|
|
22352
|
+
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz",
|
|
22353
|
+
"integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==",
|
|
22354
22354
|
"dev": true
|
|
22355
22355
|
},
|
|
22356
22356
|
"typical": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automattic/vip",
|
|
3
|
-
"version": "3.7.
|
|
3
|
+
"version": "3.7.1",
|
|
4
4
|
"description": "The VIP Javascript library & CLI",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -168,7 +168,7 @@
|
|
|
168
168
|
"node-fetch": "^2.6.1",
|
|
169
169
|
"open": "^10.0.0",
|
|
170
170
|
"proxy-from-env": "^1.1.0",
|
|
171
|
-
"semver": "7.6.
|
|
171
|
+
"semver": "7.6.3",
|
|
172
172
|
"shelljs": "^0.8.5",
|
|
173
173
|
"single-line-log": "1.1.2",
|
|
174
174
|
"socket.io-client": "^4.5.3",
|