@automattic/vip 3.7.1 → 3.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -271,6 +271,13 @@ tooling:
271
271
  cmd:
272
272
  - wp
273
273
 
274
+ db-myloader:
275
+ service: php
276
+ description: "Run mydumper's myloader to import database dumps generated by mydumper"
277
+ user: root
278
+ cmd:
279
+ - myloader -h database -u wordpress -p wordpress --database wordpress
280
+
274
281
  db:
275
282
  service: php
276
283
  description: "Connect to the DB using mysql client (e.g. allow to run imports)"
@@ -5,6 +5,7 @@ exports.__esModule = true;
5
5
  exports.deleteEnvVarCommand = deleteEnvVarCommand;
6
6
  var _chalk = _interopRequireDefault(require("chalk"));
7
7
  var _command = _interopRequireDefault(require("../lib/cli/command"));
8
+ var _format = require("../lib/cli/format");
8
9
  var _api = require("../lib/envvar/api");
9
10
  var _input = require("../lib/envvar/input");
10
11
  var _logging = require("../lib/envvar/logging");
@@ -35,6 +36,16 @@ async function deleteEnvVarCommand(arg, opt) {
35
36
  skip_confirm: Boolean(opt.skipConfirmation),
36
37
  variable_name: name
37
38
  };
39
+ const envName = opt.env.type;
40
+ const appName = opt.app.name;
41
+ if (!opt.skipConfirmation && envName === 'production') {
42
+ const yes = await (0, _input.confirm)(`Are you sure you want to delete the environment variable ${name} on ${(0, _format.formatEnvironment)(envName)} for site ${appName}?`);
43
+ if (!yes) {
44
+ (0, _tracker.trackEvent)('wpcli_confirm_cancel', trackingParams).catch(() => {});
45
+ console.log('Command cancelled');
46
+ process.exit();
47
+ }
48
+ }
38
49
  (0, _logging.debug)(`Request: Delete environment variable ${JSON.stringify(name)} for ${(0, _logging.getEnvContext)(opt.app, opt.env)}`);
39
50
  await (0, _tracker.trackEvent)('envvar_delete_command_execute', trackingParams);
40
51
  if (!(0, _api.validateNameWithMessage)(name)) {
@@ -5,6 +5,7 @@ exports.__esModule = true;
5
5
  exports.setEnvVarCommand = setEnvVarCommand;
6
6
  var _chalk = _interopRequireDefault(require("chalk"));
7
7
  var _command = _interopRequireDefault(require("../lib/cli/command"));
8
+ var _format = require("../lib/cli/format");
8
9
  var _api = require("../lib/envvar/api");
9
10
  var _input = require("../lib/envvar/input");
10
11
  var _logging = require("../lib/envvar/logging");
@@ -35,6 +36,16 @@ async function setEnvVarCommand(arg, opt) {
35
36
  skip_confirm: Boolean(opt.skipConfirmation),
36
37
  variable_name: name
37
38
  };
39
+ const envName = opt.env.type;
40
+ const appName = opt.app.name;
41
+ if (!opt.skipConfirmation && envName === 'production') {
42
+ const yes = await (0, _input.confirm)(`Are you sure you want to set the environment variable ${name} on ${(0, _format.formatEnvironment)(envName)} for site ${appName}?`);
43
+ if (!yes) {
44
+ (0, _tracker.trackEvent)('wpcli_confirm_cancel', trackingParams).catch(() => {});
45
+ console.log('Command cancelled');
46
+ process.exit();
47
+ }
48
+ }
38
49
  (0, _logging.debug)(`Request: Set environment variable ${JSON.stringify(name)} for ${(0, _logging.getEnvContext)(opt.app, opt.env)}`);
39
50
  await (0, _tracker.trackEvent)('envvar_set_command_execute', trackingParams);
40
51
  if (!(0, _api.validateNameWithMessage)(name)) {
@@ -3,6 +3,7 @@
3
3
 
4
4
  var _devEnvImportSql = require("../commands/dev-env-import-sql");
5
5
  var _command = _interopRequireDefault(require("../lib/cli/command"));
6
+ var _database = require("../lib/database");
6
7
  var _devEnvironmentCli = require("../lib/dev-environment/dev-environment-cli");
7
8
  var _tracker = require("../lib/tracker");
8
9
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
@@ -30,9 +31,16 @@ const examples = [{
30
31
  }).option('slug', 'A unique name for a local environment. Default is "vip-local".', undefined, _devEnvironmentCli.processSlug).option(['r', 'search-replace'], 'Search for a string in the SQL file and replace it with a new string.').option('in-place', 'Perform a search and replace operation on the local SQL file and save the results.').option('skip-validate', 'Skip file validation.').option(['k', 'skip-reindex'], 'Skip Elasticsearch reindex after import.').option('quiet', 'Skip confirmation and suppress informational messages.').examples(examples).argv(process.argv, async (unmatchedArgs, opt) => {
31
32
  const [fileName] = unmatchedArgs;
32
33
  const slug = await (0, _devEnvironmentCli.getEnvironmentName)(opt);
34
+ if (opt.searchReplace && !Array.isArray(opt.searchReplace)) {
35
+ opt.searchReplace = [opt.searchReplace];
36
+ }
33
37
  const cmd = new _devEnvImportSql.DevEnvImportSQLCommand(fileName, opt, slug);
38
+ const dumpDetails = await (0, _database.getSqlDumpDetails)(fileName);
34
39
  const trackingInfo = (0, _devEnvironmentCli.getEnvTrackingInfo)(cmd.slug);
35
- const trackerFn = (0, _tracker.makeCommandTracker)('dev_env_import_sql', trackingInfo);
40
+ const trackerFn = (0, _tracker.makeCommandTracker)('dev_env_import_sql', {
41
+ ...trackingInfo,
42
+ sqldump_type: dumpDetails.type
43
+ });
36
44
  await trackerFn('execute');
37
45
  try {
38
46
  await cmd.run();
@@ -46,7 +46,7 @@ const appQuery = `
46
46
  dbOperationInProgress
47
47
  importInProgress
48
48
  }
49
- wpSites {
49
+ wpSitesSDS {
50
50
  nodes {
51
51
  homeUrl
52
52
  id
@@ -286,7 +286,7 @@ const displayPlaybook = ({
286
286
  // eslint-disable-next-line no-multi-spaces
287
287
  console.log(` multisite: ${isMultiSite.toString()}`);
288
288
  const selectedEnvironmentObj = app?.environments?.find(env => unformattedEnvironment === env.type);
289
- siteArray = selectedEnvironmentObj?.wpSites?.nodes;
289
+ siteArray = selectedEnvironmentObj?.wpSitesSDS?.nodes;
290
290
  }
291
291
  if (!tableNames.length) {
292
292
  debug('Validation was skipped, no playbook information will be displayed');
@@ -4,10 +4,13 @@ exports.__esModule = true;
4
4
  exports.DevEnvImportSQLCommand = void 0;
5
5
  var _chalk = _interopRequireDefault(require("chalk"));
6
6
  var _fs = _interopRequireDefault(require("fs"));
7
+ var _os = _interopRequireDefault(require("os"));
7
8
  var exit = _interopRequireWildcard(require("../lib/cli/exit"));
8
9
  var _clientFileUploader = require("../lib/client-file-uploader");
10
+ var _database = require("../lib/database");
9
11
  var _devEnvironmentCli = require("../lib/dev-environment/dev-environment-cli");
10
12
  var _devEnvironmentCore = require("../lib/dev-environment/dev-environment-core");
13
+ var _devEnvironmentDatabase = require("../lib/dev-environment/dev-environment-database");
11
14
  var _devEnvironmentLando = require("../lib/dev-environment/dev-environment-lando");
12
15
  var _userError = _interopRequireDefault(require("../lib/user-error"));
13
16
  var _utils = require("../lib/utils");
@@ -25,6 +28,8 @@ class DevEnvImportSQLCommand {
25
28
  const lando = await (0, _devEnvironmentLando.bootstrapLando)();
26
29
  (0, _devEnvironmentCli.validateDependencies)(lando);
27
30
  (0, _sql.validateImportFileExtension)(this.fileName);
31
+ const dumpDetails = await (0, _database.getSqlDumpDetails)(this.fileName);
32
+ const isMyDumper = dumpDetails.type === _database.SqlDumpType.MYDUMPER;
28
33
 
29
34
  // Check if file is compressed and if so, extract the
30
35
  const fileMeta = await (0, _clientFileUploader.getFileMeta)(this.fileName);
@@ -57,14 +62,14 @@ class DevEnvImportSQLCommand {
57
62
  const expectedDomain = `${this.slug}.${lando.config.domain}`;
58
63
  await (0, _sql.validate)(resolvedPath, {
59
64
  isImport: false,
60
- skipChecks: [],
65
+ skipChecks: isMyDumper ? ['dropTable', 'dropDB'] : [],
61
66
  extraCheckParams: {
62
67
  siteHomeUrlLando: expectedDomain
63
68
  }
64
69
  });
65
70
  }
66
71
  const fd = await _fs.default.promises.open(resolvedPath, 'r');
67
- const importArg = ['db', '--disable-auto-rehash'].concat(this.options.quiet ? '--silent' : []);
72
+ const importArg = this.getImportArgs(dumpDetails);
68
73
  const origIsTTY = process.stdin.isTTY;
69
74
  try {
70
75
  /**
@@ -87,18 +92,23 @@ class DevEnvImportSQLCommand {
87
92
  if (searchReplace?.length && !inPlace) {
88
93
  _fs.default.unlinkSync(resolvedPath);
89
94
  }
90
- const cacheArg = ['wp', 'cache', 'flush', '--skip-plugins', '--skip-themes'].concat(this.options.quiet ? '--quiet' : []);
91
- await (0, _devEnvironmentCore.exec)(lando, this.slug, cacheArg);
95
+ await (0, _devEnvironmentDatabase.flushCache)(lando, this.slug, this.options.quiet);
92
96
  if (undefined === this.options.skipReindex || !(0, _devEnvironmentCli.processBooleanOption)(this.options.skipReindex)) {
93
97
  try {
94
- await (0, _devEnvironmentCore.exec)(lando, this.slug, ['wp', 'cli', 'has-command', 'vip-search']);
95
- await (0, _devEnvironmentCore.exec)(lando, this.slug, ['wp', 'vip-search', 'index', '--setup', '--network-wide', '--skip-confirm']);
98
+ await (0, _devEnvironmentDatabase.reIndexSearch)(lando, this.slug);
96
99
  } catch {
97
100
  // Exception means they don't have vip-search enabled.
98
101
  }
99
102
  }
100
- const addUserArg = ['wp', 'dev-env-add-admin', '--username=vipgo', '--password=password', '--skip-plugins', '--skip-themes'].concat(this.options.quiet ? '--quiet' : []);
101
- await (0, _devEnvironmentCore.exec)(lando, this.slug, addUserArg);
103
+ await (0, _devEnvironmentDatabase.addAdminUser)(lando, this.slug);
104
+ }
105
+ getImportArgs(dumpDetails) {
106
+ let importArg = ['db', '--disable-auto-rehash'].concat(this.options.quiet ? '--silent' : []);
107
+ const threadCount = Math.max(_os.default.cpus().length - 2, 1);
108
+ if (dumpDetails.type === _database.SqlDumpType.MYDUMPER) {
109
+ importArg = ['db-myloader', '--overwrite-tables', `--source-db=${dumpDetails.sourceDb}`, `--threads=${threadCount}`, '--max-threads-for-schema-creation=10', '--max-threads-for-index-creation=10', '--skip-triggers', '--skip-post', '--innodb-optimize-keys', '--checksum=SKIP', '--metadata-refresh-interval=2000000', '--stream'].concat(this.options.quiet ? ['--verbose=0'] : ['--verbose=3']);
110
+ }
111
+ return importArg;
102
112
  }
103
113
  }
104
114
  exports.DevEnvImportSQLCommand = DevEnvImportSQLCommand;
@@ -6,12 +6,14 @@ exports.DevEnvSyncSQLCommand = void 0;
6
6
  var _vipSearchReplace = require("@automattic/vip-search-replace");
7
7
  var _chalk = _interopRequireDefault(require("chalk"));
8
8
  var _fs = _interopRequireDefault(require("fs"));
9
+ var _promises = require("node:stream/promises");
9
10
  var _url = _interopRequireDefault(require("url"));
10
11
  var _devEnvImportSql = require("./dev-env-import-sql");
11
12
  var _exportSql = require("./export-sql");
12
13
  var _backupStorageAvailability = require("../lib/backup-storage-availability/backup-storage-availability");
13
14
  var exit = _interopRequireWildcard(require("../lib/cli/exit"));
14
15
  var _clientFileUploader = require("../lib/client-file-uploader");
16
+ var _database = require("../lib/database");
15
17
  var _utils = require("../lib/utils");
16
18
  var _lineByLine = require("../lib/validations/line-by-line");
17
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); }
@@ -24,7 +26,7 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
24
26
  * @return Site home url. null if not found
25
27
  */
26
28
  function findSiteHomeUrl(sql) {
27
- const regex = "'(siteurl|home)',\\s?'(.*?)'";
29
+ const regex = `['"](siteurl|home)['"],\\s?['"](.*?)['"]`;
28
30
  const url = sql.match(regex)?.[2] || '';
29
31
  return _url.default.parse(url).hostname || null;
30
32
  }
@@ -57,7 +59,8 @@ class DevEnvSyncSQLCommand {
57
59
  tmpDir;
58
60
  siteUrls = [];
59
61
  searchReplaceMap = {};
60
- track;
62
+ _track;
63
+ _sqlDumpType;
61
64
 
62
65
  /**
63
66
  * Creates a new instance of the command
@@ -73,9 +76,15 @@ class DevEnvSyncSQLCommand {
73
76
  this.env = env;
74
77
  this.slug = slug;
75
78
  this.lando = lando;
76
- this.track = trackerFn;
79
+ this._track = trackerFn;
77
80
  this.tmpDir = (0, _utils.makeTempDir)();
78
81
  }
82
+ track(name, eventProps) {
83
+ return this._track(name, {
84
+ ...eventProps,
85
+ sqldump_type: this._sqlDumpType
86
+ });
87
+ }
79
88
  get landoDomain() {
80
89
  return `${this.slug}.${this.lando.config.domain}`;
81
90
  }
@@ -85,6 +94,16 @@ class DevEnvSyncSQLCommand {
85
94
  get gzFile() {
86
95
  return `${this.tmpDir}/sql-export.sql.gz`;
87
96
  }
97
+ getSqlDumpType() {
98
+ if (!this._sqlDumpType) {
99
+ throw new Error('SQL Dump type not initialized');
100
+ }
101
+ return this._sqlDumpType;
102
+ }
103
+ async initSqlDumpType() {
104
+ const dumpDetails = await (0, _database.getSqlDumpDetails)(this.sqlFile);
105
+ this._sqlDumpType = dumpDetails.type;
106
+ }
88
107
  async confirmEnoughStorage(job) {
89
108
  const storageAvailability = _backupStorageAvailability.BackupStorageAvailability.createFromDbCopyJob(job);
90
109
  return await storageAvailability.validateAndPromptDiskSpaceWarningForDevEnvBackupImport();
@@ -98,7 +117,7 @@ class DevEnvSyncSQLCommand {
98
117
  const exportCommand = new _exportSql.ExportSQLCommand(this.app, this.env, {
99
118
  outputFile: this.gzFile,
100
119
  confirmEnoughStorageHook: this.confirmEnoughStorage.bind(this)
101
- }, this.track);
120
+ }, this.track.bind(this));
102
121
  await exportCommand.run();
103
122
  }
104
123
 
@@ -114,14 +133,13 @@ class DevEnvSyncSQLCommand {
114
133
  const readStream = _fs.default.createReadStream(this.sqlFile);
115
134
  const replacedStream = await (0, _vipSearchReplace.replace)(readStream, replacements);
116
135
  const outputFile = `${this.tmpDir}/sql-export-sr.sql`;
117
- replacedStream.pipe(_fs.default.createWriteStream(outputFile));
118
- return new Promise((resolve, reject) => {
119
- replacedStream.on('finish', () => {
120
- _fs.default.renameSync(outputFile, this.sqlFile);
121
- resolve();
122
- });
123
- replacedStream.on('error', reject);
124
- });
136
+ const streams = [replacedStream];
137
+ if (this.getSqlDumpType() === _database.SqlDumpType.MYDUMPER) {
138
+ streams.push((0, _database.fixMyDumperTransform)());
139
+ }
140
+ streams.push(_fs.default.createWriteStream(outputFile));
141
+ await (0, _promises.pipeline)(streams);
142
+ _fs.default.renameSync(outputFile, this.sqlFile);
125
143
  }
126
144
  generateSearchReplaceMap() {
127
145
  this.searchReplaceMap = {};
@@ -187,6 +205,7 @@ class DevEnvSyncSQLCommand {
187
205
  try {
188
206
  console.log(`Extracting the exported file ${this.gzFile}...`);
189
207
  await (0, _clientFileUploader.unzipFile)(this.gzFile, this.sqlFile);
208
+ await this.initSqlDumpType();
190
209
  console.log(`${_chalk.default.green('✓')} Extracted to ${this.sqlFile}`);
191
210
  } catch (err) {
192
211
  const error = err;
@@ -231,7 +250,6 @@ class DevEnvSyncSQLCommand {
231
250
  console.log('Importing the SQL file...');
232
251
  await this.runImport();
233
252
  console.log(`${_chalk.default.green('✓')} SQL file imported`);
234
- return true;
235
253
  } catch (err) {
236
254
  const error = err;
237
255
  await this.track('error', {
@@ -241,6 +259,7 @@ class DevEnvSyncSQLCommand {
241
259
  });
242
260
  exit.withError(`Error importing SQL file: ${error.message}`);
243
261
  }
262
+ return true;
244
263
  }
245
264
  }
246
265
  exports.DevEnvSyncSQLCommand = DevEnvSyncSQLCommand;
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.getSqlDumpDetails = exports.fixMyDumperTransform = exports.SqlDumpType = void 0;
5
+ var _nodeFs = _interopRequireDefault(require("node:fs"));
6
+ var _nodeReadline = _interopRequireDefault(require("node:readline"));
7
+ var _nodeStream = require("node:stream");
8
+ var _nodeZlib = _interopRequireDefault(require("node:zlib"));
9
+ var _promise = require("./promise");
10
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
11
+ let SqlDumpType = exports.SqlDumpType = /*#__PURE__*/function (SqlDumpType) {
12
+ SqlDumpType["MYDUMPER"] = "MYDUMPER";
13
+ SqlDumpType["MYSQLDUMP"] = "MYSQLDUMP";
14
+ return SqlDumpType;
15
+ }({});
16
+ const getSqlDumpDetails = async filePath => {
17
+ const isCompressed = filePath.endsWith('.gz');
18
+ let fileStream;
19
+ // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
20
+ const fileStreamExternalPromise = (0, _promise.createExternalizedPromise)();
21
+ if (isCompressed) {
22
+ fileStream = await getSqlFileStreamFromCompressedFile(filePath);
23
+ } else {
24
+ fileStream = _nodeFs.default.createReadStream(filePath);
25
+ }
26
+ const readLine = _nodeReadline.default.createInterface({
27
+ input: fileStream,
28
+ crlfDelay: Infinity
29
+ });
30
+ let isMyDumper = false;
31
+ let sourceDB = '';
32
+ let currentLineNumber = 0;
33
+ for await (const line of readLine) {
34
+ if (line === '') {
35
+ continue;
36
+ }
37
+ const metadataMatch = line.match(/^-- metadata.header /);
38
+ const sourceDBMatch = line.match(/^-- (.*)-schema-create.sql/) ?? [];
39
+ const sourceDBName = sourceDBMatch[1];
40
+ if (metadataMatch && !isMyDumper) {
41
+ isMyDumper = true;
42
+ }
43
+ if (sourceDBMatch && !sourceDB) {
44
+ sourceDB = sourceDBName;
45
+ }
46
+ if (sourceDB && isMyDumper) {
47
+ // all fields found? end the search early.
48
+ break;
49
+ }
50
+ if (currentLineNumber > 100) {
51
+ // we'll assume that this isn't the correct file if we still haven't found `-- metadata.header` even at the 100th line.
52
+ break;
53
+ }
54
+ currentLineNumber++;
55
+ }
56
+ if (fileStream instanceof _nodeFs.default.ReadStream) {
57
+ fileStream.on('close', () => {
58
+ fileStreamExternalPromise.resolve();
59
+ });
60
+ } else {
61
+ fileStreamExternalPromise.resolve();
62
+ }
63
+ readLine.close();
64
+ fileStream.close();
65
+ await fileStreamExternalPromise.promise;
66
+ return {
67
+ type: isMyDumper ? SqlDumpType.MYDUMPER : SqlDumpType.MYSQLDUMP,
68
+ sourceDb: sourceDB
69
+ };
70
+ };
71
+ exports.getSqlDumpDetails = getSqlDumpDetails;
72
+ const verifyFileExists = async filePath => {
73
+ try {
74
+ await _nodeFs.default.promises.access(filePath, _nodeFs.default.constants.F_OK);
75
+ } catch {
76
+ throw new Error('File not accessible. Does file exist?');
77
+ }
78
+ };
79
+ const getSqlFileStreamFromGz = async filePath => {
80
+ await verifyFileExists(filePath);
81
+ return _nodeFs.default.createReadStream(filePath).pipe(_nodeZlib.default.createGunzip());
82
+ };
83
+ const getSqlFileStreamFromCompressedFile = async filePath => {
84
+ if (filePath.endsWith('.gz')) {
85
+ return await getSqlFileStreamFromGz(filePath);
86
+ }
87
+ throw new Error('Not a supported compressed file');
88
+ };
89
+ const fixMyDumperTransform = () => {
90
+ return new _nodeStream.Transform({
91
+ transform(chunk, _encoding, callback) {
92
+ const chunkString = chunk.toString();
93
+ const lineEnding = chunkString.includes('\r\n') ? '\r\n' : '\n';
94
+ const regex = /^-- ([^ ]+) [0-9]+$/;
95
+ const lines = chunk.toString().split(lineEnding).map(line => {
96
+ const match = line.match(regex);
97
+ if (!match) {
98
+ return line;
99
+ }
100
+ const tablePart = match[1];
101
+ return `-- ${tablePart} -1`;
102
+ });
103
+ callback(null, lines.join(lineEnding));
104
+ }
105
+ });
106
+ };
107
+ exports.fixMyDumperTransform = fixMyDumperTransform;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.reIndexSearch = exports.flushCache = exports.addAdminUser = void 0;
5
+ var _devEnvironmentCore = require("./dev-environment-core");
6
+ const addAdminUser = async (lando, slug, quiet) => {
7
+ const addUserArg = ['wp', 'dev-env-add-admin', '--username=vipgo', '--password=password', '--skip-plugins', '--skip-themes'].concat(quiet ? ['--quiet'] : []);
8
+ await (0, _devEnvironmentCore.exec)(lando, slug, addUserArg);
9
+ };
10
+ exports.addAdminUser = addAdminUser;
11
+ const reIndexSearch = async (lando, slug) => {
12
+ await (0, _devEnvironmentCore.exec)(lando, slug, ['wp', 'cli', 'has-command', 'vip-search']);
13
+ await (0, _devEnvironmentCore.exec)(lando, slug, ['wp', 'vip-search', 'index', '--setup', '--network-wide', '--skip-confirm']);
14
+ };
15
+ exports.reIndexSearch = reIndexSearch;
16
+ const flushCache = async (lando, slug, quiet) => {
17
+ const cacheArg = ['wp', 'cache', 'flush', '--skip-plugins', '--skip-themes'].concat(quiet ? ['--quiet'] : []);
18
+ await (0, _devEnvironmentCore.exec)(lando, slug, cacheArg);
19
+ };
20
+ exports.flushCache = flushCache;
@@ -33,10 +33,6 @@ const IMPORT_MEDIA_PROGRESS_QUERY = (0, _graphqlTag.default)`
33
33
  failureDetails {
34
34
  previousStatus
35
35
  globalErrors
36
- fileErrors {
37
- fileName
38
- errors
39
- }
40
36
  fileErrorsUrl
41
37
  }
42
38
  }
@@ -269,13 +265,6 @@ Downloading errors details from ${fileErrorsUrl}
269
265
  progressTracker.suffix += `${_chalk.default.yellow(`⚠️ ${errorsFound} error(s) were found. File import errors report link expired.`)}`;
270
266
  }
271
267
  }
272
- async function printFailureDetails(fileErrors, results) {
273
- progressTracker.suffix += `${_chalk.default.yellow(`⚠️ ${fileErrors.length} file import error(s) were found`)}`;
274
- if ((results.filesTotal ?? 0) - (results.filesProcessed ?? 0) !== fileErrors.length) {
275
- progressTracker.suffix += `. ${_chalk.default.italic.yellow('File import errors report size threshold reached.')}`;
276
- }
277
- await exportFailureDetails(fileErrors);
278
- }
279
268
  try {
280
269
  const results = await getResults();
281
270
  overallStatus = results.status ?? 'unknown';
@@ -284,18 +273,10 @@ Downloading errors details from ${fileErrorsUrl}
284
273
  progressTracker.print();
285
274
  if (results.failureDetails?.fileErrorsUrl) {
286
275
  await promptFailureDetailsDownload(results.failureDetails.fileErrorsUrl);
287
- } else {
288
- const fileErrors = results.failureDetails?.fileErrors ?? [];
289
- if (fileErrors.length > 0) {
290
- // Errors were observed and are present in the dto
291
- // Fall back to exporting errors to local file
292
- await printFailureDetails(fileErrors, results);
293
- } else if ('ABORTED' !== overallStatus) {
294
- // Errors are not present in the dto
295
- // And file error details report link is not available
296
- // do not print this message if the import was aborted
297
- printFileErrorsReportLinkExpiredError(results);
298
- }
276
+ } else if ('ABORTED' !== overallStatus) {
277
+ // print report link expired if required
278
+ // do not print this message if the import was aborted
279
+ printFileErrorsReportLinkExpiredError(results);
299
280
  }
300
281
 
301
282
  // Print one final time
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.createExternalizedPromise = void 0;
5
+ const createExternalizedPromise = () => {
6
+ let externalResolve = null;
7
+ let externalReject = null;
8
+ const externalizedPromise = new Promise((resolve, reject) => {
9
+ externalResolve = resolve;
10
+ externalReject = reject;
11
+ });
12
+ if (!externalReject || !externalResolve) {
13
+ throw new Error("Somehow, externalReject or externalResolve didn't get set.");
14
+ }
15
+ return {
16
+ promise: externalizedPromise,
17
+ resolve: externalResolve,
18
+ reject: externalReject
19
+ };
20
+ };
21
+ exports.createExternalizedPromise = createExternalizedPromise;
@@ -9,6 +9,7 @@ var _debug = _interopRequireDefault(require("debug"));
9
9
  var _fs = _interopRequireDefault(require("fs"));
10
10
  var _promises = require("node:stream/promises");
11
11
  var _path = _interopRequireDefault(require("path"));
12
+ var _database = require("./database");
12
13
  var _utils = require("./utils");
13
14
  var exit = _interopRequireWildcard(require("../lib/cli/exit"));
14
15
  var _prompt = require("../lib/cli/prompt");
@@ -76,9 +77,12 @@ const searchAndReplace = async (fileName, pairs, {
76
77
  inPlace = false,
77
78
  output = process.stdout
78
79
  }, binary = null) => {
80
+ const dumpDetails = await (0, _database.getSqlDumpDetails)(fileName);
81
+ const isMyDumper = dumpDetails.type === _database.SqlDumpType.MYDUMPER;
79
82
  await (0, _tracker.trackEvent)('searchreplace_started', {
80
83
  is_import: isImport,
81
- in_place: inPlace
84
+ in_place: inPlace,
85
+ sqldump_type: dumpDetails.type
82
86
  });
83
87
  const startTime = process.hrtime();
84
88
  const fileSize = (0, _clientFileUploader.getFileSize)(fileName);
@@ -103,7 +107,8 @@ const searchAndReplace = async (fileName, pairs, {
103
107
  if (!approved) {
104
108
  await (0, _tracker.trackEvent)('search_replace_in_place_cancelled', {
105
109
  is_import: isImport,
106
- in_place: inPlace
110
+ in_place: inPlace,
111
+ sqldump_type: dumpDetails.type
107
112
  });
108
113
  process.exit();
109
114
  }
@@ -125,8 +130,13 @@ const searchAndReplace = async (fileName, pairs, {
125
130
  // replace() throws strings... OMG
126
131
  exit.withError(replaceError);
127
132
  }
133
+ const streams = [replacedStream];
134
+ if (isMyDumper) {
135
+ streams.push((0, _database.fixMyDumperTransform)());
136
+ }
137
+ streams.push(writeStream);
128
138
  try {
129
- await (0, _promises.pipeline)(replacedStream, writeStream);
139
+ await (0, _promises.pipeline)(streams);
130
140
  } catch (error) {
131
141
  console.log((0, _chalk.red)("Oh no! We couldn't write to the output file. Please check your available disk space and file/folder permissions."));
132
142
  throw error;
@@ -136,7 +146,8 @@ const searchAndReplace = async (fileName, pairs, {
136
146
 
137
147
  await (0, _tracker.trackEvent)('searchreplace_completed', {
138
148
  time_to_run: end,
139
- file_size: fileSize
149
+ file_size: fileSize,
150
+ sqldump_type: dumpDetails.type
140
151
  });
141
152
  return {
142
153
  inputFileName: fileName,
@@ -0,0 +1 @@
1
+ "use strict";
@@ -260,7 +260,7 @@ const checks = {
260
260
  recommendation: "Disabling 'UNIQUE_CHECKS' is not allowed. These lines should be removed"
261
261
  },
262
262
  siteHomeUrl: {
263
- matcher: "'(siteurl|home)',\\s?'(.*?)'",
263
+ matcher: `['"](siteurl|home)['"],\\s?['"](.*?)['"]`,
264
264
  matchHandler: (lineNumber, results) => ({
265
265
  text: results[1] + ' ' + results[2]
266
266
  }),
@@ -271,7 +271,7 @@ const checks = {
271
271
  recommendation: ''
272
272
  },
273
273
  siteHomeUrlLando: {
274
- matcher: "'(siteurl|home)',\\s?'([^']+)'",
274
+ matcher: `['"](siteurl|home)['"],\\s?['"]([^'"]+)['"]`,
275
275
  matchHandler: (lineNumber, results, expectedDomain) => {
276
276
  let foundDomain = results[2];
277
277
  if (!/^https?:\/\//i.test(foundDomain)) {
package/docs/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  ## Changelog
2
2
 
3
+ ## 3.7.1
4
+
5
+ * New develop release: 3.7.1-dev.0 by @github-actions in #1944
6
+ * build(deps): bump step-security/harden-runner from 2.8.1 to 2.9.0 by @dependabot in #1950
7
+ * build(deps): bump semver from 7.6.2 to 7.6.3 by @dependabot in #1946
8
+ * build(deps-dev): bump @types/node from 18.19.39 to 18.19.41 by @dependabot in #1951
9
+ * refactor(dev-env): do not load SSH keys by @sjinks in #1934
10
+ * build(deps): bump tar from 7.4.0 to 7.4.1 by @dependabot in #1952
11
+ * build(deps-dev): bump typescript from 5.5.3 to 5.5.4 by @dependabot in #1954
12
+ * build(deps-dev): bump @types/node from 18.19.41 to 18.19.42 by @dependabot in #1956
13
+ * Refactor dev-env sync, dev-env import and export-sql to TypeScript by @abdullah-kasim in #1955
14
+ * build(deps): bump tar from 7.4.1 to 7.4.3 by @dependabot in #1963
15
+ * build(deps-dev): bump @types/dockerode from 3.3.30 to 3.3.31 by @dependabot in #1960
16
+ * Gracefully fail when directory is not detected by @ariskataoka in #1947
17
+ * New package release: v3.7.1 by @github-actions in #1966
18
+
19
+ **Full Changelog**: https://github.com/Automattic/vip-cli/compare/3.7.0...3.7.1
20
+
3
21
  ## 3.7.0
4
22
 
5
23
  * New develop release: 3.6.1-dev.0 by @github-actions in #1931