scripts/release/index.ts (151 lines of code) (raw):

import ghRelease from 'gh-release' import fs from 'fs-extra' import path from 'path' import moment from 'moment' import { compareTwoStrings } from 'string-similarity' import { listCommits, lastTag, getPreviousTag, getCurrentBranch, getGithubToken, getSortableAllTags, getTaggedTime, } from './git' const LernaJSON = fs.readJSONSync(path.resolve(__dirname, '../../lerna.json')) const ReleaseTitle = 'Designable Release 🚀' const GithubRepo = 'https://github.com/alibaba/designable' const CommitGroupBy: Array<[string, string[]]> = [ [':tada: Enhancements', ['feat', 'features', 'feature']], [':beetle: Bug Fixes', ['bug', 'bugfix', 'fix']], [':boom: Breaking Changes', ['breaking', 'break']], [':memo: Documents Changes', ['doc', 'docs']], [':rose: Improve code quality', ['refactor', 'redesign']], [':rocket: Improve Performance', ['perf']], [':hammer_and_wrench: Update Workflow Scripts', ['build']], [':construction: Add/Update Test Cases', ['test']], [':blush: Other Changes', ['chore']], ] const isPublishMessage = (str: string) => { if (/chore\(\s*(?:versions?|publish)\s*\)/.test(str)) return true return /publish v?(?:\d+)\.(?:\d+)\.(?:\d+)/.test(str) } const getCurrentChanges = (from = lastTag(), to = 'HEAD') => { const summarys = [] return listCommits(from, to).filter(({ summary }) => { if (summarys.some((target) => compareTwoStrings(target, summary) > 0.5)) return false if (isPublishMessage(summary)) return false summarys.push(summary) return true }) } const getGroupChanges = (from = lastTag(), to = 'HEAD') => { const changes = getCurrentChanges(from, to) const results: Array<[string, string[]]> = CommitGroupBy.map(([group]) => [ group, [], ]) changes.forEach(({ summary, author, sha }) => { for (const [group, value] of CommitGroupBy) { if (value.some((target) => new RegExp(target).test(summary))) { results.forEach((item) => { if (item[0] === group) { item[1].push( `[${summary}](${GithubRepo}/commit/${sha}) :point_right: ( [${author}](https://github.com/${author}) )` ) } }) } } }) return results.filter(([, value]) => { return value.length > 0 }) } const createChangelog = (from = lastTag(), to = 'HEAD') => { const isHead = to === 'HEAD' const headVersion = isHead ? LernaJSON?.version : to const changes = getGroupChanges(from, to) const nowDate = isHead ? moment().format('YYYY-MM-DD') : moment(getTaggedTime(to), 'YYYY-MM-DD').format('YYYY-MM-DD') const log = changes .map(([group, contents]) => { return ` ### ${group} ${contents .map((content) => { return ` 1. ${content} ` }) .join('')} ` }) .join('') return ` ## ${headVersion}(${nowDate}) ${log ? log : '### No Change Log'} ` } const isPrerelease = (tag: string) => { return /(?:beta|rc|alpha)/.test(tag) } const createReleaseNote = () => { const to = lastTag() const from = getPreviousTag(to) const body = createChangelog(from, to) const branch = getCurrentBranch() const token = getGithubToken() return new Promise((resolve, reject) => { ghRelease( { cli: true, tag_name: to, target_commitish: branch, name: `${ReleaseTitle} - ${to}`, body, draft: false, prerelease: isPrerelease(to), owner: 'alibaba', repo: 'designable', endpoint: 'https://api.github.com', auth: { token, }, }, (err: unknown, response: unknown) => { if (err) { reject() } else { resolve(response) } } ) }) } const generateChangeLogFile = () => { const tags = getSortableAllTags() const file = ` # Changelog ${tags .slice(0, 40) .map((newer, index) => { const older = tags[index + 1] if (older) { return createChangelog(older, newer) } return '' }) .join('')} ` fs.writeFileSync(path.resolve(__dirname, '../../CHANGELOG.md'), file, 'utf8') } if (process.argv.includes('release')) { createReleaseNote() console.log('🎉:Release Note upload success!') } else if (process.argv.includes('changelog')) { generateChangeLogFile() console.log('🎉:Changelog generate success!') }