@taole/deploy-helper 0.3.4 → 0.3.6
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/index.mjs +72 -50
- package/lib/pipelineApi.mjs +36 -15
- package/lib/util.mjs +17 -0
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -5,7 +5,8 @@ import fs from 'fs';
|
|
|
5
5
|
import { join, basename, dirname } from "path";
|
|
6
6
|
import { simpleGit } from 'simple-git';
|
|
7
7
|
import { homedir } from 'os'
|
|
8
|
-
import { runPipeline, checkYunxiaoToken } from './lib/pipelineApi.mjs';
|
|
8
|
+
import { runPipeline, checkYunxiaoToken, triggerPipeline } from './lib/pipelineApi.mjs';
|
|
9
|
+
import { setDebug, log } from './lib/util.mjs';
|
|
9
10
|
|
|
10
11
|
const TEST_SERVER_HOST = "192.168.0.35";
|
|
11
12
|
/**
|
|
@@ -18,7 +19,7 @@ async function loadConfig() {
|
|
|
18
19
|
const configJson = JSON.parse(fs.readFileSync(configJsonPath, "utf-8"));
|
|
19
20
|
return configJson;
|
|
20
21
|
}
|
|
21
|
-
|
|
22
|
+
log(`deploy.config.json不存在, 请先创建`);
|
|
22
23
|
return null;
|
|
23
24
|
}
|
|
24
25
|
|
|
@@ -26,7 +27,7 @@ async function initConfigJson() {
|
|
|
26
27
|
// check if deploy.config.json exists
|
|
27
28
|
const configJsonPath = join(process.cwd(), "deploy.config.json");
|
|
28
29
|
if (fs.existsSync(configJsonPath)) {
|
|
29
|
-
|
|
30
|
+
log(`deploy.config.json已存在, 请勿重复创建`);
|
|
30
31
|
return;
|
|
31
32
|
}
|
|
32
33
|
|
|
@@ -52,7 +53,7 @@ async function initConfigJson() {
|
|
|
52
53
|
}
|
|
53
54
|
}`;
|
|
54
55
|
fs.writeFileSync(configJsonPath, content, { encoding: "utf-8" });
|
|
55
|
-
|
|
56
|
+
log(`deploy.config.json创建成功`);
|
|
56
57
|
process.exit(0);
|
|
57
58
|
}
|
|
58
59
|
|
|
@@ -72,7 +73,7 @@ async function getScpClient() {
|
|
|
72
73
|
if (fs.existsSync(sshKeyPath)) {
|
|
73
74
|
scpClientConfig.privateKey = fs.readFileSync(sshKeyPath, "utf-8");
|
|
74
75
|
} else {
|
|
75
|
-
|
|
76
|
+
log(`${sshKeyPath}不存在, 建议配置本机ssh免密登录, 参考地址:https://foochane.cn/article/2019061601.html`);
|
|
76
77
|
}
|
|
77
78
|
scpClient = await Client(scpClientConfig);
|
|
78
79
|
return scpClient;
|
|
@@ -83,13 +84,19 @@ async function getScpClient() {
|
|
|
83
84
|
|
|
84
85
|
async function main() {
|
|
85
86
|
|
|
87
|
+
// process.argv.includes("--debug") ||
|
|
88
|
+
// 默认开启debug debug目前只是打印日志的时候额外打印时间
|
|
89
|
+
setDebug(true);
|
|
90
|
+
|
|
91
|
+
log("deploy-helper start");
|
|
92
|
+
|
|
86
93
|
// await devTest();
|
|
87
|
-
//
|
|
94
|
+
// log(`process.argv: ${process.argv[2]} ${process.argv[3]} ${process.argv[4]}`);
|
|
88
95
|
|
|
89
96
|
// return;
|
|
90
97
|
// other commands
|
|
91
98
|
let command = process.argv[2];
|
|
92
|
-
if (!["init", "prod", "test", "scp", "scpevt"].includes(command)) {
|
|
99
|
+
if (!["init", "prod", "test", "scp", "scpevt", "pipeline"].includes(command)) {
|
|
93
100
|
command = "help";
|
|
94
101
|
}
|
|
95
102
|
|
|
@@ -103,6 +110,7 @@ async function main() {
|
|
|
103
110
|
console.log(`command: scp {file} {dest} 复制文件{file}到OfficialSite测试服务器{dest}`);
|
|
104
111
|
console.log(`command: scpevt {file} 复制文件{file}到events测试服务器{file}`);
|
|
105
112
|
console.log(`command: scpevt {file} {dest} 复制文件{file}到events测试服务器{dest}`);
|
|
113
|
+
log(`command: pipeline {pipelineName|pipelineId} 触发流水线{pipelineName|pipelineId}`);
|
|
106
114
|
process.exit(0);
|
|
107
115
|
} else if (command === "init") {
|
|
108
116
|
await initConfigJson();
|
|
@@ -110,18 +118,18 @@ async function main() {
|
|
|
110
118
|
} else if (["scp", "scpevt"].includes(command)) {
|
|
111
119
|
const file = process.argv[3];
|
|
112
120
|
if (!file) {
|
|
113
|
-
|
|
121
|
+
log(`file参数不能为空`);
|
|
114
122
|
process.exit(1);
|
|
115
123
|
}
|
|
116
124
|
const workDir = process.cwd(); // 当前项目根目录
|
|
117
125
|
|
|
118
126
|
const srcFilePath = join(workDir, file);
|
|
119
127
|
if (!fs.existsSync(srcFilePath)) {
|
|
120
|
-
|
|
128
|
+
log(`${srcFilePath}不存在`);
|
|
121
129
|
process.exit(1);
|
|
122
130
|
}
|
|
123
131
|
if (fs.statSync(srcFilePath).isDirectory()) {
|
|
124
|
-
|
|
132
|
+
log(`${srcFilePath}是目录, 不支持scp目录`);
|
|
125
133
|
process.exit(1);
|
|
126
134
|
}
|
|
127
135
|
// 获取srcFilePath的目录
|
|
@@ -129,42 +137,56 @@ async function main() {
|
|
|
129
137
|
const fileName = basename(srcFilePath);
|
|
130
138
|
const dest = process.argv[4] || fileName;
|
|
131
139
|
if (dest.includes("/") || dest.includes("\\")) {
|
|
132
|
-
|
|
140
|
+
log(`dest不能包含/或\\`);
|
|
133
141
|
process.exit(1);
|
|
134
142
|
}
|
|
135
143
|
|
|
136
144
|
if (workDir !== fileDir) {
|
|
137
|
-
|
|
145
|
+
log(`仅支持scp当前目录下的文件(不带子目录)`);
|
|
138
146
|
process.exit(1);
|
|
139
147
|
}
|
|
140
148
|
|
|
141
149
|
const destPath = "/home/web/website/tuwan_www/templets/static/play/" + (command === 'scp' ? '' : 'events/') + dest;
|
|
142
150
|
|
|
143
151
|
const scpClient = await getScpClient();
|
|
144
|
-
|
|
152
|
+
log(`scp: ${srcFilePath} -> ${TEST_SERVER_HOST}:${destPath}`);
|
|
145
153
|
await scpClient.uploadFile(srcFilePath, destPath);
|
|
146
|
-
|
|
154
|
+
log(`scp done.`);
|
|
147
155
|
process.exit(0);
|
|
156
|
+
} else if (command === "pipeline") {
|
|
157
|
+
const pipelineName = process.argv[3];
|
|
158
|
+
if (!pipelineName) {
|
|
159
|
+
log(`pipeline参数不能为空`);
|
|
160
|
+
process.exit(1);
|
|
161
|
+
}
|
|
162
|
+
try {
|
|
163
|
+
await triggerPipeline(pipelineName);
|
|
164
|
+
process.exit(0);
|
|
165
|
+
} catch (error) {
|
|
166
|
+
log(`触发流水线失败: ${error}`);
|
|
167
|
+
process.exit(1);
|
|
168
|
+
}
|
|
169
|
+
|
|
148
170
|
}
|
|
149
171
|
try {
|
|
150
172
|
const workDir = process.cwd(); // 当前项目根目录
|
|
151
173
|
const mode = process.argv[2] === 'prod' ? 'prod' : 'test'; // 部署环境
|
|
152
|
-
|
|
153
|
-
|
|
174
|
+
log(`deploy mode: ${mode}`);
|
|
175
|
+
log(`workDir: ${workDir}`);
|
|
154
176
|
|
|
155
177
|
// 读取配置
|
|
156
178
|
const config = await loadConfig();
|
|
157
|
-
//
|
|
179
|
+
// log(`config`, config);
|
|
158
180
|
|
|
159
181
|
// 检查配置格式
|
|
160
182
|
if (!config.assets || !config.assets.dest || !config.entry || !config.entry.dest) {
|
|
161
|
-
|
|
183
|
+
log(`配置格式错误, 请检查deploy.config.js或deploy.config.json`);
|
|
162
184
|
return;
|
|
163
185
|
}
|
|
164
186
|
|
|
165
187
|
const result = hasChangeMe(JSON.stringify(config));
|
|
166
188
|
if (result) {
|
|
167
|
-
|
|
189
|
+
log(`配置中存在默认值(CHANGE_ME), 请先修改配置`);
|
|
168
190
|
process.exit(1);
|
|
169
191
|
}
|
|
170
192
|
|
|
@@ -186,12 +208,12 @@ async function main() {
|
|
|
186
208
|
const assetsDest = join(workDir, config.assets.dest);
|
|
187
209
|
const entryDest = join(workDir, config.entry.dest);
|
|
188
210
|
if (!fs.existsSync(assetsDest)) {
|
|
189
|
-
|
|
211
|
+
log(`assets.dest路径不存在: ${assetsDest}, 请先创建`);
|
|
190
212
|
return;
|
|
191
213
|
}
|
|
192
214
|
// entry.dest
|
|
193
215
|
if (needHandleEntry && !fs.existsSync(entryDest)) {
|
|
194
|
-
|
|
216
|
+
log(`entry.dest路径不存在: ${entryDest}, 请先创建`);
|
|
195
217
|
return;
|
|
196
218
|
}
|
|
197
219
|
|
|
@@ -199,7 +221,7 @@ async function main() {
|
|
|
199
221
|
const assetsGit = simpleGit(assetsDest);
|
|
200
222
|
let assetsStatus = await assetsGit.status();
|
|
201
223
|
if (!assetsStatus.isClean()) {
|
|
202
|
-
|
|
224
|
+
log(`${assetsDest}目前有未提交内容, 请先处理`);
|
|
203
225
|
return;
|
|
204
226
|
}
|
|
205
227
|
|
|
@@ -209,7 +231,7 @@ async function main() {
|
|
|
209
231
|
entryGit = simpleGit(entryDest);
|
|
210
232
|
entryStatus = await entryGit.status();
|
|
211
233
|
if (!entryStatus.isClean()) {
|
|
212
|
-
|
|
234
|
+
log(`${entryDest}目前有未提交内容, 请先处理`);
|
|
213
235
|
return;
|
|
214
236
|
}
|
|
215
237
|
}
|
|
@@ -219,11 +241,11 @@ async function main() {
|
|
|
219
241
|
// const currentGit = simpleGit(workDir);
|
|
220
242
|
// const currentStatus = await currentGit.status();
|
|
221
243
|
// if (!currentStatus.isClean()) {
|
|
222
|
-
//
|
|
244
|
+
// log(`当前项目有未提交内容, 请先处理`);
|
|
223
245
|
// process.exit(1);
|
|
224
246
|
// }
|
|
225
247
|
// if (currentStatus.branch !== currentProdBranch) {
|
|
226
|
-
//
|
|
248
|
+
// log(`当前项目分支${currentStatus.branch}不是${currentProdBranch}分支, 请切换至${currentProdBranch}分支再执行prod命令`);
|
|
227
249
|
// process.exit(1);
|
|
228
250
|
// }
|
|
229
251
|
// }
|
|
@@ -231,14 +253,14 @@ async function main() {
|
|
|
231
253
|
// 3. 检查assets项目分支,并切换至master分支
|
|
232
254
|
// assets项目固定使用master分支
|
|
233
255
|
if (assetsStatus.current !== "master") {
|
|
234
|
-
|
|
256
|
+
log(`${assetsDest}当前分支不是master, 切换至master分支`);
|
|
235
257
|
await assetsGit.checkout("master");
|
|
236
|
-
|
|
258
|
+
log(`${assetsDest}切换至master分支成功`);
|
|
237
259
|
}
|
|
238
260
|
if (needHandleEntry && entryStatus.current !== entryTargetBranch) {
|
|
239
|
-
|
|
261
|
+
log(`${entryDest}当前分支不是${entryTargetBranch}, 切换至${entryTargetBranch}分支`);
|
|
240
262
|
await entryGit.checkout(entryTargetBranch);
|
|
241
|
-
|
|
263
|
+
log(`${entryDest}切换至${entryTargetBranch}分支成功`);
|
|
242
264
|
}
|
|
243
265
|
|
|
244
266
|
// 4. 执行git pull
|
|
@@ -254,7 +276,7 @@ async function main() {
|
|
|
254
276
|
for (const [src, dest] of Object.entries(assetsFiles)) {
|
|
255
277
|
const srcPath = join(workDir, src);
|
|
256
278
|
if (!fs.existsSync(srcPath)) {
|
|
257
|
-
|
|
279
|
+
log(`${srcPath}不存在,请确认构建产物是否正确`);
|
|
258
280
|
return;
|
|
259
281
|
}
|
|
260
282
|
const destPath = join(assetsDest, dest);
|
|
@@ -263,28 +285,28 @@ async function main() {
|
|
|
263
285
|
} else {
|
|
264
286
|
fs.copyFileSync(srcPath, destPath);
|
|
265
287
|
}
|
|
266
|
-
|
|
288
|
+
log(`assets copy: ${srcPath} -> ${destPath}`);
|
|
267
289
|
assetsFilesCount++;
|
|
268
290
|
}
|
|
269
|
-
//
|
|
291
|
+
// log(`assets copy done.`);
|
|
270
292
|
// 5.2 复制entry
|
|
271
293
|
if (needHandleEntry) {
|
|
272
294
|
const entryFiles = config.entry.files;
|
|
273
295
|
for (const [src, dest] of Object.entries(entryFiles)) {
|
|
274
296
|
const srcPath = join(workDir, src);
|
|
275
297
|
if (!fs.existsSync(srcPath)) {
|
|
276
|
-
|
|
298
|
+
log(`${srcPath}不存在,请确认构建产物是否正确`);
|
|
277
299
|
return;
|
|
278
300
|
}
|
|
279
301
|
if (fs.statSync(srcPath).isDirectory()) {
|
|
280
|
-
|
|
302
|
+
log(`entry: ${srcPath}是目录,不支持entry为目录的部署`);
|
|
281
303
|
return;
|
|
282
304
|
}
|
|
283
305
|
const destPath = join(entryDest, dest);
|
|
284
306
|
fs.copyFileSync(srcPath, destPath);
|
|
285
|
-
|
|
307
|
+
log(`entry copy: ${srcPath} -> ${destPath}`);
|
|
286
308
|
}
|
|
287
|
-
//
|
|
309
|
+
// log(`entry copy done.`);
|
|
288
310
|
}
|
|
289
311
|
|
|
290
312
|
// 6. 提交
|
|
@@ -296,10 +318,10 @@ async function main() {
|
|
|
296
318
|
await assetsGit.add(".");
|
|
297
319
|
const assetsCommit = `${config.assets.commit || "feat:部署资源文件"} by deploy-helper`;
|
|
298
320
|
const assetsCommitResult = await assetsGit.commit(assetsCommit);
|
|
299
|
-
|
|
300
|
-
|
|
321
|
+
log(`assets commit: ${assetsCommit}`);
|
|
322
|
+
log(`assets commit: ${JSON.stringify(assetsCommitResult.summary)}`);
|
|
301
323
|
} else {
|
|
302
|
-
|
|
324
|
+
log(`${assetsDest} 未发现修改内容,跳过提交`);
|
|
303
325
|
}
|
|
304
326
|
|
|
305
327
|
if (needHandleEntry) {
|
|
@@ -309,10 +331,10 @@ async function main() {
|
|
|
309
331
|
await entryGit.add(".");
|
|
310
332
|
const entryCommit = `${config.entry.commit || "feat:部署入口文件"} by deploy-helper`;
|
|
311
333
|
const entryCommitResult = await entryGit.commit(entryCommit);
|
|
312
|
-
|
|
313
|
-
|
|
334
|
+
log(`entry commit: ${entryCommit}`);
|
|
335
|
+
log(`entry commit: ${JSON.stringify(entryCommitResult.summary)}`);
|
|
314
336
|
} else {
|
|
315
|
-
|
|
337
|
+
log(`${entryDest} 未发现修改内容,跳过提交`);
|
|
316
338
|
}
|
|
317
339
|
}
|
|
318
340
|
|
|
@@ -323,7 +345,7 @@ async function main() {
|
|
|
323
345
|
} catch (error) {
|
|
324
346
|
await assetsGit.push();
|
|
325
347
|
}
|
|
326
|
-
|
|
348
|
+
log(`assets push done.`);
|
|
327
349
|
}
|
|
328
350
|
if (canPushEntry) {
|
|
329
351
|
try {
|
|
@@ -331,7 +353,7 @@ async function main() {
|
|
|
331
353
|
} catch (error) {
|
|
332
354
|
await entryGit.push();
|
|
333
355
|
}
|
|
334
|
-
|
|
356
|
+
log(`entry push done.`);
|
|
335
357
|
}
|
|
336
358
|
|
|
337
359
|
try {
|
|
@@ -342,15 +364,15 @@ async function main() {
|
|
|
342
364
|
for (const [src, dest] of Object.entries(syncTestFiles)) {
|
|
343
365
|
const srcPath = join(workDir, src);
|
|
344
366
|
const destPath = "/home/web/website/tuwan_www/templets/static/play/" + dest;
|
|
345
|
-
|
|
367
|
+
log(`scp: ${srcPath} -> ${TEST_SERVER_HOST}:${destPath}`);
|
|
346
368
|
await scpClient.uploadFile(srcPath, destPath)
|
|
347
369
|
}
|
|
348
370
|
}
|
|
349
371
|
} catch (error) {
|
|
350
|
-
|
|
351
|
-
|
|
372
|
+
log(`scp error: ${error}`);
|
|
373
|
+
log(`复制文件到测试环境服务器失败, 建议配置本机ssh免密登录, 参考地址:https://foochane.cn/article/2019061601.html`);
|
|
352
374
|
if (assetsFilesCount > 0) {
|
|
353
|
-
|
|
375
|
+
log(`不过请放心,构建产物的assets已经处理完成,只要手动处理index.html文件即可。`);
|
|
354
376
|
}
|
|
355
377
|
process.exit(1);
|
|
356
378
|
}
|
|
@@ -359,11 +381,11 @@ async function main() {
|
|
|
359
381
|
// 处理触发流水线的任务
|
|
360
382
|
await runPipeline(config, mode);
|
|
361
383
|
|
|
362
|
-
|
|
384
|
+
log(`deploy-helper deploy done.`);
|
|
363
385
|
process.exit(0);
|
|
364
386
|
|
|
365
387
|
} catch (error) {
|
|
366
|
-
|
|
388
|
+
log(`error occurred in deploy-helper`, error);
|
|
367
389
|
process.exit(1);
|
|
368
390
|
}
|
|
369
391
|
}
|
package/lib/pipelineApi.mjs
CHANGED
|
@@ -2,8 +2,9 @@ import { homedir } from 'node:os';
|
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import fs from 'node:fs';
|
|
4
4
|
import simpleGit from 'simple-git';
|
|
5
|
+
import { log, isDebug } from './util.mjs';
|
|
5
6
|
|
|
6
|
-
import { createPipelineRunFunc,
|
|
7
|
+
import { createPipelineRunFunc, listPipelinesFunc, getPipelineFunc } from '../modules/alibabacloud-devops-mcp-server/dist/operations/flow/pipeline.js'
|
|
7
8
|
|
|
8
9
|
export const organizationId = "5ec8bb7bd1d1abe63b55cd33";
|
|
9
10
|
|
|
@@ -35,7 +36,7 @@ export function getYunxiaoToken(pipelineConfig) {
|
|
|
35
36
|
if (devToken) {
|
|
36
37
|
if (isFirstFoundToken) {
|
|
37
38
|
isFirstFoundToken = false;
|
|
38
|
-
|
|
39
|
+
log(`将使用devToken`);
|
|
39
40
|
}
|
|
40
41
|
return devToken;
|
|
41
42
|
}
|
|
@@ -45,7 +46,7 @@ export function getYunxiaoToken(pipelineConfig) {
|
|
|
45
46
|
if (token) {
|
|
46
47
|
if (isFirstFoundToken) {
|
|
47
48
|
isFirstFoundToken = false;
|
|
48
|
-
|
|
49
|
+
log(`将使用来自环境变量YUNXIAO_ACCESS_TOKEN的云效token`);
|
|
49
50
|
}
|
|
50
51
|
return token;
|
|
51
52
|
}
|
|
@@ -62,7 +63,7 @@ export function getYunxiaoToken(pipelineConfig) {
|
|
|
62
63
|
if (token) {
|
|
63
64
|
if (isFirstFoundToken) {
|
|
64
65
|
isFirstFoundToken = false;
|
|
65
|
-
|
|
66
|
+
log(`将使用来自${userDeployHelperDir}的云效token`);
|
|
66
67
|
}
|
|
67
68
|
return token;
|
|
68
69
|
}
|
|
@@ -83,14 +84,34 @@ async function getPipelineInfoByName(name) {
|
|
|
83
84
|
pipeline = pipelines.items.find(item => item.name === name);
|
|
84
85
|
}
|
|
85
86
|
} catch (error) {
|
|
86
|
-
throw new Error(`获取流水线信息失败,
|
|
87
|
+
throw new Error(`获取流水线信息失败, 请确认流水线名称:【${name}】是否正确或检查云效token的权限是否足够: ${error}`);
|
|
87
88
|
}
|
|
88
89
|
if (!pipeline) {
|
|
89
|
-
throw new Error(`未找到对应的流水线,
|
|
90
|
+
throw new Error(`未找到对应的流水线, 请确认流水线名称:【${name}】是否正确或检查云效token的权限是否足够`);
|
|
90
91
|
}
|
|
91
92
|
return pipeline;
|
|
92
93
|
}
|
|
93
94
|
|
|
95
|
+
export async function triggerPipeline(pipelineName) {
|
|
96
|
+
const yunxiaoToken = getYunxiaoToken({});
|
|
97
|
+
if(!yunxiaoToken) {
|
|
98
|
+
throw new Error(`未设置云效token, 请检查云效token是否正确`);
|
|
99
|
+
}
|
|
100
|
+
let pipelineID = "";
|
|
101
|
+
let name = pipelineName;
|
|
102
|
+
if(/^\d+$/.test(pipelineName)) {
|
|
103
|
+
pipelineID = pipelineName;
|
|
104
|
+
const pipelineInfo = await getPipelineFunc(organizationId, pipelineID);
|
|
105
|
+
name = pipelineInfo.name;
|
|
106
|
+
} else {
|
|
107
|
+
const pipelineInfo = await getPipelineInfoByName(pipelineName);
|
|
108
|
+
pipelineID = pipelineInfo.id;
|
|
109
|
+
name = pipelineInfo.name;
|
|
110
|
+
}
|
|
111
|
+
const runId = await createPipelineRunFunc(organizationId, pipelineID, {});
|
|
112
|
+
const pipelineRunDetailUrl = `https://flow.aliyun.com/pipelines/${pipelineID}/builds/${runId}`;
|
|
113
|
+
log(`流水线${name}[${pipelineID}]触发成功,流水线执行id: ${runId}, 流水线执行详情: ${pipelineRunDetailUrl}`);
|
|
114
|
+
}
|
|
94
115
|
|
|
95
116
|
|
|
96
117
|
/**
|
|
@@ -125,14 +146,14 @@ export function checkYunxiaoToken(config, mode) {
|
|
|
125
146
|
}
|
|
126
147
|
|
|
127
148
|
async function runSinglePipeline(pipeline, index, total) {
|
|
128
|
-
|
|
149
|
+
log(`开始处理流水线: ${pipeline.name}, 当前是第${index + 1}个, 总共${total}个`);
|
|
129
150
|
let pipelineId = pipeline.id || "";
|
|
130
151
|
if (!pipelineId) {
|
|
131
152
|
// 获取流水线信息
|
|
132
153
|
const pipelineInfo = await getPipelineInfoByName(pipeline.name);
|
|
133
154
|
pipelineId = pipelineInfo.id;
|
|
134
155
|
}
|
|
135
|
-
|
|
156
|
+
log(`流水线${pipeline.name}的id: ${pipelineId}`);
|
|
136
157
|
|
|
137
158
|
// 处理分支强推的问题
|
|
138
159
|
const force2Branch = pipeline.force2Branch;
|
|
@@ -140,32 +161,32 @@ async function runSinglePipeline(pipeline, index, total) {
|
|
|
140
161
|
let repo = pipeline.repo || "./";
|
|
141
162
|
repo = join(process.cwd(), repo);
|
|
142
163
|
if (!fs.existsSync(repo)) {
|
|
143
|
-
|
|
164
|
+
log(`仓库${repo}有未提交的修改, 跳过流水线处理`);
|
|
144
165
|
return;
|
|
145
166
|
}
|
|
146
167
|
// 强推到指定分支
|
|
147
168
|
const git = simpleGit(repo);
|
|
148
169
|
const gitStatus = await git.status();
|
|
149
170
|
if (!gitStatus.isClean()) {
|
|
150
|
-
|
|
171
|
+
log(`仓库${repo}有未提交的修改, 跳过流水线处理`);
|
|
151
172
|
return;
|
|
152
173
|
}
|
|
153
174
|
if (gitStatus.current !== force2Branch.src) {
|
|
154
|
-
|
|
175
|
+
log(`仓库${repo}当前分支不是${force2Branch.src}, 切换到${force2Branch.src}`);
|
|
155
176
|
await git.checkout(force2Branch.src);
|
|
156
|
-
|
|
177
|
+
log(`仓库${repo}切换到${force2Branch.src}完成`);
|
|
157
178
|
}
|
|
158
179
|
await git.pull();
|
|
159
180
|
await git.push();
|
|
160
181
|
// git push origin master-test-0513:test --force
|
|
161
182
|
await git.raw("push", "origin", `${force2Branch.src}:${force2Branch.dest}`, "--force");
|
|
162
|
-
|
|
183
|
+
log(`仓库${repo}强推${force2Branch.src}到${force2Branch.dest}完成`);
|
|
163
184
|
}
|
|
164
185
|
// TODO: PERF: 获取流水线信息后, 可以缓存下来, 避免每次都重新获取
|
|
165
186
|
// TODO: 触发流水线时, 可以传入参数, 比如分支, 比如环境, 但是不知道为什么覆盖不了。这里先不传了
|
|
166
187
|
const runId = await createPipelineRunFunc(organizationId, pipelineId, {});
|
|
167
188
|
const piplineRunDetailUrl = `https://flow.aliyun.com/pipelines/${pipelineId}/builds/${runId}`;
|
|
168
|
-
|
|
189
|
+
log(`流水线${pipeline.name}触发成功,流水线执行id: ${runId}, 流水线执行详情: ${piplineRunDetailUrl}`);
|
|
169
190
|
}
|
|
170
191
|
|
|
171
192
|
export async function runPipeline(config, mode) {
|
|
@@ -176,7 +197,7 @@ export async function runPipeline(config, mode) {
|
|
|
176
197
|
}
|
|
177
198
|
const token = getYunxiaoToken(pipelineConfig);
|
|
178
199
|
if (!token) {
|
|
179
|
-
|
|
200
|
+
log(`未设置云效token, 此次流水线未自动执行: ${JSON.stringify(pipelineConfig)}`);
|
|
180
201
|
}
|
|
181
202
|
process.env.YUNXIAO_ACCESS_TOKEN = token;
|
|
182
203
|
|
package/lib/util.mjs
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
let _isDebug = false;
|
|
2
|
+
export function setDebug(debug) {
|
|
3
|
+
_isDebug = debug;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function isDebug() {
|
|
7
|
+
return _isDebug;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function log(...args) {
|
|
11
|
+
if (_isDebug) {
|
|
12
|
+
// 打印时间
|
|
13
|
+
console.log(`[${new Date().toLocaleString()}]`, ...args);
|
|
14
|
+
} else {
|
|
15
|
+
console.log(...args);
|
|
16
|
+
}
|
|
17
|
+
}
|