Skip to content

Commit 6a0a5f0

Browse files
authored
Env: Support running arbitrary commands and use it for linting and server registered fixtures. (WordPress#18986)
* Env: Support running arbitrary commands and use it for linting and server registered fixtures. * Travis: Provide NodeGit with correct C bindings. * Env: Fix tests. * Travis: Add clarifying comments to C lib includes.
1 parent 8401390 commit 6a0a5f0

File tree

7 files changed

+136
-19
lines changed

7 files changed

+136
-19
lines changed

.travis.yml

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
dist: trusty
2-
31
language: generic
42

53
services:
@@ -32,6 +30,14 @@ env:
3230
- INSTALL_COMPOSER: false
3331
- INSTALL_WORDPRESS: true
3432

33+
# Make sure NodeGit gets the correct C libs.
34+
addons:
35+
apt:
36+
sources:
37+
- ubuntu-toolchain-r-test
38+
packages:
39+
- libstdc++-4.9-dev
40+
3541
before_install:
3642
- nvm install --latest-npm
3743
- |

package.json

+4-3
Original file line numberDiff line numberDiff line change
@@ -176,13 +176,13 @@
176176
"dev:packages": "node ./bin/packages/watch.js",
177177
"docs:build": "node ./docs/tool/index.js && node ./bin/update-readmes.js",
178178
"fixtures:clean": "rimraf \"packages/e2e-tests/fixtures/blocks/*.+(json|serialized.html)\"",
179-
"fixtures:server-registered": "wp-scripts env docker-run php ./bin/get-server-blocks.php > test/integration/full-content/server-registered.json",
179+
"fixtures:server-registered": "npm run wp-env run tests-wordpress-phpunit './bin/get-server-blocks.php > test/integration/full-content/server-registered.json'",
180180
"fixtures:generate": "npm run fixtures:server-registered && cross-env GENERATE_MISSING_FIXTURES=y npm run test-unit",
181181
"fixtures:regenerate": "npm run fixtures:clean && npm run fixtures:generate",
182182
"lint": "concurrently \"npm run lint-js\" \"npm run lint-pkg-json\" \"npm run lint-css\" \"npm run lint-types\"",
183183
"lint-js": "wp-scripts lint-js",
184184
"lint-js:fix": "npm run lint-js -- --fix",
185-
"lint-php": "wp-scripts env lint-php",
185+
"lint-php": "npm run wp-env run composer run-script lint",
186186
"lint-pkg-json": "wp-scripts lint-pkg-json . 'packages/*/package.json'",
187187
"lint-css": "wp-scripts lint-style '**/*.scss'",
188188
"lint-css:fix": "npm run lint-css -- --fix",
@@ -214,7 +214,8 @@
214214
"playground:build": "npm run storybook:build",
215215
"playground:dev": "echo \"Please use storybook:dev instead.\"",
216216
"preenv": "npm run check-engines",
217-
"env": "wp-scripts env"
217+
"env": "wp-scripts env",
218+
"wp-env": "packages/env/bin/wp-env"
218219
},
219220
"husky": {
220221
"hooks": {

packages/env/README.md

+22-11
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,18 @@ $ wp-env --help
1414
wp-env <command>
1515

1616
Commands:
17-
wp-env start [ref] Starts WordPress for development on port 8888
18-
(​http://localhost:8888​) (override with
19-
WP_ENV_PORT) and tests on port 8889
20-
(​http://localhost:8889​) (override with
21-
WP_ENV_TESTS_PORT). If the current working
22-
directory is a plugin and/or has e2e-tests with
23-
plugins and/or mu-plugins, they will be mounted
24-
appropriately.
25-
wp-env stop Stops running WordPress for development and tests
26-
and frees the ports.
27-
wp-env clean [environment] Cleans the WordPress databases.
17+
wp-env start [ref] Starts WordPress for development on port
18+
8888 (​http://localhost:8888​) and tests
19+
on port 8889 (​http://localhost:8889​). If
20+
the current working directory is a plugin
21+
and/or has e2e-tests with plugins and/or
22+
mu-plugins, they will be mounted
23+
appropiately.
24+
wp-env stop Stops running WordPress for development
25+
and tests and frees the ports.
26+
wp-env clean [environment] Cleans the WordPress databases.
27+
wp-env run <container> [command..] Runs an arbitrary command in one of the
28+
underlying Docker containers.
2829

2930
Options:
3031
--help Show help [boolean]
@@ -67,6 +68,16 @@ Positionals:
6768
[string] [choices: "all", "development", "tests"] [default: "tests"]
6869
```
6970
71+
### `$ wp-env run --help`
72+
73+
```sh
74+
wp-env run <container> [command..]
75+
Runs an arbitrary command in one of the underlying Docker containers.
76+
Positionals:
77+
container The container to run the command on. [string] [required]
78+
command The command to run. [array] [default: []]
79+
```
80+
7081
<br/><br/><p align="center"><img src="https://s.w.org/style/images/codeispoetry.png?1" alt="Code is Poetry." /></p>
7182
7283
## Additional Configuration and Running with Multiple Plugins/Themes

packages/env/lib/cli.js

+21-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,12 @@ const withSpinner = ( command ) => ( ...args ) => {
3333
) }ms)`
3434
);
3535
},
36-
( err ) => spinner.fail( err.message || err.err )
36+
( err ) => {
37+
spinner.fail( err.message || err.err );
38+
// eslint-disable-next-line no-console
39+
console.error( `\n\n${ err.out || err.err }\n\n` );
40+
process.exit( err.exitCode || 1 );
41+
}
3742
);
3843
};
3944

@@ -82,6 +87,21 @@ module.exports = function cli() {
8287
},
8388
withSpinner( env.clean )
8489
);
90+
yargs.command(
91+
'run <container> [command..]',
92+
'Runs an arbitrary command in one of the underlying Docker containers.',
93+
( args ) => {
94+
args.positional( 'container', {
95+
type: 'string',
96+
describe: 'The container to run the command on.',
97+
} );
98+
args.positional( 'command', {
99+
type: 'string',
100+
describe: 'The command to run.',
101+
} );
102+
},
103+
withSpinner( env.run )
104+
);
85105

86106
return yargs;
87107
};

packages/env/lib/create-docker-compose-config.js

+16-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ ${ dependencyMappings }
2020
const testsVolumes = `
2121
- ${ cwd }/../${ cwdName }-tests-wordpress/:/var/www/html/${ commonVolumes }`;
2222
return `version: '2.1'
23+
volumes:
24+
tests-wordpress-phpunit:
2325
services:
2426
mysql:
2527
environment:
@@ -57,5 +59,18 @@ services:
5759
- tests-wordpress
5860
image: wordpress:cli
5961
volumes:${ testsVolumes }
60-
`;
62+
tests-wordpress-phpunit:
63+
depends_on:
64+
- mysql
65+
environment:
66+
PHPUNIT_DB_HOST: mysql
67+
image: chriszarate/wordpress-phpunit
68+
volumes:
69+
- ${ cwd }/:/app/
70+
- tests-wordpress-phpunit/:/tmp/
71+
composer:
72+
image: composer
73+
volumes:
74+
- ${ cwd }/:/app/
75+
`;
6176
};

packages/env/lib/env.js

+36
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const cwdTestsPath = fs.existsSync( './packages' ) ? '/packages' : '';
2828
const dockerComposeOptions = {
2929
config: path.join( __dirname, 'docker-compose.yml' ),
3030
};
31+
const hasConfigFile = fs.existsSync( dockerComposeOptions.config );
3132

3233
// WP CLI Utils
3334
const wpCliRun = ( command, isTests = false ) =>
@@ -210,4 +211,39 @@ module.exports = {
210211
await dockerCompose.rm( dockerComposeOptions );
211212
spinner.text = `Cleaned ${ description }.`;
212213
},
214+
215+
async run( { container, command, spinner } ) {
216+
command = command.join( ' ' );
217+
spinner.text = `Running \`${ command }\` in "${ container }".`;
218+
219+
// Generate config file if we don't have one.
220+
if ( ! hasConfigFile ) {
221+
fs.writeFileSync(
222+
dockerComposeOptions.config,
223+
createDockerComposeConfig(
224+
cwdTestsPath,
225+
await detectContext(),
226+
await resolveDependencies()
227+
)
228+
);
229+
}
230+
231+
const result = await dockerCompose.run(
232+
container,
233+
command,
234+
dockerComposeOptions
235+
);
236+
if ( result.out ) {
237+
// eslint-disable-next-line no-console
238+
console.log( `\n\n${ result.out }\n\n` );
239+
} else if ( result.err ) {
240+
// eslint-disable-next-line no-console
241+
console.error( `\n\n${ result.err }\n\n` );
242+
throw result.err;
243+
}
244+
245+
// Remove dangling containers and finish.
246+
await dockerCompose.rm( dockerComposeOptions );
247+
spinner.text = `Ran \`${ command }\` in "${ container }".`;
248+
},
213249
};

packages/env/test/cli.js

+29-1
Original file line numberDiff line numberDiff line change
@@ -87,17 +87,45 @@ describe( 'env cli', () => {
8787
} );
8888

8989
it( 'handles failed commands with messages.', async () => {
90-
env.start.mockRejectedValueOnce( { message: 'failure message' } );
90+
/* eslint-disable no-console */
91+
env.start.mockRejectedValueOnce( {
92+
message: 'failure message',
93+
out: 'failure message',
94+
exitCode: 2,
95+
} );
96+
const consoleError = console.error;
97+
console.error = jest.fn();
98+
const processExit = process.exit;
99+
process.exit = jest.fn();
100+
91101
cli().parse( [ 'start' ] );
92102
const { spinner } = env.start.mock.calls[ 0 ][ 0 ];
93103
await env.start.mock.results[ 0 ].value.catch( () => {} );
104+
94105
expect( spinner.fail ).toHaveBeenCalledWith( 'failure message' );
106+
expect( console.error ).toHaveBeenCalledWith( '\n\nfailure message\n\n' );
107+
expect( process.exit ).toHaveBeenCalledWith( 2 );
108+
console.error = consoleError;
109+
process.exit = processExit;
110+
/* eslint-enable no-console */
95111
} );
96112
it( 'handles failed commands with errors.', async () => {
113+
/* eslint-disable no-console */
97114
env.start.mockRejectedValueOnce( { err: 'failure error' } );
115+
const consoleError = console.error;
116+
console.error = jest.fn();
117+
const processExit = process.exit;
118+
process.exit = jest.fn();
119+
98120
cli().parse( [ 'start' ] );
99121
const { spinner } = env.start.mock.calls[ 0 ][ 0 ];
100122
await env.start.mock.results[ 0 ].value.catch( () => {} );
123+
101124
expect( spinner.fail ).toHaveBeenCalledWith( 'failure error' );
125+
expect( console.error ).toHaveBeenCalledWith( '\n\nfailure error\n\n' );
126+
expect( process.exit ).toHaveBeenCalledWith( 1 );
127+
console.error = consoleError;
128+
process.exit = processExit;
129+
/* eslint-enable no-console */
102130
} );
103131
} );

0 commit comments

Comments
 (0)