@wordpress/env 5.16.0 → 6.0.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
@@ -18,9 +18,11 @@ The database credentials are: user `root`, password `password`. For a comprehens
18
18
 
19
19
  ## Prerequisites
20
20
 
21
- `wp-env` requires Docker to be installed. There are instructions available for installing Docker on [Windows](https://docs.docker.com/desktop/install/windows-install/), [macOS](https://docs.docker.com/docker-for-mac/install/), and [Linux](https://docs.docker.com/desktop/install/linux-install/).
21
+ `wp-env` relies on a few commonly used developer tools:
22
22
 
23
- Node.js and npm are required. The latest LTS version of Node.js is used to develop `wp-env` and is recommended.
23
+ - **Docker**. `wp-env` is powered by Docker. There are instructions available for installing Docker on [Windows](https://docs.docker.com/desktop/install/windows-install/) (we recommend the WSL2 backend), [macOS](https://docs.docker.com/docker-for-mac/install/), and [Linux](https://docs.docker.com/desktop/install/linux-install/).
24
+ - **Node.js**. `wp-env` is written as a Node script. We recommend using a Node version manager like [nvm](https://github.com/nvm-sh/nvm) to install the latest LTS version. Alternatively, you can [download it directly here](https://nodejs.org/en/download).
25
+ - **git**. Git is used for downloading software from source control, such as WordPress, plugins, and themes. [You can find the installation instructions here.](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
24
26
 
25
27
  ## Installation
26
28
 
@@ -237,13 +239,13 @@ You should only have to translate `port` and `pathMappings` to the format used b
237
239
 
238
240
  ```json
239
241
  {
240
- "name": "Listen for XDebug",
241
- "type": "php",
242
- "request": "launch",
243
- "port": 9003,
244
- "pathMappings": {
245
- "/var/www/html/wp-content/plugins/gutenberg": "${workspaceFolder}/"
246
- }
242
+ "name": "Listen for XDebug",
243
+ "type": "php",
244
+ "request": "launch",
245
+ "port": 9003,
246
+ "pathMappings": {
247
+ "/var/www/html/wp-content/plugins/gutenberg": "${workspaceFolder}/"
248
+ }
247
249
  }
248
250
  ```
249
251
 
@@ -313,22 +315,20 @@ Positionals:
313
315
 
314
316
  The run command can be used to open shell sessions or invoke WP-CLI commands.
315
317
 
316
- <div class="callout callout-alert">
317
- In some cases, `wp-env` may consume options that you are attempting to pass to
318
- the container. This happens with options that `wp-env` has already declared,
319
- such as `--debug`, `--help`, and `--version`. When this happens, you should fall
320
- back to using quotation marks; `wp-env` considers everything inside the
318
+ <div class="callout callout-alert">In some cases, <code>wp-env</code> may consume options that you are attempting to pass to
319
+ the container. This happens with options that <code>wp-env</code> has already declared,
320
+ such as <code>--env-cwd</code>, <code>--debug</code>, <code>--help</code>, and <code>--version</code>. When this happens, you should fall
321
+ back to using quotation marks; <code>wp-env</code> considers everything inside the
321
322
  quotation marks to be command argument.
322
323
 
323
- For example, to ask `WP-CLI` for its help text:
324
-
325
- ```sh
326
- wp-env run cli "wp --help"
327
- ```
328
-
329
- Without the quotation marks, `wp-env` will print its own help text instead of
324
+ For example, to ask <code>WP-CLI</code> for its help text:
325
+ <pre>sh
326
+ <code class="language-sh">wp-env run cli "wp --help"</code></pre>
327
+
328
+ Without the quotation marks, <code>wp-env</code> will print its own help text instead of
330
329
  passing it to the container. If you experience any problems where the command
331
330
  is not being passed correctly, fall back to using quotation marks.
331
+
332
332
  </div>
333
333
 
334
334
  ```sh
@@ -349,6 +349,9 @@ Options:
349
349
  --help Show help [boolean]
350
350
  --version Show version number [boolean]
351
351
  --debug Enable debug output. [boolean] [default: false]
352
+ --env-cwd The command's working directory inside of the container. Paths
353
+ without a leading slash are relative to the WordPress root.
354
+ [string] [default: "."]
352
355
  ```
353
356
 
354
357
  For example:
@@ -465,7 +468,7 @@ You can customize the WordPress installation, plugins and themes that the develo
465
468
  | `"plugins"` | `string[]` | `[]` | A list of plugins to install and activate in the environment. |
466
469
  | `"themes"` | `string[]` | `[]` | A list of themes to install in the environment. |
467
470
  | `"port"` | `integer` | `8888` (`8889` for the tests instance) | The primary port number to use for the installation. You'll access the instance through the port: 'http://localhost:8888'. |
468
- | `"testsPort"` | `integer` | `8889` | The port number for the test site. You'll access the instance through the port: 'http://localhost:8889'. |
471
+ | `"testsPort"` | `integer` | `8889` | The port number for the test site. You'll access the instance through the port: 'http://localhost:8889'. |
469
472
  | `"config"` | `Object` | See below. | Mapping of wp-config.php constants to their desired values. |
470
473
  | `"mappings"` | `Object` | `"{}"` | Mapping of WordPress directories to local directories to be mounted in the WordPress instance. |
471
474
 
@@ -473,13 +476,13 @@ _Note: the port number environment variables (`WP_ENV_PORT` and `WP_ENV_TESTS_PO
473
476
 
474
477
  Several types of strings can be passed into the `core`, `plugins`, `themes`, and `mappings` fields.
475
478
 
476
- | Type | Format | Example(s) |
477
- | ----------------- | -------------------------------------------- | -------------------------------------------------------- |
478
- | Relative path | `.<path>\|~<path>` | `"./a/directory"`, `"../a/directory"`, `"~/a/directory"` |
479
- | Absolute path | `/<path>\|<letter>:\<path>` | `"/a/directory"`, `"C:\\a\\directory"` |
479
+ | Type | Format | Example(s) |
480
+ | ----------------- | -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
481
+ | Relative path | `.<path>\|~<path>` | `"./a/directory"`, `"../a/directory"`, `"~/a/directory"` |
482
+ | Absolute path | `/<path>\|<letter>:\<path>` | `"/a/directory"`, `"C:\\a\\directory"` |
480
483
  | GitHub repository | `<owner>/<repo>[#<ref>]` | `"WordPress/WordPress"`, `"WordPress/gutenberg#trunk"`, if no branch is provided wp-env will fall back to the repos default branch |
481
- | SSH repository | `ssh://user@host/<owner>/<repo>.git[#<ref>]` | `"ssh://git@github.com/WordPress/WordPress.git"` |
482
- | ZIP File | `http[s]://<host>/<path>.zip` | `"https://wordpress.org/wordpress-5.4-beta2.zip"` |
484
+ | SSH repository | `ssh://user@host/<owner>/<repo>.git[#<ref>]` | `"ssh://git@github.com/WordPress/WordPress.git"` |
485
+ | ZIP File | `http[s]://<host>/<path>.zip` | `"https://wordpress.org/wordpress-5.4-beta2.zip"` |
483
486
 
484
487
  Remote sources will be downloaded into a temporary directory located in `~/.wp-env`.
485
488
 
@@ -487,22 +490,22 @@ Additionally, the key `env` is available to override any of the above options on
487
490
 
488
491
  ```json
489
492
  {
490
- "plugins": ["."],
491
- "config": {
492
- "KEY_1": true,
493
- "KEY_2": false
494
- },
495
- "env": {
496
- "development": {
497
- "themes": ["./one-theme"]
498
- },
499
- "tests": {
500
- "config": {
501
- "KEY_1": false
502
- },
503
- "port": 3000
504
- }
505
- }
493
+ "plugins": [ "." ],
494
+ "config": {
495
+ "KEY_1": true,
496
+ "KEY_2": false
497
+ },
498
+ "env": {
499
+ "development": {
500
+ "themes": [ "./one-theme" ]
501
+ },
502
+ "tests": {
503
+ "config": {
504
+ "KEY_1": false
505
+ },
506
+ "port": 3000
507
+ }
508
+ }
506
509
  }
507
510
  ```
508
511
 
@@ -545,8 +548,8 @@ This is useful for plugin development.
545
548
 
546
549
  ```json
547
550
  {
548
- "core": null,
549
- "plugins": ["."]
551
+ "core": null,
552
+ "plugins": [ "." ]
550
553
  }
551
554
  ```
552
555
 
@@ -556,8 +559,8 @@ This is useful for plugin development when upstream Core changes need to be test
556
559
 
557
560
  ```json
558
561
  {
559
- "core": "WordPress/WordPress#master",
560
- "plugins": ["."]
562
+ "core": "WordPress/WordPress#master",
563
+ "plugins": [ "." ]
561
564
  }
562
565
  ```
563
566
 
@@ -569,8 +572,8 @@ If you are running a _build_ of `wordpress-develop`, point `core` to the `build`
569
572
 
570
573
  ```json
571
574
  {
572
- "core": "../wordpress-develop/build",
573
- "plugins": ["."]
575
+ "core": "../wordpress-develop/build",
576
+ "plugins": [ "." ]
574
577
  }
575
578
  ```
576
579
 
@@ -578,8 +581,8 @@ If you are running `wordpress-develop` in a dev mode (e.g. the watch command `de
578
581
 
579
582
  ```json
580
583
  {
581
- "core": "../wordpress-develop/src",
582
- "plugins": ["."]
584
+ "core": "../wordpress-develop/src",
585
+ "plugins": [ "." ]
583
586
  }
584
587
  ```
585
588
 
@@ -589,9 +592,9 @@ This is useful for integration testing: that is, testing how old versions of Wor
589
592
 
590
593
  ```json
591
594
  {
592
- "core": "WordPress/WordPress#5.2.0",
593
- "plugins": ["WordPress/wp-lazy-loading", "WordPress/classic-editor"],
594
- "themes": ["WordPress/theme-experiments"]
595
+ "core": "WordPress/WordPress#5.2.0",
596
+ "plugins": [ "WordPress/wp-lazy-loading", "WordPress/classic-editor" ],
597
+ "themes": [ "WordPress/theme-experiments" ]
595
598
  }
596
599
  ```
597
600
 
@@ -601,12 +604,12 @@ You can add mu-plugins via the mapping config. The mapping config also allows yo
601
604
 
602
605
  ```json
603
606
  {
604
- "plugins": ["."],
605
- "mappings": {
606
- "wp-content/mu-plugins": "./path/to/local/mu-plugins",
607
- "wp-content/themes": "./path/to/local/themes",
608
- "wp-content/themes/specific-theme": "./path/to/local/theme-1"
609
- }
607
+ "plugins": [ "." ],
608
+ "mappings": {
609
+ "wp-content/mu-plugins": "./path/to/local/mu-plugins",
610
+ "wp-content/themes": "./path/to/local/themes",
611
+ "wp-content/themes/specific-theme": "./path/to/local/theme-1"
612
+ }
610
613
  }
611
614
  ```
612
615
 
@@ -616,10 +619,10 @@ Since all plugins in the `plugins` key are activated by default, you should use
616
619
 
617
620
  ```json
618
621
  {
619
- "plugins": ["."],
620
- "mappings": {
621
- "wp-content/plugins/my-test-plugin": "./path/to/test/plugin"
622
- }
622
+ "plugins": [ "." ],
623
+ "mappings": {
624
+ "wp-content/plugins/my-test-plugin": "./path/to/test/plugin"
625
+ }
623
626
  }
624
627
  ```
625
628
 
@@ -629,12 +632,12 @@ If you need a plugin active in one environment but not the other, you can use `e
629
632
 
630
633
  ```json
631
634
  {
632
- "plugins": ["."],
633
- "env": {
634
- "tests": {
635
- "plugins": [".", "path/to/test/plugin"]
636
- }
637
- }
635
+ "plugins": [ "." ],
636
+ "env": {
637
+ "tests": {
638
+ "plugins": [ ".", "path/to/test/plugin" ]
639
+ }
640
+ }
638
641
  }
639
642
  ```
640
643
 
@@ -644,13 +647,13 @@ You can tell `wp-env` to use a custom port number so that your instance does not
644
647
 
645
648
  ```json
646
649
  {
647
- "plugins": ["."],
648
- "port": 4013,
649
- "env": {
650
- "tests": {
651
- "port": 4012
652
- }
653
- }
650
+ "plugins": [ "." ],
651
+ "port": 4013,
652
+ "env": {
653
+ "tests": {
654
+ "port": 4012
655
+ }
656
+ }
654
657
  }
655
658
  ```
656
659
 
@@ -660,8 +663,8 @@ You can tell `wp-env` to use a specific PHP version for compatibility and testin
660
663
 
661
664
  ```json
662
665
  {
663
- "phpVersion": "7.2",
664
- "plugins": ["."]
666
+ "phpVersion": "7.2",
667
+ "plugins": [ "." ]
665
668
  }
666
669
  ```
667
670
 
package/lib/cli.js CHANGED
@@ -174,6 +174,13 @@ module.exports = function cli() {
174
174
  'run <container> [command..]',
175
175
  '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.',
176
176
  ( args ) => {
177
+ args.option( 'env-cwd', {
178
+ type: 'string',
179
+ requiresArg: true,
180
+ default: '.',
181
+ describe:
182
+ "The command's working directory inside of the container. Paths without a leading slash are relative to the WordPress root.",
183
+ } );
177
184
  args.positional( 'container', {
178
185
  type: 'string',
179
186
  describe: 'The container to run the command on.',
@@ -2,6 +2,7 @@
2
2
  * External dependencies
3
3
  */
4
4
  const { spawn } = require( 'child_process' );
5
+ const path = require( 'path' );
5
6
 
6
7
  /**
7
8
  * Internal dependencies
@@ -18,10 +19,17 @@ const initConfig = require( '../init-config' );
18
19
  * @param {Object} options
19
20
  * @param {string} options.container The Docker container to run the command on.
20
21
  * @param {string[]} options.command The command to run.
22
+ * @param {string} options.envCwd The working directory for the command to be executed from.
21
23
  * @param {Object} options.spinner A CLI spinner which indicates progress.
22
24
  * @param {boolean} options.debug True if debug mode is enabled.
23
25
  */
24
- module.exports = async function run( { container, command, spinner, debug } ) {
26
+ module.exports = async function run( {
27
+ container,
28
+ command,
29
+ envCwd,
30
+ spinner,
31
+ debug,
32
+ } ) {
25
33
  const config = await initConfig( { spinner, debug } );
26
34
 
27
35
  command = command.join( ' ' );
@@ -29,12 +37,7 @@ module.exports = async function run( { container, command, spinner, debug } ) {
29
37
  // Shows a contextual tip for the given command.
30
38
  showCommandTips( command, container, spinner );
31
39
 
32
- await spawnCommandDirectly( {
33
- container,
34
- command,
35
- spinner,
36
- config,
37
- } );
40
+ await spawnCommandDirectly( config, container, command, envCwd, spinner );
38
41
 
39
42
  spinner.text = `Ran \`${ command }\` in '${ container }'.`;
40
43
  };
@@ -42,17 +45,22 @@ module.exports = async function run( { container, command, spinner, debug } ) {
42
45
  /**
43
46
  * Runs an arbitrary command on the given Docker container.
44
47
  *
45
- * @param {Object} options
46
- * @param {string} options.container The Docker container to run the command on.
47
- * @param {string} options.command The command to run.
48
- * @param {WPConfig} options.config The wp-env configuration.
49
- * @param {Object} options.spinner A CLI spinner which indicates progress.
48
+ * @param {WPConfig} config The wp-env configuration.
49
+ * @param {string} container The Docker container to run the command on.
50
+ * @param {string} command The command to run.
51
+ * @param {string} envCwd The working directory for the command to be executed from.
52
+ * @param {Object} spinner A CLI spinner which indicates progress.
50
53
  */
51
- function spawnCommandDirectly( { container, command, config, spinner } ) {
54
+ function spawnCommandDirectly( config, container, command, envCwd, spinner ) {
55
+ // We need to pass absolute paths to the container.
56
+ envCwd = path.resolve( '/var/www/html', envCwd );
57
+
52
58
  const composeCommand = [
53
59
  '-f',
54
60
  config.dockerComposeConfigPath,
55
61
  'run',
62
+ '-w',
63
+ envCwd,
56
64
  '--rm',
57
65
  container,
58
66
  ...command.split( ' ' ), // The command will fail if passed as a complete string.
@@ -193,7 +193,7 @@ module.exports = async function start( { spinner, debug, update, xdebug } ) {
193
193
  }
194
194
 
195
195
  const siteUrl = config.env.development.config.WP_SITEURL;
196
- const e2eSiteUrl = `http://${ config.env.tests.config.WP_TESTS_DOMAIN }:${ config.env.tests.port }/`;
196
+ const testsSiteUrl = config.env.tests.config.WP_SITEURL;
197
197
 
198
198
  const { out: mySQLAddress } = await dockerCompose.port(
199
199
  'mysql',
@@ -213,7 +213,7 @@ module.exports = async function start( { spinner, debug, update, xdebug } ) {
213
213
  .concat( siteUrl ? ` at ${ siteUrl }` : '.' )
214
214
  .concat( '\n' )
215
215
  .concat( 'WordPress test site started' )
216
- .concat( e2eSiteUrl ? ` at ${ e2eSiteUrl }` : '.' )
216
+ .concat( testsSiteUrl ? ` at ${ testsSiteUrl }` : '.' )
217
217
  .concat( '\n' )
218
218
  .concat( `MySQL is listening on port ${ mySQLPort }` )
219
219
  .concat(
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ const { ValidationError } = require( './validate-config' );
5
+
6
+ /**
7
+ * Adds or replaces the port to the given domain or URI.
8
+ *
9
+ * @param {string} input The domain or URI to operate on.
10
+ * @param {string} port The port to append.
11
+ * @param {boolean} [replace] Indicates whether or not the port should be replaced if one is already present. Defaults to true.
12
+ * @return {string} The string with the port added or replaced.
13
+ */
14
+ module.exports = function addOrReplacePort( input, port, replace = true ) {
15
+ // This matches both domains and URIs with an optional port and anything
16
+ // that remains after. We can use this to build an output string that
17
+ // adds or replaces the port without making any other changes to the input.
18
+ const matches = input.match(
19
+ /^((?:.+:\/\/)?[a-z0-9.\-]+)(?::([0-9]+))?(.*)$/i
20
+ );
21
+ if ( ! matches ) {
22
+ throw new ValidationError( `Invalid domain or uri: ${ input }.` );
23
+ }
24
+
25
+ // When a port is already present we will do nothing if the caller doesn't want it to be replaced.
26
+ if ( matches[ 2 ] !== undefined && ! replace ) {
27
+ return input;
28
+ }
29
+
30
+ // Place the port in the correct location in the input.
31
+ return matches[ 1 ] + ':' + port + matches[ 3 ];
32
+ };
@@ -14,6 +14,7 @@ const { validateConfig, ValidationError } = require( './validate-config' );
14
14
  const readRawConfigFile = require( './read-raw-config-file' );
15
15
  const parseConfig = require( './parse-config' );
16
16
  const { includeTestsPath, parseSourceString } = parseConfig;
17
+ const addOrReplacePort = require( './add-or-replace-port' );
17
18
  const md5 = require( '../md5' );
18
19
 
19
20
  /**
@@ -272,30 +273,25 @@ function withOverrides( config ) {
272
273
  config.env.tests.phpVersion =
273
274
  process.env.WP_ENV_PHP_VERSION || config.env.tests.phpVersion;
274
275
 
275
- const updateEnvUrl = ( configKey ) => {
276
- [ 'development', 'tests' ].forEach( ( envKey ) => {
277
- try {
278
- const baseUrl = new URL(
279
- config.env[ envKey ].config[ configKey ]
280
- );
281
-
282
- // Don't overwrite the port of WP_HOME when set.
283
- if ( ! ( configKey === 'WP_HOME' && !! baseUrl.port ) ) {
284
- baseUrl.port = config.env[ envKey ].port;
285
- }
276
+ // Some of our configuration options need to have the port added to them.
277
+ const addConfigPort = ( configKey ) => {
278
+ // Don't replace the port if one is set in WP_HOME.
279
+ const replace = configKey !== 'WP_HOME';
286
280
 
287
- config.env[ envKey ].config[ configKey ] = baseUrl.toString();
288
- } catch ( error ) {
289
- throw new ValidationError(
290
- `Invalid .wp-env.json: config.${ configKey } must be a valid URL.`
291
- );
292
- }
293
- } );
281
+ config.env.development.config[ configKey ] = addOrReplacePort(
282
+ config.env.development.config[ configKey ],
283
+ config.env.development.port,
284
+ replace
285
+ );
286
+ config.env.tests.config[ configKey ] = addOrReplacePort(
287
+ config.env.tests.config[ configKey ],
288
+ config.env.tests.port,
289
+ replace
290
+ );
294
291
  };
295
-
296
- // Update wp config options to include the correct port number in the URL.
297
- updateEnvUrl( 'WP_SITEURL' );
298
- updateEnvUrl( 'WP_HOME' );
292
+ addConfigPort( 'WP_TESTS_DOMAIN' );
293
+ addConfigPort( 'WP_SITEURL' );
294
+ addConfigPort( 'WP_HOME' );
299
295
 
300
296
  return config;
301
297
  }
@@ -14,10 +14,10 @@ exports[`readConfig config file should match snapshot 1`] = `
14
14
  "TEST_VAL3": false,
15
15
  "WP_DEBUG": true,
16
16
  "WP_ENVIRONMENT_TYPE": "local",
17
- "WP_HOME": "http://localhost:2000/",
17
+ "WP_HOME": "http://localhost:2000",
18
18
  "WP_PHP_BINARY": "php",
19
- "WP_SITEURL": "http://localhost:2000/",
20
- "WP_TESTS_DOMAIN": "localhost",
19
+ "WP_SITEURL": "http://localhost:2000",
20
+ "WP_TESTS_DOMAIN": "localhost:2000",
21
21
  "WP_TESTS_EMAIL": "admin@example.org",
22
22
  "WP_TESTS_TITLE": "Test Blog",
23
23
  },
@@ -36,10 +36,10 @@ exports[`readConfig config file should match snapshot 1`] = `
36
36
  "TEST_VAL3": false,
37
37
  "WP_DEBUG": false,
38
38
  "WP_ENVIRONMENT_TYPE": "local",
39
- "WP_HOME": "http://localhost:1000/",
39
+ "WP_HOME": "http://localhost:1000",
40
40
  "WP_PHP_BINARY": "php",
41
- "WP_SITEURL": "http://localhost:1000/",
42
- "WP_TESTS_DOMAIN": "localhost",
41
+ "WP_SITEURL": "http://localhost:1000",
42
+ "WP_TESTS_DOMAIN": "localhost:1000",
43
43
  "WP_TESTS_EMAIL": "admin@example.org",
44
44
  "WP_TESTS_TITLE": "Test Blog",
45
45
  },
@@ -59,10 +59,10 @@ exports[`readConfig wp config values should use default config values 1`] = `
59
59
  "SCRIPT_DEBUG": false,
60
60
  "WP_DEBUG": false,
61
61
  "WP_ENVIRONMENT_TYPE": "local",
62
- "WP_HOME": "http://localhost:8889/",
62
+ "WP_HOME": "http://localhost:8889",
63
63
  "WP_PHP_BINARY": "php",
64
- "WP_SITEURL": "http://localhost:8889/",
65
- "WP_TESTS_DOMAIN": "localhost",
64
+ "WP_SITEURL": "http://localhost:8889",
65
+ "WP_TESTS_DOMAIN": "localhost:8889",
66
66
  "WP_TESTS_EMAIL": "admin@example.org",
67
67
  "WP_TESTS_TITLE": "Test Blog",
68
68
  }
@@ -73,10 +73,10 @@ exports[`readConfig wp config values should use default config values 2`] = `
73
73
  "SCRIPT_DEBUG": true,
74
74
  "WP_DEBUG": true,
75
75
  "WP_ENVIRONMENT_TYPE": "local",
76
- "WP_HOME": "http://localhost:8888/",
76
+ "WP_HOME": "http://localhost:8888",
77
77
  "WP_PHP_BINARY": "php",
78
- "WP_SITEURL": "http://localhost:8888/",
79
- "WP_TESTS_DOMAIN": "localhost",
78
+ "WP_SITEURL": "http://localhost:8888",
79
+ "WP_TESTS_DOMAIN": "localhost:8888",
80
80
  "WP_TESTS_EMAIL": "admin@example.org",
81
81
  "WP_TESTS_TITLE": "Test Blog",
82
82
  }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ const addOrReplacePort = require( '../add-or-replace-port.js' );
5
+
6
+ describe( 'addOrReplacePort', () => {
7
+ beforeEach( () => {
8
+ jest.clearAllMocks();
9
+ } );
10
+
11
+ it( 'should add or replace port with various inputs', () => {
12
+ const testMap = [
13
+ // Addition
14
+ { in: 'test', expect: 'test:101' },
15
+ { in: 'test/test?test#test', expect: 'test:101/test?test#test' },
16
+ { in: 'http://test.com', expect: 'http://test.com:101' },
17
+ {
18
+ in: 'http://test.com/test?test#test',
19
+ expect: 'http://test.com:101/test?test#test',
20
+ },
21
+ { in: 'ssh://test.com', expect: 'ssh://test.com:101' },
22
+ { in: 'test.com', expect: 'test.com:101' },
23
+
24
+ // Replacement
25
+ { in: 'test:99', expect: 'test:101' },
26
+ { in: 'test:99/test?test#test', expect: 'test:101/test?test#test' },
27
+ { in: 'http://test.com:99', expect: 'http://test.com:101' },
28
+ {
29
+ in: 'http://test.com:99/test?test#test',
30
+ expect: 'http://test.com:101/test?test#test',
31
+ },
32
+ { in: 'ssh://test.com:99', expect: 'ssh://test.com:101' },
33
+ { in: 'test.com:99', expect: 'test.com:101' },
34
+ ];
35
+
36
+ for ( const test of testMap ) {
37
+ const result = addOrReplacePort( test.in, '101' );
38
+ expect( result ).toEqual( test.expect );
39
+ }
40
+ } );
41
+
42
+ it( 'should do nothing if port is present but replacement is not requested', () => {
43
+ const testMap = [
44
+ { in: 'test', expect: 'test:103' },
45
+ { in: 'test:99', expect: 'test:99' },
46
+ ];
47
+
48
+ for ( const test of testMap ) {
49
+ const result = addOrReplacePort( test.in, '103', false );
50
+ expect( result ).toEqual( test.expect );
51
+ }
52
+ } );
53
+ } );
@@ -70,6 +70,44 @@ describe( 'readConfig', () => {
70
70
  }
71
71
  } );
72
72
 
73
+ it( 'should throw a validation error if WP_SITEURL is not a valid URL', async () => {
74
+ readFile.mockImplementation( () =>
75
+ Promise.resolve(
76
+ JSON.stringify( {
77
+ config: {
78
+ WP_SITEURL: 'test',
79
+ },
80
+ } )
81
+ )
82
+ );
83
+ expect.assertions( 2 );
84
+ try {
85
+ await readConfig( '.wp-env.json' );
86
+ } catch ( error ) {
87
+ expect( error ).toBeInstanceOf( ValidationError );
88
+ expect( error.message ).toContain( 'must be a valid URL' );
89
+ }
90
+ } );
91
+
92
+ it( 'should throw a validation error if WP_HOME is not a valid URL', async () => {
93
+ readFile.mockImplementation( () =>
94
+ Promise.resolve(
95
+ JSON.stringify( {
96
+ config: {
97
+ WP_SITEURL: 'test',
98
+ },
99
+ } )
100
+ )
101
+ );
102
+ expect.assertions( 2 );
103
+ try {
104
+ await readConfig( '.wp-env.json' );
105
+ } catch ( error ) {
106
+ expect( error ).toBeInstanceOf( ValidationError );
107
+ expect( error.message ).toContain( 'must be a valid URL' );
108
+ }
109
+ } );
110
+
73
111
  it( 'should infer a core config when ran from a core directory', async () => {
74
112
  readFile.mockImplementation( () =>
75
113
  Promise.reject( { code: 'ENOENT' } )
@@ -854,17 +892,17 @@ describe( 'readConfig', () => {
854
892
  development: {
855
893
  port: 1000,
856
894
  config: {
857
- WP_TESTS_DOMAIN: 'localhost',
858
- WP_SITEURL: 'http://localhost:1000/',
859
- WP_HOME: 'http://localhost:1000/',
895
+ WP_TESTS_DOMAIN: 'localhost:1000',
896
+ WP_SITEURL: 'http://localhost:1000',
897
+ WP_HOME: 'http://localhost:1000',
860
898
  },
861
899
  },
862
900
  tests: {
863
901
  port: 2000,
864
902
  config: {
865
- WP_TESTS_DOMAIN: 'localhost',
866
- WP_SITEURL: 'http://localhost:2000/',
867
- WP_HOME: 'http://localhost:2000/',
903
+ WP_TESTS_DOMAIN: 'localhost:2000',
904
+ WP_SITEURL: 'http://localhost:2000',
905
+ WP_HOME: 'http://localhost:2000',
868
906
  },
869
907
  },
870
908
  },
@@ -878,7 +916,7 @@ describe( 'readConfig', () => {
878
916
  port: 1000,
879
917
  testsPort: 2000,
880
918
  config: {
881
- WP_HOME: 'http://localhost:3000/',
919
+ WP_HOME: 'http://localhost:3000',
882
920
  },
883
921
  } )
884
922
  )
@@ -890,17 +928,17 @@ describe( 'readConfig', () => {
890
928
  development: {
891
929
  port: 1000,
892
930
  config: {
893
- WP_TESTS_DOMAIN: 'localhost',
894
- WP_SITEURL: 'http://localhost:1000/',
895
- WP_HOME: 'http://localhost:3000/',
931
+ WP_TESTS_DOMAIN: 'localhost:1000',
932
+ WP_SITEURL: 'http://localhost:1000',
933
+ WP_HOME: 'http://localhost:3000',
896
934
  },
897
935
  },
898
936
  tests: {
899
937
  port: 2000,
900
938
  config: {
901
- WP_TESTS_DOMAIN: 'localhost',
902
- WP_SITEURL: 'http://localhost:2000/',
903
- WP_HOME: 'http://localhost:3000/',
939
+ WP_TESTS_DOMAIN: 'localhost:2000',
940
+ WP_SITEURL: 'http://localhost:2000',
941
+ WP_HOME: 'http://localhost:3000',
904
942
  },
905
943
  },
906
944
  },
@@ -1153,9 +1191,9 @@ describe( 'readConfig', () => {
1153
1191
  WP_PHP_BINARY: 'php',
1154
1192
  WP_TESTS_EMAIL: 'admin@example.org',
1155
1193
  WP_TESTS_TITLE: 'Test Blog',
1156
- WP_TESTS_DOMAIN: 'localhost',
1157
- WP_SITEURL: 'http://localhost:8889/',
1158
- WP_HOME: 'http://localhost:8889/',
1194
+ WP_TESTS_DOMAIN: 'localhost:8889',
1195
+ WP_SITEURL: 'http://localhost:8889',
1196
+ WP_HOME: 'http://localhost:8889',
1159
1197
  } );
1160
1198
 
1161
1199
  expect( config.env.development.config ).toEqual( {
@@ -1167,9 +1205,9 @@ describe( 'readConfig', () => {
1167
1205
  WP_PHP_BINARY: 'php',
1168
1206
  WP_TESTS_EMAIL: 'admin@example.org',
1169
1207
  WP_TESTS_TITLE: 'Test Blog',
1170
- WP_TESTS_DOMAIN: 'localhost',
1171
- WP_SITEURL: 'http://localhost:8888/',
1172
- WP_HOME: 'http://localhost:8888/',
1208
+ WP_TESTS_DOMAIN: 'localhost:8888',
1209
+ WP_SITEURL: 'http://localhost:8888',
1210
+ WP_HOME: 'http://localhost:8888',
1173
1211
  } );
1174
1212
  } );
1175
1213
  } );
@@ -83,9 +83,33 @@ function validateConfig( config, envLocation ) {
83
83
  );
84
84
  }
85
85
 
86
+ checkValidURL( envPrefix, config.config, 'WP_SITEURL' );
87
+ checkValidURL( envPrefix, config.config, 'WP_HOME' );
88
+
86
89
  return config;
87
90
  }
88
91
 
92
+ /**
93
+ * Validates the input and throws if it isn't a valid URL.
94
+ *
95
+ * @param {string} envPrefix The environment we're validating.
96
+ * @param {Object} config The configuration object we're looking at.
97
+ * @param {string} configKey The configuration key we're validating.
98
+ */
99
+ function checkValidURL( envPrefix, config, configKey ) {
100
+ if ( config[ configKey ] === undefined ) {
101
+ return;
102
+ }
103
+
104
+ try {
105
+ new URL( config[ configKey ] );
106
+ } catch {
107
+ throw new ValidationError(
108
+ `Invalid .wp-env.json: "${ envPrefix }config.${ configKey }" must be a valid URL.`
109
+ );
110
+ }
111
+ }
112
+
89
113
  module.exports = {
90
114
  validateConfig,
91
115
  ValidationError,
package/lib/wordpress.js CHANGED
@@ -44,20 +44,7 @@ async function checkDatabaseConnection( { dockerComposeConfigPath, debug } ) {
44
44
  * @param {Object} spinner A CLI spinner which indicates progress.
45
45
  */
46
46
  async function configureWordPress( environment, config, spinner ) {
47
- const url = ( () => {
48
- const port = config.env[ environment ].port;
49
- const domain =
50
- environment === 'tests'
51
- ? config.env.tests.config.WP_TESTS_DOMAIN
52
- : config.env.development.config.WP_SITEURL;
53
- if ( port === 80 ) {
54
- return domain;
55
- }
56
-
57
- return `${ domain }:${ port }`;
58
- } )();
59
-
60
- const installCommand = `wp core install --url="${ url }" --title="${ config.name }" --admin_user=admin --admin_password=password --admin_email=wordpress@example.com --skip-email`;
47
+ const installCommand = `wp core install --url="${ config.env[ environment ].config.WP_SITEURL }" --title="${ config.name }" --admin_user=admin --admin_password=password --admin_email=wordpress@example.com --skip-email`;
61
48
 
62
49
  // -eo pipefail exits the command as soon as anything fails in bash.
63
50
  const setupCommands = [ 'set -eo pipefail', installCommand ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/env",
3
- "version": "5.16.0",
3
+ "version": "6.0.0",
4
4
  "description": "A zero-config, self contained local WordPress environment for development and testing.",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -51,5 +51,5 @@
51
51
  "scripts": {
52
52
  "test": "echo \"Error: run tests from root\" && exit 1"
53
53
  },
54
- "gitHead": "d61700b9f1c72ba0b030fc815ef1685b4f4031ec"
54
+ "gitHead": "6df0c62d43b8901414ccd22ffbe56eaa99d012a6"
55
55
  }