easybuild-nox 1.0.0
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/LICENSE +21 -0
- package/README.md +405 -0
- package/bin/easy.js +71 -0
- package/easy.config.js +58 -0
- package/package.json +69 -0
- package/src/commands/analyze.js +203 -0
- package/src/commands/build.js +80 -0
- package/src/commands/clean.js +109 -0
- package/src/commands/config.js +104 -0
- package/src/commands/db.js +423 -0
- package/src/commands/deploy.js +203 -0
- package/src/commands/dev.js +188 -0
- package/src/commands/docker.js +264 -0
- package/src/commands/electron.js +210 -0
- package/src/commands/env.js +302 -0
- package/src/commands/generate.js +556 -0
- package/src/commands/health.js +261 -0
- package/src/commands/info.js +139 -0
- package/src/commands/init.js +794 -0
- package/src/commands/lint.js +111 -0
- package/src/commands/modules.js +333 -0
- package/src/commands/package.js +265 -0
- package/src/commands/proxy.js +73 -0
- package/src/commands/run.js +199 -0
- package/src/commands/test.js +104 -0
- package/src/index.js +30 -0
- package/src/targets/docker.js +201 -0
- package/src/targets/electron.js +157 -0
- package/src/targets/frontend.js +391 -0
- package/src/targets/library.js +164 -0
- package/src/targets/node.js +146 -0
- package/src/utils/config.js +191 -0
- package/src/utils/detector.js +407 -0
- package/src/utils/globalConfig.js +106 -0
- package/src/utils/logger.js +98 -0
- package/src/utils/modules.js +571 -0
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
const { Command } = require('commander');
|
|
2
|
+
const inquirer = require('inquirer');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs-extra');
|
|
5
|
+
const logger = require('../utils/logger');
|
|
6
|
+
|
|
7
|
+
const dbCommand = new Command('db')
|
|
8
|
+
.description('Database operations')
|
|
9
|
+
.option('-a, --action <action>', 'Action (init, migrate, rollback, seed, studio, generate)')
|
|
10
|
+
.option('-n, --name <name>', 'Migration/seed name')
|
|
11
|
+
.action(async (options) => {
|
|
12
|
+
logger.header('🗄️ Database Manager');
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
const action = options.action || 'init';
|
|
16
|
+
|
|
17
|
+
const actions = {
|
|
18
|
+
init: dbInit,
|
|
19
|
+
migrate: dbMigrate,
|
|
20
|
+
rollback: dbRollback,
|
|
21
|
+
seed: dbSeed,
|
|
22
|
+
studio: dbStudio,
|
|
23
|
+
generate: dbGenerate,
|
|
24
|
+
reset: dbReset,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const actionFn = actions[action];
|
|
28
|
+
if (!actionFn) {
|
|
29
|
+
logger.error(`Unknown action: ${action}`);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
await actionFn(options);
|
|
34
|
+
} catch (error) {
|
|
35
|
+
logger.error(`Database operation failed: ${error.message}`);
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
async function dbInit(options) {
|
|
41
|
+
logger.info('Initializing database configuration...');
|
|
42
|
+
|
|
43
|
+
const answer = await inquirer.prompt([
|
|
44
|
+
{
|
|
45
|
+
type: 'list',
|
|
46
|
+
name: 'orm',
|
|
47
|
+
message: 'Select your ORM:',
|
|
48
|
+
choices: [
|
|
49
|
+
{ name: 'Prisma', value: 'prisma' },
|
|
50
|
+
{ name: 'Drizzle', value: 'drizzle' },
|
|
51
|
+
{ name: 'TypeORM', value: 'typeorm' },
|
|
52
|
+
{ name: 'Mongoose', value: 'mongoose' },
|
|
53
|
+
{ name: 'Sequelize', value: 'sequelize' },
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
type: 'list',
|
|
58
|
+
name: 'database',
|
|
59
|
+
message: 'Select your database:',
|
|
60
|
+
choices: [
|
|
61
|
+
{ name: 'PostgreSQL', value: 'postgresql' },
|
|
62
|
+
{ name: 'MySQL', value: 'mysql' },
|
|
63
|
+
{ name: 'SQLite', value: 'sqlite' },
|
|
64
|
+
{ name: 'MongoDB', value: 'mongodb' },
|
|
65
|
+
],
|
|
66
|
+
},
|
|
67
|
+
]);
|
|
68
|
+
|
|
69
|
+
const ormTemplates = {
|
|
70
|
+
prisma: {
|
|
71
|
+
'prisma/schema.prisma': `generator client {
|
|
72
|
+
provider = "prisma-client-js"
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
datasource db {
|
|
76
|
+
provider = "${answer.database}"
|
|
77
|
+
url = env("DATABASE_URL")
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
model User {
|
|
81
|
+
id Int @id @default(autoincrement())
|
|
82
|
+
email String @unique
|
|
83
|
+
name String?
|
|
84
|
+
createdAt DateTime @default(now())
|
|
85
|
+
updatedAt DateTime @updatedAt
|
|
86
|
+
}`,
|
|
87
|
+
'.env': `DATABASE_URL="${getDefaultDbUrl(answer.database)}"`,
|
|
88
|
+
},
|
|
89
|
+
drizzle: {
|
|
90
|
+
'drizzle.config.ts': `import type { Config } from 'drizzle-kit';
|
|
91
|
+
|
|
92
|
+
export default {
|
|
93
|
+
schema: './src/schema/*',
|
|
94
|
+
out: './drizzle',
|
|
95
|
+
dialect: '${answer.database}',
|
|
96
|
+
dbCredentials: {
|
|
97
|
+
url: process.env.DATABASE_URL!,
|
|
98
|
+
},
|
|
99
|
+
} satisfies Config;`,
|
|
100
|
+
'src/schema/index.ts': `import { pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core';
|
|
101
|
+
|
|
102
|
+
export const users = pgTable('users', {
|
|
103
|
+
id: serial('id').primaryKey(),
|
|
104
|
+
name: text('name'),
|
|
105
|
+
email: text('email').notNull().unique(),
|
|
106
|
+
createdAt: timestamp('created_at').defaultNow(),
|
|
107
|
+
});`,
|
|
108
|
+
},
|
|
109
|
+
typeorm: {
|
|
110
|
+
'src/entity/User.ts': `import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm';
|
|
111
|
+
|
|
112
|
+
@Entity()
|
|
113
|
+
export class User {
|
|
114
|
+
@PrimaryGeneratedColumn()
|
|
115
|
+
id: number;
|
|
116
|
+
|
|
117
|
+
@Column()
|
|
118
|
+
name: string;
|
|
119
|
+
|
|
120
|
+
@Column({ unique: true })
|
|
121
|
+
email: string;
|
|
122
|
+
|
|
123
|
+
@CreateDateColumn()
|
|
124
|
+
createdAt: Date;
|
|
125
|
+
|
|
126
|
+
@UpdateDateColumn()
|
|
127
|
+
updatedAt: Date;
|
|
128
|
+
}`,
|
|
129
|
+
},
|
|
130
|
+
mongoose: {
|
|
131
|
+
'src/models/User.ts': `import mongoose, { Schema, Document } from 'mongoose';
|
|
132
|
+
|
|
133
|
+
export interface IUser extends Document {
|
|
134
|
+
name: string;
|
|
135
|
+
email: string;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const UserSchema = new Schema<IUser>({
|
|
139
|
+
name: { type: String, required: true },
|
|
140
|
+
email: { type: String, required: true, unique: true },
|
|
141
|
+
}, {
|
|
142
|
+
timestamps: true,
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
export const User = mongoose.model<IUser>('User', UserSchema);`,
|
|
146
|
+
},
|
|
147
|
+
sequelize: {
|
|
148
|
+
'src/models/User.ts': `import { DataTypes, Model } from 'sequelize';
|
|
149
|
+
import { sequelize } from '../config/database';
|
|
150
|
+
|
|
151
|
+
export class User extends Model {
|
|
152
|
+
public id!: number;
|
|
153
|
+
public name!: string;
|
|
154
|
+
public email!: string;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
User.init({
|
|
158
|
+
id: {
|
|
159
|
+
type: DataTypes.INTEGER,
|
|
160
|
+
autoIncrement: true,
|
|
161
|
+
primaryKey: true,
|
|
162
|
+
},
|
|
163
|
+
name: {
|
|
164
|
+
type: DataTypes.STRING,
|
|
165
|
+
allowNull: false,
|
|
166
|
+
},
|
|
167
|
+
email: {
|
|
168
|
+
type: DataTypes.STRING,
|
|
169
|
+
allowNull: false,
|
|
170
|
+
unique: true,
|
|
171
|
+
},
|
|
172
|
+
}, {
|
|
173
|
+
sequelize,
|
|
174
|
+
tableName: 'users',
|
|
175
|
+
timestamps: true,
|
|
176
|
+
});`,
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const templates = ormTemplates[options.orm || 'prisma'];
|
|
181
|
+
if (!templates) {
|
|
182
|
+
logger.error('Unsupported ORM');
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
for (const [filePath, content] of Object.entries(templates)) {
|
|
187
|
+
const fullPath = path.join(process.cwd(), filePath);
|
|
188
|
+
await fs.ensureDir(path.dirname(fullPath));
|
|
189
|
+
await fs.writeFile(fullPath, content);
|
|
190
|
+
logger.success(`Created ${filePath}`);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
logger.info('Run "easy db migrate" to apply migrations');
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
async function dbMigrate(options) {
|
|
197
|
+
logger.info('Running migrations...');
|
|
198
|
+
|
|
199
|
+
// Detect ORM and run appropriate command
|
|
200
|
+
const orm = await detectOrm();
|
|
201
|
+
if (!orm) {
|
|
202
|
+
logger.error('No ORM detected. Run "easy db init" first.');
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const commands = {
|
|
207
|
+
prisma: 'npx prisma migrate dev',
|
|
208
|
+
drizzle: 'npx drizzle-kit push',
|
|
209
|
+
typeorm: 'npx typeorm migration:run',
|
|
210
|
+
sequelize: 'npx sequelize-cli db:migrate',
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
const { spawn } = require('child_process');
|
|
214
|
+
const cmd = commands[orm];
|
|
215
|
+
if (!cmd) {
|
|
216
|
+
logger.error(`Unsupported ORM: ${orm}`);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const [command, ...args] = cmd.split(' ');
|
|
221
|
+
const child = spawn(command, args, { stdio: 'inherit', shell: true });
|
|
222
|
+
|
|
223
|
+
return new Promise((resolve, reject) => {
|
|
224
|
+
child.on('close', (code) => {
|
|
225
|
+
if (code === 0) {
|
|
226
|
+
logger.success('Migrations applied successfully!');
|
|
227
|
+
resolve();
|
|
228
|
+
} else {
|
|
229
|
+
logger.error('Migration failed');
|
|
230
|
+
reject(new Error('Migration failed'));
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
async function dbRollback(options) {
|
|
237
|
+
logger.info('Rolling back migrations...');
|
|
238
|
+
|
|
239
|
+
const orm = await detectOrm();
|
|
240
|
+
if (!orm) {
|
|
241
|
+
logger.error('No ORM detected');
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const commands = {
|
|
246
|
+
prisma: 'npx prisma migrate reset',
|
|
247
|
+
typeorm: 'npx typeorm migration:revert',
|
|
248
|
+
sequelize: 'npx sequelize-cli db:migrate:undo',
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
const { spawn } = require('child_process');
|
|
252
|
+
const cmd = commands[orm];
|
|
253
|
+
if (!cmd) {
|
|
254
|
+
logger.error(`Rollback not supported for ${orm}`);
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const [command, ...args] = cmd.split(' ');
|
|
259
|
+
const child = spawn(command, args, { stdio: 'inherit', shell: true });
|
|
260
|
+
|
|
261
|
+
return new Promise((resolve, reject) => {
|
|
262
|
+
child.on('close', (code) => {
|
|
263
|
+
if (code === 0) {
|
|
264
|
+
logger.success('Rollback completed!');
|
|
265
|
+
resolve();
|
|
266
|
+
} else {
|
|
267
|
+
reject(new Error('Rollback failed'));
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
async function dbSeed(options) {
|
|
274
|
+
logger.info('Seeding database...');
|
|
275
|
+
|
|
276
|
+
const orm = await detectOrm();
|
|
277
|
+
if (!orm) {
|
|
278
|
+
logger.error('No ORM detected');
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const commands = {
|
|
283
|
+
prisma: 'npx prisma db seed',
|
|
284
|
+
drizzle: 'npx tsx src/seed.ts',
|
|
285
|
+
sequelize: 'npx sequelize-cli db:seed:all',
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
const { spawn } = require('child_process');
|
|
289
|
+
const cmd = commands[orm];
|
|
290
|
+
if (!cmd) {
|
|
291
|
+
logger.error(`Seeding not supported for ${orm}`);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const [command, ...args] = cmd.split(' ');
|
|
296
|
+
const child = spawn(command, args, { stdio: 'inherit', shell: true });
|
|
297
|
+
|
|
298
|
+
return new Promise((resolve, reject) => {
|
|
299
|
+
child.on('close', (code) => {
|
|
300
|
+
if (code === 0) {
|
|
301
|
+
logger.success('Database seeded!');
|
|
302
|
+
resolve();
|
|
303
|
+
} else {
|
|
304
|
+
reject(new Error('Seeding failed'));
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
async function dbStudio(options) {
|
|
311
|
+
logger.info('Opening database studio...');
|
|
312
|
+
|
|
313
|
+
const orm = await detectOrm();
|
|
314
|
+
if (!orm) {
|
|
315
|
+
logger.error('No ORM detected');
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const commands = {
|
|
320
|
+
prisma: 'npx prisma studio',
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
const { spawn } = require('child_process');
|
|
324
|
+
const cmd = commands[orm];
|
|
325
|
+
if (!cmd) {
|
|
326
|
+
logger.error(`Studio not supported for ${orm}`);
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const [command, ...args] = cmd.split(' ');
|
|
331
|
+
const child = spawn(command, args, { stdio: 'inherit', shell: true });
|
|
332
|
+
|
|
333
|
+
return new Promise((resolve) => {
|
|
334
|
+
child.on('close', () => resolve());
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
async function dbGenerate(options) {
|
|
339
|
+
let name = options.name;
|
|
340
|
+
if (!name) {
|
|
341
|
+
const answer = await inquirer.prompt([
|
|
342
|
+
{ type: 'input', name: 'name', message: 'Migration name:' },
|
|
343
|
+
]);
|
|
344
|
+
name = answer.name;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
logger.info(`Generating migration: ${name}...`);
|
|
348
|
+
|
|
349
|
+
const orm = await detectOrm();
|
|
350
|
+
if (!orm) {
|
|
351
|
+
logger.error('No ORM detected');
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
const timestamp = new Date().toISOString().replace(/[-:]/g, '').split('.')[0];
|
|
356
|
+
const migrationDir = `migrations/${timestamp}_${name}`;
|
|
357
|
+
|
|
358
|
+
await fs.ensureDir(migrationDir);
|
|
359
|
+
await fs.writeFile(
|
|
360
|
+
path.join(migrationDir, 'up.sql'),
|
|
361
|
+
`-- Migration: ${name}\n-- UP\n\n`
|
|
362
|
+
);
|
|
363
|
+
await fs.writeFile(
|
|
364
|
+
path.join(migrationDir, 'down.sql'),
|
|
365
|
+
`-- Migration: ${name}\n-- DOWN\n\n`
|
|
366
|
+
);
|
|
367
|
+
|
|
368
|
+
logger.success(`Created migration files in ${migrationDir}`);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
async function dbReset(options) {
|
|
372
|
+
const answer = await inquirer.prompt([
|
|
373
|
+
{
|
|
374
|
+
type: 'confirm',
|
|
375
|
+
name: 'confirm',
|
|
376
|
+
message: 'This will destroy all data. Continue?',
|
|
377
|
+
default: false,
|
|
378
|
+
},
|
|
379
|
+
]);
|
|
380
|
+
|
|
381
|
+
if (!answer.confirm) {
|
|
382
|
+
logger.info('Cancelled');
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
logger.info('Resetting database...');
|
|
387
|
+
await dbRollback(options);
|
|
388
|
+
await dbMigrate(options);
|
|
389
|
+
await dbSeed(options);
|
|
390
|
+
logger.success('Database reset complete!');
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
async function detectOrm() {
|
|
394
|
+
const pkgPath = path.join(process.cwd(), 'package.json');
|
|
395
|
+
if (await fs.pathExists(pkgPath)) {
|
|
396
|
+
const pkg = await fs.readJson(pkgPath);
|
|
397
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
398
|
+
|
|
399
|
+
if (deps.prisma || deps['@prisma/client']) return 'prisma';
|
|
400
|
+
if (deps['drizzle-orm'] || deps['drizzle-kit']) return 'drizzle';
|
|
401
|
+
if (deps.typeorm) return 'typeorm';
|
|
402
|
+
if (deps.mongoose) return 'mongoose';
|
|
403
|
+
if (deps.sequelize) return 'sequelize';
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
if (await fs.pathExists(path.join(process.cwd(), 'prisma/schema.prisma'))) return 'prisma';
|
|
407
|
+
if (await fs.pathExists(path.join(process.cwd(), 'drizzle.config.ts'))) return 'drizzle';
|
|
408
|
+
if (await fs.pathExists(path.join(process.cwd(), 'drizzle.config.js'))) return 'drizzle';
|
|
409
|
+
|
|
410
|
+
return null;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
function getDefaultDbUrl(database) {
|
|
414
|
+
const urls = {
|
|
415
|
+
postgresql: 'postgresql://postgres:password@localhost:5432/mydb',
|
|
416
|
+
mysql: 'mysql://root:password@localhost:3306/mydb',
|
|
417
|
+
sqlite: 'file:./dev.db',
|
|
418
|
+
mongodb: 'mongodb://localhost:27017/mydb',
|
|
419
|
+
};
|
|
420
|
+
return urls[database] || urls.postgresql;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
module.exports = dbCommand;
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
const { Command } = require('commander');
|
|
2
|
+
const inquirer = require('inquirer');
|
|
3
|
+
const { spawn } = require('child_process');
|
|
4
|
+
const logger = require('../utils/logger');
|
|
5
|
+
const ProjectDetector = require('../utils/detector');
|
|
6
|
+
const ConfigLoader = require('../utils/config');
|
|
7
|
+
|
|
8
|
+
const deployCommand = new Command('deploy')
|
|
9
|
+
.description('Deploy your application')
|
|
10
|
+
.option('-p, --provider <provider>', 'Cloud provider (aws, gcp, azure, vercel, netlify, railway, render, fly)')
|
|
11
|
+
.option('-e, --environment <env>', 'Deployment environment', 'production')
|
|
12
|
+
.action(async (options) => {
|
|
13
|
+
logger.header('🚀 Deploying Application');
|
|
14
|
+
|
|
15
|
+
const detector = new ProjectDetector();
|
|
16
|
+
const config = new ConfigLoader();
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const projectInfo = await detector.detect();
|
|
20
|
+
const configData = await config.load();
|
|
21
|
+
|
|
22
|
+
let provider = options.provider;
|
|
23
|
+
|
|
24
|
+
// Get provider if not provided
|
|
25
|
+
if (!provider) {
|
|
26
|
+
const providerAnswer = await inquirer.prompt([
|
|
27
|
+
{
|
|
28
|
+
type: 'list',
|
|
29
|
+
name: 'provider',
|
|
30
|
+
message: 'Select deployment provider:',
|
|
31
|
+
choices: [
|
|
32
|
+
{ name: 'Vercel - Best for frontend/fullstack', value: 'vercel' },
|
|
33
|
+
{ name: 'Netlify - Best for static sites', value: 'netlify' },
|
|
34
|
+
{ name: 'Railway - Easy fullstack deployment', value: 'railway' },
|
|
35
|
+
{ name: 'Render - Simple cloud hosting', value: 'render' },
|
|
36
|
+
{ name: 'Fly.io - Global edge deployment', value: 'fly' },
|
|
37
|
+
{ name: 'AWS - Amazon Web Services', value: 'aws' },
|
|
38
|
+
{ name: 'Google Cloud Platform', value: 'gcp' },
|
|
39
|
+
{ name: 'Microsoft Azure', value: 'azure' },
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
]);
|
|
43
|
+
provider = providerAnswer.provider;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
await deploy(projectInfo, configData, provider, options);
|
|
47
|
+
} catch (error) {
|
|
48
|
+
logger.error(`Deployment failed: ${error.message}`);
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
async function deploy(projectInfo, config, provider, options) {
|
|
54
|
+
logger.info(`Provider: ${provider}`);
|
|
55
|
+
logger.info(`Environment: ${options.environment}`);
|
|
56
|
+
logger.info('');
|
|
57
|
+
|
|
58
|
+
const deployers = {
|
|
59
|
+
vercel: deployVercel,
|
|
60
|
+
netlify: deployNetlify,
|
|
61
|
+
railway: deployRailway,
|
|
62
|
+
render: deployRender,
|
|
63
|
+
fly: deployFly,
|
|
64
|
+
aws: deployAWS,
|
|
65
|
+
gcp: deployGCP,
|
|
66
|
+
azure: deployAzure,
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const deployer = deployers[provider];
|
|
70
|
+
if (!deployer) {
|
|
71
|
+
throw new Error(`Unsupported provider: ${provider}`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
await deployer(projectInfo, config, options);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function deployVercel(projectInfo, config, options) {
|
|
78
|
+
logger.info('Deploying to Vercel...');
|
|
79
|
+
|
|
80
|
+
// Check if vercel is installed
|
|
81
|
+
const child = spawn('npx', ['vercel', options.environment === 'production' ? '--prod' : ''], {
|
|
82
|
+
stdio: 'inherit',
|
|
83
|
+
shell: true,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
return new Promise((resolve, reject) => {
|
|
87
|
+
child.on('close', (code) => {
|
|
88
|
+
if (code === 0) {
|
|
89
|
+
logger.success('Deployed to Vercel successfully!');
|
|
90
|
+
resolve();
|
|
91
|
+
} else {
|
|
92
|
+
reject(new Error('Vercel deployment failed'));
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function deployNetlify(projectInfo, config, options) {
|
|
99
|
+
logger.info('Deploying to Netlify...');
|
|
100
|
+
|
|
101
|
+
const child = spawn('npx', ['netlify-cli', 'deploy', options.environment === 'production' ? '--prod' : ''], {
|
|
102
|
+
stdio: 'inherit',
|
|
103
|
+
shell: true,
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
return new Promise((resolve, reject) => {
|
|
107
|
+
child.on('close', (code) => {
|
|
108
|
+
if (code === 0) {
|
|
109
|
+
logger.success('Deployed to Netlify successfully!');
|
|
110
|
+
resolve();
|
|
111
|
+
} else {
|
|
112
|
+
reject(new Error('Netlify deployment failed'));
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async function deployRailway(projectInfo, config, options) {
|
|
119
|
+
logger.info('Deploying to Railway...');
|
|
120
|
+
|
|
121
|
+
const child = spawn('npx', ['railway', 'up'], {
|
|
122
|
+
stdio: 'inherit',
|
|
123
|
+
shell: true,
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
return new Promise((resolve, reject) => {
|
|
127
|
+
child.on('close', (code) => {
|
|
128
|
+
if (code === 0) {
|
|
129
|
+
logger.success('Deployed to Railway successfully!');
|
|
130
|
+
resolve();
|
|
131
|
+
} else {
|
|
132
|
+
reject(new Error('Railway deployment failed'));
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async function deployRender(projectInfo, config, options) {
|
|
139
|
+
logger.info('Deploying to Render...');
|
|
140
|
+
logger.info('Please connect your repository to Render dashboard');
|
|
141
|
+
logger.info('https://dashboard.render.com');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async function deployFly(projectInfo, config, options) {
|
|
145
|
+
logger.info('Deploying to Fly.io...');
|
|
146
|
+
|
|
147
|
+
const child = spawn('flyctl', ['deploy'], {
|
|
148
|
+
stdio: 'inherit',
|
|
149
|
+
shell: true,
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
return new Promise((resolve, reject) => {
|
|
153
|
+
child.on('close', (code) => {
|
|
154
|
+
if (code === 0) {
|
|
155
|
+
logger.success('Deployed to Fly.io successfully!');
|
|
156
|
+
resolve();
|
|
157
|
+
} else {
|
|
158
|
+
reject(new Error('Fly.io deployment failed'));
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async function deployAWS(projectInfo, config, options) {
|
|
165
|
+
logger.info('Deploying to AWS...');
|
|
166
|
+
logger.info('Supported AWS services:');
|
|
167
|
+
logger.list([
|
|
168
|
+
'AWS Lambda (serverless)',
|
|
169
|
+
'AWS Elastic Beanstalk',
|
|
170
|
+
'AWS ECS/Fargate',
|
|
171
|
+
'AWS App Runner',
|
|
172
|
+
]);
|
|
173
|
+
logger.info('');
|
|
174
|
+
logger.info('Please configure your AWS credentials and select a service');
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async function deployGCP(projectInfo, config, options) {
|
|
178
|
+
logger.info('Deploying to Google Cloud...');
|
|
179
|
+
logger.info('Supported GCP services:');
|
|
180
|
+
logger.list([
|
|
181
|
+
'Cloud Run',
|
|
182
|
+
'Cloud Functions',
|
|
183
|
+
'App Engine',
|
|
184
|
+
'Cloud Run Jobs',
|
|
185
|
+
]);
|
|
186
|
+
logger.info('');
|
|
187
|
+
logger.info('Please configure gcloud CLI and select a service');
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
async function deployAzure(projectInfo, config, options) {
|
|
191
|
+
logger.info('Deploying to Microsoft Azure...');
|
|
192
|
+
logger.info('Supported Azure services:');
|
|
193
|
+
logger.list([
|
|
194
|
+
'Azure App Service',
|
|
195
|
+
'Azure Functions',
|
|
196
|
+
'Azure Container Apps',
|
|
197
|
+
'Azure Static Web Apps',
|
|
198
|
+
]);
|
|
199
|
+
logger.info('');
|
|
200
|
+
logger.info('Please configure Azure CLI and select a service');
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
module.exports = deployCommand;
|