@cruxgarden/cli 0.0.9 → 0.0.10
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 +85 -9
- package/bin/crux.js +17 -9
- package/docker/docker-compose.nursery.yml +25 -14
- package/lib/commands.js +135 -29
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -57,7 +57,7 @@ Start the Nursery environment:
|
|
|
57
57
|
crux nursery start
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
-
The
|
|
60
|
+
The App will be available at `http://localhost:8080` and the API at `http://localhost:3000` with demo data loaded.
|
|
61
61
|
|
|
62
62
|
View logs:
|
|
63
63
|
|
|
@@ -77,15 +77,26 @@ All commands are scoped under `crux nursery`:
|
|
|
77
77
|
|
|
78
78
|
### `crux nursery start`
|
|
79
79
|
|
|
80
|
-
Start the Nursery environment (
|
|
80
|
+
Start the Nursery environment (App, API, PostgreSQL, Redis with demo data).
|
|
81
81
|
|
|
82
82
|
```bash
|
|
83
83
|
crux nursery start
|
|
84
|
+
|
|
85
|
+
# With inline environment variables
|
|
86
|
+
crux nursery start API_PORT=3001 APP_PORT=8081
|
|
87
|
+
|
|
88
|
+
# With options and environment variables
|
|
89
|
+
crux nursery start --api-only JWT_SECRET=my-secret
|
|
84
90
|
```
|
|
85
91
|
|
|
86
92
|
**Options:**
|
|
87
93
|
|
|
88
94
|
- `--db-only` - Start only database services (PostgreSQL and Redis)
|
|
95
|
+
- `--api-only` - Start only API services (API, PostgreSQL, Redis) without the App
|
|
96
|
+
|
|
97
|
+
**Environment Variables:**
|
|
98
|
+
|
|
99
|
+
You can pass environment variables directly on the command line in `KEY=VALUE` format after the command and options. These override values from your `.env` file.
|
|
89
100
|
|
|
90
101
|
### `crux nursery stop`
|
|
91
102
|
|
|
@@ -103,6 +114,11 @@ Restart the Nursery environment.
|
|
|
103
114
|
crux nursery restart
|
|
104
115
|
```
|
|
105
116
|
|
|
117
|
+
**Options:**
|
|
118
|
+
|
|
119
|
+
- `--db-only` - Restart only database services (PostgreSQL and Redis)
|
|
120
|
+
- `--api-only` - Restart only API services (API, PostgreSQL, Redis) without the App
|
|
121
|
+
|
|
106
122
|
### `crux nursery status`
|
|
107
123
|
|
|
108
124
|
Show the status of all Nursery services.
|
|
@@ -198,6 +214,14 @@ Connect to Nursery Redis with `redis-cli`.
|
|
|
198
214
|
crux nursery redis connect
|
|
199
215
|
```
|
|
200
216
|
|
|
217
|
+
### `crux nursery api start`
|
|
218
|
+
|
|
219
|
+
Start only Nursery API services (API, PostgreSQL, Redis) without the App.
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
crux nursery api start
|
|
223
|
+
```
|
|
224
|
+
|
|
201
225
|
### `crux nursery api connect`
|
|
202
226
|
|
|
203
227
|
Open a shell in the Nursery API container.
|
|
@@ -217,31 +241,81 @@ The Nursery is a production-like demo environment that:
|
|
|
217
241
|
|
|
218
242
|
**Services:**
|
|
219
243
|
|
|
244
|
+
- **App**: `http://localhost:8080` - Crux Garden Web Application
|
|
220
245
|
- **API**: `http://localhost:3000` - Crux Garden API (published image with demo data)
|
|
221
246
|
- **PostgreSQL**: `localhost:5432` - Database
|
|
222
247
|
- **Redis**: `localhost:6379` - Cache
|
|
223
248
|
|
|
224
249
|
## Environment Variables
|
|
225
250
|
|
|
226
|
-
The Nursery environment has defaults for all environment variables, so
|
|
251
|
+
The Nursery environment has defaults for all environment variables, so configuration is optional. You can override variables in two ways:
|
|
252
|
+
|
|
253
|
+
### 1. Using a `.env` file
|
|
254
|
+
|
|
255
|
+
Create a `.env` file in your working directory:
|
|
227
256
|
|
|
228
257
|
```bash
|
|
229
|
-
#
|
|
258
|
+
# Port Mappings
|
|
259
|
+
API_PORT=3000 # External API port
|
|
260
|
+
APP_PORT=8080 # External App port
|
|
261
|
+
POSTGRES_PORT=5432 # External PostgreSQL port
|
|
262
|
+
REDIS_PORT=6379 # External Redis port
|
|
263
|
+
|
|
264
|
+
# PostgreSQL Configuration
|
|
265
|
+
POSTGRES_DB=cruxgarden
|
|
266
|
+
POSTGRES_USER=cruxgarden
|
|
267
|
+
POSTGRES_PASSWORD=cruxgarden_nursery_password
|
|
268
|
+
|
|
269
|
+
# Database & Cache URLs (override to use external services)
|
|
270
|
+
DATABASE_URL=postgresql://cruxgarden:cruxgarden_nursery_password@postgres:5432/cruxgarden
|
|
271
|
+
REDIS_URL=redis://redis:6379
|
|
272
|
+
|
|
273
|
+
# Security (has dev default, but you should use a different one)
|
|
230
274
|
JWT_SECRET=your-super-secret-jwt-key-min-32-chars
|
|
231
275
|
|
|
232
|
-
# AWS (defaults to "dummy" values)
|
|
276
|
+
# AWS Configuration (defaults to "dummy" values)
|
|
233
277
|
AWS_ACCESS_KEY_ID=your-key
|
|
234
278
|
AWS_SECRET_ACCESS_KEY=your-secret
|
|
235
279
|
AWS_REGION=us-east-1
|
|
236
280
|
AWS_SES_FROM_EMAIL=demo@example.com
|
|
237
281
|
AWS_S3_ATTACHMENTS_BUCKET=crux-garden-attachments
|
|
238
282
|
|
|
239
|
-
# Optional
|
|
283
|
+
# Optional Configuration
|
|
284
|
+
NODE_ENV=production
|
|
240
285
|
CORS_ORIGIN=*
|
|
241
286
|
LOG_LEVEL=info
|
|
242
|
-
|
|
287
|
+
HOSTNAME=0.0.0.0
|
|
288
|
+
DB_POOL_MIN=2
|
|
289
|
+
DB_POOL_MAX=10
|
|
290
|
+
DB_POOL_IDLE_TIMEOUT=30000
|
|
291
|
+
DB_POOL_ACQUIRE_TIMEOUT=60000
|
|
292
|
+
RATE_LIMIT_TTL=60000
|
|
293
|
+
RATE_LIMIT_MAX=100
|
|
243
294
|
```
|
|
244
295
|
|
|
296
|
+
### 2. Using inline environment variables
|
|
297
|
+
|
|
298
|
+
Pass environment variables directly on the command line:
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
# Override ports
|
|
302
|
+
crux nursery start API_PORT=3001 APP_PORT=8081
|
|
303
|
+
|
|
304
|
+
# Override database connection
|
|
305
|
+
crux nursery start DATABASE_URL=postgresql://user:pass@external-host:5432/db
|
|
306
|
+
|
|
307
|
+
# Multiple variables
|
|
308
|
+
crux nursery start API_PORT=3001 JWT_SECRET=my-secret AWS_REGION=us-west-2
|
|
309
|
+
|
|
310
|
+
# Works with all start commands
|
|
311
|
+
crux nursery api start API_PORT=4000
|
|
312
|
+
crux nursery db start POSTGRES_PORT=5433
|
|
313
|
+
crux nursery restart API_PORT=3001
|
|
314
|
+
crux nursery reset JWT_SECRET=new-secret
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
**Note:** Inline environment variables override values from your `.env` file. You can override `DATABASE_URL` and `REDIS_URL` to connect the API to external database/cache services instead of the bundled ones.
|
|
318
|
+
|
|
245
319
|
## Common Workflows
|
|
246
320
|
|
|
247
321
|
### Demo/Trial Setup
|
|
@@ -249,10 +323,11 @@ PORT=3000
|
|
|
249
323
|
Use the Nursery environment for demos, trials, or showcasing features:
|
|
250
324
|
|
|
251
325
|
```bash
|
|
252
|
-
# First time setup - pulls
|
|
326
|
+
# First time setup - pulls images and starts with demo data
|
|
253
327
|
crux nursery start
|
|
254
328
|
|
|
255
|
-
# View the
|
|
329
|
+
# View the app at http://localhost:8080
|
|
330
|
+
# Or access the API directly at http://localhost:3000
|
|
256
331
|
|
|
257
332
|
# Stop (keeps data for next demo)
|
|
258
333
|
crux nursery stop
|
|
@@ -304,6 +379,7 @@ If you get an error about ports being in use, stop any existing services:
|
|
|
304
379
|
|
|
305
380
|
```bash
|
|
306
381
|
# Check what's using the ports
|
|
382
|
+
lsof -i :8080 # Nursery App
|
|
307
383
|
lsof -i :3000 # Nursery API
|
|
308
384
|
lsof -i :5432 # Nursery PostgreSQL
|
|
309
385
|
lsof -i :6379 # Nursery Redis
|
package/bin/crux.js
CHANGED
|
@@ -37,13 +37,14 @@ const nursery = program
|
|
|
37
37
|
.description("Manage the Nursery environment (demo/trial environment)");
|
|
38
38
|
|
|
39
39
|
nursery
|
|
40
|
-
.command("start")
|
|
41
|
-
.description("Start the Nursery environment (api, postgres, redis)")
|
|
40
|
+
.command("start [env...]")
|
|
41
|
+
.description("Start the Nursery environment (app, api, postgres, redis)")
|
|
42
42
|
.option("--db-only", "Start only database services (postgres, redis)")
|
|
43
|
+
.option("--api-only", "Start only API services (api, postgres, redis) without app")
|
|
43
44
|
.option("--no-banner", "Hide the startup banner")
|
|
44
|
-
.action((options) => {
|
|
45
|
+
.action((envVars, options) => {
|
|
45
46
|
if (!options.noBanner) showBanner();
|
|
46
|
-
startNursery(options);
|
|
47
|
+
startNursery(options, envVars);
|
|
47
48
|
});
|
|
48
49
|
|
|
49
50
|
nursery
|
|
@@ -52,9 +53,11 @@ nursery
|
|
|
52
53
|
.action(stopNursery);
|
|
53
54
|
|
|
54
55
|
nursery
|
|
55
|
-
.command("restart")
|
|
56
|
+
.command("restart [env...]")
|
|
56
57
|
.description("Restart the Nursery environment")
|
|
57
|
-
.
|
|
58
|
+
.option("--db-only", "Restart only database services (postgres, redis)")
|
|
59
|
+
.option("--api-only", "Restart only API services (api, postgres, redis) without app")
|
|
60
|
+
.action((envVars, options) => restartNursery(options, envVars));
|
|
58
61
|
|
|
59
62
|
nursery
|
|
60
63
|
.command("status")
|
|
@@ -85,7 +88,7 @@ nursery
|
|
|
85
88
|
.action(updateNursery);
|
|
86
89
|
|
|
87
90
|
nursery
|
|
88
|
-
.command("reset")
|
|
91
|
+
.command("reset [env...]")
|
|
89
92
|
.description("Complete fresh reset (stop, clean, pull latest image, restart)")
|
|
90
93
|
.action(resetNursery);
|
|
91
94
|
|
|
@@ -95,9 +98,9 @@ const nurseryDb = nursery
|
|
|
95
98
|
.description("Manage Nursery database services");
|
|
96
99
|
|
|
97
100
|
nurseryDb
|
|
98
|
-
.command("start")
|
|
101
|
+
.command("start [env...]")
|
|
99
102
|
.description("Start only Nursery database services (postgres, redis)")
|
|
100
|
-
.action(() => startNursery({ dbOnly: true }));
|
|
103
|
+
.action((envVars) => startNursery({ dbOnly: true }, envVars));
|
|
101
104
|
|
|
102
105
|
nurseryDb
|
|
103
106
|
.command("stop")
|
|
@@ -122,6 +125,11 @@ nurseryRedis
|
|
|
122
125
|
// Nursery API commands
|
|
123
126
|
const nurseryApi = nursery.command("api").description("Manage Nursery API");
|
|
124
127
|
|
|
128
|
+
nurseryApi
|
|
129
|
+
.command("start [env...]")
|
|
130
|
+
.description("Start only Nursery API services (api, postgres, redis) without app")
|
|
131
|
+
.action((envVars) => startNursery({ apiOnly: true }, envVars));
|
|
132
|
+
|
|
125
133
|
nurseryApi
|
|
126
134
|
.command("connect")
|
|
127
135
|
.description("Open a shell in the Nursery API container")
|
|
@@ -12,15 +12,15 @@ services:
|
|
|
12
12
|
image: postgres:16-alpine
|
|
13
13
|
container_name: cruxgarden-nursery-postgres
|
|
14
14
|
environment:
|
|
15
|
-
POSTGRES_DB: cruxgarden
|
|
16
|
-
POSTGRES_USER: cruxgarden
|
|
17
|
-
POSTGRES_PASSWORD: cruxgarden_nursery_password
|
|
15
|
+
POSTGRES_DB: ${POSTGRES_DB:-cruxgarden}
|
|
16
|
+
POSTGRES_USER: ${POSTGRES_USER:-cruxgarden}
|
|
17
|
+
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-cruxgarden_nursery_password}
|
|
18
18
|
ports:
|
|
19
|
-
- "5432:5432"
|
|
19
|
+
- "${POSTGRES_PORT:-5432}:5432"
|
|
20
20
|
volumes:
|
|
21
21
|
- postgres_data_nursery:/var/lib/postgresql/data
|
|
22
22
|
healthcheck:
|
|
23
|
-
test: ["CMD-SHELL", "pg_isready -U cruxgarden"]
|
|
23
|
+
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-cruxgarden}"]
|
|
24
24
|
interval: 5s
|
|
25
25
|
timeout: 5s
|
|
26
26
|
retries: 5
|
|
@@ -31,7 +31,7 @@ services:
|
|
|
31
31
|
container_name: cruxgarden-nursery-redis
|
|
32
32
|
command: redis-server --appendonly yes
|
|
33
33
|
ports:
|
|
34
|
-
- "6379:6379"
|
|
34
|
+
- "${REDIS_PORT:-6379}:6379"
|
|
35
35
|
volumes:
|
|
36
36
|
- redis_data_nursery:/data
|
|
37
37
|
healthcheck:
|
|
@@ -48,8 +48,8 @@ services:
|
|
|
48
48
|
postgres:
|
|
49
49
|
condition: service_healthy
|
|
50
50
|
environment:
|
|
51
|
-
NODE_ENV: production
|
|
52
|
-
DATABASE_URL: postgresql://cruxgarden:cruxgarden_nursery_password@postgres:5432/cruxgarden
|
|
51
|
+
NODE_ENV: ${NODE_ENV:-production}
|
|
52
|
+
DATABASE_URL: ${DATABASE_URL:-postgresql://cruxgarden:cruxgarden_nursery_password@postgres:5432/cruxgarden}
|
|
53
53
|
command: ["npm", "run", "migrate:nursery"]
|
|
54
54
|
restart: "no"
|
|
55
55
|
|
|
@@ -64,16 +64,16 @@ services:
|
|
|
64
64
|
redis:
|
|
65
65
|
condition: service_healthy
|
|
66
66
|
ports:
|
|
67
|
-
- "${
|
|
67
|
+
- "${API_PORT:-3000}:3000"
|
|
68
68
|
environment:
|
|
69
69
|
# Application
|
|
70
|
-
NODE_ENV: production
|
|
70
|
+
NODE_ENV: ${NODE_ENV:-production}
|
|
71
71
|
PORT: 3000
|
|
72
|
-
HOSTNAME: 0.0.0.0
|
|
72
|
+
HOSTNAME: ${HOSTNAME:-0.0.0.0}
|
|
73
73
|
|
|
74
|
-
# Bundled Services
|
|
75
|
-
DATABASE_URL: postgresql://cruxgarden:cruxgarden_nursery_password@postgres:5432/cruxgarden
|
|
76
|
-
REDIS_URL: redis://redis:6379
|
|
74
|
+
# Bundled Services (can override to use external services)
|
|
75
|
+
DATABASE_URL: ${DATABASE_URL:-postgresql://cruxgarden:cruxgarden_nursery_password@postgres:5432/cruxgarden}
|
|
76
|
+
REDIS_URL: ${REDIS_URL:-redis://redis:6379}
|
|
77
77
|
|
|
78
78
|
# Security
|
|
79
79
|
JWT_SECRET: ${JWT_SECRET:-your-super-secret-jwt-key-min-32-chars-for-development-only}
|
|
@@ -107,6 +107,17 @@ services:
|
|
|
107
107
|
retries: 3
|
|
108
108
|
start_period: 40s
|
|
109
109
|
|
|
110
|
+
# Crux Garden App - Web Application
|
|
111
|
+
app:
|
|
112
|
+
image: ghcr.io/cruxgarden/app:latest
|
|
113
|
+
container_name: cruxgarden-nursery-app
|
|
114
|
+
restart: unless-stopped
|
|
115
|
+
depends_on:
|
|
116
|
+
api:
|
|
117
|
+
condition: service_healthy
|
|
118
|
+
ports:
|
|
119
|
+
- "${APP_PORT:-8080}:80"
|
|
120
|
+
|
|
110
121
|
volumes:
|
|
111
122
|
postgres_data_nursery:
|
|
112
123
|
redis_data_nursery:
|
package/lib/commands.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { execSync, spawn } from "child_process";
|
|
2
2
|
import { fileURLToPath } from "url";
|
|
3
3
|
import { dirname, join } from "path";
|
|
4
|
-
import { readFileSync } from "fs";
|
|
4
|
+
import { readFileSync, existsSync } from "fs";
|
|
5
5
|
import readline from "readline";
|
|
6
6
|
import chalk from "chalk";
|
|
7
7
|
import ora from "ora";
|
|
@@ -166,35 +166,110 @@ function ensureDockerRunning() {
|
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
+
function getEnvFileFlag() {
|
|
170
|
+
const envFilePath = join(process.cwd(), ".env");
|
|
171
|
+
if (existsSync(envFilePath)) {
|
|
172
|
+
return `--env-file "${envFilePath}"`;
|
|
173
|
+
}
|
|
174
|
+
return "";
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function parseAndSetEnvVars(envArgs = []) {
|
|
178
|
+
if (!envArgs || envArgs.length === 0) return;
|
|
179
|
+
|
|
180
|
+
for (const arg of envArgs) {
|
|
181
|
+
const match = arg.match(/^([A-Z_][A-Z0-9_]*)=(.*)$/);
|
|
182
|
+
if (match) {
|
|
183
|
+
const [, key, value] = match;
|
|
184
|
+
process.env[key] = value;
|
|
185
|
+
console.log(chalk.gray(` Setting ${key}=${value}`));
|
|
186
|
+
} else {
|
|
187
|
+
console.log(chalk.yellow(` Warning: Ignoring invalid env var format: ${arg}`));
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
169
192
|
// ============================================================================
|
|
170
193
|
// Nursery Environment Commands
|
|
171
194
|
// ============================================================================
|
|
172
195
|
|
|
173
|
-
export async function startNursery(options) {
|
|
196
|
+
export async function startNursery(options, envVars) {
|
|
174
197
|
ensureDockerRunning();
|
|
198
|
+
|
|
199
|
+
// Parse and set environment variables from command line
|
|
200
|
+
if (envVars && envVars.length > 0) {
|
|
201
|
+
console.log(chalk.cyan("\nApplying environment variables:"));
|
|
202
|
+
parseAndSetEnvVars(envVars);
|
|
203
|
+
console.log();
|
|
204
|
+
}
|
|
205
|
+
|
|
175
206
|
const spinner = ora("Starting Crux Garden Nursery environment...").start();
|
|
207
|
+
const envFileFlag = getEnvFileFlag();
|
|
208
|
+
|
|
209
|
+
// Get actual port values from environment
|
|
210
|
+
const appPort = process.env.APP_PORT || "8080";
|
|
211
|
+
const apiPort = process.env.API_PORT || "3000";
|
|
212
|
+
const postgresPort = process.env.POSTGRES_PORT || "5432";
|
|
213
|
+
const redisPort = process.env.REDIS_PORT || "6379";
|
|
176
214
|
|
|
177
215
|
try {
|
|
178
216
|
if (options.dbOnly) {
|
|
179
217
|
spinner.text = "Starting nursery database services (postgres, redis)...";
|
|
180
218
|
await runCommandAsync(
|
|
181
|
-
|
|
219
|
+
`docker-compose ${envFileFlag} -f docker-compose.nursery.yml up -d --remove-orphans postgres redis`,
|
|
182
220
|
{ silent: true },
|
|
183
221
|
);
|
|
184
222
|
spinner.succeed("Nursery database services started!");
|
|
185
223
|
console.log(
|
|
186
224
|
chalk.hex(SUCCESS_GREEN)("\n✓ PostgreSQL running on:"),
|
|
187
|
-
|
|
225
|
+
`localhost:${postgresPort}`,
|
|
226
|
+
);
|
|
227
|
+
console.log(
|
|
228
|
+
chalk.hex(SUCCESS_GREEN)("✓ Redis running on:"),
|
|
229
|
+
`localhost:${redisPort}`,
|
|
230
|
+
);
|
|
231
|
+
} else if (options.apiOnly) {
|
|
232
|
+
spinner.text =
|
|
233
|
+
"Starting nursery API services (api, postgres, redis)...";
|
|
234
|
+
await runCommandAsync(
|
|
235
|
+
`docker-compose ${envFileFlag} -f docker-compose.nursery.yml up -d --remove-orphans postgres redis migrations api`,
|
|
236
|
+
{
|
|
237
|
+
silent: true,
|
|
238
|
+
},
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
// Clean up the migrations container if it exists (cross-platform)
|
|
242
|
+
await runCommandAsync(
|
|
243
|
+
"docker rm cruxgarden-nursery-migrations",
|
|
244
|
+
{
|
|
245
|
+
silent: true,
|
|
246
|
+
ignoreError: true,
|
|
247
|
+
},
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
spinner.succeed("Crux Garden Nursery API services started!");
|
|
251
|
+
console.log(
|
|
252
|
+
chalk.hex(SUCCESS_GREEN)("\n✓ API running on:"),
|
|
253
|
+
`http://localhost:${apiPort}`,
|
|
254
|
+
);
|
|
255
|
+
console.log(
|
|
256
|
+
chalk.hex(SUCCESS_GREEN)("✓ PostgreSQL running on:"),
|
|
257
|
+
`localhost:${postgresPort}`,
|
|
188
258
|
);
|
|
189
259
|
console.log(
|
|
190
260
|
chalk.hex(SUCCESS_GREEN)("✓ Redis running on:"),
|
|
191
|
-
|
|
261
|
+
`localhost:${redisPort}`,
|
|
262
|
+
);
|
|
263
|
+
console.log(
|
|
264
|
+
chalk.yellow(
|
|
265
|
+
"\nℹ Nursery includes demo data for trials and showcases",
|
|
266
|
+
),
|
|
192
267
|
);
|
|
193
268
|
} else {
|
|
194
269
|
spinner.text =
|
|
195
|
-
"Starting nursery services (api, postgres, redis)...";
|
|
270
|
+
"Starting nursery services (app, api, postgres, redis)...";
|
|
196
271
|
await runCommandAsync(
|
|
197
|
-
|
|
272
|
+
`docker-compose ${envFileFlag} -f docker-compose.nursery.yml up -d --remove-orphans`,
|
|
198
273
|
{
|
|
199
274
|
silent: true,
|
|
200
275
|
},
|
|
@@ -211,16 +286,20 @@ export async function startNursery(options) {
|
|
|
211
286
|
|
|
212
287
|
spinner.succeed("Crux Garden Nursery environment started!");
|
|
213
288
|
console.log(
|
|
214
|
-
chalk.hex(SUCCESS_GREEN)("\n✓
|
|
215
|
-
|
|
289
|
+
chalk.hex(SUCCESS_GREEN)("\n✓ App running on:"),
|
|
290
|
+
`http://localhost:${appPort}`,
|
|
291
|
+
);
|
|
292
|
+
console.log(
|
|
293
|
+
chalk.hex(SUCCESS_GREEN)("✓ API running on:"),
|
|
294
|
+
`http://localhost:${apiPort}`,
|
|
216
295
|
);
|
|
217
296
|
console.log(
|
|
218
297
|
chalk.hex(SUCCESS_GREEN)("✓ PostgreSQL running on:"),
|
|
219
|
-
|
|
298
|
+
`localhost:${postgresPort}`,
|
|
220
299
|
);
|
|
221
300
|
console.log(
|
|
222
301
|
chalk.hex(SUCCESS_GREEN)("✓ Redis running on:"),
|
|
223
|
-
|
|
302
|
+
`localhost:${redisPort}`,
|
|
224
303
|
);
|
|
225
304
|
console.log(
|
|
226
305
|
chalk.yellow(
|
|
@@ -259,7 +338,8 @@ export async function startNursery(options) {
|
|
|
259
338
|
export async function stopNursery() {
|
|
260
339
|
ensureDockerRunning();
|
|
261
340
|
const spinner = ora("Stopping Crux Garden Nursery environment...").start();
|
|
262
|
-
|
|
341
|
+
const envFileFlag = getEnvFileFlag();
|
|
342
|
+
await runCommandAsync(`docker-compose ${envFileFlag} -f docker-compose.nursery.yml down`, {
|
|
263
343
|
silent: true,
|
|
264
344
|
});
|
|
265
345
|
spinner.succeed("Crux Garden Nursery environment stopped!");
|
|
@@ -273,13 +353,16 @@ export async function stopNursery() {
|
|
|
273
353
|
|
|
274
354
|
export async function logsNursery(options) {
|
|
275
355
|
ensureDockerRunning();
|
|
356
|
+
const envFileFlag = getEnvFileFlag();
|
|
357
|
+
const envFileArgs = envFileFlag ? envFileFlag.split(" ") : [];
|
|
358
|
+
|
|
276
359
|
if (options.follow) {
|
|
277
360
|
console.log(
|
|
278
361
|
chalk.gray("Following nursery logs (press Ctrl+C to exit)...\n"),
|
|
279
362
|
);
|
|
280
363
|
const child = spawn(
|
|
281
364
|
"docker-compose",
|
|
282
|
-
["-f", "docker-compose.nursery.yml", "logs", "-f"],
|
|
365
|
+
[...envFileArgs, "-f", "docker-compose.nursery.yml", "logs", "-f"],
|
|
283
366
|
{
|
|
284
367
|
cwd: dockerDir,
|
|
285
368
|
stdio: "inherit",
|
|
@@ -291,7 +374,7 @@ export async function logsNursery(options) {
|
|
|
291
374
|
process.exit(0);
|
|
292
375
|
});
|
|
293
376
|
} else {
|
|
294
|
-
runCommand(
|
|
377
|
+
runCommand(`docker-compose ${envFileFlag} -f docker-compose.nursery.yml logs --tail=100`);
|
|
295
378
|
console.log();
|
|
296
379
|
}
|
|
297
380
|
}
|
|
@@ -316,9 +399,10 @@ export async function cleanNursery() {
|
|
|
316
399
|
const spinner = ora(
|
|
317
400
|
"Cleaning up nursery (removing containers and volumes)...",
|
|
318
401
|
).start();
|
|
402
|
+
const envFileFlag = getEnvFileFlag();
|
|
319
403
|
|
|
320
404
|
await runCommandAsync(
|
|
321
|
-
|
|
405
|
+
`docker-compose ${envFileFlag} -f docker-compose.nursery.yml down -v`,
|
|
322
406
|
{
|
|
323
407
|
silent: true,
|
|
324
408
|
ignoreError: true,
|
|
@@ -359,9 +443,10 @@ export async function purgeNursery() {
|
|
|
359
443
|
const spinner = ora(
|
|
360
444
|
"Purging nursery (removing containers, volumes, and images)...",
|
|
361
445
|
).start();
|
|
446
|
+
const envFileFlag = getEnvFileFlag();
|
|
362
447
|
|
|
363
448
|
await runCommandAsync(
|
|
364
|
-
|
|
449
|
+
`docker-compose ${envFileFlag} -f docker-compose.nursery.yml down -v --rmi all`,
|
|
365
450
|
{
|
|
366
451
|
silent: true,
|
|
367
452
|
ignoreError: true,
|
|
@@ -383,6 +468,7 @@ export async function updateNursery() {
|
|
|
383
468
|
const spinner = ora(
|
|
384
469
|
"Checking for latest Crux Garden API image from ghcr.io...",
|
|
385
470
|
).start();
|
|
471
|
+
const envFileFlag = getEnvFileFlag();
|
|
386
472
|
|
|
387
473
|
try {
|
|
388
474
|
// Get the current local image digest before pulling
|
|
@@ -394,7 +480,7 @@ export async function updateNursery() {
|
|
|
394
480
|
|
|
395
481
|
// Pull latest images
|
|
396
482
|
spinner.text = "Pulling latest images...";
|
|
397
|
-
await runCommandAsync(
|
|
483
|
+
await runCommandAsync(`docker-compose ${envFileFlag} -f docker-compose.nursery.yml pull`, {
|
|
398
484
|
silent: true,
|
|
399
485
|
});
|
|
400
486
|
|
|
@@ -433,7 +519,7 @@ export async function updateNursery() {
|
|
|
433
519
|
console.log();
|
|
434
520
|
}
|
|
435
521
|
|
|
436
|
-
export async function resetNursery() {
|
|
522
|
+
export async function resetNursery(envVars) {
|
|
437
523
|
ensureDockerRunning();
|
|
438
524
|
console.log(
|
|
439
525
|
chalk.yellow(
|
|
@@ -450,13 +536,27 @@ export async function resetNursery() {
|
|
|
450
536
|
return;
|
|
451
537
|
}
|
|
452
538
|
|
|
539
|
+
// Parse and set environment variables from command line
|
|
540
|
+
if (envVars && envVars.length > 0) {
|
|
541
|
+
console.log(chalk.cyan("\nApplying environment variables:"));
|
|
542
|
+
parseAndSetEnvVars(envVars);
|
|
543
|
+
console.log();
|
|
544
|
+
}
|
|
545
|
+
|
|
453
546
|
const spinner = ora("Resetting nursery environment...").start();
|
|
547
|
+
const envFileFlag = getEnvFileFlag();
|
|
548
|
+
|
|
549
|
+
// Get actual port values from environment
|
|
550
|
+
const appPort = process.env.APP_PORT || "8080";
|
|
551
|
+
const apiPort = process.env.API_PORT || "3000";
|
|
552
|
+
const postgresPort = process.env.POSTGRES_PORT || "5432";
|
|
553
|
+
const redisPort = process.env.REDIS_PORT || "6379";
|
|
454
554
|
|
|
455
555
|
try {
|
|
456
556
|
// Stop and remove volumes
|
|
457
557
|
spinner.text = "Stopping and removing containers/volumes...";
|
|
458
558
|
await runCommandAsync(
|
|
459
|
-
|
|
559
|
+
`docker-compose ${envFileFlag} -f docker-compose.nursery.yml down -v`,
|
|
460
560
|
{
|
|
461
561
|
silent: true,
|
|
462
562
|
ignoreError: true,
|
|
@@ -465,14 +565,14 @@ export async function resetNursery() {
|
|
|
465
565
|
|
|
466
566
|
// Pull latest image
|
|
467
567
|
spinner.text = "Pulling latest image...";
|
|
468
|
-
await runCommandAsync(
|
|
568
|
+
await runCommandAsync(`docker-compose ${envFileFlag} -f docker-compose.nursery.yml pull`, {
|
|
469
569
|
silent: true,
|
|
470
570
|
});
|
|
471
571
|
|
|
472
572
|
// Start fresh
|
|
473
573
|
spinner.text = "Starting fresh nursery environment...";
|
|
474
574
|
await runCommandAsync(
|
|
475
|
-
|
|
575
|
+
`docker-compose ${envFileFlag} -f docker-compose.nursery.yml up -d --remove-orphans`,
|
|
476
576
|
{
|
|
477
577
|
silent: true,
|
|
478
578
|
},
|
|
@@ -489,16 +589,20 @@ export async function resetNursery() {
|
|
|
489
589
|
|
|
490
590
|
spinner.succeed("Nursery environment reset complete!");
|
|
491
591
|
console.log(
|
|
492
|
-
chalk.hex(SUCCESS_GREEN)("\n✓
|
|
493
|
-
|
|
592
|
+
chalk.hex(SUCCESS_GREEN)("\n✓ App running on:"),
|
|
593
|
+
`http://localhost:${appPort}`,
|
|
594
|
+
);
|
|
595
|
+
console.log(
|
|
596
|
+
chalk.hex(SUCCESS_GREEN)("✓ API running on:"),
|
|
597
|
+
`http://localhost:${apiPort}`,
|
|
494
598
|
);
|
|
495
599
|
console.log(
|
|
496
600
|
chalk.hex(SUCCESS_GREEN)("✓ PostgreSQL running on:"),
|
|
497
|
-
|
|
601
|
+
`localhost:${postgresPort}`,
|
|
498
602
|
);
|
|
499
603
|
console.log(
|
|
500
604
|
chalk.hex(SUCCESS_GREEN)("✓ Redis running on:"),
|
|
501
|
-
|
|
605
|
+
`localhost:${redisPort}`,
|
|
502
606
|
);
|
|
503
607
|
console.log(
|
|
504
608
|
chalk.yellow("\nℹ Fresh nursery with latest demo data loaded"),
|
|
@@ -510,15 +614,16 @@ export async function resetNursery() {
|
|
|
510
614
|
}
|
|
511
615
|
}
|
|
512
616
|
|
|
513
|
-
export async function restartNursery() {
|
|
617
|
+
export async function restartNursery(options = {}, envVars) {
|
|
514
618
|
await stopNursery();
|
|
515
|
-
await startNursery(
|
|
619
|
+
await startNursery(options, envVars);
|
|
516
620
|
}
|
|
517
621
|
|
|
518
622
|
export async function statusNursery() {
|
|
519
623
|
ensureDockerRunning();
|
|
624
|
+
const envFileFlag = getEnvFileFlag();
|
|
520
625
|
console.log(chalk.bold("\nCrux Garden Nursery Environment Status:\n"));
|
|
521
|
-
runCommand(
|
|
626
|
+
runCommand(`docker-compose ${envFileFlag} -f docker-compose.nursery.yml ps`);
|
|
522
627
|
console.log();
|
|
523
628
|
}
|
|
524
629
|
|
|
@@ -545,8 +650,9 @@ export async function connectNurseryApi() {
|
|
|
545
650
|
export async function stopNurseryDb() {
|
|
546
651
|
ensureDockerRunning();
|
|
547
652
|
const spinner = ora("Stopping nursery database services...").start();
|
|
653
|
+
const envFileFlag = getEnvFileFlag();
|
|
548
654
|
await runCommandAsync(
|
|
549
|
-
|
|
655
|
+
`docker-compose ${envFileFlag} -f docker-compose.nursery.yml stop postgres redis`,
|
|
550
656
|
{ silent: true },
|
|
551
657
|
);
|
|
552
658
|
spinner.succeed("Nursery database services stopped!");
|