t-comm
Version:
专业、稳定、纯粹的工具库
141 lines (124 loc) • 4.75 kB
JavaScript
/**
* @file t-comm merge-branches CLI 子命令
* @description 调用 mergeBranches 将源分支(或 commit)合并到目标分支。
*
* 支持两种使用方式:
* 1. 直接传入 MR URL(--mr <url>):自动解析 projectName,并通过 queryMRByIId 拿到
* source_branch / target_branch(以及可能的 source_project_id),然后发起合并。
* 2. 显式传参(--id, --source, --target):与原有 trial 脚本行为一致。
*/
const {
mergeBranches,
parseMRUrl,
queryMRByIId,
} = require('../lib');
/**
* 解析 MR URL,并通过 queryMRByIId 获取分支信息
* @param {string} url MR URL
* @param {object} ctx 上下文:privateToken、baseUrl
* @returns {Promise<{ projectName: string, sourceBranch: string, targetBranch: string, sourceProjectId?: number }>}
*/
async function resolveFromMrUrl(url, { privateToken, baseUrl }) {
const parsed = parseMRUrl(url);
if (!parsed) {
throw new Error(`无法从 URL 解析出 projectName 和 mrIid: ${url}`);
}
const { projectName, mrIid } = parsed;
const review = await queryMRByIId({
projectName,
mrIid,
privateToken,
baseUrl,
});
const sourceBranch = review && review.source_branch;
const targetBranch = review && review.target_branch;
if (!sourceBranch || !targetBranch) {
throw new Error(`通过 queryMRByIId 未获取到 source_branch/target_branch,请检查 MR 状态: ${url}`);
}
return {
projectName,
sourceBranch,
targetBranch,
// 跨项目 MR 时 source_project_id 与目标项目可能不同,透传给 mergeBranches
sourceProjectId: review.source_project_id,
};
}
/**
* t-comm merge-branches CLI 命令处理函数
* @param {object} options Commander 解析得到的选项
*/
async function mergeBranchesCommand(options) {
const {
mr,
id,
source,
target,
sourceProjectId,
mergeType = 'merge',
commitMessage,
privateToken,
baseUrl,
} = options;
const token = privateToken || process.env.GIT_WOA_PRIVATE_TOKEN;
const finalBaseUrl = baseUrl || process.env.GIT_WOA_BASE_URL;
if (!token) {
console.error('❌ 缺少 PRIVATE TOKEN,请通过 --private-token 或环境变量 GIT_WOA_PRIVATE_TOKEN 提供');
process.exit(1);
}
const validMergeTypes = ['merge', 'rebase', 'squash'];
if (!validMergeTypes.includes(mergeType)) {
console.error(`❌ 无效的 --merge-type "${mergeType}",可选值:${validMergeTypes.join(' | ')}`);
process.exit(1);
}
if (mergeType === 'rebase' && !commitMessage) {
console.error('❌ --merge-type=rebase 时必须通过 --commit-message 提供合并点提交信息');
process.exit(1);
}
let resolvedId = id;
let resolvedSource = source;
let resolvedTarget = target;
let resolvedSourceProjectId = sourceProjectId ? Number(sourceProjectId) : undefined;
if (mr) {
const info = await resolveFromMrUrl(mr, { privateToken: token, baseUrl: finalBaseUrl });
// MR URL 推导出的字段,仅在用户未显式覆盖时使用
resolvedId = resolvedId || info.projectName;
resolvedSource = resolvedSource || info.sourceBranch;
resolvedTarget = resolvedTarget || info.targetBranch;
if (resolvedSourceProjectId === undefined && info.sourceProjectId !== undefined) {
resolvedSourceProjectId = Number(info.sourceProjectId);
}
console.log(`🔗 已解析 MR: ${mr}`);
console.log(` 项目: ${resolvedId},源分支: ${resolvedSource} -> 目标分支: ${resolvedTarget}`);
}
if (!resolvedId || !resolvedSource || !resolvedTarget) {
console.error('❌ 缺少必要参数:--id <id>、--source <branch>、--target <branch>(或使用 --mr <url> 自动解析)');
process.exit(1);
}
// id 支持数字 ID 或项目全路径
const finalId = typeof resolvedId === 'string' && /^\d+$/.test(resolvedId)
? Number(resolvedId)
: resolvedId;
console.log(`🚀 正在合并: ${resolvedSource} -> ${resolvedTarget}`);
console.log(` 项目: ${finalId},合并方式: ${mergeType}${commitMessage ? `,提交信息: ${commitMessage}` : ''}${resolvedSourceProjectId ? `,源项目 ID: ${resolvedSourceProjectId}` : ''}`);
try {
const res = await mergeBranches({
id: finalId,
sourceObjectId: resolvedSource,
targetBranch: resolvedTarget,
mergeType,
commitMessage,
sourceProjectId: resolvedSourceProjectId,
privateToken: token,
baseUrl: finalBaseUrl,
});
console.log('✅ 合并成功:', res);
} catch (err) {
const detail = err && err.response ? err.response.data : err;
console.error('❌ 合并失败:', detail);
process.exit(1);
}
}
module.exports = {
mergeBranchesCommand,
resolveFromMrUrl,
};