@automattic/jetpack-cli 0.1.0-beta.2 → 0.1.0-beta3
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/README.md +18 -0
- package/bin/jp.js +149 -124
- package/package.json +2 -2
package/README.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Jetpack
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
## How to install Jetpack plugin on your site
|
|
5
|
+
### Installation From Git Repo
|
|
6
|
+
|
|
7
|
+
## Contribute
|
|
8
|
+
|
|
9
|
+
## Get Help
|
|
10
|
+
|
|
11
|
+
## Security
|
|
12
|
+
|
|
13
|
+
Need to report a security vulnerability? Go to [https://automattic.com/security/](https://automattic.com/security/) or directly to our security bug bounty site [https://hackerone.com/automattic](https://hackerone.com/automattic).
|
|
14
|
+
|
|
15
|
+
## License
|
|
16
|
+
|
|
17
|
+
Licensed under [GNU General Public License v2 (or later)](./LICENSE.txt).
|
|
18
|
+
|
package/bin/jp.js
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { spawnSync } from 'child_process';
|
|
4
|
-
import fs from 'fs';
|
|
4
|
+
import fs, { readFileSync } from 'fs';
|
|
5
5
|
import { dirname, resolve } from 'path';
|
|
6
6
|
import process from 'process';
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
7
8
|
import chalk from 'chalk';
|
|
8
9
|
import dotenv from 'dotenv';
|
|
9
10
|
import prompts from 'prompts';
|
|
10
11
|
|
|
12
|
+
// Get package.json path relative to this file
|
|
13
|
+
const __dirname = dirname( fileURLToPath( import.meta.url ) );
|
|
14
|
+
const packageJson = JSON.parse( readFileSync( resolve( __dirname, '../package.json' ), 'utf8' ) );
|
|
15
|
+
|
|
11
16
|
/**
|
|
12
17
|
* Check if a directory is the monorepo root.
|
|
13
18
|
*
|
|
@@ -46,7 +51,6 @@ const findMonorepoRoot = startDir => {
|
|
|
46
51
|
* @throws {Error} If clone fails
|
|
47
52
|
*/
|
|
48
53
|
const cloneMonorepo = async targetDir => {
|
|
49
|
-
// eslint-disable-next-line no-console
|
|
50
54
|
console.log( chalk.blue( 'Cloning Jetpack monorepo...' ) );
|
|
51
55
|
const result = spawnSync(
|
|
52
56
|
'git',
|
|
@@ -84,15 +88,15 @@ const initJetpack = async () => {
|
|
|
84
88
|
|
|
85
89
|
try {
|
|
86
90
|
await cloneMonorepo( targetDir );
|
|
87
|
-
|
|
91
|
+
|
|
88
92
|
console.log( chalk.green( '\nJetpack monorepo has been cloned successfully!' ) );
|
|
89
|
-
|
|
93
|
+
|
|
90
94
|
console.log( '\nNext steps:' );
|
|
91
|
-
|
|
95
|
+
|
|
92
96
|
console.log( '1. cd', response.directory );
|
|
93
|
-
|
|
97
|
+
|
|
94
98
|
console.log( '2. jp docker up' );
|
|
95
|
-
|
|
99
|
+
|
|
96
100
|
console.log( '3. jp docker install' );
|
|
97
101
|
} catch ( error ) {
|
|
98
102
|
throw new Error( `Failed to initialize Jetpack: ${ error.message }` );
|
|
@@ -104,6 +108,12 @@ const main = async () => {
|
|
|
104
108
|
try {
|
|
105
109
|
const args = process.argv.slice( 2 );
|
|
106
110
|
|
|
111
|
+
// Handle version flag
|
|
112
|
+
if ( args[ 0 ] === '--version' || args[ 0 ] === '-v' ) {
|
|
113
|
+
console.log( chalk.green( packageJson.version ) );
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
107
117
|
// Handle 'init' command specially
|
|
108
118
|
if ( args[ 0 ] === 'init' ) {
|
|
109
119
|
await initJetpack();
|
|
@@ -114,144 +124,160 @@ const main = async () => {
|
|
|
114
124
|
const monorepoRoot = findMonorepoRoot( process.cwd() );
|
|
115
125
|
|
|
116
126
|
if ( ! monorepoRoot ) {
|
|
117
|
-
// eslint-disable-next-line no-console
|
|
118
127
|
console.error( chalk.red( 'Could not find Jetpack monorepo.' ) );
|
|
119
|
-
|
|
128
|
+
|
|
120
129
|
console.log( '\nTo get started:' );
|
|
121
|
-
|
|
130
|
+
|
|
122
131
|
console.log( '1. Run', chalk.blue( 'jp init' ), 'to clone the repository' );
|
|
123
|
-
|
|
132
|
+
|
|
124
133
|
console.log( ' OR' );
|
|
125
|
-
|
|
134
|
+
|
|
126
135
|
console.log( '2. Navigate to an existing Jetpack monorepo directory' );
|
|
127
136
|
throw new Error( 'Monorepo not found' );
|
|
128
137
|
}
|
|
129
138
|
|
|
130
|
-
// Handle docker commands on the host
|
|
139
|
+
// Handle docker commands that must run on the host machine
|
|
131
140
|
if ( args[ 0 ] === 'docker' ) {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
143
|
-
|
|
141
|
+
const hostCommands = [ 'up', 'down', 'stop', 'clean' ];
|
|
142
|
+
if ( hostCommands.includes( args[ 1 ] ) ) {
|
|
143
|
+
// Handle command-specific setup/cleanup
|
|
144
|
+
if ( args[ 1 ] === 'up' ) {
|
|
145
|
+
// Create required directories
|
|
146
|
+
fs.mkdirSync( resolve( monorepoRoot, 'tools/docker/data/jetpack_dev_mysql' ), {
|
|
147
|
+
recursive: true,
|
|
148
|
+
} );
|
|
149
|
+
fs.mkdirSync( resolve( monorepoRoot, 'tools/docker/data/ssh.keys' ), {
|
|
150
|
+
recursive: true,
|
|
151
|
+
} );
|
|
152
|
+
fs.mkdirSync( resolve( monorepoRoot, 'tools/docker/wordpress' ), { recursive: true } );
|
|
144
153
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
154
|
+
// Create empty .env file
|
|
155
|
+
fs.writeFileSync( resolve( monorepoRoot, 'tools/docker/.env' ), '' );
|
|
150
156
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
fs.mkdirSync( resolve( monorepoRoot, 'tools/docker/wordpress' ), { recursive: true } );
|
|
159
|
-
|
|
160
|
-
const images = [
|
|
161
|
-
{ name: 'mariadb:lts' },
|
|
162
|
-
{ name: 'automattic/jetpack-wordpress-dev:latest' },
|
|
163
|
-
{ name: 'phpmyadmin/phpmyadmin:latest', platform: 'linux/amd64' },
|
|
164
|
-
{ name: 'maildev/maildev', platform: 'linux/amd64' },
|
|
165
|
-
{ name: 'atmoz/sftp', platform: 'linux/amd64' },
|
|
166
|
-
];
|
|
157
|
+
const images = [
|
|
158
|
+
{ name: 'mariadb:lts' },
|
|
159
|
+
{ name: 'automattic/jetpack-wordpress-dev:latest' },
|
|
160
|
+
{ name: 'phpmyadmin/phpmyadmin:latest', platform: 'linux/amd64' },
|
|
161
|
+
{ name: 'maildev/maildev', platform: 'linux/amd64' },
|
|
162
|
+
{ name: 'atmoz/sftp', platform: 'linux/amd64' },
|
|
163
|
+
];
|
|
167
164
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
165
|
+
for ( const image of images ) {
|
|
166
|
+
const inspect = spawnSync( 'docker', [ 'image', 'inspect', image.name ], {
|
|
167
|
+
stdio: 'ignore',
|
|
168
|
+
} );
|
|
169
|
+
if ( inspect.status !== 0 ) {
|
|
170
|
+
console.log( chalk.blue( `Pulling ${ image.name }...` ) );
|
|
171
|
+
const pullArgs = [ 'pull', image.name ];
|
|
172
|
+
if ( image.platform ) {
|
|
173
|
+
pullArgs.splice( 1, 0, '--platform', image.platform );
|
|
174
|
+
}
|
|
175
|
+
const pull = spawnSync( 'docker', pullArgs, { stdio: 'inherit' } );
|
|
176
|
+
if ( pull.status !== 0 ) {
|
|
177
|
+
throw new Error( `Failed to pull ${ image.name }` );
|
|
178
|
+
}
|
|
177
179
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const configResult = spawnSync(
|
|
183
|
+
resolve( monorepoRoot, 'tools/docker/bin/monorepo' ),
|
|
184
|
+
[ 'pnpm', 'jetpack', 'docker', 'config' ],
|
|
185
|
+
{
|
|
186
|
+
stdio: 'inherit',
|
|
187
|
+
shell: true,
|
|
188
|
+
cwd: monorepoRoot,
|
|
181
189
|
}
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
if ( configResult.status !== 0 ) {
|
|
193
|
+
throw new Error( 'Failed to generate Docker config' );
|
|
182
194
|
}
|
|
195
|
+
} else if ( args[ 1 ] === 'clean' ) {
|
|
196
|
+
// After docker-compose down -v, also remove local files
|
|
197
|
+
const projectName = args.includes( '--type=e2e' ) ? 'jetpack_e2e' : 'jetpack_dev';
|
|
198
|
+
const cleanupPaths = [
|
|
199
|
+
resolve( monorepoRoot, 'tools/docker/wordpress/' ),
|
|
200
|
+
resolve( monorepoRoot, 'tools/docker/wordpress-develop/*' ),
|
|
201
|
+
resolve( monorepoRoot, 'tools/docker/logs/', projectName ),
|
|
202
|
+
resolve( monorepoRoot, 'tools/docker/data/', `${ projectName }_mysql` ),
|
|
203
|
+
];
|
|
204
|
+
|
|
205
|
+
// Function to clean up after docker-compose down
|
|
206
|
+
const cleanupFiles = () => {
|
|
207
|
+
for ( const path of cleanupPaths ) {
|
|
208
|
+
try {
|
|
209
|
+
fs.rmSync( path, { recursive: true, force: true } );
|
|
210
|
+
} catch ( error ) {
|
|
211
|
+
console.warn(
|
|
212
|
+
chalk.yellow( `Warning: Could not remove ${ path }: ${ error.message }` )
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
// Add cleanup to process events to ensure it runs after docker-compose
|
|
219
|
+
process.once( 'beforeExit', cleanupFiles );
|
|
220
|
+
|
|
221
|
+
// Replace 'clean' with 'down -v' in the arguments
|
|
222
|
+
args.splice( 1, 1, 'down', '-v' );
|
|
183
223
|
}
|
|
184
224
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
225
|
+
// Get project name (from docker.js)
|
|
226
|
+
const projectName = args.includes( '--type=e2e' ) ? 'jetpack_e2e' : 'jetpack_dev';
|
|
227
|
+
|
|
228
|
+
// Load versions from .github/versions.sh
|
|
229
|
+
const versionsPath = resolve( monorepoRoot, '.github/versions.sh' );
|
|
230
|
+
const versions = fs.readFileSync( versionsPath, 'utf8' );
|
|
231
|
+
const versionVars = {};
|
|
232
|
+
versions.split( '\n' ).forEach( line => {
|
|
233
|
+
const match = line.match( /^([A-Z_]+)=(.+)$/ );
|
|
234
|
+
if ( match ) {
|
|
235
|
+
versionVars[ match[ 1 ] ] = match[ 2 ].replace( /['"]/g, '' );
|
|
192
236
|
}
|
|
193
|
-
);
|
|
237
|
+
} );
|
|
194
238
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
239
|
+
// Build environment variables (from docker.js)
|
|
240
|
+
const envVars = {
|
|
241
|
+
...process.env,
|
|
242
|
+
// Load from default.env
|
|
243
|
+
...( fs.existsSync( resolve( monorepoRoot, 'tools/docker/default.env' ) )
|
|
244
|
+
? dotenv.parse( fs.readFileSync( resolve( monorepoRoot, 'tools/docker/default.env' ) ) )
|
|
245
|
+
: {} ),
|
|
246
|
+
// Load from .env if it exists
|
|
247
|
+
...( fs.existsSync( resolve( monorepoRoot, 'tools/docker/.env' ) )
|
|
248
|
+
? dotenv.parse( fs.readFileSync( resolve( monorepoRoot, 'tools/docker/.env' ) ) )
|
|
249
|
+
: {} ),
|
|
250
|
+
HOST_CWD: monorepoRoot,
|
|
251
|
+
PHP_VERSION: versionVars.PHP_VERSION,
|
|
252
|
+
COMPOSER_VERSION: versionVars.COMPOSER_VERSION,
|
|
253
|
+
NODE_VERSION: versionVars.NODE_VERSION,
|
|
254
|
+
PNPM_VERSION: versionVars.PNPM_VERSION,
|
|
255
|
+
COMPOSE_PROJECT_NAME: projectName,
|
|
256
|
+
PORT_WORDPRESS: args.includes( '--type=e2e' ) ? '8889' : '80',
|
|
257
|
+
};
|
|
199
258
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
if ( match ) {
|
|
210
|
-
versionVars[ match[ 1 ] ] = match[ 2 ].replace( /['"]/g, '' );
|
|
211
|
-
}
|
|
212
|
-
} );
|
|
213
|
-
|
|
214
|
-
// Build environment variables (from docker.js)
|
|
215
|
-
const envVars = {
|
|
216
|
-
...process.env,
|
|
217
|
-
// Load from default.env
|
|
218
|
-
...( fs.existsSync( resolve( monorepoRoot, 'tools/docker/default.env' ) )
|
|
219
|
-
? dotenv.parse( fs.readFileSync( resolve( monorepoRoot, 'tools/docker/default.env' ) ) )
|
|
220
|
-
: {} ),
|
|
221
|
-
// Load from .env if it exists
|
|
222
|
-
...( fs.existsSync( resolve( monorepoRoot, 'tools/docker/.env' ) )
|
|
223
|
-
? dotenv.parse( fs.readFileSync( resolve( monorepoRoot, 'tools/docker/.env' ) ) )
|
|
224
|
-
: {} ),
|
|
225
|
-
HOST_CWD: monorepoRoot,
|
|
226
|
-
PHP_VERSION: versionVars.PHP_VERSION,
|
|
227
|
-
COMPOSER_VERSION: versionVars.COMPOSER_VERSION,
|
|
228
|
-
NODE_VERSION: versionVars.NODE_VERSION,
|
|
229
|
-
PNPM_VERSION: versionVars.PNPM_VERSION,
|
|
230
|
-
COMPOSE_PROJECT_NAME: projectName,
|
|
231
|
-
PORT_WORDPRESS: args.includes( '--type=e2e' ) ? '8889' : '80',
|
|
232
|
-
};
|
|
233
|
-
|
|
234
|
-
// Build the list of compose files to use
|
|
235
|
-
const composeFiles = [
|
|
236
|
-
'-f',
|
|
237
|
-
resolve( monorepoRoot, 'tools/docker/docker-compose.yml' ),
|
|
238
|
-
'-f',
|
|
239
|
-
resolve( monorepoRoot, 'tools/docker/compose-mappings.built.yml' ),
|
|
240
|
-
'-f',
|
|
241
|
-
resolve( monorepoRoot, 'tools/docker/compose-extras.built.yml' ),
|
|
242
|
-
];
|
|
243
|
-
|
|
244
|
-
const result = spawnSync( 'docker', [ 'compose', ...composeFiles, ...args.slice( 1 ) ], {
|
|
245
|
-
stdio: 'inherit',
|
|
246
|
-
shell: true,
|
|
247
|
-
cwd: resolve( monorepoRoot, 'tools/docker' ),
|
|
248
|
-
env: envVars,
|
|
249
|
-
} );
|
|
259
|
+
// Build the list of compose files to use
|
|
260
|
+
const composeFiles = [
|
|
261
|
+
'-f',
|
|
262
|
+
resolve( monorepoRoot, 'tools/docker/docker-compose.yml' ),
|
|
263
|
+
'-f',
|
|
264
|
+
resolve( monorepoRoot, 'tools/docker/compose-mappings.built.yml' ),
|
|
265
|
+
'-f',
|
|
266
|
+
resolve( monorepoRoot, 'tools/docker/compose-extras.built.yml' ),
|
|
267
|
+
];
|
|
250
268
|
|
|
251
|
-
|
|
252
|
-
|
|
269
|
+
const result = spawnSync( 'docker', [ 'compose', ...composeFiles, ...args.slice( 1 ) ], {
|
|
270
|
+
stdio: 'inherit',
|
|
271
|
+
shell: true,
|
|
272
|
+
cwd: resolve( monorepoRoot, 'tools/docker' ),
|
|
273
|
+
env: envVars,
|
|
274
|
+
} );
|
|
275
|
+
|
|
276
|
+
if ( result.status !== 0 ) {
|
|
277
|
+
throw new Error( `Docker command failed with status ${ result.status }` );
|
|
278
|
+
}
|
|
279
|
+
return;
|
|
253
280
|
}
|
|
254
|
-
return;
|
|
255
281
|
}
|
|
256
282
|
|
|
257
283
|
// Run the monorepo script with the original arguments
|
|
@@ -269,7 +295,6 @@ const main = async () => {
|
|
|
269
295
|
throw new Error( `Command failed with status ${ result.status }` );
|
|
270
296
|
}
|
|
271
297
|
} catch ( error ) {
|
|
272
|
-
// eslint-disable-next-line no-console
|
|
273
298
|
console.error( chalk.red( error.message ) );
|
|
274
299
|
process.exitCode = 1;
|
|
275
300
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automattic/jetpack-cli",
|
|
3
|
-
"version": "0.1.0-
|
|
3
|
+
"version": "0.1.0-beta3",
|
|
4
4
|
"description": "Docker-based CLI for Jetpack development",
|
|
5
5
|
"bin": {
|
|
6
6
|
"jp": "bin/jp.js"
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
],
|
|
11
11
|
"type": "module",
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"chalk": "^4.1
|
|
13
|
+
"chalk": "^5.4.1",
|
|
14
14
|
"dotenv": "^16.3.1",
|
|
15
15
|
"prompts": "^2.4.2"
|
|
16
16
|
},
|