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: Add phpMyAdmin support #67588

Merged
merged 6 commits into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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

### Enhancements

- Add phpMyAdmin as an optional service. Enabled via the new `phpmyadminPort` environment config, as well as env vars `WP_ENV_PHPMYADMIN_PORT` and `WP_ENV_TESTS_PHPMYADMIN_PORT`.

## 10.13.0 (2024-11-27)

## 10.12.0 (2024-11-16)
Expand Down
2 changes: 1 addition & 1 deletion packages/env/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ containers.
Positionals:
container The Docker service to run the command on.
[string] [required] [choices: "mysql", "tests-mysql", "wordpress",
"tests-wordpress", "cli", "tests-cli", "composer", "phpunit"]
"tests-wordpress", "cli", "tests-cli", "composer", "phpmyadmin"]
command The command to run. [required]

Options:
Expand Down
27 changes: 27 additions & 0 deletions packages/env/lib/build-docker-compose-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,13 @@ module.exports = function buildDockerComposeConfig( config ) {
config.env.tests.mysqlPort ?? ''
}}:3306`;

const developmentPhpmyadminPorts = `\${WP_ENV_PHPMYADMIN_PORT:-${
config.env.development.phpmyadminPort ?? ''
}}:80`;
const testsPhpmyadminPorts = `\${WP_ENV_TESTS_PHPMYADMIN_PORT:-${
config.env.tests.phpmyadminPort ?? ''
}}:80`;

return {
services: {
mysql: {
Expand Down Expand Up @@ -266,6 +273,26 @@ module.exports = function buildDockerComposeConfig( config ) {
},
extra_hosts: [ 'host.docker.internal:host-gateway' ],
},
phpmyadmin: {
image: 'phpmyadmin',
ports: [ developmentPhpmyadminPorts ],
environment: {
PMA_PORT: 3306,
PMA_HOST: 'mysql',
PMA_USER: 'root',
PMA_PASSWORD: 'password',
},
},
'tests-phpmyadmin': {
image: 'phpmyadmin',
ports: [ testsPhpmyadminPorts ],
environment: {
PMA_PORT: 3306,
PMA_HOST: 'tests-mysql',
PMA_USER: 'root',
PMA_PASSWORD: 'password',
},
},
},
volumes: {
...( ! config.env.development.coreSource && { wordpress: {} } ),
Expand Down
76 changes: 60 additions & 16 deletions packages/env/lib/commands/start.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,24 @@ module.exports = async function start( {
}
);

if ( config.env.development.phpmyadminPort ) {
await dockerCompose.upOne( 'phpmyadmin', {
...dockerComposeConfig,
commandOptions: shouldConfigureWp
? [ '--build', '--force-recreate' ]
: [],
} );
}

if ( config.env.tests.phpmyadminPort ) {
await dockerCompose.upOne( 'tests-phpmyadmin', {
...dockerComposeConfig,
commandOptions: shouldConfigureWp
? [ '--build', '--force-recreate' ]
: [],
} );
}

// Make sure we've consumed the custom CLI dockerfile.
if ( shouldConfigureWp ) {
await dockerCompose.buildOne( [ 'cli' ], { ...dockerComposeConfig } );
Expand Down Expand Up @@ -225,35 +243,61 @@ module.exports = async function start( {
const siteUrl = config.env.development.config.WP_SITEURL;
const testsSiteUrl = config.env.tests.config.WP_SITEURL;

const { out: mySQLAddress } = await dockerCompose.port(
const mySQLPort = await getPublicDockerPort(
'mysql',
3306,
dockerComposeConfig
);
const mySQLPort = mySQLAddress.split( ':' ).pop();

const { out: testsMySQLAddress } = await dockerCompose.port(
const testsMySQLPort = await getPublicDockerPort(
'tests-mysql',
3306,
dockerComposeConfig
);
const testsMySQLPort = testsMySQLAddress.split( ':' ).pop();

spinner.prefixText = 'WordPress development site started'
.concat( siteUrl ? ` at ${ siteUrl }` : '.' )
.concat( '\n' )
.concat( 'WordPress test site started' )
.concat( testsSiteUrl ? ` at ${ testsSiteUrl }` : '.' )
.concat( '\n' )
.concat( `MySQL is listening on port ${ mySQLPort }` )
.concat(
`MySQL for automated testing is listening on port ${ testsMySQLPort }`
)
.concat( '\n' );

const phpmyadminPort = config.env.development.phpmyadminPort
? await getPublicDockerPort( 'phpmyadmin', 80, dockerComposeConfig )
: null;

const testsPhpmyadminPort = config.env.tests.phpmyadminPort
? await getPublicDockerPort(
'tests-phpmyadmin',
80,
dockerComposeConfig
)
: null;

spinner.prefixText = [
'WordPress development site started' +
( siteUrl ? ` at ${ siteUrl }` : '.' ),
'WordPress test site started' +
( testsSiteUrl ? ` at ${ testsSiteUrl }` : '.' ),
`MySQL is listening on port ${ mySQLPort }`,
`MySQL for automated testing is listening on port ${ testsMySQLPort }`,
phpmyadminPort &&
`phpMyAdmin started at http://localhost:${ phpmyadminPort }`,
testsPhpmyadminPort &&
`phpMyAdmin for automated testing started at http://localhost:${ testsPhpmyadminPort }`,
]
.filter( Boolean )
.join( '\n' );
spinner.prefixText += '\n\n';
spinner.text = 'Done!';
};

async function getPublicDockerPort(
service,
containerPort,
dockerComposeConfig
) {
const { out: address } = await dockerCompose.port(
service,
containerPort,
dockerComposeConfig
);
return address.split( ':' ).pop().trim();
}

/**
* Checks for legacy installs and provides
* the user the option to delete them.
Expand Down
7 changes: 7 additions & 0 deletions packages/env/lib/config/get-config-from-environment-vars.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const { checkPort, checkVersion, checkString } = require( './validate-config' );
* @property {?number} mysqlPort An override for the development environment's MySQL port.
* @property {?number} testsPort An override for the testing environment's port.
* @property {?number} testsMysqlPort An override for the testing environment's MySQL port.
* @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 {?Object.<string, string>} lifecycleScripts An override for various lifecycle scripts.
Expand All @@ -40,6 +41,12 @@ module.exports = function getConfigFromEnvironmentVars( cacheDirectoryPath ) {
testsMysqlPort: getPortFromEnvironmentVariable(
'WP_ENV_TESTS_MYSQL_PORT'
),
phpmyadminPort: getPortFromEnvironmentVariable(
'WP_ENV_PHPMYADMIN_PORT'
),
testsPhpmyadminPort: getPortFromEnvironmentVariable(
'WP_ENV_TESTS_PHPMYADMIN_PORT'
),
lifecycleScripts: getLifecycleScriptOverrides(),
};

Expand Down
27 changes: 19 additions & 8 deletions packages/env/lib/config/parse-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,15 @@ const mergeConfigs = require( './merge-configs' );
* The environment-specific configuration options. (development/tests/etc)
*
* @typedef WPEnvironmentConfig
* @property {WPSource} coreSource The WordPress installation to load in the environment.
* @property {WPSource[]} pluginSources Plugins to load in the environment.
* @property {WPSource[]} themeSources Themes to load in the environment.
* @property {number} port The port to use.
* @property {number} mysqlPort The port to use for MySQL. Random if empty.
* @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 {WPSource} coreSource The WordPress installation to load in the environment.
* @property {WPSource[]} pluginSources Plugins to load in the environment.
* @property {WPSource[]} themeSources Themes to load in the environment.
* @property {number} port The port to use.
* @property {number} mysqlPort The port to use for MySQL. Random if empty.
* @property {number} phpmyadminPort The port to use for phpMyAdmin. If empty, disabled phpMyAdmin.
* @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.
*/

/**
Expand Down Expand Up @@ -87,6 +88,7 @@ const DEFAULT_ENVIRONMENT_CONFIG = {
port: 8888,
testsPort: 8889,
mysqlPort: null,
phpmyadminPort: null,
mappings: {},
config: {
FS_METHOD: 'direct',
Expand Down Expand Up @@ -282,6 +284,11 @@ function getEnvironmentVarOverrides( cacheDirectoryPath ) {
overrideConfig.env.development.mysqlPort = overrides.mysqlPort;
}

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

if ( overrides.testsPort ) {
overrideConfig.testsPort = overrides.testsPort;
overrideConfig.env.tests.port = overrides.testsPort;
Expand Down Expand Up @@ -455,6 +462,10 @@ async function parseEnvironmentConfig(
parsedConfig.mysqlPort = config.mysqlPort;
}

if ( config.phpmyadminPort !== undefined ) {
parsedConfig.phpmyadminPort = config.phpmyadminPort;
}

if ( config.phpVersion !== undefined ) {
// Support null as a valid input.
if ( config.phpVersion !== null ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ exports[`Config Integration should load local and override configuration files 1
"mappings": {},
"mysqlPort": 23306,
"phpVersion": null,
"phpmyadminPort": null,
"pluginSources": [],
"port": 999,
"themeSources": [],
Expand Down Expand Up @@ -60,6 +61,7 @@ exports[`Config Integration should load local and override configuration files 1
"mappings": {},
"mysqlPort": 23307,
"phpVersion": null,
"phpmyadminPort": null,
"pluginSources": [],
"port": 456,
"themeSources": [],
Expand Down Expand Up @@ -106,6 +108,7 @@ exports[`Config Integration should load local configuration file 1`] = `
"mappings": {},
"mysqlPort": 13306,
"phpVersion": null,
"phpmyadminPort": null,
"pluginSources": [],
"port": 123,
"themeSources": [],
Expand Down Expand Up @@ -135,6 +138,7 @@ exports[`Config Integration should load local configuration file 1`] = `
"mappings": {},
"mysqlPort": 23307,
"phpVersion": null,
"phpmyadminPort": null,
"pluginSources": [],
"port": 8889,
"themeSources": [],
Expand Down Expand Up @@ -181,6 +185,7 @@ exports[`Config Integration should use default configuration 1`] = `
"mappings": {},
"mysqlPort": null,
"phpVersion": null,
"phpmyadminPort": null,
"pluginSources": [],
"port": 8888,
"themeSources": [],
Expand Down Expand Up @@ -210,6 +215,7 @@ exports[`Config Integration should use default configuration 1`] = `
"mappings": {},
"mysqlPort": null,
"phpVersion": null,
"phpmyadminPort": null,
"pluginSources": [],
"port": 8889,
"themeSources": [],
Expand Down Expand Up @@ -256,6 +262,7 @@ exports[`Config Integration should use environment variables over local and over
"mappings": {},
"mysqlPort": 23306,
"phpVersion": null,
"phpmyadminPort": null,
"pluginSources": [],
"port": 12345,
"testsPort": 61234,
Expand Down Expand Up @@ -286,6 +293,7 @@ exports[`Config Integration should use environment variables over local and over
"mappings": {},
"mysqlPort": 23307,
"phpVersion": null,
"phpmyadminPort": null,
"pluginSources": [],
"port": 61234,
"testsPort": 61234,
Expand Down
54 changes: 54 additions & 0 deletions packages/env/lib/config/test/parse-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const DEFAULT_CONFIG = {
port: 8888,
testsPort: 8889,
mysqlPort: null,
phpmyadminPort: null,
phpVersion: null,
coreSource: {
type: 'git',
Expand Down Expand Up @@ -400,4 +401,57 @@ describe( 'parseConfig', () => {
)
);
} );

it( 'should parse phpmyadmin configuration for a given environment', async () => {
readRawConfigFile.mockImplementation( async ( configFile ) => {
if ( configFile === '/test/gutenberg/.wp-env.json' ) {
return {
core: 'WordPress/WordPress#Test',
phpVersion: '1.0',
lifecycleScripts: {
afterStart: 'test',
},
env: {
development: {
phpmyadminPort: 9001,
},
},
};
}
} );

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

const expected = {
development: {
...DEFAULT_CONFIG.env.development,
phpmyadminPort: 9001,
},
tests: DEFAULT_CONFIG.env.tests,
};
expect( parsed.env ).toEqual( expected );
} );

it( 'should ignore root-level configuration for phpmyadmin', async () => {
readRawConfigFile.mockImplementation( async ( configFile ) => {
if ( configFile === '/test/gutenberg/.wp-env.json' ) {
return {
core: 'WordPress/WordPress#Test',
phpVersion: '1.0',
lifecycleScripts: {
afterStart: 'test',
},
phpmyadminPort: 9001,
};
}
} );

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

const expected = {
development: DEFAULT_CONFIG.env.development,
tests: DEFAULT_CONFIG.env.tests,
};
expect( parsed.env ).toEqual( expected );
} );
} );
1 change: 1 addition & 0 deletions packages/env/lib/validate-run-container.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const RUN_CONTAINERS = [
'tests-wordpress',
'cli',
'tests-cli',
'phpmyadmin',
];

/**
Expand Down
Loading