@wxuns/zp-cli 0.0.1

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.
@@ -0,0 +1,51 @@
1
+ name: Publish to npm
2
+
3
+ on:
4
+ # 推送版本标签时触发 (例如 v1.0.0, v1.1.0)
5
+ push:
6
+ tags:
7
+ - 'v*'
8
+
9
+ # 也可以手动触发
10
+ workflow_dispatch:
11
+
12
+ jobs:
13
+ publish:
14
+ runs-on: ubuntu-latest
15
+
16
+ steps:
17
+ # 1. 检出代码
18
+ - name: Checkout code
19
+ uses: actions/checkout@v4
20
+
21
+ # 2. 设置 Node.js 环境
22
+ - name: Setup Node.js
23
+ uses: actions/setup-node@v4
24
+ with:
25
+ node-version: '18'
26
+ registry-url: 'https://registry.npmjs.org'
27
+
28
+ # 3. 安装依赖
29
+ - name: Install dependencies
30
+ run: npm install
31
+
32
+ # 4. 运行测试 (如果有)
33
+ # - name: Run tests
34
+ # run: npm test
35
+
36
+ # 5. 发布到 npm
37
+ - name: Publish to npm
38
+ run: npm publish --access public
39
+ env:
40
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
41
+
42
+ # 6. 创建 GitHub Release (可选)
43
+ - name: Create GitHub Release
44
+ uses: actions/create-release@v1
45
+ env:
46
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
47
+ with:
48
+ tag_name: ${{ github.ref }}
49
+ release_name: Release ${{ github.ref }}
50
+ draft: false
51
+ prerelease: false
package/DEBUG.md ADDED
@@ -0,0 +1,129 @@
1
+ # zp-cli 本地调试指南
2
+
3
+ ## npm link 全局链接
4
+
5
+ 将本地项目链接到全局,使 `zp-cli` 命令直接指向本地代码,修改代码后立即生效。
6
+
7
+ ### 链接
8
+
9
+ ```bash
10
+ cd D:/epg/codes/zp-cli
11
+ npm link
12
+ ```
13
+
14
+ 执行后 `zp-cli` 命令将指向当前目录,可以直接使用:
15
+
16
+ ```bash
17
+ zp-cli --help
18
+ zp-cli init
19
+ zp-cli upload ./some-file --server <服务器别名> --remote-path /tmp/test
20
+ ```
21
+
22
+ ### 取消链接
23
+
24
+ ```bash
25
+ cd D:/epg/codes/zp-cli
26
+ npm unlink -g zp-cli
27
+ ```
28
+
29
+ 或直接全局卸载:
30
+
31
+ ```bash
32
+ npm uninstall -g zp-cli
33
+ ```
34
+
35
+ ### 验证链接状态
36
+
37
+ ```bash
38
+ # 查看 zp-cli 命令指向的路径
39
+ which zp-cli
40
+
41
+ # 应输出类似:
42
+ # /c/Users/<用户名>/AppData/Roaming/npm/zp-cli -> /d/epg/codes/zp-cli/bin/zp-cli.js
43
+ ```
44
+
45
+ ---
46
+
47
+ ## 调试流程
48
+
49
+ ### 1. 基础命令测试
50
+
51
+ ```bash
52
+ # 帮助信息
53
+ zp-cli --help
54
+ zp-cli upload --help
55
+ zp-cli init --help
56
+
57
+ # 版本
58
+ zp-cli -v
59
+
60
+ # 配置路径
61
+ zp-cli config path
62
+
63
+ # 查看配置
64
+ zp-cli config show
65
+ ```
66
+
67
+ ### 2. 初始化配置
68
+
69
+ ```bash
70
+ # 生成 demo 配置
71
+ zp-cli init
72
+
73
+ # 编辑配置文件,填入真实的服务器信息
74
+ notepad %USERPROFILE%\.zp-cli.json
75
+ ```
76
+
77
+ ### 3. 上传测试
78
+
79
+ ```bash
80
+ # 指定服务器和远程路径(跳过 Git 匹配)
81
+ zp-cli upload ./test.txt --server <服务器别名> --remote-path /tmp/test.txt
82
+
83
+ # 上传目录
84
+ zp-cli upload ./dist --server <服务器别名> --remote-path /tmp/dist
85
+
86
+ # 在 Git 仓库内,自动匹配(需要先配好 mappings)
87
+ zp-cli upload ./vue_zte3.0/dist
88
+ ```
89
+
90
+ ### 4. 查看部署结果
91
+
92
+ ```bash
93
+ # 登录服务器验证(根据实际配置替换信息)
94
+ ssh <用户名>@<服务器地址> "ls -la /tmp/"
95
+ ```
96
+
97
+ ---
98
+
99
+ ## 常见问题
100
+
101
+ ### 命令找不到
102
+
103
+ ```bash
104
+ # 检查 npm 全局 bin 目录是否在 PATH 中
105
+ npm config get prefix
106
+
107
+ # Windows 下通常在:
108
+ # C:\Users\<用户名>\AppData\Roaming\npm
109
+ ```
110
+
111
+ ### 修改代码后不生效
112
+
113
+ npm link 后修改代码会立即生效,无需重新 link。如果出现缓存问题:
114
+
115
+ ```bash
116
+ # 重新 link
117
+ npm unlink -g zp-cli
118
+ npm link
119
+ ```
120
+
121
+ ### 权限问题(Linux/Mac)
122
+
123
+ ```bash
124
+ sudo npm link
125
+ ```
126
+
127
+ ### Windows 上 tar 命令报错
128
+
129
+ 确保使用 Git Bash 终端运行,Git Bash 自带 tar 命令。或安装 WSL。
package/README.md ADDED
@@ -0,0 +1,289 @@
1
+ # zp-cli
2
+
3
+ 将本地代码通过 SSH 部署到远程服务器的命令行工具。支持单文件/目录上传,支持同一仓库不同子目录部署到不同服务器。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ npm install -g @wxuns/zp-cli
9
+ ```
10
+
11
+ ## 快速开始
12
+
13
+ ```bash
14
+ # 1. 生成配置文件模板
15
+ zp-cli init
16
+
17
+ # 2. 编辑配置文件,填入你的服务器信息
18
+ # Windows: notepad %USERPROFILE%\.zp-cli.json
19
+ # Linux/Mac: vim ~/.zp-cli.json
20
+
21
+ # 3. 上传文件
22
+ zp-cli upload ./dist/index.html
23
+ zp-cli upload ./dist
24
+ ```
25
+
26
+ ---
27
+
28
+ ## 命令一览
29
+
30
+ | 命令 | 说明 |
31
+ |------|------|
32
+ | `zp-cli init` | 生成 demo 配置文件 `~/.zp-cli.json` |
33
+ | `zp-cli upload <路径>` | 上传文件或目录到远程服务器 |
34
+ | `zp-cli config show` | 查看当前配置内容 |
35
+ | `zp-cli config path` | 显示配置文件路径 |
36
+ | `zp-cli --help` | 查看帮助 |
37
+ | `zp-cli -v` | 查看版本 |
38
+
39
+ ### upload 命令选项
40
+
41
+ ```bash
42
+ zp-cli upload <路径> [选项]
43
+
44
+ 选项:
45
+ -s, --server <别名> 指定目标服务器(覆盖自动匹配)
46
+ -r, --remote-path <路径> 指定远程目标路径(覆盖配置中的默认值)
47
+ ```
48
+
49
+ ---
50
+
51
+ ## 配置文件说明
52
+
53
+ 配置文件路径:`~/.zp-cli.json`(Windows 下为 `%USERPROFILE%\.zp-cli.json`)
54
+
55
+ 执行 `zp-cli init` 会生成如下 demo 配置:
56
+
57
+ ```jsonc
58
+ {
59
+ "servers": [
60
+ {
61
+ "alias": "test-server", // 服务器别名,命令行中用于指定目标
62
+ "host": "192.168.1.100", // 服务器 IP 或域名
63
+ "port": 22, // SSH 端口,默认 22
64
+ "username": "root", // SSH 登录用户名
65
+ "password": "your-password", // 密码认证(与 privateKeyPath 二选一)
66
+ "privateKeyPath": "~/.ssh/id_rsa",// 私钥认证(与 password 二选一)
67
+ "defaultRemotePath": "/home/www", // 默认远程目录(可被 --remote-path 覆盖)
68
+ "rootPassword": "" // root 密码,需要 su root 时填写
69
+ }
70
+ ],
71
+
72
+ "mappings": [
73
+ {
74
+ "gitRemoteUrl": "git@github.com:yourorg/project.git",
75
+ "serverAlias": "test-server",
76
+ "remotePath": "/var/www/project",
77
+ "subdirectoryMappings": {}
78
+ }
79
+ ]
80
+ }
81
+ ```
82
+
83
+ ### servers 字段
84
+
85
+ | 字段 | 类型 | 必填 | 说明 |
86
+ |------|------|------|------|
87
+ | `alias` | string | **必填** | 服务器别名,用于 `--server` 参数和 `mappings` 中引用 |
88
+ | `host` | string | **必填** | 服务器 IP 或域名 |
89
+ | `port` | number | 选填 | SSH 端口,默认 `22` |
90
+ | `username` | string | **必填** | 登录用户名 |
91
+ | `password` | string | **条件必填** | 登录密码,与 `privateKeyPath` 至少填一个 |
92
+ | `privateKeyPath` | string | **条件必填** | SSH 私钥路径,与 `password` 至少填一个。支持 `~` |
93
+ | `defaultRemotePath` | string | 选填 | 默认远程部署目录,可被 `--remote-path` 覆盖 |
94
+ | `rootPassword` | string | 选填 | root 密码,需要提权操作时填写 |
95
+
96
+ > **条件必填**:`password` 和 `privateKeyPath` 至少填一个。同时存在时优先使用 `privateKeyPath`。
97
+
98
+ ### mappings 字段
99
+
100
+ 每条映射将一个 Git 仓库关联到服务器部署路径。
101
+
102
+ | 字段 | 类型 | 必填 | 说明 |
103
+ |------|------|------|------|
104
+ | `gitRemoteUrl` | string | **必填** | Git 远程仓库地址,支持 SSH 和 HTTPS 两种格式(自动归一化匹配) |
105
+ | `serverAlias` | string | **条件必填** | 目标服务器别名,有子映射时可省略 |
106
+ | `remotePath` | string | **条件必填** | 远程部署根路径,有子映射时可省略 |
107
+ | `subdirectoryMappings` | object | 选填 | 子目录映射,可将仓库不同子目录部署到不同路径/服务器 |
108
+
109
+ > **条件必填**:如果所有文件都通过 `subdirectoryMappings` 映射到具体服务器和路径,则顶层 `serverAlias` 和 `remotePath` 可省略。否则必须填写。
110
+ >
111
+ > **优先级**:子目录映射 > 映射顶层 `serverAlias` / `remotePath`
112
+
113
+ ### 子目录映射(subdirectoryMappings)
114
+
115
+ 支持两种格式:
116
+
117
+ **格式一:字符串 — 同服务器不同路径**
118
+
119
+ ```json
120
+ "subdirectoryMappings": {
121
+ "web": "/var/www/project/frontend"
122
+ }
123
+ ```
124
+
125
+ 上传 `./web/index.js` → 部署到 `/var/www/project/frontend/index.js`
126
+
127
+ **格式二:对象 — 部署到不同服务器**
128
+
129
+ ```json
130
+ "subdirectoryMappings": {
131
+ "api": {
132
+ "serverAlias": "backend-server",
133
+ "remotePath": "/opt/services/api"
134
+ }
135
+ }
136
+ ```
137
+
138
+ 上传 `./api/main.py` → 部署到 `backend-server` 的 `/opt/services/api/main.py`
139
+
140
+ **对象格式字段说明:**
141
+
142
+ | 字段 | 类型 | 必填 | 说明 |
143
+ |------|------|------|------|
144
+ | `serverAlias` | string | **必填** | 目标服务器别名 |
145
+ | `remotePath` | string | **必填** | 该子目录在目标服务器上的部署路径 |
146
+
147
+ **完整示例:**
148
+
149
+ ```json
150
+ {
151
+ "servers": [
152
+ { "alias": "web-server", "host": "10.0.0.1", "username": "root", "password": "xxx" },
153
+ { "alias": "backend-server", "host": "10.0.0.2", "username": "root", "password": "xxx" }
154
+ ],
155
+ "mappings": [
156
+ {
157
+ "gitRemoteUrl": "git@github.com:yourorg/mono-repo.git",
158
+ "serverAlias": "web-server",
159
+ "remotePath": "/var/www/mono",
160
+ "subdirectoryMappings": {
161
+ "web": "/var/www/mono/frontend",
162
+ "api": {
163
+ "serverAlias": "backend-server",
164
+ "remotePath": "/opt/services/api"
165
+ },
166
+ "config": "/etc/mono-repo"
167
+ }
168
+ }
169
+ ]
170
+ }
171
+ ```
172
+
173
+ 对应部署结果:
174
+
175
+ | 上传路径 | 目标服务器 | 远程路径 |
176
+ |---------|-----------|---------|
177
+ | `./web/index.js` | web-server | `/var/www/mono/frontend/index.js` |
178
+ | `./api/main.py` | **backend-server** | `/opt/services/api/main.py` |
179
+ | `./config/app.conf` | web-server | `/etc/mono-repo/app.conf` |
180
+ | `./README.md` | web-server | `/var/www/mono/README.md` |
181
+
182
+ **纯子目录映射示例**(顶层不设 serverAlias/remotePath,全部由子映射决定):
183
+
184
+ ```json
185
+ {
186
+ "servers": [
187
+ { "alias": "web-server", "host": "10.0.0.1", "username": "root", "password": "xxx" },
188
+ { "alias": "backend-server", "host": "10.0.0.2", "username": "root", "password": "xxx" }
189
+ ],
190
+ "mappings": [
191
+ {
192
+ "gitRemoteUrl": "git@github.com:yourorg/full-stack.git",
193
+ "subdirectoryMappings": {
194
+ "frontend": {
195
+ "serverAlias": "web-server",
196
+ "remotePath": "/var/www/frontend"
197
+ },
198
+ "backend": {
199
+ "serverAlias": "backend-server",
200
+ "remotePath": "/opt/services/backend"
201
+ }
202
+ }
203
+ }
204
+ ]
205
+ }
206
+ ```
207
+
208
+ | 上传路径 | 目标服务器 | 远程路径 |
209
+ |---------|-----------|---------|
210
+ | `./frontend/index.html` | web-server | `/var/www/frontend/index.html` |
211
+ | `./backend/app.py` | **backend-server** | `/opt/services/backend/app.py` |
212
+ | `./README.md` | ❌ 报错 | 未匹配到子映射,且无顶层回退路径 |
213
+
214
+ ---
215
+
216
+ ## Git URL 匹配规则
217
+
218
+ 配置中的 `gitRemoteUrl` 和实际仓库的 `origin` 地址会自动归一化后匹配,以下写法等价:
219
+
220
+ ```
221
+ git@github.com:org/repo.git ←→ https://github.com/org/repo.git
222
+ ssh://git@github.com:22/org/repo.git ←→ git@github.com:org/repo.git
223
+ git@gitlab.com:group/sub/repo.git ←→ https://gitlab.com/group/sub/repo.git
224
+ ```
225
+
226
+ ---
227
+
228
+ ## 部署流程
229
+
230
+ 执行 `zp-cli upload` 时的完整流程:
231
+
232
+ ```
233
+ 1. 检查本地路径是否存在
234
+ 2. 读取 ~/.zp-cli.json 配置
235
+ 3. 确定目标服务器和远程路径
236
+ ├─ 命令行指定了 --server / --remote-path → 直接使用
237
+ └─ 未指定 → 读取 .git/config 获取 origin 地址 → 匹配 mappings
238
+ 4. 建立 SSH 连接
239
+ 5. 如果是目录 → 本地 tar -czf 打包
240
+ 6. 上传文件到服务器 /tmp 临时目录
241
+ 7. 在服务器上解压/复制到目标路径
242
+ 8. 清理远程临时文件
243
+ 9. 关闭连接
244
+ ```
245
+
246
+ ---
247
+
248
+ ## 常见问题
249
+
250
+ **Q: 报错"配置文件不存在"**
251
+ A: 先执行 `zp-cli init` 生成配置文件。
252
+
253
+ **Q: 报错"无法自动确定部署目标"**
254
+ A: 当前目录不在 Git 仓库内,或配置文件中没有匹配的映射。可以用 `--server` 和 `--remote-path` 手动指定。
255
+
256
+ **Q: 如何部署到同一台服务器的不同目录?**
257
+ A: 在 `subdirectoryMappings` 中用字符串格式配置即可。
258
+
259
+ **Q: 如何将仓库的不同子目录部署到不同服务器?**
260
+ A: 在 `subdirectoryMappings` 中用对象格式,指定 `serverAlias` 和 `remotePath`。
261
+
262
+ **Q: Windows 上打包报错?**
263
+ A: 确保系统中有 `tar` 命令(Git Bash 自带)。或使用 WSL。
264
+
265
+ ---
266
+
267
+ ## 项目结构
268
+
269
+ ```
270
+ zp-cli/
271
+ ├── package.json
272
+ ├── bin/
273
+ │ └── zp-cli.js # 主入口
274
+ ├── lib/
275
+ │ ├── commands/
276
+ │ │ ├── init.js # 生成 demo 配置
277
+ │ │ └── upload.js # 上传部署逻辑
278
+ │ ├── core/
279
+ │ │ ├── configManager.js # 配置读写
280
+ │ │ ├── gitHelper.js # Git 仓库感知、URL 归一化、路径映射
281
+ │ │ └── sshDeployer.js # SSH 连接、打包、上传、解压
282
+ │ └── utils/
283
+ │ └── logger.js # 终端彩色输出
284
+ └── README.md
285
+ ```
286
+
287
+ ## License
288
+
289
+ MIT
package/bin/zp-cli.js ADDED
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * zp-cli - 命令行部署工具主入口
5
+ * 使用 commander 解析命令行参数,提供 init / upload / config 子命令
6
+ */
7
+ const { Command } = require('commander');
8
+ const chalk = require('chalk');
9
+ const configManager = require('../lib/core/configManager');
10
+ const logger = require('../lib/utils/logger');
11
+ const pkg = require('../package.json');
12
+
13
+ const program = new Command();
14
+
15
+ program
16
+ .name('zp-cli')
17
+ .description('zp-cli - 高效的命令行部署工具,将本地代码通过 SSH 部署到远程服务器')
18
+ .version(pkg.version, '-v, --version', '显示版本号');
19
+
20
+ // ========== init 命令 ==========
21
+ program
22
+ .command('init')
23
+ .alias('i')
24
+ .description('生成 demo 配置文件 ~/.zp-cli.json')
25
+ .action(async () => {
26
+ const initCmd = require('../lib/commands/init');
27
+ await initCmd.run();
28
+ });
29
+
30
+ // ========== upload 命令 ==========
31
+ program
32
+ .command('upload <路径>')
33
+ .alias('up')
34
+ .description('上传文件或目录到远程服务器')
35
+ .option('-s, --server <别名>', '指定目标服务器别名')
36
+ .option('-r, --remote-path <路径>', '指定远程目标路径(覆盖配置中的默认值)')
37
+ .action(async (localPath, options) => {
38
+ const uploadCmd = require('../lib/commands/upload');
39
+ await uploadCmd.run(localPath, options);
40
+ });
41
+
42
+ // ========== config 命令(查看/管理配置) ==========
43
+ const configCmd = program
44
+ .command('config')
45
+ .alias('c')
46
+ .description('查看和管理配置信息');
47
+
48
+ configCmd
49
+ .command('show')
50
+ .alias('ls')
51
+ .description('显示当前配置文件内容')
52
+ .action(() => {
53
+ const config = configManager.loadConfig();
54
+ if (!config) {
55
+ logger.error('配置文件不存在,请先执行 ' + chalk.cyan('zp-cli init'));
56
+ process.exit(1);
57
+ }
58
+ logger.log(chalk.bold('\n📋 当前配置:\n'));
59
+ logger.log(JSON.stringify(config, null, 2));
60
+ logger.newline();
61
+ logger.log(chalk.gray(`配置文件路径: ${configManager.getConfigPath()}`));
62
+ });
63
+
64
+ configCmd
65
+ .command('path')
66
+ .alias('p')
67
+ .description('显示配置文件路径')
68
+ .action(() => {
69
+ logger.log(configManager.getConfigPath());
70
+ });
71
+
72
+ // ========== 未提供子命令时显示帮助 ==========
73
+ program.on('command:*', () => {
74
+ logger.error(`未知命令: ${program.args.join(' ')}`);
75
+ logger.log('');
76
+ program.help();
77
+ });
78
+
79
+ // 如果没有输入任何命令,显示帮助
80
+ if (process.argv.length <= 2) {
81
+ program.help();
82
+ }
83
+
84
+ program.parse(process.argv);
@@ -0,0 +1,93 @@
1
+ /**
2
+ * init.js - 配置初始化命令
3
+ * 直接生成一个 demo 配置文件,用户自行修改
4
+ */
5
+ const chalk = require('chalk');
6
+ const logger = require('../utils/logger');
7
+ const configManager = require('../core/configManager');
8
+
9
+ /** demo 配置模板 */
10
+ const DEMO_CONFIG = {
11
+ servers: [
12
+ {
13
+ alias: "test-server",
14
+ host: "192.168.1.100",
15
+ port: 22,
16
+ username: "root",
17
+ password: "your-password",
18
+ // privateKeyPath: "~/.ssh/id_rsa", // 私钥认证,与 password 二选一
19
+ defaultRemotePath: "/home/www",
20
+ rootPassword: "" // 需要 su root 时填写
21
+ },
22
+ {
23
+ alias: "prod-server",
24
+ host: "10.0.0.1",
25
+ port: 22,
26
+ username: "deploy",
27
+ password: "",
28
+ privateKeyPath: "~/.ssh/id_rsa",
29
+ defaultRemotePath: "/home/www",
30
+ rootPassword: ""
31
+ }
32
+ ],
33
+
34
+ mappings: [
35
+ // ── 示例1:整个仓库部署到同一台服务器 ──
36
+ {
37
+ "gitRemoteUrl": "git@github.com:yourorg/simple-project.git",
38
+ "serverAlias": "test-server",
39
+ "remotePath": "/var/www/simple-project"
40
+ },
41
+
42
+ // ── 示例2:同一仓库,不同子目录部署到不同服务器(顶层 + 子映射混合) ──
43
+ {
44
+ "gitRemoteUrl": "git@github.com:yourorg/mono-repo.git",
45
+ "serverAlias": "test-server",
46
+ "remotePath": "/var/www/mono",
47
+ "subdirectoryMappings": {
48
+ "web": "/var/www/mono/frontend",
49
+ "api": {
50
+ "serverAlias": "prod-server",
51
+ "remotePath": "/opt/services/api"
52
+ }
53
+ }
54
+ },
55
+
56
+ // ── 示例3:纯子目录映射,serverAlias/remotePath 全在子映射里 ──
57
+ {
58
+ "gitRemoteUrl": "git@github.com:yourorg/full-stack.git",
59
+ "subdirectoryMappings": {
60
+ "frontend": {
61
+ "serverAlias": "test-server",
62
+ "remotePath": "/var/www/frontend"
63
+ },
64
+ "backend": {
65
+ "serverAlias": "prod-server",
66
+ "remotePath": "/opt/services/backend"
67
+ }
68
+ }
69
+ }
70
+ ]
71
+ };
72
+
73
+ /**
74
+ * 执行 init 命令
75
+ */
76
+ async function run() {
77
+ const configPath = configManager.getConfigPath();
78
+
79
+ // 已存在则提示
80
+ if (configManager.configExists()) {
81
+ logger.warn(`配置文件已存在: ${configPath}`);
82
+ logger.log(chalk.gray('如需重新生成,请先手动删除该文件'));
83
+ return;
84
+ }
85
+
86
+ configManager.saveConfig(DEMO_CONFIG);
87
+ logger.success(`配置文件已生成: ${configPath}`);
88
+ logger.newline();
89
+ logger.log(chalk.bold('请编辑配置文件,填入你的服务器信息和仓库映射。'));
90
+ logger.log(chalk.gray('详细说明请参考 README.md 或执行 zp-cli init --help'));
91
+ }
92
+
93
+ module.exports = { run };