katax-cli 1.1.3 ā 1.2.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/dist/commands/add-endpoint.d.ts.map +1 -1
- package/dist/commands/add-endpoint.js +121 -97
- package/dist/commands/add-endpoint.js.map +1 -1
- package/dist/commands/deploy.d.ts +3 -0
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +287 -153
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/generate-crud.d.ts.map +1 -1
- package/dist/commands/generate-crud.js +60 -56
- package/dist/commands/generate-crud.js.map +1 -1
- package/dist/commands/generate-docs.d.ts +8 -0
- package/dist/commands/generate-docs.d.ts.map +1 -0
- package/dist/commands/generate-docs.js +159 -0
- package/dist/commands/generate-docs.js.map +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +506 -244
- package/dist/commands/init.js.map +1 -1
- package/dist/index.js +83 -69
- package/dist/index.js.map +1 -1
- package/dist/services/openapi-generator.service.d.ts +37 -0
- package/dist/services/openapi-generator.service.d.ts.map +1 -0
- package/dist/services/openapi-generator.service.js +333 -0
- package/dist/services/openapi-generator.service.js.map +1 -0
- package/dist/services/project-structure-generator.d.ts +1 -1
- package/dist/services/project-structure-generator.d.ts.map +1 -1
- package/dist/services/project-structure-generator.js +443 -445
- package/dist/services/project-structure-generator.js.map +1 -1
- package/dist/templates/generators/swagger-template.d.ts +3 -0
- package/dist/templates/generators/swagger-template.d.ts.map +1 -0
- package/dist/templates/generators/swagger-template.js +117 -0
- package/dist/templates/generators/swagger-template.js.map +1 -0
- package/dist/types/index.d.ts +19 -10
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/commands/deploy.js
CHANGED
|
@@ -1,96 +1,96 @@
|
|
|
1
|
-
import chalk from
|
|
2
|
-
import inquirer from
|
|
3
|
-
import ora from
|
|
4
|
-
import path from
|
|
5
|
-
import { execa } from
|
|
6
|
-
import { success, error, warning, title, info, gray } from
|
|
7
|
-
import { directoryExists, writeFile } from
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import inquirer from "inquirer";
|
|
3
|
+
import ora from "ora";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import { execa } from "execa";
|
|
6
|
+
import { success, error, warning, title, info, gray } from "../utils/logger.js";
|
|
7
|
+
import { directoryExists, writeFile, fileExists } from "../utils/file-utils.js";
|
|
8
8
|
export async function deployInitCommand() {
|
|
9
|
-
title(
|
|
9
|
+
title("š Katax Deploy - Initial Setup");
|
|
10
10
|
const pm2Installed = await checkPM2Installation();
|
|
11
11
|
if (!pm2Installed) {
|
|
12
|
-
error(
|
|
13
|
-
info(
|
|
12
|
+
error("PM2 is not installed globally!");
|
|
13
|
+
info("Install with: npm install -g pm2");
|
|
14
14
|
process.exit(1);
|
|
15
15
|
}
|
|
16
16
|
const answers = await inquirer.prompt([
|
|
17
17
|
{
|
|
18
|
-
type:
|
|
19
|
-
name:
|
|
20
|
-
message:
|
|
21
|
-
default:
|
|
18
|
+
type: "input",
|
|
19
|
+
name: "appName",
|
|
20
|
+
message: "Application name for PM2:",
|
|
21
|
+
default: "my-api",
|
|
22
22
|
validate: (input) => {
|
|
23
23
|
if (!/^[a-z0-9-_]+$/i.test(input)) {
|
|
24
|
-
return
|
|
24
|
+
return "App name can only contain letters, numbers, hyphens, and underscores";
|
|
25
25
|
}
|
|
26
26
|
return true;
|
|
27
|
-
}
|
|
27
|
+
},
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
|
-
type:
|
|
31
|
-
name:
|
|
32
|
-
message:
|
|
30
|
+
type: "list",
|
|
31
|
+
name: "repoType",
|
|
32
|
+
message: "Repository connection type:",
|
|
33
33
|
choices: [
|
|
34
|
-
{ name:
|
|
35
|
-
{ name:
|
|
34
|
+
{ name: "HTTPS (username/password or token)", value: "https" },
|
|
35
|
+
{ name: "SSH (requires SSH key setup)", value: "ssh" },
|
|
36
36
|
],
|
|
37
|
-
default:
|
|
37
|
+
default: "https",
|
|
38
38
|
},
|
|
39
39
|
{
|
|
40
|
-
type:
|
|
41
|
-
name:
|
|
42
|
-
message:
|
|
40
|
+
type: "input",
|
|
41
|
+
name: "repoUrl",
|
|
42
|
+
message: "Git repository URL:",
|
|
43
43
|
validate: (input) => {
|
|
44
44
|
if (!input)
|
|
45
|
-
return
|
|
46
|
-
if (!input.includes(
|
|
47
|
-
return
|
|
45
|
+
return "Repository URL is required";
|
|
46
|
+
if (!input.includes("git") && !input.includes(".git")) {
|
|
47
|
+
return "Please provide a valid Git repository URL";
|
|
48
48
|
}
|
|
49
49
|
return true;
|
|
50
|
-
}
|
|
50
|
+
},
|
|
51
51
|
},
|
|
52
52
|
{
|
|
53
|
-
type:
|
|
54
|
-
name:
|
|
55
|
-
message:
|
|
56
|
-
default:
|
|
53
|
+
type: "input",
|
|
54
|
+
name: "branch",
|
|
55
|
+
message: "Branch to deploy:",
|
|
56
|
+
default: "main",
|
|
57
57
|
},
|
|
58
58
|
{
|
|
59
|
-
type:
|
|
60
|
-
name:
|
|
61
|
-
message:
|
|
62
|
-
default: `/home/${process.env.USER ||
|
|
59
|
+
type: "input",
|
|
60
|
+
name: "installPath",
|
|
61
|
+
message: "Installation path (absolute):",
|
|
62
|
+
default: `/home/${process.env.USER || "ubuntu"}/apps`,
|
|
63
63
|
validate: (input) => {
|
|
64
64
|
if (!path.isAbsolute(input)) {
|
|
65
|
-
return
|
|
65
|
+
return "Please provide an absolute path";
|
|
66
66
|
}
|
|
67
67
|
return true;
|
|
68
|
-
}
|
|
68
|
+
},
|
|
69
69
|
},
|
|
70
70
|
{
|
|
71
|
-
type:
|
|
72
|
-
name:
|
|
73
|
-
message:
|
|
71
|
+
type: "list",
|
|
72
|
+
name: "instances",
|
|
73
|
+
message: "PM2 instances (cluster mode):",
|
|
74
74
|
choices: [
|
|
75
|
-
{ name:
|
|
76
|
-
{ name:
|
|
77
|
-
{ name:
|
|
78
|
-
{ name:
|
|
75
|
+
{ name: "Max (use all CPU cores)", value: "max" },
|
|
76
|
+
{ name: "1 instance", value: 1 },
|
|
77
|
+
{ name: "2 instances", value: 2 },
|
|
78
|
+
{ name: "4 instances", value: 4 },
|
|
79
79
|
],
|
|
80
|
-
default:
|
|
80
|
+
default: "max",
|
|
81
81
|
},
|
|
82
82
|
{
|
|
83
|
-
type:
|
|
84
|
-
name:
|
|
85
|
-
message:
|
|
86
|
-
default:
|
|
83
|
+
type: "input",
|
|
84
|
+
name: "maxMemory",
|
|
85
|
+
message: "Max memory per instance (e.g., 512M, 1G):",
|
|
86
|
+
default: "512M",
|
|
87
87
|
},
|
|
88
88
|
{
|
|
89
|
-
type:
|
|
90
|
-
name:
|
|
91
|
-
message:
|
|
92
|
-
default: true
|
|
93
|
-
}
|
|
89
|
+
type: "confirm",
|
|
90
|
+
name: "addEnvVars",
|
|
91
|
+
message: "Add environment variables?",
|
|
92
|
+
default: true,
|
|
93
|
+
},
|
|
94
94
|
]);
|
|
95
95
|
let envVars = {};
|
|
96
96
|
if (answers.addEnvVars) {
|
|
@@ -104,108 +104,180 @@ export async function deployInitCommand() {
|
|
|
104
104
|
pm2Config: {
|
|
105
105
|
instances: answers.instances,
|
|
106
106
|
maxMemory: answers.maxMemory,
|
|
107
|
-
env: envVars
|
|
108
|
-
}
|
|
107
|
+
env: envVars,
|
|
108
|
+
},
|
|
109
109
|
};
|
|
110
110
|
await executeInitialDeploy(deployConfig);
|
|
111
111
|
}
|
|
112
112
|
export async function deployUpdateCommand(options) {
|
|
113
|
-
title(
|
|
113
|
+
title("š Katax Deploy - Update Application");
|
|
114
114
|
const isGitRepo = await checkGitRepository();
|
|
115
115
|
if (!isGitRepo) {
|
|
116
|
-
error(
|
|
117
|
-
info(
|
|
116
|
+
error("Not a git repository! Run this command from your project directory.");
|
|
117
|
+
info("Or use: katax deploy init");
|
|
118
118
|
process.exit(1);
|
|
119
119
|
}
|
|
120
120
|
const pm2Installed = await checkPM2Installation();
|
|
121
121
|
if (!pm2Installed) {
|
|
122
|
-
error(
|
|
123
|
-
info(
|
|
122
|
+
error("PM2 is not installed globally!");
|
|
123
|
+
info("Install with: npm install -g pm2");
|
|
124
124
|
process.exit(1);
|
|
125
125
|
}
|
|
126
126
|
const currentDir = process.cwd();
|
|
127
|
-
|
|
127
|
+
let appName = options.appName;
|
|
128
|
+
let wasAutoDiscovered = false;
|
|
129
|
+
if (!appName) {
|
|
130
|
+
const discovered = await discoverPM2AppName(currentDir);
|
|
131
|
+
if (discovered) {
|
|
132
|
+
appName = discovered;
|
|
133
|
+
wasAutoDiscovered = true;
|
|
134
|
+
info(`š Discovered PM2 app: ${chalk.cyan(appName)}`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (!appName) {
|
|
138
|
+
const configPath = path.join(currentDir, ".katax-deploy.json");
|
|
139
|
+
if (fileExists(configPath)) {
|
|
140
|
+
try {
|
|
141
|
+
const fs = await import("fs");
|
|
142
|
+
const configContent = fs.readFileSync(configPath, "utf-8");
|
|
143
|
+
const config = JSON.parse(configContent);
|
|
144
|
+
appName = config.appName;
|
|
145
|
+
info(`š Using app name from config: ${chalk.cyan(appName)}`);
|
|
146
|
+
}
|
|
147
|
+
catch (err) {
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (!appName) {
|
|
152
|
+
appName = path.basename(currentDir);
|
|
153
|
+
warning(`ā ļø Using directory name as fallback: ${chalk.yellow(appName)}`);
|
|
154
|
+
info(`š” Tip: Run ${chalk.cyan("pm2 list")} to verify the app name`);
|
|
155
|
+
}
|
|
128
156
|
let targetBranch = options.branch;
|
|
129
157
|
if (!targetBranch) {
|
|
130
|
-
const branchResult = await execa(
|
|
158
|
+
const branchResult = await execa("git", ["branch", "--show-current"]);
|
|
131
159
|
targetBranch = branchResult.stdout.trim();
|
|
132
160
|
}
|
|
161
|
+
if (wasAutoDiscovered && appName) {
|
|
162
|
+
await saveAppNameToConfig(currentDir, appName, targetBranch);
|
|
163
|
+
}
|
|
133
164
|
info(`š¦ Application: ${chalk.cyan(appName)}`);
|
|
134
165
|
info(`šæ Branch: ${chalk.cyan(targetBranch)}`);
|
|
135
166
|
if (options.hard) {
|
|
136
|
-
warning(
|
|
167
|
+
warning("ā ļø Hard reset enabled - all local changes will be lost!");
|
|
137
168
|
}
|
|
138
169
|
const { confirm } = await inquirer.prompt([
|
|
139
170
|
{
|
|
140
|
-
type:
|
|
141
|
-
name:
|
|
142
|
-
message:
|
|
143
|
-
default: true
|
|
144
|
-
}
|
|
171
|
+
type: "confirm",
|
|
172
|
+
name: "confirm",
|
|
173
|
+
message: "Proceed with update?",
|
|
174
|
+
default: true,
|
|
175
|
+
},
|
|
145
176
|
]);
|
|
146
177
|
if (!confirm) {
|
|
147
|
-
warning(
|
|
178
|
+
warning("Update cancelled");
|
|
148
179
|
return;
|
|
149
180
|
}
|
|
150
181
|
await executeUpdate(appName, targetBranch, options.hard || false);
|
|
182
|
+
if (!wasAutoDiscovered) {
|
|
183
|
+
await saveAppNameToConfig(currentDir, appName, targetBranch, true);
|
|
184
|
+
}
|
|
151
185
|
}
|
|
152
186
|
export async function deployRollbackCommand(options) {
|
|
153
|
-
title(
|
|
187
|
+
title("ā®ļø Katax Deploy - Rollback");
|
|
154
188
|
const isGitRepo = await checkGitRepository();
|
|
155
189
|
if (!isGitRepo) {
|
|
156
|
-
error(
|
|
190
|
+
error("Not a git repository!");
|
|
157
191
|
process.exit(1);
|
|
158
192
|
}
|
|
159
193
|
const commits = options.commits || 1;
|
|
160
194
|
const currentDir = process.cwd();
|
|
161
|
-
|
|
195
|
+
let appName = options.appName;
|
|
196
|
+
if (!appName) {
|
|
197
|
+
appName = (await discoverPM2AppName(currentDir)) || undefined;
|
|
198
|
+
}
|
|
199
|
+
if (!appName) {
|
|
200
|
+
const configPath = path.join(currentDir, ".katax-deploy.json");
|
|
201
|
+
if (fileExists(configPath)) {
|
|
202
|
+
try {
|
|
203
|
+
const fs = await import("fs");
|
|
204
|
+
const configContent = fs.readFileSync(configPath, "utf-8");
|
|
205
|
+
const config = JSON.parse(configContent);
|
|
206
|
+
appName = config.appName;
|
|
207
|
+
}
|
|
208
|
+
catch (err) {
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (!appName) {
|
|
213
|
+
appName = path.basename(currentDir);
|
|
214
|
+
}
|
|
162
215
|
warning(`Rolling back ${commits} commit(s) for ${appName}`);
|
|
163
216
|
const { confirm } = await inquirer.prompt([
|
|
164
217
|
{
|
|
165
|
-
type:
|
|
166
|
-
name:
|
|
167
|
-
message:
|
|
168
|
-
default: false
|
|
169
|
-
}
|
|
218
|
+
type: "confirm",
|
|
219
|
+
name: "confirm",
|
|
220
|
+
message: "This will reset your code. Continue?",
|
|
221
|
+
default: false,
|
|
222
|
+
},
|
|
170
223
|
]);
|
|
171
224
|
if (!confirm) {
|
|
172
|
-
warning(
|
|
225
|
+
warning("Rollback cancelled");
|
|
173
226
|
return;
|
|
174
227
|
}
|
|
175
228
|
await executeRollback(appName, commits);
|
|
176
229
|
}
|
|
177
230
|
export async function deployLogsCommand(options) {
|
|
178
231
|
const currentDir = process.cwd();
|
|
179
|
-
|
|
232
|
+
let appName = options.appName;
|
|
233
|
+
if (!appName) {
|
|
234
|
+
appName = (await discoverPM2AppName(currentDir)) || undefined;
|
|
235
|
+
}
|
|
236
|
+
if (!appName) {
|
|
237
|
+
const configPath = path.join(currentDir, ".katax-deploy.json");
|
|
238
|
+
if (fileExists(configPath)) {
|
|
239
|
+
try {
|
|
240
|
+
const fs = await import("fs");
|
|
241
|
+
const configContent = fs.readFileSync(configPath, "utf-8");
|
|
242
|
+
const config = JSON.parse(configContent);
|
|
243
|
+
appName = config.appName;
|
|
244
|
+
}
|
|
245
|
+
catch (err) {
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
if (!appName) {
|
|
250
|
+
appName = path.basename(currentDir);
|
|
251
|
+
}
|
|
180
252
|
title(`š PM2 Logs - ${appName}`);
|
|
181
|
-
const args = [
|
|
253
|
+
const args = ["logs", appName];
|
|
182
254
|
if (options.lines) {
|
|
183
|
-
args.push(
|
|
255
|
+
args.push("--lines", options.lines.toString());
|
|
184
256
|
}
|
|
185
257
|
if (!options.follow) {
|
|
186
|
-
args.push(
|
|
258
|
+
args.push("--nostream");
|
|
187
259
|
}
|
|
188
260
|
try {
|
|
189
|
-
await execa(
|
|
261
|
+
await execa("pm2", args, { stdio: "inherit" });
|
|
190
262
|
}
|
|
191
263
|
catch (err) {
|
|
192
|
-
error(
|
|
264
|
+
error("Failed to fetch logs");
|
|
193
265
|
console.error(err);
|
|
194
266
|
}
|
|
195
267
|
}
|
|
196
268
|
export async function deployStatusCommand() {
|
|
197
|
-
title(
|
|
269
|
+
title("š PM2 Status");
|
|
198
270
|
try {
|
|
199
|
-
await execa(
|
|
271
|
+
await execa("pm2", ["list"], { stdio: "inherit" });
|
|
200
272
|
}
|
|
201
273
|
catch (err) {
|
|
202
|
-
error(
|
|
274
|
+
error("Failed to get PM2 status");
|
|
203
275
|
console.error(err);
|
|
204
276
|
}
|
|
205
277
|
}
|
|
206
278
|
async function checkPM2Installation() {
|
|
207
279
|
try {
|
|
208
|
-
await execa(
|
|
280
|
+
await execa("pm2", ["--version"]);
|
|
209
281
|
return true;
|
|
210
282
|
}
|
|
211
283
|
catch {
|
|
@@ -214,32 +286,80 @@ async function checkPM2Installation() {
|
|
|
214
286
|
}
|
|
215
287
|
async function checkGitRepository() {
|
|
216
288
|
try {
|
|
217
|
-
await execa(
|
|
289
|
+
await execa("git", ["rev-parse", "--git-dir"]);
|
|
218
290
|
return true;
|
|
219
291
|
}
|
|
220
292
|
catch {
|
|
221
293
|
return false;
|
|
222
294
|
}
|
|
223
295
|
}
|
|
296
|
+
async function saveAppNameToConfig(projectDir, appName, branch, silent = false) {
|
|
297
|
+
try {
|
|
298
|
+
const configPath = path.join(projectDir, ".katax-deploy.json");
|
|
299
|
+
if (fileExists(configPath)) {
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
const config = {
|
|
303
|
+
appName: appName,
|
|
304
|
+
createdAt: new Date().toISOString(),
|
|
305
|
+
branch: branch,
|
|
306
|
+
autoDiscovered: true,
|
|
307
|
+
};
|
|
308
|
+
await writeFile(configPath, JSON.stringify(config, null, 2));
|
|
309
|
+
if (!silent) {
|
|
310
|
+
success(`š¾ Saved app name to .katax-deploy.json for future deployments`);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
catch (err) {
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
async function discoverPM2AppName(targetDir) {
|
|
317
|
+
try {
|
|
318
|
+
const { stdout } = await execa("pm2", ["jlist"]);
|
|
319
|
+
const processes = JSON.parse(stdout);
|
|
320
|
+
const normalizedTargetDir = path.resolve(targetDir).toLowerCase();
|
|
321
|
+
for (const proc of processes) {
|
|
322
|
+
if (proc.pm2_env && proc.pm2_env.pm_cwd) {
|
|
323
|
+
const procDir = path.resolve(proc.pm2_env.pm_cwd).toLowerCase();
|
|
324
|
+
if (procDir === normalizedTargetDir) {
|
|
325
|
+
return proc.name;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
if (proc.pm2_env && proc.pm2_env.pm_exec_path) {
|
|
329
|
+
const execDir = path
|
|
330
|
+
.resolve(path.dirname(proc.pm2_env.pm_exec_path))
|
|
331
|
+
.toLowerCase();
|
|
332
|
+
if (execDir === normalizedTargetDir ||
|
|
333
|
+
execDir.startsWith(normalizedTargetDir)) {
|
|
334
|
+
return proc.name;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return null;
|
|
339
|
+
}
|
|
340
|
+
catch (err) {
|
|
341
|
+
return null;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
224
344
|
async function collectEnvVars() {
|
|
225
345
|
const envVars = {};
|
|
226
|
-
info(
|
|
346
|
+
info("\nš Add environment variables (leave empty to finish):\n");
|
|
227
347
|
while (true) {
|
|
228
348
|
const { key } = await inquirer.prompt([
|
|
229
349
|
{
|
|
230
|
-
type:
|
|
231
|
-
name:
|
|
232
|
-
message:
|
|
233
|
-
}
|
|
350
|
+
type: "input",
|
|
351
|
+
name: "key",
|
|
352
|
+
message: "Variable name:",
|
|
353
|
+
},
|
|
234
354
|
]);
|
|
235
355
|
if (!key)
|
|
236
356
|
break;
|
|
237
357
|
const { value } = await inquirer.prompt([
|
|
238
358
|
{
|
|
239
|
-
type:
|
|
240
|
-
name:
|
|
359
|
+
type: "input",
|
|
360
|
+
name: "value",
|
|
241
361
|
message: `Value for ${key}:`,
|
|
242
|
-
}
|
|
362
|
+
},
|
|
243
363
|
]);
|
|
244
364
|
envVars[key] = value;
|
|
245
365
|
success(`ā ${key} added`);
|
|
@@ -252,124 +372,138 @@ async function executeInitialDeploy(config) {
|
|
|
252
372
|
error(`Directory ${fullPath} already exists!`);
|
|
253
373
|
process.exit(1);
|
|
254
374
|
}
|
|
255
|
-
const
|
|
375
|
+
const deployConfigFile = {
|
|
376
|
+
appName: config.appName,
|
|
377
|
+
createdAt: new Date().toISOString(),
|
|
378
|
+
branch: config.branch,
|
|
379
|
+
};
|
|
380
|
+
await writeFile(path.join(fullPath, ".katax-deploy.json"), JSON.stringify(deployConfigFile, null, 2));
|
|
381
|
+
const cloneSpinner = ora("Cloning repository...").start();
|
|
256
382
|
try {
|
|
257
|
-
await execa(
|
|
258
|
-
|
|
383
|
+
await execa("git", [
|
|
384
|
+
"clone",
|
|
385
|
+
"--branch",
|
|
386
|
+
config.branch,
|
|
387
|
+
config.repoUrl,
|
|
388
|
+
fullPath,
|
|
389
|
+
]);
|
|
390
|
+
cloneSpinner.succeed("Repository cloned");
|
|
259
391
|
}
|
|
260
392
|
catch (err) {
|
|
261
|
-
cloneSpinner.fail(
|
|
393
|
+
cloneSpinner.fail("Failed to clone repository");
|
|
262
394
|
console.error(err);
|
|
263
395
|
process.exit(1);
|
|
264
396
|
}
|
|
265
|
-
const installSpinner = ora(
|
|
397
|
+
const installSpinner = ora("Installing dependencies...").start();
|
|
266
398
|
try {
|
|
267
|
-
await execa(
|
|
268
|
-
installSpinner.succeed(
|
|
399
|
+
await execa("npm", ["install"], { cwd: fullPath });
|
|
400
|
+
installSpinner.succeed("Dependencies installed");
|
|
269
401
|
}
|
|
270
402
|
catch (err) {
|
|
271
|
-
installSpinner.fail(
|
|
403
|
+
installSpinner.fail("Failed to install dependencies");
|
|
272
404
|
console.error(err);
|
|
273
405
|
process.exit(1);
|
|
274
406
|
}
|
|
275
|
-
const buildSpinner = ora(
|
|
407
|
+
const buildSpinner = ora("Building project...").start();
|
|
276
408
|
try {
|
|
277
|
-
await execa(
|
|
278
|
-
buildSpinner.succeed(
|
|
409
|
+
await execa("npm", ["run", "build"], { cwd: fullPath });
|
|
410
|
+
buildSpinner.succeed("Project built");
|
|
279
411
|
}
|
|
280
412
|
catch (err) {
|
|
281
|
-
buildSpinner.fail(
|
|
413
|
+
buildSpinner.fail("Failed to build project");
|
|
282
414
|
console.error(err);
|
|
283
415
|
process.exit(1);
|
|
284
416
|
}
|
|
285
417
|
await generatePM2Config(fullPath, config);
|
|
286
|
-
const pm2Spinner = ora(
|
|
418
|
+
const pm2Spinner = ora("Starting with PM2...").start();
|
|
287
419
|
try {
|
|
288
|
-
await execa(
|
|
289
|
-
await execa(
|
|
290
|
-
pm2Spinner.succeed(
|
|
420
|
+
await execa("pm2", ["start", "ecosystem.config.cjs", "--env", "production"], { cwd: fullPath });
|
|
421
|
+
await execa("pm2", ["save"]);
|
|
422
|
+
pm2Spinner.succeed("Application started with PM2");
|
|
291
423
|
}
|
|
292
424
|
catch (err) {
|
|
293
|
-
pm2Spinner.fail(
|
|
425
|
+
pm2Spinner.fail("Failed to start with PM2");
|
|
294
426
|
console.error(err);
|
|
295
427
|
process.exit(1);
|
|
296
428
|
}
|
|
297
429
|
success(`\nā
Deployment completed successfully!`);
|
|
298
430
|
info(`\nš Location: ${fullPath}`);
|
|
299
431
|
info(`š§ PM2 App Name: ${config.appName}`);
|
|
432
|
+
info(`š Config saved: .katax-deploy.json`);
|
|
300
433
|
info(`\nUseful commands:`);
|
|
301
434
|
gray(` pm2 logs ${config.appName} # View logs`);
|
|
302
435
|
gray(` pm2 restart ${config.appName} # Restart app`);
|
|
303
436
|
gray(` pm2 stop ${config.appName} # Stop app`);
|
|
304
|
-
gray(` katax deploy update # Update deployment
|
|
437
|
+
gray(` katax deploy update # Update deployment`);
|
|
438
|
+
gray(` katax deploy update --app-name ${config.appName} # Specify app name\n`);
|
|
305
439
|
}
|
|
306
440
|
async function executeUpdate(appName, branch, hard) {
|
|
307
441
|
const currentDir = process.cwd();
|
|
308
|
-
const gitSpinner = ora(
|
|
442
|
+
const gitSpinner = ora("Updating code from git...").start();
|
|
309
443
|
try {
|
|
310
|
-
await execa(
|
|
444
|
+
await execa("git", ["fetch", "origin", branch]);
|
|
311
445
|
if (hard) {
|
|
312
|
-
await execa(
|
|
446
|
+
await execa("git", ["reset", "--hard", `origin/${branch}`]);
|
|
313
447
|
}
|
|
314
448
|
else {
|
|
315
|
-
await execa(
|
|
449
|
+
await execa("git", ["pull", "origin", branch]);
|
|
316
450
|
}
|
|
317
|
-
gitSpinner.succeed(
|
|
451
|
+
gitSpinner.succeed("Code updated");
|
|
318
452
|
}
|
|
319
453
|
catch (err) {
|
|
320
|
-
gitSpinner.fail(
|
|
454
|
+
gitSpinner.fail("Git update failed");
|
|
321
455
|
error(err.message);
|
|
322
456
|
process.exit(1);
|
|
323
457
|
}
|
|
324
|
-
const installSpinner = ora(
|
|
458
|
+
const installSpinner = ora("Installing dependencies...").start();
|
|
325
459
|
try {
|
|
326
|
-
await execa(
|
|
327
|
-
installSpinner.succeed(
|
|
460
|
+
await execa("npm", ["install"], { cwd: currentDir });
|
|
461
|
+
installSpinner.succeed("Dependencies updated");
|
|
328
462
|
}
|
|
329
463
|
catch (err) {
|
|
330
|
-
installSpinner.fail(
|
|
464
|
+
installSpinner.fail("Failed to install dependencies");
|
|
331
465
|
console.error(err);
|
|
332
466
|
process.exit(1);
|
|
333
467
|
}
|
|
334
|
-
const buildSpinner = ora(
|
|
468
|
+
const buildSpinner = ora("Building project...").start();
|
|
335
469
|
try {
|
|
336
|
-
await execa(
|
|
337
|
-
buildSpinner.succeed(
|
|
470
|
+
await execa("npm", ["run", "build"], { cwd: currentDir });
|
|
471
|
+
buildSpinner.succeed("Project rebuilt");
|
|
338
472
|
}
|
|
339
473
|
catch (err) {
|
|
340
|
-
buildSpinner.fail(
|
|
474
|
+
buildSpinner.fail("Build failed");
|
|
341
475
|
console.error(err);
|
|
342
476
|
process.exit(1);
|
|
343
477
|
}
|
|
344
|
-
const pm2Spinner = ora(
|
|
478
|
+
const pm2Spinner = ora("Restarting PM2...").start();
|
|
345
479
|
try {
|
|
346
|
-
await execa(
|
|
347
|
-
pm2Spinner.succeed(
|
|
480
|
+
await execa("pm2", ["restart", appName]);
|
|
481
|
+
pm2Spinner.succeed("Application restarted");
|
|
348
482
|
}
|
|
349
483
|
catch (err) {
|
|
350
|
-
pm2Spinner.fail(
|
|
484
|
+
pm2Spinner.fail("PM2 restart failed");
|
|
351
485
|
console.error(err);
|
|
352
486
|
process.exit(1);
|
|
353
487
|
}
|
|
354
|
-
success(
|
|
488
|
+
success("\nā
Update completed successfully!");
|
|
355
489
|
info(`\nView logs with: pm2 logs ${appName}\n`);
|
|
356
490
|
}
|
|
357
491
|
async function executeRollback(appName, commits) {
|
|
358
492
|
const rollbackSpinner = ora(`Rolling back ${commits} commit(s)...`).start();
|
|
359
493
|
try {
|
|
360
|
-
await execa(
|
|
361
|
-
rollbackSpinner.succeed(
|
|
362
|
-
const buildSpinner = ora(
|
|
363
|
-
await execa(
|
|
364
|
-
await execa(
|
|
365
|
-
buildSpinner.succeed(
|
|
366
|
-
const pm2Spinner = ora(
|
|
367
|
-
await execa(
|
|
368
|
-
pm2Spinner.succeed(
|
|
369
|
-
success(
|
|
494
|
+
await execa("git", ["reset", "--hard", `HEAD~${commits}`]);
|
|
495
|
+
rollbackSpinner.succeed("Code rolled back");
|
|
496
|
+
const buildSpinner = ora("Rebuilding...").start();
|
|
497
|
+
await execa("npm", ["install"]);
|
|
498
|
+
await execa("npm", ["run", "build"]);
|
|
499
|
+
buildSpinner.succeed("Project rebuilt");
|
|
500
|
+
const pm2Spinner = ora("Restarting PM2...").start();
|
|
501
|
+
await execa("pm2", ["restart", appName]);
|
|
502
|
+
pm2Spinner.succeed("Application restarted");
|
|
503
|
+
success("\nā
Rollback completed successfully!");
|
|
370
504
|
}
|
|
371
505
|
catch (err) {
|
|
372
|
-
rollbackSpinner.fail(
|
|
506
|
+
rollbackSpinner.fail("Rollback failed");
|
|
373
507
|
console.error(err);
|
|
374
508
|
process.exit(1);
|
|
375
509
|
}
|
|
@@ -384,7 +518,7 @@ module.exports = {
|
|
|
384
518
|
script: './dist/index.js',
|
|
385
519
|
|
|
386
520
|
// Cluster mode
|
|
387
|
-
instances: ${typeof config.pm2Config.instances ===
|
|
521
|
+
instances: ${typeof config.pm2Config.instances === "number" ? config.pm2Config.instances : `'${config.pm2Config.instances}'`},
|
|
388
522
|
exec_mode: 'cluster',
|
|
389
523
|
|
|
390
524
|
// Resource limits
|
|
@@ -404,13 +538,13 @@ module.exports = {
|
|
|
404
538
|
|
|
405
539
|
// Environment variables
|
|
406
540
|
env_production: ${JSON.stringify({
|
|
407
|
-
NODE_ENV:
|
|
408
|
-
...config.pm2Config.env
|
|
541
|
+
NODE_ENV: "production",
|
|
542
|
+
...config.pm2Config.env,
|
|
409
543
|
}, null, 6)}
|
|
410
544
|
}]
|
|
411
545
|
};
|
|
412
546
|
`;
|
|
413
|
-
await writeFile(path.join(projectPath,
|
|
414
|
-
success(
|
|
547
|
+
await writeFile(path.join(projectPath, "ecosystem.config.cjs"), ecosystem);
|
|
548
|
+
success("ā PM2 ecosystem.config.cjs generated");
|
|
415
549
|
}
|
|
416
550
|
//# sourceMappingURL=deploy.js.map
|