nodebbs 0.0.2 → 0.0.4

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.
Files changed (62) hide show
  1. package/README.md +103 -111
  2. package/bin/dev.js +6 -1
  3. package/bin/run.js +6 -1
  4. package/dist/commands/clean/index.d.ts +11 -0
  5. package/dist/commands/clean/index.js +93 -0
  6. package/dist/commands/db/backup.d.ts +9 -0
  7. package/dist/commands/db/backup.js +78 -0
  8. package/dist/commands/db/generate.d.ts +3 -0
  9. package/dist/commands/db/generate.js +9 -3
  10. package/dist/commands/db/migrate.d.ts +3 -0
  11. package/dist/commands/db/migrate.js +8 -2
  12. package/dist/commands/db/push.d.ts +3 -0
  13. package/dist/commands/db/push.js +8 -2
  14. package/dist/commands/db/reset.d.ts +3 -0
  15. package/dist/commands/db/reset.js +10 -4
  16. package/dist/commands/db/seed.d.ts +3 -0
  17. package/dist/commands/db/seed.js +9 -3
  18. package/dist/commands/logs/api.d.ts +3 -0
  19. package/dist/commands/logs/api.js +8 -2
  20. package/dist/commands/logs/db.d.ts +3 -0
  21. package/dist/commands/logs/db.js +8 -2
  22. package/dist/commands/logs/index.d.ts +3 -0
  23. package/dist/commands/logs/index.js +8 -2
  24. package/dist/commands/logs/redis.d.ts +3 -0
  25. package/dist/commands/logs/redis.js +8 -2
  26. package/dist/commands/logs/web.d.ts +3 -0
  27. package/dist/commands/logs/web.js +9 -3
  28. package/dist/commands/{db → rebuild}/index.d.ts +2 -1
  29. package/dist/commands/rebuild/index.js +11 -0
  30. package/dist/commands/restart/index.d.ts +3 -0
  31. package/dist/commands/restart/index.js +10 -2
  32. package/dist/commands/shell/api.d.ts +3 -0
  33. package/dist/commands/shell/api.js +9 -3
  34. package/dist/commands/shell/db.d.ts +3 -0
  35. package/dist/commands/shell/db.js +9 -3
  36. package/dist/commands/shell/redis.d.ts +3 -0
  37. package/dist/commands/shell/redis.js +9 -3
  38. package/dist/commands/shell/web.d.ts +3 -0
  39. package/dist/commands/shell/web.js +9 -3
  40. package/dist/commands/{dev → start}/index.d.ts +2 -2
  41. package/dist/commands/start/index.js +111 -0
  42. package/dist/commands/status/index.d.ts +3 -0
  43. package/dist/commands/status/index.js +8 -2
  44. package/dist/commands/stop/index.d.ts +1 -0
  45. package/dist/commands/stop/index.js +9 -1
  46. package/dist/interactive.d.ts +1 -0
  47. package/dist/interactive.js +171 -0
  48. package/dist/templates/env +61 -0
  49. package/dist/utils/docker.js +10 -18
  50. package/dist/utils/env.js +20 -10
  51. package/dist/utils/selection.d.ts +7 -0
  52. package/dist/utils/selection.js +68 -0
  53. package/dist/utils/template.d.ts +11 -0
  54. package/dist/utils/template.js +18 -0
  55. package/oclif.manifest.json +367 -90
  56. package/package.json +30 -25
  57. package/dist/commands/db/index.js +0 -11
  58. package/dist/commands/deploy/index.d.ts +0 -8
  59. package/dist/commands/deploy/index.js +0 -95
  60. package/dist/commands/dev/index.js +0 -59
  61. package/dist/commands/setup/index.d.ts +0 -5
  62. package/dist/commands/setup/index.js +0 -12
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # NodeBBS CLI
2
2
 
3
- > 全栈友好的 NodeBBS 部署和管理命令行工具
3
+ > NodeBBS 论坛系统专业运维工具
4
4
 
5
5
  [![oclif](https://img.shields.io/badge/cli-oclif-brightgreen.svg)](https://oclif.io)
6
6
  [![Version](https://img.shields.io/npm/v/nodebbs.svg)](https://npmjs.org/package/nodebbs)
@@ -11,7 +11,8 @@ NodeBBS CLI 是一个专为全栈开发者设计的命令行工具,用于简
11
11
 
12
12
  ### 特性
13
13
 
14
- - 🚀 **快速启动** - 一键启动开发环境
14
+ - �️ **交互式菜单** - 支持键盘导航的可视化命令选择(新增)
15
+ - �🚀 **快速启动** - 一键启动开发环境
15
16
  - 🎯 **全栈友好** - 命令设计贴近开发者思维
16
17
  - 🔧 **服务级控制** - 可以单独管理每个服务
17
18
  - 📊 **实时日志** - 方便查看各服务日志
@@ -32,44 +33,36 @@ pnpm add -g nodebbs
32
33
  yarn global add nodebbs
33
34
  ```
34
35
 
35
- 或者直接使用 npx(无需安装):
36
+ 或者直接使用 npx(推荐):
36
37
 
37
38
  ```bash
39
+ # 进入交互式菜单(推荐)
40
+ npx nodebbs
41
+
42
+ # 运行特定命令
38
43
  npx nodebbs [command]
39
44
  ```
40
45
 
41
46
  ## 🚀 快速开始
42
47
 
43
- ### 1. 初始化项目
44
-
45
- ```bash
46
- # 首次使用,初始化项目环境
47
- npx nodebbs setup
48
- ```
49
-
50
- 这会创建 `.env` 文件,请编辑该文件并修改:
51
- - `POSTGRES_PASSWORD` - 数据库密码
52
- - `REDIS_PASSWORD` - Redis 密码
53
- - `JWT_SECRET` - JWT 密钥
54
-
55
- ### 2. 启动开发环境
48
+ ### 1. 启动服务
56
49
 
57
50
  ```bash
58
- # 启动所有服务
59
- npx nodebbs dev
51
+ # 启动所有服务(生产模式,包含完整检查)
52
+ npx nodebbs start
60
53
 
61
- # 或者重新构建并启动
62
- npx nodebbs dev --rebuild
54
+ # 重新构建并启动(跳过检查,用于更新)
55
+ npx nodebbs start --build
63
56
  ```
64
57
 
65
- ### 3. 查看服务状态
58
+ ### 2. 查看服务状态
66
59
 
67
60
  ```bash
68
61
  # 查看所有服务状态
69
62
  npx nodebbs status
70
63
  ```
71
64
 
72
- ### 4. 访问应用
65
+ ### 3. 访问应用
73
66
 
74
67
  - **Web 前端**: http://localhost:3100
75
68
  - **API 文档**: http://localhost:7100/docs
@@ -77,61 +70,46 @@ npx nodebbs status
77
70
 
78
71
  ## 📚 命令参考
79
72
 
80
- ### 核心命令
81
-
82
- #### `nodebbs setup`
83
- 初始化项目(首次使用)
73
+ #### `nodebbs start`
74
+ 开始部署
84
75
 
85
76
  ```bash
86
- npx nodebbs setup
87
- ```
88
-
89
- #### `nodebbs dev`
90
- 启动开发环境
91
-
92
- ```bash
93
- # 启动所有服务
94
- npx nodebbs dev
95
-
96
- # 重新构建并启动
97
- npx nodebbs dev --rebuild
98
- npx nodebbs dev -r
77
+ # 交互式启动
78
+ npx nodebbs start
99
79
 
100
80
  # 指定环境启动
101
- npx nodebbs dev -e production
102
- npx nodebbs dev -e lowmem
103
- npx nodebbs dev -e basic
81
+ npx nodebbs start -e production
82
+
83
+ # 重新构建并启动(跳过检查)
84
+ npx nodebbs start --build
104
85
  ```
105
86
 
106
87
  **参数**:
107
88
  - `-e, --env` - 部署环境(production, lowmem, basic)
108
- - `-r, --rebuild` - 重新构建镜像
109
-
110
- #### `nodebbs deploy`
111
- 部署到生产环境
89
+ - `-b, --build` - 重新构建镜像并启动(跳过健康检查和初始化)
112
90
 
113
- ```bash
114
- # 完整部署流程
115
- npx nodebbs deploy
116
-
117
- # 指定环境部署
118
- npx nodebbs deploy -e production
119
- ```
120
-
121
- 包含:
91
+ 启动流程包含:
122
92
  - Docker 环境检查
123
93
  - 环境变量验证
124
94
  - 镜像构建
125
95
  - 服务启动
126
- - 健康检查
127
- - 数据库初始化(可选)
96
+ - 健康检查(默认开启,使用 `--build` 跳过)
97
+ - 数据库初始化(默认开启,使用 `--build` 跳过)
98
+
99
+ #### `nodebbs restart`
100
+ 重启所有服务(不更新镜像,支持环境选择)
101
+
102
+ ```bash
103
+ npx nodebbs restart
104
+ npx nodebbs restart -e production
105
+ ```
128
106
 
129
107
  #### `nodebbs stop`
130
- 停止服务
108
+ 停止服务(支持环境选择)
131
109
 
132
110
  ```bash
133
- # 停止所有服务
134
111
  npx nodebbs stop
112
+ npx nodebbs stop -e production
135
113
 
136
114
  # 停止服务并删除数据卷(危险!)
137
115
  npx nodebbs stop --volumes
@@ -141,27 +119,25 @@ npx nodebbs stop -v
141
119
  **参数**:
142
120
  - `-v, --volumes` - 同时删除数据卷
143
121
 
144
- #### `nodebbs restart`
145
- 重启所有服务
146
-
147
- ```bash
148
- npx nodebbs restart
149
- ```
150
-
151
122
  #### `nodebbs status`
152
123
  查看服务状态
153
124
 
154
125
  ```bash
155
126
  npx nodebbs status
127
+ # 查看指定环境状态
128
+ npx nodebbs status -e production
156
129
  ```
157
130
 
158
131
  ### 日志管理
159
132
 
160
133
  #### `nodebbs logs`
161
- 查看所有服务日志
134
+ 查看服务日志
162
135
 
163
136
  ```bash
137
+ # 查看所有日志
164
138
  npx nodebbs logs
139
+ # 查看指定环境日志
140
+ npx nodebbs logs -e production
165
141
  ```
166
142
 
167
143
  #### `nodebbs logs:api`
@@ -194,11 +170,14 @@ npx nodebbs logs:redis
194
170
 
195
171
  ### Shell 访问
196
172
 
197
- #### `nodebbs shell:api`
198
- 进入 API 容器
173
+ #### `nodebbs shell`
174
+ 进入容器 Shell (支持 api, web, db, redis)
199
175
 
200
176
  ```bash
177
+ # 进入 API 容器
201
178
  npx nodebbs shell:api
179
+ # 进入生产环境 API 容器
180
+ npx nodebbs shell:api -e production
202
181
  ```
203
182
 
204
183
  #### `nodebbs shell:web`
@@ -224,12 +203,7 @@ npx nodebbs shell:redis
224
203
 
225
204
  ### 数据库管理
226
205
 
227
- #### `nodebbs db`
228
- 打开数据库管理界面(Drizzle Studio)
229
206
 
230
- ```bash
231
- npx nodebbs db
232
- ```
233
207
 
234
208
  #### `nodebbs db:generate`
235
209
  生成数据库迁移文件
@@ -266,30 +240,49 @@ npx nodebbs db:seed
266
240
  npx nodebbs db:reset
267
241
  ```
268
242
 
243
+ #### `nodebbs db:backup`
244
+ 备份数据库
245
+
246
+ ```bash
247
+ npx nodebbs db:backup
248
+ npx nodebbs db:backup -o backup.sql
249
+ ```
250
+
251
+ #### `nodebbs clean`
252
+ 清理 Docker 缓存和残留资源
253
+
254
+ ```bash
255
+ # 交互式选择清理项目
256
+ npx nodebbs clean
257
+
258
+ # 自动清理所有(构建缓存、无用镜像、网络)
259
+ npx nodebbs clean -a
260
+
261
+ # 仅清理构建缓存
262
+ npx nodebbs clean --cache
263
+ ```
264
+
269
265
  ## 🎯 使用场景
270
266
 
271
267
  ### 场景 1:新开发者加入项目
272
268
 
273
269
  ```bash
274
- # 1. 初始化项目
275
- npx nodebbs setup
276
-
277
- # 2. 启动开发环境
278
- npx nodebbs dev
270
+ # 1. 启动服务
271
+ npx nodebbs start
279
272
 
280
- # 3. 初始化数据库
273
+ # 2. 初始化数据库
281
274
  npx nodebbs db:push
282
275
  npx nodebbs db:seed
283
276
 
284
- # 4. 查看服务状态
277
+ # 3. 查看服务状态
285
278
  npx nodebbs status
286
279
  ```
287
280
 
288
281
  ### 场景 2:日常开发
289
282
 
290
283
  ```bash
291
- # 启动开发环境
292
- npx nodebbs dev
284
+ # 启动服务
285
+ npx nodebbs start
293
286
 
294
287
  # 查看 API 日志
295
288
  npx nodebbs logs:api
@@ -297,8 +290,7 @@ npx nodebbs logs:api
297
290
  # 进入 API 容器调试
298
291
  npx nodebbs shell:api
299
292
 
300
- # 打开数据库管理
301
- npx nodebbs db
293
+
302
294
 
303
295
  # 重置测试数据
304
296
  npx nodebbs db:reset
@@ -311,7 +303,7 @@ npx nodebbs db:reset
311
303
  npx nodebbs stop
312
304
 
313
305
  # 重新构建并启动
314
- npx nodebbs dev --rebuild
306
+ npx nodebbs start --build
315
307
 
316
308
  # 查看日志确认启动成功
317
309
  npx nodebbs logs
@@ -321,7 +313,7 @@ npx nodebbs logs
321
313
 
322
314
  ```bash
323
315
  # 部署到生产环境
324
- npx nodebbs deploy -e production
316
+ npx nodebbs start -e production
325
317
 
326
318
  # 查看服务状态
327
319
  npx nodebbs status
@@ -336,8 +328,7 @@ npx nodebbs db:migrate
336
328
  ### 场景 5:数据库操作
337
329
 
338
330
  ```bash
339
- # 打开数据库管理界面
340
- npx nodebbs db
331
+
341
332
 
342
333
  # 运行迁移
343
334
  npx nodebbs db:migrate
@@ -355,18 +346,16 @@ npx nodebbs shell:db
355
346
 
356
347
  | Makefile 命令 | NodeBBS CLI 命令 |
357
348
  |--------------|-----------------|
358
- | `make init` | `npx nodebbs setup` |
359
- | `make up` | `npx nodebbs dev` |
360
- | `make build` | `npx nodebbs dev --rebuild` |
361
- | `make rebuild` | `npx nodebbs dev --rebuild` |
362
- | `ENV=prod make rebuild` | `npx nodebbs deploy -e production` |
349
+ | `make up` | `npx nodebbs start` |
350
+ | `make build` | `npx nodebbs start --build` |
351
+ | `make rebuild` | `npx nodebbs start --build` |
352
+ | `ENV=prod make rebuild` | `npx nodebbs start -e production --build` |
363
353
  | `make down` | `npx nodebbs stop` |
364
- | `make restart` | `npx nodebbs restart` |
365
354
  | `make ps` | `npx nodebbs status` |
366
355
  | `make logs` | `npx nodebbs logs` |
367
356
  | `make logs-api` | `npx nodebbs logs:api` |
368
357
  | `make exec-api` | `npx nodebbs shell:api` |
369
- | `make db-studio` | `npx nodebbs db` |
358
+
370
359
  | `make clean-all` | `npx nodebbs stop --volumes` |
371
360
 
372
361
  ## ⚙️ 环境配置
@@ -400,6 +389,18 @@ API_URL=http://localhost:7100
400
389
  CORS_ORIGIN=*
401
390
  ```
402
391
 
392
+ > **提示**:可以使用 `openssl rand -hex 32` 命令生成安全的随机密钥。
393
+
394
+ ### 环境持久化
395
+
396
+ CLI 会自动记住您上次启动的环境:
397
+
398
+ 1. 当您运行 `nodebbs start` 并选择环境(如 `production`)后,CLI 会在当前目录创建 `.nodebbs-env` 文件记录该选择。
399
+ 2. 后续运行 `nodebbs logs`, `nodebbs status` 等命令时,会自动使用该环境,无需再次指定 `-e production`。
400
+ 3. 运行 `nodebbs stop` 成功停止服务后,会自动删除 `.nodebbs-env` 文件。
401
+
402
+ **注意**:如果您需要临时操作其他环境,仍然可以使用 `-e` 参数强制指定,例如 `nodebbs logs -e basic`。
403
+
403
404
  ## 🛠️ 高级用法
404
405
 
405
406
  ### 内置模板
@@ -408,7 +409,7 @@ NodeBBS CLI 内置了 Docker Compose 配置文件,即使项目中没有这些
408
409
 
409
410
  ```bash
410
411
  # 在任何目录运行
411
- npx nodebbs dev
412
+ npx nodebbs start
412
413
  ```
413
414
 
414
415
  CLI 会自动:
@@ -474,7 +475,7 @@ npx nodebbs stop --volumes
474
475
 
475
476
  ```bash
476
477
  # 克隆仓库
477
- git clone https://github.com/nodebbs/nodebbs.git
478
+ git clone https://github.com/aiprojecthub/nodebbs.git
478
479
  cd nodebbs
479
480
 
480
481
  # 安装依赖
@@ -493,26 +494,17 @@ pnpm build
493
494
  # 查看帮助
494
495
  ./bin/run.js --help
495
496
 
496
- # 测试 dev 命令
497
- ./bin/run.js dev --help
497
+ # 测试 start 命令
498
+ ./bin/run.js start --help
498
499
 
499
500
  # 测试 logs 命令
500
501
  ./bin/run.js logs --help
501
502
  ```
502
503
 
503
- ## 🤝 贡献
504
-
505
- 欢迎贡献!请查看 [CONTRIBUTING.md](CONTRIBUTING.md) 了解详情。
506
-
507
- ## 📄 许可证
508
-
509
- MIT License - 详见 [LICENSE](LICENSE) 文件
510
-
511
504
  ## 🔗 相关链接
512
505
 
513
- - [NodeBBS 项目](https://github.com/nodebbs/nodebbs)
514
- - [问题反馈](https://github.com/nodebbs/nodebbs/issues)
515
- - [更新日志](CHANGELOG.md)
506
+ - [NodeBBS 项目](https://github.com/aiprojecthub/nodebbs)
507
+ - [问题反馈](https://github.com/aiprojecthub/nodebbs/issues)
516
508
 
517
509
  ## 💡 提示
518
510
 
package/bin/dev.js CHANGED
@@ -2,4 +2,9 @@
2
2
 
3
3
  import {execute} from '@oclif/core'
4
4
 
5
- await execute({development: true, dir: import.meta.url})
5
+ if (process.argv.length <= 2) {
6
+ const {runInteractive} = await import('../src/interactive.ts')
7
+ await runInteractive(import.meta.url)
8
+ } else {
9
+ await execute({development: true, dir: import.meta.url})
10
+ }
package/bin/run.js CHANGED
@@ -2,4 +2,9 @@
2
2
 
3
3
  import {execute} from '@oclif/core'
4
4
 
5
- await execute({dir: import.meta.url})
5
+ if (process.argv.length <= 2) {
6
+ const {runInteractive} = await import('../dist/interactive.js')
7
+ await runInteractive(import.meta.url)
8
+ } else {
9
+ await execute({dir: import.meta.url})
10
+ }
@@ -0,0 +1,11 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class Clean extends Command {
3
+ static description: string;
4
+ static flags: {
5
+ all: import("@oclif/core/interfaces").BooleanFlag<boolean>;
6
+ cache: import("@oclif/core/interfaces").BooleanFlag<boolean>;
7
+ images: import("@oclif/core/interfaces").BooleanFlag<boolean>;
8
+ force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
9
+ };
10
+ run(): Promise<void>;
11
+ }
@@ -0,0 +1,93 @@
1
+ import { Command, Flags } from '@oclif/core';
2
+ import { checkbox, confirm } from '@inquirer/prompts';
3
+ import { logger } from '../../utils/logger.js';
4
+ import { execa } from 'execa';
5
+ export default class Clean extends Command {
6
+ static description = '清理 Docker 缓存和残留资源';
7
+ static flags = {
8
+ all: Flags.boolean({
9
+ char: 'a',
10
+ description: '清理所有 (构建缓存、无用镜像、网络)',
11
+ default: false,
12
+ }),
13
+ cache: Flags.boolean({
14
+ description: '清理构建缓存',
15
+ default: false,
16
+ }),
17
+ images: Flags.boolean({
18
+ description: '清理无用镜像 (dangling)',
19
+ default: false,
20
+ }),
21
+ force: Flags.boolean({
22
+ char: 'f',
23
+ description: '跳过确认提示',
24
+ default: false,
25
+ }),
26
+ };
27
+ async run() {
28
+ const { flags } = await this.parse(Clean);
29
+ let targets = [];
30
+ // 根据标志确定清理目标
31
+ if (flags.all) {
32
+ targets = ['cache', 'images', 'networks'];
33
+ }
34
+ else {
35
+ if (flags.cache)
36
+ targets.push('cache');
37
+ if (flags.images)
38
+ targets.push('images');
39
+ }
40
+ // 如果未提供标志,进行交互式选择
41
+ if (targets.length === 0) {
42
+ targets = await checkbox({
43
+ message: '请选择要清理的项目:',
44
+ choices: [
45
+ { name: '构建缓存 (Build Cache)', value: 'cache' },
46
+ { name: '无用镜像 (Dangling Images)', value: 'images' },
47
+ { name: '无用网络 (Unused Networks)', value: 'networks' },
48
+ ],
49
+ });
50
+ }
51
+ if (targets.length === 0) {
52
+ logger.info('未选择任何清理项目。');
53
+ return;
54
+ }
55
+ // 确认提示
56
+ if (!flags.force) {
57
+ logger.warning(`即将清理: ${targets.join(', ')}`);
58
+ const confirmed = await confirm({
59
+ message: '确认继续?',
60
+ default: false
61
+ });
62
+ if (!confirmed) {
63
+ logger.info('操作已取消。');
64
+ return;
65
+ }
66
+ }
67
+ // 执行清理
68
+ try {
69
+ if (targets.includes('cache')) {
70
+ logger.info('正在清理构建缓存...');
71
+ await execa('docker', ['builder', 'prune', '-f'], { stdio: 'inherit' });
72
+ logger.success('构建缓存已清理');
73
+ }
74
+ if (targets.includes('images')) {
75
+ logger.info('正在清理无用镜像...');
76
+ await execa('docker', ['image', 'prune', '-f'], { stdio: 'inherit' });
77
+ logger.success('无用镜像已清理');
78
+ }
79
+ if (targets.includes('networks')) {
80
+ logger.info('正在清理无用网络...');
81
+ await execa('docker', ['network', 'prune', '-f'], { stdio: 'inherit' });
82
+ logger.success('无用网络已清理');
83
+ }
84
+ }
85
+ catch (error) {
86
+ logger.error('清理过程中发生错误');
87
+ if (error instanceof Error) {
88
+ logger.error(error.message);
89
+ }
90
+ this.exit(1);
91
+ }
92
+ }
93
+ }
@@ -0,0 +1,9 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class DbBackup extends Command {
3
+ static description: string;
4
+ static flags: {
5
+ env: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
6
+ output: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
7
+ };
8
+ run(): Promise<void>;
9
+ }
@@ -0,0 +1,78 @@
1
+ import { Command, Flags } from '@oclif/core';
2
+ import { getComposeFiles } from '../../utils/docker.js';
3
+ import { logger } from '../../utils/logger.js';
4
+ import { execa } from 'execa';
5
+ import fs from 'node:fs';
6
+ import path from 'node:path';
7
+ import dotenv from 'dotenv';
8
+ import { EnvFlag, selectEnvironment } from '../../utils/selection.js';
9
+ export default class DbBackup extends Command {
10
+ static description = '备份数据库 (PostgreSQL)';
11
+ static flags = {
12
+ env: EnvFlag,
13
+ output: Flags.string({
14
+ char: 'o',
15
+ description: '输出文件路径',
16
+ }),
17
+ };
18
+ async run() {
19
+ const { flags } = await this.parse(DbBackup);
20
+ // 1. 选择环境
21
+ const env = await selectEnvironment(flags.env);
22
+ // 2. 确定输出文件
23
+ let outputFile = flags.output;
24
+ if (!outputFile) {
25
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
26
+ outputFile = `backup_${timestamp}.sql`;
27
+ }
28
+ // 确保绝对路径
29
+ const outputPath = path.resolve(process.cwd(), outputFile);
30
+ // 3. 获取 Compose 文件
31
+ const { files, isBuiltIn } = await getComposeFiles(env);
32
+ logger.info(`正在备份数据库到: ${outputPath}`);
33
+ logger.info('环境: ' + env);
34
+ // 加载环境配置
35
+ const envConfig = dotenv.config().parsed || {};
36
+ const dbUser = envConfig.POSTGRES_USER || 'postgres';
37
+ const dbName = envConfig.POSTGRES_DB || 'nodebbs';
38
+ const dbPassword = envConfig.POSTGRES_PASSWORD;
39
+ // 4. 构建 Compose 参数
40
+ const composeArgs = files.flatMap(f => ['-f', f]);
41
+ if (isBuiltIn) {
42
+ composeArgs.push('--project-directory', process.cwd());
43
+ }
44
+ // 5. 运行 pg_dump
45
+ const dumpArgs = [...composeArgs, 'exec', '-T'];
46
+ // 如果有密码则注入
47
+ if (dbPassword) {
48
+ dumpArgs.push('-e', `PGPASSWORD=${dbPassword}`);
49
+ }
50
+ dumpArgs.push('postgres', 'pg_dump', '-U', dbUser, dbName);
51
+ try {
52
+ const subprocess = execa('docker', ['compose', ...dumpArgs]);
53
+ if (subprocess.stdout) {
54
+ subprocess.stdout.pipe(fs.createWriteStream(outputPath));
55
+ }
56
+ await subprocess;
57
+ // 检查文件大小
58
+ const stats = fs.statSync(outputPath);
59
+ if (stats.size === 0) {
60
+ logger.error('备份文件为空,备份可能失败。');
61
+ }
62
+ else {
63
+ logger.success(`数据库备份成功!文件大小: ${(stats.size / 1024 / 1024).toFixed(2)} MB`);
64
+ }
65
+ }
66
+ catch (error) {
67
+ logger.error('数据库备份失败');
68
+ if (error instanceof Error) {
69
+ logger.error(error.message);
70
+ }
71
+ // 如果失败则清理空文件
72
+ if (fs.existsSync(outputPath) && fs.statSync(outputPath).size === 0) {
73
+ fs.unlinkSync(outputPath);
74
+ }
75
+ this.exit(1);
76
+ }
77
+ }
78
+ }
@@ -1,5 +1,8 @@
1
1
  import { Command } from '@oclif/core';
2
2
  export default class DbGenerate extends Command {
3
3
  static description: string;
4
+ static flags: {
5
+ env: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
6
+ };
4
7
  run(): Promise<void>;
5
8
  }
@@ -1,11 +1,17 @@
1
1
  import { Command } from '@oclif/core';
2
2
  import { execCompose, getComposeFiles } from '../../utils/docker.js';
3
3
  import { logger } from '../../utils/logger.js';
4
+ import { EnvFlag, selectEnvironment } from '../../utils/selection.js';
4
5
  export default class DbGenerate extends Command {
5
- static description = '生成数据库迁移文件';
6
+ static description = '生成 Prisma Client (db:generate)';
7
+ static flags = {
8
+ env: EnvFlag,
9
+ };
6
10
  async run() {
7
- const { files, isBuiltIn } = await getComposeFiles('basic');
8
- logger.info('正在生成数据库迁移...');
11
+ const { flags } = await this.parse(DbGenerate);
12
+ const env = await selectEnvironment(flags.env);
13
+ const { files, isBuiltIn } = await getComposeFiles(env);
14
+ logger.info('正在生成 Prisma Client...');
9
15
  await execCompose(files, 'api', ['npm', 'run', 'db:generate'], isBuiltIn);
10
16
  logger.success('数据库迁移文件生成完成');
11
17
  }
@@ -1,5 +1,8 @@
1
1
  import { Command } from '@oclif/core';
2
2
  export default class DbMigrate extends Command {
3
3
  static description: string;
4
+ static flags: {
5
+ env: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
6
+ };
4
7
  run(): Promise<void>;
5
8
  }
@@ -1,10 +1,16 @@
1
1
  import { Command } from '@oclif/core';
2
2
  import { execCompose, getComposeFiles } from '../../utils/docker.js';
3
3
  import { logger } from '../../utils/logger.js';
4
+ import { EnvFlag, selectEnvironment } from '../../utils/selection.js';
4
5
  export default class DbMigrate extends Command {
5
- static description = '执行数据库迁移';
6
+ static description = '执行数据库迁移 (db:migrate)';
7
+ static flags = {
8
+ env: EnvFlag,
9
+ };
6
10
  async run() {
7
- const { files, isBuiltIn } = await getComposeFiles('basic');
11
+ const { flags } = await this.parse(DbMigrate);
12
+ const env = await selectEnvironment(flags.env);
13
+ const { files, isBuiltIn } = await getComposeFiles(env);
8
14
  logger.info('正在执行数据库迁移...');
9
15
  await execCompose(files, 'api', ['npm', 'run', 'db:migrate'], isBuiltIn);
10
16
  logger.success('数据库迁移完成');