long-git-cli
Version:
A CLI tool for Git tag management.
175 lines • 5.19 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.TAG_FORMATS = void 0;
exports.parseTagFormat = parseTagFormat;
exports.parseTag = parseTag;
exports.detectTagFormat = detectTagFormat;
exports.incrementVersion = incrementVersion;
exports.formatTag = formatTag;
exports.compareVersions = compareVersions;
exports.findLatestTag = findLatestTag;
exports.generateNextTag = generateNextTag;
/**
* 预定义的 Tag 格式
*/
exports.TAG_FORMATS = {
TEST: { prefix: 'test-v', pattern: '00.00.0000' },
UAT: { prefix: 'uat-v', pattern: '00.00.0000' },
PROD: { prefix: 'v', pattern: '00.00.0000' },
};
/**
* 解析 tag 格式配置
* @param format 格式字符串,如 'test-v00.00.0000'
*/
function parseTagFormat(format) {
/** 提取前缀(非数字部分) */
const match = format.match(/^([^\d]+)([\d.]+)$/);
if (!match) {
throw new Error(`无效的 tag 格式: ${format}`);
}
return {
prefix: match[1],
pattern: match[2],
};
}
/**
* 解析 tag 字符串,提取版本号信息
* @param tag tag 字符串
* @param format 可选的格式配置,如果不提供则自动检测
*/
function parseTag(tag, format) {
let prefix;
let pattern;
if (format) {
prefix = format.prefix;
pattern = format.pattern;
}
else {
/** 自动检测格式 */
const detectedFormat = detectTagFormat(tag);
if (!detectedFormat) {
throw new Error(`无法识别的 tag 格式: ${tag}`);
}
prefix = detectedFormat.prefix;
pattern = detectedFormat.pattern;
}
/** 移除前缀 */
if (!tag.startsWith(prefix)) {
throw new Error(`tag "${tag}" 不匹配前缀 "${prefix}"`);
}
const versionPart = tag.substring(prefix.length);
/** 解析版本号 */
const parts = versionPart.split('.');
if (parts.length !== 3) {
throw new Error(`无效的版本号格式: ${versionPart},期望 3 个部分`);
}
return {
version: tag,
major: parseInt(parts[0], 10),
minor: parseInt(parts[1], 10),
patch: parseInt(parts[2], 10),
build: parseInt(parts[2], 10),
};
}
/**
* 自动检测 tag 格式
*/
function detectTagFormat(tag) {
/** 尝试匹配已知格式 */
for (const format of Object.values(exports.TAG_FORMATS)) {
if (tag.startsWith(format.prefix)) {
return format;
}
}
/** 尝试通用匹配 */
const match = tag.match(/^([^\d]+)([\d.]+)$/);
if (match) {
return {
prefix: match[1],
pattern: match[2].replace(/\d/g, '0'),
};
}
return null;
}
/**
* 递增版本号,将 build 和 patch 版本号加 1
*/
function incrementVersion(tagInfo) {
return {
...tagInfo,
build: tagInfo.build + 1,
patch: tagInfo.build + 1,
};
}
/**
* 格式化版本信息为 tag 字符串
* @param tagInfo 版本信息
* @param format 格式配置
*/
function formatTag(tagInfo, format) {
const patternParts = format.pattern.split('.');
const major = tagInfo.major.toString().padStart(patternParts[0].length, '0');
const minor = tagInfo.minor.toString().padStart(patternParts[1].length, '0');
const build = tagInfo.build.toString().padStart(patternParts[2].length, '0');
return `${format.prefix}${major}.${minor}.${build}`;
}
/**
* 比较两个版本号的大小
*/
function compareVersions(a, b) {
if (a.major !== b.major)
return a.major - b.major;
if (a.minor !== b.minor)
return a.minor - b.minor;
return a.build - b.build;
}
/**
* 查找匹配格式的最新 tag
* @param tags tag 列表
* @param format 格式配置
*/
function findLatestTag(tags, format) {
/** 过滤匹配前缀的 tags */
const matchedTags = tags.filter((tag) => tag.startsWith(format.prefix));
if (matchedTags.length === 0) {
return null;
}
/** 解析并排序 */
const parsedTags = matchedTags
.map((tag) => {
try {
return parseTag(tag, format);
}
catch {
return null;
}
})
.filter((t) => t !== null);
if (parsedTags.length === 0) {
return null;
}
/** 按版本号排序,返回最新的 */
parsedTags.sort(compareVersions);
return parsedTags[parsedTags.length - 1].version;
}
/**
* 生成下一个 tag
* @param tags 现有 tag 列表
* @param format 格式配置
*/
function generateNextTag(tags, format) {
const latestTag = findLatestTag(tags, format);
if (!latestTag) {
/** 如果没有现有 tag,返回初始版本 */
const patternParts = format.pattern.split('.');
const major = '0'.repeat(patternParts[0].length);
const minor = '0'.repeat(patternParts[1].length);
const build = '1'.padStart(patternParts[2].length, '0');
return `${format.prefix}${major}.${minor}.${build}`;
}
/** 递增版本号 */
const tagInfo = parseTag(latestTag, format);
const nextTagInfo = incrementVersion(tagInfo);
return formatTag(nextTagInfo, format);
}
//# sourceMappingURL=tag.js.map