Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
b2ee325
Env: Add a MariaDB version validator
desrosj Sep 29, 2026
74e817f
Env: Parse the mariadbVersion option and WP_ENV_MARIADB_VERSION
desrosj Sep 29, 2026
2c66eb3
Env: Use the configured MariaDB version for the database image and he…
desrosj Sep 29, 2026
3c46564
Env: Document the mariadbVersion option and add it to the schema
desrosj Sep 29, 2026
ef273b3
Env: Detect healthcheck.sh in pinned MariaDB images instead of matchi…
desrosj Sep 29, 2026
964b1e2
Env: Link the MariaDB version changelog entry to its PR
desrosj Sep 29, 2026
ad38c10
Merge branch 'trunk' into add/database-version-control-to-wp-env
desrosj Sep 29, 2026
5cc17af
Merge branch 'trunk' into add/database-version-control-to-wp-env
desrosj Sep 29, 2026
706b900
Merge branch 'trunk' into add/database-version-control-to-wp-env
desrosj Oct 1, 2026
30874d3
Env: Fix the health check for older MariaDB images.
desrosj Oct 1, 2026
23f53b6
Env: Explain when a database was last used by a newer MariaDB.
desrosj Oct 2, 2026
80a1c59
Env: Use one MariaDB health check for every version.
desrosj Oct 2, 2026
7cc2a91
Env: Define the MariaDB image tags and default in one place.
desrosj Oct 2, 2026
91d3614
Env: Validate PHP and MariaDB versions with one anchored pattern.
desrosj Oct 2, 2026
e535c7c
Env: Test what the MariaDB health check does, not its text.
desrosj Oct 2, 2026
427f8ec
Env: Correct which MariaDB versions need emulation on ARM.
desrosj Oct 2, 2026
25a976c
Env: Name images that cannot be pulled or found locally.
desrosj Oct 2, 2026
1a602e5
Merge branch 'trunk' into add/database-version-control-to-wp-env
desrosj Oct 5, 2026
cbd1928
Env: Remove a health check test that can no longer fail.
desrosj Oct 5, 2026
8f7e27f
Env: Check the database versions in parallel.
desrosj Oct 5, 2026
17b285a
Env: Say what `wp-env cleanup` removes when suggesting it.
desrosj Oct 5, 2026
c687c83
Env: Only report a MariaDB downgrade when a database failed to start.
desrosj Oct 5, 2026
f400648
Env: Only run healthcheck.sh when the MariaDB image has it.
desrosj Oct 5, 2026
794ca55
Env: Skip the MariaDB health check shell tests on Windows.
desrosj Oct 5, 2026
478674e
Merge branch 'trunk' into add/database-version-control-to-wp-env
desrosj Oct 5, 2026
f6b0a70
Merge branch 'add/database-version-control-to-wp-env' of https://gith…
desrosj Oct 5, 2026
099afff
Env: Let `wp db` commands connect to MariaDB versions before 11.4.
desrosj Oct 5, 2026
bcbad4f
Merge branch 'trunk' into add/database-version-control-to-wp-env
desrosj Oct 6, 2026
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

### New Features

- Add a `mariadbVersion` option and `WP_ENV_MARIADB_VERSION` environment variable to choose the MariaDB version used by the Docker runtime, including versions older than 10.4 ([#83751](https://github.com/WordPress/gutenberg/pull/83751)).

### Bug Fixes

- Pass `-T` to `docker compose exec` when stdin is not a terminal, so commands run from a Git hook, which has a TTY on stdout but not on stdin, no longer fail with "cannot attach stdin to a TTY-enabled container" ([#78374](https://github.com/WordPress/gutenberg/pull/78374)).
Expand Down
17 changes: 17 additions & 0 deletions packages/env/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ $ wp-env start --runtime=playground
| MySQL database | Yes | No (SQLite) |
| Multisite | Yes | Yes |
| Custom PHP version | Yes | Yes |
| Custom MariaDB version | Yes | No (SQLite) |
| Plugin/theme mounting | Yes | Yes |
| `wp-env run` command | Yes | No |

Expand Down Expand Up @@ -601,6 +602,7 @@ To enable editor autocomplete and validation, add a `$schema` key:
|----------------------|----------------|----------------------------------------|----------------------------------------------------------------------------------------------------------------------------------|
| `"core"` | `string\|null` | `null` | The WordPress installation to use. If `null` is specified, `wp-env` will use the latest production release of WordPress. |
| `"phpVersion"` | `string\|null` | `null` | The PHP version to use. If `null` is specified, `wp-env` will use the default version used with production release of WordPress. |
| `"mariadbVersion"` | `string\|null` | `null` | The MariaDB version to use: `"lts"`, `"latest"`, or a version such as `"10.11"`. If `null` is specified, `lts` is used. |
| `"plugins"` | `string[]` | `[]` | A list of plugins to install and activate in the environment. |
| `"themes"` | `string[]` | `[]` | A list of themes to install in the environment. |
| `"port"` | `integer` | `8888` | The port number to use for the installation. |
Expand Down Expand Up @@ -827,6 +829,21 @@ You can tell `wp-env` to use a specific PHP version for compatibility and testin
}
```

### Specific MariaDB Version

You can tell `wp-env` which MariaDB version the database should run, for compatibility and testing. Use `"lts"`, `"latest"`, or a version such as `"10.11"` or `"11.4.2"`. This can also be set via the environment variable `WP_ENV_MARIADB_VERSION`, which applies to every environment. The Playground runtime uses SQLite and ignores this option.

```json
{
"mariadbVersion": "10.11",
"plugins": [ "." ]
}
```

MariaDB cannot start on a database written by a newer version. When switching to a lower version, run `wp-env destroy` first so the database is recreated.
Comment thread
desrosj marked this conversation as resolved.
Outdated

MariaDB 5.5 and 10.0 images are not published for ARM processors. On Apple silicon, run those versions under emulation by setting `DOCKER_DEFAULT_PLATFORM=linux/amd64` before running `wp-env start`.
Comment thread
desrosj marked this conversation as resolved.
Outdated

### Multisite support

You can tell `wp-env` if the site should be multisite enabled.
Expand Down
17 changes: 16 additions & 1 deletion packages/env/lib/config/get-config-from-environment-vars.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ const {
parseSourceString,
includeTestsPath,
} = require( './parse-source-string' );
const { checkPort, checkVersion, checkString } = require( './validate-config' );
const {
checkPort,
checkVersion,
checkMariaDBVersion,
checkString,
} = require( './validate-config' );

/**
* @typedef {import('./parse-source-string').WPSource} WPSource
Expand All @@ -20,6 +25,7 @@ const { checkPort, checkVersion, checkString } = require( './validate-config' );
* @property {?number} phpmyadminPort An override for the development environment's phpMyAdmin port.
* @property {?WPSource} coreSource An override for all environment's coreSource.
* @property {?string} phpVersion An override for all environment's PHP version.
* @property {?string} mariadbVersion An override for all environment's MariaDB version.
* @property {?Object.<string, string>} lifecycleScripts An override for various lifecycle scripts.
*/

Expand Down Expand Up @@ -65,6 +71,15 @@ module.exports = function getConfigFromEnvironmentVars( cacheDirectoryPath ) {
environmentConfig.phpVersion = process.env.WP_ENV_PHP_VERSION;
}

if ( process.env.WP_ENV_MARIADB_VERSION ) {
checkMariaDBVersion(
'environment variable',
'WP_ENV_MARIADB_VERSION',
process.env.WP_ENV_MARIADB_VERSION
);
environmentConfig.mariadbVersion = process.env.WP_ENV_MARIADB_VERSION;
}

return environmentConfig;
};

Expand Down
22 changes: 22 additions & 0 deletions packages/env/lib/config/parse-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const {
checkStringArray,
checkObjectWithValues,
checkVersion,
checkMariaDBVersion,
checkValidURL,
} = require( './validate-config' );
const getConfigFromEnvironmentVars = require( './get-config-from-environment-vars' );
Expand Down Expand Up @@ -51,6 +52,7 @@ const mergeConfigs = require( './merge-configs' );
* @property {Object} config Mapping of wp-config.php constants to their desired values.
* @property {Object.<string, WPSource>} mappings Mapping of WordPress directories to local directories which should be mounted.
* @property {string|null} phpVersion Version of PHP to use in the environments, of the format 0.0.
* @property {string|null} mariadbVersion Version of MariaDB to use in the environments: "lts", "latest", or of the format 0.0. Null uses the default.
*/

/**
Expand Down Expand Up @@ -79,6 +81,7 @@ const mergeConfigs = require( './merge-configs' );
const DEFAULT_ENVIRONMENT_CONFIG = {
core: null,
phpVersion: null,
mariadbVersion: null,
plugins: [],
themes: [],
port: 8888,
Expand Down Expand Up @@ -327,6 +330,13 @@ function getEnvironmentVarOverrides( cacheDirectoryPath ) {
overrideConfig.env.tests.phpVersion = overrides.phpVersion;
}

if ( overrides.mariadbVersion ) {
overrideConfig.mariadbVersion = overrides.mariadbVersion;
overrideConfig.env.development.mariadbVersion =
overrides.mariadbVersion;
overrideConfig.env.tests.mariadbVersion = overrides.mariadbVersion;
}

if ( overrides.multisite ) {
overrideConfig.multisite = overrides.multisite;
overrideConfig.env.development.multisite = overrides.multisite;
Expand Down Expand Up @@ -532,6 +542,18 @@ async function parseEnvironmentConfig(
parsedConfig.phpVersion = config.phpVersion;
}

if ( config.mariadbVersion !== undefined ) {
// Support null as a valid input.
if ( config.mariadbVersion !== null ) {
checkMariaDBVersion(
configFile,
`${ environmentPrefix }mariadbVersion`,
config.mariadbVersion
);
}
parsedConfig.mariadbVersion = config.mariadbVersion;
}

if ( config.core !== undefined ) {
parsedConfig.coreSource = includeTestsPath(
await parseCoreSource( config.core, options ),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ exports[`Config Integration > should load local and override configuration files
"url": "https://github.com/WordPress/WordPress.git",
},
"mappings": {},
"mariadbVersion": null,
"multisite": false,
"mysqlPort": 23306,
"phpVersion": null,
Expand Down Expand Up @@ -62,6 +63,7 @@ exports[`Config Integration > should load local and override configuration files
"url": "https://github.com/WordPress/WordPress.git",
},
"mappings": {},
"mariadbVersion": null,
"multisite": false,
"mysqlPort": 23307,
"phpVersion": null,
Expand Down Expand Up @@ -115,6 +117,7 @@ exports[`Config Integration > should load local configuration file 1`] = `
"url": "https://github.com/WordPress/WordPress.git",
},
"mappings": {},
"mariadbVersion": null,
"multisite": false,
"mysqlPort": 13306,
"phpVersion": null,
Expand Down Expand Up @@ -147,6 +150,7 @@ exports[`Config Integration > should load local configuration file 1`] = `
"url": "https://github.com/WordPress/WordPress.git",
},
"mappings": {},
"mariadbVersion": null,
"multisite": false,
"mysqlPort": 23307,
"phpVersion": null,
Expand Down Expand Up @@ -200,6 +204,7 @@ exports[`Config Integration > should use default configuration 1`] = `
"url": "https://github.com/WordPress/WordPress.git",
},
"mappings": {},
"mariadbVersion": null,
"multisite": false,
"mysqlPort": null,
"phpVersion": null,
Expand Down Expand Up @@ -232,6 +237,7 @@ exports[`Config Integration > should use default configuration 1`] = `
"url": "https://github.com/WordPress/WordPress.git",
},
"mappings": {},
"mariadbVersion": null,
"multisite": false,
"mysqlPort": null,
"phpVersion": null,
Expand Down Expand Up @@ -285,6 +291,7 @@ exports[`Config Integration > should use environment variables over local and ov
"url": "https://github.com/WordPress/WordPress.git",
},
"mappings": {},
"mariadbVersion": null,
"multisite": false,
"mysqlPort": 23306,
"phpVersion": null,
Expand Down Expand Up @@ -318,6 +325,7 @@ exports[`Config Integration > should use environment variables over local and ov
"url": "https://github.com/WordPress/WordPress.git",
},
"mappings": {},
"mariadbVersion": null,
"multisite": false,
"mysqlPort": 23307,
"phpVersion": null,
Expand Down
104 changes: 104 additions & 0 deletions packages/env/lib/config/test/parse-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ const DEFAULT_CONFIG = {
phpmyadminPort: null,
multisite: false,
phpVersion: null,
mariadbVersion: null,
coreSource: {
type: 'git',
url: 'https://github.com/WordPress/WordPress.git',
Expand Down Expand Up @@ -104,6 +105,7 @@ describe( 'parseConfig', () => {
delete process.env.WP_ENV_TESTS_PORT;
delete process.env.WP_ENV_CORE;
delete process.env.WP_ENV_PHP_VERSION;
delete process.env.WP_ENV_MARIADB_VERSION;
delete process.env.WP_ENV_LIFECYCLE_SCRIPT_AFTER_START;
} );

Expand Down Expand Up @@ -612,4 +614,106 @@ describe( 'parseConfig', () => {
)
);
} );

it( 'should parse mariadbVersion at the root and per environment', async () => {
readRawConfigFile.mockImplementation( async ( configFile ) => {
if ( configFile === '/test/gutenberg/.wp-env.json' ) {
return {
mariadbVersion: '10.11',
env: {
tests: {
mariadbVersion: 'latest',
},
},
};
}

if ( configFile === '/test/gutenberg/.wp-env.override.json' ) {
return {};
}

throw new Error( 'Invalid File: ' + configFile );
} );

const parsed = await parseConfig( '/test/gutenberg', '/cache' );

expect( parsed.mariadbVersion ).toBe( '10.11' );
expect( parsed.env.tests.mariadbVersion ).toBe( 'latest' );
} );

it( 'should accept a null mariadbVersion', async () => {
readRawConfigFile.mockImplementation( async ( configFile ) => {
if ( configFile === '/test/gutenberg/.wp-env.json' ) {
return { mariadbVersion: null };
}

if ( configFile === '/test/gutenberg/.wp-env.override.json' ) {
return {};
}

throw new Error( 'Invalid File: ' + configFile );
} );

const parsed = await parseConfig( '/test/gutenberg', '/cache' );

expect( parsed.mariadbVersion ).toBeNull();
} );

it( 'should throw for an invalid mariadbVersion', async () => {
readRawConfigFile.mockImplementation( async ( configFile ) => {
if ( configFile === '/test/gutenberg/.wp-env.json' ) {
return { env: { tests: { mariadbVersion: 'LTS' } } };
}

if ( configFile === '/test/gutenberg/.wp-env.override.json' ) {
return {};
}

throw new Error( 'Invalid File: ' + configFile );
} );

await expect(
parseConfig( '/test/gutenberg', '/cache' )
).rejects.toEqual(
new ValidationError(
'Invalid /test/gutenberg/.wp-env.json: "tests.mariadbVersion" must be "lts", "latest", or a version such as "10.11" or "11.4.2".'
)
);
} );

it( 'should override mariadbVersion in every environment with WP_ENV_MARIADB_VERSION', async () => {
readRawConfigFile.mockImplementation( async ( configFile ) => {
if ( configFile === '/test/gutenberg/.wp-env.json' ) {
return {
mariadbVersion: '10.11',
env: { tests: { mariadbVersion: 'latest' } },
};
}

if ( configFile === '/test/gutenberg/.wp-env.override.json' ) {
return {};
}

throw new Error( 'Invalid File: ' + configFile );
} );
process.env.WP_ENV_MARIADB_VERSION = '10.3';

const parsed = await parseConfig( '/test/gutenberg', '/cache' );

expect( parsed.mariadbVersion ).toBe( '10.3' );
expect( parsed.env.development.mariadbVersion ).toBe( '10.3' );
expect( parsed.env.tests.mariadbVersion ).toBe( '10.3' );
} );

it( 'should throw for an invalid WP_ENV_MARIADB_VERSION', async () => {
process.env.WP_ENV_MARIADB_VERSION = 'LTS';

await expect(
parseConfig( '/test/gutenberg', '/cache' )
).rejects.toEqual(
new ValidationError(
'Invalid environment variable: "WP_ENV_MARIADB_VERSION" must be "lts", "latest", or a version such as "10.11" or "11.4.2".'
)
);
} );
} );
35 changes: 35 additions & 0 deletions packages/env/lib/config/test/validate-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const {
checkStringArray,
checkObjectWithValues,
checkVersion,
checkMariaDBVersion,
checkValidURL,
} = require( '../validate-config' );

Expand Down Expand Up @@ -304,6 +305,40 @@ describe( 'validate-config', () => {
} );
} );

describe( 'checkMariaDBVersion', () => {
it( 'throws for non-string', () => {
expect( () =>
checkMariaDBVersion( 'test.json', 'test', 10.11 )
).toThrow(
new ValidationError(
'Invalid test.json: "test" must be a string.'
)
);
} );

it.each( [ 'LTS', 'Latest', '11-noble', 'lts-10', '10.x', '' ] )(
'throws for invalid value %j',
( version ) => {
expect( () =>
checkMariaDBVersion( 'test.json', 'test', version )
).toThrow(
new ValidationError(
'Invalid test.json: "test" must be "lts", "latest", or a version such as "10.11" or "11.4.2".'
)
);
}
);

it.each( [ 'lts', 'latest', '5', '10', '10.11', '10.3.39', '11.4.2' ] )(
'passes for %j',
( version ) => {
expect( () =>
checkMariaDBVersion( 'test.json', 'test', version )
).not.toThrow();
}
);
} );

describe( 'checkValidURL', () => {
it( 'throws for invalid URLs', () => {
expect( () =>
Expand Down
Loading
Loading