@idealyst/cli 1.0.29 → 1.0.31
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/dist/index.js +96 -35
- package/dist/types/generators/utils.d.ts +1 -0
- package/package.json +9 -5
- package/templates/shared/rollup.config.js +43 -0
- package/templates/workspace/.devcontainer/post-create.sh +3 -0
- package/templates/workspace/.dockerignore +1 -1
- package/templates/workspace/DOCKER.md +14 -1
- package/templates/workspace/Dockerfile +18 -3
- package/templates/workspace/README.md +6 -0
- package/templates/workspace/scripts/docker-build.sh +151 -0
package/dist/index.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { Command } from 'commander';
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import path from 'path';
|
|
5
|
-
import { fileURLToPath } from 'url';
|
|
6
5
|
import fs from 'fs-extra';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
7
|
import { spawn } from 'child_process';
|
|
8
8
|
import ora from 'ora';
|
|
9
9
|
import validatePackageName from 'validate-npm-package-name';
|
|
@@ -119,12 +119,23 @@ async function installDependencies(projectPath, skipInstall = false) {
|
|
|
119
119
|
}
|
|
120
120
|
function runCommand(command, args, options) {
|
|
121
121
|
return new Promise((resolve, reject) => {
|
|
122
|
+
const timeoutMs = options.timeout || 300000; // 5 minutes default timeout
|
|
122
123
|
const process = spawn(command, args, {
|
|
123
124
|
cwd: options.cwd,
|
|
124
|
-
stdio: 'inherit',
|
|
125
|
+
stdio: ['pipe', 'inherit', 'inherit'], // Pipe stdin to prevent hanging on prompts
|
|
125
126
|
shell: true
|
|
126
127
|
});
|
|
128
|
+
// Set up timeout
|
|
129
|
+
const timeoutId = setTimeout(() => {
|
|
130
|
+
process.kill('SIGTERM');
|
|
131
|
+
reject(new Error(`Command timed out after ${timeoutMs / 1000} seconds`));
|
|
132
|
+
}, timeoutMs);
|
|
133
|
+
// Close stdin immediately to prevent hanging on interactive prompts
|
|
134
|
+
if (process.stdin) {
|
|
135
|
+
process.stdin.end();
|
|
136
|
+
}
|
|
127
137
|
process.on('close', (code) => {
|
|
138
|
+
clearTimeout(timeoutId);
|
|
128
139
|
if (code === 0) {
|
|
129
140
|
resolve();
|
|
130
141
|
}
|
|
@@ -133,6 +144,7 @@ function runCommand(command, args, options) {
|
|
|
133
144
|
}
|
|
134
145
|
});
|
|
135
146
|
process.on('error', (error) => {
|
|
147
|
+
clearTimeout(timeoutId);
|
|
136
148
|
reject(error);
|
|
137
149
|
});
|
|
138
150
|
});
|
|
@@ -210,9 +222,15 @@ async function resolveProjectPath(projectName, directory) {
|
|
|
210
222
|
async function initializeReactNativeProject(projectName, directory, displayName, skipInstall) {
|
|
211
223
|
const spinner = ora('Initializing React Native project...').start();
|
|
212
224
|
try {
|
|
213
|
-
// Use
|
|
225
|
+
// Use create-react-native-app for a more reliable setup
|
|
214
226
|
const cliCommand = 'npx';
|
|
215
|
-
const args = [
|
|
227
|
+
const args = [
|
|
228
|
+
'react-native@latest',
|
|
229
|
+
'init',
|
|
230
|
+
projectName,
|
|
231
|
+
'--pm', 'yarn',
|
|
232
|
+
'--skip-git-init'
|
|
233
|
+
];
|
|
216
234
|
// Add title if displayName is provided
|
|
217
235
|
if (displayName) {
|
|
218
236
|
args.push('--title', displayName);
|
|
@@ -221,19 +239,31 @@ async function initializeReactNativeProject(projectName, directory, displayName,
|
|
|
221
239
|
if (skipInstall) {
|
|
222
240
|
args.push('--skip-install');
|
|
223
241
|
}
|
|
224
|
-
|
|
225
|
-
|
|
242
|
+
spinner.text = 'Initializing React Native project (this may take a few minutes)...';
|
|
243
|
+
// Run React Native initialization with timeout
|
|
244
|
+
await runCommand(cliCommand, args, {
|
|
245
|
+
cwd: directory,
|
|
246
|
+
timeout: 600000 // 10 minutes timeout for React Native init
|
|
247
|
+
});
|
|
226
248
|
spinner.succeed('React Native project initialized successfully');
|
|
227
249
|
}
|
|
228
250
|
catch (error) {
|
|
229
251
|
spinner.fail('Failed to initialize React Native project');
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
252
|
+
if (error instanceof Error && error.message.includes('timed out')) {
|
|
253
|
+
console.log(chalk.red('❌ React Native initialization timed out'));
|
|
254
|
+
console.log(chalk.yellow('This can happen due to:'));
|
|
255
|
+
console.log(chalk.white(' • Slow internet connection'));
|
|
256
|
+
console.log(chalk.white(' • Network issues downloading dependencies'));
|
|
257
|
+
console.log(chalk.white(' • React Native CLI hanging on prompts'));
|
|
258
|
+
}
|
|
259
|
+
console.log(chalk.yellow('\n💡 Alternative approaches:'));
|
|
260
|
+
console.log(chalk.white('1. Try manually creating the project:'));
|
|
261
|
+
console.log(chalk.white(` npx react-native@latest init ${projectName} --pm yarn --skip-git-init`));
|
|
262
|
+
console.log(chalk.white('\n2. Use Expo (faster alternative):'));
|
|
263
|
+
console.log(chalk.white(` npx create-expo-app@latest ${projectName} --template blank-typescript`));
|
|
264
|
+
console.log(chalk.white('\n3. Ensure prerequisites:'));
|
|
265
|
+
console.log(chalk.white(' npm install -g react-native-cli'));
|
|
266
|
+
console.log(chalk.white(' npm install -g @react-native-community/cli'));
|
|
237
267
|
throw error;
|
|
238
268
|
}
|
|
239
269
|
}
|
|
@@ -506,43 +536,70 @@ async function generateNativeProject(options) {
|
|
|
506
536
|
const templatePath = path.join(__dirname$4, '..', 'templates', 'native');
|
|
507
537
|
const templateData = getTemplateData(name, `React Native app built with Idealyst Framework`, displayName, workspaceScope || undefined);
|
|
508
538
|
try {
|
|
509
|
-
// Step 1: Update workspace configuration FIRST
|
|
539
|
+
// Step 1: Update workspace configuration FIRST
|
|
510
540
|
await updateWorkspacePackageJson(workspacePath, directory);
|
|
511
|
-
// Step 2:
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
541
|
+
// Step 2: Try React Native CLI initialization, with fallback to template-only
|
|
542
|
+
const useRnCli = process.env.IDEALYST_USE_RN_CLI !== 'false';
|
|
543
|
+
if (useRnCli) {
|
|
544
|
+
try {
|
|
545
|
+
console.log(chalk.blue('🚀 Attempting React Native CLI initialization...'));
|
|
546
|
+
console.log(chalk.gray(' (This creates proper Android/iOS native directories)'));
|
|
547
|
+
// Initialize React Native project using CLI with --skip-install
|
|
548
|
+
const projectDir = path.dirname(projectPath);
|
|
549
|
+
const projectName = path.basename(projectPath);
|
|
550
|
+
await initializeReactNativeProject(projectName, projectDir, displayName, true);
|
|
551
|
+
// Step 3: Overlay Idealyst-specific files
|
|
552
|
+
await overlayIdealystFiles(templatePath, projectPath, templateData);
|
|
553
|
+
console.log(chalk.green('✅ React Native project created with native platform support'));
|
|
554
|
+
}
|
|
555
|
+
catch (rnError) {
|
|
556
|
+
console.log(chalk.yellow('⚠️ React Native CLI failed, falling back to template-only approach...'));
|
|
557
|
+
await createNativeProjectFromTemplate(templatePath, projectPath, templateData);
|
|
558
|
+
console.log(chalk.yellow('📝 Template-only project created. You may need to run "npx react-native init" later for native platforms.'));
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
else {
|
|
562
|
+
console.log(chalk.blue('��️ Creating project from template only (IDEALYST_USE_RN_CLI=false)'));
|
|
563
|
+
await createNativeProjectFromTemplate(templatePath, projectPath, templateData);
|
|
564
|
+
}
|
|
518
565
|
// Step 4: Handle tRPC setup
|
|
519
566
|
if (withTrpc) {
|
|
520
567
|
await copyTrpcFiles(templatePath, projectPath, templateData);
|
|
521
568
|
await copyTrpcAppComponent(templatePath, projectPath, templateData);
|
|
522
569
|
}
|
|
523
|
-
// Step 5: Configure Android vector icons
|
|
524
|
-
await
|
|
525
|
-
|
|
570
|
+
// Step 5: Configure Android vector icons (only if we have Android directory)
|
|
571
|
+
const hasAndroid = await fs.pathExists(path.join(projectPath, 'android'));
|
|
572
|
+
if (hasAndroid) {
|
|
573
|
+
await configureAndroidVectorIcons(projectPath);
|
|
574
|
+
}
|
|
575
|
+
// Step 6: Remove tRPC dependencies if not requested
|
|
526
576
|
if (!withTrpc) {
|
|
527
577
|
await removeTrpcDependencies(projectPath);
|
|
528
578
|
}
|
|
529
|
-
// Step 7: Install dependencies
|
|
579
|
+
// Step 7: Install dependencies
|
|
530
580
|
await installDependencies(projectPath, skipInstall);
|
|
531
581
|
console.log(chalk.green('✅ React Native project created successfully!'));
|
|
532
582
|
console.log(chalk.blue('📋 Project includes:'));
|
|
533
|
-
console.log(chalk.white(' • React Native with
|
|
534
|
-
console.log(chalk.white(' • Idealyst Components'));
|
|
535
|
-
console.log(chalk.white(' • Idealyst
|
|
536
|
-
console.log(chalk.white(' •
|
|
537
|
-
console.log(chalk.white(' •
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
583
|
+
console.log(chalk.white(' • React Native with TypeScript'));
|
|
584
|
+
console.log(chalk.white(' • Idealyst Components & Navigation'));
|
|
585
|
+
console.log(chalk.white(' • Idealyst Theme & Styling'));
|
|
586
|
+
console.log(chalk.white(' • Jest testing configuration'));
|
|
587
|
+
console.log(chalk.white(' • Metro & Babel configuration'));
|
|
588
|
+
if (hasAndroid) {
|
|
589
|
+
console.log(chalk.white(' • Android native platform setup'));
|
|
590
|
+
console.log(chalk.white(' • React Native Vector Icons (configured)'));
|
|
591
|
+
}
|
|
592
|
+
const hasIos = await fs.pathExists(path.join(projectPath, 'ios'));
|
|
593
|
+
if (hasIos) {
|
|
594
|
+
console.log(chalk.white(' • iOS native platform setup'));
|
|
595
|
+
}
|
|
596
|
+
if (!hasAndroid && !hasIos) {
|
|
597
|
+
console.log(chalk.yellow(' ⚠️ No native platforms detected'));
|
|
598
|
+
console.log(chalk.yellow(' Run "npx react-native init" in project directory for native support'));
|
|
599
|
+
}
|
|
542
600
|
if (withTrpc) {
|
|
543
601
|
console.log(chalk.white(' • tRPC client setup and utilities'));
|
|
544
602
|
console.log(chalk.white(' • React Query integration'));
|
|
545
|
-
console.log(chalk.white(' • Pre-configured tRPC provider'));
|
|
546
603
|
}
|
|
547
604
|
}
|
|
548
605
|
catch (error) {
|
|
@@ -551,6 +608,10 @@ async function generateNativeProject(options) {
|
|
|
551
608
|
throw error;
|
|
552
609
|
}
|
|
553
610
|
}
|
|
611
|
+
// Helper function to create project from template only (fallback when RN CLI fails)
|
|
612
|
+
async function createNativeProjectFromTemplate(templatePath, projectPath, templateData) {
|
|
613
|
+
await copyTemplate(templatePath, projectPath, templateData);
|
|
614
|
+
}
|
|
554
615
|
|
|
555
616
|
const __filename$3 = fileURLToPath(import.meta.url);
|
|
556
617
|
const __dirname$3 = path.dirname(__filename$3);
|
|
@@ -8,6 +8,7 @@ export declare function processTemplateFile(filePath: string, data: TemplateData
|
|
|
8
8
|
export declare function installDependencies(projectPath: string, skipInstall?: boolean): Promise<void>;
|
|
9
9
|
export declare function runCommand(command: string, args: string[], options: {
|
|
10
10
|
cwd: string;
|
|
11
|
+
timeout?: number;
|
|
11
12
|
}): Promise<void>;
|
|
12
13
|
export declare function getTemplateData(projectName: string, description?: string, appName?: string, workspaceScope?: string): TemplateData;
|
|
13
14
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@idealyst/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.31",
|
|
4
4
|
"description": "CLI tool for generating Idealyst Framework projects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -19,10 +19,11 @@
|
|
|
19
19
|
"access": "public"
|
|
20
20
|
},
|
|
21
21
|
"scripts": {
|
|
22
|
-
"build": "
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
22
|
+
"build": "tsc",
|
|
23
|
+
"test": "jest",
|
|
24
|
+
"test:integration": "jest __tests__/integration.test.ts",
|
|
25
|
+
"dev": "tsc --watch",
|
|
26
|
+
"clean": "rm -rf dist"
|
|
26
27
|
},
|
|
27
28
|
"dependencies": {
|
|
28
29
|
"chalk": "^5.0.0",
|
|
@@ -35,13 +36,16 @@
|
|
|
35
36
|
"devDependencies": {
|
|
36
37
|
"@types/fs-extra": "^11.0.0",
|
|
37
38
|
"@types/inquirer": "^9.0.0",
|
|
39
|
+
"@types/jest": "^29.5.0",
|
|
38
40
|
"@types/node": "^20.0.0",
|
|
39
41
|
"@types/validate-npm-package-name": "^4.0.0",
|
|
42
|
+
"jest": "^29.7.0",
|
|
40
43
|
"rollup": "^3.20.0",
|
|
41
44
|
"rollup-plugin-commonjs": "^10.1.0",
|
|
42
45
|
"rollup-plugin-json": "^4.0.0",
|
|
43
46
|
"rollup-plugin-node-resolve": "^5.2.0",
|
|
44
47
|
"rollup-plugin-typescript2": "^0.34.0",
|
|
48
|
+
"ts-jest": "^29.1.0",
|
|
45
49
|
"typescript": "^5.0.0"
|
|
46
50
|
},
|
|
47
51
|
"files": [
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const typescript = require('rollup-plugin-typescript2');
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
input: 'src/index.ts',
|
|
5
|
+
output: [
|
|
6
|
+
{
|
|
7
|
+
file: 'dist/index.js',
|
|
8
|
+
format: 'cjs',
|
|
9
|
+
exports: 'named',
|
|
10
|
+
sourcemap: true,
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
file: 'dist/index.esm.js',
|
|
14
|
+
format: 'esm',
|
|
15
|
+
exports: 'named',
|
|
16
|
+
sourcemap: true,
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
plugins: [
|
|
20
|
+
typescript({
|
|
21
|
+
typescript: require('typescript'),
|
|
22
|
+
tsconfig: './tsconfig.json',
|
|
23
|
+
exclude: ['**/*.test.ts', '**/*.test.tsx', '**/*.native.ts', '**/*.native.tsx'],
|
|
24
|
+
declaration: true,
|
|
25
|
+
declarationDir: 'dist',
|
|
26
|
+
rootDir: 'src',
|
|
27
|
+
clean: true,
|
|
28
|
+
}),
|
|
29
|
+
],
|
|
30
|
+
external: [
|
|
31
|
+
'react',
|
|
32
|
+
'react-dom',
|
|
33
|
+
'react-native',
|
|
34
|
+
'react-native-unistyles',
|
|
35
|
+
'@react-native/normalize-colors',
|
|
36
|
+
'react-native-edge-to-edge',
|
|
37
|
+
'react-native-nitro-modules',
|
|
38
|
+
'@react-native-vector-icons/common',
|
|
39
|
+
'@react-native-vector-icons/material-design-icons',
|
|
40
|
+
'@mdi/js',
|
|
41
|
+
'@mdi/react',
|
|
42
|
+
],
|
|
43
|
+
};
|
|
@@ -6,6 +6,9 @@ echo "🚀 Setting up Idealyst development environment..."
|
|
|
6
6
|
# Set proper permissions
|
|
7
7
|
sudo chown -R devuser:devuser /app
|
|
8
8
|
|
|
9
|
+
# Make scripts executable
|
|
10
|
+
chmod +x /app/scripts/*.sh
|
|
11
|
+
|
|
9
12
|
# Install dependencies if not already installed
|
|
10
13
|
if [ ! -d "/app/node_modules" ]; then
|
|
11
14
|
echo "📦 Installing dependencies..."
|
|
@@ -295,7 +295,20 @@ All services include health checks:
|
|
|
295
295
|
docker-compose build --no-cache
|
|
296
296
|
```
|
|
297
297
|
|
|
298
|
-
4. **
|
|
298
|
+
4. **Yarn Lockfile Issues**
|
|
299
|
+
If you see "The lockfile would have been created by this install, which is explicitly forbidden":
|
|
300
|
+
```bash
|
|
301
|
+
# Create lockfile first
|
|
302
|
+
yarn install
|
|
303
|
+
|
|
304
|
+
# Then build Docker
|
|
305
|
+
docker-compose build
|
|
306
|
+
|
|
307
|
+
# Alternative: Use development mode (handles missing lockfile)
|
|
308
|
+
docker-compose up dev
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
5. **Permission Issues**
|
|
299
312
|
```bash
|
|
300
313
|
# Fix file permissions
|
|
301
314
|
sudo chown -R $USER:$USER .
|
|
@@ -11,9 +11,17 @@ RUN corepack enable
|
|
|
11
11
|
|
|
12
12
|
# Dependencies stage - install all dependencies
|
|
13
13
|
FROM base AS deps
|
|
14
|
-
COPY package.json yarn.lock
|
|
14
|
+
COPY package.json yarn.lock .yarnrc.yml ./
|
|
15
15
|
COPY .yarn .yarn
|
|
16
|
-
|
|
16
|
+
|
|
17
|
+
# Create packages directory structure and copy package.json files
|
|
18
|
+
RUN mkdir -p packages/api packages/app packages/components packages/web
|
|
19
|
+
COPY packages/api/package.json ./packages/api/
|
|
20
|
+
COPY packages/app/package.json ./packages/app/
|
|
21
|
+
COPY packages/components/package.json ./packages/components/
|
|
22
|
+
COPY packages/web/package.json ./packages/web/
|
|
23
|
+
|
|
24
|
+
RUN yarn install
|
|
17
25
|
|
|
18
26
|
# Build stage - build all packages
|
|
19
27
|
FROM base AS builder
|
|
@@ -70,9 +78,16 @@ RUN apk add --no-cache \
|
|
|
70
78
|
RUN npm install -g @types/node typescript ts-node nodemon
|
|
71
79
|
|
|
72
80
|
# Copy package files
|
|
73
|
-
COPY package.json yarn.lock
|
|
81
|
+
COPY package.json yarn.lock .yarnrc.yml ./
|
|
74
82
|
COPY .yarn .yarn
|
|
75
83
|
|
|
84
|
+
# Create packages directory structure and copy package.json files
|
|
85
|
+
RUN mkdir -p packages/api packages/app packages/components packages/web
|
|
86
|
+
COPY packages/api/package.json ./packages/api/
|
|
87
|
+
COPY packages/app/package.json ./packages/app/
|
|
88
|
+
COPY packages/components/package.json ./packages/components/
|
|
89
|
+
COPY packages/web/package.json ./packages/web/
|
|
90
|
+
|
|
76
91
|
# Install dependencies including dev dependencies
|
|
77
92
|
RUN yarn install
|
|
78
93
|
|
|
@@ -130,6 +130,10 @@ This workspace includes comprehensive Docker support for development, staging, a
|
|
|
130
130
|
### Quick Start with Docker
|
|
131
131
|
|
|
132
132
|
```bash
|
|
133
|
+
# Use the Docker build helper (recommended)
|
|
134
|
+
./scripts/docker-build.sh dev
|
|
135
|
+
|
|
136
|
+
# Or manually:
|
|
133
137
|
# Development environment
|
|
134
138
|
cp .env.example .env
|
|
135
139
|
./scripts/docker/deploy.sh development
|
|
@@ -140,6 +144,8 @@ cp .env.production .env
|
|
|
140
144
|
./scripts/docker/deploy.sh production
|
|
141
145
|
```
|
|
142
146
|
|
|
147
|
+
**Docker Build Helper**: The `./scripts/docker-build.sh` script automatically handles common issues like missing yarn.lock files and environment configuration.
|
|
148
|
+
|
|
143
149
|
### VS Code Dev Container
|
|
144
150
|
|
|
145
151
|
Open this workspace in VS Code and select "Reopen in Container" for a fully configured development environment with:
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Docker build helper script for Idealyst workspace
|
|
4
|
+
# Handles common issues like missing yarn.lock files
|
|
5
|
+
|
|
6
|
+
set -e
|
|
7
|
+
|
|
8
|
+
# Colors for output
|
|
9
|
+
RED='\033[0;31m'
|
|
10
|
+
GREEN='\033[0;32m'
|
|
11
|
+
YELLOW='\033[1;33m'
|
|
12
|
+
BLUE='\033[0;34m'
|
|
13
|
+
NC='\033[0m' # No Color
|
|
14
|
+
|
|
15
|
+
echo -e "${BLUE}🐳 Idealyst Docker Build Helper${NC}"
|
|
16
|
+
echo ""
|
|
17
|
+
|
|
18
|
+
# Check if yarn.lock exists
|
|
19
|
+
if [ ! -f "yarn.lock" ]; then
|
|
20
|
+
echo -e "${YELLOW}⚠️ yarn.lock not found${NC}"
|
|
21
|
+
echo "This can cause Docker build failures with 'immutable' installs."
|
|
22
|
+
echo ""
|
|
23
|
+
read -p "Would you like to generate yarn.lock now? (y/N): " -n 1 -r
|
|
24
|
+
echo ""
|
|
25
|
+
|
|
26
|
+
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
27
|
+
echo -e "${BLUE}📦 Installing dependencies to generate yarn.lock...${NC}"
|
|
28
|
+
yarn install
|
|
29
|
+
echo -e "${GREEN}✅ yarn.lock generated${NC}"
|
|
30
|
+
else
|
|
31
|
+
echo -e "${YELLOW}⚠️ Continuing without yarn.lock (may cause build issues)${NC}"
|
|
32
|
+
fi
|
|
33
|
+
echo ""
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
# Check if .env exists
|
|
37
|
+
if [ ! -f ".env" ]; then
|
|
38
|
+
echo -e "${YELLOW}⚠️ .env file not found${NC}"
|
|
39
|
+
if [ -f ".env.example" ]; then
|
|
40
|
+
read -p "Would you like to copy .env.example to .env? (y/N): " -n 1 -r
|
|
41
|
+
echo ""
|
|
42
|
+
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
43
|
+
cp .env.example .env
|
|
44
|
+
echo -e "${GREEN}✅ .env file created from .env.example${NC}"
|
|
45
|
+
echo -e "${YELLOW}📝 Please review and update .env with your settings${NC}"
|
|
46
|
+
fi
|
|
47
|
+
else
|
|
48
|
+
echo -e "${YELLOW}📝 Please create a .env file with your configuration${NC}"
|
|
49
|
+
fi
|
|
50
|
+
echo ""
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
# Determine what to build
|
|
54
|
+
if [ $# -eq 0 ]; then
|
|
55
|
+
echo "What would you like to do?"
|
|
56
|
+
echo "1) Build and start development environment"
|
|
57
|
+
echo "2) Build and start production services"
|
|
58
|
+
echo "3) Build specific service"
|
|
59
|
+
echo "4) Just build (no start)"
|
|
60
|
+
echo ""
|
|
61
|
+
read -p "Choice (1-4): " -n 1 -r
|
|
62
|
+
echo ""
|
|
63
|
+
|
|
64
|
+
case $REPLY in
|
|
65
|
+
1)
|
|
66
|
+
echo -e "${BLUE}🚀 Building and starting development environment...${NC}"
|
|
67
|
+
docker-compose build dev
|
|
68
|
+
docker-compose up -d postgres redis
|
|
69
|
+
docker-compose up dev
|
|
70
|
+
;;
|
|
71
|
+
2)
|
|
72
|
+
echo -e "${BLUE}🚀 Building and starting production services...${NC}"
|
|
73
|
+
docker-compose build
|
|
74
|
+
docker-compose up -d
|
|
75
|
+
;;
|
|
76
|
+
3)
|
|
77
|
+
echo "Available services: api, web, dev, postgres, redis"
|
|
78
|
+
read -p "Service name: " service
|
|
79
|
+
echo -e "${BLUE}🚀 Building ${service}...${NC}"
|
|
80
|
+
docker-compose build $service
|
|
81
|
+
;;
|
|
82
|
+
4)
|
|
83
|
+
echo -e "${BLUE}🏗️ Building all services...${NC}"
|
|
84
|
+
docker-compose build
|
|
85
|
+
;;
|
|
86
|
+
*)
|
|
87
|
+
echo -e "${RED}❌ Invalid choice${NC}"
|
|
88
|
+
exit 1
|
|
89
|
+
;;
|
|
90
|
+
esac
|
|
91
|
+
else
|
|
92
|
+
# Handle command line arguments
|
|
93
|
+
case "$1" in
|
|
94
|
+
"dev")
|
|
95
|
+
echo -e "${BLUE}🚀 Building and starting development environment...${NC}"
|
|
96
|
+
docker-compose build dev
|
|
97
|
+
docker-compose up -d postgres redis
|
|
98
|
+
docker-compose up dev
|
|
99
|
+
;;
|
|
100
|
+
"prod"|"production")
|
|
101
|
+
echo -e "${BLUE}🚀 Building and starting production services...${NC}"
|
|
102
|
+
docker-compose build
|
|
103
|
+
docker-compose up -d
|
|
104
|
+
;;
|
|
105
|
+
"build")
|
|
106
|
+
if [ -n "$2" ]; then
|
|
107
|
+
echo -e "${BLUE}🏗️ Building ${2}...${NC}"
|
|
108
|
+
docker-compose build $2
|
|
109
|
+
else
|
|
110
|
+
echo -e "${BLUE}🏗️ Building all services...${NC}"
|
|
111
|
+
docker-compose build
|
|
112
|
+
fi
|
|
113
|
+
;;
|
|
114
|
+
"help"|"-h"|"--help")
|
|
115
|
+
echo "Usage: $0 [command] [service]"
|
|
116
|
+
echo ""
|
|
117
|
+
echo "Commands:"
|
|
118
|
+
echo " dev Build and start development environment"
|
|
119
|
+
echo " prod Build and start production services"
|
|
120
|
+
echo " build [svc] Build all services or specific service"
|
|
121
|
+
echo " help Show this help"
|
|
122
|
+
echo ""
|
|
123
|
+
echo "Services: api, web, dev, postgres, redis"
|
|
124
|
+
;;
|
|
125
|
+
*)
|
|
126
|
+
echo -e "${RED}❌ Unknown command: $1${NC}"
|
|
127
|
+
echo "Use '$0 help' for usage information"
|
|
128
|
+
exit 1
|
|
129
|
+
;;
|
|
130
|
+
esac
|
|
131
|
+
fi
|
|
132
|
+
|
|
133
|
+
echo ""
|
|
134
|
+
echo -e "${GREEN}🎉 Done!${NC}"
|
|
135
|
+
|
|
136
|
+
# Show helpful information
|
|
137
|
+
if docker-compose ps | grep -q "Up"; then
|
|
138
|
+
echo ""
|
|
139
|
+
echo -e "${BLUE}📋 Running services:${NC}"
|
|
140
|
+
docker-compose ps
|
|
141
|
+
echo ""
|
|
142
|
+
echo -e "${BLUE}🔗 Access your application:${NC}"
|
|
143
|
+
echo "• Web: http://localhost:3000"
|
|
144
|
+
echo "• API: http://localhost:3001"
|
|
145
|
+
echo "• Vite Dev: http://localhost:5173"
|
|
146
|
+
echo ""
|
|
147
|
+
echo -e "${BLUE}💡 Useful commands:${NC}"
|
|
148
|
+
echo "• View logs: docker-compose logs -f"
|
|
149
|
+
echo "• Stop services: docker-compose down"
|
|
150
|
+
echo "• Access dev container: docker-compose exec dev bash"
|
|
151
|
+
fi
|