@elementor/wp-lite-env 0.0.8 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
}
|