diff --git a/packages/env/CHANGELOG.md b/packages/env/CHANGELOG.md
index 50943d92016352..bb68681c18f0fd 100644
--- a/packages/env/CHANGELOG.md
+++ b/packages/env/CHANGELOG.md
@@ -2,6 +2,10 @@
## Unreleased
+### Breaking Changes
+
+- `run` command now has a `--env-cwd` option to set the working directory in the container for the command to execute from.
+
## 5.16.0 (2023-04-12)
## 5.15.0 (2023-03-29)
diff --git a/packages/env/README.md b/packages/env/README.md
index 5c2ac83708a132..7a22dfe88428cf 100644
--- a/packages/env/README.md
+++ b/packages/env/README.md
@@ -316,7 +316,7 @@ The run command can be used to open shell sessions or invoke WP-CLI commands.
In some cases, `wp-env` may consume options that you are attempting to pass to
the container. This happens with options that `wp-env` has already declared,
-such as `--debug`, `--help`, and `--version`. When this happens, you should fall
+such as `--env-cwd`, `--debug`, `--help`, and `--version`. When this happens, you should fall
back to using quotation marks; `wp-env` considers everything inside the
quotation marks to be command argument.
@@ -349,6 +349,9 @@ Options:
--help Show help [boolean]
--version Show version number [boolean]
--debug Enable debug output. [boolean] [default: false]
+ --env-cwd The command's working directory inside of the container. Paths
+ without a leading slash are relative to the WordPress root.
+ [string] [default: "."]
```
For example:
diff --git a/packages/env/lib/cli.js b/packages/env/lib/cli.js
index abca20c9b3619a..68316855c6bede 100644
--- a/packages/env/lib/cli.js
+++ b/packages/env/lib/cli.js
@@ -174,6 +174,13 @@ module.exports = function cli() {
'run [command..]',
'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.',
( args ) => {
+ args.option( 'env-cwd', {
+ type: 'string',
+ requiresArg: true,
+ default: '.',
+ describe:
+ "The command's working directory inside of the container. Paths without a leading slash are relative to the WordPress root.",
+ } );
args.positional( 'container', {
type: 'string',
describe: 'The container to run the command on.',
diff --git a/packages/env/lib/commands/run.js b/packages/env/lib/commands/run.js
index f944d8de84fa53..fd0f800041cb91 100644
--- a/packages/env/lib/commands/run.js
+++ b/packages/env/lib/commands/run.js
@@ -2,6 +2,7 @@
* External dependencies
*/
const { spawn } = require( 'child_process' );
+const path = require( 'path' );
/**
* Internal dependencies
@@ -18,10 +19,17 @@ const initConfig = require( '../init-config' );
* @param {Object} options
* @param {string} options.container The Docker container to run the command on.
* @param {string[]} options.command The command to run.
+ * @param {string} options.envCwd The working directory for the command to be executed from.
* @param {Object} options.spinner A CLI spinner which indicates progress.
* @param {boolean} options.debug True if debug mode is enabled.
*/
-module.exports = async function run( { container, command, spinner, debug } ) {
+module.exports = async function run( {
+ container,
+ command,
+ envCwd,
+ spinner,
+ debug,
+} ) {
const config = await initConfig( { spinner, debug } );
command = command.join( ' ' );
@@ -29,12 +37,7 @@ module.exports = async function run( { container, command, spinner, debug } ) {
// Shows a contextual tip for the given command.
showCommandTips( command, container, spinner );
- await spawnCommandDirectly( {
- container,
- command,
- spinner,
- config,
- } );
+ await spawnCommandDirectly( config, container, command, envCwd, spinner );
spinner.text = `Ran \`${ command }\` in '${ container }'.`;
};
@@ -42,17 +45,22 @@ module.exports = async function run( { container, command, spinner, debug } ) {
/**
* Runs an arbitrary command on the given Docker container.
*
- * @param {Object} options
- * @param {string} options.container The Docker container to run the command on.
- * @param {string} options.command The command to run.
- * @param {WPConfig} options.config The wp-env configuration.
- * @param {Object} options.spinner A CLI spinner which indicates progress.
+ * @param {WPConfig} config The wp-env configuration.
+ * @param {string} container The Docker container to run the command on.
+ * @param {string} command The command to run.
+ * @param {string} envCwd The working directory for the command to be executed from.
+ * @param {Object} spinner A CLI spinner which indicates progress.
*/
-function spawnCommandDirectly( { container, command, config, spinner } ) {
+function spawnCommandDirectly( config, container, command, envCwd, spinner ) {
+ // We need to pass absolute paths to the container.
+ envCwd = path.resolve( '/var/www/html', envCwd );
+
const composeCommand = [
'-f',
config.dockerComposeConfigPath,
'run',
+ '-w',
+ envCwd,
'--rm',
container,
...command.split( ' ' ), // The command will fail if passed as a complete string.