@wordpress/env 4.9.0 → 5.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/CHANGELOG.md CHANGED
@@ -2,7 +2,21 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 5.0.0 (2022-07-27)
6
+
7
+ ### Breaking Changes
8
+ - Removed the `WP_PHPUNIT__TESTS_CONFIG` environment variable from the `phpunit` container. **This removes automatic support for the `wp-phpunit/wp-phpunit` Composer package. To continue using the package, set the following two environment variables in your `phpunit.xml` file or similar: `WP_TESTS_DIR=""` and `WP_PHPUNIT__TESTS_CONFIG="/wordpress-phpunit/wp-tests-config.php"`.**
9
+ - Removed the generated `/var/www/html/phpunit-wp-config.php` file from the environment.
10
+
11
+ ### Enhancement
12
+ - Read WordPress' version and include the corresponding PHPUnit test files in the environment.
13
+ - Set the `WP_TESTS_DIR` environment variable in all containers to point at the PHPUnit test files.
14
+
15
+ ### Bug Fix
16
+ - Restrict `WP_TESTS_DOMAIN` constant to just hostname rather than an entire URL (e.g. it now excludes scheme, port, etc.) ([#41039](https://github.com/WordPress/gutenberg/pull/41039)).
17
+
5
18
  ## 4.8.0 (2022-06-01)
19
+
6
20
  ### Enhancement
7
21
  - Removed the need for quotation marks when passing options to `wp-env run`.
8
22
  - Setting a `config` key to `null` will prevent adding the constant to `wp-config.php` even if a default value is defined by `wp-env`.
package/README.md CHANGED
@@ -188,6 +188,14 @@ wp-env start --debug
188
188
  ...
189
189
  ```
190
190
 
191
+ ## Using included WordPress PHPUnit test files
192
+
193
+ Out of the box `wp-env` includes the [WordPress' PHPUnit test files](https://develop.svn.wordpress.org/trunk/tests/phpunit/) corresponding to the version of WordPress installed. There is an environment variable, `WP_TESTS_DIR`, which points to the location of these files within each container. By including these files in the environment, we remove the need for you to use a package or install and mount them yourself. If you do not want to use these files, you should ignore the `WP_TESTS_DIR` environment variable and load them from the location of your choosing.
194
+
195
+ ### Customizing the `wp-tests-config.php` file
196
+
197
+ While we do provide a default `wp-tests-config.php` file within the environment, there may be cases where you want to use your own. WordPress provides a `WP_TESTS_CONFIG_FILE_PATH` constant that you can use to change the `wp-config.php` file used for testing. Set this to a desired path in your `bootstrap.php` file and the file you've chosen will be used instead of the one included in the environment.
198
+
191
199
  ## Using Xdebug
192
200
 
193
201
  Xdebug is installed in the wp-env environment, but it is turned off by default. To enable Xdebug, you can use the `--xdebug` flag with the `wp-env start` command. Here is a reference to how the flag works:
@@ -511,7 +519,7 @@ SCRIPT_DEBUG: true,
511
519
  WP_PHP_BINARY: 'php',
512
520
  WP_TESTS_EMAIL: 'admin@example.org',
513
521
  WP_TESTS_TITLE: 'Test Blog',
514
- WP_TESTS_DOMAIN: 'http://localhost',
522
+ WP_TESTS_DOMAIN: 'localhost',
515
523
  WP_SITEURL: 'http://localhost',
516
524
  WP_HOME: 'http://localhost',
517
525
  ```
@@ -19,13 +19,18 @@ const { dbEnv } = require( './config' );
19
19
  /**
20
20
  * Gets the volume mounts for an individual service.
21
21
  *
22
- * @param {WPServiceConfig} config The service config to get the mounts from.
23
- * @param {string} wordpressDefault The default internal path for the WordPress
24
- * source code (such as tests-wordpress).
22
+ * @param {string} workDirectoryPath The working directory for wp-env.
23
+ * @param {WPServiceConfig} config The service config to get the mounts from.
24
+ * @param {string} wordpressDefault The default internal path for the WordPress
25
+ * source code (such as tests-wordpress).
25
26
  *
26
27
  * @return {string[]} An array of volumes to mount in string format.
27
28
  */
28
- function getMounts( config, wordpressDefault = 'wordpress' ) {
29
+ function getMounts(
30
+ workDirectoryPath,
31
+ config,
32
+ wordpressDefault = 'wordpress'
33
+ ) {
29
34
  // Top-level WordPress directory mounts (like wp-content/themes)
30
35
  const directoryMounts = Object.entries( config.mappings ).map(
31
36
  ( [ wpDir, source ] ) => `${ source.path }:/var/www/html/${ wpDir }`
@@ -45,9 +50,19 @@ function getMounts( config, wordpressDefault = 'wordpress' ) {
45
50
  config.coreSource ? config.coreSource.path : wordpressDefault
46
51
  }:/var/www/html`;
47
52
 
53
+ const corePHPUnitMount = `${ path.join(
54
+ workDirectoryPath,
55
+ wordpressDefault === 'wordpress'
56
+ ? 'WordPress-PHPUnit'
57
+ : 'tests-WordPress-PHPUnit',
58
+ 'tests',
59
+ 'phpunit'
60
+ ) }:/wordpress-phpunit`;
61
+
48
62
  return [
49
63
  ...new Set( [
50
64
  coreMount,
65
+ corePHPUnitMount,
51
66
  ...directoryMounts,
52
67
  ...pluginMounts,
53
68
  ...themeMounts,
@@ -64,8 +79,15 @@ function getMounts( config, wordpressDefault = 'wordpress' ) {
64
79
  * @return {Object} A docker-compose config object, ready to serialize into YAML.
65
80
  */
66
81
  module.exports = function buildDockerComposeConfig( config ) {
67
- const developmentMounts = getMounts( config.env.development );
68
- const testsMounts = getMounts( config.env.tests, 'tests-wordpress' );
82
+ const developmentMounts = getMounts(
83
+ config.workDirectoryPath,
84
+ config.env.development
85
+ );
86
+ const testsMounts = getMounts(
87
+ config.workDirectoryPath,
88
+ config.env.tests,
89
+ 'tests-wordpress'
90
+ );
69
91
 
70
92
  // When both tests and development reference the same WP source, we need to
71
93
  // ensure that tests pulls from a copy of the files so that it maintains
@@ -208,6 +230,7 @@ module.exports = function buildDockerComposeConfig( config ) {
208
230
  environment: {
209
231
  ...dbEnv.credentials,
210
232
  ...dbEnv.development,
233
+ WP_TESTS_DIR: '/wordpress-phpunit',
211
234
  },
212
235
  volumes: developmentMounts,
213
236
  },
@@ -218,6 +241,7 @@ module.exports = function buildDockerComposeConfig( config ) {
218
241
  environment: {
219
242
  ...dbEnv.credentials,
220
243
  ...dbEnv.tests,
244
+ WP_TESTS_DIR: '/wordpress-phpunit',
221
245
  },
222
246
  volumes: testsMounts,
223
247
  },
@@ -229,6 +253,7 @@ module.exports = function buildDockerComposeConfig( config ) {
229
253
  environment: {
230
254
  ...dbEnv.credentials,
231
255
  ...dbEnv.development,
256
+ WP_TESTS_DIR: '/wordpress-phpunit',
232
257
  },
233
258
  },
234
259
  'tests-cli': {
@@ -239,6 +264,7 @@ module.exports = function buildDockerComposeConfig( config ) {
239
264
  environment: {
240
265
  ...dbEnv.credentials,
241
266
  ...dbEnv.tests,
267
+ WP_TESTS_DIR: '/wordpress-phpunit',
242
268
  },
243
269
  },
244
270
  composer: {
@@ -256,8 +282,7 @@ module.exports = function buildDockerComposeConfig( config ) {
256
282
  ],
257
283
  environment: {
258
284
  LOCAL_DIR: 'html',
259
- WP_PHPUNIT__TESTS_CONFIG:
260
- '/var/www/html/phpunit-wp-config.php',
285
+ WP_TESTS_DIR: '/wordpress-phpunit',
261
286
  ...dbEnv.credentials,
262
287
  ...dbEnv.tests,
263
288
  },
@@ -9,7 +9,7 @@ const { spawn } = require( 'child_process' );
9
9
  const initConfig = require( '../init-config' );
10
10
 
11
11
  /**
12
- * @typedef {import('../config').Config} Config
12
+ * @typedef {import('../config').WPConfig} WPConfig
13
13
  */
14
14
 
15
15
  /**
@@ -42,11 +42,11 @@ module.exports = async function run( { container, command, spinner, debug } ) {
42
42
  /**
43
43
  * Runs an arbitrary command on the given Docker container.
44
44
  *
45
- * @param {Object} options
46
- * @param {string} options.container The Docker container to run the command on.
47
- * @param {string} options.command The command to run.
48
- * @param {Config} options.config The wp-env configuration.
49
- * @param {Object} options.spinner A CLI spinner which indicates progress.
45
+ * @param {Object} options
46
+ * @param {string} options.container The Docker container to run the command on.
47
+ * @param {string} options.command The command to run.
48
+ * @param {WPConfig} options.config The wp-env configuration.
49
+ * @param {Object} options.spinner A CLI spinner which indicates progress.
50
50
  */
51
51
  function spawnCommandDirectly( { container, command, config, spinner } ) {
52
52
  const composeCommand = [
@@ -21,16 +21,18 @@ const retry = require( '../retry' );
21
21
  const stop = require( './stop' );
22
22
  const initConfig = require( '../init-config' );
23
23
  const downloadSources = require( '../download-sources' );
24
+ const downloadWPPHPUnit = require( '../download-wp-phpunit' );
24
25
  const {
25
26
  checkDatabaseConnection,
26
27
  configureWordPress,
27
28
  setupWordPressDirectories,
29
+ readWordPressVersion,
28
30
  } = require( '../wordpress' );
29
31
  const { didCacheChange, setCache } = require( '../cache' );
30
32
  const md5 = require( '../md5' );
31
33
 
32
34
  /**
33
- * @typedef {import('../config').Config} Config
35
+ * @typedef {import('../config').WPConfig} WPConfig
34
36
  */
35
37
  const CONFIG_CACHE_KEY = 'config_checksum';
36
38
 
@@ -127,7 +129,25 @@ module.exports = async function start( { spinner, debug, update, xdebug } ) {
127
129
  ] );
128
130
 
129
131
  if ( shouldConfigureWp ) {
132
+ spinner.text = 'Setting up WordPress directories';
133
+
130
134
  await setupWordPressDirectories( config );
135
+
136
+ // Use the WordPress versions to download the PHPUnit suite.
137
+ const wpVersions = await Promise.all( [
138
+ readWordPressVersion(
139
+ config.env.development.coreSource,
140
+ spinner,
141
+ debug
142
+ ),
143
+ readWordPressVersion( config.env.tests.coreSource, spinner, debug ),
144
+ ] );
145
+ await downloadWPPHPUnit(
146
+ config,
147
+ { development: wpVersions[ 0 ], tests: wpVersions[ 1 ] },
148
+ spinner,
149
+ debug
150
+ );
131
151
  }
132
152
 
133
153
  spinner.text = 'Starting WordPress.';
@@ -173,7 +193,7 @@ module.exports = async function start( { spinner, debug, update, xdebug } ) {
173
193
  }
174
194
 
175
195
  const siteUrl = config.env.development.config.WP_SITEURL;
176
- const e2eSiteUrl = config.env.tests.config.WP_TESTS_DOMAIN;
196
+ const e2eSiteUrl = `http://${ config.env.tests.config.WP_TESTS_DOMAIN }:${ config.env.tests.port }/`;
177
197
 
178
198
  const { out: mySQLAddress } = await dockerCompose.port(
179
199
  'mysql',
@@ -83,7 +83,7 @@ module.exports = async function readConfig( configPath ) {
83
83
  WP_PHP_BINARY: 'php',
84
84
  WP_TESTS_EMAIL: 'admin@example.org',
85
85
  WP_TESTS_TITLE: 'Test Blog',
86
- WP_TESTS_DOMAIN: 'http://localhost',
86
+ WP_TESTS_DOMAIN: 'localhost',
87
87
  WP_SITEURL: 'http://localhost',
88
88
  WP_HOME: 'http://localhost',
89
89
  },
@@ -297,7 +297,6 @@ function withOverrides( config ) {
297
297
  };
298
298
 
299
299
  // Update wp config options to include the correct port number in the URL.
300
- updateEnvUrl( 'WP_TESTS_DOMAIN' );
301
300
  updateEnvUrl( 'WP_SITEURL' );
302
301
  updateEnvUrl( 'WP_HOME' );
303
302
 
@@ -17,7 +17,7 @@ Object {
17
17
  "WP_HOME": "http://localhost:2000/",
18
18
  "WP_PHP_BINARY": "php",
19
19
  "WP_SITEURL": "http://localhost:2000/",
20
- "WP_TESTS_DOMAIN": "http://localhost:2000/",
20
+ "WP_TESTS_DOMAIN": "localhost",
21
21
  "WP_TESTS_EMAIL": "admin@example.org",
22
22
  "WP_TESTS_TITLE": "Test Blog",
23
23
  },
@@ -40,7 +40,7 @@ Object {
40
40
  "WP_HOME": "http://localhost:1000/",
41
41
  "WP_PHP_BINARY": "php",
42
42
  "WP_SITEURL": "http://localhost:1000/",
43
- "WP_TESTS_DOMAIN": "http://localhost:1000/",
43
+ "WP_TESTS_DOMAIN": "localhost",
44
44
  "WP_TESTS_EMAIL": "admin@example.org",
45
45
  "WP_TESTS_TITLE": "Test Blog",
46
46
  },
@@ -64,7 +64,7 @@ Object {
64
64
  "WP_HOME": "http://localhost:8889/",
65
65
  "WP_PHP_BINARY": "php",
66
66
  "WP_SITEURL": "http://localhost:8889/",
67
- "WP_TESTS_DOMAIN": "http://localhost:8889/",
67
+ "WP_TESTS_DOMAIN": "localhost",
68
68
  "WP_TESTS_EMAIL": "admin@example.org",
69
69
  "WP_TESTS_TITLE": "Test Blog",
70
70
  }
@@ -78,7 +78,7 @@ Object {
78
78
  "WP_HOME": "http://localhost:8888/",
79
79
  "WP_PHP_BINARY": "php",
80
80
  "WP_SITEURL": "http://localhost:8888/",
81
- "WP_TESTS_DOMAIN": "http://localhost:8888/",
81
+ "WP_TESTS_DOMAIN": "localhost",
82
82
  "WP_TESTS_EMAIL": "admin@example.org",
83
83
  "WP_TESTS_TITLE": "Test Blog",
84
84
  }
@@ -265,17 +265,17 @@ describe( 'readConfig', () => {
265
265
  pluginSources: [
266
266
  {
267
267
  type: 'local',
268
- path: expect.stringMatching( /^(\/||\\).*relative$/ ),
268
+ path: expect.stringMatching( /^(\/|\\).*relative$/ ),
269
269
  basename: 'relative',
270
270
  },
271
271
  {
272
272
  type: 'local',
273
- path: expect.stringMatching( /^(\/||\\).*parent$/ ),
273
+ path: expect.stringMatching( /^(\/|\\).*parent$/ ),
274
274
  basename: 'parent',
275
275
  },
276
276
  {
277
277
  type: 'local',
278
- path: expect.stringMatching( /^(\/||\\).*home$/ ),
278
+ path: expect.stringMatching( /^(\/|\\).*home$/ ),
279
279
  basename: 'home',
280
280
  },
281
281
  ],
@@ -284,17 +284,17 @@ describe( 'readConfig', () => {
284
284
  pluginSources: [
285
285
  {
286
286
  type: 'local',
287
- path: expect.stringMatching( /^(\/||\\).*relative$/ ),
287
+ path: expect.stringMatching( /^(\/|\\).*relative$/ ),
288
288
  basename: 'relative',
289
289
  },
290
290
  {
291
291
  type: 'local',
292
- path: expect.stringMatching( /^(\/||\\).*parent$/ ),
292
+ path: expect.stringMatching( /^(\/|\\).*parent$/ ),
293
293
  basename: 'parent',
294
294
  },
295
295
  {
296
296
  type: 'local',
297
- path: expect.stringMatching( /^(\/||\\).*home$/ ),
297
+ path: expect.stringMatching( /^(\/|\\).*home$/ ),
298
298
  basename: 'home',
299
299
  },
300
300
  ],
@@ -324,28 +324,28 @@ describe( 'readConfig', () => {
324
324
  expect( config.env.development.pluginSources ).toEqual( [
325
325
  {
326
326
  type: 'local',
327
- path: expect.stringMatching( /^(\/||\\).*test1a$/ ),
327
+ path: expect.stringMatching( /^(\/|\\).*test1a$/ ),
328
328
  basename: 'test1a',
329
329
  },
330
330
  ] );
331
331
  expect( config.env.development.themeSources ).toEqual( [
332
332
  {
333
333
  type: 'local',
334
- path: expect.stringMatching( /^(\/||\\).*test2a$/ ),
334
+ path: expect.stringMatching( /^(\/|\\).*test2a$/ ),
335
335
  basename: 'test2a',
336
336
  },
337
337
  ] );
338
338
  expect( config.env.tests.pluginSources ).toEqual( [
339
339
  {
340
340
  type: 'local',
341
- path: expect.stringMatching( /^(\/||\\).*test1b$/ ),
341
+ path: expect.stringMatching( /^(\/|\\).*test1b$/ ),
342
342
  basename: 'test1b',
343
343
  },
344
344
  ] );
345
345
  expect( config.env.tests.themeSources ).toEqual( [
346
346
  {
347
347
  type: 'local',
348
- path: expect.stringMatching( /^(\/||\\).*test2b$/ ),
348
+ path: expect.stringMatching( /^(\/|\\).*test2b$/ ),
349
349
  basename: 'test2b',
350
350
  },
351
351
  ] );
@@ -359,18 +359,18 @@ describe( 'readConfig', () => {
359
359
  expect( config.env.development ).toMatchObject( {
360
360
  coreSource: {
361
361
  type: 'local',
362
- path: expect.stringMatching( /^(\/||\\).*relative$/ ),
362
+ path: expect.stringMatching( /^(\/|\\).*relative$/ ),
363
363
  testsPath: expect.stringMatching(
364
- /^(\/||\\).*tests-relative$/
364
+ /^(\/|\\).*tests-relative$/
365
365
  ),
366
366
  },
367
367
  } );
368
368
  expect( config.env.tests ).toMatchObject( {
369
369
  coreSource: {
370
370
  type: 'local',
371
- path: expect.stringMatching( /^(\/||\\).*relative$/ ),
371
+ path: expect.stringMatching( /^(\/|\\).*relative$/ ),
372
372
  testsPath: expect.stringMatching(
373
- /^(\/||\\).*tests-relative$/
373
+ /^(\/|\\).*tests-relative$/
374
374
  ),
375
375
  },
376
376
  } );
@@ -396,21 +396,21 @@ describe( 'readConfig', () => {
396
396
  type: 'git',
397
397
  url: 'https://github.com/WordPress/gutenberg.git',
398
398
  ref: undefined,
399
- path: expect.stringMatching( /^(\/||\\).*gutenberg$/ ),
399
+ path: expect.stringMatching( /^(\/|\\).*gutenberg$/ ),
400
400
  basename: 'gutenberg',
401
401
  },
402
402
  {
403
403
  type: 'git',
404
404
  url: 'https://github.com/WordPress/gutenberg.git',
405
405
  ref: 'trunk',
406
- path: expect.stringMatching( /^(\/||\\).*gutenberg$/ ),
406
+ path: expect.stringMatching( /^(\/|\\).*gutenberg$/ ),
407
407
  basename: 'gutenberg',
408
408
  },
409
409
  {
410
410
  type: 'git',
411
411
  url: 'https://github.com/WordPress/gutenberg.git',
412
412
  ref: '5.0',
413
- path: expect.stringMatching( /^(\/||\\).*gutenberg$/ ),
413
+ path: expect.stringMatching( /^(\/|\\).*gutenberg$/ ),
414
414
  basename: 'gutenberg',
415
415
  },
416
416
  {
@@ -418,7 +418,7 @@ describe( 'readConfig', () => {
418
418
  url: 'https://github.com/WordPress/theme-experiments.git',
419
419
  ref: 'tt1-blocks@0.4.3',
420
420
  path: expect.stringMatching(
421
- /^(\/||\\).*theme-experiments(\/||\\)tt1-blocks$/
421
+ /^(\/|\\).*theme-experiments(\/|\\)tt1-blocks$/
422
422
  ),
423
423
  basename: 'tt1-blocks',
424
424
  },
@@ -447,20 +447,20 @@ describe( 'readConfig', () => {
447
447
  {
448
448
  type: 'zip',
449
449
  url: 'https://downloads.wordpress.org/plugin/gutenberg.zip',
450
- path: expect.stringMatching( /^(\/||\\).*gutenberg$/ ),
450
+ path: expect.stringMatching( /^(\/|\\).*gutenberg$/ ),
451
451
  basename: 'gutenberg',
452
452
  },
453
453
  {
454
454
  type: 'zip',
455
455
  url: 'https://downloads.wordpress.org/plugin/gutenberg.8.1.0.zip',
456
- path: expect.stringMatching( /^(\/||\\).*gutenberg$/ ),
456
+ path: expect.stringMatching( /^(\/|\\).*gutenberg$/ ),
457
457
  basename: 'gutenberg',
458
458
  },
459
459
  {
460
460
  type: 'zip',
461
461
  url: 'https://downloads.wordpress.org/theme/twentytwenty.zip',
462
462
  path: expect.stringMatching(
463
- /^(\/||\\).*twentytwenty$/
463
+ /^(\/|\\).*twentytwenty$/
464
464
  ),
465
465
  basename: 'twentytwenty',
466
466
  },
@@ -468,7 +468,7 @@ describe( 'readConfig', () => {
468
468
  type: 'zip',
469
469
  url: 'https://downloads.wordpress.org/theme/twentytwenty.1.3.zip',
470
470
  path: expect.stringMatching(
471
- /^(\/||\\).*twentytwenty$/
471
+ /^(\/|\\).*twentytwenty$/
472
472
  ),
473
473
  basename: 'twentytwenty',
474
474
  },
@@ -498,14 +498,14 @@ describe( 'readConfig', () => {
498
498
  {
499
499
  type: 'zip',
500
500
  url: 'https://www.example.com/test/path/to/gutenberg.zip',
501
- path: expect.stringMatching( /^(\/||\\).*gutenberg$/ ),
501
+ path: expect.stringMatching( /^(\/|\\).*gutenberg$/ ),
502
502
  basename: 'gutenberg',
503
503
  },
504
504
  {
505
505
  type: 'zip',
506
506
  url: 'https://www.example.com/test/path/to/gutenberg.8.1.0.zip',
507
507
  path: expect.stringMatching(
508
- /^(\/||\\).*gutenberg.8.1.0$/
508
+ /^(\/|\\).*gutenberg.8.1.0$/
509
509
  ),
510
510
  basename: 'gutenberg.8.1.0',
511
511
  },
@@ -513,7 +513,7 @@ describe( 'readConfig', () => {
513
513
  type: 'zip',
514
514
  url: 'https://www.example.com/test/path/to/twentytwenty.zip',
515
515
  path: expect.stringMatching(
516
- /^(\/||\\).*twentytwenty$/
516
+ /^(\/|\\).*twentytwenty$/
517
517
  ),
518
518
  basename: 'twentytwenty',
519
519
  },
@@ -521,7 +521,7 @@ describe( 'readConfig', () => {
521
521
  type: 'zip',
522
522
  url: 'https://www.example.com/test/path/to/twentytwenty.1.3.zip',
523
523
  path: expect.stringMatching(
524
- /^(\/||\\).*twentytwenty.1.3$/
524
+ /^(\/|\\).*twentytwenty.1.3$/
525
525
  ),
526
526
  basename: 'twentytwenty.1.3',
527
527
  },
@@ -529,7 +529,7 @@ describe( 'readConfig', () => {
529
529
  type: 'zip',
530
530
  url: 'https://example.com/twentytwenty.1.3.zip',
531
531
  path: expect.stringMatching(
532
- /^(\/||\\).*twentytwenty.1.3$/
532
+ /^(\/|\\).*twentytwenty.1.3$/
533
533
  ),
534
534
  basename: 'twentytwenty.1.3',
535
535
  },
@@ -571,12 +571,12 @@ describe( 'readConfig', () => {
571
571
  const matchObj = {
572
572
  test: {
573
573
  type: 'local',
574
- path: expect.stringMatching( /^(\/||\\).*relative$/ ),
574
+ path: expect.stringMatching( /^(\/|\\).*relative$/ ),
575
575
  basename: 'relative',
576
576
  },
577
577
  test2: {
578
578
  type: 'git',
579
- path: expect.stringMatching( /^(\/||\\).*gutenberg$/ ),
579
+ path: expect.stringMatching( /^(\/|\\).*gutenberg$/ ),
580
580
  basename: 'gutenberg',
581
581
  },
582
582
  };
@@ -804,7 +804,7 @@ describe( 'readConfig', () => {
804
804
  development: {
805
805
  port: 1000,
806
806
  config: {
807
- WP_TESTS_DOMAIN: 'http://localhost:1000/',
807
+ WP_TESTS_DOMAIN: 'localhost',
808
808
  WP_SITEURL: 'http://localhost:1000/',
809
809
  WP_HOME: 'http://localhost:1000/',
810
810
  },
@@ -812,7 +812,7 @@ describe( 'readConfig', () => {
812
812
  tests: {
813
813
  port: 2000,
814
814
  config: {
815
- WP_TESTS_DOMAIN: 'http://localhost:2000/',
815
+ WP_TESTS_DOMAIN: 'localhost',
816
816
  WP_SITEURL: 'http://localhost:2000/',
817
817
  WP_HOME: 'http://localhost:2000/',
818
818
  },
@@ -840,7 +840,7 @@ describe( 'readConfig', () => {
840
840
  development: {
841
841
  port: 1000,
842
842
  config: {
843
- WP_TESTS_DOMAIN: 'http://localhost:1000/',
843
+ WP_TESTS_DOMAIN: 'localhost',
844
844
  WP_SITEURL: 'http://localhost:1000/',
845
845
  WP_HOME: 'http://localhost:3000/',
846
846
  },
@@ -848,7 +848,7 @@ describe( 'readConfig', () => {
848
848
  tests: {
849
849
  port: 2000,
850
850
  config: {
851
- WP_TESTS_DOMAIN: 'http://localhost:2000/',
851
+ WP_TESTS_DOMAIN: 'localhost',
852
852
  WP_SITEURL: 'http://localhost:2000/',
853
853
  WP_HOME: 'http://localhost:3000/',
854
854
  },
@@ -1103,7 +1103,7 @@ describe( 'readConfig', () => {
1103
1103
  WP_PHP_BINARY: 'php',
1104
1104
  WP_TESTS_EMAIL: 'admin@example.org',
1105
1105
  WP_TESTS_TITLE: 'Test Blog',
1106
- WP_TESTS_DOMAIN: 'http://localhost:8889/',
1106
+ WP_TESTS_DOMAIN: 'localhost',
1107
1107
  WP_SITEURL: 'http://localhost:8889/',
1108
1108
  WP_HOME: 'http://localhost:8889/',
1109
1109
  } );
@@ -1117,7 +1117,7 @@ describe( 'readConfig', () => {
1117
1117
  WP_PHP_BINARY: 'php',
1118
1118
  WP_TESTS_EMAIL: 'admin@example.org',
1119
1119
  WP_TESTS_TITLE: 'Test Blog',
1120
- WP_TESTS_DOMAIN: 'http://localhost:8888/',
1120
+ WP_TESTS_DOMAIN: 'localhost',
1121
1121
  WP_SITEURL: 'http://localhost:8888/',
1122
1122
  WP_HOME: 'http://localhost:8888/',
1123
1123
  } );
@@ -16,7 +16,7 @@ const extractZip = util.promisify( require( 'extract-zip' ) );
16
16
  const rimraf = util.promisify( require( 'rimraf' ) );
17
17
 
18
18
  /**
19
- * @typedef {import('./config').Config} Config
19
+ * @typedef {import('./config').WPConfig} WPConfig
20
20
  * @typedef {import('./config').WPSource} WPSource
21
21
  */
22
22
 
@@ -24,8 +24,8 @@ const rimraf = util.promisify( require( 'rimraf' ) );
24
24
  * Download each source for each environment. If the same source is used in
25
25
  * multiple environments, it will only be downloaded once.
26
26
  *
27
- * @param {Config} config The wp-env configuration object.
28
- * @param {Object} spinner The spinner object to show progress.
27
+ * @param {WPConfig} config The wp-env configuration object.
28
+ * @param {Object} spinner The spinner object to show progress.
29
29
  * @return {Promise} Returns a promise which resolves when the downloads finish.
30
30
  */
31
31
  module.exports = function downloadSources( config, spinner ) {
@@ -0,0 +1,140 @@
1
+ 'use strict';
2
+ /**
3
+ * External dependencies
4
+ */
5
+ const SimpleGit = require( 'simple-git' );
6
+ const fs = require( 'fs' );
7
+ const path = require( 'path' );
8
+
9
+ /**
10
+ * @typedef {import('./config').WPConfig} WPConfig
11
+ */
12
+
13
+ /**
14
+ * Downloads the WordPress PHPUnit files for each environment into the appropriate directories.
15
+ *
16
+ * @param {WPConfig} config The wp-env config object.
17
+ * @param {Object} wpVersions The WordPress versions for each environment.
18
+ * @param {Object} spinner The spinner object to show progress.
19
+ * @param {boolean} debug Indicates whether or not debug mode is active.
20
+ * @return {Promise} Returns a promise which resolves when the downloads finish.
21
+ */
22
+ module.exports = function downloadWPPHPUnit(
23
+ config,
24
+ wpVersions,
25
+ spinner,
26
+ debug
27
+ ) {
28
+ const progresses = {};
29
+ const getProgressSetter = ( id ) => ( progress ) => {
30
+ progresses[ id ] = progress;
31
+ spinner.text =
32
+ 'Downloading WordPress PHPUnit Suite.\n' +
33
+ Object.entries( progresses )
34
+ .map(
35
+ ( [ key, value ] ) =>
36
+ ` - ${ key }: ${ ( value * 100 ).toFixed( 0 ) }/100%`
37
+ )
38
+ .join( '\n' );
39
+ };
40
+
41
+ const promises = [];
42
+ for ( const env in config.env ) {
43
+ const wpVersion = wpVersions[ env ] ? wpVersions[ env ] : null;
44
+ const directory = path.join(
45
+ config.workDirectoryPath,
46
+ env === 'development'
47
+ ? 'WordPress-PHPUnit'
48
+ : 'tests-WordPress-PHPUnit'
49
+ );
50
+ promises.push(
51
+ downloadTestSuite( directory, wpVersion, {
52
+ onProgress: getProgressSetter,
53
+ spinner,
54
+ debug,
55
+ } )
56
+ );
57
+ }
58
+
59
+ return Promise.all( promises );
60
+ };
61
+
62
+ /**
63
+ * Downloads the PHPUnit tests for a given WordPress version into the appropriate directory.
64
+ *
65
+ * @param {string} directory The directory to place the PHPUnit tests in.
66
+ * @param {string} wpVersion The version of WordPress to install PHPUnit tests for. Trunk when empty.
67
+ * @param {Object} options
68
+ * @param {Function} options.onProgress A function called with download progress. Will be invoked with one argument: a number that ranges from 0 to 1 which indicates current download progress for this source.
69
+ * @param {Object} options.spinner A CLI spinner which indicates progress.
70
+ * @param {boolean} options.debug True if debug mode is enabled.
71
+ */
72
+ async function downloadTestSuite(
73
+ directory,
74
+ wpVersion,
75
+ { onProgress, spinner, debug }
76
+ ) {
77
+ const log = debug
78
+ ? ( message ) => {
79
+ spinner.info( `SimpleGit: ${ message }` );
80
+ spinner.start();
81
+ }
82
+ : () => {};
83
+ onProgress( 0 );
84
+
85
+ const progressHandler = ( { progress } ) => {
86
+ onProgress( progress / 100 );
87
+ };
88
+
89
+ // Make sure that the version is in X.X.X format. This is required
90
+ // because WordPress/wordpress-develop uses X.X.X tags but
91
+ // WordPress uses X.X for non-patch releases.
92
+ if ( wpVersion && wpVersion.match( /^[0-9]+.[0-9]+$/ ) ) {
93
+ wpVersion += '.0';
94
+ }
95
+
96
+ log( 'Cloning or getting the PHPUnit suite from GitHub.' );
97
+ const git = SimpleGit( { progress: progressHandler } );
98
+
99
+ const isRepo =
100
+ fs.existsSync( directory ) &&
101
+ ( await git.cwd( directory ).checkIsRepo( 'root' ) );
102
+
103
+ if ( isRepo ) {
104
+ log( 'Repo already exists, using it.' );
105
+ } else {
106
+ await git.clone(
107
+ 'https://github.com/WordPress/wordpress-develop.git',
108
+ directory,
109
+ {
110
+ '--depth': '1',
111
+ '--no-checkout': null,
112
+ }
113
+ );
114
+ await git.cwd( directory );
115
+
116
+ // We use a sparse checkout to minimize the amount of data we need to download.
117
+ log( 'Enabling sparse checkout.' );
118
+ await git.raw( 'sparse-checkout', 'set', '--cone', 'tests/phpunit' );
119
+ }
120
+
121
+ // Figure out the ref that we need to checkout to get the correct version of the PHPUnit library.
122
+ // Alpha, Beta, and RC versions are bleeding edge and should pull from trunk.
123
+ let ref;
124
+ const fetchRaw = [];
125
+ if ( ! wpVersion || wpVersion.match( /-(?:alpha|beta|rc)/ ) ) {
126
+ ref = 'trunk';
127
+ fetchRaw.push( 'fetch', 'origin', ref, '--depth', '1' );
128
+ } else {
129
+ ref = `tags/${ wpVersion }`;
130
+ fetchRaw.push( 'fetch', 'origin', 'tag', wpVersion, '--depth', '1' );
131
+ }
132
+
133
+ log( `Fetching ${ ref }.` );
134
+ await git.raw( fetchRaw );
135
+
136
+ log( `Checking out ${ ref }.` );
137
+ await git.checkout( ref );
138
+
139
+ onProgress( 1 );
140
+ }
package/lib/wordpress.js CHANGED
@@ -14,6 +14,7 @@ const copyDir = util.promisify( require( 'copy-dir' ) );
14
14
  /**
15
15
  * @typedef {import('./config').WPConfig} WPConfig
16
16
  * @typedef {import('./config').WPServiceConfig} WPServiceConfig
17
+ * @typedef {import('./config').WPSource} WPSource
17
18
  * @typedef {'development'|'tests'} WPEnvironment
18
19
  * @typedef {'development'|'tests'|'all'} WPEnvironmentSelection
19
20
  */
@@ -101,25 +102,15 @@ async function configureWordPress( environment, config, spinner ) {
101
102
  }
102
103
  );
103
104
 
104
- /**
105
- * Since wp-phpunit loads wp-settings.php at the end of its wp-config.php
106
- * file, we need to avoid loading it too early in our own wp-config.php. If
107
- * we load it too early, then some things (like MULTISITE) will be defined
108
- * before wp-phpunit has a chance to configure them. To avoid this, create a
109
- * copy of wp-config.php for phpunit which doesn't require wp-settings.php.
110
- *
111
- * Note that This needs to be executed using `exec` on the wordpress service
112
- * so that file permissions work properly.
113
- *
114
- * This will be removed in the future. @see https://github.com/WordPress/gutenberg/issues/23171
115
- *
116
- */
105
+ // WordPress' PHPUnit suite expects a `wp-tests-config.php` in
106
+ // the directory that the test suite is contained within.
107
+ // Make sure ABSPATH points to the WordPress install.
117
108
  await dockerCompose.exec(
118
109
  environment === 'development' ? 'wordpress' : 'tests-wordpress',
119
110
  [
120
111
  'sh',
121
112
  '-c',
122
- 'sed "/^require.*wp-settings.php/d" /var/www/html/wp-config.php > /var/www/html/phpunit-wp-config.php && chmod 777 /var/www/html/phpunit-wp-config.php',
113
+ `sed -e "/^require.*wp-settings.php/d" -e "s/define( 'ABSPATH', __DIR__ . '\\/' );/define( 'ABSPATH', '\\/var\\/www\\/html\\/' );\\n\\tdefine( 'WP_DEFAULT_THEME', 'default' );/" /var/www/html/wp-config.php > /wordpress-phpunit/wp-tests-config.php`,
123
114
  ],
124
115
  {
125
116
  config: config.dockerComposeConfigPath,
@@ -246,10 +237,49 @@ async function copyCoreFiles( fromPath, toPath ) {
246
237
  } );
247
238
  }
248
239
 
240
+ /**
241
+ * Scans through a WordPress source to find the version of WordPress it contains.
242
+ *
243
+ * @param {WPSource} coreSource The WordPress source.
244
+ * @param {Object} spinner A CLI spinner which indicates progress.
245
+ * @param {boolean} debug Indicates whether or not the CLI is in debug mode.
246
+ * @return {string} The version of WordPress the source is for.
247
+ */
248
+ async function readWordPressVersion( coreSource, spinner, debug ) {
249
+ // No source means they're using the bleeding edge.
250
+ if ( coreSource === null ) {
251
+ return null;
252
+ }
253
+
254
+ const versionFilePath = path.join(
255
+ coreSource.path,
256
+ 'wp-includes',
257
+ 'version.php'
258
+ );
259
+ const versionFile = await fs.readFile( versionFilePath, {
260
+ encoding: 'utf-8',
261
+ } );
262
+ const versionMatch = versionFile.match(
263
+ /\$wp_version = '([A-Za-z\-0-9.]+)'/
264
+ );
265
+ if ( ! versionMatch ) {
266
+ throw new Error( `Failed to find version in ${ versionFilePath }` );
267
+ }
268
+
269
+ if ( debug ) {
270
+ spinner.info(
271
+ `Found WordPress ${ versionMatch[ 1 ] } in ${ versionFilePath }.`
272
+ );
273
+ }
274
+
275
+ return versionMatch[ 1 ];
276
+ }
277
+
249
278
  module.exports = {
250
279
  hasSameCoreSource,
251
280
  checkDatabaseConnection,
252
281
  configureWordPress,
253
282
  resetDatabase,
254
283
  setupWordPressDirectories,
284
+ readWordPressVersion,
255
285
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/env",
3
- "version": "4.9.0",
3
+ "version": "5.0.0",
4
4
  "description": "A zero-config, self contained local WordPress environment for development and testing.",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -36,7 +36,7 @@
36
36
  "copy-dir": "^1.3.0",
37
37
  "docker-compose": "^0.22.2",
38
38
  "extract-zip": "^1.6.7",
39
- "got": "^10.7.0",
39
+ "got": "^11.8.5",
40
40
  "inquirer": "^7.1.0",
41
41
  "js-yaml": "^3.13.1",
42
42
  "ora": "^4.0.2",
@@ -51,5 +51,5 @@
51
51
  "scripts": {
52
52
  "test": "echo \"Error: run tests from root\" && exit 1"
53
53
  },
54
- "gitHead": "48d5f37dfb52d2e77c8eeb662f9874cf141b8c6b"
54
+ "gitHead": "0315dbc240cb2aa146d7c1bafd251f004b88300e"
55
55
  }