From cf8fa0a13659229ff8651e7ffd8d252ddf225e53 Mon Sep 17 00:00:00 2001 From: Noah Allen Date: Wed, 12 Feb 2020 21:23:30 -0800 Subject: [PATCH] wp-env: Add custom ports to .wp-env.json (#20158) Allows the user to set `port` and `testsPort` in .wp-env.json. - Port must be a number - Ports must be different - Ports can still be overridden with the environment variables --- packages/env/CHANGELOG.md | 4 ++ packages/env/README.md | 24 +++++++- .../env/lib/build-docker-compose-config.js | 8 ++- packages/env/lib/config.js | 24 ++++++++ packages/env/test/config.js | 61 +++++++++++++++++++ 5 files changed, 117 insertions(+), 4 deletions(-) diff --git a/packages/env/CHANGELOG.md b/packages/env/CHANGELOG.md index 9400e9a113faa..61f195cbb1a54 100644 --- a/packages/env/CHANGELOG.md +++ b/packages/env/CHANGELOG.md @@ -1,5 +1,9 @@ ## Master +### New Feature + +- The `.wp-env.json` coniguration file now accepts `port` and `testsPort` options which can be used to set the ports on which the docker instance is mounted. + ## 1.0.0 (2020-02-10) ### Breaking Changes diff --git a/packages/env/README.md b/packages/env/README.md index 9e4ac9f7b4387..c651f228ffd4a 100644 --- a/packages/env/README.md +++ b/packages/env/README.md @@ -79,6 +79,8 @@ $ WP_ENV_PORT=3333 wp-env start Running `docker ps` and inspecting the `PORTS` column allows you to determine which port `wp-env` is currently using. +You may also specify the port numbers in your `.wp-env.json` file, but the environment variables take precedent. + ### 3. Restart `wp-env` Restarting `wp-env` will restart the underlying Docker containers which can fix many issues. @@ -175,15 +177,19 @@ Positionals: You can customize the WordPress installation, plugins and themes that the development environment will use by specifying a `.wp-env.json` file in the directory that you run `wp-env` from. -`.wp-env.json` supports three fields: +`.wp-env.json` supports five fields: | Field | Type | Default | Description | | -- | -- | -- | -- | | `"core"` | `string|null` | `null` | The WordPress installation to use. If `null` is specified, `wp-env` will use the latest production release of WordPress. | | `"plugins"` | `string[]` | `[]` | A list of plugins to install and activate in the environment. | | `"themes"` | `string[]` | `[]` | A list of themes to install in the environment. The first theme in the list will be activated. | +| `"port"` | `string` | `"8888"` | The primary port number to use for the insallation. You'll access the instance through the port: 'http://localhost:8888'. | +| `"testsPort"` | `string` | `"8889"` | The port number to use for the tests instance. | + +_Note: the port number environment variables (`WP_ENV_PORT` and `WP_ENV_TESTS_PORT`) take precedent over the .wp-env.json values._ -Several types of strings can be passed into these fields: +Several types of strings can be passed into the `core`, `plugins`, and `themes` fields: | Type | Format | Example(s) | | -- | -- | -- | @@ -251,4 +257,18 @@ This is useful for integration testing: that is, testing how old versions of Wor } ``` +#### Custom Port Numbers + +You can tell `wp-env` to use a custom port number so that your instance does not conflict with other `wp-env` instances. + +```json +{ + "plugins": [ + ".", + ], + "port": 4013, + "testsPort": 4012 +} +``` +

Code is Poetry.

diff --git a/packages/env/lib/build-docker-compose-config.js b/packages/env/lib/build-docker-compose-config.js index fae4a6d743e1b..3b4dc1a5f769c 100644 --- a/packages/env/lib/build-docker-compose-config.js +++ b/packages/env/lib/build-docker-compose-config.js @@ -51,6 +51,10 @@ module.exports = function buildDockerComposeConfig( config ) { ...themeMounts, ]; + // Set the default ports based on the config values. + const developmentPorts = `\${WP_ENV_PORT:-${ config.port }}:80`; + const testsPorts = `\${WP_ENV_TESTS_PORT:-${ config.testsPort }}:80`; + return { version: '3.7', services: { @@ -63,7 +67,7 @@ module.exports = function buildDockerComposeConfig( config ) { wordpress: { depends_on: [ 'mysql' ], image: 'wordpress', - ports: [ '${WP_ENV_PORT:-8888}:80' ], + ports: [ developmentPorts ], environment: { WORDPRESS_DEBUG: '1', WORDPRESS_DB_NAME: 'wordpress', @@ -73,7 +77,7 @@ module.exports = function buildDockerComposeConfig( config ) { 'tests-wordpress': { depends_on: [ 'mysql' ], image: 'wordpress', - ports: [ '${WP_ENV_TESTS_PORT:-8889}:80' ], + ports: [ testsPorts ], environment: { WORDPRESS_DEBUG: '1', WORDPRESS_DB_NAME: 'tests-wordpress', diff --git a/packages/env/lib/config.js b/packages/env/lib/config.js index 817b71b9540dc..fac6e7b6f5566 100644 --- a/packages/env/lib/config.js +++ b/packages/env/lib/config.js @@ -35,6 +35,8 @@ const HOME_PATH_PREFIX = `~${ path.sep }`; * @property {Source|null} coreSource The WordPress installation to load in the environment. * @property {Source[]} pluginSources Plugins to load in the environment. * @property {Source[]} themeSources Themes to load in the environment. + * @property {number} port The port on which to start the development WordPress environment. + * @property {number} testsPort The port on which to start the testing WordPress environment. */ /** @@ -96,6 +98,8 @@ module.exports = { core: null, plugins: [], themes: [], + port: 8888, + testsPort: 8889, }, config ); @@ -124,6 +128,24 @@ module.exports = { ); } + if ( ! Number.isInteger( config.port ) ) { + throw new ValidationError( + 'Invalid .wp-env.json: "port" must be an integer.' + ); + } + + if ( ! Number.isInteger( config.testsPort ) ) { + throw new ValidationError( + 'Invalid .wp-env.json: "testsPort" must be an integer.' + ); + } + + if ( config.port === config.testsPort ) { + throw new ValidationError( + 'Invalid .wp-env.json: "testsPort" and "port" must be different.' + ); + } + const workDirectoryPath = path.resolve( os.homedir(), '.wp-env', @@ -134,6 +156,8 @@ module.exports = { name: path.basename( configDirectoryPath ), configDirectoryPath, workDirectoryPath, + port: config.port, + testsPort: config.testsPort, dockerComposeConfigPath: path.resolve( workDirectoryPath, 'docker-compose.yml' diff --git a/packages/env/test/config.js b/packages/env/test/config.js index ef886f078ce4c..eb6065ba9635c 100644 --- a/packages/env/test/config.js +++ b/packages/env/test/config.js @@ -217,4 +217,65 @@ describe( 'readConfig', () => { ); } } ); + + it( 'should throw a validaton error if the ports are not numbers', async () => { + expect.assertions( 10 ); + testPortNumberValidation( 'port', 'string' ); + testPortNumberValidation( 'testsPort', [] ); + testPortNumberValidation( 'port', {} ); + testPortNumberValidation( 'testsPort', false ); + testPortNumberValidation( 'port', null ); + } ); + + it( 'should throw a validaton error if the ports are the same', async () => { + expect.assertions( 2 ); + readFile.mockImplementation( () => + Promise.resolve( JSON.stringify( { port: 8888, testsPort: 8888 } ) ) + ); + try { + await readConfig( '.wp-env.json' ); + } catch ( error ) { + expect( error ).toBeInstanceOf( ValidationError ); + expect( error.message ).toContain( + 'Invalid .wp-env.json: "testsPort" and "port" must be different.' + ); + } + } ); + + it( 'should parse custom ports', async () => { + readFile.mockImplementation( () => + Promise.resolve( + JSON.stringify( { + port: 1000, + } ) + ) + ); + const config = await readConfig( '.wp-env.json' ); + // Custom port is overriden while testsPort gets the deault value. + expect( config ).toMatchObject( { + port: 1000, + testsPort: 8889, + } ); + } ); } ); + +/** + * Tests that readConfig will throw errors when invalid port numbers are passed. + * + * @param {string} portName The name of the port to test ('port' or 'testsPort') + * @param {any} value A value which should throw an error. + */ +async function testPortNumberValidation( portName, value ) { + readFile.mockImplementation( () => + Promise.resolve( JSON.stringify( { [ portName ]: value } ) ) + ); + try { + await readConfig( '.wp-env.json' ); + } catch ( error ) { + expect( error ).toBeInstanceOf( ValidationError ); + expect( error.message ).toContain( + `Invalid .wp-env.json: "${ portName }" must be an integer.` + ); + } + jest.clearAllMocks(); +}