UNPKG

long-git-cli

Version:

A CLI tool for Git tag management.

170 lines 7.26 kB
"use strict"; /** * 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