@wordpress/env 4.5.0 → 4.7.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,11 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 4.7.0 (2022-05-18)
6
+
7
+ ### Enhancement
8
+ - Added SSH protocol support for git sources
9
+
5
10
  ## 4.2.0 (2022-01-27)
6
11
 
7
12
  ### Enhancement
package/README.md CHANGED
@@ -460,12 +460,13 @@ _Note: the port number environment variables (`WP_ENV_PORT` and `WP_ENV_TESTS_PO
460
460
 
461
461
  Several types of strings can be passed into the `core`, `plugins`, `themes`, and `mappings` fields.
462
462
 
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"` |
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
+ | SSH repository | `ssh://user@host/<owner>/<repo>.git[#<ref>]` | `"ssh://git@github.com/WordPress/WordPress.git"` |
469
+ | ZIP File | `http[s]://<host>/<path>.zip` | `"https://wordpress.org/wordpress-5.4-beta2.zip"` |
469
470
 
470
471
  Remote sources will be downloaded into a temporary directory located in `~/.wp-env`.
471
472
 
@@ -534,9 +535,9 @@ This is useful for plugin development.
534
535
  }
535
536
  ```
536
537
 
537
- #### Latest development WordPress + current directory as a plugin
538
+ ### Latest development WordPress + current directory as a plugin
538
539
 
539
- This is useful for plugin development when upstream Core changes need to be tested.
540
+ This is useful for plugin development when upstream Core changes need to be tested. This can also be set via the environment variable `WP_ENV_CORE`.
540
541
 
541
542
  ```json
542
543
  {
@@ -13,6 +13,7 @@ const detectDirectoryType = require( './detect-directory-type' );
13
13
  const { validateConfig, ValidationError } = require( './validate-config' );
14
14
  const readRawConfigFile = require( './read-raw-config-file' );
15
15
  const parseConfig = require( './parse-config' );
16
+ const { includeTestsPath, parseSourceString } = parseConfig;
16
17
  const md5 = require( '../md5' );
17
18
 
18
19
  /**
@@ -256,6 +257,18 @@ function withOverrides( config ) {
256
257
  getNumberFromEnvVariable( 'WP_ENV_TESTS_PORT' ) ||
257
258
  config.env.tests.port;
258
259
 
260
+ // Override WordPress core with environment variable.
261
+ if ( process.env.WP_ENV_CORE ) {
262
+ const coreSource = includeTestsPath(
263
+ parseSourceString( process.env.WP_ENV_CORE, {
264
+ workDirectoryPath: config.workDirectoryPath,
265
+ } ),
266
+ { workDirectoryPath: config.workDirectoryPath }
267
+ );
268
+ config.env.development.coreSource = coreSource;
269
+ config.env.tests.coreSource = coreSource;
270
+ }
271
+
259
272
  // Override PHP version with environment variable.
260
273
  config.env.development.phpVersion =
261
274
  process.env.WP_ENV_PHP_VERSION || config.env.development.phpVersion;
@@ -114,6 +114,33 @@ 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 ) || 'master',
137
+ path: workingPath,
138
+ clonePath: workingPath,
139
+ basename,
140
+ };
141
+ }
142
+ } catch ( err ) {}
143
+
117
144
  const gitHubFields = sourceString.match(
118
145
  /^([^\/]+)\/([^#\/]+)(\/([^#]+))?(?:#(.+))?$/
119
146
  );
@@ -136,6 +163,7 @@ function parseSourceString( sourceString, { workDirectoryPath } ) {
136
163
  `Invalid or unrecognized source: "${ sourceString }".`
137
164
  );
138
165
  }
166
+ module.exports.parseSourceString = parseSourceString;
139
167
 
140
168
  /**
141
169
  * Given a source object, returns a new source object with the testsPath
@@ -160,3 +188,4 @@ function includeTestsPath( source, { workDirectoryPath } ) {
160
188
  ),
161
189
  };
162
190
  }
191
+ module.exports.includeTestsPath = includeTestsPath;
@@ -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
  } );
@@ -378,21 +396,21 @@ describe( 'readConfig', () => {
378
396
  type: 'git',
379
397
  url: 'https://github.com/WordPress/gutenberg.git',
380
398
  ref: 'master',
381
- path: expect.stringMatching( /^\/.*gutenberg$/ ),
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
  {
@@ -401,7 +419,7 @@ describe( 'readConfig', () => {
401
419
  'https://github.com/WordPress/theme-experiments.git',
402
420
  ref: 'tt1-blocks@0.4.3',
403
421
  path: expect.stringMatching(
404
- /^\/.*theme-experiments\/tt1-blocks$/
422
+ /^(\/||\\).*theme-experiments(\/||\\)tt1-blocks$/
405
423
  ),
406
424
  basename: 'tt1-blocks',
407
425
  },
@@ -431,28 +449,32 @@ describe( 'readConfig', () => {
431
449
  type: 'zip',
432
450
  url:
433
451
  'https://downloads.wordpress.org/plugin/gutenberg.zip',
434
- path: expect.stringMatching( /^\/.*gutenberg$/ ),
452
+ path: expect.stringMatching( /^(\/||\\).*gutenberg$/ ),
435
453
  basename: 'gutenberg',
436
454
  },
437
455
  {
438
456
  type: 'zip',
439
457
  url:
440
458
  'https://downloads.wordpress.org/plugin/gutenberg.8.1.0.zip',
441
- path: expect.stringMatching( /^\/.*gutenberg$/ ),
459
+ path: expect.stringMatching( /^(\/||\\).*gutenberg$/ ),
442
460
  basename: 'gutenberg',
443
461
  },
444
462
  {
445
463
  type: 'zip',
446
464
  url:
447
465
  'https://downloads.wordpress.org/theme/twentytwenty.zip',
448
- path: expect.stringMatching( /^\/.*twentytwenty$/ ),
466
+ path: expect.stringMatching(
467
+ /^(\/||\\).*twentytwenty$/
468
+ ),
449
469
  basename: 'twentytwenty',
450
470
  },
451
471
  {
452
472
  type: 'zip',
453
473
  url:
454
474
  'https://downloads.wordpress.org/theme/twentytwenty.1.3.zip',
455
- path: expect.stringMatching( /^\/.*twentytwenty$/ ),
475
+ path: expect.stringMatching(
476
+ /^(\/||\\).*twentytwenty$/
477
+ ),
456
478
  basename: 'twentytwenty',
457
479
  },
458
480
  ],
@@ -482,34 +504,42 @@ describe( 'readConfig', () => {
482
504
  type: 'zip',
483
505
  url:
484
506
  'https://www.example.com/test/path/to/gutenberg.zip',
485
- path: expect.stringMatching( /^\/.*gutenberg$/ ),
507
+ path: expect.stringMatching( /^(\/||\\).*gutenberg$/ ),
486
508
  basename: 'gutenberg',
487
509
  },
488
510
  {
489
511
  type: 'zip',
490
512
  url:
491
513
  'https://www.example.com/test/path/to/gutenberg.8.1.0.zip',
492
- path: expect.stringMatching( /^\/.*gutenberg.8.1.0$/ ),
514
+ path: expect.stringMatching(
515
+ /^(\/||\\).*gutenberg.8.1.0$/
516
+ ),
493
517
  basename: 'gutenberg.8.1.0',
494
518
  },
495
519
  {
496
520
  type: 'zip',
497
521
  url:
498
522
  'https://www.example.com/test/path/to/twentytwenty.zip',
499
- path: expect.stringMatching( /^\/.*twentytwenty$/ ),
523
+ path: expect.stringMatching(
524
+ /^(\/||\\).*twentytwenty$/
525
+ ),
500
526
  basename: 'twentytwenty',
501
527
  },
502
528
  {
503
529
  type: 'zip',
504
530
  url:
505
531
  'https://www.example.com/test/path/to/twentytwenty.1.3.zip',
506
- path: expect.stringMatching( /^\/.*twentytwenty.1.3$/ ),
532
+ path: expect.stringMatching(
533
+ /^(\/||\\).*twentytwenty.1.3$/
534
+ ),
507
535
  basename: 'twentytwenty.1.3',
508
536
  },
509
537
  {
510
538
  type: 'zip',
511
539
  url: 'https://example.com/twentytwenty.1.3.zip',
512
- path: expect.stringMatching( /^\/.*twentytwenty.1.3$/ ),
540
+ path: expect.stringMatching(
541
+ /^(\/||\\).*twentytwenty.1.3$/
542
+ ),
513
543
  basename: 'twentytwenty.1.3',
514
544
  },
515
545
  ],
@@ -550,12 +580,12 @@ describe( 'readConfig', () => {
550
580
  const matchObj = {
551
581
  test: {
552
582
  type: 'local',
553
- path: expect.stringMatching( /^\/.*relative$/ ),
583
+ path: expect.stringMatching( /^(\/||\\).*relative$/ ),
554
584
  basename: 'relative',
555
585
  },
556
586
  test2: {
557
587
  type: 'git',
558
- path: expect.stringMatching( /^\/.*gutenberg$/ ),
588
+ path: expect.stringMatching( /^(\/||\\).*gutenberg$/ ),
559
589
  basename: 'gutenberg',
560
590
  },
561
591
  };
@@ -653,24 +683,25 @@ describe( 'readConfig', () => {
653
683
  expect( config.env.development.mappings ).toEqual( {
654
684
  test1: {
655
685
  basename: 'test1',
656
- path: '/test1',
686
+ // resolve is required to remove drive letters on Windows.
687
+ path: resolve( '/test1' ),
657
688
  type: 'local',
658
689
  },
659
690
  test3: {
660
691
  basename: 'test3',
661
- path: '/test3',
692
+ path: resolve( '/test3' ),
662
693
  type: 'local',
663
694
  },
664
695
  } );
665
696
  expect( config.env.tests.mappings ).toEqual( {
666
697
  test1: {
667
698
  basename: 'test1',
668
- path: '/test1',
699
+ path: resolve( '/test1' ),
669
700
  type: 'local',
670
701
  },
671
702
  test2: {
672
703
  basename: 'test2',
673
- path: '/test2',
704
+ path: resolve( '/test2' ),
674
705
  type: 'local',
675
706
  },
676
707
  } );
@@ -702,14 +733,14 @@ describe( 'readConfig', () => {
702
733
  expect( config.env.development.mappings ).toEqual( {
703
734
  test: {
704
735
  basename: 'test3',
705
- path: '/test3',
736
+ path: resolve( '/test3' ),
706
737
  type: 'local',
707
738
  },
708
739
  } );
709
740
  expect( config.env.tests.mappings ).toEqual( {
710
741
  test: {
711
742
  basename: 'test2',
712
- path: '/test2',
743
+ path: resolve( '/test2' ),
713
744
  type: 'local',
714
745
  },
715
746
  } );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/env",
3
- "version": "4.5.0",
3
+ "version": "4.7.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": "11eb1241e63c9240018323551c6753f8a5fa96f9"
54
+ "gitHead": "198fa129cf1af8dc615918987ea6795cd40ab7df"
55
55
  }