@wordpress/env 10.38.1-next.v.0 → 11.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.
Files changed (37) hide show
  1. package/README.md +158 -75
  2. package/lib/cli.js +85 -24
  3. package/lib/commands/clean.js +16 -38
  4. package/lib/commands/cleanup.js +79 -0
  5. package/lib/commands/destroy.js +33 -41
  6. package/lib/commands/index.js +6 -2
  7. package/lib/commands/logs.js +20 -62
  8. package/lib/commands/reset.js +46 -0
  9. package/lib/commands/run.js +16 -117
  10. package/lib/commands/start.js +78 -243
  11. package/lib/commands/status.js +160 -0
  12. package/lib/commands/stop.js +17 -19
  13. package/lib/config/get-config-from-environment-vars.js +2 -5
  14. package/lib/config/load-config.js +35 -5
  15. package/lib/config/parse-config.js +53 -21
  16. package/lib/config/post-process-config.js +38 -16
  17. package/lib/config/test/__snapshots__/config-integration.js.snap +16 -0
  18. package/lib/config/test/parse-config.js +33 -0
  19. package/lib/config/test/post-process-config.js +52 -0
  20. package/lib/download-sources.js +9 -53
  21. package/lib/{build-docker-compose-config.js → runtime/docker/build-docker-compose-config.js} +167 -128
  22. package/lib/runtime/docker/download-sources.js +63 -0
  23. package/lib/{download-wp-phpunit.js → runtime/docker/download-wp-phpunit.js} +4 -1
  24. package/lib/runtime/docker/index.js +863 -0
  25. package/lib/{init-config.js → runtime/docker/init-config.js} +22 -14
  26. package/lib/runtime/docker/wordpress.js +309 -0
  27. package/lib/runtime/errors.js +28 -0
  28. package/lib/runtime/index.js +91 -0
  29. package/lib/runtime/playground/blueprint-builder.js +158 -0
  30. package/lib/runtime/playground/index.js +530 -0
  31. package/lib/test/build-docker-compose-config.js +150 -3
  32. package/lib/test/cli.js +49 -13
  33. package/lib/wordpress.js +1 -297
  34. package/package.json +6 -3
  35. package/lib/commands/install-path.js +0 -21
  36. /package/lib/{get-host-user.js → runtime/docker/get-host-user.js} +0 -0
  37. /package/lib/{validate-run-container.js → runtime/docker/validate-run-container.js} +0 -0
@@ -9,12 +9,12 @@ const path = require( 'path' );
9
9
  * Internal dependencies
10
10
  */
11
11
  const { hasSameCoreSource } = require( './wordpress' );
12
- const { dbEnv } = require( './config' );
12
+ const { dbEnv } = require( '../../config' );
13
13
  const getHostUser = require( './get-host-user' );
14
14
 
15
15
  /**
16
- * @typedef {import('./config').WPConfig} WPConfig
17
- * @typedef {import('./config').WPEnvironmentConfig} WPEnvironmentConfig
16
+ * @typedef {import('../../config').WPConfig} WPConfig
17
+ * @typedef {import('../../config').WPEnvironmentConfig} WPEnvironmentConfig
18
18
  */
19
19
 
20
20
  /**
@@ -88,6 +88,8 @@ function getMounts(
88
88
  * @return {Object} A docker-compose config object, ready to serialize into YAML.
89
89
  */
90
90
  module.exports = function buildDockerComposeConfig( config ) {
91
+ const testsEnabled = config.testsEnvironment !== false;
92
+
91
93
  // Since we are mounting files from the host operating system
92
94
  // we want to create the host user in some of our containers.
93
95
  // This ensures ownership parity and lets us access files
@@ -99,12 +101,14 @@ module.exports = function buildDockerComposeConfig( config ) {
99
101
  config.env.development,
100
102
  hostUser.name
101
103
  );
102
- const testsMounts = getMounts(
103
- config.workDirectoryPath,
104
- config.env.tests,
105
- hostUser.name,
106
- 'tests-wordpress'
107
- );
104
+ const testsMounts = testsEnabled
105
+ ? getMounts(
106
+ config.workDirectoryPath,
107
+ config.env.tests,
108
+ hostUser.name,
109
+ 'tests-wordpress'
110
+ )
111
+ : [];
108
112
 
109
113
  // We use a custom Dockerfile in order to make sure that
110
114
  // the current host user exists inside the container.
@@ -135,6 +139,7 @@ module.exports = function buildDockerComposeConfig( config ) {
135
139
  //
136
140
  // https://github.com/WordPress/gutenberg/issues/21164
137
141
  if (
142
+ testsEnabled &&
138
143
  config.env.development.coreSource &&
139
144
  hasSameCoreSource( [ config.env.development, config.env.tests ] )
140
145
  ) {
@@ -169,138 +174,172 @@ module.exports = function buildDockerComposeConfig( config ) {
169
174
  const developmentMysqlPorts = `\${WP_ENV_MYSQL_PORT:-${
170
175
  config.env.development.mysqlPort ?? ''
171
176
  }}:3306`;
172
- const testsPorts = `\${WP_ENV_TESTS_PORT:-${ config.env.tests.port }}:80`;
173
- const testsMysqlPorts = `\${WP_ENV_TESTS_MYSQL_PORT:-${
174
- config.env.tests.mysqlPort ?? ''
175
- }}:3306`;
176
177
 
177
178
  const developmentPhpmyadminPorts = `\${WP_ENV_PHPMYADMIN_PORT:-${
178
179
  config.env.development.phpmyadminPort ?? ''
179
180
  }}:80`;
180
- const testsPhpmyadminPorts = `\${WP_ENV_TESTS_PHPMYADMIN_PORT:-${
181
- config.env.tests.phpmyadminPort ?? ''
182
- }}:80`;
183
181
 
184
- return {
185
- services: {
186
- mysql: {
187
- image: 'mariadb:lts',
188
- ports: [ developmentMysqlPorts ],
189
- environment: {
190
- MYSQL_ROOT_HOST: '%',
191
- MYSQL_ROOT_PASSWORD:
192
- dbEnv.credentials.WORDPRESS_DB_PASSWORD,
193
- MYSQL_DATABASE: dbEnv.development.WORDPRESS_DB_NAME,
194
- },
195
- volumes: [ 'mysql:/var/lib/mysql' ],
196
- },
197
- 'tests-mysql': {
198
- image: 'mariadb:lts',
199
- ports: [ testsMysqlPorts ],
200
- environment: {
201
- MYSQL_ROOT_HOST: '%',
202
- MYSQL_ROOT_PASSWORD:
203
- dbEnv.credentials.WORDPRESS_DB_PASSWORD,
204
- MYSQL_DATABASE: dbEnv.tests.WORDPRESS_DB_NAME,
205
- },
206
- volumes: [ 'mysql-test:/var/lib/mysql' ],
207
- },
208
- wordpress: {
209
- depends_on: [ 'mysql' ],
210
- build: {
211
- context: '.',
212
- dockerfile: 'WordPress.Dockerfile',
213
- args: imageBuildArgs,
214
- },
215
- ports: [ developmentPorts ],
216
- environment: {
217
- APACHE_RUN_USER: '#' + hostUser.uid,
218
- APACHE_RUN_GROUP: '#' + hostUser.gid,
219
- ...dbEnv.credentials,
220
- ...dbEnv.development,
221
- WP_TESTS_DIR: '/wordpress-phpunit',
222
- },
223
- volumes: developmentMounts,
224
- extra_hosts: [ 'host.docker.internal:host-gateway' ],
182
+ // MySQL healthcheck using MariaDB's official healthcheck.sh script.
183
+ // --connect: verifies TCP connection and that entrypoint has finished
184
+ // --innodb_initialized: ensures InnoDB storage engine is fully initialized
185
+ // MARIADB_AUTO_UPGRADE env var ensures healthcheck user exists for existing installations.
186
+ // Timing is generous to support slow CI environments.
187
+ const mysqlHealthcheck = {
188
+ test: [ 'CMD', 'healthcheck.sh', '--connect', '--innodb_initialized' ],
189
+ interval: '5s',
190
+ timeout: '10s',
191
+ retries: 12,
192
+ start_period: '60s',
193
+ };
194
+
195
+ // Build the services object, conditionally including tests services.
196
+ const services = {
197
+ mysql: {
198
+ image: 'mariadb:lts',
199
+ ports: [ developmentMysqlPorts ],
200
+ environment: {
201
+ MYSQL_ROOT_HOST: '%',
202
+ MYSQL_ROOT_PASSWORD: dbEnv.credentials.WORDPRESS_DB_PASSWORD,
203
+ MYSQL_DATABASE: dbEnv.development.WORDPRESS_DB_NAME,
204
+ // Ensures healthcheck user is created for existing installations.
205
+ MARIADB_AUTO_UPGRADE: '1',
225
206
  },
226
- 'tests-wordpress': {
227
- depends_on: [ 'tests-mysql' ],
228
- build: {
229
- context: '.',
230
- dockerfile: 'Tests-WordPress.Dockerfile',
231
- args: imageBuildArgs,
232
- },
233
- ports: [ testsPorts ],
234
- environment: {
235
- APACHE_RUN_USER: '#' + hostUser.uid,
236
- APACHE_RUN_GROUP: '#' + hostUser.gid,
237
- ...dbEnv.credentials,
238
- ...dbEnv.tests,
239
- WP_TESTS_DIR: '/wordpress-phpunit',
207
+ volumes: [ 'mysql:/var/lib/mysql' ],
208
+ healthcheck: mysqlHealthcheck,
209
+ },
210
+ wordpress: {
211
+ depends_on: {
212
+ mysql: {
213
+ condition: 'service_healthy',
240
214
  },
241
- volumes: testsMounts,
242
- extra_hosts: [ 'host.docker.internal:host-gateway' ],
243
215
  },
244
- cli: {
245
- depends_on: [ 'wordpress' ],
246
- build: {
247
- context: '.',
248
- dockerfile: 'CLI.Dockerfile',
249
- args: imageBuildArgs,
250
- },
251
- volumes: developmentMounts,
252
- user: hostUser.fullUser,
253
- environment: {
254
- ...dbEnv.credentials,
255
- ...dbEnv.development,
256
- WP_TESTS_DIR: '/wordpress-phpunit',
257
- },
258
- extra_hosts: [ 'host.docker.internal:host-gateway' ],
216
+ build: {
217
+ context: '.',
218
+ dockerfile: 'WordPress.Dockerfile',
219
+ args: imageBuildArgs,
259
220
  },
260
- 'tests-cli': {
261
- depends_on: [ 'tests-wordpress' ],
262
- build: {
263
- context: '.',
264
- dockerfile: 'Tests-CLI.Dockerfile',
265
- args: imageBuildArgs,
266
- },
267
- volumes: testsMounts,
268
- user: hostUser.fullUser,
269
- environment: {
270
- ...dbEnv.credentials,
271
- ...dbEnv.tests,
272
- WP_TESTS_DIR: '/wordpress-phpunit',
273
- },
274
- extra_hosts: [ 'host.docker.internal:host-gateway' ],
221
+ ports: [ developmentPorts ],
222
+ environment: {
223
+ APACHE_RUN_USER: '#' + hostUser.uid,
224
+ APACHE_RUN_GROUP: '#' + hostUser.gid,
225
+ ...dbEnv.credentials,
226
+ ...dbEnv.development,
227
+ WP_TESTS_DIR: '/wordpress-phpunit',
275
228
  },
276
- phpmyadmin: {
277
- image: 'phpmyadmin',
278
- ports: [ developmentPhpmyadminPorts ],
279
- environment: {
280
- PMA_PORT: 3306,
281
- PMA_HOST: 'mysql',
282
- PMA_USER: 'root',
283
- PMA_PASSWORD: 'password',
284
- },
229
+ volumes: developmentMounts,
230
+ extra_hosts: [ 'host.docker.internal:host-gateway' ],
231
+ },
232
+ cli: {
233
+ depends_on: [ 'wordpress' ],
234
+ build: {
235
+ context: '.',
236
+ dockerfile: 'CLI.Dockerfile',
237
+ args: imageBuildArgs,
285
238
  },
286
- 'tests-phpmyadmin': {
287
- image: 'phpmyadmin',
288
- ports: [ testsPhpmyadminPorts ],
289
- environment: {
290
- PMA_PORT: 3306,
291
- PMA_HOST: 'tests-mysql',
292
- PMA_USER: 'root',
293
- PMA_PASSWORD: 'password',
294
- },
239
+ volumes: developmentMounts,
240
+ user: hostUser.fullUser,
241
+ environment: {
242
+ ...dbEnv.credentials,
243
+ ...dbEnv.development,
244
+ WP_TESTS_DIR: '/wordpress-phpunit',
295
245
  },
246
+ extra_hosts: [ 'host.docker.internal:host-gateway' ],
296
247
  },
297
- volumes: {
298
- ...( ! config.env.development.coreSource && { wordpress: {} } ),
299
- ...( ! config.env.tests.coreSource && { 'tests-wordpress': {} } ),
300
- mysql: {},
301
- 'mysql-test': {},
302
- 'user-home': {},
303
- 'tests-user-home': {},
248
+ phpmyadmin: {
249
+ image: 'phpmyadmin',
250
+ ports: [ developmentPhpmyadminPorts ],
251
+ environment: {
252
+ PMA_PORT: 3306,
253
+ PMA_HOST: 'mysql',
254
+ PMA_USER: 'root',
255
+ PMA_PASSWORD: 'password',
256
+ },
304
257
  },
305
258
  };
259
+
260
+ const volumes = {
261
+ ...( ! config.env.development.coreSource && { wordpress: {} } ),
262
+ mysql: {},
263
+ 'user-home': {},
264
+ };
265
+
266
+ if ( testsEnabled ) {
267
+ const testsPorts = `\${WP_ENV_TESTS_PORT:-${ config.env.tests.port }}:80`;
268
+ const testsMysqlPorts = `\${WP_ENV_TESTS_MYSQL_PORT:-${
269
+ config.env.tests.mysqlPort ?? ''
270
+ }}:3306`;
271
+ const testsPhpmyadminPorts = `\${WP_ENV_TESTS_PHPMYADMIN_PORT:-${
272
+ config.env.tests.phpmyadminPort ?? ''
273
+ }}:80`;
274
+
275
+ services[ 'tests-mysql' ] = {
276
+ image: 'mariadb:lts',
277
+ ports: [ testsMysqlPorts ],
278
+ environment: {
279
+ MYSQL_ROOT_HOST: '%',
280
+ MYSQL_ROOT_PASSWORD: dbEnv.credentials.WORDPRESS_DB_PASSWORD,
281
+ MYSQL_DATABASE: dbEnv.tests.WORDPRESS_DB_NAME,
282
+ // Ensures healthcheck user is created for existing installations.
283
+ MARIADB_AUTO_UPGRADE: '1',
284
+ },
285
+ volumes: [ 'mysql-test:/var/lib/mysql' ],
286
+ healthcheck: mysqlHealthcheck,
287
+ };
288
+ services[ 'tests-wordpress' ] = {
289
+ depends_on: {
290
+ 'tests-mysql': {
291
+ condition: 'service_healthy',
292
+ },
293
+ },
294
+ build: {
295
+ context: '.',
296
+ dockerfile: 'Tests-WordPress.Dockerfile',
297
+ args: imageBuildArgs,
298
+ },
299
+ ports: [ testsPorts ],
300
+ environment: {
301
+ APACHE_RUN_USER: '#' + hostUser.uid,
302
+ APACHE_RUN_GROUP: '#' + hostUser.gid,
303
+ ...dbEnv.credentials,
304
+ ...dbEnv.tests,
305
+ WP_TESTS_DIR: '/wordpress-phpunit',
306
+ },
307
+ volumes: testsMounts,
308
+ extra_hosts: [ 'host.docker.internal:host-gateway' ],
309
+ };
310
+ services[ 'tests-cli' ] = {
311
+ depends_on: [ 'tests-wordpress' ],
312
+ build: {
313
+ context: '.',
314
+ dockerfile: 'Tests-CLI.Dockerfile',
315
+ args: imageBuildArgs,
316
+ },
317
+ volumes: testsMounts,
318
+ user: hostUser.fullUser,
319
+ environment: {
320
+ ...dbEnv.credentials,
321
+ ...dbEnv.tests,
322
+ WP_TESTS_DIR: '/wordpress-phpunit',
323
+ },
324
+ extra_hosts: [ 'host.docker.internal:host-gateway' ],
325
+ };
326
+ services[ 'tests-phpmyadmin' ] = {
327
+ image: 'phpmyadmin',
328
+ ports: [ testsPhpmyadminPorts ],
329
+ environment: {
330
+ PMA_PORT: 3306,
331
+ PMA_HOST: 'tests-mysql',
332
+ PMA_USER: 'root',
333
+ PMA_PASSWORD: 'password',
334
+ },
335
+ };
336
+
337
+ if ( ! config.env.tests.coreSource ) {
338
+ volumes[ 'tests-wordpress' ] = {};
339
+ }
340
+ volumes[ 'mysql-test' ] = {};
341
+ volumes[ 'tests-user-home' ] = {};
342
+ }
343
+
344
+ return { services, volumes };
306
345
  };
@@ -0,0 +1,63 @@
1
+ 'use strict';
2
+ /**
3
+ * Internal dependencies
4
+ */
5
+ const { downloadSource } = require( '../../download-sources' );
6
+
7
+ /**
8
+ * @typedef {import('./config').WPConfig} WPConfig
9
+ * @typedef {import('./config').WPSource} WPSource
10
+ */
11
+
12
+ /**
13
+ * Download each source for each environment. If the same source is used in
14
+ * multiple environments, it will only be downloaded once.
15
+ *
16
+ * @param {WPConfig} config The wp-env configuration object.
17
+ * @param {Object} spinner The spinner object to show progress.
18
+ * @return {Promise} Returns a promise which resolves when the downloads finish.
19
+ */
20
+ module.exports = function downloadSources( config, spinner ) {
21
+ const progresses = {};
22
+ const getProgressSetter = ( id ) => ( progress ) => {
23
+ progresses[ id ] = progress;
24
+ spinner.text =
25
+ 'Downloading WordPress.\n' +
26
+ Object.entries( progresses )
27
+ .map(
28
+ ( [ key, value ] ) =>
29
+ ` - ${ key }: ${ ( value * 100 ).toFixed( 0 ) }%`
30
+ )
31
+ .join( '\n' );
32
+ };
33
+
34
+ // Will contain a unique array of sources to download.
35
+ const sources = [];
36
+ const addedSources = {};
37
+ const addSource = ( source ) => {
38
+ if ( source && source.url && ! addedSources[ source.url ] ) {
39
+ sources.push( source );
40
+ addedSources[ source.url ] = true;
41
+ }
42
+ };
43
+
44
+ for ( const envName of Object.keys( config.env ) ) {
45
+ if ( envName === 'tests' && config.testsEnvironment === false ) {
46
+ continue;
47
+ }
48
+ const env = config.env[ envName ];
49
+ env.pluginSources.forEach( addSource );
50
+ env.themeSources.forEach( addSource );
51
+ Object.values( env.mappings ).forEach( addSource );
52
+ addSource( env.coreSource );
53
+ }
54
+
55
+ return Promise.all(
56
+ sources.map( ( source ) =>
57
+ downloadSource( source, {
58
+ onProgress: getProgressSetter( source.basename ),
59
+ spinner,
60
+ } )
61
+ )
62
+ );
63
+ };
@@ -2,9 +2,9 @@
2
2
  /**
3
3
  * External dependencies
4
4
  */
5
- const SimpleGit = require( 'simple-git' );
6
5
  const fs = require( 'fs' );
7
6
  const path = require( 'path' );
7
+ const SimpleGit = require( 'simple-git' );
8
8
 
9
9
  /**
10
10
  * @typedef {import('./config').WPConfig} WPConfig
@@ -40,6 +40,9 @@ module.exports = function downloadWPPHPUnit(
40
40
 
41
41
  const promises = [];
42
42
  for ( const env in config.env ) {
43
+ if ( env === 'tests' && config.testsEnvironment === false ) {
44
+ continue;
45
+ }
43
46
  const wpVersion = wpVersions[ env ] ? wpVersions[ env ] : null;
44
47
  const directory = path.join(
45
48
  config.workDirectoryPath,