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-now: execute blueprint steps given a file path #82

Merged
merged 24 commits into from
Jun 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
124f62d
wp-now: add blueprint parameter
sejas Jun 19, 2023
3d2b4a6
wp-now: read and parse blueprint on config
sejas Jun 19, 2023
6602715
wp-now: Compile and execute blueprint steps
sejas Jun 19, 2023
49dde3a
wp-now: output only the step name
sejas Jun 19, 2023
f616148
wp-now: move blueprint executinon before any php request to avoid php…
sejas Jun 20, 2023
82011a5
wp-now: avoid appending default port 80
sejas Jun 20, 2023
498d7c7
wp-now: use blueprint WP_SITEURL to overwrite options.absoluteUrl
sejas Jun 20, 2023
753eb73
wp-now: use blueprint WP_SITEURL to overwrite options.absoluteUrl
sejas Jun 20, 2023
f9ef309
wp-now: apply same blueprint logic to defineSiteUrl
sejas Jun 20, 2023
83b77e2
wp-now: set siteUrl from blueprint to work remotely
sejas Jun 20, 2023
9cdae2a
wp-now: code style
sejas Jun 20, 2023
f0e91f1
Bump minimum Node version to v20 to be able to use CustomEvent and Fi…
sejas Jun 22, 2023
9124473
wp-now: consider case where output is undefined
sejas Jun 23, 2023
420ef76
wp-now: add tests for blueprints
sejas Jun 23, 2023
a1ecbfb
wp-now: remove todo validate blueprint since it will happen on compil…
sejas Jun 23, 2023
0263f8e
wp-now: update blueprint tests
sejas Jun 23, 2023
a426b99
wp-now: add Blueprint documentation to README.md
sejas Jun 23, 2023
ba1ad7a
wp-now: add Debugging steps using blueprints to README.md
sejas Jun 23, 2023
b749bec
Merge branch 'trunk' of github.com:WordPress/playground-tools into ad…
sejas Jun 23, 2023
598c570
wp-now: remove unnecessary import
sejas Jun 23, 2023
56f2e44
wp-now: update blueprint tests to include WP_DEBUG_LOG and simplify W…
sejas Jun 23, 2023
e821a67
code style format
sejas Jun 23, 2023
f42ddfd
wp-now: update blueprint tests
sejas Jun 23, 2023
d61b6c2
wp-now: undo restore removed tests
sejas Jun 23, 2023
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
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v18.13.0
v20.0.0
87 changes: 87 additions & 0 deletions packages/wp-now/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ wp-now php my-file.php
- `--php=<version>`: the version of PHP to use. This is optional and if not provided, it will use a default version which is `8.0`(example usage: `--php=7.4`);
- `--port=<port>`: the port number on which the server will listen. This is optional and if not provided, it will pick an open port number automatically. The default port number is set to `8881`(example of usage: `--port=3000`);
- `--wp=<version>`: the version of WordPress to use. This is optional and if not provided, it will use a default version. The default version is set to the [latest WordPress version](https://wordpress.org/download/releases/)(example usage: `--wp=5.8`)
- `--blueprint=<path>`: the path of a JSON file with the Blueprint steps. This is optional, if provided will execute the defined Blueprints. See [Using Blueprints](#using-blueprints) for more details.

Of these, `wp-now php` currently supports the `--path=<path>` and `--php=<version>` arguments.

Expand All @@ -65,6 +66,92 @@ Of these, `wp-now php` currently supports the `--path=<path>` and `--php=<versio
- The `~/.wp-now` home directory is used to store the WP versions and the `wp-content` folders for projects using 'theme', 'plugin', 'wp-content', and 'playground' modes. The path to `wp-content` directory for the 'plugin', 'theme', and 'wp-content' modes is `~/.wp-now/wp-content/${projectName}-${directoryHash}`. 'playground' mode shares the same `~/.wp-now/wp-content/playground` directory, regardless of where it's started.
- For the database setup, `wp-now` is using [SQLite database integration plugin](https://wordpress.org/plugins/sqlite-database-integration/). The path to SQLite database is ` ~/.wp-now/wp-content/${projectName}-${directoryHash}/database/.ht.sqlite`

## Using Blueprints
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for including docs! I cleaned up a couple of things with #85


Blueprints are JSON files with a list of steps to execute after starting wp-now. They can be used to automate the setup of a WordPress site, including defining wp-config constants, installing plugins, themes, and content.

## Defining a custom URL

Here is an example of a blueprint that defines custom URL constant. `wp-now` will automatically detect the blueprint and execute it after starting the server. In consequence, the site will be available at `http://myurl.wpnow`. Make sure myurl.wpnow is added to your hosts file.

To execute this blueprint, create a file named `blueprint-example.json` and run `wp-now start --blueprint=path/to/blueprint-example.json`. Note that the `virtualize` is set to `true` to avoid modifying the `wp-config.php` file that is shared between all the projects.

```json
{
"steps": [
{
"step": "defineWpConfigConsts",
"consts": {
"WP_HOME": "http://myurl.wpnow:8881",
"WP_SITEURL": "http://myurl.wpnow:8881"
},
"virtualize": true
}
]
}
```

This step can be also used along with `ngrok`, in this case you can run `ngrok http 8881`, copy the ngrok URL and replace `WP_HOME` and `WP_SITEURL` in the blueprint file.

If you prefer to use a different port, you can use the `--port` argument when starting the server.
`wp-now start --blueprint=path/to/blueprint-example.json --port=80`

The Blueprint to listen on port `80` will look like this:

```json
{
"steps": [
{
"step": "defineWpConfigConsts",
"consts": {
"WP_HOME": "http://myurl.wpnow",
"WP_SITEURL": "http://myurl.wpnow"
},
"virtualize": true
}
]
}
```

## Debugging

In the similar way we can define `WP_DEBUG` constants and read the debug logs.

Run `wp-now start --blueprint=path/to/blueprint-example.json` where `blueprint-example.json` is:

```json
{
"steps": [
{
"step": "defineWpConfigConsts",
"consts": {
"WP_DEBUG": true,
"WP_DEBUG_LOG": true
},
"virtualize": true
}
]
}
```

This will enable the debug logs and will create a `debug.log` file in the `~/wp-now/wp-content/${project}/debug.log` directory.
If you prefer to set a custom path for the debug log file, you can set `WP_DEBUG_LOG` to be a directory. Remember that the `php-wasm` server runs udner a VFS (virtual file system) where the default documentRoot is always `/var/www/html`.
For example, if you run `wp-now start --blueprint=path/to/blueprint-example.json` from a theme named `atlas` you could use this directory: `/var/www/html/wp-content/themes/atlas/example.log` and you will find the `example.log` file in your project directory.

```json
{
"steps": [
{
"step": "defineWpConfigConsts",
"consts": {
"WP_DEBUG_LOG": "/var/www/html/wp-content/themes/atlas/example.log"
},
"virtualize": true
}
]
}
```

## Known Issues

- Running `wp-now start` in 'wp-content' or 'wordpress' mode will produce some empty directories: [WordPress/wordpress-playground#328](https://github.com/WordPress/wordpress-playground/issues/328)
Expand Down
57 changes: 53 additions & 4 deletions packages/wp-now/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,22 @@ import {
SupportedPHPVersionsList,
} from '@php-wasm/universal';
import crypto from 'crypto';
import fs from 'fs-extra';
import path from 'path';
import { Blueprint } from '@wp-playground/blueprints';
import { getCodeSpaceURL, isGitHubCodespace } from './github-codespaces';
import { inferMode } from './wp-now';
import { portFinder } from './port-finder';
import { isValidWordPressVersion } from './wp-playground-wordpress';
import getWpNowPath from './get-wp-now-path';

import path from 'path';

import { DEFAULT_PHP_VERSION, DEFAULT_WORDPRESS_VERSION } from './constants';

export interface CliOptions {
php?: string;
path?: string;
wp?: string;
port?: number;
blueprint?: string;
}

export const enum WPNowMode {
Expand All @@ -41,6 +42,7 @@ export interface WPNowOptions {
wpContentPath?: string;
wordPressVersion?: string;
numberOfPhpInstances?: number;
blueprintObject?: Blueprint;
}

export const DEFAULT_OPTIONS: WPNowOptions = {
Expand All @@ -63,12 +65,23 @@ export interface WPEnvOptions {
mappings: Object;
}

let absoluteUrlFromBlueprint = '';

async function getAbsoluteURL() {
const port = await portFinder.getOpenPort();
if (isGitHubCodespace) {
return getCodeSpaceURL(port);
}
return `http://localhost:${port}`;

if (absoluteUrlFromBlueprint) {
return absoluteUrlFromBlueprint;
}

const url = 'http://localhost';
if (port === 80) {
return url;
}
return `${url}:${port}`;
}

function getWpContentHomePath(projectPath: string, mode: string) {
Expand Down Expand Up @@ -135,5 +148,41 @@ export default async function getWpNowConfig(
}. Supported versions: ${SupportedPHPVersionsList.join(', ')}`
);
}
if (args.blueprint) {
const blueprintPath = path.resolve(args.blueprint);
if (!fs.existsSync(blueprintPath)) {
throw new Error(`Blueprint file not found: ${blueprintPath}`);
}
const blueprintObject = JSON.parse(
fs.readFileSync(blueprintPath, 'utf8')
);

options.blueprintObject = blueprintObject;
const siteUrl = extractSiteUrlFromBlueprint(blueprintObject);
if (siteUrl) {
options.absoluteUrl = siteUrl;
absoluteUrlFromBlueprint = siteUrl;
}
}
return options;
}

function extractSiteUrlFromBlueprint(
blueprintObject: Blueprint
): string | false {
for (const step of blueprintObject.steps) {
if (typeof step !== 'object') {
return false;
}

if (step.step === 'defineSiteUrl') {
return `${step.siteUrl}`;
} else if (
step.step === 'defineWpConfigConsts' &&
step.consts.WP_SITEURL
) {
return `${step.consts.WP_SITEURL}`;
}
}
return false;
}
2 changes: 1 addition & 1 deletion packages/wp-now/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { runCli } from './run-cli';

const requiredMajorVersion = 18;
const requiredMajorVersion = 20;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the future, can we handle version bumps as a separate PR?

Related WordPress/wordpress-playground#591 (review)


const currentNodeVersion = parseInt(process.versions?.node?.split('.')?.[0]);

Expand Down
5 changes: 5 additions & 0 deletions packages/wp-now/src/run-cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ export async function runCli() {
describe: 'Server port',
type: 'number',
});
yargs.option('blueprint', {
describe: 'Path to a blueprint file to be executed',
type: 'string',
});
},
async (argv) => {
const spinner = startSpinner('Starting the server...');
Expand All @@ -76,6 +80,7 @@ export async function runCli() {
php: argv.php as SupportedPHPVersion,
wp: argv.wp as string,
port: argv.port as number,
blueprint: argv.blueprint as string,
});
portFinder.setPort(options.port as number);
const { url } = await startServer(options);
Expand Down
12 changes: 12 additions & 0 deletions packages/wp-now/src/tests/blueprints/wp-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"steps": [
{
"step": "defineWpConfigConsts",
"consts": {
"WP_HOME": "http://127.0.0.1",
"WP_SITEURL": "http://127.0.0.1"
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using 127.0.0.1 instead of myurl.wpnow because the DNS tests would fail resolving that custom URL.
The default URL is localhost:8881.

},
"virtualize": true
}
]
}
11 changes: 11 additions & 0 deletions packages/wp-now/src/tests/blueprints/wp-debug.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"steps": [
{
"step": "defineWpConfigConsts",
"consts": {
"WP_DEBUG_LOG": "/var/www/html/wp-content/themes/fake/example.log"
},
"virtualize": true
}
]
}
53 changes: 53 additions & 0 deletions packages/wp-now/src/tests/wp-now.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,59 @@ describe('Test starting different modes', () => {
expect(req.headers.get('content-encoding')).toBe(null);
});
});

/**
* Test blueprints execution.
*/
describe('blueprints', () => {
const blueprintExamplesPath = path.join(__dirname, 'blueprints');

afterEach(() => {
// Clean the custom url from the SQLite database
fs.rmSync(
path.join(getWpNowTmpPath(), 'wp-content', 'playground'),
{ recursive: true }
);
});

test('setting wp-config variable WP_DEBUG_LOG through blueprint', async () => {
const options = await getWpNowConfig({
blueprint: path.join(blueprintExamplesPath, 'wp-debug.json'),
});
const { php, stopServer } = await startServer(options);
php.writeFile(
`${php.documentRoot}/print-constants.php`,
`<?php echo WP_DEBUG_LOG;`
);
const result = await php.request({
method: 'GET',
url: '/print-constants.php',
});
expect(result.text).toMatch(
'/var/www/html/wp-content/themes/fake/example.log'
);
await stopServer();
});

test('setting wp-config variable WP_SITEURL through blueprint', async () => {
const options = await getWpNowConfig({
blueprint: path.join(blueprintExamplesPath, 'wp-config.json'),
});
const { php, stopServer } = await startServer(options);
expect(options.absoluteUrl).toBe('http://127.0.0.1');

php.writeFile(
`${php.documentRoot}/print-constants.php`,
`<?php echo WP_SITEURL;`
);
const result = await php.request({
method: 'GET',
url: '/print-constants.php',
});
expect(result.text).toMatch('http://127.0.0.1');
await stopServer();
});
});
});

/**
Expand Down
13 changes: 13 additions & 0 deletions packages/wp-now/src/wp-now.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@ import {
downloadWordPress,
} from './download';
import {
StepDefinition,
activatePlugin,
activateTheme,
compileBlueprint,
defineWpConfigConsts,
login,
runBlueprintSteps,
} from '@wp-playground/blueprints';
import { WPNowOptions, WPNowMode } from './config';
import {
Expand Down Expand Up @@ -119,6 +122,16 @@ export default async function startWPNow(
}
});

if (options.blueprintObject) {
output?.log(`blueprint steps: ${options.blueprintObject.steps.length}`);
const compiled = compileBlueprint(options.blueprintObject, {
onStepCompleted: (result, step: StepDefinition) => {
output?.log(`Blueprint step completed: ${step.step}`);
},
});
await runBlueprintSteps(compiled, php);
}

await installationStep2(php);
await login(php, {
username: 'admin',
Expand Down