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' ;
9
+ import dotenv from 'dotenv' ;
8
10
import prompts from 'prompts' ;
9
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
+
10
16
/**
11
17
* Check if a directory is the monorepo root.
12
18
*
@@ -45,7 +51,6 @@ const findMonorepoRoot = startDir => {
45
51
* @throws {Error } If clone fails
46
52
*/
47
53
const cloneMonorepo = async targetDir => {
48
- // eslint-disable-next-line no-console
49
54
console . log ( chalk . blue ( 'Cloning Jetpack monorepo...' ) ) ;
50
55
const result = spawnSync (
51
56
'git' ,
@@ -83,15 +88,15 @@ const initJetpack = async () => {
83
88
84
89
try {
85
90
await cloneMonorepo ( targetDir ) ;
86
- // eslint-disable-next-line no-console
91
+
87
92
console . log ( chalk . green ( '\nJetpack monorepo has been cloned successfully!' ) ) ;
88
- // eslint-disable-next-line no-console
93
+
89
94
console . log ( '\nNext steps:' ) ;
90
- // eslint-disable-next-line no-console
95
+
91
96
console . log ( '1. cd' , response . directory ) ;
92
- // eslint-disable-next-line no-console
97
+
93
98
console . log ( '2. jp docker up' ) ;
94
- // eslint-disable-next-line no-console
99
+
95
100
console . log ( '3. jp docker install' ) ;
96
101
} catch ( error ) {
97
102
throw new Error ( `Failed to initialize Jetpack: ${ error . message } ` ) ;
@@ -103,6 +108,12 @@ const main = async () => {
103
108
try {
104
109
const args = process . argv . slice ( 2 ) ;
105
110
111
+ // Handle version flag
112
+ if ( args [ 0 ] === '--version' || args [ 0 ] === '-v' ) {
113
+ console . log ( chalk . green ( packageJson . version ) ) ;
114
+ return ;
115
+ }
116
+
106
117
// Handle 'init' command specially
107
118
if ( args [ 0 ] === 'init' ) {
108
119
await initJetpack ( ) ;
@@ -113,19 +124,145 @@ const main = async () => {
113
124
const monorepoRoot = findMonorepoRoot ( process . cwd ( ) ) ;
114
125
115
126
if ( ! monorepoRoot ) {
116
- // eslint-disable-next-line no-console
117
127
console . error ( chalk . red ( 'Could not find Jetpack monorepo.' ) ) ;
118
- // eslint-disable-next-line no-console
128
+
119
129
console . log ( '\nTo get started:' ) ;
120
- // eslint-disable-next-line no-console
130
+
121
131
console . log ( '1. Run' , chalk . blue ( 'jp init' ) , 'to clone the repository' ) ;
122
- // eslint-disable-next-line no-console
132
+
123
133
console . log ( ' OR' ) ;
124
- // eslint-disable-next-line no-console
134
+
125
135
console . log ( '2. Navigate to an existing Jetpack monorepo directory' ) ;
126
136
throw new Error ( 'Monorepo not found' ) ;
127
137
}
128
138
139
+ // Handle docker commands on the host
140
+ if ( args [ 0 ] === 'docker' ) {
141
+ // Commands that should run in the container
142
+ const containerCommands = [ 'build-image' , 'install' ] ;
143
+ if ( containerCommands . includes ( args [ 1 ] ) ) {
144
+ const result = spawnSync (
145
+ resolve ( monorepoRoot , 'tools/docker/bin/monorepo' ) ,
146
+ [ 'pnpm' , 'jetpack' , ...args ] ,
147
+ {
148
+ stdio : 'inherit' ,
149
+ shell : true ,
150
+ cwd : monorepoRoot ,
151
+ }
152
+ ) ;
153
+
154
+ if ( result . status !== 0 ) {
155
+ throw new Error ( `Command failed with status ${ result . status } ` ) ;
156
+ }
157
+ return ;
158
+ }
159
+
160
+ // Run config generation first if this is an 'up' command
161
+ if ( args [ 1 ] === 'up' ) {
162
+ // Create required directories
163
+ fs . mkdirSync ( resolve ( monorepoRoot , 'tools/docker/data/jetpack_dev_mysql' ) , {
164
+ recursive : true ,
165
+ } ) ;
166
+ fs . mkdirSync ( resolve ( monorepoRoot , 'tools/docker/data/ssh.keys' ) , { recursive : true } ) ;
167
+ fs . mkdirSync ( resolve ( monorepoRoot , 'tools/docker/wordpress' ) , { recursive : true } ) ;
168
+
169
+ const images = [
170
+ { name : 'mariadb:lts' } ,
171
+ { name : 'automattic/jetpack-wordpress-dev:latest' } ,
172
+ { name : 'phpmyadmin/phpmyadmin:latest' , platform : 'linux/amd64' } ,
173
+ { name : 'maildev/maildev' , platform : 'linux/amd64' } ,
174
+ { name : 'atmoz/sftp' , platform : 'linux/amd64' } ,
175
+ ] ;
176
+
177
+ for ( const image of images ) {
178
+ const inspect = spawnSync ( 'docker' , [ 'image' , 'inspect' , image . name ] , {
179
+ stdio : 'ignore' ,
180
+ } ) ;
181
+ if ( inspect . status !== 0 ) {
182
+ console . log ( chalk . blue ( `Pulling ${ image . name } ...` ) ) ;
183
+ const pullArgs = [ 'pull' , image . name ] ;
184
+ if ( image . platform ) {
185
+ pullArgs . splice ( 1 , 0 , '--platform' , image . platform ) ;
186
+ }
187
+ const pull = spawnSync ( 'docker' , pullArgs , { stdio : 'inherit' } ) ;
188
+ if ( pull . status !== 0 ) {
189
+ throw new Error ( `Failed to pull ${ image . name } ` ) ;
190
+ }
191
+ }
192
+ }
193
+
194
+ const configResult = spawnSync (
195
+ resolve ( monorepoRoot , 'tools/docker/bin/monorepo' ) ,
196
+ [ 'pnpm' , 'jetpack' , 'docker' , 'config' ] ,
197
+ {
198
+ stdio : 'inherit' ,
199
+ shell : true ,
200
+ cwd : monorepoRoot ,
201
+ }
202
+ ) ;
203
+
204
+ if ( configResult . status !== 0 ) {
205
+ throw new Error ( 'Failed to generate Docker config' ) ;
206
+ }
207
+ }
208
+
209
+ // Get project name (from docker.js)
210
+ const projectName = args . includes ( '--type=e2e' ) ? 'jetpack_e2e' : 'jetpack_dev' ;
211
+
212
+ // Load versions from .github/versions.sh
213
+ const versionsPath = resolve ( monorepoRoot , '.github/versions.sh' ) ;
214
+ const versions = fs . readFileSync ( versionsPath , 'utf8' ) ;
215
+ const versionVars = { } ;
216
+ versions . split ( '\n' ) . forEach ( line => {
217
+ const match = line . match ( / ^ ( [ A - Z _ ] + ) = ( .+ ) $ / ) ;
218
+ if ( match ) {
219
+ versionVars [ match [ 1 ] ] = match [ 2 ] . replace ( / [ ' " ] / g, '' ) ;
220
+ }
221
+ } ) ;
222
+
223
+ // Build environment variables (from docker.js)
224
+ const envVars = {
225
+ ...process . env ,
226
+ // Load from default.env
227
+ ...( fs . existsSync ( resolve ( monorepoRoot , 'tools/docker/default.env' ) )
228
+ ? dotenv . parse ( fs . readFileSync ( resolve ( monorepoRoot , 'tools/docker/default.env' ) ) )
229
+ : { } ) ,
230
+ // Load from .env if it exists
231
+ ...( fs . existsSync ( resolve ( monorepoRoot , 'tools/docker/.env' ) )
232
+ ? dotenv . parse ( fs . readFileSync ( resolve ( monorepoRoot , 'tools/docker/.env' ) ) )
233
+ : { } ) ,
234
+ HOST_CWD : monorepoRoot ,
235
+ PHP_VERSION : versionVars . PHP_VERSION ,
236
+ COMPOSER_VERSION : versionVars . COMPOSER_VERSION ,
237
+ NODE_VERSION : versionVars . NODE_VERSION ,
238
+ PNPM_VERSION : versionVars . PNPM_VERSION ,
239
+ COMPOSE_PROJECT_NAME : projectName ,
240
+ PORT_WORDPRESS : args . includes ( '--type=e2e' ) ? '8889' : '80' ,
241
+ } ;
242
+
243
+ // Build the list of compose files to use
244
+ const composeFiles = [
245
+ '-f' ,
246
+ resolve ( monorepoRoot , 'tools/docker/docker-compose.yml' ) ,
247
+ '-f' ,
248
+ resolve ( monorepoRoot , 'tools/docker/compose-mappings.built.yml' ) ,
249
+ '-f' ,
250
+ resolve ( monorepoRoot , 'tools/docker/compose-extras.built.yml' ) ,
251
+ ] ;
252
+
253
+ const result = spawnSync ( 'docker' , [ 'compose' , ...composeFiles , ...args . slice ( 1 ) ] , {
254
+ stdio : 'inherit' ,
255
+ shell : true ,
256
+ cwd : resolve ( monorepoRoot , 'tools/docker' ) ,
257
+ env : envVars ,
258
+ } ) ;
259
+
260
+ if ( result . status !== 0 ) {
261
+ throw new Error ( `Docker command failed with status ${ result . status } ` ) ;
262
+ }
263
+ return ;
264
+ }
265
+
129
266
// Run the monorepo script with the original arguments
130
267
const result = spawnSync (
131
268
resolve ( monorepoRoot , 'tools/docker/bin/monorepo' ) ,
@@ -141,7 +278,6 @@ const main = async () => {
141
278
throw new Error ( `Command failed with status ${ result . status } ` ) ;
142
279
}
143
280
} catch ( error ) {
144
- // eslint-disable-next-line no-console
145
281
console . error ( chalk . red ( error . message ) ) ;
146
282
process . exitCode = 1 ;
147
283
}
0 commit comments