@cruxgarden/cli 0.0.8 → 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 +142 -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,6 +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, existsSync } from "fs";
|
|
4
5
|
import readline from "readline";
|
|
5
6
|
import chalk from "chalk";
|
|
6
7
|
import ora from "ora";
|
|
@@ -9,6 +10,12 @@ const __filename = fileURLToPath(import.meta.url);
|
|
|
9
10
|
const __dirname = dirname(__filename);
|
|
10
11
|
const dockerDir = join(__dirname, "..", "docker");
|
|
11
12
|
|
|
13
|
+
// Read version from package.json
|
|
14
|
+
const packageJson = JSON.parse(
|
|
15
|
+
readFileSync(join(__dirname, "..", "package.json"), "utf-8")
|
|
16
|
+
);
|
|
17
|
+
const VERSION = packageJson.version;
|
|
18
|
+
|
|
12
19
|
// Colors
|
|
13
20
|
const SUCCESS_GREEN = "#9BD39B";
|
|
14
21
|
|
|
@@ -50,7 +57,7 @@ export function showBanner() {
|
|
|
50
57
|
console.log(randomColor(line));
|
|
51
58
|
});
|
|
52
59
|
|
|
53
|
-
console.log(chalk.gray(
|
|
60
|
+
console.log(chalk.gray(` Nursery Environment - Demo & Trial (v${VERSION})\n`));
|
|
54
61
|
|
|
55
62
|
// Set environment variable so it persists for this shell session
|
|
56
63
|
process.env.CRUX_BANNER_SHOWN = "1";
|
|
@@ -159,35 +166,110 @@ function ensureDockerRunning() {
|
|
|
159
166
|
}
|
|
160
167
|
}
|
|
161
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
|
+
|
|
162
192
|
// ============================================================================
|
|
163
193
|
// Nursery Environment Commands
|
|
164
194
|
// ============================================================================
|
|
165
195
|
|
|
166
|
-
export async function startNursery(options) {
|
|
196
|
+
export async function startNursery(options, envVars) {
|
|
167
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
|
+
|
|
168
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";
|
|
169
214
|
|
|
170
215
|
try {
|
|
171
216
|
if (options.dbOnly) {
|
|
172
217
|
spinner.text = "Starting nursery database services (postgres, redis)...";
|
|
173
218
|
await runCommandAsync(
|
|
174
|
-
|
|
219
|
+
`docker-compose ${envFileFlag} -f docker-compose.nursery.yml up -d --remove-orphans postgres redis`,
|
|
175
220
|
{ silent: true },
|
|
176
221
|
);
|
|
177
222
|
spinner.succeed("Nursery database services started!");
|
|
178
223
|
console.log(
|
|
179
224
|
chalk.hex(SUCCESS_GREEN)("\n✓ PostgreSQL running on:"),
|
|
180
|
-
|
|
225
|
+
`localhost:${postgresPort}`,
|
|
181
226
|
);
|
|
182
227
|
console.log(
|
|
183
228
|
chalk.hex(SUCCESS_GREEN)("✓ Redis running on:"),
|
|
184
|
-
|
|
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}`,
|
|
258
|
+
);
|
|
259
|
+
console.log(
|
|
260
|
+
chalk.hex(SUCCESS_GREEN)("✓ Redis running on:"),
|
|
261
|
+
`localhost:${redisPort}`,
|
|
262
|
+
);
|
|
263
|
+
console.log(
|
|
264
|
+
chalk.yellow(
|
|
265
|
+
"\nℹ Nursery includes demo data for trials and showcases",
|
|
266
|
+
),
|
|
185
267
|
);
|
|
186
268
|
} else {
|
|
187
269
|
spinner.text =
|
|
188
|
-
"Starting nursery services (api, postgres, redis)...";
|
|
270
|
+
"Starting nursery services (app, api, postgres, redis)...";
|
|
189
271
|
await runCommandAsync(
|
|
190
|
-
|
|
272
|
+
`docker-compose ${envFileFlag} -f docker-compose.nursery.yml up -d --remove-orphans`,
|
|
191
273
|
{
|
|
192
274
|
silent: true,
|
|
193
275
|
},
|
|
@@ -204,16 +286,20 @@ export async function startNursery(options) {
|
|
|
204
286
|
|
|
205
287
|
spinner.succeed("Crux Garden Nursery environment started!");
|
|
206
288
|
console.log(
|
|
207
|
-
chalk.hex(SUCCESS_GREEN)("\n✓
|
|
208
|
-
|
|
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}`,
|
|
209
295
|
);
|
|
210
296
|
console.log(
|
|
211
297
|
chalk.hex(SUCCESS_GREEN)("✓ PostgreSQL running on:"),
|
|
212
|
-
|
|
298
|
+
`localhost:${postgresPort}`,
|
|
213
299
|
);
|
|
214
300
|
console.log(
|
|
215
301
|
chalk.hex(SUCCESS_GREEN)("✓ Redis running on:"),
|
|
216
|
-
|
|
302
|
+
`localhost:${redisPort}`,
|
|
217
303
|
);
|
|
218
304
|
console.log(
|
|
219
305
|
chalk.yellow(
|
|
@@ -252,7 +338,8 @@ export async function startNursery(options) {
|
|
|
252
338
|
export async function stopNursery() {
|
|
253
339
|
ensureDockerRunning();
|
|
254
340
|
const spinner = ora("Stopping Crux Garden Nursery environment...").start();
|
|
255
|
-
|
|
341
|
+
const envFileFlag = getEnvFileFlag();
|
|
342
|
+
await runCommandAsync(`docker-compose ${envFileFlag} -f docker-compose.nursery.yml down`, {
|
|
256
343
|
silent: true,
|
|
257
344
|
});
|
|
258
345
|
spinner.succeed("Crux Garden Nursery environment stopped!");
|
|
@@ -266,13 +353,16 @@ export async function stopNursery() {
|
|
|
266
353
|
|
|
267
354
|
export async function logsNursery(options) {
|
|
268
355
|
ensureDockerRunning();
|
|
356
|
+
const envFileFlag = getEnvFileFlag();
|
|
357
|
+
const envFileArgs = envFileFlag ? envFileFlag.split(" ") : [];
|
|
358
|
+
|
|
269
359
|
if (options.follow) {
|
|
270
360
|
console.log(
|
|
271
361
|
chalk.gray("Following nursery logs (press Ctrl+C to exit)...\n"),
|
|
272
362
|
);
|
|
273
363
|
const child = spawn(
|
|
274
364
|
"docker-compose",
|
|
275
|
-
["-f", "docker-compose.nursery.yml", "logs", "-f"],
|
|
365
|
+
[...envFileArgs, "-f", "docker-compose.nursery.yml", "logs", "-f"],
|
|
276
366
|
{
|
|
277
367
|
cwd: dockerDir,
|
|
278
368
|
stdio: "inherit",
|
|
@@ -284,7 +374,7 @@ export async function logsNursery(options) {
|
|
|
284
374
|
process.exit(0);
|
|
285
375
|
});
|
|
286
376
|
} else {
|
|
287
|
-
runCommand(
|
|
377
|
+
runCommand(`docker-compose ${envFileFlag} -f docker-compose.nursery.yml logs --tail=100`);
|
|
288
378
|
console.log();
|
|
289
379
|
}
|
|
290
380
|
}
|
|
@@ -309,9 +399,10 @@ export async function cleanNursery() {
|
|
|
309
399
|
const spinner = ora(
|
|
310
400
|
"Cleaning up nursery (removing containers and volumes)...",
|
|
311
401
|
).start();
|
|
402
|
+
const envFileFlag = getEnvFileFlag();
|
|
312
403
|
|
|
313
404
|
await runCommandAsync(
|
|
314
|
-
|
|
405
|
+
`docker-compose ${envFileFlag} -f docker-compose.nursery.yml down -v`,
|
|
315
406
|
{
|
|
316
407
|
silent: true,
|
|
317
408
|
ignoreError: true,
|
|
@@ -352,9 +443,10 @@ export async function purgeNursery() {
|
|
|
352
443
|
const spinner = ora(
|
|
353
444
|
"Purging nursery (removing containers, volumes, and images)...",
|
|
354
445
|
).start();
|
|
446
|
+
const envFileFlag = getEnvFileFlag();
|
|
355
447
|
|
|
356
448
|
await runCommandAsync(
|
|
357
|
-
|
|
449
|
+
`docker-compose ${envFileFlag} -f docker-compose.nursery.yml down -v --rmi all`,
|
|
358
450
|
{
|
|
359
451
|
silent: true,
|
|
360
452
|
ignoreError: true,
|
|
@@ -376,6 +468,7 @@ export async function updateNursery() {
|
|
|
376
468
|
const spinner = ora(
|
|
377
469
|
"Checking for latest Crux Garden API image from ghcr.io...",
|
|
378
470
|
).start();
|
|
471
|
+
const envFileFlag = getEnvFileFlag();
|
|
379
472
|
|
|
380
473
|
try {
|
|
381
474
|
// Get the current local image digest before pulling
|
|
@@ -387,7 +480,7 @@ export async function updateNursery() {
|
|
|
387
480
|
|
|
388
481
|
// Pull latest images
|
|
389
482
|
spinner.text = "Pulling latest images...";
|
|
390
|
-
await runCommandAsync(
|
|
483
|
+
await runCommandAsync(`docker-compose ${envFileFlag} -f docker-compose.nursery.yml pull`, {
|
|
391
484
|
silent: true,
|
|
392
485
|
});
|
|
393
486
|
|
|
@@ -426,7 +519,7 @@ export async function updateNursery() {
|
|
|
426
519
|
console.log();
|
|
427
520
|
}
|
|
428
521
|
|
|
429
|
-
export async function resetNursery() {
|
|
522
|
+
export async function resetNursery(envVars) {
|
|
430
523
|
ensureDockerRunning();
|
|
431
524
|
console.log(
|
|
432
525
|
chalk.yellow(
|
|
@@ -443,13 +536,27 @@ export async function resetNursery() {
|
|
|
443
536
|
return;
|
|
444
537
|
}
|
|
445
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
|
+
|
|
446
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";
|
|
447
554
|
|
|
448
555
|
try {
|
|
449
556
|
// Stop and remove volumes
|
|
450
557
|
spinner.text = "Stopping and removing containers/volumes...";
|
|
451
558
|
await runCommandAsync(
|
|
452
|
-
|
|
559
|
+
`docker-compose ${envFileFlag} -f docker-compose.nursery.yml down -v`,
|
|
453
560
|
{
|
|
454
561
|
silent: true,
|
|
455
562
|
ignoreError: true,
|
|
@@ -458,14 +565,14 @@ export async function resetNursery() {
|
|
|
458
565
|
|
|
459
566
|
// Pull latest image
|
|
460
567
|
spinner.text = "Pulling latest image...";
|
|
461
|
-
await runCommandAsync(
|
|
568
|
+
await runCommandAsync(`docker-compose ${envFileFlag} -f docker-compose.nursery.yml pull`, {
|
|
462
569
|
silent: true,
|
|
463
570
|
});
|
|
464
571
|
|
|
465
572
|
// Start fresh
|
|
466
573
|
spinner.text = "Starting fresh nursery environment...";
|
|
467
574
|
await runCommandAsync(
|
|
468
|
-
|
|
575
|
+
`docker-compose ${envFileFlag} -f docker-compose.nursery.yml up -d --remove-orphans`,
|
|
469
576
|
{
|
|
470
577
|
silent: true,
|
|
471
578
|
},
|
|
@@ -482,16 +589,20 @@ export async function resetNursery() {
|
|
|
482
589
|
|
|
483
590
|
spinner.succeed("Nursery environment reset complete!");
|
|
484
591
|
console.log(
|
|
485
|
-
chalk.hex(SUCCESS_GREEN)("\n✓
|
|
486
|
-
|
|
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}`,
|
|
487
598
|
);
|
|
488
599
|
console.log(
|
|
489
600
|
chalk.hex(SUCCESS_GREEN)("✓ PostgreSQL running on:"),
|
|
490
|
-
|
|
601
|
+
`localhost:${postgresPort}`,
|
|
491
602
|
);
|
|
492
603
|
console.log(
|
|
493
604
|
chalk.hex(SUCCESS_GREEN)("✓ Redis running on:"),
|
|
494
|
-
|
|
605
|
+
`localhost:${redisPort}`,
|
|
495
606
|
);
|
|
496
607
|
console.log(
|
|
497
608
|
chalk.yellow("\nℹ Fresh nursery with latest demo data loaded"),
|
|
@@ -503,15 +614,16 @@ export async function resetNursery() {
|
|
|
503
614
|
}
|
|
504
615
|
}
|
|
505
616
|
|
|
506
|
-
export async function restartNursery() {
|
|
617
|
+
export async function restartNursery(options = {}, envVars) {
|
|
507
618
|
await stopNursery();
|
|
508
|
-
await startNursery(
|
|
619
|
+
await startNursery(options, envVars);
|
|
509
620
|
}
|
|
510
621
|
|
|
511
622
|
export async function statusNursery() {
|
|
512
623
|
ensureDockerRunning();
|
|
624
|
+
const envFileFlag = getEnvFileFlag();
|
|
513
625
|
console.log(chalk.bold("\nCrux Garden Nursery Environment Status:\n"));
|
|
514
|
-
runCommand(
|
|
626
|
+
runCommand(`docker-compose ${envFileFlag} -f docker-compose.nursery.yml ps`);
|
|
515
627
|
console.log();
|
|
516
628
|
}
|
|
517
629
|
|
|
@@ -538,8 +650,9 @@ export async function connectNurseryApi() {
|
|
|
538
650
|
export async function stopNurseryDb() {
|
|
539
651
|
ensureDockerRunning();
|
|
540
652
|
const spinner = ora("Stopping nursery database services...").start();
|
|
653
|
+
const envFileFlag = getEnvFileFlag();
|
|
541
654
|
await runCommandAsync(
|
|
542
|
-
|
|
655
|
+
`docker-compose ${envFileFlag} -f docker-compose.nursery.yml stop postgres redis`,
|
|
543
656
|
{ silent: true },
|
|
544
657
|
);
|
|
545
658
|
spinner.succeed("Nursery database services stopped!");
|