Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wp-env: Add custom port numbers to .wp-env.json #20158

Merged
merged 11 commits into from
Feb 13, 2020
24 changes: 22 additions & 2 deletions packages/env/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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) |
| -- | -- | -- |
Expand Down Expand Up @@ -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
}
```

<br/><br/><p align="center"><img src="https://s.w.org/style/images/codeispoetry.png?1" alt="Code is Poetry." /></p>
8 changes: 6 additions & 2 deletions packages/env/lib/build-docker-compose-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand All @@ -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',
Expand All @@ -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',
Expand Down
24 changes: 24 additions & 0 deletions packages/env/lib/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 main WordPress environment.
noahtallen marked this conversation as resolved.
Show resolved Hide resolved
* @property {number} testsPort The port on which to start the tests WordPress environment.
noahtallen marked this conversation as resolved.
Show resolved Hide resolved
*/

/**
Expand Down Expand Up @@ -96,6 +98,8 @@ module.exports = {
core: null,
plugins: [],
themes: [],
port: 8888,
testsPort: 8889,
},
config
);
Expand Down Expand Up @@ -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',
Expand All @@ -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'
Expand Down
45 changes: 45 additions & 0 deletions packages/env/test/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -217,4 +217,49 @@ 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.'
);
}
} );
} );

/**
* 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();
}