@elementor/wp-lite-env 0.0.7 → 0.0.9
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/.changeset/README.md +8 -0
- package/.changeset/config.json +11 -0
- package/.github/workflows/ci.yml +30 -0
- package/.github/workflows/release.yml +48 -0
- package/.github/workflows/require-changesets.yml +47 -0
- package/CHANGELOG.md +55 -0
- package/LICENSE +674 -0
- package/README.md +76 -0
- package/__tests__/__snapshots__/template.test.ts.snap +71 -0
- package/__tests__/config.test.ts +20 -0
- package/__tests__/e2e.ts +21 -0
- package/__tests__/template.test.ts +103 -0
- package/dist/package.json +46 -0
- package/eslint.config.mjs +13 -0
- package/index.ts +19 -0
- package/jest.config.js +8 -0
- package/package.json +44 -45
- package/src/config.ts +35 -0
- package/src/run.ts +125 -0
- package/src/templates.ts +117 -0
- package/tests/.wp-lite-env.json +16 -0
- package/tsconfig.json +32 -0
- package/index.d.ts.map +0 -1
- package/src/config.d.ts.map +0 -1
- package/src/run.d.ts.map +0 -1
- package/src/templates.d.ts.map +0 -1
- /package/{index.d.ts → dist/index.d.ts} +0 -0
- /package/{index.js → dist/index.js} +0 -0
- /package/{src → dist/src}/config.d.ts +0 -0
- /package/{src → dist/src}/config.js +0 -0
- /package/{src → dist/src}/run.d.ts +0 -0
- /package/{src → dist/src}/run.js +0 -0
- /package/{src → dist/src}/templates.d.ts +0 -0
- /package/{src → dist/src}/templates.js +0 -0
package/README.md
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
# wp-lite-env
|
2
|
+
A simple, lightweight, docker-based WordPress environment
|
3
|
+
|
4
|
+
# Usage
|
5
|
+
## Installation
|
6
|
+
To install the package, run the following command:
|
7
|
+
```bash
|
8
|
+
npm install -g @elementor/wp-lite-env
|
9
|
+
```
|
10
|
+
If you want to install the package for a specific project, run the following command:
|
11
|
+
```bash
|
12
|
+
npm install --save-dev @elementor/wp-lite-env
|
13
|
+
```
|
14
|
+
## Creating a configuration file
|
15
|
+
The configuration file is a JSON file that contains the configuration for the WordPress environment.
|
16
|
+
|
17
|
+
| Field | Type | Default | Description |
|
18
|
+
|----------------|----------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
19
|
+
| `"core"` | `string\|null` | `null` | The WordPress installation to use. If `null` is specified, the latest production release of WordPress will be used. |
|
20
|
+
| `"phpVersion"` | `string\|null` | `null` | The PHP version to use. If `null` is specified, the latest version of PHP that is compatible with the latest production release of WordPress will be used. |
|
21
|
+
| `"plugins"` | `Object` | `{}` | A set of plugins to install and activate in the environment. The entries are a key-value pair in the format of <slug>: <path to plugin> |
|
22
|
+
| `"themes"` | `Object` | `{}` | A set of themes to install in the environment. The entries are a key-value pair in the format of <slug>: <path to theme> |
|
23
|
+
| `"config"` | `Object` | `{}` | Mapping of wp-config.php constants to their desired values. |
|
24
|
+
| `"mappings"` | `Object` | `"{}"` | Mapping of WordPress directories to local directories to be mounted in the WordPress instance. |
|
25
|
+
|
26
|
+
The following is an example of a configuration file:
|
27
|
+
```json
|
28
|
+
{
|
29
|
+
"core": "6.7",
|
30
|
+
"phpVersion": "8.2",
|
31
|
+
"plugins": {
|
32
|
+
"elementor": "./elementor/build"
|
33
|
+
},
|
34
|
+
"themes": {
|
35
|
+
"hello-elementor": "./hello-elementor"
|
36
|
+
},
|
37
|
+
"mappings": {
|
38
|
+
"resources": "./resources"
|
39
|
+
},
|
40
|
+
"config": {
|
41
|
+
"SCRIPT_DEBUG": false,
|
42
|
+
"WP_DEBUG": false
|
43
|
+
}
|
44
|
+
}
|
45
|
+
```
|
46
|
+
## Usage
|
47
|
+
### Starting a new WordPress environment
|
48
|
+
To start a new WordPress environment, run the following command:
|
49
|
+
```bash
|
50
|
+
npx wp-lite-env start config=<path to configuration file> -- port=<port>
|
51
|
+
```
|
52
|
+
For example:
|
53
|
+
```bash
|
54
|
+
npx wp-lite-env start config=./tests/.wp-lite-env.json -- port=1234
|
55
|
+
```
|
56
|
+
### Stopping a WordPress environment
|
57
|
+
To stop a running WordPress environment, run the following command:
|
58
|
+
```bash
|
59
|
+
npx wp-lite-env start config=<path to configuration file> -- port=<port used by the WordPress environment>
|
60
|
+
```
|
61
|
+
For example:
|
62
|
+
```bash
|
63
|
+
npx wp-lite-env stop config=./tests/.wp-lite-env.json -- port=1234
|
64
|
+
```
|
65
|
+
### Starting a new WordPress environment
|
66
|
+
The WordPress CLI is available for use on the server. To use it, run the following command:
|
67
|
+
```bash
|
68
|
+
npx wp-lite-env cli config=<path to configuration file> -- port=<port used by the WordPress environment> command="<CLI command>"
|
69
|
+
```
|
70
|
+
For example:
|
71
|
+
```bash
|
72
|
+
npx wp-lite-env cli config=./tests/.wp-lite-env.json -- port=1234 command="ls -la /var/www/html"
|
73
|
+
```
|
74
|
+
|
75
|
+
# Contributors
|
76
|
+
This package is developed and maintained by the [Elementor](https://elementor.com) team. With that being said, we want to thank the [@wordpress/env](https://www.npmjs.com/package/@wordpress/env) team, this package is heavily inspired by their wonderful work.
|
@@ -0,0 +1,71 @@
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
2
|
+
|
3
|
+
exports[`templates compose file generation snapshot test 1`] = `
|
4
|
+
"services:
|
5
|
+
mysql:
|
6
|
+
image: 'mariadb:lts'
|
7
|
+
ports:
|
8
|
+
- '\${WP_ENV_MYSQL_PORT:-}:3306'
|
9
|
+
environment:
|
10
|
+
MYSQL_ROOT_HOST: '%'
|
11
|
+
MYSQL_ROOT_PASSWORD: password
|
12
|
+
MYSQL_DATABASE: wordpress
|
13
|
+
volumes:
|
14
|
+
- 'mysql:/var/lib/mysql'
|
15
|
+
wordpress:
|
16
|
+
depends_on:
|
17
|
+
- mysql
|
18
|
+
build:
|
19
|
+
context: .
|
20
|
+
dockerfile: WordPress.Dockerfile
|
21
|
+
no_cache: true
|
22
|
+
args: &ref_0
|
23
|
+
HOST_USERNAME: yotams
|
24
|
+
HOST_UID: '502'
|
25
|
+
HOST_GID: '20'
|
26
|
+
ports:
|
27
|
+
- '\${WP_ENV_PORT:-1234}:80'
|
28
|
+
environment:
|
29
|
+
APACHE_RUN_USER: '#502'
|
30
|
+
APACHE_RUN_GROUP: '#20'
|
31
|
+
WORDPRESS_DB_USER: root
|
32
|
+
WORDPRESS_DB_PASSWORD: password
|
33
|
+
WORDPRESS_DB_NAME: wordpress
|
34
|
+
volumes: &ref_1
|
35
|
+
- >-
|
36
|
+
wpcontent:/var/www/html
|
37
|
+
- >-
|
38
|
+
/some/wp-config/path:/var/www/html/wp-config
|
39
|
+
|
40
|
+
extra_hosts:
|
41
|
+
- 'host.docker.internal:host-gateway'
|
42
|
+
cli:
|
43
|
+
depends_on:
|
44
|
+
- wordpress
|
45
|
+
build:
|
46
|
+
context: .
|
47
|
+
dockerfile: CLI.Dockerfile
|
48
|
+
args: *ref_0
|
49
|
+
volumes: *ref_1
|
50
|
+
user: '502:20'
|
51
|
+
environment:
|
52
|
+
WORDPRESS_DB_USER: root
|
53
|
+
WORDPRESS_DB_PASSWORD: password
|
54
|
+
WORDPRESS_DB_NAME: wordpress
|
55
|
+
extra_hosts:
|
56
|
+
- 'host.docker.internal:host-gateway'
|
57
|
+
volumes:
|
58
|
+
mysql: {}
|
59
|
+
wpcontent: {}
|
60
|
+
"
|
61
|
+
`;
|
62
|
+
|
63
|
+
exports[`templates configuration file generation config file is generated with the correct values 1`] = `
|
64
|
+
"#!/bin/bash
|
65
|
+
set -eox pipefail
|
66
|
+
|
67
|
+
wp core install --url="http://localhost:1234" --title="test" --admin_user=admin --admin_password=password --admin_email=wordpress@example.com --skip-email
|
68
|
+
wp config set ELEMENTOR_SHOW_HIDDEN_EXPERIMENTS true --raw
|
69
|
+
wp config set SCRIPT_DEBUG false --raw
|
70
|
+
wp config set WP_DEBUG false --raw"
|
71
|
+
`;
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import {describe, expect, jest, test} from '@jest/globals';
|
2
|
+
import fs from 'fs';
|
3
|
+
import {getConfig} from "../src/config";
|
4
|
+
import {MockInstance} from "jest-mock";
|
5
|
+
|
6
|
+
jest.mock('fs');
|
7
|
+
describe('config', () => {
|
8
|
+
test('defaults', () => {
|
9
|
+
(fs.readFileSync as unknown as MockInstance).mockReturnValueOnce(JSON.stringify({"some" : "data"}));
|
10
|
+
const config = getConfig('some/path');
|
11
|
+
expect(config).toEqual({
|
12
|
+
core: '6.7',
|
13
|
+
phpVersion: '8.1',
|
14
|
+
plugins: {},
|
15
|
+
themes: {},
|
16
|
+
mappings: {},
|
17
|
+
config: {},
|
18
|
+
});
|
19
|
+
});
|
20
|
+
});
|
package/__tests__/e2e.ts
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
import {afterEach, describe, expect, test} from "@jest/globals";
|
2
|
+
import {cleanup, generateFiles, getConfigFilePath, start, stop} from "../src/run";
|
3
|
+
|
4
|
+
const port = '1234';
|
5
|
+
const runPath = (port: string) => {
|
6
|
+
return generateFiles(port, getConfigFilePath(['', '', '', 'config=./tests/.wp-lite-env.json']));
|
7
|
+
};
|
8
|
+
|
9
|
+
describe('end to end tests', () => {
|
10
|
+
afterEach(async () => {
|
11
|
+
const theRunPath = runPath(port);
|
12
|
+
await stop(port, theRunPath);
|
13
|
+
cleanup(port, theRunPath);
|
14
|
+
}, 30000);
|
15
|
+
test('WordPress is up and running', async () => {
|
16
|
+
await start( port, runPath(port) );
|
17
|
+
const response = await fetch(`http://localhost:${port}`);
|
18
|
+
expect(response.ok).toBe(true);
|
19
|
+
expect(await response.text()).toContain('Welcome to WordPress');
|
20
|
+
}, 60000);
|
21
|
+
});
|
@@ -0,0 +1,103 @@
|
|
1
|
+
import {describe, expect, test} from '@jest/globals';
|
2
|
+
import {
|
3
|
+
generateCliDockerfileTemplate,
|
4
|
+
generateConfiguration, generateDockerComposeYmlTemplate,
|
5
|
+
generateWordPressDockerfileTemplate
|
6
|
+
} from "../src/templates";
|
7
|
+
|
8
|
+
describe('templates', () => {
|
9
|
+
describe('docker files', () => {
|
10
|
+
test('WordPress Dockerfile', () => {
|
11
|
+
const core = '1.2';
|
12
|
+
const phpVersion = '3.4';
|
13
|
+
const dockerfile = generateWordPressDockerfileTemplate( { core, phpVersion});
|
14
|
+
expect(dockerfile).toMatch(new RegExp(`^FROM wordpress:${ core }-php${ phpVersion }?`));
|
15
|
+
});
|
16
|
+
|
17
|
+
test('CLI Dockerfile', () => {
|
18
|
+
const phpVersion = '3.4';
|
19
|
+
const dockerfile = generateCliDockerfileTemplate( { phpVersion});
|
20
|
+
expect(dockerfile).toMatch(new RegExp(`^FROM wordpress:cli-php${ phpVersion }?`));
|
21
|
+
});
|
22
|
+
});
|
23
|
+
|
24
|
+
describe('configuration file generation', () => {
|
25
|
+
test('config file is generated with the correct values', () => {
|
26
|
+
const config = {
|
27
|
+
config: {
|
28
|
+
"ELEMENTOR_SHOW_HIDDEN_EXPERIMENTS": true,
|
29
|
+
"SCRIPT_DEBUG": false,
|
30
|
+
"WP_DEBUG": false
|
31
|
+
}
|
32
|
+
};
|
33
|
+
const configTemplate = generateConfiguration( config, '1234' );
|
34
|
+
expect(configTemplate).toMatchSnapshot();
|
35
|
+
});
|
36
|
+
});
|
37
|
+
|
38
|
+
describe('compose file generation', () => {
|
39
|
+
test('snapshot test', () => {
|
40
|
+
const config = {
|
41
|
+
mappings: {},
|
42
|
+
plugins: {},
|
43
|
+
themes: {},
|
44
|
+
}
|
45
|
+
const composeYml = generateDockerComposeYmlTemplate( config, '/some/base/path', '1234', '/some/wp-config/path' );
|
46
|
+
expect(composeYml).toMatchSnapshot();
|
47
|
+
});
|
48
|
+
test('mappings are mounted correctly', () => {
|
49
|
+
const config = {
|
50
|
+
mappings: {
|
51
|
+
'some/host/path': 'some/container/path',
|
52
|
+
'some/other/host/path': 'some/other/container/path',
|
53
|
+
},
|
54
|
+
plugins: {},
|
55
|
+
themes: {},
|
56
|
+
}
|
57
|
+
const basePath = '/some/base/path';
|
58
|
+
const composeYml = generateDockerComposeYmlTemplate( config, basePath, '1234', '/some/wp-config/path' );
|
59
|
+
expect(composeYml).toMatch(new RegExp(`${basePath}/some/container/path:/var/www/html/some/host/path`));
|
60
|
+
expect(composeYml).toMatch(new RegExp(`${basePath}/some/other/container/path:/var/www/html/some/other/host/path`));
|
61
|
+
});
|
62
|
+
test('plugins are mounted correctly', () => {
|
63
|
+
const config = {
|
64
|
+
mappings: {
|
65
|
+
},
|
66
|
+
plugins: {
|
67
|
+
'plugin1': '../some/plugin/path',
|
68
|
+
'plugin2': '../some/other/plugin/path',
|
69
|
+
},
|
70
|
+
themes: {},
|
71
|
+
}
|
72
|
+
const basePath = '/some/base/path';
|
73
|
+
const composeYml = generateDockerComposeYmlTemplate( config, basePath, '1234', '/some/wp-config/path' );
|
74
|
+
expect(composeYml).toMatch(new RegExp(`/some/base/some/plugin/path:/var/www/html/wp-content/plugins/plugin1`));
|
75
|
+
expect(composeYml).toMatch(new RegExp(`/some/base/some/other/plugin/path:/var/www/html/wp-content/plugins/plugin2`));
|
76
|
+
});
|
77
|
+
test('themes are mounted correctly', () => {
|
78
|
+
const config = {
|
79
|
+
mappings: {},
|
80
|
+
plugins: {},
|
81
|
+
themes: {
|
82
|
+
'theme1': '../some/theme/path',
|
83
|
+
'theme2': '../some/other/theme/path',
|
84
|
+
},
|
85
|
+
}
|
86
|
+
const basePath = '/some/base/path';
|
87
|
+
const composeYml = generateDockerComposeYmlTemplate( config, basePath, '1234', '/some/wp-config/path' );
|
88
|
+
expect(composeYml).toMatch(new RegExp(`/some/base/some/theme/path:/var/www/html/wp-content/themes/theme1`));
|
89
|
+
expect(composeYml).toMatch(new RegExp(`/some/base/some/other/theme/path:/var/www/html/wp-content/themes/theme2`));
|
90
|
+
});
|
91
|
+
test('wp-config is mounted correctly', () => {
|
92
|
+
// /some/wp-config/path:/var/www/html/wp-config
|
93
|
+
const config = {
|
94
|
+
mappings: {},
|
95
|
+
plugins: {},
|
96
|
+
themes: {},
|
97
|
+
}
|
98
|
+
const basePath = '/some/base/path';
|
99
|
+
const composeYml = generateDockerComposeYmlTemplate( config, basePath, '1234', '/some/wp-config/path' );
|
100
|
+
expect(composeYml).toMatch(new RegExp(`/some/wp-config/path:/var/www/html/wp-config`));
|
101
|
+
});
|
102
|
+
});
|
103
|
+
});
|
@@ -0,0 +1,46 @@
|
|
1
|
+
{
|
2
|
+
"name": "@elementor/wp-lite-env",
|
3
|
+
"version": "0.0.9",
|
4
|
+
"private": false,
|
5
|
+
"description": "A simple, lightweight, docker-based WordPress environment",
|
6
|
+
"main": "dist/index.js",
|
7
|
+
"type": "module",
|
8
|
+
"types": "dist/index.d.ts",
|
9
|
+
"bin": {
|
10
|
+
"wp-lite-env": "dist/index.js"
|
11
|
+
},
|
12
|
+
"scripts": {
|
13
|
+
"build": "tsc",
|
14
|
+
"lint": "eslint",
|
15
|
+
"release": "npm run build && changeset publish",
|
16
|
+
"test": "jest --coverage=true"
|
17
|
+
},
|
18
|
+
"repository": {
|
19
|
+
"type": "git",
|
20
|
+
"url": "git+https://github.com/elementor/wp-lite-env.git"
|
21
|
+
},
|
22
|
+
"publishConfig": {
|
23
|
+
"access": "public"
|
24
|
+
},
|
25
|
+
"author": "Elementor Team",
|
26
|
+
"license": "ISC",
|
27
|
+
"bugs": {
|
28
|
+
"url": "https://github.com/elementor/wp-lite-env/issues"
|
29
|
+
},
|
30
|
+
"homepage": "https://github.com/elementor/wp-lite-env#readme",
|
31
|
+
"dependencies": {
|
32
|
+
"docker-compose": "^1.1.0"
|
33
|
+
},
|
34
|
+
"devDependencies": {
|
35
|
+
"@changesets/cli": "^2.27.9",
|
36
|
+
"@eslint/js": "^9.15.0",
|
37
|
+
"@jest/globals": "^29.7.0",
|
38
|
+
"@types/eslint__js": "^8.42.3",
|
39
|
+
"@types/node": "^22.9.0",
|
40
|
+
"eslint": "~9.14.0",
|
41
|
+
"jest": "^29.7.0",
|
42
|
+
"ts-jest": "^29.2.5",
|
43
|
+
"typescript": "^5.6.3",
|
44
|
+
"typescript-eslint": "^8.14.0"
|
45
|
+
}
|
46
|
+
}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
// @ts-check
|
2
|
+
|
3
|
+
import eslint from '@eslint/js';
|
4
|
+
import tseslint from 'typescript-eslint';
|
5
|
+
|
6
|
+
export default tseslint.config(
|
7
|
+
{
|
8
|
+
// config with just ignores is the replacement for `.eslintignore`
|
9
|
+
ignores: ['dist/**', '**.js', '**.map'],
|
10
|
+
},
|
11
|
+
eslint.configs.recommended,
|
12
|
+
...tseslint.configs.recommended,
|
13
|
+
);
|
package/index.ts
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
import {cleanup, commandMap, generateFiles, getCliCommand, getConfigFilePath, getPort} from './src/run';
|
4
|
+
|
5
|
+
const command = process.argv[ 2 ];
|
6
|
+
if ( ! commandMap[ command ] ) {
|
7
|
+
console.log( `Valid commands: ${ Object.keys( commandMap ).join( ', ' ) }. You used ${ command }` );
|
8
|
+
}
|
9
|
+
|
10
|
+
const port = getPort( process.argv );
|
11
|
+
const configFilePath = getConfigFilePath( process.argv )
|
12
|
+
const runPath = generateFiles( port, configFilePath );
|
13
|
+
const cliCommand = getCliCommand( process.argv );
|
14
|
+
|
15
|
+
try {
|
16
|
+
await commandMap[command](port, runPath, cliCommand);
|
17
|
+
} finally {
|
18
|
+
cleanup( port, runPath );
|
19
|
+
}
|
package/jest.config.js
ADDED
package/package.json
CHANGED
@@ -1,47 +1,46 @@
|
|
1
1
|
{
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
"
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
"
|
33
|
-
|
34
|
-
|
35
|
-
"
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
}
|
2
|
+
"name": "@elementor/wp-lite-env",
|
3
|
+
"version": "0.0.9",
|
4
|
+
"private": false,
|
5
|
+
"description": "A simple, lightweight, docker-based WordPress environment",
|
6
|
+
"main": "dist/index.js",
|
7
|
+
"type": "module",
|
8
|
+
"types": "dist/index.d.ts",
|
9
|
+
"bin": {
|
10
|
+
"wp-lite-env": "dist/index.js"
|
11
|
+
},
|
12
|
+
"scripts": {
|
13
|
+
"build": "tsc",
|
14
|
+
"lint": "eslint",
|
15
|
+
"release": "npm run build && changeset publish",
|
16
|
+
"test": "jest --coverage=true"
|
17
|
+
},
|
18
|
+
"repository": {
|
19
|
+
"type": "git",
|
20
|
+
"url": "git+https://github.com/elementor/wp-lite-env.git"
|
21
|
+
},
|
22
|
+
"publishConfig": {
|
23
|
+
"access": "public"
|
24
|
+
},
|
25
|
+
"author": "Elementor Team",
|
26
|
+
"license": "ISC",
|
27
|
+
"bugs": {
|
28
|
+
"url": "https://github.com/elementor/wp-lite-env/issues"
|
29
|
+
},
|
30
|
+
"homepage": "https://github.com/elementor/wp-lite-env#readme",
|
31
|
+
"dependencies": {
|
32
|
+
"docker-compose": "^1.1.0"
|
33
|
+
},
|
34
|
+
"devDependencies": {
|
35
|
+
"@changesets/cli": "^2.27.9",
|
36
|
+
"@eslint/js": "^9.15.0",
|
37
|
+
"@jest/globals": "^29.7.0",
|
38
|
+
"@types/eslint__js": "^8.42.3",
|
39
|
+
"@types/node": "^22.9.0",
|
40
|
+
"eslint": "~9.14.0",
|
41
|
+
"jest": "^29.7.0",
|
42
|
+
"ts-jest": "^29.2.5",
|
43
|
+
"typescript": "^5.6.3",
|
44
|
+
"typescript-eslint": "^8.14.0"
|
45
|
+
}
|
47
46
|
}
|
package/src/config.ts
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
import fs from 'fs';
|
2
|
+
|
3
|
+
export type Config = {
|
4
|
+
core?: string,
|
5
|
+
phpVersion?: string,
|
6
|
+
plugins?: { [key: string]: string },
|
7
|
+
themes?: { [key: string]: string },
|
8
|
+
mappings?: { [key: string]: string },
|
9
|
+
config?: Record<string, string|boolean>,
|
10
|
+
}
|
11
|
+
|
12
|
+
export const getConfig = ( configFilePath?: string ): Config => {
|
13
|
+
let configFile: Config = {};
|
14
|
+
if ( configFilePath ) {
|
15
|
+
configFile = JSON.parse( fs.readFileSync( configFilePath, 'utf8' ) ) as Config;
|
16
|
+
}
|
17
|
+
|
18
|
+
const defaultConfig: Config = {
|
19
|
+
core: '6.7',
|
20
|
+
phpVersion: '8.1',
|
21
|
+
plugins: {},
|
22
|
+
themes: {},
|
23
|
+
mappings: {},
|
24
|
+
config: {},
|
25
|
+
};
|
26
|
+
|
27
|
+
return {
|
28
|
+
core: configFile.core || defaultConfig.core,
|
29
|
+
phpVersion: configFile.phpVersion || defaultConfig.phpVersion,
|
30
|
+
plugins: configFile.plugins || defaultConfig.plugins,
|
31
|
+
themes: configFile.themes || defaultConfig.themes,
|
32
|
+
mappings: configFile.mappings || defaultConfig.mappings,
|
33
|
+
config: configFile.config || defaultConfig.config,
|
34
|
+
};
|
35
|
+
};
|
package/src/run.ts
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
import {downAll, run, upAll} from "docker-compose";
|
2
|
+
import path from "path";
|
3
|
+
import {getConfig} from "./config";
|
4
|
+
import fs from "fs";
|
5
|
+
import {
|
6
|
+
generateCliDockerfileTemplate,
|
7
|
+
generateConfiguration,
|
8
|
+
generateDockerComposeYmlTemplate,
|
9
|
+
generateWordPressDockerfileTemplate
|
10
|
+
} from "./templates";
|
11
|
+
import {createHash} from "crypto";
|
12
|
+
import os from "node:os";
|
13
|
+
|
14
|
+
const waitForServer = async ( url: string, timeoutMs: number ) => {
|
15
|
+
const startTime = Date.now();
|
16
|
+
const sleep = ( ms: number ) => new Promise( ( r ) => setTimeout( r, ms ) );
|
17
|
+
|
18
|
+
while ( startTime + timeoutMs > Date.now() ) {
|
19
|
+
try {
|
20
|
+
const response = await fetch( url );
|
21
|
+
if ( response.ok && ( 200 === response.status || 302 === response.status ) ) {
|
22
|
+
return true;
|
23
|
+
}
|
24
|
+
} catch ( e ) { // eslint-disable-line @typescript-eslint/no-unused-vars
|
25
|
+
// Ignore
|
26
|
+
} finally {
|
27
|
+
await sleep( 100 );
|
28
|
+
}
|
29
|
+
}
|
30
|
+
return false;
|
31
|
+
};
|
32
|
+
|
33
|
+
export const start = async ( port: string, runPath: string ) => {
|
34
|
+
await upAll( {
|
35
|
+
commandOptions: [ '--build' ],
|
36
|
+
composeOptions: [ '-p', `port${ port }` ],
|
37
|
+
cwd: runPath,
|
38
|
+
log: true,
|
39
|
+
} );
|
40
|
+
await waitForServer( `http://localhost:${ port }`, 10000 );
|
41
|
+
await cli( port, runPath, 'bash wp-config/configure-wp.sh' );
|
42
|
+
};
|
43
|
+
|
44
|
+
export const stop = async ( port: string, runPath: string ) => {
|
45
|
+
await downAll( {
|
46
|
+
cwd: runPath,
|
47
|
+
commandOptions: [ '--volumes', '--remove-orphans' ],
|
48
|
+
composeOptions: [ '-p', `port${ port }` ],
|
49
|
+
log: true,
|
50
|
+
} );
|
51
|
+
};
|
52
|
+
|
53
|
+
const cli = async ( port: string, runPath: string, command: string ) => {
|
54
|
+
await run( 'cli', command, {
|
55
|
+
cwd: runPath,
|
56
|
+
commandOptions: [ '--rm' ],
|
57
|
+
composeOptions: [ '-p', `port${ port }` ],
|
58
|
+
log: true,
|
59
|
+
} );
|
60
|
+
};
|
61
|
+
|
62
|
+
export const commandMap: { [key: string]: ( ( port: string ) => Promise<void> ) | ( ( port: string, runPath: string, command: string ) => Promise<void> ) } = {
|
63
|
+
start,
|
64
|
+
stop,
|
65
|
+
cli,
|
66
|
+
};
|
67
|
+
|
68
|
+
const getWpConfigPath = ( port: string ) => path.resolve( process.cwd(), port );
|
69
|
+
|
70
|
+
export const generateFiles = ( port: string, configFilePath: string ) => {
|
71
|
+
const config = getConfig( configFilePath );
|
72
|
+
|
73
|
+
// Using a local path since Docker Compose cannot access /tmp
|
74
|
+
// See: https://github.com/docker/compose/issues/1153
|
75
|
+
const wpConfigPath = getWpConfigPath( port );
|
76
|
+
if ( ! fs.existsSync( wpConfigPath ) ) {
|
77
|
+
fs.mkdirSync( wpConfigPath, { recursive: true } );
|
78
|
+
}
|
79
|
+
const wpConfig = generateConfiguration( config, port );
|
80
|
+
fs.writeFileSync( path.resolve( wpConfigPath, 'configure-wp.sh' ), wpConfig );
|
81
|
+
|
82
|
+
const dockerComposeYmlTemplate = generateDockerComposeYmlTemplate( config, process.cwd(), port, wpConfigPath );
|
83
|
+
const wordPressDockerfileTemplate = generateWordPressDockerfileTemplate( config );
|
84
|
+
const cliDockerfileTemplate = generateCliDockerfileTemplate( config );
|
85
|
+
const hash = createHash( 'sha256' );
|
86
|
+
hash.update( dockerComposeYmlTemplate + wordPressDockerfileTemplate + cliDockerfileTemplate + port );
|
87
|
+
const runPath = path.resolve( os.tmpdir(), `${ hash.digest( 'hex' ) }` );
|
88
|
+
if ( ! fs.existsSync( runPath ) ) {
|
89
|
+
fs.mkdirSync( runPath );
|
90
|
+
}
|
91
|
+
|
92
|
+
console.log( `writing files to run path: ${ runPath }` );
|
93
|
+
fs.writeFileSync( path.resolve( runPath, 'docker-compose.yml' ), dockerComposeYmlTemplate );
|
94
|
+
fs.writeFileSync( path.resolve( runPath, 'WordPress.Dockerfile' ), wordPressDockerfileTemplate );
|
95
|
+
fs.writeFileSync( path.resolve( runPath, 'CLI.Dockerfile' ), cliDockerfileTemplate );
|
96
|
+
|
97
|
+
return runPath;
|
98
|
+
};
|
99
|
+
|
100
|
+
const getArgument = ( argumentKey: string, processArgs: string[] ) => {
|
101
|
+
for ( let i = 3; i < processArgs.length; i++ ) {
|
102
|
+
const argument = processArgs[ i ];
|
103
|
+
if ( argument.startsWith( `${ argumentKey }=` ) ) {
|
104
|
+
return argument.substring( argumentKey.length + 1 );
|
105
|
+
}
|
106
|
+
}
|
107
|
+
return undefined;
|
108
|
+
};
|
109
|
+
|
110
|
+
export const getConfigFilePath = ( processArgs: string[] ) => {
|
111
|
+
return path.resolve(getArgument( 'config', processArgs ));
|
112
|
+
};
|
113
|
+
|
114
|
+
export const getCliCommand = ( processArgs: string[] ) => {
|
115
|
+
return getArgument( 'command', processArgs );
|
116
|
+
};
|
117
|
+
|
118
|
+
export const getPort = ( processArgs: string[] ) => {
|
119
|
+
return getArgument( 'port', processArgs ) || '8888';
|
120
|
+
};
|
121
|
+
|
122
|
+
export const cleanup = ( port: string, runPath: string ) => {
|
123
|
+
fs.rmSync( getWpConfigPath( port ), { recursive: true, force: true } );
|
124
|
+
fs.rmSync( runPath, { recursive: true, force: true } );
|
125
|
+
}
|