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 better default PHPunit settings, fix Xdebug, and update docs #50490

Merged
merged 12 commits into from
May 10, 2023
4 changes: 2 additions & 2 deletions packages/env/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@

### Breaking Change

- Docker containers now run as the host user. This should resolve problems with permissions arising from different owners
between the host, web container, and cli container. If you still encounter permissions issues, try running `npx wp-env destroy` so that the environment can be recreated with the correct permissions.
- Docker containers now run as the host user. This should resolve problems with permissions arising from different owners between the host, web container, and cli container. If you still encounter permissions issues, try running `npx wp-env destroy` so that the environment can be recreated with the correct permissions.
- Remove the `composer` and `phpunit` Docker containers. If you are currently using the `run composer` or `run phpunit` command you can migrate to `run cli composer` or `run tests-cli phpunit` respectively. Note that with `composer`, you will need to use the `--env-cwd` option to navigate to your plugin's directory as it is no longer the default working directory.

### New feature
Expand All @@ -23,6 +22,7 @@ between the host, web container, and cli container. If you still encounter permi
### Enhancement

- `wp-env run ...` now uses docker-compose exec instead of docker-compose run. As a result, it is much faster, since commands are executed against existing services, rather than creating them from scratch each time.
- Increase the maximum upload size to 1GB.

## 6.0.0 (2023-04-26)

Expand Down
54 changes: 50 additions & 4 deletions packages/env/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,26 @@ Out of the box `wp-env` includes the [WordPress' PHPUnit test files](https://dev

While we do provide a default `wp-tests-config.php` file within the environment, there may be cases where you want to use your own. WordPress provides a `WP_TESTS_CONFIG_FILE_PATH` constant that you can use to change the `wp-config.php` file used for testing. Set this to a desired path in your `bootstrap.php` file and the file you've chosen will be used instead of the one included in the environment.

## Using `composer`, `phpunit`, and `wp-cli` tools.

For ease of use, Composer, PHPUnit, and wp-cli are available for in the environment. To run these executables, use `wp-env run <env> <tool> <command>`. For example, `wp-env run cli composer install`, or `wp-env run tests-cli phpunit`. You can also access various shells like `wp-env run cli bash` or `wp-env run cli wp shell`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I worry that including wp-cli here makes it ambiguous. It feels like this is saying you should use wp-env run cli wp-cli <command>.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point. I was trying to provide a search result if someone is looking to use wp-cli. And to actually use it, you have to do run cli wp... how do you think we should phrase it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I think this is fine. If you look at https://wp-cli.org, the official documentation has you using wp as the command. Anyone looking to use wp-cli will have that as the expectation I bet.


For the `env` part, `cli` and `wordpress` share a database and mapped volumes, but more tools are available in the cli environment. You should use the `tests-cli` / `tests-wordpress` environments for a separate testing database.

By default, the cwd of the run command is the root of the WordPress install. If you're working on a plugin, you likely need to pass `--env-cwd` to make sure composer/phpunit commands are executed relative to the plugin you're working on. For example, `wp-env run cli --env-cwd=wp-content/plugins/gutenberg composer install`.

To make this easier, it's often helpful to add scripts in your `package.json` file:

```json
{
"scripts": {
"composer": "wp-env run cli --env-cwd=wp-content/plugins/gutenberg composer"
}
}
```

Then, `npm run composer install` would run composer install in the environment. You could also do this for phpunit, wp-cli, etc.

## Using Xdebug

Xdebug is installed in the wp-env environment, but it is turned off by default. To enable Xdebug, you can use the `--xdebug` flag with the `wp-env start` command. Here is a reference to how the flag works:
Expand Down Expand Up @@ -310,9 +330,10 @@ back to using quotation marks; <code>wp-env</code> considers everything inside t
quotation marks to be command argument.

For example, to ask <code>WP-CLI</code> for its help text:

<pre>sh
<code class="language-sh">wp-env run cli "wp --help"</code></pre>

Without the quotation marks, <code>wp-env</code> will print its own help text instead of
passing it to the container. If you experience any problems where the command
is not being passed correctly, fall back to using quotation marks.
Expand Down Expand Up @@ -396,6 +417,7 @@ Success: Installed 1 of 1 plugins.
```

#### Changing the permalink structure

You might want to do this to enable access to the REST API (`wp-env/wp/v2/`) endpoint in your wp-env environment. The endpoint is not available with plain permalinks.

**Examples**
Expand Down Expand Up @@ -540,14 +562,14 @@ Additionally, the values referencing a URL include the specified port for the gi
## Lifecycle Hooks

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
environments, so, ensure any commands you build won't break on subsequent executions.
environments, so, ensure any commands you build won't break on subsequent executions.

### After Setup

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:

- `wp-env start`: Runs when the config changes, WordPress updates, or you pass the `--update` flag.
- `wp-env clean`: Runs after the selected environments have been cleaned.
- `wp-env start`: Runs when the config changes, WordPress updates, or you pass the `--update` flag.
- `wp-env clean`: Runs after the selected environments have been cleaned.

You can override the `afterSetup` option using the `WP_ENV_AFTER_SETUP` environment variable.

Expand Down Expand Up @@ -689,6 +711,30 @@ This is useful for performing some actions after setting up the environment, suc
}
```

### Advanced PHP settings

You can set PHP settings by mapping an `.htaccess` file:

```json
{
"mappings": {
"wp-content/.htaccess": "./.htaccess"
}
}
```

Then, your .htaccess file can contain various settings like this:

```
# Note: the default upload value is 1G.

php_value post_max_size 2G
php_value upload_max_filesize 2G
php_value memory_limit 2G
```

This is useful if there are options you'd normally add to `php.ini`, which is difficult to access in this environment.

## Contributing to this package

This is an individual package that's part of the Gutenberg project. The project is organized as a monorepo. It's made up of multiple self-contained software packages, each with a specific purpose. The packages in this monorepo are published to [npm](https://www.npmjs.com/) and used by [WordPress](https://make.wordpress.org/core/) as well as other software projects.
Expand Down
4 changes: 4 additions & 0 deletions packages/env/lib/build-docker-compose-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ module.exports = function buildDockerComposeConfig( config ) {
WP_TESTS_DIR: '/wordpress-phpunit',
},
volumes: developmentMounts,
extra_hosts: [ 'host.docker.internal:host-gateway' ],
},
'tests-wordpress': {
depends_on: [ 'tests-mysql' ],
Expand All @@ -226,6 +227,7 @@ module.exports = function buildDockerComposeConfig( config ) {
WP_TESTS_DIR: '/wordpress-phpunit',
},
volumes: testsMounts,
extra_hosts: [ 'host.docker.internal:host-gateway' ],
},
cli: {
depends_on: [ 'wordpress' ],
Expand All @@ -241,6 +243,7 @@ module.exports = function buildDockerComposeConfig( config ) {
...dbEnv.development,
WP_TESTS_DIR: '/wordpress-phpunit',
},
extra_hosts: [ 'host.docker.internal:host-gateway' ],
noahtallen marked this conversation as resolved.
Show resolved Hide resolved
},
'tests-cli': {
depends_on: [ 'tests-wordpress' ],
Expand All @@ -256,6 +259,7 @@ module.exports = function buildDockerComposeConfig( config ) {
...dbEnv.tests,
WP_TESTS_DIR: '/wordpress-phpunit',
},
extra_hosts: [ 'host.docker.internal:host-gateway' ],
},
},
volumes: {
Expand Down
65 changes: 32 additions & 33 deletions packages/env/lib/init-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ const path = require( 'path' );
const { writeFile, mkdir } = require( 'fs' ).promises;
const { existsSync } = require( 'fs' );
const yaml = require( 'js-yaml' );
const os = require( 'os' );

/**
* Internal dependencies
Expand Down Expand Up @@ -224,8 +223,9 @@ function installDependencies( environment, config ) {
// WordPress image uses Ubuntu while the CLI image uses Alpine.

// Start with some environment-specific dependency installations.
if ( environment === 'wordpress' ) {
dockerFileContent += `
switch ( environment ) {
case 'wordpress': {
dockerFileContent += `
# Make sure we're working with the latest packages.
RUN apt-get -qy update

Expand All @@ -235,33 +235,29 @@ RUN apt-get -qy install $PHPIZE_DEPS && touch /usr/local/etc/php/php.ini
# Set up sudo so they can have root access.
RUN apt-get -qy install sudo
RUN echo "$HOST_USERNAME ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers`;
} else {
dockerFileContent += `
break;
}
case 'cli': {
noahtallen marked this conversation as resolved.
Show resolved Hide resolved
dockerFileContent += `
RUN apk update
RUN apk --no-cache add $PHPIZE_DEPS && touch /usr/local/etc/php/php.ini
RUN apk --no-cache add sudo
RUN apk --no-cache add sudo linux-headers
RUN echo "$HOST_USERNAME ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers`;
break;
}
default: {
throw new Error( `Invalid environment "${ environment }" given` );
}
}

if ( config.xdebug !== 'off' ) {
const usingCompatiblePhp = checkXdebugPhpCompatibility( config );
if ( usingCompatiblePhp ) {
// Discover client host does not appear to work on macOS with Docker.
const clientDetectSettings =
os.type() === 'Linux'
? 'xdebug.discover_client_host=true'
: 'xdebug.client_host="host.docker.internal"';
dockerFileContent += getXdebugConfig( config );

dockerFileContent += `
RUN if [ -z "$(pecl list | grep xdebug)" ] ; then pecl install xdebug ; fi
RUN docker-php-ext-enable xdebug
RUN echo 'xdebug.start_with_request=yes' >> /usr/local/etc/php/php.ini
RUN echo 'xdebug.mode=true' >> /usr/local/etc/php/php.ini
RUN echo '${ clientDetectSettings }' >> /usr/local/etc/php/php.ini`;
}
}
// Add better PHP settings.
dockerFileContent += `
RUN echo 'upload_max_filesize = 1G' >> /usr/local/etc/php/php.ini
RUN echo 'post_max_size = 1G' >> /usr/local/etc/php/php.ini`;

// Make sure Composer is available for use in the container.
// Make sure Composer is available for use in all environments.
dockerFileContent += `
RUN curl -sS https://getcomposer.org/installer -o /tmp/composer-setup.php
RUN export COMPOSER_HASH=\`curl -sS https://composer.github.io/installer.sig\` && php -r "if (hash_file('SHA384', '/tmp/composer-setup.php') === '$COMPOSER_HASH') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('/tmp/composer-setup.php'); } echo PHP_EOL;"
Expand All @@ -280,19 +276,17 @@ USER root`;
}

/**
* Checks the configured PHP version
* against the minimum version supported by Xdebug
* Gets the Xdebug config based on the options in the config object.
*
* @param {WPConfig} config
* @return {boolean} Whether the PHP version is supported by Xdebug
* @return {string} The Xdebug config -- can be an empty string when it's not used.
*/
function checkXdebugPhpCompatibility( config ) {
// By default, an undefined phpVersion uses the version on the docker image,
// which is supported by Xdebug 3.
const phpCompatibility = true;
function getXdebugConfig( config ) {
if ( config.xdebug === 'off' ) {
return '';
}

// If PHP version is defined
// ensure it meets the Xdebug minimum compatibility requirment.
// Throw an error if someone tries to use Xdebug with an unsupported PHP version.
if ( config.env.development.phpVersion ) {
noahtallen marked this conversation as resolved.
Show resolved Hide resolved
const versionTokens = config.env.development.phpVersion.split( '.' );
const majorVer = parseInt( versionTokens[ 0 ] );
Expand All @@ -311,5 +305,10 @@ function checkXdebugPhpCompatibility( config ) {
}
}

return phpCompatibility;
return `
RUN if [ -z "$(pecl list | grep xdebug)" ] ; then pecl install xdebug ; fi
RUN docker-php-ext-enable xdebug
RUN echo 'xdebug.start_with_request=yes' >> /usr/local/etc/php/php.ini
RUN echo 'xdebug.mode=${ config.xdebug }' >> /usr/local/etc/php/php.ini
RUN echo 'xdebug.client_host="host.docker.internal"' >> /usr/local/etc/php/php.ini`;
}