@automattic/vip 2.26.0 → 2.26.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  ## Changelog
2
2
 
3
+ ### 2.26.2
4
+
5
+ - #1278 Prepare v2.26.2
6
+ - #1277 Fix the PassThrough class import
7
+ - #1276 [dev-env] Add ability to override default options for lando with a global Lando config.yml
8
+
9
+ ### 2.26.1
10
+
11
+ - #1275 Prepare v2.26.1
12
+ - #1271 refactor(dev-env): Switch to mysql:8
13
+ - #1273 Add library for the dev-env-sync-sql command
14
+ - #1274 Run validation on filename & not on full filepath
15
+ - #1272 fix(dev-env): Suppress health warnings for new environments
16
+ - #1234 fix(dev-env): Force IPv4 for services bound to localhost
17
+
3
18
  ### 2.26.0
4
19
 
5
20
  - #1237 Skip requoting if the arg is a valid JSON Object
@@ -59,18 +59,28 @@ services:
59
59
  volume:
60
60
  nocopy: true
61
61
  <% wpVolumes() %>
62
+ run_as_root:
63
+ - chown www-data:www-data /wp/wp-content/mu-plugins /wp/config /wp/log /wp/wp-content/uploads /wp
62
64
  run:
63
65
  - sh /dev-tools/setup.sh database root "http://<%= siteSlug %>.vipdev.lndo.site/" "<%= wpTitle %>" <% if ( multisite ) { %> <%= siteSlug %>.vipdev.lndo.site <% } %>
64
66
 
65
67
  database:
66
68
  type: compose
67
69
  services:
70
+ <% if ( mariadb ) { %>
68
71
  image: mariadb:<%= mariadb %>
69
72
  command: docker-entrypoint.sh mysqld --sql-mode=ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION --max_allowed_packet=67M
73
+ <% } else { %>
74
+ image: mysql:8
75
+ command: docker-entrypoint.sh mysqld --sql-mode=ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION --max_allowed_packet=67M --default-authentication-plugin=mysql_native_password
76
+ <% } %>
70
77
  ports:
71
78
  - ":3306"
72
79
  environment:
73
- MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: 'true'
80
+ MYSQL_ALLOW_EMPTY_PASSWORD: 'true'
81
+ MYSQL_USER: wordpress
82
+ MYSQL_PASSWORD: wordpress
83
+ MYSQL_DATABASE: wordpress
74
84
  volumes:
75
85
  - database_data:/var/lib/mysql
76
86
  volumes:
Binary file
@@ -87,7 +87,8 @@ cmd.argv(process.argv, async (arg, opt) => {
87
87
  try {
88
88
  await (0, _devEnvironmentCore.createEnvironment)(instanceData);
89
89
  await (0, _devEnvironmentCore.printEnvironmentInfo)(lando, slug, {
90
- extended: false
90
+ extended: false,
91
+ suppressWarnings: true
91
92
  });
92
93
  const message = '\n' + _chalk.default.green('✓') + ` environment created.\n\nTo start it please run:\n\n${startCommand}\n`;
93
94
  console.log(message);
@@ -8,22 +8,18 @@
8
8
  /**
9
9
  * External dependencies
10
10
  */
11
+
12
+ /**
13
+ * Internal dependencies
14
+ */
11
15
  "use strict";
12
16
 
13
- var _fs = _interopRequireDefault(require("fs"));
14
- var _chalk = _interopRequireDefault(require("chalk"));
15
17
  var _tracker = require("../lib/tracker");
16
18
  var _command = _interopRequireDefault(require("../lib/cli/command"));
17
19
  var _devEnvironmentCli = require("../lib/dev-environment/dev-environment-cli");
18
- var _devEnvironmentCore = require("../lib/dev-environment/dev-environment-core");
19
20
  var _devEnvironment = require("../lib/constants/dev-environment");
20
- var _sql = require("../lib/validations/sql");
21
- var _devEnvironmentLando = require("../lib/dev-environment/dev-environment-lando");
22
- var _userError = _interopRequireDefault(require("../lib/user-error"));
21
+ var _devEnvImportSql = require("../commands/dev-env-import-sql");
23
22
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
24
- /**
25
- * Internal dependencies
26
- */
27
23
  const examples = [{
28
24
  usage: `${_devEnvironment.DEV_ENVIRONMENT_FULL_COMMAND} import sql some-wp-db-file.sql`,
29
25
  description: 'Import the contents of a WordPress database from an SQL file'
@@ -41,65 +37,10 @@ const examples = [{
41
37
  requiredArgs: 1
42
38
  }).option('slug', 'Custom name of the dev environment').option(['r', 'search-replace'], 'Perform Search and Replace on the specified SQL file').option('in-place', 'Search and Replace explicitly on the given input file').option('skip-validate', 'Do not perform file validation.').examples(examples).argv(process.argv, async (unmatchedArgs, opt) => {
43
39
  const [fileName] = unmatchedArgs;
44
- const {
45
- searchReplace,
46
- inPlace
47
- } = opt;
48
- const slug = (0, _devEnvironmentCli.getEnvironmentName)(opt);
49
- const lando = await (0, _devEnvironmentLando.bootstrapLando)();
50
- await (0, _devEnvironmentCli.validateDependencies)(lando, slug);
51
- const trackingInfo = (0, _devEnvironmentCli.getEnvTrackingInfo)(slug);
52
- await (0, _tracker.trackEvent)('dev_env_import_sql_command_execute', trackingInfo);
40
+ const cmd = new _devEnvImportSql.DevEnvImportSQLCommand(fileName, opt);
41
+ const trackingInfo = (0, _devEnvironmentCli.getEnvTrackingInfo)(cmd.slug);
53
42
  try {
54
- const resolvedPath = await (0, _devEnvironmentCore.resolveImportPath)(slug, fileName, searchReplace, inPlace);
55
- if (!opt.skipValidate) {
56
- if (!(0, _devEnvironmentLando.isEnvUp)(lando, (0, _devEnvironmentCore.getEnvironmentPath)(slug))) {
57
- throw new _userError.default('Environment needs to be started first');
58
- }
59
- const expectedDomain = `${slug}.vipdev.lndo.site`;
60
- await (0, _sql.validate)(resolvedPath, {
61
- isImport: false,
62
- skipChecks: [],
63
- extraCheckParams: {
64
- siteHomeUrlLando: expectedDomain
65
- }
66
- });
67
- }
68
- const fd = await _fs.default.promises.open(resolvedPath, 'r');
69
- const importArg = ['db', '--disable-auto-rehash'];
70
- const origIsTTY = process.stdin.isTTY;
71
- try {
72
- /**
73
- * When stdin is a TTY, Lando passes the `--tty` flag to Docker.
74
- * This breaks our code when we pass the stream as stdin to Docker.
75
- * exec() then fails with "the input device is not a TTY".
76
- *
77
- * Therefore, for the things to work, we have to pretend that stdin is not a TTY :-)
78
- */
79
- process.stdin.isTTY = false;
80
- await (0, _devEnvironmentCore.exec)(lando, slug, importArg, {
81
- stdio: [fd, 'pipe', 'pipe']
82
- });
83
- console.log(`${_chalk.default.green.bold('Success:')} Database imported.`);
84
- } finally {
85
- process.stdin.isTTY = origIsTTY;
86
- }
87
- if (searchReplace && searchReplace.length && !inPlace) {
88
- _fs.default.unlinkSync(resolvedPath);
89
- }
90
- const cacheArg = ['wp', 'cache', 'flush'];
91
- await (0, _devEnvironmentCore.exec)(lando, slug, cacheArg);
92
- try {
93
- await (0, _devEnvironmentCore.exec)(lando, slug, ['wp', 'cli', 'has-command', 'vip-search']);
94
- const doIndex = await (0, _devEnvironmentCli.promptForBoolean)('Do you want to index data in Elasticsearch (used by Enterprise Search)?', true);
95
- if (doIndex) {
96
- await (0, _devEnvironmentCore.exec)(lando, slug, ['wp', 'vip-search', 'index', '--setup', '--network-wide', '--skip-confirm']);
97
- }
98
- } catch (err) {
99
- // Exception means they don't have vip-search enabled.
100
- }
101
- const addUserArg = ['wp', 'dev-env-add-admin', '--username=vipgo', '--password=password'];
102
- await (0, _devEnvironmentCore.exec)(lando, slug, addUserArg);
43
+ await cmd.run();
103
44
  await (0, _tracker.trackEvent)('dev_env_import_sql_command_success', trackingInfo);
104
45
  } catch (error) {
105
46
  await (0, _devEnvironmentCli.handleCLIException)(error, 'dev_env_import_sql_command_error', trackingInfo);
@@ -40,7 +40,8 @@ const examples = [{
40
40
  debug('Args: ', arg, 'Options: ', opt);
41
41
  try {
42
42
  const options = {
43
- extended: !!opt.extended
43
+ extended: !!opt.extended,
44
+ suppressWarnings: true
44
45
  };
45
46
  if (opt.all) {
46
47
  await (0, _devEnvironmentCore.printAllEnvironmentsInfo)(lando, options);
@@ -52,7 +52,7 @@ cmd.argv(process.argv, async (arg, opt) => {
52
52
  const defaultOptions = {
53
53
  appCode: currentInstanceData.appCode.dir || currentInstanceData.appCode.tag || 'latest',
54
54
  muPlugins: currentInstanceData.muPlugins.dir || currentInstanceData.muPlugins.tag || 'latest',
55
- wordpress: currentInstanceData.wordpress.tag,
55
+ wordpress: currentInstanceData.wordpress.tag || 'trunk',
56
56
  elasticsearch: currentInstanceData.elasticsearch,
57
57
  php: currentInstanceData.php || _devEnvironment.DEV_ENVIRONMENT_PHP_VERSIONS.default,
58
58
  mariadb: currentInstanceData.mariadb,
@@ -66,8 +66,8 @@ cmd.argv(process.argv, async (arg, opt) => {
66
66
  const providedOptions = Object.keys(opt).filter(option => option.length > 1) // Filter out single letter aliases
67
67
  .filter(option => !['debug', 'help', 'slug'].includes(option)); // Filter out options that are not related to instance configuration
68
68
 
69
- const supressPrompts = providedOptions.length > 0;
70
- const instanceData = await (0, _devEnvironmentCli.promptForArguments)(preselectedOptions, defaultOptions, supressPrompts);
69
+ const suppressPrompts = providedOptions.length > 0;
70
+ const instanceData = await (0, _devEnvironmentCli.promptForArguments)(preselectedOptions, defaultOptions, suppressPrompts);
71
71
  instanceData.siteSlug = slug;
72
72
  await (0, _devEnvironmentCore.updateEnvironment)(instanceData);
73
73
  const message = '\n' + _chalk.default.green('✓') + ' environment updated. Restart environment for changes to take an affect.';
@@ -353,10 +353,10 @@ const displayPlaybook = ({
353
353
  const domain = env !== null && env !== void 0 && (_env$primaryDomain = env.primaryDomain) !== null && _env$primaryDomain !== void 0 && _env$primaryDomain.name ? env.primaryDomain.name : `#${env.id}`;
354
354
  const formattedEnvironment = (0, _format.formatEnvironment)(opts.env.type);
355
355
  const launched = opts.env.launched;
356
- let fileNameToUpload = fileName;
357
356
 
358
- // Exit if filename contains unsafe character
359
- validateFilename(fileNameToUpload);
357
+ // Extract base file name and exit if it contains unsafe character
358
+ validateFilename(fileMeta.basename);
359
+ let fileNameToUpload = fileName;
360
360
 
361
361
  // SQL file validations
362
362
  const tableNames = await validateAndGetTableNames({
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.DevEnvImportSQLCommand = void 0;
7
+ var _fs = _interopRequireDefault(require("fs"));
8
+ var _chalk = _interopRequireDefault(require("chalk"));
9
+ var _devEnvironmentCli = require("../lib/dev-environment/dev-environment-cli");
10
+ var _devEnvironmentCore = require("../lib/dev-environment/dev-environment-core");
11
+ var _devEnvironmentLando = require("../lib/dev-environment/dev-environment-lando");
12
+ var _userError = _interopRequireDefault(require("../lib/user-error"));
13
+ var _sql = require("../lib/validations/sql");
14
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
15
+ /**
16
+ *
17
+ * @format
18
+ */
19
+
20
+ /**
21
+ * External dependencies
22
+ */
23
+
24
+ /**
25
+ * Internal dependencies
26
+ */
27
+
28
+ class DevEnvImportSQLCommand {
29
+ constructor(fileName, options) {
30
+ this.fileName = fileName;
31
+ this.options = options;
32
+ this.slug = (0, _devEnvironmentCli.getEnvironmentName)(options);
33
+ }
34
+ async run(silent = false) {
35
+ const lando = await (0, _devEnvironmentLando.bootstrapLando)();
36
+ await (0, _devEnvironmentCli.validateDependencies)(lando, this.slug, silent);
37
+ const {
38
+ searchReplace,
39
+ inPlace
40
+ } = this.options;
41
+ const resolvedPath = await (0, _devEnvironmentCore.resolveImportPath)(this.slug, this.fileName, searchReplace, inPlace);
42
+ if (!this.options.skipValidate) {
43
+ if (!(await (0, _devEnvironmentLando.isEnvUp)(lando, (0, _devEnvironmentCore.getEnvironmentPath)(this.slug)))) {
44
+ throw new _userError.default('Environment needs to be started first');
45
+ }
46
+ const expectedDomain = `${this.slug}.vipdev.lndo.site`;
47
+ await (0, _sql.validate)(resolvedPath, {
48
+ isImport: false,
49
+ skipChecks: [],
50
+ extraCheckParams: {
51
+ siteHomeUrlLando: expectedDomain
52
+ }
53
+ });
54
+ }
55
+ const fd = await _fs.default.promises.open(resolvedPath, 'r');
56
+ const importArg = ['db', '--disable-auto-rehash'];
57
+ const origIsTTY = process.stdin.isTTY;
58
+ try {
59
+ /**
60
+ * When stdin is a TTY, Lando passes the `--tty` flag to Docker.
61
+ * This breaks our code when we pass the stream as stdin to Docker.
62
+ * exec() then fails with "the input device is not a TTY".
63
+ *
64
+ * Therefore, for the things to work, we have to pretend that stdin is not a TTY :-)
65
+ */
66
+ process.stdin.isTTY = false;
67
+ await (0, _devEnvironmentCore.exec)(lando, this.slug, importArg, {
68
+ stdio: [fd, 'pipe', 'pipe']
69
+ });
70
+ if (!silent) {
71
+ console.log(`${_chalk.default.green.bold('Success:')} Database imported.`);
72
+ }
73
+ } finally {
74
+ process.stdin.isTTY = origIsTTY;
75
+ }
76
+ if (searchReplace && searchReplace.length && !inPlace) {
77
+ _fs.default.unlinkSync(resolvedPath);
78
+ }
79
+ const cacheArg = ['wp', 'cache', 'flush'];
80
+ await (0, _devEnvironmentCore.exec)(lando, this.slug, cacheArg);
81
+ try {
82
+ await (0, _devEnvironmentCore.exec)(lando, this.slug, ['wp', 'cli', 'has-command', 'vip-search']);
83
+ const doIndex = await (0, _devEnvironmentCli.promptForBoolean)('Do you want to index data in Elasticsearch (used by Enterprise Search)?', true);
84
+ if (doIndex) {
85
+ await (0, _devEnvironmentCore.exec)(lando, this.slug, ['wp', 'vip-search', 'index', '--setup', '--network-wide', '--skip-confirm']);
86
+ }
87
+ } catch (err) {
88
+ // Exception means they don't have vip-search enabled.
89
+ }
90
+ const addUserArg = ['wp', 'dev-env-add-admin', '--username=vipgo', '--password=password'];
91
+ await (0, _devEnvironmentCore.exec)(lando, this.slug, addUserArg);
92
+ }
93
+ }
94
+ exports.DevEnvImportSQLCommand = DevEnvImportSQLCommand;
@@ -0,0 +1,184 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ *
5
+ * @format
6
+ */
7
+
8
+ /**
9
+ * External dependencies
10
+ */
11
+ "use strict";
12
+
13
+ Object.defineProperty(exports, "__esModule", {
14
+ value: true
15
+ });
16
+ exports.DevEnvSyncSQLCommand = void 0;
17
+ var _fs = _interopRequireDefault(require("fs"));
18
+ var _chalk = _interopRequireDefault(require("chalk"));
19
+ var _vipSearchReplace = require("@automattic/vip-search-replace");
20
+ var _clientFileUploader = require("../lib/client-file-uploader");
21
+ var _exportSql = require("./export-sql");
22
+ var _utils = require("../lib/utils");
23
+ var _lineByLine = require("../lib/validations/line-by-line");
24
+ var exit = _interopRequireWildcard(require("../lib/cli/exit"));
25
+ var _devEnvImportSql = require("./dev-env-import-sql");
26
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
27
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
28
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
29
+ /**
30
+ * Internal dependencies
31
+ */
32
+ /**
33
+ * Finds the site home url from the SQL line
34
+ *
35
+ * @param {string} sql A line in a SQL file
36
+ * @return {string} Site home url. null if not found
37
+ */
38
+ function findSiteHomeUrl(sql) {
39
+ const regex = "'(siteurl|home)',\\s?'(.*?)'";
40
+ const results = sql.match(regex);
41
+ if (results) {
42
+ const domain = results[2].replace(/https?:\/\//, '');
43
+ return domain;
44
+ }
45
+ return null;
46
+ }
47
+
48
+ /**
49
+ * Extracts a list of site urls from the SQL file
50
+ *
51
+ * @param {string} sqlFile Path to the SQL file
52
+ * @return {Promise<string[]>} List of site urls
53
+ * @throws {Error} If there is an error reading the file
54
+ */
55
+ async function extractSiteUrls(sqlFile) {
56
+ const readInterface = await (0, _lineByLine.getReadInterface)(sqlFile);
57
+ return new Promise((resolve, reject) => {
58
+ const domains = [];
59
+ readInterface.on('line', line => {
60
+ const domain = findSiteHomeUrl(line);
61
+ if (domain) {
62
+ domains.push(domain);
63
+ }
64
+ });
65
+ readInterface.on('close', () => {
66
+ resolve(domains);
67
+ });
68
+ readInterface.on('error', reject);
69
+ });
70
+ }
71
+ class DevEnvSyncSQLCommand {
72
+ /**
73
+ * Creates a new instance of the command
74
+ *
75
+ * @param {string} app The app object
76
+ * @param {string} env The environment object
77
+ * @param {string} slug The site slug
78
+ */
79
+ constructor(app, env, slug) {
80
+ this.app = app;
81
+ this.env = env;
82
+ this.slug = slug;
83
+ this.tmpDir = (0, _utils.makeTempDir)();
84
+ }
85
+ get landoDomain() {
86
+ return `${this.slug}.vipdev.lndo.site`;
87
+ }
88
+ get sqlFile() {
89
+ return `${this.tmpDir}/sql-export.sql`;
90
+ }
91
+ get gzFile() {
92
+ return `${this.tmpDir}/sql-export.sql.gz`;
93
+ }
94
+
95
+ /**
96
+ * Runs the SQL export command to generate the SQL export from
97
+ * the latest backup
98
+ *
99
+ * @return {Promise<void>} Promise that resolves when the export is complete
100
+ */
101
+ async generateExport() {
102
+ const exportCommand = new _exportSql.ExportSQLCommand(this.app, this.env, this.gzFile);
103
+ await exportCommand.run();
104
+ }
105
+
106
+ /**
107
+ * Runs the search-replace operation on the SQL file
108
+ * to replace the site urls with the lando domain
109
+ *
110
+ * @return {Promise<void>} Promise that resolves when the search-replace is complete
111
+ * @throws {Error} If there is an error reading the file
112
+ */
113
+ async runSearchReplace() {
114
+ const replacements = this.siteUrls.reduce((acc, url) => [...acc, url, this.landoDomain], []);
115
+ const readStream = _fs.default.createReadStream(this.sqlFile);
116
+ const replacedStream = await (0, _vipSearchReplace.replace)(readStream, replacements);
117
+ replacedStream.pipe(_fs.default.createWriteStream(this.sqlFile));
118
+ return new Promise((resolve, reject) => {
119
+ replacedStream.on('finish', resolve);
120
+ replacedStream.on('error', reject);
121
+ });
122
+ }
123
+
124
+ /**
125
+ * Runs the SQL import command to import the SQL file
126
+ *
127
+ * @return {Promise<void>} Promise that resolves when the import is complete
128
+ * @throws {Error} If there is an error importing the file
129
+ */
130
+ async runImport() {
131
+ const importOptions = {
132
+ slug: this.slug,
133
+ inPlace: true,
134
+ skipValidate: true
135
+ };
136
+ const importCommand = new _devEnvImportSql.DevEnvImportSQLCommand(this.sqlFile, importOptions);
137
+ await importCommand.run(true);
138
+ }
139
+
140
+ /**
141
+ * Sequentially runs the commands to export, search-replace, and import the SQL file
142
+ * to the local environment
143
+ *
144
+ * @return {Promise<void>} Promise that resolves when the commands are complete
145
+ */
146
+ async run() {
147
+ try {
148
+ await this.generateExport();
149
+ } catch (err) {
150
+ exit.withError(`Error exporting SQL backup: ${err === null || err === void 0 ? void 0 : err.message}`);
151
+ }
152
+ try {
153
+ console.log(`Extracting the exported file ${this.gzFile}...`);
154
+ await (0, _clientFileUploader.unzipFile)(this.gzFile, this.sqlFile);
155
+ console.log(`${_chalk.default.green('✓')} Extracted to ${this.sqlFile}`);
156
+ } catch (err) {
157
+ exit.withError(`Error extracting the SQL export: ${err === null || err === void 0 ? void 0 : err.message}`);
158
+ }
159
+ try {
160
+ console.log('Extracting site urls from the SQL file...');
161
+ this.siteUrls = await extractSiteUrls(this.sqlFile);
162
+ } catch (err) {
163
+ exit.withError(`Error extracting site URLs: ${err === null || err === void 0 ? void 0 : err.message}`);
164
+ }
165
+ try {
166
+ console.log('Running the following search-replace operations on the SQL file:');
167
+ this.siteUrls.forEach(domain => {
168
+ console.log(` ${domain} -> ${this.landoDomain}`);
169
+ });
170
+ await this.runSearchReplace();
171
+ console.log(`${_chalk.default.green('✓')} Search-replace operation is complete`);
172
+ } catch (err) {
173
+ exit.withError(`Error replacing domains: ${err === null || err === void 0 ? void 0 : err.message}`);
174
+ }
175
+ try {
176
+ console.log('Importing the SQL file...');
177
+ await this.runImport();
178
+ console.log(`${_chalk.default.green('✓')} SQL file imported`);
179
+ } catch (err) {
180
+ exit.withError(`Error importing SQL file: ${err === null || err === void 0 ? void 0 : err.message}`);
181
+ }
182
+ }
183
+ }
184
+ exports.DevEnvSyncSQLCommand = DevEnvSyncSQLCommand;
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.SQLExportCommand = exports.GENERATE_DOWNLOAD_LINK_MUTATION = exports.CREATE_EXPORT_JOB_MUTATION = void 0;
6
+ exports.GENERATE_DOWNLOAD_LINK_MUTATION = exports.ExportSQLCommand = exports.CREATE_EXPORT_JOB_MUTATION = void 0;
7
7
  var _graphqlTag = _interopRequireDefault(require("graphql-tag"));
8
8
  var _fs = _interopRequireDefault(require("fs"));
9
9
  var _https = _interopRequireDefault(require("https"));
@@ -188,7 +188,7 @@ async function createExportJob(appId, envId, backupId) {
188
188
  /**
189
189
  * Class representing an export command workflow
190
190
  */
191
- class SQLExportCommand {
191
+ class ExportSQLCommand {
192
192
  steps = {
193
193
  PREPARE: 'prepare',
194
194
  CREATE: 'create',
@@ -313,7 +313,7 @@ class SQLExportCommand {
313
313
  *
314
314
  * @return {Promise} A promise which resolves to void
315
315
  */
316
- async runSequence() {
316
+ async run() {
317
317
  console.log(`Fetching the latest backup for ${this.app.name}`);
318
318
  const {
319
319
  latestBackup
@@ -357,4 +357,4 @@ class SQLExportCommand {
357
357
  }
358
358
  }
359
359
  }
360
- exports.SQLExportCommand = SQLExportCommand;
360
+ exports.ExportSQLCommand = ExportSQLCommand;
@@ -15,6 +15,7 @@ exports.getPartBoundaries = getPartBoundaries;
15
15
  exports.getSignedUploadRequestData = getSignedUploadRequestData;
16
16
  exports.gzipFile = exports.getWorkingTempDir = void 0;
17
17
  exports.isFile = isFile;
18
+ exports.unzipFile = void 0;
18
19
  exports.uploadImportSqlFileToS3 = uploadImportSqlFileToS3;
19
20
  exports.uploadPart = uploadPart;
20
21
  exports.uploadParts = uploadParts;
@@ -27,6 +28,7 @@ var _nodeFetch = _interopRequireDefault(require("node-fetch"));
27
28
  var _chalk = _interopRequireDefault(require("chalk"));
28
29
  var _zlib = require("zlib");
29
30
  var _crypto = require("crypto");
31
+ var _promises = require("node:stream/promises");
30
32
  var _stream = require("stream");
31
33
  var _xml2js = require("xml2js");
32
34
  var _debug = _interopRequireDefault(require("debug"));
@@ -77,7 +79,21 @@ const getFileMD5Hash = async fileName => new Promise((resolve, reject) => _fs.de
77
79
  }).on('error', error => reject(`could not generate file hash: ${error}`)));
78
80
  exports.getFileMD5Hash = getFileMD5Hash;
79
81
  const gzipFile = async (uncompressedFileName, compressedFileName) => new Promise((resolve, reject) => _fs.default.createReadStream(uncompressedFileName).pipe((0, _zlib.createGzip)()).pipe(_fs.default.createWriteStream(compressedFileName)).on('finish', resolve).on('error', error => reject(`could not compress file: ${error}`)));
82
+
83
+ /**
84
+ * Extract a .gz file and save it to a specified location
85
+ *
86
+ * @param {string} inputFilename The file to unzip
87
+ * @param {string} outputFilename The file where the unzipped data will be written
88
+ * @return {Promise} A promise that resolves when the file is unzipped
89
+ */
80
90
  exports.gzipFile = gzipFile;
91
+ const unzipFile = async (inputFilename, outputFilename) => {
92
+ const source = _fs.default.createReadStream(inputFilename);
93
+ const destination = _fs.default.createWriteStream(outputFilename);
94
+ await (0, _promises.pipeline)(source, (0, _zlib.createGunzip)(), destination);
95
+ };
96
+ exports.unzipFile = unzipFile;
81
97
  async function getFileMeta(fileName) {
82
98
  const fileSize = await getFileSize(fileName);
83
99
  const basename = _path.default.basename(fileName);
@@ -11,7 +11,6 @@ exports.DEV_ENVIRONMENT_FULL_COMMAND = DEV_ENVIRONMENT_FULL_COMMAND;
11
11
  const DEV_ENVIRONMENT_DEFAULTS = {
12
12
  title: 'VIP Dev',
13
13
  multisite: false,
14
- mariadbVersion: '10.3',
15
14
  phpVersion: '8.0'
16
15
  };
17
16
  exports.DEV_ENVIRONMENT_DEFAULTS = DEV_ENVIRONMENT_DEFAULTS;
@@ -14,6 +14,7 @@ exports.handleCLIException = handleCLIException;
14
14
  exports.printTable = printTable;
15
15
  exports.processBooleanOption = processBooleanOption;
16
16
  exports.processComponentOptionInput = processComponentOptionInput;
17
+ exports.processVersionOption = processVersionOption;
17
18
  exports.promptForArguments = promptForArguments;
18
19
  exports.promptForBoolean = promptForBoolean;
19
20
  exports.promptForComponent = promptForComponent;
@@ -274,7 +275,7 @@ async function promptForArguments(preselectedOptions, defaultOptions, suppressPr
274
275
  multisite: 'multisite' in preselectedOptions ? preselectedOptions.multisite : await promptForBoolean(multisiteText, !!multisiteDefault),
275
276
  elasticsearch: false,
276
277
  php: preselectedOptions.php ? resolvePhpVersion(preselectedOptions.php) : await promptForPhpVersion(resolvePhpVersion(defaultOptions.php || _devEnvironment.DEV_ENVIRONMENT_DEFAULTS.phpVersion)),
277
- mariadb: preselectedOptions.mariadb || defaultOptions.mariadb || _devEnvironment.DEV_ENVIRONMENT_DEFAULTS.mariadbVersion,
278
+ mariadb: preselectedOptions.mariadb || defaultOptions.mariadb,
278
279
  mediaRedirectDomain: preselectedOptions.mediaRedirectDomain || '',
279
280
  wordpress: {
280
281
  mode: 'image',
@@ -343,7 +344,9 @@ async function processComponent(component, preselectedValue, defaultValue) {
343
344
  const defaultObject = defaultValue ? processComponentOptionInput(defaultValue, allowLocal) : null;
344
345
  if (preselectedValue) {
345
346
  result = processComponentOptionInput(preselectedValue, allowLocal);
346
- console.log(`${_chalk.default.green('✓')} Path to your local ${componentDisplayNames[component]}: ${preselectedValue}`);
347
+ if (allowLocal) {
348
+ console.log(`${_chalk.default.green('✓')} Path to your local ${componentDisplayNames[component]}: ${preselectedValue}`);
349
+ }
347
350
  } else {
348
351
  result = await promptForComponent(component, allowLocal, defaultObject);
349
352
  }
@@ -449,9 +452,7 @@ function resolvePhpVersion(version) {
449
452
  }
450
453
  const versions = Object.keys(_devEnvironment.DEV_ENVIRONMENT_PHP_VERSIONS);
451
454
  const images = Object.values(_devEnvironment.DEV_ENVIRONMENT_PHP_VERSIONS);
452
-
453
- // eslint-disable-next-line eqeqeq -- use loose comparison because commander resolves '8.0' to '8'
454
- const index = versions.findIndex(value => value == version);
455
+ const index = versions.findIndex(value => value === version);
455
456
  if (index === -1) {
456
457
  const image = images.find(value => value === version);
457
458
  return image !== null && image !== void 0 ? image : images[0];
@@ -551,8 +552,16 @@ function processBooleanOption(value) {
551
552
  }
552
553
  return !FALSE_OPTIONS.includes((_value$toLowerCase = value.toLowerCase) === null || _value$toLowerCase === void 0 ? void 0 : _value$toLowerCase.call(value));
553
554
  }
555
+ function processVersionOption(value) {
556
+ if (!isNaN(value) && value % 1 === 0) {
557
+ // If it's an Integer passed in, let's ensure that it has a decimal in it to match the version tags e.g. 6 => 6.0
558
+ return parseFloat(value).toFixed(1);
559
+ }
560
+ return value;
561
+ }
554
562
  function addDevEnvConfigurationOptions(command) {
555
- return command.option('wordpress', 'Use a specific WordPress version').option(['u', 'mu-plugins'], 'Use a specific mu-plugins changeset or local directory').option('app-code', 'Use the application code from a local directory or use "demo" for VIP skeleton code').option('phpmyadmin', 'Enable PHPMyAdmin component. By default it is disabled', undefined, processBooleanOption).option('xdebug', 'Enable XDebug. By default it is disabled', undefined, processBooleanOption).option('xdebug_config', 'Extra configuration to pass to xdebug via XDEBUG_CONFIG environment variable').option('elasticsearch', 'Enable Elasticsearch (needed by Enterprise Search)', undefined, processBooleanOption).option('mariadb', 'Explicitly choose MariaDB version to use').option(['r', 'media-redirect-domain'], 'Domain to redirect for missing media files. This can be used to still have images without the need to import them locally.').option('php', 'Explicitly choose PHP version to use').option(['A', 'mailhog'], 'Enable MailHog. By default it is disabled', undefined, processBooleanOption);
563
+ // We leave the third parameter to undefined on some because the defaults are handled in preProcessInstanceData()
564
+ return command.option('wordpress', 'Use a specific WordPress version', undefined, processVersionOption).option(['u', 'mu-plugins'], 'Use a specific mu-plugins changeset or local directory').option('app-code', 'Use the application code from a local directory or use "demo" for VIP skeleton code').option('phpmyadmin', 'Enable PHPMyAdmin component. By default it is disabled', undefined, processBooleanOption).option('xdebug', 'Enable XDebug. By default it is disabled', undefined, processBooleanOption).option('xdebug_config', 'Extra configuration to pass to xdebug via XDEBUG_CONFIG environment variable').option('elasticsearch', 'Enable Elasticsearch (needed by Enterprise Search)', undefined, processBooleanOption).option(['r', 'media-redirect-domain'], 'Domain to redirect for missing media files. This can be used to still have images without the need to import them locally.').option('php', 'Explicitly choose PHP version to use', undefined, processVersionOption).option(['A', 'mailhog'], 'Enable MailHog. By default it is disabled', undefined, processBooleanOption);
556
565
  }
557
566
 
558
567
  /**
@@ -562,20 +571,20 @@ async function getTagChoices() {
562
571
  let versions = await (0, _devEnvironmentCore.getVersionList)();
563
572
  if (versions.length < 1) {
564
573
  versions = [{
565
- ref: '5.9.5',
566
- tag: '5.9',
574
+ ref: '6.1.1',
575
+ tag: '6.1',
567
576
  cacheable: true,
568
577
  locked: true,
569
578
  prerelease: false
570
579
  }, {
571
- ref: '5.8.6',
572
- tag: '5.8',
580
+ ref: '6.0.3',
581
+ tag: '6.0',
573
582
  cacheable: true,
574
583
  locked: true,
575
584
  prerelease: false
576
585
  }, {
577
- ref: '5.7.8',
578
- tag: '5.7',
586
+ ref: '5.9.5',
587
+ tag: '5.9',
579
588
  cacheable: true,
580
589
  locked: true,
581
590
  prerelease: false