@wordpress/env 7.0.0 → 8.1.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
@@ -44,9 +44,9 @@ If your project already has a package.json, it's also possible to use `wp-env` a
44
44
  $ npm i @wordpress/env --save-dev
45
45
  ```
46
46
 
47
- At this point, you can use the local, project-level version of wp-env via [`npx`](https://www.npmjs.com/package/npx), a utility automatically installed with `npm`.`npx` finds binaries like wp-env installed through node modules. As an example: `npx wp-env start --update`.
47
+ If you have also installed `wp-env` globally, running it will automatically execute the local, project-level package. Alternatively, you can execute `wp-env` via [`npx`](https://www.npmjs.com/package/npx), a utility automatically installed with `npm`.`npx` finds binaries like `wp-env` installed through node modules. As an example: `npx wp-env start --update`.
48
48
 
49
- If you don't wish to use `npx`, modify your package.json and add an extra command to npm `scripts` (https://docs.npmjs.com/misc/scripts):
49
+ If you don't wish to use the global installation or `npx`, modify your `package.json` and add an extra command to npm `scripts` (https://docs.npmjs.com/misc/scripts):
50
50
 
51
51
  ```json
52
52
  "scripts": {
@@ -319,40 +319,38 @@ Options:
319
319
  --scripts Execute any configured lifecycle scripts. [boolean] [default: true]
320
320
  ```
321
321
 
322
- ### `wp-env run [container] [command]`
322
+ ### `wp-env run <container> [command...]`
323
323
 
324
- The run command can be used to open shell sessions or invoke WP-CLI commands.
324
+ The run command can be used to open shell sessions, invoke WP-CLI commands, or run any arbitrary commands inside of a container.
325
325
 
326
- <div class="callout callout-alert">In some cases, <code>wp-env</code> may consume options that you are attempting to pass to
327
- the container. This happens with options that <code>wp-env</code> has already declared,
328
- such as <code>--env-cwd</code>, <code>--debug</code>, <code>--help</code>, and <code>--version</code>. When this happens, you should fall
329
- back to using quotation marks; <code>wp-env</code> considers everything inside the
330
- quotation marks to be command argument.
331
-
332
- For example, to ask <code>WP-CLI</code> for its help text:
333
-
334
- <pre>sh
335
- <code class="language-sh">wp-env run cli "wp --help"</code></pre>
336
-
337
- Without the quotation marks, <code>wp-env</code> will print its own help text instead of
338
- passing it to the container. If you experience any problems where the command
339
- is not being passed correctly, fall back to using quotation marks.
326
+ <div class="callout callout-alert">
327
+ <p>
328
+ In some cases <code class="language-sh">wp-env run</code> may conflict with options that you are passing to the container.
329
+ When this happens, <code class="language-sh">wp-env</code> will treat the option as its own and take action accordingly.
330
+ For example, if you try <code class="language-sh">wp-env run cli php --help</code>, you will receive the <code class="language-sh">wp-env</code> help text.
331
+ </p>
340
332
 
333
+ <p>
334
+ You can get around this by passing any conflicting options after a double dash. <code class="language-sh">wp-env</code> will not process anything after
335
+ the double dash and will simply pass it on to the container. To get the PHP help text you would use <code class="language-sh">wp-env run cli php -- --help</code>.
336
+ </p>
341
337
  </div>
342
338
 
343
339
  ```sh
344
- wp-env run <container> [command..]
340
+ wp-env run <container> [command...]
345
341
 
346
- Runs an arbitrary command in one of the underlying Docker containers. The
347
- "container" param should reference one of the underlying Docker services like
348
- "development", "tests", or "cli". To run a wp-cli command, use the "cli" or
349
- "tests-cli" service. You can also use this command to open shell sessions like
350
- bash and the WordPress shell in the WordPress instance. For example, `wp-env run
351
- cli bash` will open bash in the development WordPress instance.
342
+ Runs an arbitrary command in one of the underlying Docker containers. A double
343
+ dash can be used to pass arguments to the container without parsing them. This
344
+ is necessary if you are using an option that is defined below. You can use
345
+ `bash` to open a shell session and both `composer` and `phpunit` are available
346
+ in all WordPress and CLI containers. WP-CLI is also available in the CLI
347
+ containers.
352
348
 
353
349
  Positionals:
354
- container The container to run the command on. [string] [required]
355
- command The command to run. [array] [default: []]
350
+ container The Docker service to run the command on.
351
+ [string] [required] [choices: "mysql", "tests-mysql", "wordpress",
352
+ "tests-wordpress", "cli", "tests-cli", "composer", "phpunit"]
353
+ command The command to run. [required]
356
354
 
357
355
  Options:
358
356
  --debug Enable debug output. [boolean] [default: false]
@@ -443,7 +441,8 @@ Destroy the WordPress environment. Deletes docker containers, volumes, and
443
441
  networks associated with the WordPress environment and removes local files.
444
442
 
445
443
  Options:
446
- --debug Enable debug output. [boolean] [default: false]
444
+ --debug Enable debug output. [boolean] [default: false]
445
+ --scripts Execute any configured lifecycle scripts. [boolean] [default: true]
447
446
  ```
448
447
 
449
448
  ### `wp-env logs [environment]`
@@ -559,19 +558,16 @@ These can be overridden by setting a value within the `config` configuration. Se
559
558
 
560
559
  Additionally, the values referencing a URL include the specified port for the given environment. So if you set `testsPort: 3000, port: 2000`, `WP_HOME` (for example) will be `http://localhost:3000` on the tests instance and `http://localhost:2000` on the development instance.
561
560
 
562
- ## Lifecycle Hooks
563
-
564
- These hooks are executed at certain points during the lifecycle of a command's execution. Keep in mind that these will be executed on both fresh and existing
565
- environments, so, ensure any commands you build won't break on subsequent executions.
566
-
567
- ### After Setup
561
+ ## Lifecycle Scripts
568
562
 
569
- Using the `afterSetup` option in `.wp-env.json` files will allow you to configure an arbitrary command to execute after the environment's setup is complete:
563
+ Using the `lifecycleScripts` option in `.wp-env.json` will allow you to set arbitrary commands to be executed at certain points in the lifecycle. This configuration
564
+ can also be overridden using `WP_ENV_LIFECYCLE_SCRIPT_{LIFECYCLE_EVENT}` environment variables, with the remainder being the all-caps snake_case name of the option, for
565
+ example, `WP_ENV_LIFECYCLE_SCRIPT_AFTER_START`. Keep in mind that these will be executed on both fresh and existing environments, so, ensure any commands you
566
+ build won't break on subsequent executions.
570
567
 
571
- - `wp-env start`: Runs when the config changes, WordPress updates, or you pass the `--update` flag.
572
- - `wp-env clean`: Runs after the selected environments have been cleaned.
573
-
574
- You can override the `afterSetup` option using the `WP_ENV_AFTER_SETUP` environment variable.
568
+ * `afterStart`: Runs after `wp-env start` has finished setting up the environment.
569
+ * `afterClean`: Runs after `wp-env clean` has finished cleaning the environment.
570
+ * `afterDestroy`: Runs after `wp-env destroy` has destroyed the environment.
575
571
 
576
572
  ## Examples
577
573
 
@@ -707,7 +703,9 @@ This is useful for performing some actions after setting up the environment, suc
707
703
 
708
704
  ```json
709
705
  {
710
- "afterSetup": "node tests/e2e/bin/setup-env.js"
706
+ "lifecycleScripts": {
707
+ "afterStart": "node tests/e2e/bin/setup-env.js"
708
+ }
711
709
  }
712
710
  ```
713
711
 
package/bin/wp-env CHANGED
@@ -1,4 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict';
3
- const command = process.argv.slice( 2 );
4
- require( '../lib/cli' )().parse( command.length ? command : [ '--help' ] );
3
+
4
+ // Remove 'node' and the name of the script from the arguments.
5
+ let command = process.argv.slice( 2 );
6
+ // Default to help text when they aren't running any commands.
7
+ if ( ! command.length ) {
8
+ command = [ '--help' ];
9
+ }
10
+
11
+ // Rather than just executing the current CLI we will attempt to find a local version
12
+ // and execute that one instead. This prevents users from accidentally using the
13
+ // global CLI when a potentially different local version is expected.
14
+ const localPath = require.resolve( '@wordpress/env/lib/cli.js', {
15
+ paths: [ process.cwd(), __dirname ],
16
+ } );
17
+ const cli = require( localPath )();
18
+
19
+ // Now we can execute the CLI with the given command.
20
+ cli.parse( command );
package/lib/cli.js CHANGED
@@ -11,8 +11,13 @@ const { execSync } = require( 'child_process' );
11
11
  /**
12
12
  * Internal dependencies
13
13
  */
14
+ const pkg = require( '../package.json' );
14
15
  const env = require( './env' );
15
16
  const parseXdebugMode = require( './parse-xdebug-mode' );
17
+ const {
18
+ RUN_CONTAINERS,
19
+ validateRunContainer,
20
+ } = require( './validate-run-container' );
16
21
 
17
22
  // Colors.
18
23
  const boldWhite = chalk.bold.white;
@@ -41,7 +46,7 @@ const withSpinner =
41
46
  ( error ) => {
42
47
  if (
43
48
  error instanceof env.ValidationError ||
44
- error instanceof env.AfterSetupError
49
+ error instanceof env.LifecycleScriptError
45
50
  ) {
46
51
  // Error is a configuration error. That means the user did something wrong.
47
52
  spinner.fail( error.message );
@@ -99,9 +104,16 @@ module.exports = function cli() {
99
104
  default: false,
100
105
  } );
101
106
 
102
- // Make sure any unknown arguments are passed to the command as arguments.
103
- // This allows options to be passed to "run" without being quoted.
104
- yargs.parserConfiguration( { 'unknown-options-as-args': true } );
107
+ yargs.parserConfiguration( {
108
+ // Treats unknown options as arguments for commands to deal with instead of discarding them.
109
+ 'unknown-options-as-args': true,
110
+ // Populates '--' in the command options with arguments after the double dash.
111
+ 'populate--': true,
112
+ } );
113
+
114
+ // Since we might be running a different CLI version than the one that was called
115
+ // we need to set the version manually from the correct package.json.
116
+ yargs.version( pkg.version );
105
117
 
106
118
  yargs.command(
107
119
  'start',
@@ -184,8 +196,8 @@ module.exports = function cli() {
184
196
  'Displays the latest logs for the e2e test environment without watching.'
185
197
  );
186
198
  yargs.command(
187
- 'run <container> [command..]',
188
- 'Runs an arbitrary command in one of the underlying Docker containers. The "container" param should reference one of the underlying Docker services like "development", "tests", or "cli". To run a wp-cli command, use the "cli" or "tests-cli" service. You can also use this command to open shell sessions like bash and the WordPress shell in the WordPress instance. For example, `wp-env run cli bash` will open bash in the development WordPress instance. When using long commands with arguments and quotation marks, you need to wrap the "command" param in quotation marks. For example: `wp-env run tests-cli "wp post create --post_type=page --post_title=\'Test\'"` will create a post on the tests WordPress instance.',
199
+ 'run <container> [command...]',
200
+ 'Runs an arbitrary command in one of the underlying Docker containers. A double dash can be used to pass arguments to the container without parsing them. This is necessary if you are using an option that is defined below. You can use `bash` to open a shell session and both `composer` and `phpunit` are available in all WordPress and CLI containers. WP-CLI is also available in the CLI containers.',
189
201
  ( args ) => {
190
202
  args.option( 'env-cwd', {
191
203
  type: 'string',
@@ -196,7 +208,10 @@ module.exports = function cli() {
196
208
  } );
197
209
  args.positional( 'container', {
198
210
  type: 'string',
199
- describe: 'The container to run the command on.',
211
+ describe:
212
+ 'The underlying Docker service to run the command on.',
213
+ choices: RUN_CONTAINERS,
214
+ coerce: validateRunContainer,
200
215
  } );
201
216
  args.positional( 'command', {
202
217
  type: 'array',
@@ -223,7 +238,13 @@ module.exports = function cli() {
223
238
  wpRed(
224
239
  'Destroy the WordPress environment. Deletes docker containers, volumes, and networks associated with the WordPress environment and removes local files.'
225
240
  ),
226
- () => {},
241
+ ( args ) => {
242
+ args.option( 'scripts', {
243
+ type: 'boolean',
244
+ describe: 'Execute any configured lifecycle scripts.',
245
+ default: true,
246
+ } );
247
+ },
227
248
  withSpinner( env.destroy )
228
249
  );
229
250
  yargs.command(
@@ -9,7 +9,7 @@ const dockerCompose = require( 'docker-compose' );
9
9
  */
10
10
  const initConfig = require( '../init-config' );
11
11
  const { configureWordPress, resetDatabase } = require( '../wordpress' );
12
- const { executeAfterSetup } = require( '../execute-after-setup' );
12
+ const { executeLifecycleScript } = require( '../execute-lifecycle-script' );
13
13
 
14
14
  /**
15
15
  * @typedef {import('../wordpress').WPEnvironment} WPEnvironment
@@ -65,9 +65,8 @@ module.exports = async function clean( {
65
65
 
66
66
  await Promise.all( tasks );
67
67
 
68
- // Execute any configured command that should run after the environment has finished being set up.
69
68
  if ( scripts ) {
70
- executeAfterSetup( config, spinner );
69
+ await executeLifecycleScript( 'afterClean', config, spinner );
71
70
  }
72
71
 
73
72
  spinner.text = `Cleaned ${ description }.`;
@@ -17,21 +17,21 @@ const rimraf = util.promisify( require( 'rimraf' ) );
17
17
  * Internal dependencies
18
18
  */
19
19
  const { loadConfig } = require( '../config' );
20
+ const { executeLifecycleScript } = require( '../execute-lifecycle-script' );
20
21
 
21
22
  /**
22
23
  * Destroy the development server.
23
24
  *
24
25
  * @param {Object} options
25
26
  * @param {Object} options.spinner A CLI spinner which indicates progress.
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.
27
29
  */
28
- module.exports = async function destroy( { spinner, debug } ) {
29
- const { dockerComposeConfigPath, workDirectoryPath } = await loadConfig(
30
- path.resolve( '.' )
31
- );
30
+ module.exports = async function destroy( { spinner, scripts, debug } ) {
31
+ const config = await loadConfig( path.resolve( '.' ) );
32
32
 
33
33
  try {
34
- await fs.readdir( workDirectoryPath );
34
+ await fs.readdir( config.workDirectoryPath );
35
35
  } catch {
36
36
  spinner.text = 'Could not find any files to remove.';
37
37
  return;
@@ -60,7 +60,7 @@ module.exports = async function destroy( { spinner, debug } ) {
60
60
  spinner.text = 'Removing docker images, volumes, and networks.';
61
61
 
62
62
  await dockerCompose.down( {
63
- config: dockerComposeConfigPath,
63
+ config: config.dockerComposeConfigPath,
64
64
  commandOptions: [ '--volumes', '--remove-orphans', '--rmi', 'all' ],
65
65
  log: debug,
66
66
  } );
@@ -70,7 +70,11 @@ module.exports = async function destroy( { spinner, debug } ) {
70
70
  // by this point, which causes rimraf to fail. We need to wait at least 2.5-5s,
71
71
  // but using 10s in case it's dependant on the machine.
72
72
  await new Promise( ( resolve ) => setTimeout( resolve, 10000 ) );
73
- await rimraf( workDirectoryPath );
73
+ await rimraf( config.workDirectoryPath );
74
+
75
+ if ( scripts ) {
76
+ await executeLifecycleScript( 'afterDestroy', config, spinner );
77
+ }
74
78
 
75
79
  spinner.text = 'Removed WordPress environment.';
76
80
  };
@@ -10,7 +10,6 @@ const path = require( 'path' );
10
10
  */
11
11
  const initConfig = require( '../init-config' );
12
12
  const getHostUser = require( '../get-host-user' );
13
- const { ValidationError } = require( '../config' );
14
13
 
15
14
  /**
16
15
  * @typedef {import('../config').WPConfig} WPConfig
@@ -22,6 +21,7 @@ const { ValidationError } = require( '../config' );
22
21
  * @param {Object} options
23
22
  * @param {string} options.container The Docker container to run the command on.
24
23
  * @param {string[]} options.command The command to run.
24
+ * @param {string[]} options.'--' Any arguments that were passed after a double dash.
25
25
  * @param {string} options.envCwd The working directory for the command to be executed from.
26
26
  * @param {Object} options.spinner A CLI spinner which indicates progress.
27
27
  * @param {boolean} options.debug True if debug mode is enabled.
@@ -29,66 +29,34 @@ const { ValidationError } = require( '../config' );
29
29
  module.exports = async function run( {
30
30
  container,
31
31
  command,
32
+ '--': doubleDashedArgs,
32
33
  envCwd,
33
34
  spinner,
34
35
  debug,
35
36
  } ) {
36
- validateContainerExistence( container );
37
-
38
37
  const config = await initConfig( { spinner, debug } );
39
38
 
40
- command = command.join( ' ' );
39
+ // Include any double dashed arguments in the command so that we can pass them to Docker.
40
+ // This lets users pass options that the command defines without them being parsed.
41
+ if ( Array.isArray( doubleDashedArgs ) ) {
42
+ command.push( ...doubleDashedArgs );
43
+ }
41
44
 
42
45
  // Shows a contextual tip for the given command.
43
- showCommandTips( command, container, spinner );
46
+ const joinedCommand = command.join( ' ' );
47
+ showCommandTips( joinedCommand, container, spinner );
44
48
 
45
49
  await spawnCommandDirectly( config, container, command, envCwd, spinner );
46
50
 
47
- spinner.text = `Ran \`${ command }\` in '${ container }'.`;
51
+ spinner.text = `Ran \`${ joinedCommand }\` in '${ container }'.`;
48
52
  };
49
53
 
50
- /**
51
- * Validates the container option and throws if it is invalid.
52
- *
53
- * @param {string} container The Docker container to run the command on.
54
- */
55
- function validateContainerExistence( container ) {
56
- // Give better errors for containers that we have removed.
57
- if ( container === 'phpunit' ) {
58
- throw new ValidationError(
59
- "The 'phpunit' container has been removed. Please use 'wp-env run tests-cli --env-cwd=wp-content/path/to/plugin phpunit' instead."
60
- );
61
- }
62
- if ( container === 'composer' ) {
63
- throw new ValidationError(
64
- "The 'composer' container has been removed. Please use 'wp-env run cli --env-cwd=wp-content/path/to/plugin composer' instead."
65
- );
66
- }
67
-
68
- // Provide better error output than Docker's "service does not exist" messaging.
69
- const validContainers = [
70
- 'mysql',
71
- 'tests-mysql',
72
- 'wordpress',
73
- 'tests-wordpress',
74
- 'cli',
75
- 'tests-cli',
76
- ];
77
- if ( ! validContainers.includes( container ) ) {
78
- throw new ValidationError(
79
- `The '${ container }' container does not exist. Valid selections are: ${ validContainers.join(
80
- ', '
81
- ) }`
82
- );
83
- }
84
- }
85
-
86
54
  /**
87
55
  * Runs an arbitrary command on the given Docker container.
88
56
  *
89
57
  * @param {WPConfig} config The wp-env configuration.
90
58
  * @param {string} container The Docker container to run the command on.
91
- * @param {string} command The command to run.
59
+ * @param {string[]} command The command to run.
92
60
  * @param {string} envCwd The working directory for the command to be executed from.
93
61
  * @param {Object} spinner A CLI spinner which indicates progress.
94
62
  */
@@ -99,8 +67,9 @@ function spawnCommandDirectly( config, container, command, envCwd, spinner ) {
99
67
  // to interact with the files mounted from the host.
100
68
  const hostUser = getHostUser();
101
69
 
102
- // We need to pass absolute paths to the container.
103
- envCwd = path.resolve(
70
+ // Since Docker requires absolute paths, we should resolve the input to a POSIX path.
71
+ // This is needed because Windows resolves relative paths from the C: drive.
72
+ envCwd = path.posix.resolve(
104
73
  // Not all containers have the same starting working directory.
105
74
  container === 'mysql' || container === 'tests-mysql'
106
75
  ? '/'
@@ -108,20 +77,22 @@ function spawnCommandDirectly( config, container, command, envCwd, spinner ) {
108
77
  envCwd
109
78
  );
110
79
 
111
- const isTTY = process.stdout.isTTY;
112
80
  const composeCommand = [
113
81
  '-f',
114
82
  config.dockerComposeConfigPath,
115
83
  'exec',
116
- ! isTTY ? '-T' : '',
117
84
  '-w',
118
85
  envCwd,
119
86
  '--user',
120
87
  hostUser.fullUser,
121
- container,
122
- ...command.split( ' ' ), // The command will fail if passed as a complete string.
123
88
  ];
124
89
 
90
+ if ( ! process.stdout.isTTY ) {
91
+ composeCommand.push( '-T' );
92
+ }
93
+
94
+ composeCommand.push( container, ...command );
95
+
125
96
  return new Promise( ( resolve, reject ) => {
126
97
  // Note: since the npm docker-compose package uses the -T option, we
127
98
  // cannot use it to spawn an interactive command. Thus, we run docker-
@@ -129,10 +100,7 @@ function spawnCommandDirectly( config, container, command, envCwd, spinner ) {
129
100
  const childProc = spawn(
130
101
  'docker-compose',
131
102
  composeCommand,
132
- {
133
- stdio: 'inherit',
134
- shell: true,
135
- },
103
+ { stdio: 'inherit' },
136
104
  spinner
137
105
  );
138
106
  childProc.on( 'error', reject );
@@ -153,17 +121,17 @@ function spawnCommandDirectly( config, container, command, envCwd, spinner ) {
153
121
  * bash) may have weird behavior (exit with ctrl-d instead of ctrl-c or ctrl-z),
154
122
  * so we want the user to have that information without having to ask someone.
155
123
  *
156
- * @param {string} command The command for which to show a tip.
157
- * @param {string} container The container the command will be run on.
158
- * @param {Object} spinner A spinner object to show progress.
124
+ * @param {string} joinedCommand The command for which to show a tip joined by spaces.
125
+ * @param {string} container The container the command will be run on.
126
+ * @param {Object} spinner A spinner object to show progress.
159
127
  */
160
- function showCommandTips( command, container, spinner ) {
161
- if ( ! command.length ) {
128
+ function showCommandTips( joinedCommand, container, spinner ) {
129
+ if ( ! joinedCommand.length ) {
162
130
  return;
163
131
  }
164
132
 
165
- const tip = `Starting '${ command }' on the ${ container } container. ${ ( () => {
166
- switch ( command ) {
133
+ const tip = `Starting '${ joinedCommand }' on the ${ container } container. ${ ( () => {
134
+ switch ( joinedCommand ) {
167
135
  case 'bash':
168
136
  return 'Exit bash with ctrl-d.';
169
137
  case 'wp shell':
@@ -31,7 +31,7 @@ const {
31
31
  } = require( '../wordpress' );
32
32
  const { didCacheChange, setCache } = require( '../cache' );
33
33
  const md5 = require( '../md5' );
34
- const { executeAfterSetup } = require( '../execute-after-setup' );
34
+ const { executeLifecycleScript } = require( '../execute-lifecycle-script' );
35
35
 
36
36
  /**
37
37
  * @typedef {import('../config').WPConfig} WPConfig
@@ -203,17 +203,16 @@ module.exports = async function start( {
203
203
  } ),
204
204
  ] );
205
205
 
206
- // Execute any configured command that should run after the environment has finished being set up.
207
- if ( scripts ) {
208
- executeAfterSetup( config, spinner );
209
- }
210
-
211
206
  // Set the cache key once everything has been configured.
212
207
  await setCache( CONFIG_CACHE_KEY, configHash, {
213
208
  workDirectoryPath,
214
209
  } );
215
210
  }
216
211
 
212
+ if ( scripts ) {
213
+ await executeLifecycleScript( 'afterStart', config, spinner );
214
+ }
215
+
217
216
  const siteUrl = config.env.development.config.WP_SITEURL;
218
217
  const testsSiteUrl = config.env.tests.config.WP_SITEURL;
219
218
 
@@ -16,10 +16,11 @@ const { checkPort, checkVersion, checkString } = require( './validate-config' );
16
16
  * Environment variable configuration.
17
17
  *
18
18
  * @typedef WPEnvironmentVariableConfig
19
- * @property {?number} port An override for the development environment's port.
20
- * @property {?number} testsPort An override for the testing environment's port.
21
- * @property {?WPSource} coreSource An override for all environment's coreSource.
22
- * @property {?string} phpVersion An override for all environment's PHP version.
19
+ * @property {?number} port An override for the development environment's port.
20
+ * @property {?number} testsPort An override for the testing environment's port.
21
+ * @property {?WPSource} coreSource An override for all environment's coreSource.
22
+ * @property {?string} phpVersion An override for all environment's PHP version.
23
+ * @property {?Object.<string, string>} lifecycleScripts An override for various lifecycle scripts.
23
24
  */
24
25
 
25
26
  /**
@@ -33,6 +34,7 @@ module.exports = function getConfigFromEnvironmentVars( cacheDirectoryPath ) {
33
34
  const environmentConfig = {
34
35
  port: getPortFromEnvironmentVariable( 'WP_ENV_PORT' ),
35
36
  testsPort: getPortFromEnvironmentVariable( 'WP_ENV_TESTS_PORT' ),
37
+ lifecycleScripts: getLifecycleScriptOverrides(),
36
38
  };
37
39
 
38
40
  if ( process.env.WP_ENV_CORE ) {
@@ -53,15 +55,6 @@ module.exports = function getConfigFromEnvironmentVars( cacheDirectoryPath ) {
53
55
  environmentConfig.phpVersion = process.env.WP_ENV_PHP_VERSION;
54
56
  }
55
57
 
56
- if ( process.env.WP_ENV_AFTER_SETUP ) {
57
- checkString(
58
- 'environment variable',
59
- 'WP_ENV_AFTER_SETUP',
60
- process.env.WP_ENV_AFTER_SETUP
61
- );
62
- environmentConfig.afterSetup = process.env.WP_ENV_AFTER_SETUP;
63
- }
64
-
65
58
  return environmentConfig;
66
59
  };
67
60
 
@@ -70,7 +63,7 @@ module.exports = function getConfigFromEnvironmentVars( cacheDirectoryPath ) {
70
63
  *
71
64
  * @param {string} varName The environment variable to check (e.g. WP_ENV_PORT).
72
65
  *
73
- * @return {number} The parsed port number
66
+ * @return {number} The parsed port number.
74
67
  */
75
68
  function getPortFromEnvironmentVariable( varName ) {
76
69
  if ( ! process.env[ varName ] ) {
@@ -84,3 +77,30 @@ function getPortFromEnvironmentVariable( varName ) {
84
77
 
85
78
  return port;
86
79
  }
80
+
81
+ /**
82
+ * Parses the lifecycle script environment variables.
83
+ *
84
+ * @return {Object.<string, string>} The parsed lifecycle scripts.
85
+ */
86
+ function getLifecycleScriptOverrides() {
87
+ const lifecycleScripts = {};
88
+
89
+ // Find all of the lifecycle script overrides and parse them.
90
+ const lifecycleEnvironmentVars = {
91
+ WP_ENV_LIFECYCLE_SCRIPT_AFTER_START: 'afterStart',
92
+ WP_ENV_LIFECYCLE_SCRIPT_AFTER_CLEAN: 'afterClean',
93
+ WP_ENV_LIFECYCLE_SCRIPT_AFTER_DESTROY: 'afterDestroy',
94
+ };
95
+ for ( const envVar in lifecycleEnvironmentVars ) {
96
+ const scriptValue = process.env[ envVar ];
97
+ if ( scriptValue === undefined ) {
98
+ continue;
99
+ }
100
+
101
+ checkString( 'environment variable', envVar, scriptValue );
102
+ lifecycleScripts[ lifecycleEnvironmentVars[ envVar ] ] = scriptValue;
103
+ }
104
+
105
+ return lifecycleScripts;
106
+ }
@@ -27,7 +27,7 @@ const postProcessConfig = require( './post-process-config' );
27
27
  * @property {string} workDirectoryPath Path to the work directory located in ~/.wp-env.
28
28
  * @property {string} dockerComposeConfigPath Path to the docker-compose.yml file.
29
29
  * @property {boolean} detectedLocalConfig If true, wp-env detected local config and used it.
30
- * @property {string} afterSetup The command(s) to run after configuring WordPress on start and clean.
30
+ * @property {Object.<string, string>} lifecycleScripts Any lifecycle scripts that we might need to execute.
31
31
  * @property {Object.<string, WPEnvironmentConfig>} env Specific config for different environments.
32
32
  * @property {boolean} debug True if debug mode is enabled.
33
33
  */
@@ -68,7 +68,7 @@ module.exports = async function loadConfig( configDirectoryPath ) {
68
68
  configFilePath,
69
69
  getConfigFilePath( configDirectoryPath, 'override' ),
70
70
  ] ),
71
- afterSetup: config.afterSetup,
71
+ lifecycleScripts: config.lifecycleScripts,
72
72
  env: config.env,
73
73
  };
74
74
  };
@@ -45,7 +45,8 @@ function mergeConfig( config, toMerge ) {
45
45
  switch ( option ) {
46
46
  // Some config options are merged together instead of entirely replaced.
47
47
  case 'config':
48
- case 'mappings': {
48
+ case 'mappings':
49
+ case 'lifecycleScripts': {
49
50
  config[ option ] = Object.assign(
50
51
  config[ option ],
51
52
  toMerge[ option ]