long-git-cli
Version:
A CLI tool for Git tag management.
342 lines • 14.5 kB
JavaScript
;
/**
* 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