@taole/deploy-helper 0.3.6 → 0.4.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/index.mjs +14 -5
- package/lib/pipelineApi.mjs +110 -5
- package/lib/util.mjs +2 -2
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -88,7 +88,6 @@ async function main() {
|
|
|
88
88
|
// 默认开启debug debug目前只是打印日志的时候额外打印时间
|
|
89
89
|
setDebug(true);
|
|
90
90
|
|
|
91
|
-
log("deploy-helper start");
|
|
92
91
|
|
|
93
92
|
// await devTest();
|
|
94
93
|
// log(`process.argv: ${process.argv[2]} ${process.argv[3]} ${process.argv[4]}`);
|
|
@@ -110,9 +109,13 @@ async function main() {
|
|
|
110
109
|
console.log(`command: scp {file} {dest} 复制文件{file}到OfficialSite测试服务器{dest}`);
|
|
111
110
|
console.log(`command: scpevt {file} 复制文件{file}到events测试服务器{file}`);
|
|
112
111
|
console.log(`command: scpevt {file} {dest} 复制文件{file}到events测试服务器{dest}`);
|
|
113
|
-
log(`command: pipeline {pipelineName|pipelineId} 触发流水线{pipelineName|pipelineId}`);
|
|
112
|
+
console.log(`command: pipeline {pipelineName|pipelineId} 触发流水线{pipelineName|pipelineId}`);
|
|
114
113
|
process.exit(0);
|
|
115
|
-
}
|
|
114
|
+
}
|
|
115
|
+
log("deploy-helper start");
|
|
116
|
+
|
|
117
|
+
// 其他命令
|
|
118
|
+
if (command === "init") {
|
|
116
119
|
await initConfigJson();
|
|
117
120
|
process.exit(0);
|
|
118
121
|
} else if (["scp", "scpevt"].includes(command)) {
|
|
@@ -160,7 +163,7 @@ async function main() {
|
|
|
160
163
|
process.exit(1);
|
|
161
164
|
}
|
|
162
165
|
try {
|
|
163
|
-
await triggerPipeline(pipelineName);
|
|
166
|
+
await triggerPipeline(pipelineName, true);
|
|
164
167
|
process.exit(0);
|
|
165
168
|
} catch (error) {
|
|
166
169
|
log(`触发流水线失败: ${error}`);
|
|
@@ -196,7 +199,7 @@ async function main() {
|
|
|
196
199
|
const entryTestBranch = (config.entry && config.entry.testBranch) || "test";
|
|
197
200
|
const entryProdBranch = (config.entry && config.entry.prodBranch) || "master";
|
|
198
201
|
const entryTargetBranch = mode === 'prod' ? entryProdBranch : entryTestBranch;
|
|
199
|
-
const currentProdBranch = config.prodBranch || "master";
|
|
202
|
+
// const currentProdBranch = config.prodBranch || "master";
|
|
200
203
|
|
|
201
204
|
|
|
202
205
|
// 检查流水线配置
|
|
@@ -264,9 +267,13 @@ async function main() {
|
|
|
264
267
|
}
|
|
265
268
|
|
|
266
269
|
// 4. 执行git pull
|
|
270
|
+
log(`${assetsDest}执行git pull`);
|
|
267
271
|
await assetsGit.pull();
|
|
272
|
+
log(`${assetsDest} git pull done`);
|
|
268
273
|
if (entryGit) {
|
|
274
|
+
log(`${entryDest}执行git pull`);
|
|
269
275
|
await entryGit.pull();
|
|
276
|
+
log(`${entryDest} git pull done`);
|
|
270
277
|
}
|
|
271
278
|
|
|
272
279
|
// 5. 复制构建产物
|
|
@@ -340,6 +347,7 @@ async function main() {
|
|
|
340
347
|
|
|
341
348
|
// 7. 推送
|
|
342
349
|
if (canPushAssets) {
|
|
350
|
+
log(`assets push start`);
|
|
343
351
|
try {
|
|
344
352
|
await assetsGit.push();
|
|
345
353
|
} catch (error) {
|
|
@@ -348,6 +356,7 @@ async function main() {
|
|
|
348
356
|
log(`assets push done.`);
|
|
349
357
|
}
|
|
350
358
|
if (canPushEntry) {
|
|
359
|
+
log(`entry push start`);
|
|
351
360
|
try {
|
|
352
361
|
await entryGit.push();
|
|
353
362
|
} catch (error) {
|
package/lib/pipelineApi.mjs
CHANGED
|
@@ -3,12 +3,68 @@ import { join } from 'node:path';
|
|
|
3
3
|
import fs from 'node:fs';
|
|
4
4
|
import simpleGit from 'simple-git';
|
|
5
5
|
import { log, isDebug } from './util.mjs';
|
|
6
|
+
import { PipelineRunSchema } from "../modules/alibabacloud-devops-mcp-server/dist/common/types.js";
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
import * as utils from "../modules/alibabacloud-devops-mcp-server/dist/common/utils.js";
|
|
6
9
|
|
|
7
|
-
import { createPipelineRunFunc, listPipelinesFunc, getPipelineFunc }
|
|
10
|
+
import { createPipelineRunFunc, listPipelinesFunc, getPipelineFunc, getPipelineRunFunc }
|
|
11
|
+
from '../modules/alibabacloud-devops-mcp-server/dist/operations/flow/pipeline.js'
|
|
8
12
|
|
|
9
13
|
export const organizationId = "5ec8bb7bd1d1abe63b55cd33";
|
|
10
14
|
|
|
11
15
|
|
|
16
|
+
// docs: https://help.aliyun.com/zh/yunxiao/developer-reference/passpipelinevalidate
|
|
17
|
+
// POST https://{domain}/oapi/v1/flow/organizations/{organizationId}/pipelines/{pipelineId}/pipelineRuns/{pipelineRunId}/jobs/{jobId}/pass
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 获取当前阶段和任务
|
|
21
|
+
* @param {z.infer<typeof PipelineRunSchema>} runDetail 流水线执行详情
|
|
22
|
+
*/
|
|
23
|
+
function getCurrentJob(runDetail) {
|
|
24
|
+
let currentStage = null;
|
|
25
|
+
let currentJob = null;
|
|
26
|
+
const stages = runDetail.stages;
|
|
27
|
+
|
|
28
|
+
// 找到当前阶段
|
|
29
|
+
for(let i = 0; i < stages.length; i++) {
|
|
30
|
+
const stage = stages[i];
|
|
31
|
+
currentStage = stage;
|
|
32
|
+
const stageStatus = stage.stageInfo.status;
|
|
33
|
+
if(stageStatus === "RUNNING" || stageStatus === "WAITING" || stageStatus === "FAIL") {
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if(currentStage) {
|
|
39
|
+
const jobs = currentStage.stageInfo.jobs;
|
|
40
|
+
for(let i = 0; i < jobs.length; i++) {
|
|
41
|
+
const job = jobs[i];
|
|
42
|
+
currentJob = job;
|
|
43
|
+
const jobStatus = job.status;
|
|
44
|
+
if(jobStatus === "RUNNING" || jobStatus === "WAITING" || jobStatus === "FAIL") {
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return {stage: currentStage, job: currentJob};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* 通过人工卡点
|
|
54
|
+
* @param {*} pipelineID 流水线id
|
|
55
|
+
* @param {*} runId 流水线执行id
|
|
56
|
+
* @param {*} jobId 流水线执行任务id
|
|
57
|
+
* @returns 是否通过
|
|
58
|
+
*/
|
|
59
|
+
async function passPipelineJob(pipelineID, runId, jobId) {
|
|
60
|
+
const url = `/oapi/v1/flow/organizations/${organizationId}/pipelines/${pipelineID}/pipelineRuns/${runId}/jobs/${jobId}/pass`;
|
|
61
|
+
const response = await utils.yunxiaoRequest(url, {
|
|
62
|
+
method: "POST",
|
|
63
|
+
});
|
|
64
|
+
return Boolean(response);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
|
|
12
68
|
|
|
13
69
|
let isFirstFoundToken = true;
|
|
14
70
|
|
|
@@ -92,14 +148,57 @@ async function getPipelineInfoByName(name) {
|
|
|
92
148
|
return pipeline;
|
|
93
149
|
}
|
|
94
150
|
|
|
95
|
-
|
|
151
|
+
/**
|
|
152
|
+
* 等待流水线执行完成(尝试自行通过人工卡点)
|
|
153
|
+
* @param {string|number} pipelineID 流水线id
|
|
154
|
+
* @param {string|number} runId 流水线执行id
|
|
155
|
+
* @param {number} interval 轮询间隔时间
|
|
156
|
+
* @returns 流水线执行详情
|
|
157
|
+
*/
|
|
158
|
+
async function waitPipelineRunFinish(pipelineID, runId, interval = 3000) {
|
|
159
|
+
const pipelineRunDetailUrl = `https://flow.aliyun.com/pipelines/${pipelineID}/builds/${runId}`;
|
|
160
|
+
log(`开始轮询至流水线执行完成`);
|
|
161
|
+
let runDetail = await getPipelineRunFunc(organizationId, pipelineID, runId);
|
|
162
|
+
while (runDetail.status === "RUNNING" || runDetail.status === "WAITING") {
|
|
163
|
+
const { stage, job } = getCurrentJob(runDetail);
|
|
164
|
+
log(`流水线执行状态: ${runDetail.status},阶段: ${stage.name},任务: ${job.name},等${interval / 1000}秒后重新轮询`);
|
|
165
|
+
if (runDetail.status === "WAITING") {
|
|
166
|
+
if (stage && job) {
|
|
167
|
+
log(`尝试自动通过人工卡点`);
|
|
168
|
+
const isPass = await passPipelineJob(pipelineID, runId, job.id);
|
|
169
|
+
if (isPass) {
|
|
170
|
+
log(`人工卡点通过`);
|
|
171
|
+
} else {
|
|
172
|
+
log(`人工卡点通过失败`);
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
await new Promise(resolve => setTimeout(resolve, interval));
|
|
178
|
+
runDetail = await getPipelineRunFunc(organizationId, pipelineID, runId);
|
|
179
|
+
}
|
|
180
|
+
if (runDetail.status === "SUCCESS") {
|
|
181
|
+
log(`流水线执行完成,当前状态: ${runDetail.status}`);
|
|
182
|
+
} else {
|
|
183
|
+
log(`流水线执行失败,当前状态: ${runDetail.status}, 请查看详情${pipelineRunDetailUrl}`);
|
|
184
|
+
}
|
|
185
|
+
return runDetail;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* 触发流水线
|
|
191
|
+
* @param {*} pipelineName 流水线名称或id
|
|
192
|
+
* @param {*} waitResult 是否等待流水线执行完成
|
|
193
|
+
*/
|
|
194
|
+
export async function triggerPipeline(pipelineName, waitResult = false) {
|
|
96
195
|
const yunxiaoToken = getYunxiaoToken({});
|
|
97
|
-
if(!yunxiaoToken) {
|
|
196
|
+
if (!yunxiaoToken) {
|
|
98
197
|
throw new Error(`未设置云效token, 请检查云效token是否正确`);
|
|
99
198
|
}
|
|
100
199
|
let pipelineID = "";
|
|
101
200
|
let name = pipelineName;
|
|
102
|
-
if(/^\d+$/.test(pipelineName)) {
|
|
201
|
+
if (/^\d+$/.test(pipelineName)) {
|
|
103
202
|
pipelineID = pipelineName;
|
|
104
203
|
const pipelineInfo = await getPipelineFunc(organizationId, pipelineID);
|
|
105
204
|
name = pipelineInfo.name;
|
|
@@ -111,6 +210,9 @@ export async function triggerPipeline(pipelineName) {
|
|
|
111
210
|
const runId = await createPipelineRunFunc(organizationId, pipelineID, {});
|
|
112
211
|
const pipelineRunDetailUrl = `https://flow.aliyun.com/pipelines/${pipelineID}/builds/${runId}`;
|
|
113
212
|
log(`流水线${name}[${pipelineID}]触发成功,流水线执行id: ${runId}, 流水线执行详情: ${pipelineRunDetailUrl}`);
|
|
213
|
+
if (waitResult) {
|
|
214
|
+
await waitPipelineRunFinish(pipelineID, runId);
|
|
215
|
+
}
|
|
114
216
|
}
|
|
115
217
|
|
|
116
218
|
|
|
@@ -163,7 +265,7 @@ async function runSinglePipeline(pipeline, index, total) {
|
|
|
163
265
|
if (!fs.existsSync(repo)) {
|
|
164
266
|
log(`仓库${repo}有未提交的修改, 跳过流水线处理`);
|
|
165
267
|
return;
|
|
166
|
-
}
|
|
268
|
+
}
|
|
167
269
|
// 强推到指定分支
|
|
168
270
|
const git = simpleGit(repo);
|
|
169
271
|
const gitStatus = await git.status();
|
|
@@ -187,6 +289,9 @@ async function runSinglePipeline(pipeline, index, total) {
|
|
|
187
289
|
const runId = await createPipelineRunFunc(organizationId, pipelineId, {});
|
|
188
290
|
const piplineRunDetailUrl = `https://flow.aliyun.com/pipelines/${pipelineId}/builds/${runId}`;
|
|
189
291
|
log(`流水线${pipeline.name}触发成功,流水线执行id: ${runId}, 流水线执行详情: ${piplineRunDetailUrl}`);
|
|
292
|
+
if(pipeline.waitResult) {
|
|
293
|
+
await waitPipelineRunFinish(pipelineId, runId);
|
|
294
|
+
}
|
|
190
295
|
}
|
|
191
296
|
|
|
192
297
|
export async function runPipeline(config, mode) {
|
package/lib/util.mjs
CHANGED
|
@@ -9,8 +9,8 @@ export function isDebug() {
|
|
|
9
9
|
|
|
10
10
|
export function log(...args) {
|
|
11
11
|
if (_isDebug) {
|
|
12
|
-
// 打印时间
|
|
13
|
-
console.log(`[${new Date().
|
|
12
|
+
// 打印时间
|
|
13
|
+
console.log(`[${new Date().toLocaleTimeString()}]`, ...args);
|
|
14
14
|
} else {
|
|
15
15
|
console.log(...args);
|
|
16
16
|
}
|