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 CHANGED
@@ -1,19 +1,18 @@
1
1
  # yj-deploy
2
2
 
3
- > `yj-deploy` 是为解决公司内部项目部署到镜像服务器开发的工具,可解决每次开发完需通过繁琐的步骤才能获得镜像地址的问题。
4
-
5
- <br />
6
- <br />
3
+ `yj-deploy` 是为解决公司内部项目部署到镜像服务器开发的工具,可帮助开发者自动构建镜像,并自动部署到镜像服务器上。
7
4
 
8
5
  ## 目前已实现如下功能
9
6
  - &#x2714; 项目打包完成后自动上传到跳板机
10
- - &#x2714; 自动生成目录,自动创建dockerfile,upload.sh脚本文件
7
+ - &#x2714; 自动生成项目目录,自动创建dockerfile,upload.sh脚本文件
11
8
  - &#x2714; 自动运行脚本,自动打包镜像,自动推送到镜像服务器(全程不用手动操作)
12
9
  - &#x2714; 直接集成到vite,webpack项目
13
10
  - &#x2714; 支持手动上传其他任何类型项目
14
11
  - &#x2714; 支持灵活配置dockerfile,upload.sh等脚本内容
15
12
  - &#x2714; 支持多种方式配置 `镜像仓库` `镜像环境`等参数
13
+ > 全程不需要连接跳板机做任何操作即可完成镜像推送
16
14
 
15
+ ## 运行情况
17
16
  ![预览](./img.png)
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 './lib/main.js'
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文件信息(可覆盖,单需要注意 $1 和 $2参数的顺序)
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": "vue-cli-service build --mode development -- --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": "vue-cli-service build --mode development -- --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` :是否重置项目,如果配置了此选项,则每次执行命令时会删除`dockerfile``upload.sh`配置文件,然后重新初始化项目,默认为不重置
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": "vue-cli-service build --mode development -- --deploy"
178
+ "deploy": "vite build --mode development -- --deploy"
178
179
  // 测试环境
179
- "deploy-test": "vue-cli-service build --mode development -- --deploy --imageStore=sot-admin"
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": "vue-cli-service build --mode development -- --deploy --tmpName=dev"
190
+ "deploy": "vite build --mode development -- --deploy --tmpName=dev"
190
191
  // 测试环境
191
- "deploy-test": "vue-cli-service build --mode development -- --deploy --tmpName=test"
192
- // 测试环境
193
- "deploy-prod": "vue-cli-service build --mode development -- --deploy --tmpName=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
@@ -1,10 +1,10 @@
1
- var S = Object.defineProperty;
2
- var C = (h, o, e) => o in h ? S(h, o, { enumerable: !0, configurable: !0, writable: !0, value: e }) : h[o] = e;
3
- var g = (h, o, e) => (C(h, typeof o != "symbol" ? o + "" : o, e), e);
4
- const { stdout: j } = require("single-line-log"), D = require("path"), m = require("fs"), { Client: v } = require("ssh2");
5
- class F {
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
- g(this, "config", {
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
- g(this, "ssh2Conn", null);
51
+ d(this, "ssh2Conn", null);
52
52
  // 上传状态
53
- g(this, "uploading", !1);
53
+ d(this, "uploading", !1);
54
54
  // 定时器
55
- g(this, "trim", null);
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 v(), this.ssh2Conn.on("ready", () => {
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((i, s) => {
128
- if (i) {
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", (t) => {
138
+ }).on("data", (i) => {
136
139
  l.push(`
137
- ` + t);
138
- }).stderr.on("data", (t) => {
140
+ ` + i);
141
+ }).stderr.on("data", (i) => {
139
142
  console.log(`- 远程命令错误:
140
- ` + t), this.ssh2Conn.end(), r(t);
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, i) => {
156
+ return new Promise(async (r, n) => {
154
157
  o.mkdir(e, async (s) => {
155
158
  if (s)
156
- console.log(s), i();
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 t = `${e}/${this.config.upload.name}`;
163
- await this.onShell(`touch ${t}`), await this.onShell(`echo '${this.config.upload.content.join(`
164
- `)}' > ${t}`), r();
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("- 创建项目失败"), this.breakConnect();
182
+ }).catch((t) => {
183
+ console.log(`- 创建项目失败: ${t}`), this.breakConnect();
181
184
  });
182
185
  return;
183
186
  }
184
187
  console.log("- 开始上传文件");
185
- const i = `${e}/${this.config.dist.name}`;
186
- await this.onShell(`rm -rf ${i}`), await this.onShell(`mkdir ${i}`), this.config.fileDir || (console.log("- 请配置本地文件目录 fileDir"), this.breakConnect());
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 && (console.log("- 待上传目录为空,请检查"), this.breakConnect());
189
- let l = 0;
190
- const t = (n, k = 0) => n.isDirectory ? this.onShell(`mkdir ${i}${n.remotePath}`) : new Promise((P, y) => {
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 f = m.createReadStream(n.localPath), p = o.createWriteStream(`${e}/dist${n.remotePath}`);
193
- p.on("close", () => {
194
- this.progressBar(++l, k), P();
195
- }), p.on("error", (w) => {
196
- console.log(`- 文件 ${n.remotePath} 上传失败:${w}`), y(w), this.breakConnect();
197
- }), f.pipe(p);
198
- } catch (f) {
199
- y(f);
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
- }), d = s.filter((n) => n.isDirectory);
202
- await Promise.all(d.map((n) => t(n))), await new Promise((n) => {
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
- n();
220
+ t();
205
221
  }, 500);
206
222
  });
207
- const a = s.filter((n) => !n.isDirectory);
208
- await Promise.all(a.map((n) => t(n, a.length))), console.log("- 文件上传成功"), console.log("- 开始推送镜像");
209
- let c = `cd ${e} && sh ${this.config.upload.name}`;
210
- const $ = this.getArgv("--imageStore") || this.config.imageStore;
211
- c += ` ${$}`;
212
- const u = this.getArgv("--tmpName") || this.config.tmpName;
213
- c += ` ${u}`;
214
- const b = await this.onShell(c);
215
- console.log(b), console.log("- 镜像推送完成"), this.ssh2Conn.end();
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 i = (o / e).toFixed(4), s = Math.floor(i * r), l = "";
225
- for (let a = 0; a < s; a++)
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 t = "";
228
- for (let a = 0; a < r - s; a++)
229
- t += "░";
230
- let d = `- 上传进度: ${l}${t} ${(100 * i).toFixed(2)}% (${o}/${e})`;
231
- j(d), o == e && console.log("");
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, i) => {
240
- const s = (l, t) => {
241
- m.readdirSync(l).forEach((a) => {
242
- const c = D.join(l, a), u = m.statSync(c).isDirectory();
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: u,
245
- localPath: c,
260
+ isDirectory: h,
261
+ localPath: u,
246
262
  // 本地路径
247
- remotePath: `${t}${a}`
263
+ remotePath: `${i}${c}`
248
264
  // 远程路径
249
- }), u && s(c, `${t}${a}/`);
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((i) => {
263
- i.indexOf(o) > -1 && (r = i.split("=")[1] || "");
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
  };
@@ -1,7 +1,7 @@
1
- (function(h,r){typeof exports=="object"&&typeof module<"u"?module.exports=r():typeof define=="function"&&define.amd?define(r):(h=typeof globalThis<"u"?globalThis:h||self,h["yj-deploy"]=r())})(this,function(){"use strict";var D=Object.defineProperty;var v=(h,r,g)=>r in h?D(h,r,{enumerable:!0,configurable:!0,writable:!0,value:g}):h[r]=g;var u=(h,r,g)=>(v(h,typeof r!="symbol"?r+"":r,g),g);const{stdout:h}=require("single-line-log"),r=require("path"),g=require("fs"),{Client:k}=require("ssh2");class P{constructor(e){u(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"}});u(this,"ssh2Conn",null);u(this,"uploading",!1);u(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 k,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,l)=>{this.ssh2Conn.shell((i,n)=>{if(i){this.breakConnect();return}let c=[];n.on("close",()=>{o(c.toString())}).on("data",t=>{c.push(`
2
- `+t)}).stderr.on("data",t=>{console.log(`- 远程命令错误:
3
- `+t),this.ssh2Conn.end(),l(t)}),n.end(e+`
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(l,i)=>{e.mkdir(o,async n=>{if(n)console.log(n),i();else{console.log("- 正在创建dockerfile");const c=`${o}/${this.config.dockerfile.name}`;await this.onShell(`touch ${c}`),await this.onShell(`echo '${this.config.dockerfile.content.join(`
6
- `)}' > ${c}`),console.log("- 正在创建upload.sh");const t=`${o}/${this.config.upload.name}`;await this.onShell(`touch ${t}`),await this.onShell(`echo '${this.config.upload.content.join(`
7
- `)}' > ${t}`),l()}})})}upLoadProject(e,o){e.readdir(o,async l=>{if(l){console.log("- 跳板机不存在项目, 开始创建项目"),this.projectInit(e,o).then(()=>{console.log(`- ${this.config.namespace}项目创建成功`),this.upLoadProject(e,o)}).catch(()=>{console.log("- 创建项目失败"),this.breakConnect()});return}console.log("- 开始上传文件");const i=`${o}/${this.config.dist.name}`;await this.onShell(`rm -rf ${i}`),await this.onShell(`mkdir ${i}`),this.config.fileDir||(console.log("- 请配置本地文件目录 fileDir"),this.breakConnect());const n=await this.getFilesInDirectory(this.config.fileDir);n.length===0&&(console.log("- 待上传目录为空,请检查"),this.breakConnect());let c=0;const t=(s,C=0)=>s.isDirectory?this.onShell(`mkdir ${i}${s.remotePath}`):new Promise((j,w)=>{try{const m=g.createReadStream(s.localPath),$=e.createWriteStream(`${o}/dist${s.remotePath}`);$.on("close",()=>{this.progressBar(++c,C),j()}),$.on("error",b=>{console.log(`- 文件 ${s.remotePath} 上传失败:${b}`),w(b),this.breakConnect()}),m.pipe($)}catch(m){w(m)}}),f=n.filter(s=>s.isDirectory);await Promise.all(f.map(s=>t(s))),await new Promise(s=>{setTimeout(()=>{s()},500)});const a=n.filter(s=>!s.isDirectory);await Promise.all(a.map(s=>t(s,a.length))),console.log("- 文件上传成功"),console.log("- 开始推送镜像");let d=`cd ${o} && sh ${this.config.upload.name}`;const y=this.getArgv("--imageStore")||this.config.imageStore;d+=` ${y}`;const p=this.getArgv("--tmpName")||this.config.tmpName;d+=` ${p}`;const S=await this.onShell(d);console.log(S),console.log("- 镜像推送完成"),this.ssh2Conn.end()})}progressBar(e,o,l=25){let i=(e/o).toFixed(4),n=Math.floor(i*l),c="";for(let a=0;a<n;a++)c+="█";let t="";for(let a=0;a<l-n;a++)t+="░";let f=`- 上传进度: ${c}${t} ${(100*i).toFixed(2)}% (${e}/${o})`;h(f),e==o&&console.log("")}getFilesInDirectory(e){const o=[];return new Promise((l,i)=>{const n=(c,t)=>{g.readdirSync(c).forEach(a=>{const d=r.join(c,a),p=g.statSync(d).isDirectory();o.push({isDirectory:p,localPath:d,remotePath:`${t}${a}`}),p&&n(d,`${t}${a}/`)})};n(e,"/"),l(o)})}getArgv(e){const o=process.argv;let l;return o.forEach(i=>{i.indexOf(e)>-1&&(l=i.split("=")[1]||"")}),l}}return P});
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.2",
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
+ }