import SimpleGit from 'simple-git' import { logger } from '../utils/logger' import { IReleaseOptions } from '../intf/IOptions' class ReleaseTag { /** 发布最新tag */ async releaseLatestTag(options: IReleaseOptions): Promise { const { message, push } = options try { const git = SimpleGit('./') /** 拉取最新代码, 但不合并, 用来获取最新tag */ await git.fetch() logger.info(`git fetch`) const { branches } = await git.branch() /** 获取当前分支名称 */ const currentBranchName = (() => { for (const branchName in branches) { if (branches[branchName].current) { return branchName } } })() /** 判断是否需要执行 git add . + git commit */ if (message) { await git.add('.') await git.commit(message) logger.info(`git add . && git commit -m '${message}'`) } /** 获取 tags */ const tags = await git.tags() let newTag /** 替换前缀, * 例: * feature_new_version -> release_new_version * hotfix_version -> hotfix_version * master -> release_master */ newTag = this.generateReleaseTagPrefix(currentBranchName) /** 补充时间戳 */ newTag = this.addSuffixTimestamp(newTag, tags.all) await git.addTag(newTag) logger.info(`new tag:`, newTag) await git.pushTags() logger.info(`pushed tag`) if (push) { await git.push() logger.info(`git pushed`) } } catch (error) { logger.error(`error:`, error?.message) } } /** 增加后缀时间戳及index */ addSuffixTimestamp(tag: string, tags: Array = []): string { /** 如果有后缀时间戳, skip */ if (/_[0-9]{2}[0-9]{2}[0-9]{2,3}$/.test(tag)) return tag const date = new Date() const suffix = '_' + this.valToDoubleStr(date.getMonth() + 1) + this.valToDoubleStr(date.getDate()) // 添加基本后缀 tag += suffix // 获取当前分支, 今天的上个tag const lastTag: string = tags.reduce((last, current) => { if (new RegExp(tag).test(current)) { if (last) { const lastIndex = last.match(/_[0-9]{4}([0-9]{1,})/)?.[1] const currentIndex = current.match(/_[0-9]{4}([0-9]{1,})/)?.[1] if (!lastIndex) return current else if (!currentIndex) return last else if (parseInt(currentIndex) > parseInt(lastIndex)) return current else return last } else { return current } } else { return last } }, null) if (lastTag) { const lastTagIndex = parseInt(lastTag.match(/_[0-9]{4}([0-9]{1,})/)[1]) tag += this.valToDoubleStr(lastTagIndex + 1) } else { tag += '01' } return tag } /** 数值填充 */ valToDoubleStr(val: number) { return val < 10 ? `0${val}` : val } /** 生成 release tag */ generateReleaseTagPrefix(branchName?: string): string { if (/^release_/.test(branchName)) return branchName if (/^feature_/.test(branchName)) return branchName.replace(/^feature_/, 'release_') if (/^hotfix_/.test(branchName)) return branchName // default add prefix to branch name return `release_${branchName}` } } /** 发布版本解决方案 */ export const releasePreset = async (options: IReleaseOptions) => { // 参考 c-rt await new ReleaseTag().releaseLatestTag(options) }