long-git-cli
Version:
A CLI tool for Git tag management.
170 lines • 7.26 kB
JavaScript
;
/**
* Pipeline 监听器
* 用于监听 Bitbucket Pipeline 的执行状态
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.PipelineMonitor = void 0;
/**
* Pipeline 监听器类
*/
class PipelineMonitor {
constructor(bitbucketClient) {
this.bitbucketClient = bitbucketClient;
}
/**
* 监听 Build Status(用于 AWS CodeBuild 等外部构建系统)
* @param workspace Bitbucket workspace
* @param repoSlug 仓库 slug
* @param tagName Tag 名称
* @param options 等待选项
* @returns Build status
*/
async monitorBuildStatus(workspace, repoSlug, tagName, options = {}) {
const { pollInterval = 15000, // 默认 15 秒
timeout = 30 * 60 * 1000, // 默认 30 分钟
onProgress, } = options;
const startTime = Date.now();
console.log(`获取 tag ${tagName} 的 commit hash...`);
/** 获取 tag 对应的 commit hash */
const commitHash = await this.bitbucketClient.getTagCommit(workspace, repoSlug, tagName);
console.log(`Commit hash: ${commitHash.substring(0, 7)}`);
console.log(`等待 build status 出现...`);
/** 等待 build status 出现(最多等待 2 分钟) */
let buildStatuses = [];
const maxWaitTime = 2 * 60 * 1000; // 2 分钟
const checkInterval = 5000; // 5 秒检查一次
while (buildStatuses.length === 0 && Date.now() - startTime < maxWaitTime) {
buildStatuses = await this.bitbucketClient.getCommitBuildStatus(workspace, repoSlug, commitHash);
if (buildStatuses.length === 0) {
console.log(`Build status 尚未出现,等待 ${checkInterval / 1000} 秒后重试...`);
await this.sleep(checkInterval);
}
}
if (buildStatuses.length === 0) {
throw new Error(`未找到 commit ${commitHash.substring(0, 7)} 的 build status,可能构建尚未触发`);
}
console.log(`开始监听 build status...`);
/** 轮询 build status */
while (true) {
/** 检查超时 */
if (Date.now() - startTime > timeout) {
throw new Error(`Build status 监听超时 (${timeout / 1000}秒)`);
}
/** 获取最新状态 */
buildStatuses = await this.bitbucketClient.getCommitBuildStatus(workspace, repoSlug, commitHash);
/** 检查是否所有 build 都完成 */
const allCompleted = buildStatuses.every((status) => {
return ['SUCCESSFUL', 'FAILED', 'STOPPED'].includes(status.state);
});
const anyFailed = buildStatuses.some((status) => {
return status.state === 'FAILED';
});
/** 调用进度回调 */
if (onProgress) {
onProgress({ statuses: buildStatuses });
}
console.log(`Build status: ${buildStatuses.map((s) => `${s.name || s.key}=${s.state}`).join(', ')} (${this.getElapsedTime(startTime)})`);
if (allCompleted) {
if (anyFailed) {
throw new Error(`构建失败`);
}
console.log(`所有构建已完成`);
return buildStatuses;
}
/** 等待下一次轮询 */
await this.sleep(pollInterval);
}
}
/**
* 监听指定 tag 的 Pipeline 状态
* @param workspace Bitbucket workspace
* @param repoSlug 仓库 slug
* @param tagName tag 名称
* @param options 等待选项
* @returns Pipeline 最终状态
*/
async monitorPipeline(workspace, repoSlug, tagName, options = {}) {
const { pollInterval = 15000, // 默认 15 秒
timeout = 30 * 60 * 1000, // 默认 30 分钟
onProgress, } = options;
const startTime = Date.now();
console.log(`等待 Pipeline 被触发...`);
/** 等待 Pipeline 被触发(最多等待 2 分钟) */
let pipeline = null;
const maxWaitTime = 2 * 60 * 1000; // 2 分钟
const checkInterval = 5000; // 5 秒检查一次
while (!pipeline && Date.now() - startTime < maxWaitTime) {
pipeline = await this.findPipelineByTag(workspace, repoSlug, tagName);
if (!pipeline) {
console.log(`Pipeline 尚未触发,等待 ${checkInterval / 1000} 秒后重试...`);
await new Promise(resolve => setTimeout(resolve, checkInterval));
}
}
if (!pipeline) {
throw new Error(`未找到 tag "${tagName}" 的 Pipeline,可能 Bitbucket 未配置自动触发 Pipeline`);
}
console.log(`开始监听 Pipeline: ${pipeline.uuid} (tag: ${tagName})`);
/** 轮询 Pipeline 状态 */
while (true) {
/** 检查超时 */
if (Date.now() - startTime > timeout) {
throw new Error(`Pipeline 监听超时 (${timeout / 1000}秒),当前状态: ${pipeline.state.name}`);
}
/** 获取最新状态 */
const status = await this.bitbucketClient.getPipelineStatus(workspace, repoSlug, pipeline.uuid);
/** 调用进度回调 */
if (onProgress) {
onProgress(status);
}
console.log(`Pipeline 状态: ${status.state.name} (${this.getElapsedTime(startTime)})`);
/** 判断是否完成 */
if (this.isPipelineCompleted(status)) {
if (status.state.name === "SUCCESSFUL") {
console.log(`Pipeline 执行成功`);
return status;
}
else if (status.state.name === "FAILED") {
throw new Error(`Pipeline 执行失败: ${status.state.result?.name || "未知原因"}`);
}
else if (status.state.name === "STOPPED") {
throw new Error(`Pipeline 已停止`);
}
}
/** 等待下一次轮询 */
await this.sleep(pollInterval);
}
}
/**
* 根据 tag 名称查找 Pipeline
*/
async findPipelineByTag(workspace, repoSlug, tagName) {
const pipelines = await this.bitbucketClient.getPipelinesByTag(workspace, repoSlug, tagName);
/** 返回最新的 Pipeline(已按创建时间倒序排序) */
return pipelines.length > 0 ? pipelines[0] : null;
}
/**
* 判断 Pipeline 是否已完成
*/
isPipelineCompleted(status) {
const completedStates = ["SUCCESSFUL", "FAILED", "STOPPED"];
return completedStates.includes(status.state.name);
}
/**
* 获取已用时间(格式化)
*/
getElapsedTime(startTime) {
const elapsed = Math.floor((Date.now() - startTime) / 1000);
const minutes = Math.floor(elapsed / 60);
const seconds = elapsed % 60;
return `${minutes}分${seconds}秒`;
}
/**
* 睡眠指定毫秒数
*/
sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
}
exports.PipelineMonitor = PipelineMonitor;
//# sourceMappingURL=pipeline-monitor.js.map