Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wp-env: Fix errors which prevent it from working without internet #53547

Merged
merged 6 commits into from
Oct 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/env/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### Enhancement

- `wp-env` now works offline after the environment has been created. Note that many `wp-env` configuration changes involve internet connectivity and may not work in offline mode. [#53547](https://github.com/WordPress/gutenberg/pull/53547)

## 8.10.0 (2023-10-18)

### Bug Fix
Expand Down
3 changes: 3 additions & 0 deletions packages/env/lib/cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ async function didCacheChange( key, value, options ) {
* @param {WPEnvCacheOptions} options Parsing options
*/
async function setCache( key, value, options ) {
// Make sure the cache directory exists.
await fs.mkdir( options.workDirectoryPath, { recursive: true } );

const existingCache = await getCacheFile( options );
existingCache[ key ] = value;

Expand Down
17 changes: 13 additions & 4 deletions packages/env/lib/commands/start.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const {
configureWordPress,
setupWordPressDirectories,
readWordPressVersion,
canAccessWPORG,
} = require( '../wordpress' );
const { didCacheChange, setCache } = require( '../cache' );
const md5 = require( '../md5' );
Expand Down Expand Up @@ -77,16 +78,24 @@ module.exports = async function start( {
const configHash = md5( config );
const { workDirectoryPath, dockerComposeConfigPath } = config;
const shouldConfigureWp =
update ||
( await didCacheChange( CONFIG_CACHE_KEY, configHash, {
workDirectoryPath,
} ) );
( update ||
( await didCacheChange( CONFIG_CACHE_KEY, configHash, {
workDirectoryPath,
} ) ) ) &&
// Don't reconfigure everything when we can't connect to the internet because
// the majority of update tasks involve connecting to the internet. (Such
// as downloading sources and pulling docker images.)
( await canAccessWPORG() );

const dockerComposeConfig = {
config: dockerComposeConfigPath,
log: config.debug,
};

if ( ! ( await canAccessWPORG() ) ) {
spinner.info( 'wp-env is offline' );
}

/**
* If the Docker image is already running and the `wp-env` files have been
* deleted, the start command will not complete successfully. Stopping
Expand Down
2 changes: 1 addition & 1 deletion packages/env/lib/config/parse-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,7 @@ async function parseEnvironmentConfig(
async function parseCoreSource( coreSource, options ) {
// An empty source means we should use the latest version of WordPress.
if ( ! coreSource ) {
const wpVersion = await getLatestWordPressVersion();
const wpVersion = await getLatestWordPressVersion( options );
if ( ! wpVersion ) {
throw new ValidationError(
'Could not find the latest WordPress version. There may be a network issue.'
Expand Down
2 changes: 2 additions & 0 deletions packages/env/lib/config/test/config-integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ jest.mock( 'fs', () => ( {
promises: {
readFile: jest.fn(),
stat: jest.fn().mockResolvedValue( true ),
mkdir: jest.fn(),
writeFile: jest.fn(),
},
} ) );

Expand Down
1 change: 1 addition & 0 deletions packages/env/lib/test/cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ jest.mock( 'fs', () => ( {
promises: {
readFile: jest.fn(),
writeFile: jest.fn(),
mkdir: jest.fn(),
},
} ) );

Expand Down
45 changes: 44 additions & 1 deletion packages/env/lib/wordpress.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,18 @@ const util = require( 'util' );
const fs = require( 'fs' ).promises;
const path = require( 'path' );
const got = require( 'got' );
const dns = require( 'dns' ).promises;

/**
* Promisified dependencies
*/
const copyDir = util.promisify( require( 'copy-dir' ) );

/**
* Internal dependencies
*/
const { getCache, setCache } = require( './cache' );

/**
* @typedef {import('./config').WPConfig} WPConfig
* @typedef {import('./config').WPEnvironmentConfig} WPEnvironmentConfig
Expand Down Expand Up @@ -243,26 +249,62 @@ async function readWordPressVersion( coreSource, spinner, debug ) {
return versionMatch[ 1 ];
}

/**
* Basically a quick check to see if we can connect to the internet.
*
* @return {boolean} True if we can connect to WordPress.org, false otherwise.
*/
let IS_OFFLINE;
async function canAccessWPORG() {
// Avoid situations where some parts of the code think we're offline and others don't.
if ( IS_OFFLINE !== undefined ) {
return IS_OFFLINE;
}
IS_OFFLINE = !! ( await dns.resolve( 'WordPress.org' ).catch( () => {} ) );
return IS_OFFLINE;
}

/**
* Returns the latest stable version of WordPress by requesting the stable-check
* endpoint on WordPress.org.
*
* @param {Object} options an object with cacheDirectoryPath set to the path to the cache directory in ~/.wp-env.
* @return {string} The latest stable version of WordPress, like "6.0.1"
*/
let CACHED_WP_VERSION;
async function getLatestWordPressVersion() {
async function getLatestWordPressVersion( options ) {
// Avoid extra network requests.
if ( CACHED_WP_VERSION ) {
return CACHED_WP_VERSION;
}

const cacheOptions = {
workDirectoryPath: options.cacheDirectoryPath,
};

// When we can't connect to the internet, we don't want to break wp-env or
// wait for the stable-check result to timeout.
if ( ! ( await canAccessWPORG() ) ) {
const latestVersion = await getCache(
'latestWordPressVersion',
cacheOptions
);
if ( ! latestVersion ) {
throw new Error(
'Could not find the current WordPress version in the cache and the network is not available.'
);
}
return latestVersion;
}

const versions = await got(
'https://api.wordpress.org/core/stable-check/1.0/'
).json();

for ( const [ version, status ] of Object.entries( versions ) ) {
if ( status === 'latest' ) {
CACHED_WP_VERSION = version;
await setCache( 'latestWordPressVersion', version, cacheOptions );
return version;
}
}
Expand All @@ -275,5 +317,6 @@ module.exports = {
resetDatabase,
setupWordPressDirectories,
readWordPressVersion,
canAccessWPORG,
getLatestWordPressVersion,
};
Loading