@wordpress/env 11.0.1-next.v.0 → 11.0.1-next.v.202602091733.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.
package/README.md CHANGED
@@ -186,7 +186,7 @@ To reset the database:
186
186
  **⚠️ WARNING: This will permanently delete any posts, pages, media, etc. in the local WordPress installation.**
187
187
 
188
188
  ```sh
189
- $ wp-env clean all
189
+ $ wp-env reset all
190
190
  $ wp-env start
191
191
  ```
192
192
 
@@ -295,6 +295,42 @@ Here is a summary:
295
295
 
296
296
  `wp-env` creates generated files in the `wp-env` home directory. By default, this is `~/.wp-env`. The exception is Linux, where files are placed at `~/wp-env` [for compatibility with Snap Packages](https://github.com/WordPress/gutenberg/issues/20180#issuecomment-587046325). The `wp-env` home directory contains a subdirectory for each project named `/$md5_of_project_path`. To change the `wp-env` home directory, set the `WP_ENV_HOME` environment variable. For example, running `WP_ENV_HOME="something" wp-env start` will download the project files to the directory `./something/$md5_of_project_path` (relative to the current directory).
297
297
 
298
+ ### Global options
299
+
300
+ These options apply to all `wp-env` commands:
301
+
302
+ ```
303
+ --debug Enable debug output. [boolean] [default: false]
304
+ --config Path to a custom .wp-env.json configuration file. [string]
305
+ ```
306
+
307
+ The `--config` option allows you to use a custom configuration file instead of the default `.wp-env.json`. This is useful for running multiple parallel environments from the same directory.
308
+
309
+ When using a custom config file, the override file is derived from its name. For example:
310
+ - `--config=staging.json` will look for `staging.override.json`
311
+ - `--config=./configs/dev.wp-env.json` will look for `./configs/dev.wp-env.override.json`
312
+
313
+ #### Running parallel environments
314
+
315
+ You can run multiple wp-env environments from the same folder by using different config files and ports:
316
+
317
+ ```sh
318
+ # Start first environment with default config
319
+ wp-env start
320
+
321
+ # Start second environment with custom config on different ports
322
+ WP_ENV_PORT=8890 WP_ENV_TESTS_PORT=8891 wp-env start --config=./staging.json
323
+
324
+ # Check status of each environment
325
+ wp-env status
326
+ wp-env status --config=./staging.json
327
+
328
+ # Stop specific environment
329
+ wp-env stop --config=./staging.json
330
+ ```
331
+
332
+ Each config file gets its own isolated Docker containers and data, so changes in one environment don't affect the other.
333
+
298
334
  ### `wp-env start`
299
335
 
300
336
  The start command installs and initializes the WordPress environment, which includes downloading any specified remote sources. By default, `wp-env` will not update or re-configure the environment except when the configuration file changes. Tell `wp-env` to update sources and apply the configuration options again with `wp-env start --update`. This will not overwrite any existing content.
@@ -340,15 +376,15 @@ Options:
340
376
  --debug Enable debug output. [boolean] [default: false]
341
377
  ```
342
378
 
343
- ### `wp-env clean [environment]`
379
+ ### `wp-env reset [environment]`
344
380
 
345
381
  ```sh
346
- wp-env clean [environment]
382
+ wp-env reset [environment]
347
383
 
348
- Cleans the WordPress databases.
384
+ Resets the WordPress databases.
349
385
 
350
386
  Positionals:
351
- environment Which environments' databases to clean.
387
+ environment Which environments' databases to reset.
352
388
  [string] [choices: "all", "development", "tests"] [default: "tests"]
353
389
 
354
390
  Options:
@@ -469,17 +505,32 @@ To set the permalink to the year, month, and post name:
469
505
  wp-env run cli "wp rewrite structure /%year%/%monthnum%/%postname%/"
470
506
  ```
471
507
 
508
+ ### `wp-env cleanup`
509
+
510
+ ```sh
511
+ wp-env cleanup
512
+
513
+ Cleanup the WordPress environment. Removes docker containers, volumes, networks,
514
+ and local files, but preserves docker images for faster re-starts.
515
+
516
+ Options:
517
+ --debug Enable debug output. [boolean] [default: false]
518
+ --scripts Execute any configured lifecycle scripts. [boolean] [default: true]
519
+ --force Skip the confirmation prompt. [boolean] [default: false]
520
+ ```
521
+
472
522
  ### `wp-env destroy`
473
523
 
474
524
  ```sh
475
525
  wp-env destroy
476
526
 
477
- Destroy the WordPress environment. Deletes docker containers, volumes, and
478
- networks associated with the WordPress environment and removes local files.
527
+ Destroy the WordPress environment. Deletes docker containers, volumes, networks,
528
+ and images associated with the WordPress environment and removes local files.
479
529
 
480
530
  Options:
481
531
  --debug Enable debug output. [boolean] [default: false]
482
532
  --scripts Execute any configured lifecycle scripts. [boolean] [default: true]
533
+ --force Skip the confirmation prompt. [boolean] [default: false]
483
534
  ```
484
535
 
485
536
  ### `wp-env logs [environment]`
@@ -629,7 +680,8 @@ example, `WP_ENV_LIFECYCLE_SCRIPT_AFTER_START`. Keep in mind that these will be
629
680
  build won't break on subsequent executions.
630
681
 
631
682
  * `afterStart`: Runs after `wp-env start` has finished setting up the environment.
632
- * `afterClean`: Runs after `wp-env clean` has finished cleaning the environment.
683
+ * `afterReset`: Runs after `wp-env reset` has finished resetting the environment.
684
+ * `afterCleanup`: Runs after `wp-env cleanup` has cleaned up the environment.
633
685
  * `afterDestroy`: Runs after `wp-env destroy` has destroyed the environment.
634
686
 
635
687
  ## Examples
@@ -769,7 +821,7 @@ You can tell `wp-env` to use a specific PHP version for compatibility and testin
769
821
 
770
822
  ### Multisite support
771
823
 
772
- You can tell `wp-env` if the site should be multisite enabled. This can also be set via the environment variable `WP_ENV_MULTISITE`.
824
+ You can tell `wp-env` if the site should be multisite enabled.
773
825
 
774
826
  ```json
775
827
  {
package/lib/cli.js CHANGED
@@ -18,6 +18,7 @@ const {
18
18
  getAvailableRuntimes,
19
19
  getRuntime,
20
20
  UnsupportedCommandError,
21
+ EnvironmentNotInitializedError,
21
22
  } = require( './runtime' );
22
23
 
23
24
  // Colors.
@@ -45,8 +46,11 @@ const withSpinner =
45
46
  process.exit( 0 );
46
47
  },
47
48
  ( error ) => {
48
- if ( error instanceof UnsupportedCommandError ) {
49
- // Error is an unsupported command in the current runtime.
49
+ if (
50
+ error instanceof UnsupportedCommandError ||
51
+ error instanceof EnvironmentNotInitializedError
52
+ ) {
53
+ // Error is a known user-facing error.
50
54
  spinner.fail( error.message );
51
55
  process.exit( 1 );
52
56
  } else if (
@@ -97,6 +101,11 @@ module.exports = function cli() {
97
101
  describe: 'Enable debug output.',
98
102
  default: false,
99
103
  } );
104
+ yargs.option( 'config', {
105
+ type: 'string',
106
+ describe: 'Path to a custom .wp-env.json configuration file.',
107
+ requiresArg: true,
108
+ } );
100
109
 
101
110
  yargs.parserConfiguration( {
102
111
  // Treats unknown options as arguments for commands to deal with instead of discarding them.
@@ -162,13 +171,31 @@ module.exports = function cli() {
162
171
  () => {},
163
172
  withSpinner( env.stop )
164
173
  );
174
+ yargs.command(
175
+ 'reset [environment]',
176
+ wpYellow( 'Resets the WordPress databases.' ),
177
+ ( args ) => {
178
+ args.positional( 'environment', {
179
+ type: 'string',
180
+ describe: "Which environments' databases to reset.",
181
+ choices: [ 'all', 'development', 'tests' ],
182
+ default: 'tests',
183
+ } );
184
+ args.option( 'scripts', {
185
+ type: 'boolean',
186
+ describe: 'Execute any configured lifecycle scripts.',
187
+ default: true,
188
+ } );
189
+ },
190
+ withSpinner( env.reset )
191
+ );
165
192
  yargs.command(
166
193
  'clean [environment]',
167
- wpYellow( 'Cleans the WordPress databases.' ),
194
+ chalk.gray( '[Deprecated: use reset] Resets the WordPress databases.' ),
168
195
  ( args ) => {
169
196
  args.positional( 'environment', {
170
197
  type: 'string',
171
- describe: "Which environments' databases to clean.",
198
+ describe: "Which environments' databases to reset.",
172
199
  choices: [ 'all', 'development', 'tests' ],
173
200
  default: 'tests',
174
201
  } );
@@ -246,7 +273,7 @@ module.exports = function cli() {
246
273
  yargs.command(
247
274
  'destroy',
248
275
  wpRed(
249
- 'Destroy the WordPress environment. Deletes docker containers, volumes, and networks associated with the WordPress environment and removes local files.'
276
+ 'Destroy the WordPress environment. Deletes docker containers, volumes, networks, and images associated with the WordPress environment and removes local files.'
250
277
  ),
251
278
  ( args ) => {
252
279
  args.option( 'scripts', {
@@ -254,9 +281,33 @@ module.exports = function cli() {
254
281
  describe: 'Execute any configured lifecycle scripts.',
255
282
  default: true,
256
283
  } );
284
+ args.option( 'force', {
285
+ type: 'boolean',
286
+ describe: 'Skip the confirmation prompt.',
287
+ default: false,
288
+ } );
257
289
  },
258
290
  withSpinner( env.destroy )
259
291
  );
292
+ yargs.command(
293
+ 'cleanup',
294
+ wpYellow(
295
+ 'Cleanup the WordPress environment. Removes docker containers, volumes, networks, and local files, but preserves docker images for faster re-starts.'
296
+ ),
297
+ ( args ) => {
298
+ args.option( 'scripts', {
299
+ type: 'boolean',
300
+ describe: 'Execute any configured lifecycle scripts.',
301
+ default: true,
302
+ } );
303
+ args.option( 'force', {
304
+ type: 'boolean',
305
+ describe: 'Skip the confirmation prompt.',
306
+ default: false,
307
+ } );
308
+ },
309
+ withSpinner( env.cleanup )
310
+ );
260
311
  yargs.command(
261
312
  'status',
262
313
  'Get the status of the wp-env environment including URLs, ports, and configuration.',
@@ -17,25 +17,34 @@ const { getRuntime, detectRuntime } = require( '../runtime' );
17
17
  */
18
18
 
19
19
  /**
20
- * Wipes the development server's database, the tests server's database, or both.
20
+ * @deprecated Use `reset` instead.
21
+ *
22
+ * Resets the development server's database, the tests server's database, or both.
21
23
  *
22
24
  * @param {Object} options
23
- * @param {WPEnvironmentSelection} options.environment The environment to clean. Either 'development', 'tests', or 'all'.
25
+ * @param {WPEnvironmentSelection} options.environment The environment to reset. Either 'development', 'tests', or 'all'.
24
26
  * @param {Object} options.spinner A CLI spinner which indicates progress.
25
27
  * @param {boolean} options.scripts Indicates whether or not lifecycle scripts should be executed.
26
28
  * @param {boolean} options.debug True if debug mode is enabled.
29
+ * @param {string|null} options.config Path to a custom .wp-env.json configuration file.
27
30
  */
28
31
  module.exports = async function clean( {
29
32
  environment,
30
33
  spinner,
31
34
  scripts,
32
35
  debug,
36
+ config: customConfigPath,
33
37
  } ) {
34
- const config = await loadConfig( path.resolve( '.' ) );
35
- const runtime = getRuntime( detectRuntime( config.workDirectoryPath ) );
38
+ spinner.warn( 'The `clean` command is deprecated. Use `reset` instead.' );
39
+
40
+ const config = await loadConfig( path.resolve( '.' ), customConfigPath );
41
+ const runtime = getRuntime(
42
+ await detectRuntime( config.workDirectoryPath )
43
+ );
36
44
 
37
45
  await runtime.clean( config, { environment, spinner, debug } );
38
46
 
47
+ // Execute afterClean for backwards compatibility.
39
48
  if ( scripts ) {
40
49
  await executeLifecycleScript( 'afterClean', config, spinner );
41
50
  }
@@ -0,0 +1,79 @@
1
+ 'use strict';
2
+ /**
3
+ * External dependencies
4
+ */
5
+ const fs = require( 'fs' ).promises;
6
+ const path = require( 'path' );
7
+ const { confirm } = require( '@inquirer/prompts' );
8
+
9
+ /**
10
+ * Internal dependencies
11
+ */
12
+ const { loadConfig } = require( '../config' );
13
+ const { executeLifecycleScript } = require( '../execute-lifecycle-script' );
14
+ const { getRuntime, detectRuntime } = require( '../runtime' );
15
+
16
+ /**
17
+ * Cleanup the development server.
18
+ *
19
+ * Removes Docker containers, volumes, networks, and local files,
20
+ * but preserves Docker images for faster re-starts.
21
+ *
22
+ * @param {Object} options
23
+ * @param {Object} options.spinner A CLI spinner which indicates progress.
24
+ * @param {boolean} options.scripts Indicates whether or not lifecycle scripts should be executed.
25
+ * @param {boolean} options.force If true, skips the confirmation prompt.
26
+ * @param {boolean} options.debug True if debug mode is enabled.
27
+ * @param {string|null} options.config Path to a custom .wp-env.json configuration file.
28
+ */
29
+ module.exports = async function cleanup( {
30
+ spinner,
31
+ scripts,
32
+ force,
33
+ debug,
34
+ config: customConfigPath,
35
+ } ) {
36
+ const config = await loadConfig( path.resolve( '.' ), customConfigPath );
37
+
38
+ try {
39
+ await fs.readdir( config.workDirectoryPath );
40
+ } catch {
41
+ spinner.text = 'Could not find any files to remove.';
42
+ return;
43
+ }
44
+
45
+ const runtime = getRuntime(
46
+ await detectRuntime( config.workDirectoryPath )
47
+ );
48
+
49
+ spinner.info( runtime.getCleanupWarningMessage() );
50
+
51
+ let yesDelete = force;
52
+ if ( ! force ) {
53
+ try {
54
+ yesDelete = await confirm( {
55
+ message: 'Are you sure you want to continue?',
56
+ default: false,
57
+ } );
58
+ } catch ( error ) {
59
+ if ( error.name === 'ExitPromptError' ) {
60
+ console.log( 'Cancelled.' );
61
+ process.exit( 1 );
62
+ }
63
+ throw error;
64
+ }
65
+ }
66
+
67
+ spinner.start();
68
+
69
+ if ( ! yesDelete ) {
70
+ spinner.text = 'Cancelled.';
71
+ return;
72
+ }
73
+
74
+ await runtime.cleanup( config, { spinner, debug } );
75
+
76
+ if ( scripts ) {
77
+ await executeLifecycleScript( 'afterCleanup', config, spinner );
78
+ }
79
+ };
@@ -16,13 +16,21 @@ const { getRuntime, detectRuntime } = require( '../runtime' );
16
16
  /**
17
17
  * Destroy the development server.
18
18
  *
19
- * @param {Object} options
20
- * @param {Object} options.spinner A CLI spinner which indicates progress.
21
- * @param {boolean} options.scripts Indicates whether or not lifecycle scripts should be executed.
22
- * @param {boolean} options.debug True if debug mode is enabled.
19
+ * @param {Object} options
20
+ * @param {Object} options.spinner A CLI spinner which indicates progress.
21
+ * @param {boolean} options.scripts Indicates whether or not lifecycle scripts should be executed.
22
+ * @param {boolean} options.force If true, skips the confirmation prompt.
23
+ * @param {boolean} options.debug True if debug mode is enabled.
24
+ * @param {string|null} options.config Path to a custom .wp-env.json configuration file.
23
25
  */
24
- module.exports = async function destroy( { spinner, scripts, debug } ) {
25
- const config = await loadConfig( path.resolve( '.' ) );
26
+ module.exports = async function destroy( {
27
+ spinner,
28
+ scripts,
29
+ force,
30
+ debug,
31
+ config: customConfigPath,
32
+ } ) {
33
+ const config = await loadConfig( path.resolve( '.' ), customConfigPath );
26
34
 
27
35
  try {
28
36
  await fs.readdir( config.workDirectoryPath );
@@ -31,22 +39,26 @@ module.exports = async function destroy( { spinner, scripts, debug } ) {
31
39
  return;
32
40
  }
33
41
 
34
- const runtime = getRuntime( detectRuntime( config.workDirectoryPath ) );
42
+ const runtime = getRuntime(
43
+ await detectRuntime( config.workDirectoryPath )
44
+ );
35
45
 
36
46
  spinner.info( runtime.getDestroyWarningMessage() );
37
47
 
38
- let yesDelete = false;
39
- try {
40
- yesDelete = await confirm( {
41
- message: 'Are you sure you want to continue?',
42
- default: false,
43
- } );
44
- } catch ( error ) {
45
- if ( error.name === 'ExitPromptError' ) {
46
- console.log( 'Cancelled.' );
47
- process.exit( 1 );
48
+ let yesDelete = force;
49
+ if ( ! force ) {
50
+ try {
51
+ yesDelete = await confirm( {
52
+ message: 'Are you sure you want to continue?',
53
+ default: false,
54
+ } );
55
+ } catch ( error ) {
56
+ if ( error.name === 'ExitPromptError' ) {
57
+ console.log( 'Cancelled.' );
58
+ process.exit( 1 );
59
+ }
60
+ throw error;
48
61
  }
49
- throw error;
50
62
  }
51
63
 
52
64
  spinner.start();
@@ -4,18 +4,22 @@
4
4
  */
5
5
  const start = require( './start' );
6
6
  const stop = require( './stop' );
7
+ const reset = require( './reset' );
7
8
  const clean = require( './clean' );
8
9
  const run = require( './run' );
9
10
  const destroy = require( './destroy' );
11
+ const cleanup = require( './cleanup' );
10
12
  const logs = require( './logs' );
11
13
  const status = require( './status' );
12
14
 
13
15
  module.exports = {
14
16
  start,
15
17
  stop,
18
+ reset,
16
19
  clean,
17
20
  run,
18
21
  destroy,
22
+ cleanup,
19
23
  logs,
20
24
  status,
21
25
  };
@@ -13,14 +13,23 @@ const { getRuntime, detectRuntime } = require( '../runtime' );
13
13
  /**
14
14
  * Displays the Docker & PHP logs on the given environment.
15
15
  *
16
- * @param {Object} options
17
- * @param {Object} options.environment The environment to run the command in (develop or tests).
18
- * @param {Object} options.watch If true, follow along with log output.
19
- * @param {Object} options.spinner A CLI spinner which indicates progress.
20
- * @param {boolean} options.debug True if debug mode is enabled.
16
+ * @param {Object} options
17
+ * @param {Object} options.environment The environment to run the command in (develop or tests).
18
+ * @param {Object} options.watch If true, follow along with log output.
19
+ * @param {Object} options.spinner A CLI spinner which indicates progress.
20
+ * @param {boolean} options.debug True if debug mode is enabled.
21
+ * @param {string|null} options.config Path to a custom .wp-env.json configuration file.
21
22
  */
22
- module.exports = async function logs( { environment, watch, spinner, debug } ) {
23
- const config = await loadConfig( path.resolve( '.' ) );
24
- const runtime = getRuntime( detectRuntime( config.workDirectoryPath ) );
23
+ module.exports = async function logs( {
24
+ environment,
25
+ watch,
26
+ spinner,
27
+ debug,
28
+ config: customConfigPath,
29
+ } ) {
30
+ const config = await loadConfig( path.resolve( '.' ), customConfigPath );
31
+ const runtime = getRuntime(
32
+ await detectRuntime( config.workDirectoryPath )
33
+ );
25
34
  await runtime.logs( config, { environment, watch, spinner, debug } );
26
35
  };
@@ -0,0 +1,46 @@
1
+ 'use strict';
2
+ /**
3
+ * External dependencies
4
+ */
5
+ const path = require( 'path' );
6
+
7
+ /**
8
+ * Internal dependencies
9
+ */
10
+ const { executeLifecycleScript } = require( '../execute-lifecycle-script' );
11
+ const { loadConfig } = require( '../config' );
12
+ const { getRuntime, detectRuntime } = require( '../runtime' );
13
+
14
+ /**
15
+ * @typedef {import('../wordpress').WPEnvironment} WPEnvironment
16
+ * @typedef {import('../wordpress').WPEnvironmentSelection} WPEnvironmentSelection
17
+ */
18
+
19
+ /**
20
+ * Resets the development server's database, the tests server's database, or both.
21
+ *
22
+ * @param {Object} options
23
+ * @param {WPEnvironmentSelection} options.environment The environment to reset. Either 'development', 'tests', or 'all'.
24
+ * @param {Object} options.spinner A CLI spinner which indicates progress.
25
+ * @param {boolean} options.scripts Indicates whether or not lifecycle scripts should be executed.
26
+ * @param {boolean} options.debug True if debug mode is enabled.
27
+ * @param {string|null} options.config Path to a custom .wp-env.json configuration file.
28
+ */
29
+ module.exports = async function reset( {
30
+ environment,
31
+ spinner,
32
+ scripts,
33
+ debug,
34
+ config: customConfigPath,
35
+ } ) {
36
+ const config = await loadConfig( path.resolve( '.' ), customConfigPath );
37
+ const runtime = getRuntime(
38
+ await detectRuntime( config.workDirectoryPath )
39
+ );
40
+
41
+ await runtime.clean( config, { environment, spinner, debug } );
42
+
43
+ if ( scripts ) {
44
+ await executeLifecycleScript( 'afterReset', config, spinner );
45
+ }
46
+ };
@@ -13,13 +13,14 @@ const { getRuntime, detectRuntime } = require( '../runtime' );
13
13
  /**
14
14
  * Runs an arbitrary command on the given Docker container.
15
15
  *
16
- * @param {Object} options
17
- * @param {string} options.container The Docker container to run the command on.
18
- * @param {string[]} options.command The command to run.
19
- * @param {string[]} options.'--' Any arguments that were passed after a double dash.
20
- * @param {string} options.envCwd The working directory for the command to be executed from.
21
- * @param {Object} options.spinner A CLI spinner which indicates progress.
22
- * @param {boolean} options.debug True if debug mode is enabled.
16
+ * @param {Object} options
17
+ * @param {string} options.container The Docker container to run the command on.
18
+ * @param {string[]} options.command The command to run.
19
+ * @param {string[]} options.'--' Any arguments that were passed after a double dash.
20
+ * @param {string} options.envCwd The working directory for the command to be executed from.
21
+ * @param {Object} options.spinner A CLI spinner which indicates progress.
22
+ * @param {boolean} options.debug True if debug mode is enabled.
23
+ * @param {string|null} options.config Path to a custom .wp-env.json configuration file.
23
24
  */
24
25
  module.exports = async function run( {
25
26
  container,
@@ -28,9 +29,12 @@ module.exports = async function run( {
28
29
  envCwd,
29
30
  spinner,
30
31
  debug,
32
+ config: customConfigPath,
31
33
  } ) {
32
- const config = await loadConfig( path.resolve( '.' ) );
33
- const runtime = getRuntime( detectRuntime( config.workDirectoryPath ) );
34
+ const config = await loadConfig( path.resolve( '.' ), customConfigPath );
35
+ const runtime = getRuntime(
36
+ await detectRuntime( config.workDirectoryPath )
37
+ );
34
38
 
35
39
  // Include any double dashed arguments in the command so that we can pass them to Docker.
36
40
  // This lets users pass options that the command defines without them being parsed.
@@ -12,7 +12,7 @@ const { rimraf } = require( 'rimraf' );
12
12
  */
13
13
  const { loadConfig } = require( '../config' );
14
14
  const { executeLifecycleScript } = require( '../execute-lifecycle-script' );
15
- const { getRuntime } = require( '../runtime' );
15
+ const { getRuntime, getSavedRuntime, saveRuntime } = require( '../runtime' );
16
16
 
17
17
  /**
18
18
  * @typedef {import('../config').WPConfig} WPConfig
@@ -21,14 +21,15 @@ const { getRuntime } = require( '../runtime' );
21
21
  /**
22
22
  * Starts the development server.
23
23
  *
24
- * @param {Object} options
25
- * @param {Object} options.spinner A CLI spinner which indicates progress.
26
- * @param {boolean} options.update If true, update sources.
27
- * @param {string} options.xdebug The Xdebug mode to set.
28
- * @param {string} options.spx The SPX mode to set.
29
- * @param {boolean} options.scripts Indicates whether or not lifecycle scripts should be executed.
30
- * @param {boolean} options.debug True if debug mode is enabled.
31
- * @param {string} options.runtime The runtime to use ('docker' or 'playground').
24
+ * @param {Object} options
25
+ * @param {Object} options.spinner A CLI spinner which indicates progress.
26
+ * @param {boolean} options.update If true, update sources.
27
+ * @param {string} options.xdebug The Xdebug mode to set.
28
+ * @param {string} options.spx The SPX mode to set.
29
+ * @param {boolean} options.scripts Indicates whether or not lifecycle scripts should be executed.
30
+ * @param {boolean} options.debug True if debug mode is enabled.
31
+ * @param {string} options.runtime The runtime to use ('docker' or 'playground').
32
+ * @param {string|null} options.config Path to a custom .wp-env.json configuration file.
32
33
  */
33
34
  module.exports = async function start( {
34
35
  spinner,
@@ -38,6 +39,7 @@ module.exports = async function start( {
38
39
  scripts,
39
40
  debug,
40
41
  runtime: runtimeName = 'docker',
42
+ config: customConfigPath,
41
43
  } ) {
42
44
  spinner.text = 'Reading configuration.';
43
45
 
@@ -48,9 +50,41 @@ module.exports = async function start( {
48
50
  await checkForLegacyInstall( spinner );
49
51
  }
50
52
 
51
- const config = await loadConfig( path.resolve( '.' ) );
53
+ const config = await loadConfig( path.resolve( '.' ), customConfigPath );
52
54
  config.debug = debug;
53
55
 
56
+ // Check if switching runtimes and prompt user to destroy old environment first.
57
+ const savedRuntime = await getSavedRuntime( config.workDirectoryPath );
58
+ if ( savedRuntime && savedRuntime !== runtimeName ) {
59
+ spinner.stop();
60
+ let shouldDestroy = false;
61
+ try {
62
+ shouldDestroy = await confirm( {
63
+ message: `Environment was previously started with '${ savedRuntime }' runtime. Destroy it and start with '${ runtimeName }'?`,
64
+ default: true,
65
+ } );
66
+ } catch ( error ) {
67
+ if ( error.name === 'ExitPromptError' ) {
68
+ console.log( 'Cancelled.' );
69
+ process.exit( 1 );
70
+ }
71
+ throw error;
72
+ }
73
+
74
+ if ( ! shouldDestroy ) {
75
+ spinner.fail(
76
+ `Aborted. Run 'wp-env destroy' manually or start with '--runtime=${ savedRuntime }'.`
77
+ );
78
+ process.exit( 1 );
79
+ }
80
+
81
+ // User confirmed - destroy old runtime first.
82
+ spinner.start();
83
+ spinner.text = `Destroying previous ${ savedRuntime } environment.`;
84
+ const oldRuntime = getRuntime( savedRuntime );
85
+ await oldRuntime.destroy( config, { spinner } );
86
+ }
87
+
54
88
  if ( ! config.detectedLocalConfig ) {
55
89
  const { configDirectoryPath } = config;
56
90
  spinner.warn(
@@ -76,6 +110,9 @@ module.exports = async function start( {
76
110
  spx,
77
111
  debug,
78
112
  } );
113
+
114
+ // Save the runtime type after successful start.
115
+ await saveRuntime( runtimeName, config.workDirectoryPath );
79
116
  } catch ( error ) {
80
117
  // Attempt to stop any partially-started environment so that
81
118
  // processes do not linger after a failed start.