xuanwu-cli 1.0.0 → 2.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/README.md +138 -88
- package/dist/api/client.d.ts +25 -1
- package/dist/api/client.js +92 -0
- package/dist/commands/app.d.ts +5 -0
- package/dist/commands/app.js +241 -0
- package/dist/commands/build.js +74 -17
- package/dist/commands/svc.d.ts +1 -1
- package/dist/commands/svc.js +219 -24
- package/dist/config/types.d.ts +92 -0
- package/dist/index.js +5 -116
- package/package.json +3 -2
- package/src/api/client.ts +111 -1
- package/src/commands/app.ts +269 -0
- package/src/commands/build.ts +78 -18
- package/src/commands/svc.ts +266 -25
- package/src/config/types.ts +105 -0
- package/src/index.ts +5 -97
- package/test/REPORT.md +78 -0
- package/test/integration.js +299 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# xuanwu-cli
|
|
2
2
|
|
|
3
|
-
玄武工厂平台 CLI 工具
|
|
3
|
+
玄武工厂平台 CLI 工具 (v2.0)
|
|
4
4
|
|
|
5
5
|
## 快速开始
|
|
6
6
|
|
|
@@ -20,152 +20,202 @@ npm run build
|
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
22
|
# 添加连接
|
|
23
|
-
|
|
23
|
+
xw connect add prod \
|
|
24
24
|
--endpoint http://localhost:3000 \
|
|
25
25
|
--token <your-api-token>
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
## 命令概览
|
|
29
29
|
|
|
30
|
-
```
|
|
31
|
-
|
|
30
|
+
```
|
|
31
|
+
xw <resource> <action> [args] [flags]
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
###
|
|
34
|
+
### 资源命令
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
| 命令 | 说明 |
|
|
37
|
+
|------|------|
|
|
38
|
+
| `xw connect` | 管理连接 |
|
|
39
|
+
| `xw env` | 环境管理 (K8s namespace) |
|
|
40
|
+
| `xw app` | 应用管理 (Application) |
|
|
41
|
+
| `xw svc` | 服务管理 (K8s Deployment/Service) |
|
|
42
|
+
| `xw build` | 构建管理 |
|
|
43
|
+
| `xw deploy` | 部署服务 |
|
|
44
|
+
| `xw scale` | 扩缩容 |
|
|
45
|
+
| `xw logs` | 查看日志 |
|
|
46
|
+
| `xw pods` | Pod 列表 |
|
|
39
47
|
|
|
40
|
-
##
|
|
48
|
+
## 应用命令 (xw app)
|
|
41
49
|
|
|
42
|
-
|
|
50
|
+
使用 `code` 作为唯一标识符管理应用。
|
|
43
51
|
|
|
44
52
|
```bash
|
|
45
|
-
|
|
46
|
-
|
|
53
|
+
# 列出应用
|
|
54
|
+
xw app list
|
|
55
|
+
xw app ls
|
|
47
56
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
- ✅ CLI 编译和执行
|
|
52
|
-
- ✅ 用户认证(注册、登录)
|
|
53
|
-
- ✅ 环境管理(列出、创建)
|
|
54
|
-
- ✅ 服务管理(列出、查询)
|
|
55
|
-
- ✅ 所有 CLI 命令
|
|
57
|
+
# 查看应用
|
|
58
|
+
xw app get <code>
|
|
59
|
+
xw app describe <code>
|
|
56
60
|
|
|
57
|
-
|
|
61
|
+
# 创建应用
|
|
62
|
+
xw app create -n "用户服务" -c user-service --git https://github.com/example/user-service.git
|
|
58
63
|
|
|
59
|
-
|
|
60
|
-
|
|
64
|
+
# 更新应用
|
|
65
|
+
xw app update <code> --name "新名称"
|
|
61
66
|
|
|
62
|
-
|
|
67
|
+
# 删除应用
|
|
68
|
+
xw app delete <code>
|
|
69
|
+
xw app rm <code>
|
|
63
70
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
- 服务管理 API
|
|
67
|
-
- K8s 查询 API
|
|
68
|
-
- 扩缩容 API
|
|
69
|
-
- 用户认证 API
|
|
71
|
+
# 触发构建
|
|
72
|
+
xw app build <code> [--branch <name>]
|
|
70
73
|
|
|
71
|
-
|
|
74
|
+
# 查看构建列表
|
|
75
|
+
xw app builds <code> [--status SUCCESS|FAILED]
|
|
76
|
+
```
|
|
72
77
|
|
|
73
|
-
##
|
|
78
|
+
## 服务命令 (xw svc)
|
|
74
79
|
|
|
75
|
-
|
|
80
|
+
使用 `namespace/name` 格式管理 K8s 服务。
|
|
76
81
|
|
|
77
|
-
|
|
82
|
+
```bash
|
|
83
|
+
# 列出服务
|
|
84
|
+
xw svc list --env <namespace>
|
|
85
|
+
xw svc ls
|
|
78
86
|
|
|
79
|
-
|
|
87
|
+
# 查看服务
|
|
88
|
+
xw svc get <namespace>/<name>
|
|
80
89
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
curl -X POST http://localhost:3000/api/auth/login \
|
|
84
|
-
-H "Content-Type: application/json" \
|
|
85
|
-
-d '{"email": "your@email.com", "password": "password"}'
|
|
90
|
+
# 服务状态
|
|
91
|
+
xw svc status <namespace>/<name>
|
|
86
92
|
|
|
87
|
-
#
|
|
88
|
-
|
|
89
|
-
-H "Authorization: Bearer <jwt-token>" \
|
|
90
|
-
-H "Content-Type: application/json" \
|
|
91
|
-
-d '{"name": "cli-token"}'
|
|
92
|
-
```
|
|
93
|
+
# 查看日志
|
|
94
|
+
xw svc logs <namespace>/<name> [-f] [--tail 100]
|
|
93
95
|
|
|
94
|
-
|
|
96
|
+
# 重启服务
|
|
97
|
+
xw svc restart <namespace>/<name>
|
|
98
|
+
|
|
99
|
+
# 扩缩容
|
|
100
|
+
xw svc scale <namespace>/<name> --replicas 3
|
|
95
101
|
|
|
96
|
-
|
|
102
|
+
# 进入容器
|
|
103
|
+
xw svc exec <namespace>/<name> -it -- bash
|
|
104
|
+
|
|
105
|
+
# 列出 Pods
|
|
106
|
+
xw svc pods <namespace>/<name>
|
|
107
|
+
|
|
108
|
+
# 删除服务
|
|
109
|
+
xw svc delete <namespace>/<name>
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## 构建命令 (xw build)
|
|
97
113
|
|
|
98
114
|
```bash
|
|
99
|
-
|
|
115
|
+
# 列出构建
|
|
116
|
+
xw build list --app <code>
|
|
117
|
+
xw build ls
|
|
118
|
+
|
|
119
|
+
# 查看构建
|
|
120
|
+
xw build get <id>
|
|
121
|
+
|
|
122
|
+
# 取消构建
|
|
123
|
+
xw build cancel <id>
|
|
100
124
|
```
|
|
101
125
|
|
|
102
|
-
|
|
126
|
+
## 环境命令 (xw env)
|
|
103
127
|
|
|
104
128
|
```bash
|
|
105
129
|
# 列出环境
|
|
106
|
-
|
|
130
|
+
xw env ls
|
|
107
131
|
|
|
108
132
|
# 创建环境
|
|
109
|
-
|
|
133
|
+
xw env create <namespace>
|
|
134
|
+
|
|
135
|
+
# 删除环境
|
|
136
|
+
xw env rm <namespace>
|
|
137
|
+
|
|
138
|
+
# 环境详情
|
|
139
|
+
xw env info <namespace>
|
|
110
140
|
```
|
|
111
141
|
|
|
112
|
-
|
|
142
|
+
## 部署命令 (xw deploy)
|
|
113
143
|
|
|
114
144
|
```bash
|
|
115
145
|
# 部署镜像
|
|
116
|
-
|
|
146
|
+
xw deploy <namespace> <service> --type image --image nginx:latest
|
|
117
147
|
|
|
118
148
|
# 部署数据库
|
|
119
|
-
|
|
149
|
+
xw deploy <namespace> <service> --type database --db-type mysql
|
|
120
150
|
|
|
121
|
-
#
|
|
122
|
-
|
|
123
|
-
--git https-dev api://gitlab.com/user/repo.git \
|
|
124
|
-
--git-branch main \
|
|
125
|
-
--build-type template \
|
|
126
|
-
--language java-springboot
|
|
151
|
+
# 部署应用
|
|
152
|
+
xw deploy <namespace> <service> --type application --git https://...
|
|
127
153
|
```
|
|
128
154
|
|
|
129
|
-
|
|
155
|
+
## 获取 API Token
|
|
130
156
|
|
|
131
|
-
|
|
132
|
-
# 列出服务
|
|
133
|
-
xuanwu svc ls shop-dev
|
|
157
|
+
### 方法1: 注册新用户
|
|
134
158
|
|
|
135
|
-
|
|
136
|
-
|
|
159
|
+
```bash
|
|
160
|
+
curl -X POST http://localhost:3000/api/auth/register \
|
|
161
|
+
-H "Content-Type: application/json" \
|
|
162
|
+
-d '{"email": "your@email.com", "password": "password", "name": "Your Name"}'
|
|
137
163
|
```
|
|
138
164
|
|
|
139
|
-
###
|
|
165
|
+
### 方法2: 登录
|
|
140
166
|
|
|
141
167
|
```bash
|
|
142
|
-
|
|
143
|
-
|
|
168
|
+
curl -X POST http://localhost:3000/api/auth/login \
|
|
169
|
+
-H "Content-Type: application/json" \
|
|
170
|
+
-d '{"email": "your@email.com", "password": "password"}'
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## 集成测试
|
|
144
174
|
|
|
145
|
-
|
|
146
|
-
xuanwu logs shop-dev nginx -f
|
|
175
|
+
运行集成测试验证 API 功能:
|
|
147
176
|
|
|
148
|
-
|
|
149
|
-
|
|
177
|
+
```bash
|
|
178
|
+
# 设置环境变量
|
|
179
|
+
export XW_TOKEN="your-jwt-token"
|
|
180
|
+
export XW_ENDPOINT="http://localhost:3000"
|
|
181
|
+
|
|
182
|
+
# 运行测试
|
|
183
|
+
node test/integration.js
|
|
150
184
|
```
|
|
151
185
|
|
|
152
|
-
|
|
186
|
+
### 测试结果
|
|
153
187
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
188
|
+
```
|
|
189
|
+
============================================================
|
|
190
|
+
📊 测试报告 - CLI API v2.0
|
|
191
|
+
============================================================
|
|
192
|
+
总测试数: 17
|
|
193
|
+
通过: 17 ✅
|
|
194
|
+
失败: 0 ❌
|
|
195
|
+
通过率: 100.0%
|
|
196
|
+
============================================================
|
|
197
|
+
```
|
|
164
198
|
|
|
165
199
|
## 输出格式
|
|
166
200
|
|
|
167
|
-
|
|
201
|
+
默认输出人类可读格式:
|
|
168
202
|
|
|
169
203
|
```bash
|
|
170
|
-
|
|
204
|
+
xw app list
|
|
171
205
|
```
|
|
206
|
+
|
|
207
|
+
JSON 格式(需要程序化处理时使用):
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
xw app list -o json
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## 版本历史
|
|
214
|
+
|
|
215
|
+
- **v2.0** - 基于新的 API v2.0 重构
|
|
216
|
+
- 使用 `code` 作为应用唯一标识
|
|
217
|
+
- 服务操作使用 `namespace/name` 格式
|
|
218
|
+
- 新增 `xw app` 命令
|
|
219
|
+
- 17/17 集成测试通过
|
|
220
|
+
|
|
221
|
+
- **v1.0** - 初始版本
|
package/dist/api/client.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* API 客户端
|
|
3
3
|
*/
|
|
4
|
-
import { Connection, CLIResult, ServiceInfo, NamespaceInfo, DeployOptions } from '../config/types';
|
|
4
|
+
import { Connection, CLIResult, ServiceInfo, NamespaceInfo, DeployOptions, Application, Build, CreateApplicationDto, UpdateApplicationDto, TriggerBuildOptions } from '../config/types';
|
|
5
5
|
export declare class APIClient {
|
|
6
6
|
private client;
|
|
7
7
|
constructor(connection: Connection);
|
|
@@ -11,6 +11,8 @@ export declare class APIClient {
|
|
|
11
11
|
deleteNamespace(id: string): Promise<CLIResult<void>>;
|
|
12
12
|
getNamespaceInfo(identifier: string): Promise<CLIResult<any>>;
|
|
13
13
|
getProjects(): Promise<CLIResult<any[]>>;
|
|
14
|
+
createProject(name: string, description?: string): Promise<CLIResult<any>>;
|
|
15
|
+
deleteProject(projectId: string): Promise<CLIResult<void>>;
|
|
14
16
|
createNamespaceWithProject(name: string, projectId: string, environment?: string): Promise<CLIResult<any>>;
|
|
15
17
|
listServices(namespace: string): Promise<CLIResult<ServiceInfo[]>>;
|
|
16
18
|
getServiceStatus(namespace: string, name: string): Promise<CLIResult<any>>;
|
|
@@ -26,5 +28,27 @@ export declare class APIClient {
|
|
|
26
28
|
listPods(namespace: string, serviceName: string): Promise<CLIResult<any>>;
|
|
27
29
|
getMetrics(namespace: string, serviceName: string, podName?: string): Promise<CLIResult<any>>;
|
|
28
30
|
exec(namespace: string, serviceName: string, command: string, podName?: string): Promise<CLIResult<any>>;
|
|
31
|
+
listApplications(): Promise<CLIResult<Application[]>>;
|
|
32
|
+
getApplication(code: string): Promise<CLIResult<Application>>;
|
|
33
|
+
createApplication(dto: CreateApplicationDto): Promise<CLIResult<Application>>;
|
|
34
|
+
updateApplication(code: string, dto: UpdateApplicationDto): Promise<CLIResult<Application>>;
|
|
35
|
+
deleteApplication(code: string): Promise<CLIResult<void>>;
|
|
36
|
+
triggerApplicationBuild(code: string, options?: TriggerBuildOptions): Promise<CLIResult<Build>>;
|
|
37
|
+
listApplicationBuilds(code: string): Promise<CLIResult<Build[]>>;
|
|
38
|
+
listK8sServices(namespace?: string): Promise<CLIResult<any>>;
|
|
39
|
+
getK8sService(namespace: string, name: string): Promise<CLIResult<any>>;
|
|
40
|
+
getK8sServiceStatus(namespace: string, name: string): Promise<CLIResult<any>>;
|
|
41
|
+
getK8sServiceLogs(namespace: string, name: string, lines?: number, follow?: boolean): Promise<CLIResult<any>>;
|
|
42
|
+
restartK8sService(namespace: string, name: string): Promise<CLIResult<any>>;
|
|
43
|
+
scaleK8sService(namespace: string, name: string, replicas: number): Promise<CLIResult<any>>;
|
|
44
|
+
execK8sService(namespace: string, name: string, command: string, podName?: string): Promise<CLIResult<any>>;
|
|
45
|
+
listK8sServicePods(namespace: string, name: string): Promise<CLIResult<any>>;
|
|
46
|
+
deleteK8sService(namespace: string, name: string): Promise<CLIResult<void>>;
|
|
47
|
+
listBuilds(options?: {
|
|
48
|
+
appCode?: string;
|
|
49
|
+
status?: string;
|
|
50
|
+
}): Promise<CLIResult<Build[]>>;
|
|
51
|
+
getBuild(id: string): Promise<CLIResult<Build>>;
|
|
52
|
+
cancelBuild(id: string): Promise<CLIResult<void>>;
|
|
29
53
|
}
|
|
30
54
|
export declare function createClient(connection: Connection): APIClient;
|
package/dist/api/client.js
CHANGED
|
@@ -79,6 +79,15 @@ class APIClient {
|
|
|
79
79
|
async getProjects() {
|
|
80
80
|
return this.request('GET', '/api/projects');
|
|
81
81
|
}
|
|
82
|
+
async createProject(name, description) {
|
|
83
|
+
return this.request('POST', '/api/projects', {
|
|
84
|
+
name,
|
|
85
|
+
description: description || ''
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
async deleteProject(projectId) {
|
|
89
|
+
return this.request('DELETE', `/api/projects/${projectId}`);
|
|
90
|
+
}
|
|
82
91
|
async createNamespaceWithProject(name, projectId, environment = 'development') {
|
|
83
92
|
return this.request('POST', '/api/deploy-spaces', {
|
|
84
93
|
name,
|
|
@@ -325,6 +334,89 @@ class APIClient {
|
|
|
325
334
|
command
|
|
326
335
|
});
|
|
327
336
|
}
|
|
337
|
+
// ===================
|
|
338
|
+
// Application (CLI API - using code)
|
|
339
|
+
// ===================
|
|
340
|
+
async listApplications() {
|
|
341
|
+
return this.request('GET', '/api/cli/apps');
|
|
342
|
+
}
|
|
343
|
+
async getApplication(code) {
|
|
344
|
+
return this.request('GET', `/api/cli/apps/${code}`);
|
|
345
|
+
}
|
|
346
|
+
async createApplication(dto) {
|
|
347
|
+
return this.request('POST', '/api/applications', dto);
|
|
348
|
+
}
|
|
349
|
+
async updateApplication(code, dto) {
|
|
350
|
+
return this.request('PUT', `/api/cli/apps/${code}`, dto);
|
|
351
|
+
}
|
|
352
|
+
async deleteApplication(code) {
|
|
353
|
+
return this.request('DELETE', `/api/cli/apps/${code}`);
|
|
354
|
+
}
|
|
355
|
+
async triggerApplicationBuild(code, options) {
|
|
356
|
+
return this.request('POST', `/api/cli/apps/${code}/build`, options);
|
|
357
|
+
}
|
|
358
|
+
async listApplicationBuilds(code) {
|
|
359
|
+
return this.request('GET', `/api/cli/apps/${code}/builds`);
|
|
360
|
+
}
|
|
361
|
+
// ===================
|
|
362
|
+
// Service (CLI API - using ns/name)
|
|
363
|
+
// ===================
|
|
364
|
+
async listK8sServices(namespace) {
|
|
365
|
+
const url = namespace ? `/api/cli/services?namespace=${namespace}` : '/api/cli/services';
|
|
366
|
+
return this.request('GET', url);
|
|
367
|
+
}
|
|
368
|
+
async getK8sService(namespace, name) {
|
|
369
|
+
return this.request('GET', `/api/cli/services/${namespace}/${name}`);
|
|
370
|
+
}
|
|
371
|
+
async getK8sServiceStatus(namespace, name) {
|
|
372
|
+
return this.request('GET', `/api/cli/services/${namespace}/${name}/status`);
|
|
373
|
+
}
|
|
374
|
+
async getK8sServiceLogs(namespace, name, lines, follow) {
|
|
375
|
+
let url = `/api/cli/services/${namespace}/${name}/logs`;
|
|
376
|
+
const params = [];
|
|
377
|
+
if (lines)
|
|
378
|
+
params.push(`lines=${lines}`);
|
|
379
|
+
if (follow)
|
|
380
|
+
params.push(`follow=true`);
|
|
381
|
+
if (params.length > 0)
|
|
382
|
+
url += '?' + params.join('&');
|
|
383
|
+
return this.request('GET', url);
|
|
384
|
+
}
|
|
385
|
+
async restartK8sService(namespace, name) {
|
|
386
|
+
return this.request('POST', `/api/cli/services/${namespace}/${name}/restart`);
|
|
387
|
+
}
|
|
388
|
+
async scaleK8sService(namespace, name, replicas) {
|
|
389
|
+
return this.request('POST', `/api/cli/services/${namespace}/${name}/scale`, { replicas });
|
|
390
|
+
}
|
|
391
|
+
async execK8sService(namespace, name, command, podName) {
|
|
392
|
+
return this.request('POST', `/api/cli/services/${namespace}/${name}/exec`, { command, podName });
|
|
393
|
+
}
|
|
394
|
+
async listK8sServicePods(namespace, name) {
|
|
395
|
+
return this.request('GET', `/api/cli/services/${namespace}/${name}/pods`);
|
|
396
|
+
}
|
|
397
|
+
async deleteK8sService(namespace, name) {
|
|
398
|
+
return this.request('DELETE', `/api/cli/services/${namespace}/${name}`);
|
|
399
|
+
}
|
|
400
|
+
// ===================
|
|
401
|
+
// Build (CLI API)
|
|
402
|
+
// ===================
|
|
403
|
+
async listBuilds(options) {
|
|
404
|
+
let url = '/api/cli/builds';
|
|
405
|
+
const params = [];
|
|
406
|
+
if (options?.appCode)
|
|
407
|
+
params.push(`appCode=${options.appCode}`);
|
|
408
|
+
if (options?.status)
|
|
409
|
+
params.push(`status=${options.status}`);
|
|
410
|
+
if (params.length > 0)
|
|
411
|
+
url += '?' + params.join('&');
|
|
412
|
+
return this.request('GET', url);
|
|
413
|
+
}
|
|
414
|
+
async getBuild(id) {
|
|
415
|
+
return this.request('GET', `/api/cli/builds/${id}`);
|
|
416
|
+
}
|
|
417
|
+
async cancelBuild(id) {
|
|
418
|
+
return this.request('POST', `/api/cli/builds/${id}/cancel`);
|
|
419
|
+
}
|
|
328
420
|
}
|
|
329
421
|
exports.APIClient = APIClient;
|
|
330
422
|
function createClient(connection) {
|