@wordpress/env 5.16.0 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +189 -120
- package/lib/build-docker-compose-config.js +67 -96
- package/lib/cache.js +1 -0
- package/lib/cli.js +23 -3
- package/lib/commands/clean.js +14 -1
- package/lib/commands/destroy.js +12 -37
- package/lib/commands/index.js +1 -0
- package/lib/commands/install-path.js +1 -0
- package/lib/commands/logs.js +1 -0
- package/lib/commands/run.js +79 -15
- package/lib/commands/start.js +32 -10
- package/lib/commands/stop.js +1 -0
- package/lib/config/add-or-replace-port.js +41 -0
- package/lib/config/db-env.js +1 -0
- package/lib/config/detect-directory-type.js +1 -1
- package/lib/config/get-cache-directory.js +39 -0
- package/lib/config/get-config-from-environment-vars.js +86 -0
- package/lib/config/index.js +7 -5
- package/lib/config/load-config.js +92 -0
- package/lib/config/merge-configs.js +104 -0
- package/lib/config/parse-config.js +418 -157
- package/lib/config/parse-source-string.js +164 -0
- package/lib/config/post-process-config.js +202 -0
- package/lib/config/read-raw-config-file.js +7 -33
- package/lib/config/test/__snapshots__/config-integration.js.snap +271 -0
- package/lib/config/test/add-or-replace-port.js +81 -0
- package/lib/config/test/config-integration.js +143 -0
- package/lib/config/test/get-cache-directory.js +57 -0
- package/lib/config/test/merge-configs.js +111 -0
- package/lib/config/test/parse-config.js +342 -0
- package/lib/config/test/parse-source-string.js +154 -0
- package/lib/config/test/post-process-config.js +295 -0
- package/lib/config/test/read-raw-config-file.js +19 -63
- package/lib/config/test/validate-config.js +305 -0
- package/lib/config/validate-config.js +103 -40
- package/lib/env.js +2 -0
- package/lib/execute-after-setup.js +51 -0
- package/lib/get-host-user.js +31 -0
- package/lib/init-config.js +181 -63
- package/lib/md5.js +1 -0
- package/lib/parse-xdebug-mode.js +1 -0
- package/lib/retry.js +1 -0
- package/lib/test/__snapshots__/md5.js.snap +9 -0
- package/lib/test/build-docker-compose-config.js +134 -0
- package/lib/test/cache.js +154 -0
- package/lib/test/cli.js +149 -0
- package/lib/test/execute-after-setup.js +66 -0
- package/lib/test/md5.js +35 -0
- package/lib/test/parse-xdebug-mode.js +41 -0
- package/lib/wordpress.js +5 -33
- package/package.json +2 -2
- package/lib/config/config.js +0 -357
- package/lib/config/test/__snapshots__/config.js.snap +0 -83
- package/lib/config/test/config.js +0 -1203
|
@@ -10,25 +10,28 @@ const path = require( 'path' );
|
|
|
10
10
|
*/
|
|
11
11
|
const { hasSameCoreSource } = require( './wordpress' );
|
|
12
12
|
const { dbEnv } = require( './config' );
|
|
13
|
+
const getHostUser = require( './get-host-user' );
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* @typedef {import('./config').WPConfig} WPConfig
|
|
16
|
-
* @typedef {import('./config').
|
|
17
|
+
* @typedef {import('./config').WPEnvironmentConfig} WPEnvironmentConfig
|
|
17
18
|
*/
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* Gets the volume mounts for an individual service.
|
|
21
22
|
*
|
|
22
|
-
* @param {string}
|
|
23
|
-
* @param {
|
|
24
|
-
* @param {string}
|
|
25
|
-
*
|
|
23
|
+
* @param {string} workDirectoryPath The working directory for wp-env.
|
|
24
|
+
* @param {WPEnvironmentConfig} config The service config to get the mounts from.
|
|
25
|
+
* @param {string} hostUsername The username of the host running wp-env.
|
|
26
|
+
* @param {string} wordpressDefault The default internal path for the WordPress
|
|
27
|
+
* source code (such as tests-wordpress).
|
|
26
28
|
*
|
|
27
29
|
* @return {string[]} An array of volumes to mount in string format.
|
|
28
30
|
*/
|
|
29
31
|
function getMounts(
|
|
30
32
|
workDirectoryPath,
|
|
31
33
|
config,
|
|
34
|
+
hostUsername,
|
|
32
35
|
wordpressDefault = 'wordpress'
|
|
33
36
|
) {
|
|
34
37
|
// Top-level WordPress directory mounts (like wp-content/themes)
|
|
@@ -46,9 +49,10 @@ function getMounts(
|
|
|
46
49
|
`${ source.path }:/var/www/html/wp-content/themes/${ source.basename }`
|
|
47
50
|
);
|
|
48
51
|
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
+
const userHomeMount =
|
|
53
|
+
wordpressDefault === 'wordpress'
|
|
54
|
+
? `user-home:/home/${ hostUsername }`
|
|
55
|
+
: `tests-user-home:/home/${ hostUsername }`;
|
|
52
56
|
|
|
53
57
|
const corePHPUnitMount = `${ path.join(
|
|
54
58
|
workDirectoryPath,
|
|
@@ -59,10 +63,15 @@ function getMounts(
|
|
|
59
63
|
'phpunit'
|
|
60
64
|
) }:/wordpress-phpunit`;
|
|
61
65
|
|
|
66
|
+
const coreMount = `${
|
|
67
|
+
config.coreSource ? config.coreSource.path : wordpressDefault
|
|
68
|
+
}:/var/www/html`;
|
|
69
|
+
|
|
62
70
|
return [
|
|
63
71
|
...new Set( [
|
|
64
|
-
coreMount,
|
|
72
|
+
coreMount, // Must be first because of some operations later that expect it to be!
|
|
65
73
|
corePHPUnitMount,
|
|
74
|
+
userHomeMount,
|
|
66
75
|
...directoryMounts,
|
|
67
76
|
...pluginMounts,
|
|
68
77
|
...themeMounts,
|
|
@@ -79,16 +88,32 @@ function getMounts(
|
|
|
79
88
|
* @return {Object} A docker-compose config object, ready to serialize into YAML.
|
|
80
89
|
*/
|
|
81
90
|
module.exports = function buildDockerComposeConfig( config ) {
|
|
91
|
+
// Since we are mounting files from the host operating system
|
|
92
|
+
// we want to create the host user in some of our containers.
|
|
93
|
+
// This ensures ownership parity and lets us access files
|
|
94
|
+
// and folders between the containers and the host.
|
|
95
|
+
const hostUser = getHostUser();
|
|
96
|
+
|
|
82
97
|
const developmentMounts = getMounts(
|
|
83
98
|
config.workDirectoryPath,
|
|
84
|
-
config.env.development
|
|
99
|
+
config.env.development,
|
|
100
|
+
hostUser.name
|
|
85
101
|
);
|
|
86
102
|
const testsMounts = getMounts(
|
|
87
103
|
config.workDirectoryPath,
|
|
88
104
|
config.env.tests,
|
|
105
|
+
hostUser.name,
|
|
89
106
|
'tests-wordpress'
|
|
90
107
|
);
|
|
91
108
|
|
|
109
|
+
// We use a custom Dockerfile in order to make sure that
|
|
110
|
+
// the current host user exists inside the container.
|
|
111
|
+
const imageBuildArgs = {
|
|
112
|
+
HOST_USERNAME: hostUser.name,
|
|
113
|
+
HOST_UID: hostUser.uid,
|
|
114
|
+
HOST_GID: hostUser.gid,
|
|
115
|
+
};
|
|
116
|
+
|
|
92
117
|
// When both tests and development reference the same WP source, we need to
|
|
93
118
|
// ensure that tests pulls from a copy of the files so that it maintains
|
|
94
119
|
// a separate DB and config. Additionally, if the source type is local we
|
|
@@ -143,64 +168,6 @@ module.exports = function buildDockerComposeConfig( config ) {
|
|
|
143
168
|
const developmentPorts = `\${WP_ENV_PORT:-${ config.env.development.port }}:80`;
|
|
144
169
|
const testsPorts = `\${WP_ENV_TESTS_PORT:-${ config.env.tests.port }}:80`;
|
|
145
170
|
|
|
146
|
-
// Set the WordPress, WP-CLI, PHPUnit PHP version if defined.
|
|
147
|
-
const developmentPhpVersion = config.env.development.phpVersion
|
|
148
|
-
? config.env.development.phpVersion
|
|
149
|
-
: '';
|
|
150
|
-
const testsPhpVersion = config.env.tests.phpVersion
|
|
151
|
-
? config.env.tests.phpVersion
|
|
152
|
-
: '';
|
|
153
|
-
|
|
154
|
-
// Set the WordPress images with the PHP version tag.
|
|
155
|
-
const developmentWpImage = `wordpress${
|
|
156
|
-
developmentPhpVersion ? ':php' + developmentPhpVersion : ''
|
|
157
|
-
}`;
|
|
158
|
-
const testsWpImage = `wordpress${
|
|
159
|
-
testsPhpVersion ? ':php' + testsPhpVersion : ''
|
|
160
|
-
}`;
|
|
161
|
-
// Set the WordPress CLI images with the PHP version tag.
|
|
162
|
-
const developmentWpCliImage = `wordpress:cli${
|
|
163
|
-
! developmentPhpVersion || developmentPhpVersion.length === 0
|
|
164
|
-
? ''
|
|
165
|
-
: '-php' + developmentPhpVersion
|
|
166
|
-
}`;
|
|
167
|
-
const testsWpCliImage = `wordpress:cli${
|
|
168
|
-
! testsPhpVersion || testsPhpVersion.length === 0
|
|
169
|
-
? ''
|
|
170
|
-
: '-php' + testsPhpVersion
|
|
171
|
-
}`;
|
|
172
|
-
|
|
173
|
-
// Defaults are to use the most recent version of PHPUnit that provides
|
|
174
|
-
// support for the specified version of PHP.
|
|
175
|
-
// PHP Unit is assumed to be for Tests so use the testsPhpVersion.
|
|
176
|
-
let phpunitTag = 'latest';
|
|
177
|
-
const phpunitPhpVersion = '-php-' + testsPhpVersion + '-fpm';
|
|
178
|
-
if ( testsPhpVersion === '5.6' ) {
|
|
179
|
-
phpunitTag = '5' + phpunitPhpVersion;
|
|
180
|
-
} else if ( testsPhpVersion === '7.0' ) {
|
|
181
|
-
phpunitTag = '6' + phpunitPhpVersion;
|
|
182
|
-
} else if ( testsPhpVersion === '7.1' ) {
|
|
183
|
-
phpunitTag = '7' + phpunitPhpVersion;
|
|
184
|
-
} else if ( testsPhpVersion === '7.2' ) {
|
|
185
|
-
phpunitTag = '8' + phpunitPhpVersion;
|
|
186
|
-
} else if (
|
|
187
|
-
[ '7.3', '7.4', '8.0', '8.1', '8.2' ].indexOf( testsPhpVersion ) >= 0
|
|
188
|
-
) {
|
|
189
|
-
phpunitTag = '9' + phpunitPhpVersion;
|
|
190
|
-
}
|
|
191
|
-
const phpunitImage = `wordpressdevelop/phpunit:${ phpunitTag }`;
|
|
192
|
-
|
|
193
|
-
// The www-data user in wordpress:cli has a different UID (82) to the
|
|
194
|
-
// www-data user in wordpress (33). Ensure we use the wordpress www-data
|
|
195
|
-
// user for CLI commands.
|
|
196
|
-
// https://github.com/docker-library/wordpress/issues/256
|
|
197
|
-
const cliUser = '33:33';
|
|
198
|
-
|
|
199
|
-
// If the user mounted their own uploads folder, we should not override it in the phpunit service.
|
|
200
|
-
const isMappingTestUploads = testsMounts.some( ( mount ) =>
|
|
201
|
-
mount.endsWith( ':/var/www/html/wp-content/uploads' )
|
|
202
|
-
);
|
|
203
|
-
|
|
204
171
|
return {
|
|
205
172
|
version: '3.7',
|
|
206
173
|
services: {
|
|
@@ -227,69 +194,72 @@ module.exports = function buildDockerComposeConfig( config ) {
|
|
|
227
194
|
volumes: [ 'mysql-test:/var/lib/mysql' ],
|
|
228
195
|
},
|
|
229
196
|
wordpress: {
|
|
230
|
-
build: '.',
|
|
231
197
|
depends_on: [ 'mysql' ],
|
|
232
|
-
|
|
198
|
+
build: {
|
|
199
|
+
context: '.',
|
|
200
|
+
dockerfile: 'WordPress.Dockerfile',
|
|
201
|
+
args: imageBuildArgs,
|
|
202
|
+
},
|
|
233
203
|
ports: [ developmentPorts ],
|
|
234
204
|
environment: {
|
|
205
|
+
APACHE_RUN_USER: '#' + hostUser.uid,
|
|
206
|
+
APACHE_RUN_GROUP: '#' + hostUser.gid,
|
|
235
207
|
...dbEnv.credentials,
|
|
236
208
|
...dbEnv.development,
|
|
237
209
|
WP_TESTS_DIR: '/wordpress-phpunit',
|
|
238
210
|
},
|
|
239
211
|
volumes: developmentMounts,
|
|
212
|
+
extra_hosts: [ 'host.docker.internal:host-gateway' ],
|
|
240
213
|
},
|
|
241
214
|
'tests-wordpress': {
|
|
242
215
|
depends_on: [ 'tests-mysql' ],
|
|
243
|
-
|
|
216
|
+
build: {
|
|
217
|
+
context: '.',
|
|
218
|
+
dockerfile: 'Tests-WordPress.Dockerfile',
|
|
219
|
+
args: imageBuildArgs,
|
|
220
|
+
},
|
|
244
221
|
ports: [ testsPorts ],
|
|
245
222
|
environment: {
|
|
223
|
+
APACHE_RUN_USER: '#' + hostUser.uid,
|
|
224
|
+
APACHE_RUN_GROUP: '#' + hostUser.gid,
|
|
246
225
|
...dbEnv.credentials,
|
|
247
226
|
...dbEnv.tests,
|
|
248
227
|
WP_TESTS_DIR: '/wordpress-phpunit',
|
|
249
228
|
},
|
|
250
229
|
volumes: testsMounts,
|
|
230
|
+
extra_hosts: [ 'host.docker.internal:host-gateway' ],
|
|
251
231
|
},
|
|
252
232
|
cli: {
|
|
253
233
|
depends_on: [ 'wordpress' ],
|
|
254
|
-
|
|
234
|
+
build: {
|
|
235
|
+
context: '.',
|
|
236
|
+
dockerfile: 'CLI.Dockerfile',
|
|
237
|
+
args: imageBuildArgs,
|
|
238
|
+
},
|
|
255
239
|
volumes: developmentMounts,
|
|
256
|
-
user:
|
|
240
|
+
user: hostUser.fullUser,
|
|
257
241
|
environment: {
|
|
258
242
|
...dbEnv.credentials,
|
|
259
243
|
...dbEnv.development,
|
|
260
244
|
WP_TESTS_DIR: '/wordpress-phpunit',
|
|
261
245
|
},
|
|
246
|
+
extra_hosts: [ 'host.docker.internal:host-gateway' ],
|
|
262
247
|
},
|
|
263
248
|
'tests-cli': {
|
|
264
249
|
depends_on: [ 'tests-wordpress' ],
|
|
265
|
-
|
|
250
|
+
build: {
|
|
251
|
+
context: '.',
|
|
252
|
+
dockerfile: 'Tests-CLI.Dockerfile',
|
|
253
|
+
args: imageBuildArgs,
|
|
254
|
+
},
|
|
266
255
|
volumes: testsMounts,
|
|
267
|
-
user:
|
|
256
|
+
user: hostUser.fullUser,
|
|
268
257
|
environment: {
|
|
269
258
|
...dbEnv.credentials,
|
|
270
259
|
...dbEnv.tests,
|
|
271
260
|
WP_TESTS_DIR: '/wordpress-phpunit',
|
|
272
261
|
},
|
|
273
|
-
|
|
274
|
-
composer: {
|
|
275
|
-
image: 'composer',
|
|
276
|
-
volumes: [ `${ config.configDirectoryPath }:/app` ],
|
|
277
|
-
},
|
|
278
|
-
phpunit: {
|
|
279
|
-
image: phpunitImage,
|
|
280
|
-
depends_on: [ 'tests-wordpress' ],
|
|
281
|
-
volumes: [
|
|
282
|
-
...testsMounts,
|
|
283
|
-
...( ! isMappingTestUploads
|
|
284
|
-
? [ 'phpunit-uploads:/var/www/html/wp-content/uploads' ]
|
|
285
|
-
: [] ),
|
|
286
|
-
],
|
|
287
|
-
environment: {
|
|
288
|
-
LOCAL_DIR: 'html',
|
|
289
|
-
WP_TESTS_DIR: '/wordpress-phpunit',
|
|
290
|
-
...dbEnv.credentials,
|
|
291
|
-
...dbEnv.tests,
|
|
292
|
-
},
|
|
262
|
+
extra_hosts: [ 'host.docker.internal:host-gateway' ],
|
|
293
263
|
},
|
|
294
264
|
},
|
|
295
265
|
volumes: {
|
|
@@ -297,7 +267,8 @@ module.exports = function buildDockerComposeConfig( config ) {
|
|
|
297
267
|
...( ! config.env.tests.coreSource && { 'tests-wordpress': {} } ),
|
|
298
268
|
mysql: {},
|
|
299
269
|
'mysql-test': {},
|
|
300
|
-
'
|
|
270
|
+
'user-home': {},
|
|
271
|
+
'tests-user-home': {},
|
|
301
272
|
},
|
|
302
273
|
};
|
|
303
274
|
};
|
package/lib/cache.js
CHANGED
package/lib/cli.js
CHANGED
|
@@ -39,8 +39,11 @@ const withSpinner =
|
|
|
39
39
|
process.exit( 0 );
|
|
40
40
|
},
|
|
41
41
|
( error ) => {
|
|
42
|
-
if (
|
|
43
|
-
|
|
42
|
+
if (
|
|
43
|
+
error instanceof env.ValidationError ||
|
|
44
|
+
error instanceof env.AfterSetupError
|
|
45
|
+
) {
|
|
46
|
+
// Error is a configuration error. That means the user did something wrong.
|
|
44
47
|
spinner.fail( error.message );
|
|
45
48
|
process.exit( 1 );
|
|
46
49
|
} else if (
|
|
@@ -124,6 +127,11 @@ module.exports = function cli() {
|
|
|
124
127
|
coerce: parseXdebugMode,
|
|
125
128
|
type: 'string',
|
|
126
129
|
} );
|
|
130
|
+
args.option( 'scripts', {
|
|
131
|
+
type: 'boolean',
|
|
132
|
+
describe: 'Execute any configured lifecycle scripts.',
|
|
133
|
+
default: true,
|
|
134
|
+
} );
|
|
127
135
|
},
|
|
128
136
|
withSpinner( env.start )
|
|
129
137
|
);
|
|
@@ -145,6 +153,11 @@ module.exports = function cli() {
|
|
|
145
153
|
choices: [ 'all', 'development', 'tests' ],
|
|
146
154
|
default: 'tests',
|
|
147
155
|
} );
|
|
156
|
+
args.option( 'scripts', {
|
|
157
|
+
type: 'boolean',
|
|
158
|
+
describe: 'Execute any configured lifecycle scripts.',
|
|
159
|
+
default: true,
|
|
160
|
+
} );
|
|
148
161
|
},
|
|
149
162
|
withSpinner( env.clean )
|
|
150
163
|
);
|
|
@@ -174,6 +187,13 @@ module.exports = function cli() {
|
|
|
174
187
|
'run <container> [command..]',
|
|
175
188
|
'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.',
|
|
176
189
|
( args ) => {
|
|
190
|
+
args.option( 'env-cwd', {
|
|
191
|
+
type: 'string',
|
|
192
|
+
requiresArg: true,
|
|
193
|
+
default: '.',
|
|
194
|
+
describe:
|
|
195
|
+
"The command's working directory inside of the container. Paths without a leading slash are relative to the WordPress root.",
|
|
196
|
+
} );
|
|
177
197
|
args.positional( 'container', {
|
|
178
198
|
type: 'string',
|
|
179
199
|
describe: 'The container to run the command on.',
|
|
@@ -208,7 +228,7 @@ module.exports = function cli() {
|
|
|
208
228
|
);
|
|
209
229
|
yargs.command(
|
|
210
230
|
'install-path',
|
|
211
|
-
'Get the path where environment files are
|
|
231
|
+
'Get the path where all of the environment files are stored. This includes the Docker files, WordPress, PHPUnit files, and any sources that were downloaded.',
|
|
212
232
|
() => {},
|
|
213
233
|
withSpinner( env.installPath )
|
|
214
234
|
);
|
package/lib/commands/clean.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
'use strict';
|
|
1
2
|
/**
|
|
2
3
|
* External dependencies
|
|
3
4
|
*/
|
|
@@ -8,6 +9,7 @@ const dockerCompose = require( 'docker-compose' );
|
|
|
8
9
|
*/
|
|
9
10
|
const initConfig = require( '../init-config' );
|
|
10
11
|
const { configureWordPress, resetDatabase } = require( '../wordpress' );
|
|
12
|
+
const { executeAfterSetup } = require( '../execute-after-setup' );
|
|
11
13
|
|
|
12
14
|
/**
|
|
13
15
|
* @typedef {import('../wordpress').WPEnvironment} WPEnvironment
|
|
@@ -20,9 +22,15 @@ const { configureWordPress, resetDatabase } = require( '../wordpress' );
|
|
|
20
22
|
* @param {Object} options
|
|
21
23
|
* @param {WPEnvironmentSelection} options.environment The environment to clean. Either 'development', 'tests', or 'all'.
|
|
22
24
|
* @param {Object} options.spinner A CLI spinner which indicates progress.
|
|
25
|
+
* @param {boolean} options.scripts Indicates whether or not lifecycle scripts should be executed.
|
|
23
26
|
* @param {boolean} options.debug True if debug mode is enabled.
|
|
24
27
|
*/
|
|
25
|
-
module.exports = async function clean( {
|
|
28
|
+
module.exports = async function clean( {
|
|
29
|
+
environment,
|
|
30
|
+
spinner,
|
|
31
|
+
scripts,
|
|
32
|
+
debug,
|
|
33
|
+
} ) {
|
|
26
34
|
const config = await initConfig( { spinner, debug } );
|
|
27
35
|
|
|
28
36
|
const description = `${ environment } environment${
|
|
@@ -57,5 +65,10 @@ module.exports = async function clean( { environment, spinner, debug } ) {
|
|
|
57
65
|
|
|
58
66
|
await Promise.all( tasks );
|
|
59
67
|
|
|
68
|
+
// Execute any configured command that should run after the environment has finished being set up.
|
|
69
|
+
if ( scripts ) {
|
|
70
|
+
executeAfterSetup( config, spinner );
|
|
71
|
+
}
|
|
72
|
+
|
|
60
73
|
spinner.text = `Cleaned ${ description }.`;
|
|
61
74
|
};
|
package/lib/commands/destroy.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
'use strict';
|
|
1
2
|
/**
|
|
2
3
|
* External dependencies
|
|
3
4
|
*/
|
|
@@ -11,12 +12,11 @@ const inquirer = require( 'inquirer' );
|
|
|
11
12
|
* Promisified dependencies
|
|
12
13
|
*/
|
|
13
14
|
const rimraf = util.promisify( require( 'rimraf' ) );
|
|
14
|
-
const exec = util.promisify( require( 'child_process' ).exec );
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Internal dependencies
|
|
18
18
|
*/
|
|
19
|
-
const {
|
|
19
|
+
const { loadConfig } = require( '../config' );
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Destroy the development server.
|
|
@@ -26,9 +26,8 @@ const { readConfig } = require( '../../lib/config' );
|
|
|
26
26
|
* @param {boolean} options.debug True if debug mode is enabled.
|
|
27
27
|
*/
|
|
28
28
|
module.exports = async function destroy( { spinner, debug } ) {
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
configPath
|
|
29
|
+
const { dockerComposeConfigPath, workDirectoryPath } = await loadConfig(
|
|
30
|
+
path.resolve( '.' )
|
|
32
31
|
);
|
|
33
32
|
|
|
34
33
|
try {
|
|
@@ -39,7 +38,7 @@ module.exports = async function destroy( { spinner, debug } ) {
|
|
|
39
38
|
}
|
|
40
39
|
|
|
41
40
|
spinner.info(
|
|
42
|
-
'WARNING! This will remove Docker containers, volumes, and
|
|
41
|
+
'WARNING! This will remove Docker containers, volumes, networks, and images associated with the WordPress instance.'
|
|
43
42
|
);
|
|
44
43
|
|
|
45
44
|
const { yesDelete } = await inquirer.prompt( [
|
|
@@ -58,44 +57,20 @@ module.exports = async function destroy( { spinner, debug } ) {
|
|
|
58
57
|
return;
|
|
59
58
|
}
|
|
60
59
|
|
|
61
|
-
spinner.text = 'Removing
|
|
60
|
+
spinner.text = 'Removing docker images, volumes, and networks.';
|
|
62
61
|
|
|
63
|
-
await dockerCompose.
|
|
62
|
+
await dockerCompose.down( {
|
|
64
63
|
config: dockerComposeConfigPath,
|
|
65
|
-
commandOptions: [ '--
|
|
64
|
+
commandOptions: [ '--volumes', '--remove-orphans', '--rmi', 'all' ],
|
|
66
65
|
log: debug,
|
|
67
66
|
} );
|
|
68
67
|
|
|
69
|
-
const directoryHash = path.basename( workDirectoryPath );
|
|
70
|
-
|
|
71
|
-
spinner.text = 'Removing docker volumes.';
|
|
72
|
-
await removeDockerItems( 'volume', directoryHash );
|
|
73
|
-
|
|
74
|
-
spinner.text = 'Removing docker networks.';
|
|
75
|
-
await removeDockerItems( 'network', directoryHash );
|
|
76
|
-
|
|
77
68
|
spinner.text = 'Removing local files.';
|
|
78
|
-
|
|
69
|
+
// Note: there is a race condition where docker compose actually hasn't finished
|
|
70
|
+
// by this point, which causes rimraf to fail. We need to wait at least 2.5-5s,
|
|
71
|
+
// but using 10s in case it's dependant on the machine.
|
|
72
|
+
await new Promise( ( resolve ) => setTimeout( resolve, 10000 ) );
|
|
79
73
|
await rimraf( workDirectoryPath );
|
|
80
74
|
|
|
81
75
|
spinner.text = 'Removed WordPress environment.';
|
|
82
76
|
};
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Removes docker items, like networks or volumes, matching the given name.
|
|
86
|
-
*
|
|
87
|
-
* @param {string} itemType The item type, like "network" or "volume"
|
|
88
|
-
* @param {string} name Remove items whose name match this string.
|
|
89
|
-
*/
|
|
90
|
-
async function removeDockerItems( itemType, name ) {
|
|
91
|
-
const { stdout: items } = await exec(
|
|
92
|
-
`docker ${ itemType } ls -q --filter name=${ name }`
|
|
93
|
-
);
|
|
94
|
-
if ( items ) {
|
|
95
|
-
await exec(
|
|
96
|
-
`docker ${ itemType } rm ${ items
|
|
97
|
-
.split( '\n' ) // TODO: use os.EOL?
|
|
98
|
-
.join( ' ' ) }`
|
|
99
|
-
);
|
|
100
|
-
}
|
|
101
|
-
}
|
package/lib/commands/index.js
CHANGED
package/lib/commands/logs.js
CHANGED
package/lib/commands/run.js
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
|
+
'use strict';
|
|
1
2
|
/**
|
|
2
3
|
* External dependencies
|
|
3
4
|
*/
|
|
4
5
|
const { spawn } = require( 'child_process' );
|
|
6
|
+
const path = require( 'path' );
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
9
|
* Internal dependencies
|
|
8
10
|
*/
|
|
9
11
|
const initConfig = require( '../init-config' );
|
|
12
|
+
const getHostUser = require( '../get-host-user' );
|
|
13
|
+
const { ValidationError } = require( '../config' );
|
|
10
14
|
|
|
11
15
|
/**
|
|
12
16
|
* @typedef {import('../config').WPConfig} WPConfig
|
|
@@ -18,10 +22,19 @@ const initConfig = require( '../init-config' );
|
|
|
18
22
|
* @param {Object} options
|
|
19
23
|
* @param {string} options.container The Docker container to run the command on.
|
|
20
24
|
* @param {string[]} options.command The command to run.
|
|
25
|
+
* @param {string} options.envCwd The working directory for the command to be executed from.
|
|
21
26
|
* @param {Object} options.spinner A CLI spinner which indicates progress.
|
|
22
27
|
* @param {boolean} options.debug True if debug mode is enabled.
|
|
23
28
|
*/
|
|
24
|
-
module.exports = async function run( {
|
|
29
|
+
module.exports = async function run( {
|
|
30
|
+
container,
|
|
31
|
+
command,
|
|
32
|
+
envCwd,
|
|
33
|
+
spinner,
|
|
34
|
+
debug,
|
|
35
|
+
} ) {
|
|
36
|
+
validateContainerExistence( container );
|
|
37
|
+
|
|
25
38
|
const config = await initConfig( { spinner, debug } );
|
|
26
39
|
|
|
27
40
|
command = command.join( ' ' );
|
|
@@ -29,31 +42,82 @@ module.exports = async function run( { container, command, spinner, debug } ) {
|
|
|
29
42
|
// Shows a contextual tip for the given command.
|
|
30
43
|
showCommandTips( command, container, spinner );
|
|
31
44
|
|
|
32
|
-
await spawnCommandDirectly(
|
|
33
|
-
container,
|
|
34
|
-
command,
|
|
35
|
-
spinner,
|
|
36
|
-
config,
|
|
37
|
-
} );
|
|
45
|
+
await spawnCommandDirectly( config, container, command, envCwd, spinner );
|
|
38
46
|
|
|
39
47
|
spinner.text = `Ran \`${ command }\` in '${ container }'.`;
|
|
40
48
|
};
|
|
41
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Validates the container option and throws if it is invalid.
|
|
52
|
+
*
|
|
53
|
+
* @param {string} container The Docker container to run the command on.
|
|
54
|
+
*/
|
|
55
|
+
function validateContainerExistence( container ) {
|
|
56
|
+
// Give better errors for containers that we have removed.
|
|
57
|
+
if ( container === 'phpunit' ) {
|
|
58
|
+
throw new ValidationError(
|
|
59
|
+
"The 'phpunit' container has been removed. Please use 'wp-env run tests-cli --env-cwd=wp-content/path/to/plugin phpunit' instead."
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
if ( container === 'composer' ) {
|
|
63
|
+
throw new ValidationError(
|
|
64
|
+
"The 'composer' container has been removed. Please use 'wp-env run cli --env-cwd=wp-content/path/to/plugin composer' instead."
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Provide better error output than Docker's "service does not exist" messaging.
|
|
69
|
+
const validContainers = [
|
|
70
|
+
'mysql',
|
|
71
|
+
'tests-mysql',
|
|
72
|
+
'wordpress',
|
|
73
|
+
'tests-wordpress',
|
|
74
|
+
'cli',
|
|
75
|
+
'tests-cli',
|
|
76
|
+
];
|
|
77
|
+
if ( ! validContainers.includes( container ) ) {
|
|
78
|
+
throw new ValidationError(
|
|
79
|
+
`The '${ container }' container does not exist. Valid selections are: ${ validContainers.join(
|
|
80
|
+
', '
|
|
81
|
+
) }`
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
42
86
|
/**
|
|
43
87
|
* Runs an arbitrary command on the given Docker container.
|
|
44
88
|
*
|
|
45
|
-
* @param {
|
|
46
|
-
* @param {string}
|
|
47
|
-
* @param {string}
|
|
48
|
-
* @param {
|
|
49
|
-
* @param {Object}
|
|
89
|
+
* @param {WPConfig} config The wp-env configuration.
|
|
90
|
+
* @param {string} container The Docker container to run the command on.
|
|
91
|
+
* @param {string} command The command to run.
|
|
92
|
+
* @param {string} envCwd The working directory for the command to be executed from.
|
|
93
|
+
* @param {Object} spinner A CLI spinner which indicates progress.
|
|
50
94
|
*/
|
|
51
|
-
function spawnCommandDirectly(
|
|
95
|
+
function spawnCommandDirectly( config, container, command, envCwd, spinner ) {
|
|
96
|
+
// Both the `wordpress` and `tests-wordpress` containers have the host's
|
|
97
|
+
// user so that they can maintain ownership parity with the host OS.
|
|
98
|
+
// We should run any commands as that user so that they are able
|
|
99
|
+
// to interact with the files mounted from the host.
|
|
100
|
+
const hostUser = getHostUser();
|
|
101
|
+
|
|
102
|
+
// We need to pass absolute paths to the container.
|
|
103
|
+
envCwd = path.resolve(
|
|
104
|
+
// Not all containers have the same starting working directory.
|
|
105
|
+
container === 'mysql' || container === 'tests-mysql'
|
|
106
|
+
? '/'
|
|
107
|
+
: '/var/www/html',
|
|
108
|
+
envCwd
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
const isTTY = process.stdout.isTTY;
|
|
52
112
|
const composeCommand = [
|
|
53
113
|
'-f',
|
|
54
114
|
config.dockerComposeConfigPath,
|
|
55
|
-
'
|
|
56
|
-
'
|
|
115
|
+
'exec',
|
|
116
|
+
! isTTY ? '-T' : '',
|
|
117
|
+
'-w',
|
|
118
|
+
envCwd,
|
|
119
|
+
'--user',
|
|
120
|
+
hostUser.fullUser,
|
|
57
121
|
container,
|
|
58
122
|
...command.split( ' ' ), // The command will fail if passed as a complete string.
|
|
59
123
|
];
|