yj-deploy 0.0.2 → 0.0.3
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 +29 -20
- package/dist/yj-deploy.mjs +83 -70
- package/dist/yj-deploy.umd.js +6 -6
- package/package.json +33 -33
package/README.md
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
# yj-deploy
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
<br />
|
|
6
|
-
<br />
|
|
3
|
+
`yj-deploy` 是为解决公司内部项目部署到镜像服务器开发的工具,可帮助开发者自动构建镜像,并自动部署到镜像服务器上。
|
|
7
4
|
|
|
8
5
|
## 目前已实现如下功能
|
|
9
6
|
- ✔ 项目打包完成后自动上传到跳板机
|
|
10
|
-
- ✔
|
|
7
|
+
- ✔ 自动生成项目目录,自动创建dockerfile,upload.sh脚本文件
|
|
11
8
|
- ✔ 自动运行脚本,自动打包镜像,自动推送到镜像服务器(全程不用手动操作)
|
|
12
9
|
- ✔ 直接集成到vite,webpack项目
|
|
13
10
|
- ✔ 支持手动上传其他任何类型项目
|
|
14
11
|
- ✔ 支持灵活配置dockerfile,upload.sh等脚本内容
|
|
15
12
|
- ✔ 支持多种方式配置 `镜像仓库` `镜像环境`等参数
|
|
13
|
+
> 全程不需要连接跳板机做任何操作即可完成镜像推送
|
|
16
14
|
|
|
15
|
+
## 运行情况
|
|
17
16
|

|
|
18
17
|
|
|
19
18
|
## 安装
|
|
@@ -28,14 +27,14 @@ $ npm i yj-deploy -D
|
|
|
28
27
|
|
|
29
28
|
```javascript
|
|
30
29
|
import path from 'path'
|
|
31
|
-
import yjDeploy from '
|
|
30
|
+
import yjDeploy from 'yj-deploy'
|
|
32
31
|
|
|
33
32
|
const deploy = new yjDeploy({
|
|
34
33
|
host: '', // ip
|
|
35
34
|
port: '', // 端口
|
|
36
35
|
username: '', // 账号
|
|
37
36
|
password: '', // 密码
|
|
38
|
-
namespace: '', //
|
|
37
|
+
namespace: '', // 项目名称,等同git地址目录名称
|
|
39
38
|
// 本地文件目录
|
|
40
39
|
fileDir: path.resolve('./dist'),
|
|
41
40
|
})
|
|
@@ -48,7 +47,7 @@ const deploy = new yjDeploy({
|
|
|
48
47
|
port: '', // 端口 (必填)
|
|
49
48
|
username: '', // 账号 (必填)
|
|
50
49
|
password: '', // 密码 (必填)
|
|
51
|
-
namespace: '', //
|
|
50
|
+
namespace: '', // 项目名称,等同git地址目录名称(必填)
|
|
52
51
|
imageStore: 'dev-images', // 镜像仓库, 默认为 dev-images
|
|
53
52
|
tmpName: 'dev', // 镜像环境, 默认 dev
|
|
54
53
|
delay: 0, // 延迟上传时间 (部分项目构建需要时间,延迟上传可以解决)
|
|
@@ -64,7 +63,7 @@ const deploy = new yjDeploy({
|
|
|
64
63
|
]
|
|
65
64
|
},
|
|
66
65
|
|
|
67
|
-
// upload.sh
|
|
66
|
+
// upload.sh文件信息(可覆盖,但需要注意 $1 和 $2参数的顺序)
|
|
68
67
|
upload: {
|
|
69
68
|
name: 'upload.sh',
|
|
70
69
|
content: [
|
|
@@ -85,6 +84,8 @@ const deploy = new yjDeploy({
|
|
|
85
84
|
}
|
|
86
85
|
```
|
|
87
86
|
|
|
87
|
+
<br />
|
|
88
|
+
|
|
88
89
|
# 使用
|
|
89
90
|
## 配合打包命令使用
|
|
90
91
|
```javascript
|
|
@@ -101,7 +102,7 @@ module.exports = {
|
|
|
101
102
|
port: '',
|
|
102
103
|
username: '',
|
|
103
104
|
password: '',
|
|
104
|
-
namespace: '', //
|
|
105
|
+
namespace: '', // 项目名称,等同git地址目录名称
|
|
105
106
|
// 本地文件目录
|
|
106
107
|
fileDir: path.resolve('./dist'),
|
|
107
108
|
})
|
|
@@ -130,7 +131,7 @@ export default defineConfig({
|
|
|
130
131
|
port: '',
|
|
131
132
|
username: '',
|
|
132
133
|
password: '',
|
|
133
|
-
namespace: '', //
|
|
134
|
+
namespace: '', // 项目名称,等同git地址目录名称
|
|
134
135
|
// 本地文件目录
|
|
135
136
|
fileDir: path.resolve('./dist'),
|
|
136
137
|
})
|
|
@@ -139,7 +140,7 @@ export default defineConfig({
|
|
|
139
140
|
|
|
140
141
|
// package.json
|
|
141
142
|
"scripts": {
|
|
142
|
-
"deploy": "
|
|
143
|
+
"deploy": "vite build --mode development -- --deploy"
|
|
143
144
|
}
|
|
144
145
|
// 使用 yarn deploy 或 npm run deploy
|
|
145
146
|
```
|
|
@@ -152,7 +153,7 @@ export default defineConfig({
|
|
|
152
153
|
```javascript
|
|
153
154
|
// vite项目 package.json
|
|
154
155
|
"scripts": {
|
|
155
|
-
"deploy": "
|
|
156
|
+
"deploy": "vite build --mode development -- --deploy"
|
|
156
157
|
}
|
|
157
158
|
|
|
158
159
|
// webpack项目 package.json
|
|
@@ -166,7 +167,7 @@ export default defineConfig({
|
|
|
166
167
|
|
|
167
168
|
<br />
|
|
168
169
|
|
|
169
|
-
`--reset`
|
|
170
|
+
`--reset` :是否重置项目,如果配置了此选项,则每次执行命令时会删除 `dockerfile` `upload.sh` 配置文件,然后重新初始化项目,默认为不重置
|
|
170
171
|
|
|
171
172
|
<br />
|
|
172
173
|
|
|
@@ -174,9 +175,9 @@ export default defineConfig({
|
|
|
174
175
|
```javascript
|
|
175
176
|
"scripts": {
|
|
176
177
|
// 开发环境
|
|
177
|
-
"deploy": "
|
|
178
|
+
"deploy": "vite build --mode development -- --deploy"
|
|
178
179
|
// 测试环境
|
|
179
|
-
"deploy-test": "
|
|
180
|
+
"deploy-test": "vite build --mode test -- --deploy --imageStore=sot-admin"
|
|
180
181
|
}
|
|
181
182
|
```
|
|
182
183
|
|
|
@@ -186,11 +187,11 @@ export default defineConfig({
|
|
|
186
187
|
```javascript
|
|
187
188
|
"scripts": {
|
|
188
189
|
// 开发环境
|
|
189
|
-
"deploy": "
|
|
190
|
+
"deploy": "vite build --mode development -- --deploy --tmpName=dev"
|
|
190
191
|
// 测试环境
|
|
191
|
-
"deploy-test": "
|
|
192
|
-
//
|
|
193
|
-
"deploy-prod": "
|
|
192
|
+
"deploy-test": "vite build --mode test -- --deploy --tmpName=test"
|
|
193
|
+
// 正式环境
|
|
194
|
+
"deploy-prod": "vite build --mode production -- --deploy --tmpName=prod"
|
|
194
195
|
}
|
|
195
196
|
```
|
|
196
197
|
|
|
@@ -216,3 +217,11 @@ node uploader.js
|
|
|
216
217
|
// 增加动态配置
|
|
217
218
|
node uploader.js --tmpName=test
|
|
218
219
|
```
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
# 最后
|
|
223
|
+
如有意见或建议,或bug或文档不清晰等问题,可随时向我反馈,或直接修改后提交,共同完善这个工具。
|
|
224
|
+
|
|
225
|
+
<br />
|
|
226
|
+
|
|
227
|
+
项目已提交到git:https://gitlab.yunjingtech.cn:10010/frontend/yj-deploy
|
package/dist/yj-deploy.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
const { stdout:
|
|
5
|
-
class
|
|
1
|
+
var C = Object.defineProperty;
|
|
2
|
+
var j = (a, o, e) => o in a ? C(a, o, { enumerable: !0, configurable: !0, writable: !0, value: e }) : a[o] = e;
|
|
3
|
+
var d = (a, o, e) => (j(a, typeof o != "symbol" ? o + "" : o, e), e);
|
|
4
|
+
const { stdout: D } = require("single-line-log"), v = require("path"), $ = require("fs"), { Client: x } = require("ssh2");
|
|
5
|
+
module.exports = class {
|
|
6
6
|
constructor(o) {
|
|
7
|
-
|
|
7
|
+
d(this, "config", {
|
|
8
8
|
host: "",
|
|
9
9
|
port: "",
|
|
10
10
|
username: "",
|
|
@@ -48,11 +48,11 @@ class F {
|
|
|
48
48
|
name: "dist"
|
|
49
49
|
}
|
|
50
50
|
});
|
|
51
|
-
|
|
51
|
+
d(this, "ssh2Conn", null);
|
|
52
52
|
// 上传状态
|
|
53
|
-
|
|
53
|
+
d(this, "uploading", !1);
|
|
54
54
|
// 定时器
|
|
55
|
-
|
|
55
|
+
d(this, "trim", null);
|
|
56
56
|
return this.config = Object.assign(this.config, o), {
|
|
57
57
|
name: "yj-deploy",
|
|
58
58
|
isPut: this.isPut.bind(this),
|
|
@@ -99,7 +99,7 @@ class F {
|
|
|
99
99
|
console.log("- 请配置跳板机密码 password");
|
|
100
100
|
return;
|
|
101
101
|
}
|
|
102
|
-
this.uploading || (this.ssh2Conn = new
|
|
102
|
+
this.uploading || (this.ssh2Conn = new x(), this.ssh2Conn.on("ready", () => {
|
|
103
103
|
console.log("- 跳板机连接成功!"), this.ssh2Conn.sftp(async (o, e) => {
|
|
104
104
|
o && (console.log("- sftp连接失败"), this.breakConnect()), this.config.namespace || (console.log("- 请配置项目命名空间 namespace"), this.breakConnect()), this.uploading = !0, this.getArgv("--reset") !== void 0 && (console.log("- 重置项目"), await this.onShell(`rm -r ${this.config.rootDir}/${this.config.namespace}`)), this.upLoadProject(e, `${this.config.rootDir}/${this.config.namespace}`);
|
|
105
105
|
});
|
|
@@ -114,6 +114,9 @@ class F {
|
|
|
114
114
|
this.uploading = !1;
|
|
115
115
|
}));
|
|
116
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* 断开连接
|
|
119
|
+
*/
|
|
117
120
|
breakConnect() {
|
|
118
121
|
this.uploading = !1, console.log("- 已断开连接"), console.log("-------------- deploy-end --------------"), this.ssh2Conn.end();
|
|
119
122
|
}
|
|
@@ -124,20 +127,20 @@ class F {
|
|
|
124
127
|
*/
|
|
125
128
|
onShell(o) {
|
|
126
129
|
return new Promise((e, r) => {
|
|
127
|
-
this.ssh2Conn.shell((
|
|
128
|
-
if (
|
|
129
|
-
this.breakConnect();
|
|
130
|
+
this.ssh2Conn.shell((n, s) => {
|
|
131
|
+
if (n) {
|
|
132
|
+
console.log("- 远程命令错误:" + n, o), this.breakConnect(), r(n);
|
|
130
133
|
return;
|
|
131
134
|
}
|
|
132
135
|
let l = [];
|
|
133
136
|
s.on("close", () => {
|
|
134
137
|
e(l.toString());
|
|
135
|
-
}).on("data", (
|
|
138
|
+
}).on("data", (i) => {
|
|
136
139
|
l.push(`
|
|
137
|
-
` +
|
|
138
|
-
}).stderr.on("data", (
|
|
140
|
+
` + i);
|
|
141
|
+
}).stderr.on("data", (i) => {
|
|
139
142
|
console.log(`- 远程命令错误:
|
|
140
|
-
` +
|
|
143
|
+
` + i), this.breakConnect(), r(i);
|
|
141
144
|
}), s.end(o + `
|
|
142
145
|
exit
|
|
143
146
|
`);
|
|
@@ -150,18 +153,18 @@ exit
|
|
|
150
153
|
* @param {*} dir
|
|
151
154
|
*/
|
|
152
155
|
projectInit(o, e) {
|
|
153
|
-
return new Promise(async (r,
|
|
156
|
+
return new Promise(async (r, n) => {
|
|
154
157
|
o.mkdir(e, async (s) => {
|
|
155
158
|
if (s)
|
|
156
|
-
|
|
159
|
+
n(s);
|
|
157
160
|
else {
|
|
158
161
|
console.log("- 正在创建dockerfile");
|
|
159
162
|
const l = `${e}/${this.config.dockerfile.name}`;
|
|
160
163
|
await this.onShell(`touch ${l}`), await this.onShell(`echo '${this.config.dockerfile.content.join(`
|
|
161
164
|
`)}' > ${l}`), console.log("- 正在创建upload.sh");
|
|
162
|
-
const
|
|
163
|
-
await this.onShell(`touch ${
|
|
164
|
-
`)}' > ${
|
|
165
|
+
const i = `${e}/${this.config.upload.name}`;
|
|
166
|
+
await this.onShell(`touch ${i}`), await this.onShell(`echo '${this.config.upload.content.join(`
|
|
167
|
+
`)}' > ${i}`), r();
|
|
165
168
|
}
|
|
166
169
|
});
|
|
167
170
|
});
|
|
@@ -176,43 +179,56 @@ exit
|
|
|
176
179
|
if (r) {
|
|
177
180
|
console.log("- 跳板机不存在项目, 开始创建项目"), this.projectInit(o, e).then(() => {
|
|
178
181
|
console.log(`- ${this.config.namespace}项目创建成功`), this.upLoadProject(o, e);
|
|
179
|
-
}).catch(() => {
|
|
180
|
-
console.log(
|
|
182
|
+
}).catch((t) => {
|
|
183
|
+
console.log(`- 创建项目失败: ${t}`), this.breakConnect();
|
|
181
184
|
});
|
|
182
185
|
return;
|
|
183
186
|
}
|
|
184
187
|
console.log("- 开始上传文件");
|
|
185
|
-
const
|
|
186
|
-
await this.onShell(`rm -rf ${
|
|
188
|
+
const n = `${e}/${this.config.dist.name}`;
|
|
189
|
+
if (await this.onShell(`rm -rf ${n}`), await this.onShell(`mkdir ${n}`), !this.config.fileDir) {
|
|
190
|
+
console.log("- 请配置待上传文件目录 fileDir"), this.breakConnect();
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
187
193
|
const s = await this.getFilesInDirectory(this.config.fileDir);
|
|
188
|
-
s.length === 0
|
|
189
|
-
|
|
190
|
-
|
|
194
|
+
if (s.length === 0) {
|
|
195
|
+
console.log("- 待上传目录为空,请检查"), this.breakConnect();
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
let l = 0, i = s.length;
|
|
199
|
+
const g = (t) => t.isDirectory ? this.onShell(`mkdir ${n}${t.remotePath}`).then(() => {
|
|
200
|
+
this.progressBar(++l, i);
|
|
201
|
+
}) : new Promise((f, w) => {
|
|
191
202
|
try {
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
this.progressBar(++l,
|
|
195
|
-
}),
|
|
196
|
-
console.log(`- 文件 ${
|
|
197
|
-
}),
|
|
198
|
-
} catch (
|
|
199
|
-
|
|
203
|
+
const p = $.createReadStream(t.localPath), m = o.createWriteStream(`${n}${t.remotePath}`);
|
|
204
|
+
m.on("close", () => {
|
|
205
|
+
this.progressBar(++l, i), f();
|
|
206
|
+
}), m.on("error", (b) => {
|
|
207
|
+
console.log(`- 文件 ${t.remotePath} 上传失败:${b}`), w(b), this.breakConnect();
|
|
208
|
+
}), p.pipe(m);
|
|
209
|
+
} catch (p) {
|
|
210
|
+
w(p);
|
|
200
211
|
}
|
|
201
|
-
}),
|
|
202
|
-
|
|
212
|
+
}), c = (t) => {
|
|
213
|
+
if (t.length === 0)
|
|
214
|
+
return Promise.resolve();
|
|
215
|
+
const f = t.shift();
|
|
216
|
+
return g(f).then(() => c(t));
|
|
217
|
+
}, u = s.filter((t) => t.isDirectory);
|
|
218
|
+
await c(u), await new Promise((t) => {
|
|
203
219
|
setTimeout(() => {
|
|
204
|
-
|
|
220
|
+
t();
|
|
205
221
|
}, 500);
|
|
206
222
|
});
|
|
207
|
-
const
|
|
208
|
-
await Promise.all(
|
|
209
|
-
let
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
const
|
|
215
|
-
console.log(
|
|
223
|
+
const y = s.filter((t) => !t.isDirectory);
|
|
224
|
+
await Promise.all(y.map((t) => g(t))), console.log("- 文件上传成功"), console.log("- 开始推送镜像");
|
|
225
|
+
let h = `cd ${e} && sh ${this.config.upload.name}`;
|
|
226
|
+
const k = this.getArgv("--imageStore") || this.config.imageStore;
|
|
227
|
+
h += ` ${k}`;
|
|
228
|
+
const P = this.getArgv("--tmpName") || this.config.tmpName;
|
|
229
|
+
h += ` ${P}`;
|
|
230
|
+
const S = await this.onShell(h);
|
|
231
|
+
console.log(S), console.log("- 镜像推送完成"), this.breakConnect();
|
|
216
232
|
});
|
|
217
233
|
}
|
|
218
234
|
/**
|
|
@@ -221,32 +237,32 @@ exit
|
|
|
221
237
|
* @param bar_length 进度条的长度(单位:字符),默认设为 25
|
|
222
238
|
*/
|
|
223
239
|
progressBar(o, e, r = 25) {
|
|
224
|
-
let
|
|
225
|
-
for (let
|
|
240
|
+
let n = (o / e).toFixed(4), s = Math.floor(n * r), l = "";
|
|
241
|
+
for (let c = 0; c < s; c++)
|
|
226
242
|
l += "█";
|
|
227
|
-
let
|
|
228
|
-
for (let
|
|
229
|
-
|
|
230
|
-
let
|
|
231
|
-
|
|
243
|
+
let i = "";
|
|
244
|
+
for (let c = 0; c < r - s; c++)
|
|
245
|
+
i += "░";
|
|
246
|
+
let g = `- 上传进度: ${l}${i} ${(100 * n).toFixed(2)}% (${o}/${e})`;
|
|
247
|
+
D(g), o == e && console.log("");
|
|
232
248
|
}
|
|
233
249
|
/**
|
|
234
|
-
*
|
|
250
|
+
* 获取目录下所有文件并分类
|
|
235
251
|
* @param {*} dir
|
|
236
252
|
*/
|
|
237
253
|
getFilesInDirectory(o) {
|
|
238
254
|
const e = [];
|
|
239
|
-
return new Promise((r,
|
|
240
|
-
const s = (l,
|
|
241
|
-
|
|
242
|
-
const
|
|
255
|
+
return new Promise((r, n) => {
|
|
256
|
+
const s = (l, i) => {
|
|
257
|
+
$.readdirSync(l).forEach((c) => {
|
|
258
|
+
const u = v.join(l, c), h = $.statSync(u).isDirectory();
|
|
243
259
|
e.push({
|
|
244
|
-
isDirectory:
|
|
245
|
-
localPath:
|
|
260
|
+
isDirectory: h,
|
|
261
|
+
localPath: u,
|
|
246
262
|
// 本地路径
|
|
247
|
-
remotePath: `${
|
|
263
|
+
remotePath: `${i}${c}`
|
|
248
264
|
// 远程路径
|
|
249
|
-
}),
|
|
265
|
+
}), h && s(u, `${i}${c}/`);
|
|
250
266
|
});
|
|
251
267
|
};
|
|
252
268
|
s(o, "/"), r(e);
|
|
@@ -259,11 +275,8 @@ exit
|
|
|
259
275
|
getArgv(o) {
|
|
260
276
|
const e = process.argv;
|
|
261
277
|
let r;
|
|
262
|
-
return e.forEach((
|
|
263
|
-
|
|
278
|
+
return e.forEach((n) => {
|
|
279
|
+
n.indexOf(o) > -1 && (r = n.split("=")[1] || "");
|
|
264
280
|
}), r;
|
|
265
281
|
}
|
|
266
|
-
}
|
|
267
|
-
export {
|
|
268
|
-
F as default
|
|
269
282
|
};
|
package/dist/yj-deploy.umd.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
(function(
|
|
2
|
-
`+
|
|
3
|
-
`+
|
|
1
|
+
(function(a){typeof define=="function"&&define.amd?define(a):a()})(function(){"use strict";var D=Object.defineProperty;var v=(a,h,g)=>h in a?D(a,h,{enumerable:!0,configurable:!0,writable:!0,value:g}):a[h]=g;var p=(a,h,g)=>(v(a,typeof h!="symbol"?h+"":h,g),g);const{stdout:a}=require("single-line-log"),h=require("path"),g=require("fs"),{Client:P}=require("ssh2");module.exports=class{constructor(e){p(this,"config",{host:"",port:"",username:"",password:"",namespace:"",imageStore:"dev-images",tmpName:"dev",delay:0,fileDir:"",rootDir:"/home/yjweb",dockerfile:{name:"Dockerfile",content:["FROM harbor.yunjingtech.cn:30002/yj-base/nginx:latest","RUN rm -rf /usr/share/nginx/html/*","COPY dist /usr/share/nginx/html/"]},upload:{name:"upload.sh",content:["#!/bin/sh","tag=`basename \\`pwd\\``:$2-`date +%Y%m%d`",'echo "- 镜像仓库: $1"','echo "- 镜像环境: $2"',"docker build -t harbor.yunjingtech.cn:30002/$1/$tag .","docker push harbor.yunjingtech.cn:30002/$1/$tag","echo - 镜像地址: harbor.yunjingtech.cn:30002/$1/$tag"]},dist:{name:"dist"}});p(this,"ssh2Conn",null);p(this,"uploading",!1);p(this,"trim",null);return this.config=Object.assign(this.config,e),{name:"yj-deploy",isPut:this.isPut.bind(this),upload:this.upload.bind(this),apply:this.apply.bind(this),closeBundle:this.isPut.bind(this)}}apply(e){return e&&e.hooks&&e.hooks.done&&e.hooks.done.tap("yj-deploy",()=>{this.isPut()}),"build"}isPut(){this.getArgv("--deploy")!=null&&(clearTimeout(this.trim),this.trim=setTimeout(()=>{this.upload()},this.config.delay||0))}upload(){if(console.log("-------------- deploy-start --------------"),!this.config.host){console.log("- 请配置跳板机地址 host");return}if(!this.config.port){console.log("- 请配置跳板机端口 port");return}if(!this.config.username){console.log("- 请配置跳板机账号 username");return}if(!this.config.password){console.log("- 请配置跳板机密码 password");return}this.uploading||(this.ssh2Conn=new P,this.ssh2Conn.on("ready",()=>{console.log("- 跳板机连接成功!"),this.ssh2Conn.sftp(async(e,o)=>{e&&(console.log("- sftp连接失败"),this.breakConnect()),this.config.namespace||(console.log("- 请配置项目命名空间 namespace"),this.breakConnect()),this.uploading=!0,this.getArgv("--reset")!==void 0&&(console.log("- 重置项目"),await this.onShell(`rm -r ${this.config.rootDir}/${this.config.namespace}`)),this.upLoadProject(o,`${this.config.rootDir}/${this.config.namespace}`)})}).connect({host:this.config.host,port:this.config.port,username:this.config.username,password:this.config.password}),this.ssh2Conn.on("error",e=>{console.log(`- 连接失败: ${e}`),this.breakConnect()}),this.ssh2Conn.on("end",()=>{this.uploading=!1}))}breakConnect(){this.uploading=!1,console.log("- 已断开连接"),console.log("-------------- deploy-end --------------"),this.ssh2Conn.end()}onShell(e){return new Promise((o,r)=>{this.ssh2Conn.shell((n,s)=>{if(n){console.log("- 远程命令错误:"+n,e),this.breakConnect(),r(n);return}let l=[];s.on("close",()=>{o(l.toString())}).on("data",i=>{l.push(`
|
|
2
|
+
`+i)}).stderr.on("data",i=>{console.log(`- 远程命令错误:
|
|
3
|
+
`+i),this.breakConnect(),r(i)}),s.end(e+`
|
|
4
4
|
exit
|
|
5
|
-
`)})})}projectInit(e,o){return new Promise(async(
|
|
6
|
-
`)}' > ${
|
|
7
|
-
`)}' > ${
|
|
5
|
+
`)})})}projectInit(e,o){return new Promise(async(r,n)=>{e.mkdir(o,async s=>{if(s)n(s);else{console.log("- 正在创建dockerfile");const l=`${o}/${this.config.dockerfile.name}`;await this.onShell(`touch ${l}`),await this.onShell(`echo '${this.config.dockerfile.content.join(`
|
|
6
|
+
`)}' > ${l}`),console.log("- 正在创建upload.sh");const i=`${o}/${this.config.upload.name}`;await this.onShell(`touch ${i}`),await this.onShell(`echo '${this.config.upload.content.join(`
|
|
7
|
+
`)}' > ${i}`),r()}})})}upLoadProject(e,o){e.readdir(o,async r=>{if(r){console.log("- 跳板机不存在项目, 开始创建项目"),this.projectInit(e,o).then(()=>{console.log(`- ${this.config.namespace}项目创建成功`),this.upLoadProject(e,o)}).catch(t=>{console.log(`- 创建项目失败: ${t}`),this.breakConnect()});return}console.log("- 开始上传文件");const n=`${o}/${this.config.dist.name}`;if(await this.onShell(`rm -rf ${n}`),await this.onShell(`mkdir ${n}`),!this.config.fileDir){console.log("- 请配置待上传文件目录 fileDir"),this.breakConnect();return}const s=await this.getFilesInDirectory(this.config.fileDir);if(s.length===0){console.log("- 待上传目录为空,请检查"),this.breakConnect();return}let l=0,i=s.length;const d=t=>t.isDirectory?this.onShell(`mkdir ${n}${t.remotePath}`).then(()=>{this.progressBar(++l,i)}):new Promise((m,b)=>{try{const $=g.createReadStream(t.localPath),y=e.createWriteStream(`${n}${t.remotePath}`);y.on("close",()=>{this.progressBar(++l,i),m()}),y.on("error",k=>{console.log(`- 文件 ${t.remotePath} 上传失败:${k}`),b(k),this.breakConnect()}),$.pipe(y)}catch($){b($)}}),c=t=>{if(t.length===0)return Promise.resolve();const m=t.shift();return d(m).then(()=>c(t))},f=s.filter(t=>t.isDirectory);await c(f),await new Promise(t=>{setTimeout(()=>{t()},500)});const w=s.filter(t=>!t.isDirectory);await Promise.all(w.map(t=>d(t))),console.log("- 文件上传成功"),console.log("- 开始推送镜像");let u=`cd ${o} && sh ${this.config.upload.name}`;const S=this.getArgv("--imageStore")||this.config.imageStore;u+=` ${S}`;const C=this.getArgv("--tmpName")||this.config.tmpName;u+=` ${C}`;const j=await this.onShell(u);console.log(j),console.log("- 镜像推送完成"),this.breakConnect()})}progressBar(e,o,r=25){let n=(e/o).toFixed(4),s=Math.floor(n*r),l="";for(let c=0;c<s;c++)l+="█";let i="";for(let c=0;c<r-s;c++)i+="░";let d=`- 上传进度: ${l}${i} ${(100*n).toFixed(2)}% (${e}/${o})`;a(d),e==o&&console.log("")}getFilesInDirectory(e){const o=[];return new Promise((r,n)=>{const s=(l,i)=>{g.readdirSync(l).forEach(c=>{const f=h.join(l,c),u=g.statSync(f).isDirectory();o.push({isDirectory:u,localPath:f,remotePath:`${i}${c}`}),u&&s(f,`${i}${c}/`)})};s(e,"/"),r(o)})}getArgv(e){const o=process.argv;let r;return o.forEach(n=>{n.indexOf(e)>-1&&(r=n.split("=")[1]||"")}),r}}});
|
package/package.json
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "yj-deploy",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "ssh sftp",
|
|
5
|
-
"scripts": {
|
|
6
|
-
"build": "vite build"
|
|
7
|
-
},
|
|
8
|
-
"files": [
|
|
9
|
-
"dist",
|
|
10
|
-
"package.json",
|
|
11
|
-
"README.md"
|
|
12
|
-
],
|
|
13
|
-
"main": "./dist/yj-deploy.umd.js",
|
|
14
|
-
"module": "./dist/yj-deploy.mjs",
|
|
15
|
-
"exports": {
|
|
16
|
-
".": {
|
|
17
|
-
"import": "./dist/yj-deploy.mjs",
|
|
18
|
-
"require": "./dist/yj-deploy.umd.js"
|
|
19
|
-
}
|
|
20
|
-
},
|
|
21
|
-
"author": "",
|
|
22
|
-
"license": "ISC",
|
|
23
|
-
"dependencies": {
|
|
24
|
-
"single-line-log": "^1.1.2",
|
|
25
|
-
"ssh2": "^1.15.0"
|
|
26
|
-
},
|
|
27
|
-
"devDependencies": {
|
|
28
|
-
"vite": "4.5"
|
|
29
|
-
},
|
|
30
|
-
"publishConfig": {
|
|
31
|
-
"registry": "https://registry.npmjs.org"
|
|
32
|
-
}
|
|
33
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "yj-deploy",
|
|
3
|
+
"version": "0.0.3",
|
|
4
|
+
"description": "ssh sftp",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"build": "vite build"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"package.json",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"main": "./dist/yj-deploy.umd.js",
|
|
14
|
+
"module": "./dist/yj-deploy.mjs",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"import": "./dist/yj-deploy.mjs",
|
|
18
|
+
"require": "./dist/yj-deploy.umd.js"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"author": "",
|
|
22
|
+
"license": "ISC",
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"single-line-log": "^1.1.2",
|
|
25
|
+
"ssh2": "^1.15.0"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"vite": "4.5"
|
|
29
|
+
},
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"registry": "https://registry.npmjs.org"
|
|
32
|
+
}
|
|
33
|
+
}
|