@wordpress/env 10.39.0 → 11.0.1-next.v.20260206T143.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 +49 -13
- package/lib/cli.js +61 -9
- package/lib/commands/clean.js +10 -3
- package/lib/commands/cleanup.js +70 -0
- package/lib/commands/destroy.js +18 -13
- package/lib/commands/index.js +6 -2
- package/lib/commands/logs.js +3 -1
- package/lib/commands/reset.js +42 -0
- package/lib/commands/run.js +3 -1
- package/lib/commands/start.js +36 -1
- package/lib/commands/status.js +154 -0
- package/lib/commands/stop.js +3 -1
- package/lib/config/get-config-from-environment-vars.js +2 -5
- package/lib/config/parse-config.js +8 -0
- package/lib/config/test/__snapshots__/config-integration.js.snap +8 -0
- package/lib/config/test/parse-config.js +2 -0
- package/lib/runtime/docker/build-docker-compose-config.js +29 -2
- package/lib/runtime/docker/index.js +125 -25
- package/lib/runtime/docker/wordpress.js +0 -15
- package/lib/runtime/errors.js +11 -0
- package/lib/runtime/index.js +40 -18
- package/lib/runtime/playground/blueprint-builder.js +6 -14
- package/lib/runtime/playground/index.js +82 -4
- package/lib/test/build-docker-compose-config.js +83 -0
- package/lib/test/cli.js +47 -11
- package/package.json +2 -2
- package/lib/commands/install-path.js +0 -33
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/**
|
|
3
|
+
* External dependencies
|
|
4
|
+
*/
|
|
5
|
+
const path = require( 'path' );
|
|
6
|
+
const { existsSync } = require( 'fs' );
|
|
7
|
+
const chalk = require( 'chalk' );
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Internal dependencies
|
|
11
|
+
*/
|
|
12
|
+
const { loadConfig } = require( '../config' );
|
|
13
|
+
const { getRuntime, detectRuntime } = require( '../runtime' );
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Check if an environment has been initialized by looking for runtime-specific files.
|
|
17
|
+
*
|
|
18
|
+
* @param {Object} config The wp-env configuration object.
|
|
19
|
+
* @return {boolean} True if the environment has been initialized.
|
|
20
|
+
*/
|
|
21
|
+
function isEnvironmentInitialized( config ) {
|
|
22
|
+
// Check for Docker's docker-compose.yml
|
|
23
|
+
if ( existsSync( config.dockerComposeConfigPath ) ) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Check for Playground's blueprint file
|
|
28
|
+
const playgroundBlueprintPath = path.join(
|
|
29
|
+
config.workDirectoryPath,
|
|
30
|
+
'playground-blueprint.json'
|
|
31
|
+
);
|
|
32
|
+
if ( existsSync( playgroundBlueprintPath ) ) {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Outputs the status of the wp-env environment.
|
|
41
|
+
*
|
|
42
|
+
* @param {Object} options
|
|
43
|
+
* @param {Object} options.spinner A CLI spinner which indicates progress.
|
|
44
|
+
* @param {boolean} options.debug True if debug mode is enabled.
|
|
45
|
+
* @param {boolean} options.json True to output as JSON.
|
|
46
|
+
*/
|
|
47
|
+
module.exports = async function status( { spinner, debug, json } ) {
|
|
48
|
+
spinner.text = 'Getting environment status.';
|
|
49
|
+
|
|
50
|
+
const config = await loadConfig( path.resolve( '.' ) );
|
|
51
|
+
|
|
52
|
+
// Check if environment is initialized by looking for runtime-specific files.
|
|
53
|
+
// We check for these files specifically because the work directory may exist
|
|
54
|
+
// just from caching the WordPress version, but these files are only created
|
|
55
|
+
// when `wp-env start` is actually run.
|
|
56
|
+
if ( ! isEnvironmentInitialized( config ) ) {
|
|
57
|
+
spinner.stop();
|
|
58
|
+
if ( json ) {
|
|
59
|
+
console.log(
|
|
60
|
+
JSON.stringify( {
|
|
61
|
+
status: 'uninitialized',
|
|
62
|
+
installPath: config.workDirectoryPath,
|
|
63
|
+
configPath: config.configDirectoryPath,
|
|
64
|
+
} )
|
|
65
|
+
);
|
|
66
|
+
} else {
|
|
67
|
+
console.log( formatNotInitialized( config ) );
|
|
68
|
+
}
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Detect and get runtime.
|
|
73
|
+
const runtimeName = detectRuntime( config.workDirectoryPath );
|
|
74
|
+
const runtime = getRuntime( runtimeName );
|
|
75
|
+
|
|
76
|
+
// Get status from runtime.
|
|
77
|
+
const statusData = await runtime.getStatus( config, { spinner, debug } );
|
|
78
|
+
|
|
79
|
+
spinner.stop();
|
|
80
|
+
if ( json ) {
|
|
81
|
+
console.log( JSON.stringify( statusData ) );
|
|
82
|
+
} else {
|
|
83
|
+
console.log( formatStatus( statusData ) );
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Format status for human-readable output when not initialized.
|
|
89
|
+
*
|
|
90
|
+
* @param {Object} config The config object.
|
|
91
|
+
* @return {string} Formatted output.
|
|
92
|
+
*/
|
|
93
|
+
function formatNotInitialized( config ) {
|
|
94
|
+
const indent = ' - ';
|
|
95
|
+
return `
|
|
96
|
+
${ chalk.bold( 'status' ) }: ${ chalk.red( 'uninitialized' ) }
|
|
97
|
+
${ indent }install path: ${ chalk.dim( config.workDirectoryPath ) }
|
|
98
|
+
${ indent }config: ${ chalk.dim( config.configDirectoryPath ) }
|
|
99
|
+
|
|
100
|
+
${ chalk.dim( 'Run `wp-env start` to initialize the environment.' ) }
|
|
101
|
+
`;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Format status data for human-readable output.
|
|
106
|
+
*
|
|
107
|
+
* @param {Object} status The status object from runtime.
|
|
108
|
+
* @return {string} Formatted output.
|
|
109
|
+
*/
|
|
110
|
+
function formatStatus( status ) {
|
|
111
|
+
const statusColor = status.status === 'running' ? chalk.green : chalk.red;
|
|
112
|
+
const indent = ' - ';
|
|
113
|
+
|
|
114
|
+
let output = `
|
|
115
|
+
${ chalk.bold( 'status' ) }: ${ statusColor( status.status ) }
|
|
116
|
+
${ indent }runtime: ${ chalk.dim( status.runtime ) }
|
|
117
|
+
${ indent }install path: ${ chalk.dim( status.installPath ) }
|
|
118
|
+
${ indent }config: ${ chalk.dim( status.configPath ) }
|
|
119
|
+
`;
|
|
120
|
+
|
|
121
|
+
// Environment section.
|
|
122
|
+
output += `\n${ chalk.bold( 'environment' ) }:\n`;
|
|
123
|
+
if ( status.urls?.development ) {
|
|
124
|
+
output += `${ indent }url: ${ chalk.dim( status.urls.development ) }\n`;
|
|
125
|
+
}
|
|
126
|
+
output += `${ indent }multisite: ${ chalk.dim(
|
|
127
|
+
status.config?.multisite ? 'yes' : 'no'
|
|
128
|
+
) }\n`;
|
|
129
|
+
output += `${ indent }xdebug: ${ chalk.dim(
|
|
130
|
+
status.config?.xdebug || 'off'
|
|
131
|
+
) }\n`;
|
|
132
|
+
if ( status.ports?.development ) {
|
|
133
|
+
output += `${ indent }http port: ${ chalk.dim(
|
|
134
|
+
status.ports.development
|
|
135
|
+
) }\n`;
|
|
136
|
+
}
|
|
137
|
+
if ( status.urls?.phpmyadmin ) {
|
|
138
|
+
output += `${ indent }phpmyadmin url: ${ chalk.dim(
|
|
139
|
+
status.urls.phpmyadmin
|
|
140
|
+
) }\n`;
|
|
141
|
+
}
|
|
142
|
+
if ( status.ports?.mysql ) {
|
|
143
|
+
output += `${ indent }mysql port: ${ chalk.dim(
|
|
144
|
+
status.ports.mysql
|
|
145
|
+
) }\n`;
|
|
146
|
+
}
|
|
147
|
+
if ( status.ports?.tests ) {
|
|
148
|
+
output += `${ indent }test http port: ${ chalk.dim(
|
|
149
|
+
status.ports.tests
|
|
150
|
+
) }\n`;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return output;
|
|
154
|
+
}
|
package/lib/commands/stop.js
CHANGED
|
@@ -19,6 +19,8 @@ const { getRuntime, detectRuntime } = require( '../runtime' );
|
|
|
19
19
|
*/
|
|
20
20
|
module.exports = async function stop( { spinner, debug } ) {
|
|
21
21
|
const config = await loadConfig( path.resolve( '.' ) );
|
|
22
|
-
const runtime = getRuntime(
|
|
22
|
+
const runtime = getRuntime(
|
|
23
|
+
await detectRuntime( config.workDirectoryPath )
|
|
24
|
+
);
|
|
23
25
|
await runtime.stop( config, { spinner, debug } );
|
|
24
26
|
};
|
|
@@ -23,7 +23,6 @@ const { checkPort, checkVersion, checkString } = require( './validate-config' );
|
|
|
23
23
|
* @property {?number} phpmyadminPort An override for the development environment's phpMyAdmin port.
|
|
24
24
|
* @property {?WPSource} coreSource An override for all environment's coreSource.
|
|
25
25
|
* @property {?string} phpVersion An override for all environment's PHP version.
|
|
26
|
-
* @property {?boolean} multisite An override for if environmen should be multisite.
|
|
27
26
|
* @property {?Object.<string, string>} lifecycleScripts An override for various lifecycle scripts.
|
|
28
27
|
*/
|
|
29
28
|
|
|
@@ -69,10 +68,6 @@ module.exports = function getConfigFromEnvironmentVars( cacheDirectoryPath ) {
|
|
|
69
68
|
environmentConfig.phpVersion = process.env.WP_ENV_PHP_VERSION;
|
|
70
69
|
}
|
|
71
70
|
|
|
72
|
-
if ( process.env.WP_ENV_MULTISITE ) {
|
|
73
|
-
environmentConfig.multisite = !! process.env.WP_ENV_MULTISITE;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
71
|
return environmentConfig;
|
|
77
72
|
};
|
|
78
73
|
|
|
@@ -108,6 +103,8 @@ function getLifecycleScriptOverrides() {
|
|
|
108
103
|
const lifecycleEnvironmentVars = {
|
|
109
104
|
WP_ENV_LIFECYCLE_SCRIPT_AFTER_START: 'afterStart',
|
|
110
105
|
WP_ENV_LIFECYCLE_SCRIPT_AFTER_CLEAN: 'afterClean',
|
|
106
|
+
WP_ENV_LIFECYCLE_SCRIPT_AFTER_RESET: 'afterReset',
|
|
107
|
+
WP_ENV_LIFECYCLE_SCRIPT_AFTER_CLEANUP: 'afterCleanup',
|
|
111
108
|
WP_ENV_LIFECYCLE_SCRIPT_AFTER_DESTROY: 'afterDestroy',
|
|
112
109
|
};
|
|
113
110
|
for ( const envVar in lifecycleEnvironmentVars ) {
|
|
@@ -235,6 +235,8 @@ async function getDefaultConfig(
|
|
|
235
235
|
lifecycleScripts: {
|
|
236
236
|
afterStart: null,
|
|
237
237
|
afterClean: null,
|
|
238
|
+
afterReset: null,
|
|
239
|
+
afterCleanup: null,
|
|
238
240
|
afterDestroy: null,
|
|
239
241
|
},
|
|
240
242
|
env: {
|
|
@@ -312,6 +314,12 @@ function getEnvironmentVarOverrides( cacheDirectoryPath ) {
|
|
|
312
314
|
overrideConfig.env.tests.phpVersion = overrides.phpVersion;
|
|
313
315
|
}
|
|
314
316
|
|
|
317
|
+
if ( overrides.multisite ) {
|
|
318
|
+
overrideConfig.multisite = overrides.multisite;
|
|
319
|
+
overrideConfig.env.development.multisite = overrides.multisite;
|
|
320
|
+
overrideConfig.env.tests.multisite = overrides.multisite;
|
|
321
|
+
}
|
|
322
|
+
|
|
315
323
|
return overrideConfig;
|
|
316
324
|
}
|
|
317
325
|
|
|
@@ -71,7 +71,9 @@ exports[`Config Integration should load local and override configuration files 1
|
|
|
71
71
|
},
|
|
72
72
|
"lifecycleScripts": {
|
|
73
73
|
"afterClean": null,
|
|
74
|
+
"afterCleanup": null,
|
|
74
75
|
"afterDestroy": "test",
|
|
76
|
+
"afterReset": null,
|
|
75
77
|
"afterStart": null,
|
|
76
78
|
},
|
|
77
79
|
"name": "gutenberg",
|
|
@@ -150,7 +152,9 @@ exports[`Config Integration should load local configuration file 1`] = `
|
|
|
150
152
|
},
|
|
151
153
|
"lifecycleScripts": {
|
|
152
154
|
"afterClean": null,
|
|
155
|
+
"afterCleanup": null,
|
|
153
156
|
"afterDestroy": null,
|
|
157
|
+
"afterReset": null,
|
|
154
158
|
"afterStart": "test",
|
|
155
159
|
},
|
|
156
160
|
"name": "gutenberg",
|
|
@@ -229,7 +233,9 @@ exports[`Config Integration should use default configuration 1`] = `
|
|
|
229
233
|
},
|
|
230
234
|
"lifecycleScripts": {
|
|
231
235
|
"afterClean": null,
|
|
236
|
+
"afterCleanup": null,
|
|
232
237
|
"afterDestroy": null,
|
|
238
|
+
"afterReset": null,
|
|
233
239
|
"afterStart": null,
|
|
234
240
|
},
|
|
235
241
|
"name": "gutenberg",
|
|
@@ -310,7 +316,9 @@ exports[`Config Integration should use environment variables over local and over
|
|
|
310
316
|
},
|
|
311
317
|
"lifecycleScripts": {
|
|
312
318
|
"afterClean": null,
|
|
319
|
+
"afterCleanup": null,
|
|
313
320
|
"afterDestroy": null,
|
|
321
|
+
"afterReset": null,
|
|
314
322
|
"afterStart": "test",
|
|
315
323
|
},
|
|
316
324
|
"name": "gutenberg",
|
|
@@ -181,6 +181,19 @@ module.exports = function buildDockerComposeConfig( config ) {
|
|
|
181
181
|
config.env.tests.phpmyadminPort ?? ''
|
|
182
182
|
}}:80`;
|
|
183
183
|
|
|
184
|
+
// MySQL healthcheck using MariaDB's official healthcheck.sh script.
|
|
185
|
+
// --connect: verifies TCP connection and that entrypoint has finished
|
|
186
|
+
// --innodb_initialized: ensures InnoDB storage engine is fully initialized
|
|
187
|
+
// MARIADB_AUTO_UPGRADE env var ensures healthcheck user exists for existing installations.
|
|
188
|
+
// Timing is generous to support slow CI environments.
|
|
189
|
+
const mysqlHealthcheck = {
|
|
190
|
+
test: [ 'CMD', 'healthcheck.sh', '--connect', '--innodb_initialized' ],
|
|
191
|
+
interval: '5s',
|
|
192
|
+
timeout: '10s',
|
|
193
|
+
retries: 12,
|
|
194
|
+
start_period: '60s',
|
|
195
|
+
};
|
|
196
|
+
|
|
184
197
|
return {
|
|
185
198
|
services: {
|
|
186
199
|
mysql: {
|
|
@@ -191,8 +204,11 @@ module.exports = function buildDockerComposeConfig( config ) {
|
|
|
191
204
|
MYSQL_ROOT_PASSWORD:
|
|
192
205
|
dbEnv.credentials.WORDPRESS_DB_PASSWORD,
|
|
193
206
|
MYSQL_DATABASE: dbEnv.development.WORDPRESS_DB_NAME,
|
|
207
|
+
// Ensures healthcheck user is created for existing installations.
|
|
208
|
+
MARIADB_AUTO_UPGRADE: '1',
|
|
194
209
|
},
|
|
195
210
|
volumes: [ 'mysql:/var/lib/mysql' ],
|
|
211
|
+
healthcheck: mysqlHealthcheck,
|
|
196
212
|
},
|
|
197
213
|
'tests-mysql': {
|
|
198
214
|
image: 'mariadb:lts',
|
|
@@ -202,11 +218,18 @@ module.exports = function buildDockerComposeConfig( config ) {
|
|
|
202
218
|
MYSQL_ROOT_PASSWORD:
|
|
203
219
|
dbEnv.credentials.WORDPRESS_DB_PASSWORD,
|
|
204
220
|
MYSQL_DATABASE: dbEnv.tests.WORDPRESS_DB_NAME,
|
|
221
|
+
// Ensures healthcheck user is created for existing installations.
|
|
222
|
+
MARIADB_AUTO_UPGRADE: '1',
|
|
205
223
|
},
|
|
206
224
|
volumes: [ 'mysql-test:/var/lib/mysql' ],
|
|
225
|
+
healthcheck: mysqlHealthcheck,
|
|
207
226
|
},
|
|
208
227
|
wordpress: {
|
|
209
|
-
depends_on:
|
|
228
|
+
depends_on: {
|
|
229
|
+
mysql: {
|
|
230
|
+
condition: 'service_healthy',
|
|
231
|
+
},
|
|
232
|
+
},
|
|
210
233
|
build: {
|
|
211
234
|
context: '.',
|
|
212
235
|
dockerfile: 'WordPress.Dockerfile',
|
|
@@ -224,7 +247,11 @@ module.exports = function buildDockerComposeConfig( config ) {
|
|
|
224
247
|
extra_hosts: [ 'host.docker.internal:host-gateway' ],
|
|
225
248
|
},
|
|
226
249
|
'tests-wordpress': {
|
|
227
|
-
depends_on:
|
|
250
|
+
depends_on: {
|
|
251
|
+
'tests-mysql': {
|
|
252
|
+
condition: 'service_healthy',
|
|
253
|
+
},
|
|
254
|
+
},
|
|
228
255
|
build: {
|
|
229
256
|
context: '.',
|
|
230
257
|
dockerfile: 'Tests-WordPress.Dockerfile',
|
|
@@ -11,7 +11,6 @@ const { rimraf } = require( 'rimraf' );
|
|
|
11
11
|
/**
|
|
12
12
|
* Promisified dependencies
|
|
13
13
|
*/
|
|
14
|
-
const sleep = util.promisify( setTimeout );
|
|
15
14
|
const exec = util.promisify( require( 'child_process' ).exec );
|
|
16
15
|
|
|
17
16
|
/**
|
|
@@ -26,7 +25,6 @@ const {
|
|
|
26
25
|
validateRunContainer,
|
|
27
26
|
} = require( './validate-run-container' );
|
|
28
27
|
const {
|
|
29
|
-
checkDatabaseConnection,
|
|
30
28
|
configureWordPress,
|
|
31
29
|
resetDatabase,
|
|
32
30
|
setupWordPressDirectories,
|
|
@@ -174,7 +172,7 @@ class DockerRuntime {
|
|
|
174
172
|
}
|
|
175
173
|
|
|
176
174
|
await Promise.all( [
|
|
177
|
-
dockerCompose.
|
|
175
|
+
dockerCompose.upMany( [ 'mysql', 'tests-mysql' ], {
|
|
178
176
|
...dockerComposeConfig,
|
|
179
177
|
commandOptions: shouldConfigureWp
|
|
180
178
|
? [ '--build', '--force-recreate' ]
|
|
@@ -250,19 +248,6 @@ class DockerRuntime {
|
|
|
250
248
|
if ( shouldConfigureWp ) {
|
|
251
249
|
spinner.text = 'Configuring WordPress.';
|
|
252
250
|
|
|
253
|
-
try {
|
|
254
|
-
await checkDatabaseConnection( fullConfig );
|
|
255
|
-
} catch ( error ) {
|
|
256
|
-
// Wait 30 seconds for MySQL to accept connections.
|
|
257
|
-
await retry( () => checkDatabaseConnection( fullConfig ), {
|
|
258
|
-
times: 30,
|
|
259
|
-
delay: 1000,
|
|
260
|
-
} );
|
|
261
|
-
|
|
262
|
-
// It takes 3-4 seconds for MySQL to be ready after it starts accepting connections.
|
|
263
|
-
await sleep( 4000 );
|
|
264
|
-
}
|
|
265
|
-
|
|
266
251
|
// Retry WordPress installation in case MySQL *still* wasn't ready.
|
|
267
252
|
await Promise.all( [
|
|
268
253
|
retry(
|
|
@@ -369,6 +354,15 @@ class DockerRuntime {
|
|
|
369
354
|
return 'WARNING! This will remove Docker containers, volumes, networks, and images associated with the WordPress instance.';
|
|
370
355
|
}
|
|
371
356
|
|
|
357
|
+
/**
|
|
358
|
+
* Get the warning message for cleanup confirmation.
|
|
359
|
+
*
|
|
360
|
+
* @return {string} Warning message.
|
|
361
|
+
*/
|
|
362
|
+
getCleanupWarningMessage() {
|
|
363
|
+
return 'WARNING! This will remove Docker containers, volumes, networks, and local files associated with the WordPress instance. Docker images will be preserved.';
|
|
364
|
+
}
|
|
365
|
+
|
|
372
366
|
/**
|
|
373
367
|
* Stop the Docker containers.
|
|
374
368
|
*
|
|
@@ -413,7 +407,8 @@ class DockerRuntime {
|
|
|
413
407
|
spinner.text = 'Removing local files.';
|
|
414
408
|
// Note: there is a race condition where docker compose actually hasn't finished
|
|
415
409
|
// by this point, which causes rimraf to fail. We need to wait at least 2.5-5s,
|
|
416
|
-
// but using 10s in case it's
|
|
410
|
+
// but using 10s in case it's dependent on the machine. Removing images takes
|
|
411
|
+
// longer so we use a longer wait time here.
|
|
417
412
|
await new Promise( ( resolve ) => setTimeout( resolve, 10000 ) );
|
|
418
413
|
await rimraf( config.workDirectoryPath );
|
|
419
414
|
|
|
@@ -421,11 +416,38 @@ class DockerRuntime {
|
|
|
421
416
|
}
|
|
422
417
|
|
|
423
418
|
/**
|
|
424
|
-
*
|
|
419
|
+
* Cleanup the Docker containers and remove local files, but preserve images.
|
|
420
|
+
*
|
|
421
|
+
* @param {WPConfig} config The wp-env config object.
|
|
422
|
+
* @param {Object} options Cleanup options.
|
|
423
|
+
* @param {Object} options.spinner A CLI spinner which indicates progress.
|
|
424
|
+
* @param {boolean} options.debug True if debug mode is enabled.
|
|
425
|
+
*/
|
|
426
|
+
async cleanup( config, { spinner, debug } ) {
|
|
427
|
+
spinner.text = 'Removing docker containers, volumes, and networks.';
|
|
428
|
+
|
|
429
|
+
await dockerCompose.down( {
|
|
430
|
+
config: config.dockerComposeConfigPath,
|
|
431
|
+
commandOptions: [ '--volumes', '--remove-orphans' ],
|
|
432
|
+
log: debug,
|
|
433
|
+
} );
|
|
434
|
+
|
|
435
|
+
spinner.text = 'Removing local files.';
|
|
436
|
+
// Note: there is a race condition where docker compose actually hasn't finished
|
|
437
|
+
// by this point, which causes rimraf to fail. We need to wait at least 2.5-5s,
|
|
438
|
+
// but since we're not removing images, the wait can be shorter.
|
|
439
|
+
await new Promise( ( resolve ) => setTimeout( resolve, 3000 ) );
|
|
440
|
+
await rimraf( config.workDirectoryPath );
|
|
441
|
+
|
|
442
|
+
spinner.text = 'Cleaned up WordPress environment.';
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Reset the WordPress database.
|
|
425
447
|
*
|
|
426
448
|
* @param {WPConfig} config The wp-env config object.
|
|
427
|
-
* @param {Object} options
|
|
428
|
-
* @param {string} options.environment The environment to
|
|
449
|
+
* @param {Object} options Reset options.
|
|
450
|
+
* @param {string} options.environment The environment to reset.
|
|
429
451
|
* @param {Object} options.spinner A CLI spinner which indicates progress.
|
|
430
452
|
* @param {boolean} options.debug True if debug mode is enabled.
|
|
431
453
|
*/
|
|
@@ -435,13 +457,23 @@ class DockerRuntime {
|
|
|
435
457
|
const description = `${ environment } environment${
|
|
436
458
|
environment === 'all' ? 's' : ''
|
|
437
459
|
}`;
|
|
438
|
-
spinner.text = `
|
|
460
|
+
spinner.text = `Resetting ${ description }.`;
|
|
439
461
|
|
|
440
462
|
const tasks = [];
|
|
441
463
|
|
|
442
|
-
// Start the
|
|
443
|
-
//
|
|
444
|
-
|
|
464
|
+
// Start the appropriate MySQL service(s) first to avoid race conditions
|
|
465
|
+
// where parallel tasks try to create docker networks with the same name.
|
|
466
|
+
// The dependency chain (cli -> wordpress -> mysql with service_healthy)
|
|
467
|
+
// ensures MySQL is ready before database operations run.
|
|
468
|
+
const mysqlServices = [];
|
|
469
|
+
if ( environment === 'all' || environment === 'development' ) {
|
|
470
|
+
mysqlServices.push( 'mysql' );
|
|
471
|
+
}
|
|
472
|
+
if ( environment === 'all' || environment === 'tests' ) {
|
|
473
|
+
mysqlServices.push( 'tests-mysql' );
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
await dockerCompose.upMany( mysqlServices, {
|
|
445
477
|
config: fullConfig.dockerComposeConfigPath,
|
|
446
478
|
log: fullConfig.debug,
|
|
447
479
|
} );
|
|
@@ -466,7 +498,7 @@ class DockerRuntime {
|
|
|
466
498
|
|
|
467
499
|
await Promise.all( tasks );
|
|
468
500
|
|
|
469
|
-
spinner.text = `
|
|
501
|
+
spinner.text = `Reset ${ description }.`;
|
|
470
502
|
}
|
|
471
503
|
|
|
472
504
|
/**
|
|
@@ -577,6 +609,74 @@ class DockerRuntime {
|
|
|
577
609
|
spinner.text = 'Finished showing logs.';
|
|
578
610
|
}
|
|
579
611
|
|
|
612
|
+
/**
|
|
613
|
+
* Get the status of the Docker environment.
|
|
614
|
+
*
|
|
615
|
+
* @param {WPConfig} config The wp-env config object.
|
|
616
|
+
* @param {Object} options Status options.
|
|
617
|
+
* @param {Object} options.spinner A CLI spinner which indicates progress.
|
|
618
|
+
* @param {boolean} options.debug True if debug mode is enabled.
|
|
619
|
+
* @return {Promise<Object>} Status object with environment information.
|
|
620
|
+
*/
|
|
621
|
+
async getStatus( config, { spinner, debug } ) {
|
|
622
|
+
spinner.text = 'Getting environment status.';
|
|
623
|
+
|
|
624
|
+
const fullConfig = await initConfig( { spinner, debug } );
|
|
625
|
+
const dockerComposeConfig = {
|
|
626
|
+
config: fullConfig.dockerComposeConfigPath,
|
|
627
|
+
log: debug,
|
|
628
|
+
};
|
|
629
|
+
|
|
630
|
+
// Check if containers are running by trying to get a port.
|
|
631
|
+
let isRunning = false;
|
|
632
|
+
let mySQLPort = null;
|
|
633
|
+
let phpmyadminPort = null;
|
|
634
|
+
|
|
635
|
+
try {
|
|
636
|
+
mySQLPort = await this._getPublicDockerPort(
|
|
637
|
+
'mysql',
|
|
638
|
+
3306,
|
|
639
|
+
dockerComposeConfig
|
|
640
|
+
);
|
|
641
|
+
isRunning = true;
|
|
642
|
+
|
|
643
|
+
if ( fullConfig.env.development.phpmyadminPort ) {
|
|
644
|
+
phpmyadminPort = await this._getPublicDockerPort(
|
|
645
|
+
'phpmyadmin',
|
|
646
|
+
80,
|
|
647
|
+
dockerComposeConfig
|
|
648
|
+
);
|
|
649
|
+
}
|
|
650
|
+
} catch {
|
|
651
|
+
// Containers are not running.
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
const siteUrl = fullConfig.env.development.config.WP_SITEURL;
|
|
655
|
+
|
|
656
|
+
return {
|
|
657
|
+
status: isRunning ? 'running' : 'stopped',
|
|
658
|
+
runtime: 'docker',
|
|
659
|
+
urls: {
|
|
660
|
+
development: isRunning ? siteUrl : null,
|
|
661
|
+
phpmyadmin:
|
|
662
|
+
isRunning && phpmyadminPort
|
|
663
|
+
? `http://localhost:${ phpmyadminPort }`
|
|
664
|
+
: null,
|
|
665
|
+
},
|
|
666
|
+
ports: {
|
|
667
|
+
development: fullConfig.env.development.port,
|
|
668
|
+
tests: fullConfig.env.tests.port,
|
|
669
|
+
mysql: mySQLPort,
|
|
670
|
+
},
|
|
671
|
+
config: {
|
|
672
|
+
multisite: fullConfig.env.development.multisite,
|
|
673
|
+
xdebug: fullConfig.xdebug || 'off',
|
|
674
|
+
},
|
|
675
|
+
configPath: fullConfig.configDirectoryPath,
|
|
676
|
+
installPath: fullConfig.workDirectoryPath,
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
|
|
580
680
|
/**
|
|
581
681
|
* Runs an arbitrary command on the given Docker container.
|
|
582
682
|
*
|
|
@@ -47,20 +47,6 @@ function isWPMajorMinorVersionLower( version, compareVersion ) {
|
|
|
47
47
|
return versionNumber < compareVersionNumber;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
/**
|
|
51
|
-
* Checks a WordPress database connection. An error is thrown if the test is
|
|
52
|
-
* unsuccessful.
|
|
53
|
-
*
|
|
54
|
-
* @param {WPConfig} config The wp-env config object.
|
|
55
|
-
*/
|
|
56
|
-
async function checkDatabaseConnection( { dockerComposeConfigPath, debug } ) {
|
|
57
|
-
await dockerCompose.run( 'cli', 'wp db check', {
|
|
58
|
-
config: dockerComposeConfigPath,
|
|
59
|
-
commandOptions: [ '--rm' ],
|
|
60
|
-
log: debug,
|
|
61
|
-
} );
|
|
62
|
-
}
|
|
63
|
-
|
|
64
50
|
/**
|
|
65
51
|
* Configures WordPress for the given environment by installing WordPress,
|
|
66
52
|
* activating all plugins, and activating the first theme. These steps are
|
|
@@ -316,7 +302,6 @@ async function copyCoreFiles( fromPath, toPath ) {
|
|
|
316
302
|
}
|
|
317
303
|
|
|
318
304
|
module.exports = {
|
|
319
|
-
checkDatabaseConnection,
|
|
320
305
|
configureWordPress,
|
|
321
306
|
resetDatabase,
|
|
322
307
|
setupWordPressDirectories,
|
package/lib/runtime/errors.js
CHANGED
|
@@ -12,6 +12,17 @@ class UnsupportedCommandError extends Error {
|
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Error thrown when the environment has not been initialized.
|
|
17
|
+
*/
|
|
18
|
+
class EnvironmentNotInitializedError extends Error {
|
|
19
|
+
constructor() {
|
|
20
|
+
super( 'Environment not initialized. Run `wp-env start` first.' );
|
|
21
|
+
this.name = 'EnvironmentNotInitializedError';
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
15
25
|
module.exports = {
|
|
16
26
|
UnsupportedCommandError,
|
|
27
|
+
EnvironmentNotInitializedError,
|
|
17
28
|
};
|
package/lib/runtime/index.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* External dependencies
|
|
5
|
-
*/
|
|
6
|
-
const { existsSync } = require( 'fs' );
|
|
7
|
-
const path = require( 'path' );
|
|
8
|
-
|
|
9
3
|
/**
|
|
10
4
|
* Internal dependencies
|
|
11
5
|
*/
|
|
12
6
|
const DockerRuntime = require( './docker' );
|
|
13
7
|
const PlaygroundRuntime = require( './playground' );
|
|
14
|
-
const {
|
|
8
|
+
const {
|
|
9
|
+
UnsupportedCommandError,
|
|
10
|
+
EnvironmentNotInitializedError,
|
|
11
|
+
} = require( './errors' );
|
|
12
|
+
const { setCache, getCache } = require( '../cache' );
|
|
13
|
+
|
|
14
|
+
const RUNTIME_CACHE_KEY = 'runtime';
|
|
15
15
|
|
|
16
16
|
const runtimes = {
|
|
17
17
|
docker: DockerRuntime,
|
|
@@ -42,28 +42,50 @@ function getAvailableRuntimes() {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
|
-
*
|
|
46
|
-
*
|
|
45
|
+
* Save the runtime type to the cache file.
|
|
46
|
+
* Called when start command initializes the environment.
|
|
47
|
+
*
|
|
48
|
+
* @param {string} runtimeName The runtime name ('docker' or 'playground').
|
|
49
|
+
* @param {string} workDirectoryPath Path to the wp-env work directory.
|
|
50
|
+
*/
|
|
51
|
+
async function saveRuntime( runtimeName, workDirectoryPath ) {
|
|
52
|
+
await setCache( RUNTIME_CACHE_KEY, runtimeName, { workDirectoryPath } );
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Get the saved runtime type from cache.
|
|
57
|
+
*
|
|
58
|
+
* @param {string} workDirectoryPath Path to the wp-env work directory.
|
|
59
|
+
* @return {Promise<string|undefined>} The saved runtime name, or undefined if not set.
|
|
60
|
+
*/
|
|
61
|
+
async function getSavedRuntime( workDirectoryPath ) {
|
|
62
|
+
return await getCache( RUNTIME_CACHE_KEY, { workDirectoryPath } );
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Detect which runtime was used by reading from the cache.
|
|
67
|
+
* Throws EnvironmentNotInitializedError if no runtime has been saved.
|
|
47
68
|
*
|
|
48
69
|
* @param {string} workDirectoryPath Path to the wp-env work directory.
|
|
49
|
-
* @return {string} Runtime name ('docker' or 'playground').
|
|
70
|
+
* @return {Promise<string>} Runtime name ('docker' or 'playground').
|
|
71
|
+
* @throws {EnvironmentNotInitializedError} If environment not initialized.
|
|
50
72
|
*/
|
|
51
|
-
function detectRuntime( workDirectoryPath ) {
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
);
|
|
56
|
-
if ( existsSync( playgroundBlueprintFile ) ) {
|
|
57
|
-
return 'playground';
|
|
73
|
+
async function detectRuntime( workDirectoryPath ) {
|
|
74
|
+
const savedRuntime = await getSavedRuntime( workDirectoryPath );
|
|
75
|
+
if ( ! savedRuntime ) {
|
|
76
|
+
throw new EnvironmentNotInitializedError();
|
|
58
77
|
}
|
|
59
|
-
return
|
|
78
|
+
return savedRuntime;
|
|
60
79
|
}
|
|
61
80
|
|
|
62
81
|
module.exports = {
|
|
63
82
|
getRuntime,
|
|
64
83
|
getAvailableRuntimes,
|
|
65
84
|
detectRuntime,
|
|
85
|
+
saveRuntime,
|
|
86
|
+
getSavedRuntime,
|
|
66
87
|
DockerRuntime,
|
|
67
88
|
PlaygroundRuntime,
|
|
68
89
|
UnsupportedCommandError,
|
|
90
|
+
EnvironmentNotInitializedError,
|
|
69
91
|
};
|