@wordpress/env 4.6.0 → 4.9.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,6 +2,16 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 4.8.0 (2022-06-01)
6
+ ### Enhancement
7
+ - Removed the need for quotation marks when passing options to `wp-env run`.
8
+ - 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`.
9
+
10
+ ## 4.7.0 (2022-05-18)
11
+
12
+ ### Enhancement
13
+ - Added SSH protocol support for git sources
14
+
5
15
  ## 4.2.0 (2022-01-27)
6
16
 
7
17
  ### Enhancement
package/README.md CHANGED
@@ -300,21 +300,23 @@ Positionals:
300
300
  The run command can be used to open shell sessions or invoke WP-CLI commands.
301
301
 
302
302
  <div class="callout callout-alert">
303
- To run a WP-CLI command that includes optional arguments, enclose the WP-CLI command in quotation marks; otherwise, the optional arguments are ignored. This is because flags are normally passed to `wp-env` itself, meaning that the flags are not considered part of the argument that specifies the WP-CLI command. With quotation marks, `wp-env` considers everything inside quotation marks the WP-CLI command argument.
303
+ In some cases, `wp-env` may consume options that you are attempting to pass to
304
+ the container. This happens with options that `wp-env` has already declared,
305
+ such as `--debug`, `--help`, and `--version`. When this happens, you should fall
306
+ back to using quotation marks; `wp-env` considers everything inside the
307
+ quotation marks to be command argument.
304
308
 
305
- For example, to list cron schedules with optional arguments that specify the fields returned and the format of the output:
309
+ For example, to ask `WP-CLI` for its help text:
306
310
 
307
311
  ```sh
308
- wp-env run cli "wp cron schedule list --fields=name --format=csv"
312
+ wp-env run cli "wp --help"
309
313
  ```
310
314
 
311
- Without the quotation marks, WP-CLI lists the schedule in its default format, ignoring the `fields` and `format` arguments.
315
+ Without the quotation marks, `wp-env` will print its own help text instead of
316
+ passing it to the container. If you experience any problems where the command
317
+ is not being passed correctly, fall back to using quotation marks.
312
318
  </div>
313
319
 
314
- Note that quotation marks are not required for a WP-CLI command that excludes optional arguments, although it does not hurt to include them. For example, the following command syntaxes return identical results: `wp-env run cli "wp cron schedule list"` or `wp-env run cli wp cron schedule list`.
315
-
316
- For more information about all the available commands, see [WP-CLI Commands](https://developer.wordpress.org/cli/commands/).
317
-
318
320
  ```sh
319
321
  wp-env run <container> [command..]
320
322
 
@@ -323,11 +325,7 @@ Runs an arbitrary command in one of the underlying Docker containers. The
323
325
  "development", "tests", or "cli". To run a wp-cli command, use the "cli" or
324
326
  "tests-cli" service. You can also use this command to open shell sessions like
325
327
  bash and the WordPress shell in the WordPress instance. For example, `wp-env run
326
- cli bash` will open bash in the development WordPress instance. When using long
327
- commands with arguments and quotation marks, you need to wrap the "command"
328
- param in quotation marks. For example: `wp-env run tests-cli "wp post create
329
- --post_type=page --post_title='Test'"` will create a post on the tests WordPress
330
- instance.
328
+ cli bash` will open bash in the development WordPress instance.
331
329
 
332
330
  Positionals:
333
331
  container The container to run the command on. [string] [required]
@@ -460,12 +458,13 @@ _Note: the port number environment variables (`WP_ENV_PORT` and `WP_ENV_TESTS_PO
460
458
 
461
459
  Several types of strings can be passed into the `core`, `plugins`, `themes`, and `mappings` fields.
462
460
 
463
- | Type | Format | Example(s) |
464
- | ----------------- | ----------------------------- | -------------------------------------------------------- |
465
- | Relative path | `.<path>\|~<path>` | `"./a/directory"`, `"../a/directory"`, `"~/a/directory"` |
466
- | Absolute path | `/<path>\|<letter>:\<path>` | `"/a/directory"`, `"C:\\a\\directory"` |
467
- | GitHub repository | `<owner>/<repo>[#<ref>]` | `"WordPress/WordPress"`, `"WordPress/gutenberg#trunk"` |
468
- | ZIP File | `http[s]://<host>/<path>.zip` | `"https://wordpress.org/wordpress-5.4-beta2.zip"` |
461
+ | Type | Format | Example(s) |
462
+ | ----------------- | -------------------------------------------- | -------------------------------------------------------- |
463
+ | Relative path | `.<path>\|~<path>` | `"./a/directory"`, `"../a/directory"`, `"~/a/directory"` |
464
+ | Absolute path | `/<path>\|<letter>:\<path>` | `"/a/directory"`, `"C:\\a\\directory"` |
465
+ | GitHub repository | `<owner>/<repo>[#<ref>]` | `"WordPress/WordPress"`, `"WordPress/gutenberg#trunk"`, if no branch is provided wp-env will fall back to the repos default branch |
466
+ | SSH repository | `ssh://user@host/<owner>/<repo>.git[#<ref>]` | `"ssh://git@github.com/WordPress/WordPress.git"` |
467
+ | ZIP File | `http[s]://<host>/<path>.zip` | `"https://wordpress.org/wordpress-5.4-beta2.zip"` |
469
468
 
470
469
  Remote sources will be downloaded into a temporary directory located in `~/.wp-env`.
471
470
 
@@ -519,6 +518,8 @@ WP_HOME: 'http://localhost',
519
518
 
520
519
  On the test instance, all of the above are still defined, but `WP_DEBUG` and `SCRIPT_DEBUG` are set to false.
521
520
 
521
+ These can be overridden by setting a value within the `config` configuration. Setting it to `null` will prevent the constant being defined entirely.
522
+
522
523
  Additionally, the values referencing a URL include the specified port for the given environment. So if you set `testsPort: 3000, port: 2000`, `WP_HOME` (for example) will be `http://localhost:3000` on the tests instance and `http://localhost:2000` on the development instance.
523
524
 
524
525
  ### Examples
package/lib/cli.js CHANGED
@@ -22,57 +22,61 @@ const wpRed = boldWhite.bgHex( '#d94f4f' );
22
22
  const wpYellow = boldWhite.bgHex( '#f0b849' );
23
23
 
24
24
  // Spinner.
25
- const withSpinner = ( command ) => ( ...args ) => {
26
- const spinner = ora().start();
27
- args[ 0 ].spinner = spinner;
28
- let time = process.hrtime();
29
- return command( ...args ).then(
30
- ( message ) => {
31
- time = process.hrtime( time );
32
- spinner.succeed(
33
- `${ message || spinner.text } (in ${ time[ 0 ] }s ${ (
34
- time[ 1 ] / 1e6
35
- ).toFixed( 0 ) }ms)`
36
- );
37
- process.exit( 0 );
38
- },
39
- ( error ) => {
40
- if ( error instanceof env.ValidationError ) {
41
- // Error is a validation error. That means the user did something wrong.
42
- spinner.fail( error.message );
43
- process.exit( 1 );
44
- } else if (
45
- error &&
46
- typeof error === 'object' &&
47
- 'exitCode' in error &&
48
- 'err' in error &&
49
- 'out' in error
50
- ) {
51
- // Error is a docker-compose error. That means something docker-related failed.
52
- // https://github.com/PDMLab/docker-compose/blob/HEAD/src/index.ts
53
- spinner.fail( 'Error while running docker-compose command.' );
54
- if ( error.out ) {
55
- process.stdout.write( error.out );
56
- }
57
- if ( error.err ) {
58
- process.stderr.write( error.err );
59
- }
60
- process.exit( error.exitCode );
61
- } else if ( error ) {
62
- // Error is an unknown error. That means there was a bug in our code.
63
- spinner.fail(
64
- typeof error === 'string' ? error : error.message
25
+ const withSpinner =
26
+ ( command ) =>
27
+ ( ...args ) => {
28
+ const spinner = ora().start();
29
+ args[ 0 ].spinner = spinner;
30
+ let time = process.hrtime();
31
+ return command( ...args ).then(
32
+ ( message ) => {
33
+ time = process.hrtime( time );
34
+ spinner.succeed(
35
+ `${ message || spinner.text } (in ${ time[ 0 ] }s ${ (
36
+ time[ 1 ] / 1e6
37
+ ).toFixed( 0 ) }ms)`
65
38
  );
66
- // Disable reason: Using console.error() means we get a stack trace.
67
- console.error( error );
68
- process.exit( 1 );
69
- } else {
70
- spinner.fail( 'An unknown error occured.' );
71
- process.exit( 1 );
39
+ process.exit( 0 );
40
+ },
41
+ ( error ) => {
42
+ if ( error instanceof env.ValidationError ) {
43
+ // Error is a validation error. That means the user did something wrong.
44
+ spinner.fail( error.message );
45
+ process.exit( 1 );
46
+ } else if (
47
+ error &&
48
+ typeof error === 'object' &&
49
+ 'exitCode' in error &&
50
+ 'err' in error &&
51
+ 'out' in error
52
+ ) {
53
+ // Error is a docker-compose error. That means something docker-related failed.
54
+ // https://github.com/PDMLab/docker-compose/blob/HEAD/src/index.ts
55
+ spinner.fail(
56
+ 'Error while running docker-compose command.'
57
+ );
58
+ if ( error.out ) {
59
+ process.stdout.write( error.out );
60
+ }
61
+ if ( error.err ) {
62
+ process.stderr.write( error.err );
63
+ }
64
+ process.exit( error.exitCode );
65
+ } else if ( error ) {
66
+ // Error is an unknown error. That means there was a bug in our code.
67
+ spinner.fail(
68
+ typeof error === 'string' ? error : error.message
69
+ );
70
+ // Disable reason: Using console.error() means we get a stack trace.
71
+ console.error( error );
72
+ process.exit( 1 );
73
+ } else {
74
+ spinner.fail( 'An unknown error occured.' );
75
+ process.exit( 1 );
76
+ }
72
77
  }
73
- }
74
- );
75
- };
78
+ );
79
+ };
76
80
 
77
81
  module.exports = function cli() {
78
82
  // Do nothing if Docker is unavailable.
@@ -92,6 +96,10 @@ module.exports = function cli() {
92
96
  default: false,
93
97
  } );
94
98
 
99
+ // Make sure any unknown arguments are passed to the command as arguments.
100
+ // This allows options to be passed to "run" without being quoted.
101
+ yargs.parserConfiguration( { 'unknown-options-as-args': true } );
102
+
95
103
  yargs.command(
96
104
  'start',
97
105
  wpGreen(
@@ -171,7 +179,7 @@ module.exports = function cli() {
171
179
  describe: 'The container to run the command on.',
172
180
  } );
173
181
  args.positional( 'command', {
174
- type: 'string',
182
+ type: 'array',
175
183
  describe: 'The command to run.',
176
184
  } );
177
185
  },
@@ -189,6 +197,7 @@ module.exports = function cli() {
189
197
  '$0 run tests-cli bash',
190
198
  'Open a bash session in the WordPress tests instance.'
191
199
  );
200
+
192
201
  yargs.command(
193
202
  'destroy',
194
203
  wpRed(
@@ -114,14 +114,42 @@ function parseSourceString( sourceString, { workDirectoryPath } ) {
114
114
  };
115
115
  }
116
116
 
117
+ // SSH URLs (git)
118
+ const supportedProtocols = [ 'ssh:', 'git+ssh:' ];
119
+ try {
120
+ const sshUrl = new URL( sourceString );
121
+ if ( supportedProtocols.includes( sshUrl.protocol ) ) {
122
+ const pathElements = sshUrl.pathname
123
+ .split( '/' )
124
+ .filter( ( e ) => !! e );
125
+ const basename = pathElements
126
+ .slice( -1 )[ 0 ]
127
+ .replace( /\.git/, '' );
128
+ const workingPath = path.resolve(
129
+ workDirectoryPath,
130
+ ...pathElements.slice( 0, -1 ),
131
+ basename
132
+ );
133
+ return {
134
+ type: 'git',
135
+ url: sshUrl.href.split( '#' )[ 0 ],
136
+ ref: sshUrl.hash.slice( 1 ) || undefined,
137
+ path: workingPath,
138
+ clonePath: workingPath,
139
+ basename,
140
+ };
141
+ }
142
+ } catch ( err ) {}
143
+
117
144
  const gitHubFields = sourceString.match(
118
145
  /^([^\/]+)\/([^#\/]+)(\/([^#]+))?(?:#(.+))?$/
119
146
  );
147
+
120
148
  if ( gitHubFields ) {
121
149
  return {
122
150
  type: 'git',
123
151
  url: `https://github.com/${ gitHubFields[ 1 ] }/${ gitHubFields[ 2 ] }.git`,
124
- ref: gitHubFields[ 5 ] || 'master',
152
+ ref: gitHubFields[ 5 ],
125
153
  path: path.resolve(
126
154
  workDirectoryPath,
127
155
  gitHubFields[ 2 ],
@@ -4,6 +4,7 @@
4
4
  */
5
5
  const { readFile, stat } = require( 'fs' ).promises;
6
6
  const os = require( 'os' );
7
+ const { join, resolve } = require( 'path' );
7
8
 
8
9
  /**
9
10
  * Internal dependencies
@@ -101,13 +102,17 @@ describe( 'readConfig', () => {
101
102
  process.env.WP_ENV_HOME = 'here/is/a/path';
102
103
  const configWith = await readConfig( '.wp-env.json' );
103
104
  expect(
104
- configWith.workDirectoryPath.includes( 'here/is/a/path' )
105
+ configWith.workDirectoryPath.includes(
106
+ join( 'here', 'is', 'a', 'path' )
107
+ )
105
108
  ).toBe( true );
106
109
 
107
110
  process.env.WP_ENV_HOME = undefined;
108
111
  const configWithout = await readConfig( '.wp-env.json' );
109
112
  expect(
110
- configWithout.workDirectoryPath.includes( 'here/is/a/path' )
113
+ configWithout.workDirectoryPath.includes(
114
+ join( 'here', 'is', 'a', 'path' )
115
+ )
111
116
  ).toBe( false );
112
117
 
113
118
  process.env.WP_ENV_HOME = oldEnvHome;
@@ -126,13 +131,17 @@ describe( 'readConfig', () => {
126
131
  process.env.WP_ENV_HOME = 'here/is/a/path';
127
132
  const configWith = await readConfig( '.wp-env.json' );
128
133
  expect(
129
- configWith.workDirectoryPath.includes( 'here/is/a/path' )
134
+ configWith.workDirectoryPath.includes(
135
+ join( 'here', 'is', 'a', 'path' )
136
+ )
130
137
  ).toBe( true );
131
138
 
132
139
  process.env.WP_ENV_HOME = undefined;
133
140
  const configWithout = await readConfig( '.wp-env.json' );
134
141
  expect(
135
- configWithout.workDirectoryPath.includes( 'here/is/a/path' )
142
+ configWithout.workDirectoryPath.includes(
143
+ join( 'here', 'is', 'a', 'path' )
144
+ )
136
145
  ).toBe( false );
137
146
 
138
147
  process.env.WP_ENV_HOME = oldEnvHome;
@@ -242,26 +251,31 @@ describe( 'readConfig', () => {
242
251
  readFile.mockImplementation( () =>
243
252
  Promise.resolve(
244
253
  JSON.stringify( {
245
- plugins: [ './relative', '../parent', '~/home' ],
254
+ plugins: [
255
+ './relative',
256
+ '../parent',
257
+ `${ os.homedir() }/home`,
258
+ ],
246
259
  } )
247
260
  )
248
261
  );
249
262
  const config = await readConfig( '.wp-env.json' );
263
+
250
264
  expect( config.env.development ).toMatchObject( {
251
265
  pluginSources: [
252
266
  {
253
267
  type: 'local',
254
- path: expect.stringMatching( /^\/.*relative$/ ),
268
+ path: expect.stringMatching( /^(\/||\\).*relative$/ ),
255
269
  basename: 'relative',
256
270
  },
257
271
  {
258
272
  type: 'local',
259
- path: expect.stringMatching( /^\/.*parent$/ ),
273
+ path: expect.stringMatching( /^(\/||\\).*parent$/ ),
260
274
  basename: 'parent',
261
275
  },
262
276
  {
263
277
  type: 'local',
264
- path: expect.stringMatching( /^\/.*home$/ ),
278
+ path: expect.stringMatching( /^(\/||\\).*home$/ ),
265
279
  basename: 'home',
266
280
  },
267
281
  ],
@@ -270,17 +284,17 @@ describe( 'readConfig', () => {
270
284
  pluginSources: [
271
285
  {
272
286
  type: 'local',
273
- path: expect.stringMatching( /^\/.*relative$/ ),
287
+ path: expect.stringMatching( /^(\/||\\).*relative$/ ),
274
288
  basename: 'relative',
275
289
  },
276
290
  {
277
291
  type: 'local',
278
- path: expect.stringMatching( /^\/.*parent$/ ),
292
+ path: expect.stringMatching( /^(\/||\\).*parent$/ ),
279
293
  basename: 'parent',
280
294
  },
281
295
  {
282
296
  type: 'local',
283
- path: expect.stringMatching( /^\/.*home$/ ),
297
+ path: expect.stringMatching( /^(\/||\\).*home$/ ),
284
298
  basename: 'home',
285
299
  },
286
300
  ],
@@ -310,28 +324,28 @@ describe( 'readConfig', () => {
310
324
  expect( config.env.development.pluginSources ).toEqual( [
311
325
  {
312
326
  type: 'local',
313
- path: expect.stringMatching( /^\/.*test1a$/ ),
327
+ path: expect.stringMatching( /^(\/||\\).*test1a$/ ),
314
328
  basename: 'test1a',
315
329
  },
316
330
  ] );
317
331
  expect( config.env.development.themeSources ).toEqual( [
318
332
  {
319
333
  type: 'local',
320
- path: expect.stringMatching( /^\/.*test2a$/ ),
334
+ path: expect.stringMatching( /^(\/||\\).*test2a$/ ),
321
335
  basename: 'test2a',
322
336
  },
323
337
  ] );
324
338
  expect( config.env.tests.pluginSources ).toEqual( [
325
339
  {
326
340
  type: 'local',
327
- path: expect.stringMatching( /^\/.*test1b$/ ),
341
+ path: expect.stringMatching( /^(\/||\\).*test1b$/ ),
328
342
  basename: 'test1b',
329
343
  },
330
344
  ] );
331
345
  expect( config.env.tests.themeSources ).toEqual( [
332
346
  {
333
347
  type: 'local',
334
- path: expect.stringMatching( /^\/.*test2b$/ ),
348
+ path: expect.stringMatching( /^(\/||\\).*test2b$/ ),
335
349
  basename: 'test2b',
336
350
  },
337
351
  ] );
@@ -345,15 +359,19 @@ describe( 'readConfig', () => {
345
359
  expect( config.env.development ).toMatchObject( {
346
360
  coreSource: {
347
361
  type: 'local',
348
- path: expect.stringMatching( /^\/.*relative$/ ),
349
- testsPath: expect.stringMatching( /^\/.*tests-relative$/ ),
362
+ path: expect.stringMatching( /^(\/||\\).*relative$/ ),
363
+ testsPath: expect.stringMatching(
364
+ /^(\/||\\).*tests-relative$/
365
+ ),
350
366
  },
351
367
  } );
352
368
  expect( config.env.tests ).toMatchObject( {
353
369
  coreSource: {
354
370
  type: 'local',
355
- path: expect.stringMatching( /^\/.*relative$/ ),
356
- testsPath: expect.stringMatching( /^\/.*tests-relative$/ ),
371
+ path: expect.stringMatching( /^(\/||\\).*relative$/ ),
372
+ testsPath: expect.stringMatching(
373
+ /^(\/||\\).*tests-relative$/
374
+ ),
357
375
  },
358
376
  } );
359
377
  } );
@@ -377,31 +395,30 @@ describe( 'readConfig', () => {
377
395
  {
378
396
  type: 'git',
379
397
  url: 'https://github.com/WordPress/gutenberg.git',
380
- ref: 'master',
381
- path: expect.stringMatching( /^\/.*gutenberg$/ ),
398
+ ref: undefined,
399
+ path: expect.stringMatching( /^(\/||\\).*gutenberg$/ ),
382
400
  basename: 'gutenberg',
383
401
  },
384
402
  {
385
403
  type: 'git',
386
404
  url: 'https://github.com/WordPress/gutenberg.git',
387
405
  ref: 'trunk',
388
- path: expect.stringMatching( /^\/.*gutenberg$/ ),
406
+ path: expect.stringMatching( /^(\/||\\).*gutenberg$/ ),
389
407
  basename: 'gutenberg',
390
408
  },
391
409
  {
392
410
  type: 'git',
393
411
  url: 'https://github.com/WordPress/gutenberg.git',
394
412
  ref: '5.0',
395
- path: expect.stringMatching( /^\/.*gutenberg$/ ),
413
+ path: expect.stringMatching( /^(\/||\\).*gutenberg$/ ),
396
414
  basename: 'gutenberg',
397
415
  },
398
416
  {
399
417
  type: 'git',
400
- url:
401
- 'https://github.com/WordPress/theme-experiments.git',
418
+ url: 'https://github.com/WordPress/theme-experiments.git',
402
419
  ref: 'tt1-blocks@0.4.3',
403
420
  path: expect.stringMatching(
404
- /^\/.*theme-experiments\/tt1-blocks$/
421
+ /^(\/||\\).*theme-experiments(\/||\\)tt1-blocks$/
405
422
  ),
406
423
  basename: 'tt1-blocks',
407
424
  },
@@ -429,30 +446,30 @@ describe( 'readConfig', () => {
429
446
  pluginSources: [
430
447
  {
431
448
  type: 'zip',
432
- url:
433
- 'https://downloads.wordpress.org/plugin/gutenberg.zip',
434
- path: expect.stringMatching( /^\/.*gutenberg$/ ),
449
+ url: 'https://downloads.wordpress.org/plugin/gutenberg.zip',
450
+ path: expect.stringMatching( /^(\/||\\).*gutenberg$/ ),
435
451
  basename: 'gutenberg',
436
452
  },
437
453
  {
438
454
  type: 'zip',
439
- url:
440
- 'https://downloads.wordpress.org/plugin/gutenberg.8.1.0.zip',
441
- path: expect.stringMatching( /^\/.*gutenberg$/ ),
455
+ url: 'https://downloads.wordpress.org/plugin/gutenberg.8.1.0.zip',
456
+ path: expect.stringMatching( /^(\/||\\).*gutenberg$/ ),
442
457
  basename: 'gutenberg',
443
458
  },
444
459
  {
445
460
  type: 'zip',
446
- url:
447
- 'https://downloads.wordpress.org/theme/twentytwenty.zip',
448
- path: expect.stringMatching( /^\/.*twentytwenty$/ ),
461
+ url: 'https://downloads.wordpress.org/theme/twentytwenty.zip',
462
+ path: expect.stringMatching(
463
+ /^(\/||\\).*twentytwenty$/
464
+ ),
449
465
  basename: 'twentytwenty',
450
466
  },
451
467
  {
452
468
  type: 'zip',
453
- url:
454
- 'https://downloads.wordpress.org/theme/twentytwenty.1.3.zip',
455
- path: expect.stringMatching( /^\/.*twentytwenty$/ ),
469
+ url: 'https://downloads.wordpress.org/theme/twentytwenty.1.3.zip',
470
+ path: expect.stringMatching(
471
+ /^(\/||\\).*twentytwenty$/
472
+ ),
456
473
  basename: 'twentytwenty',
457
474
  },
458
475
  ],
@@ -480,36 +497,40 @@ describe( 'readConfig', () => {
480
497
  pluginSources: [
481
498
  {
482
499
  type: 'zip',
483
- url:
484
- 'https://www.example.com/test/path/to/gutenberg.zip',
485
- path: expect.stringMatching( /^\/.*gutenberg$/ ),
500
+ url: 'https://www.example.com/test/path/to/gutenberg.zip',
501
+ path: expect.stringMatching( /^(\/||\\).*gutenberg$/ ),
486
502
  basename: 'gutenberg',
487
503
  },
488
504
  {
489
505
  type: 'zip',
490
- url:
491
- 'https://www.example.com/test/path/to/gutenberg.8.1.0.zip',
492
- path: expect.stringMatching( /^\/.*gutenberg.8.1.0$/ ),
506
+ url: 'https://www.example.com/test/path/to/gutenberg.8.1.0.zip',
507
+ path: expect.stringMatching(
508
+ /^(\/||\\).*gutenberg.8.1.0$/
509
+ ),
493
510
  basename: 'gutenberg.8.1.0',
494
511
  },
495
512
  {
496
513
  type: 'zip',
497
- url:
498
- 'https://www.example.com/test/path/to/twentytwenty.zip',
499
- path: expect.stringMatching( /^\/.*twentytwenty$/ ),
514
+ url: 'https://www.example.com/test/path/to/twentytwenty.zip',
515
+ path: expect.stringMatching(
516
+ /^(\/||\\).*twentytwenty$/
517
+ ),
500
518
  basename: 'twentytwenty',
501
519
  },
502
520
  {
503
521
  type: 'zip',
504
- url:
505
- 'https://www.example.com/test/path/to/twentytwenty.1.3.zip',
506
- path: expect.stringMatching( /^\/.*twentytwenty.1.3$/ ),
522
+ url: 'https://www.example.com/test/path/to/twentytwenty.1.3.zip',
523
+ path: expect.stringMatching(
524
+ /^(\/||\\).*twentytwenty.1.3$/
525
+ ),
507
526
  basename: 'twentytwenty.1.3',
508
527
  },
509
528
  {
510
529
  type: 'zip',
511
530
  url: 'https://example.com/twentytwenty.1.3.zip',
512
- path: expect.stringMatching( /^\/.*twentytwenty.1.3$/ ),
531
+ path: expect.stringMatching(
532
+ /^(\/||\\).*twentytwenty.1.3$/
533
+ ),
513
534
  basename: 'twentytwenty.1.3',
514
535
  },
515
536
  ],
@@ -550,12 +571,12 @@ describe( 'readConfig', () => {
550
571
  const matchObj = {
551
572
  test: {
552
573
  type: 'local',
553
- path: expect.stringMatching( /^\/.*relative$/ ),
574
+ path: expect.stringMatching( /^(\/||\\).*relative$/ ),
554
575
  basename: 'relative',
555
576
  },
556
577
  test2: {
557
578
  type: 'git',
558
- path: expect.stringMatching( /^\/.*gutenberg$/ ),
579
+ path: expect.stringMatching( /^(\/||\\).*gutenberg$/ ),
559
580
  basename: 'gutenberg',
560
581
  },
561
582
  };
@@ -653,24 +674,25 @@ describe( 'readConfig', () => {
653
674
  expect( config.env.development.mappings ).toEqual( {
654
675
  test1: {
655
676
  basename: 'test1',
656
- path: '/test1',
677
+ // resolve is required to remove drive letters on Windows.
678
+ path: resolve( '/test1' ),
657
679
  type: 'local',
658
680
  },
659
681
  test3: {
660
682
  basename: 'test3',
661
- path: '/test3',
683
+ path: resolve( '/test3' ),
662
684
  type: 'local',
663
685
  },
664
686
  } );
665
687
  expect( config.env.tests.mappings ).toEqual( {
666
688
  test1: {
667
689
  basename: 'test1',
668
- path: '/test1',
690
+ path: resolve( '/test1' ),
669
691
  type: 'local',
670
692
  },
671
693
  test2: {
672
694
  basename: 'test2',
673
- path: '/test2',
695
+ path: resolve( '/test2' ),
674
696
  type: 'local',
675
697
  },
676
698
  } );
@@ -702,14 +724,14 @@ describe( 'readConfig', () => {
702
724
  expect( config.env.development.mappings ).toEqual( {
703
725
  test: {
704
726
  basename: 'test3',
705
- path: '/test3',
727
+ path: resolve( '/test3' ),
706
728
  type: 'local',
707
729
  },
708
730
  } );
709
731
  expect( config.env.tests.mappings ).toEqual( {
710
732
  test: {
711
733
  basename: 'test2',
712
- path: '/test2',
734
+ path: resolve( '/test2' ),
713
735
  type: 'local',
714
736
  },
715
737
  } );
package/lib/wordpress.js CHANGED
@@ -64,6 +64,11 @@ async function configureWordPress( environment, config, spinner ) {
64
64
  for ( let [ key, value ] of Object.entries(
65
65
  config.env[ environment ].config
66
66
  ) ) {
67
+ // Allow the configuration to skip a default constant by specifying it as null.
68
+ if ( null === value ) {
69
+ continue;
70
+ }
71
+
67
72
  // Add quotes around string values to work with multi-word strings better.
68
73
  value = typeof value === 'string' ? `"${ value }"` : value;
69
74
  setupCommands.push(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/env",
3
- "version": "4.6.0",
3
+ "version": "4.9.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",
@@ -51,5 +51,5 @@
51
51
  "scripts": {
52
52
  "test": "echo \"Error: run tests from root\" && exit 1"
53
53
  },
54
- "gitHead": "1ba52312b56db563df2d8d4fba5b00613fb46d8c"
54
+ "gitHead": "48d5f37dfb52d2e77c8eeb662f9874cf141b8c6b"
55
55
  }