UNPKG

long-git-cli

Version:

A CLI tool for Git tag management.

342 lines 14.5 kB
"use strict"; /** * Deploy 命令 * 专门为 frontend-msg-admin 项目定制的快速部署工具 */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.deployCommand = deployCommand; const chalk_1 = __importDefault(require("chalk")); const inquirer_1 = __importDefault(require("inquirer")); const config_manager_1 = require("../devops/config/config-manager"); const bitbucket_client_1 = require("../devops/api/bitbucket-client"); const jenkins_client_1 = require("../devops/api/jenkins-client"); const pipeline_monitor_1 = require("../devops/monitor/pipeline-monitor"); const jenkins_deployer_1 = require("../devops/deployer/jenkins-deployer"); const tag_1 = require("./tag"); const simple_git_1 = require("simple-git"); const git = (0, simple_git_1.simpleGit)(); // 硬编码配置 const DEPLOY_CONFIG = { project: { workspace: "vantagefxcrm", repoSlug: "frontend-msg-admin", repoUrl: "https://bitbucket.org/vantagefxcrm/frontend-msg-admin", tagFormat: "test-v00.00.0000", }, bitbucket: { baseUrl: "https://bitbucket.org/vantagefxcrm/frontend-msg-admin", }, jenkins: { baseUrl: "https://jenkins.app-alpha.com", }, environments: [ { id: 1, name: "test-01", jenkinsJob: "app-test-hy-service/frontend-msg-admin", }, { id: 2, name: "test-02", jenkinsJob: "app-test-hy-service/frontend-msg-admin2", }, { id: 3, name: "test-03", jenkinsJob: "app-test-hy-service/frontend-msg-admin3", }, { id: 4, name: "test-04", jenkinsJob: "app-test-hy-service/frontend-msg-admin4", }, ], }; /** * Deploy 命令处理函数 */ async function deployCommand(options) { // 添加 SIGINT 处理 process.on("SIGINT", () => { console.log(chalk_1.default.yellow("\n\n部署已中断")); console.log(chalk_1.default.gray("注意: 已触发的构建和部署可能仍在进行中")); process.exit(0); }); try { console.log(chalk_1.default.cyan("Frontend Msg Admin 部署工具\n")); // 1. 检查配置 const configManager = new config_manager_1.ConfigManager(); const hasConfig = await configManager.configExists(); if (!hasConfig) { console.log(chalk_1.default.yellow("未找到配置,需要配置 API Token\n")); // 交互式输入 Bitbucket Token console.log(chalk_1.default.cyan("配置 Bitbucket API Token")); const bitbucketAnswers = await inquirer_1.default.prompt([ { type: "input", name: "username", message: "Bitbucket 用户名 (邮箱):", validate: (input) => (input.trim() ? true : "用户名不能为空"), }, { type: "password", name: "token", message: "Bitbucket API Token:", validate: (input) => (input.trim() ? true : "Token 不能为空"), }, ]); // 保存 Bitbucket 配置 await configManager.updateBitbucketConfig(bitbucketAnswers.username, bitbucketAnswers.token); console.log(chalk_1.default.green("Bitbucket 配置已保存\n")); // 交互式输入 Jenkins Token console.log(chalk_1.default.cyan("配置 Jenkins API Token")); const jenkinsAnswers = await inquirer_1.default.prompt([ { type: "input", name: "username", message: "Jenkins 用户名:", validate: (input) => (input.trim() ? true : "用户名不能为空"), }, { type: "password", name: "token", message: "Jenkins API Token:", validate: (input) => (input.trim() ? true : "Token 不能为空"), }, ]); // 保存 Jenkins 配置 await configManager.addJenkinsInstance("app", DEPLOY_CONFIG.jenkins.baseUrl, jenkinsAnswers.username, jenkinsAnswers.token); console.log(chalk_1.default.green("Jenkins 配置已保存\n")); } const config = await configManager.loadConfig(); // 验证配置完整性 if (!config.bitbucket?.username || !config.bitbucket?.appPasswordHash) { console.log(chalk_1.default.yellow("Bitbucket 配置不完整")); console.log(chalk_1.default.cyan("请运行 long config 完成配置\n")); return; } // 查找 app 类型的 Jenkins 实例 const jenkinsConfig = config.jenkins?.find((j) => j.type === "app"); if (!jenkinsConfig) { console.log(chalk_1.default.yellow("未找到 Jenkins (app) 配置")); console.log(chalk_1.default.cyan("请运行 long config 添加 Jenkins 配置\n")); return; } // 如果是测试连接模式 if (options.test) { await testConnections(configManager, config, jenkinsConfig); return; } // 2. 选择环境 let envId = options.env; if (!envId) { const answer = await inquirer_1.default.prompt([ { type: "list", name: "envId", message: "选择部署环境:", choices: DEPLOY_CONFIG.environments.map((env) => ({ name: `${env.id}. ${env.name} (${env.jenkinsJob})`, value: env.id, })), }, ]); envId = answer.envId; } const environment = DEPLOY_CONFIG.environments.find((e) => e.id === envId); if (!environment) { console.log(chalk_1.default.red(`错误: 环境 ${envId} 不存在`)); console.log(chalk_1.default.yellow("可用环境: 1, 2, 3, 4")); return; } console.log(chalk_1.default.gray(`\n部署到: ${environment.name}`)); console.log(chalk_1.default.gray(`Jenkins Job: ${environment.jenkinsJob}\n`)); // 3. 验证仓库路径 let isGitRepo = false; let isLocalRepo = false; try { isGitRepo = await git.checkIsRepo(); } catch { isGitRepo = false; } if (isGitRepo) { try { const remotes = await git.getRemotes(true); const originUrl = remotes.find((r) => r.name === "origin")?.refs.fetch || ""; isLocalRepo = originUrl.includes(DEPLOY_CONFIG.project.repoSlug); } catch { isLocalRepo = false; } } // 4. 创建 Tag let tagName; if (isLocalRepo) { console.log(chalk_1.default.cyan("[1/4] 创建 Tag (本地 Git)")); // 复用 long tag 命令 await (0, tag_1.tagCommand)({ pass: true }); // 获取最新 tag const tags = await git.tags(); tagName = tags.latest || ""; console.log(chalk_1.default.green(` Tag 已创建: ${tagName}\n`)); } else { console.log(chalk_1.default.cyan("[1/4] 创建 Tag (Bitbucket API)")); // 询问分支 const branchAnswer = await inquirer_1.default.prompt([ { type: "input", name: "branch", message: "要从哪个分支创建 tag:", validate: (input) => (input.trim() ? true : "分支名称不能为空"), }, ]); // 通过 API 创建 tag const bitbucketToken = await configManager.getBitbucketPassword(); if (!bitbucketToken) { throw new Error("未找到 Bitbucket Token"); } const bitbucketClient = new bitbucket_client_1.BitbucketClient(config.bitbucket.username, bitbucketToken); // 获取分支最新 commit const commitHash = await bitbucketClient.getBranchLatestCommit(DEPLOY_CONFIG.project.workspace, DEPLOY_CONFIG.project.repoSlug, branchAnswer.branch); // 生成 tag 名称 tagName = await generateNextTag(bitbucketClient); // 创建 tag await bitbucketClient.createTag(DEPLOY_CONFIG.project.workspace, DEPLOY_CONFIG.project.repoSlug, tagName, commitHash); console.log(chalk_1.default.green(` Tag 已创建: ${tagName}\n`)); } // 5. 监听构建状态 console.log(chalk_1.default.cyan("[2/4] 监听构建状态")); const bitbucketToken = await configManager.getBitbucketPassword(); if (!bitbucketToken) { throw new Error("未找到 Bitbucket Token"); } const bitbucketClient = new bitbucket_client_1.BitbucketClient(config.bitbucket.username, bitbucketToken); const pipelineMonitor = new pipeline_monitor_1.PipelineMonitor(bitbucketClient); await pipelineMonitor.monitorBuildStatus(DEPLOY_CONFIG.project.workspace, DEPLOY_CONFIG.project.repoSlug, tagName); console.log(chalk_1.default.green(" 构建完成\n")); // 6. 触发 Jenkins 部署 console.log(chalk_1.default.cyan("[3/4] 触发 Jenkins 部署")); const jenkinsToken = await configManager.getJenkinsToken("app"); if (!jenkinsToken) { throw new Error("未找到 Jenkins Token"); } const jenkinsClient = new jenkins_client_1.JenkinsClient(DEPLOY_CONFIG.jenkins.baseUrl, jenkinsConfig.username, jenkinsToken); const jenkinsDeployer = new jenkins_deployer_1.JenkinsDeployer(jenkinsClient); console.log(chalk_1.default.cyan("[4/4] 监听部署状态")); const buildInfo = await jenkinsDeployer.deploy(environment.jenkinsJob, { TAG_VERSION: tagName, action: "approve", }); // 7. 显示结果 console.log(chalk_1.default.green("\n部署成功!\n")); console.log(chalk_1.default.hex('#FFA500')(`Tag: ${tagName}`)); console.log(chalk_1.default.hex('#FFA500')(`Jenkins 构建: #${buildInfo.number} - ${buildInfo.result}`)); console.log(chalk_1.default.hex('#FFA500')(`构建 URL: ${buildInfo.url}\n`)); } catch (error) { console.error(chalk_1.default.red("\n部署失败:"), error.message); process.exit(1); } } /** * 生成下一个 tag */ async function generateNextTag(client) { try { // 获取所有 test-v 开头的 tag const tags = await client.getTags(DEPLOY_CONFIG.project.workspace, DEPLOY_CONFIG.project.repoSlug); // 过滤出 test-v 开头的 tag const testTags = tags .filter((tag) => tag.name.startsWith("test-v")) .map((tag) => tag.name); if (testTags.length === 0) { return "test-v00.00.0001"; } // 解析版本号并找到最大值 let maxVersion = 0; for (const tag of testTags) { const match = tag.match(/test-v(\d+)\.(\d+)\.(\d+)/); if (match) { const version = parseInt(match[3], 10); if (version > maxVersion) { maxVersion = version; } } } // 生成新版本号 const newVersion = maxVersion + 1; const versionStr = String(newVersion).padStart(4, "0"); return `test-v00.00.${versionStr}`; } catch (error) { console.log(chalk_1.default.yellow(" 无法获取现有 tag,使用默认版本")); return "test-v00.00.0001"; } } /** * 测试 Bitbucket 和 Jenkins 连接 */ async function testConnections(configManager, config, jenkinsConfig) { console.log(chalk_1.default.cyan("测试连接\n")); let allSuccess = true; // 测试 Bitbucket 连接 console.log(chalk_1.default.cyan("[1/2] 测试 Bitbucket 连接")); console.log(chalk_1.default.gray(` URL: ${DEPLOY_CONFIG.bitbucket.baseUrl}`)); console.log(chalk_1.default.gray(` 用户名: ${config.bitbucket.username}`)); try { const bitbucketToken = await configManager.getBitbucketPassword(); if (!bitbucketToken) { throw new Error("未找到 Bitbucket Token"); } const bitbucketClient = new bitbucket_client_1.BitbucketClient(config.bitbucket.username, bitbucketToken); const success = await bitbucketClient.testConnection(); if (success) { console.log(chalk_1.default.green(" 连接成功\n")); } else { console.log(chalk_1.default.red(" 连接失败\n")); allSuccess = false; } } catch (error) { console.log(chalk_1.default.red(` 连接失败: ${error.message}\n`)); allSuccess = false; } // 测试 Jenkins 连接 console.log(chalk_1.default.cyan("[2/2] 测试 Jenkins 连接")); console.log(chalk_1.default.gray(` URL: ${DEPLOY_CONFIG.jenkins.baseUrl}`)); console.log(chalk_1.default.gray(` 用户名: ${jenkinsConfig.username}`)); try { const jenkinsToken = await configManager.getJenkinsToken("app"); if (!jenkinsToken) { throw new Error("未找到 Jenkins Token"); } const jenkinsClient = new jenkins_client_1.JenkinsClient(DEPLOY_CONFIG.jenkins.baseUrl, jenkinsConfig.username, jenkinsToken); const success = await jenkinsClient.testConnection(); if (success) { console.log(chalk_1.default.green(" 连接成功\n")); } else { console.log(chalk_1.default.red(" 连接失败\n")); allSuccess = false; } } catch (error) { console.log(chalk_1.default.red(` 连接失败: ${error.message}\n`)); allSuccess = false; } // 显示总结 if (allSuccess) { console.log(chalk_1.default.green("所有连接测试通过\n")); } else { console.log(chalk_1.default.red("部分连接测试失败,请检查配置\n")); process.exit(1); } } //# sourceMappingURL=deploy.js.map