From d9445d20783f2793b7c72fd421b85de1269ba588 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=98=BF=E8=8F=9C=20Cai?= <1064425721@qq.com> Date: Mon, 28 Oct 2024 18:55:19 +0800 Subject: [PATCH] chore(ci): automatically release every week (#546) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(ci): automatically release every week * chore: change repo owner * chore: 修改所有者为Tencent * chore: use `raw.githubusercontent` * chore: remove excess scripts --- .github/workflows/auto-release.yml | 25 ++++ scripts/auto-release.ts | 202 +++++++++++++++++++++++++++++ 2 files changed, 227 insertions(+) create mode 100644 .github/workflows/auto-release.yml create mode 100644 scripts/auto-release.ts diff --git a/.github/workflows/auto-release.yml b/.github/workflows/auto-release.yml new file mode 100644 index 00000000..43569e00 --- /dev/null +++ b/.github/workflows/auto-release.yml @@ -0,0 +1,25 @@ +on: + schedule: + # 相关语法 https://pubs.opengroup.org/onlinepubs/9699919799/utilities/crontab.html#tag_20_25_07 would run a command on the first and fifteenth of each month + - cron: '0 16 1,8,15,22 * *' + +jobs: + test_schedule: + if: github.repository == 'Tencent/tdesign' + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Node + uses: actions/setup-node@v4 + with: + # https://nodejs.org/en/learn/typescript/run-natively#running-typescript-code-with-nodejs + node-version: "22.6.0" + # https://docs.npmjs.com/cli/v7/using-npm/config#strict-peer-deps + - name: Install Dependencies + run: npm install @actions/github --legacy-peer-deps + - name: run JavaScript + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + node --experimental-strip-types scripts/auto-release.ts \ No newline at end of file diff --git a/scripts/auto-release.ts b/scripts/auto-release.ts new file mode 100644 index 00000000..047baec3 --- /dev/null +++ b/scripts/auto-release.ts @@ -0,0 +1,202 @@ +import * as github from '@actions/github'; + +const submodules = { + "tdesign-vue": { + "title": "## Vue2 for Web 发布", + "changelogUrl": "https://raw.githubusercontent.com/Tencent/tdesign-vue/refs/heads/main/CHANGELOG.md" + }, + "tdesign-vue-next": { + "title": "## Vue3 for Web 发布", + "changelogUrl": "https://raw.githubusercontent.com/Tencent/tdesign-vue-next/refs/heads/main/CHANGELOG.md" + }, + "tdesign-react": { + "title": "## React for Web 发布 ", + "changelogUrl": "https://raw.githubusercontent.com/Tencent/tdesign-react/refs/heads/main/CHANGELOG.md" + }, + "tdesign-miniprogram": { + "title": "## Miniprogram for WeChat 发布", + "changelogUrl": "https://raw.githubusercontent.com/Tencent/tdesign-miniprogram/refs/heads/main/CHANGELOG.md" + }, + "tdesign-mobile-vue": { + "title": "## Vue3 for Mobile 发布", + "changelogUrl": "https://raw.githubusercontent.com/Tencent/tdesign-mobile-vue/refs/heads/main/CHANGELOG.md" + }, + "tdesign-flutter": { + "title": "## Flutter for Mobile 发布", + "changelogUrl": "https://raw.githubusercontent.com/Tencent/tdesign-flutter/refs/heads/main/tdesign-site/CHANGELOG.md" + }, + "tdesign-mobile-react": { + "title": "## React for Mobile 发布", + "changelogUrl": "https://raw.githubusercontent.com/Tencent/tdesign-mobile-react/refs/heads/main/CHANGELOG.md" + }, +}; + +type SubmoduleItem = keyof typeof submodules; + +const submodulesKeys: SubmoduleItem[] = [ + 'tdesign-vue', + 'tdesign-vue-next', + 'tdesign-react', + 'tdesign-miniprogram', + 'tdesign-mobile-vue', + 'tdesign-mobile-react', + 'tdesign-flutter', +] + +/** + * @description 获取内容 + * @param {string} version + */ +const getVersionContent = (version: string, markdown: string) => { + const regex = new RegExp(`(${version}.*?(?=## 🌈|$))`, 's'); + const match = markdown.match(regex); + + if (match) { + return match[0]; + } else { + return 'Version Content not found'; + } +} + +/** + * @description 获取项目具体详情描述地址 + * @example: + * ['## Vue3 for Web 发布 [1.10.1,1.10.1](https://github.com/Tencent/tdesign-vue-next/releases/tag/1.10.1)' + * '详情见: https://github.com/Tencent/tdesign-vue-next/releases/tag/1.10.0' + * ] + * @param {string} project + * @param {string} tag + * @param {string} prefixDesc + * @param {string} suffixDesc + */ +function getProjectDesc(project: SubmoduleItem, tag: string, prefixDesc: any, suffixDesc: any) { + return [ + `${prefixDesc} [${tag}](https://github.com/Tencent/${project}/releases/tag/${tag})`, + `${suffixDesc} https://github.com/Tencent/${project}/releases/tag/${tag}`, + ]; +} + +// 开始执行 + +/** + * @description 检查日期是否在指定日期范围内 + * 在每个月的1号、8号、15号、22号生成 + * 1号生成上个月的22号到最后一天的版本 + * 8号生成这个月的1号到7号的版本 + * 15号生成这个月的8号到14号的版本 + * 22号生成这个月的15号到21号的版本 + */ + +let START_DATE = ''; +let END_DATE = ''; + +const today = new Date(); + +// 获取昨天的日期并且只取年月日格式化成'yyyy-mm-dd' +const someDaysAgo = new Date(today); +if (today.getDate() === 1) { + // 获取上个月的22号到最后一天的版本 + START_DATE = new Date(today.getFullYear(), today.getMonth() - 1, 22).toISOString().split('T')[0];; + END_DATE = new Date(someDaysAgo.setDate(today.getDate() - 1)).toISOString().split('T')[0]; +} else { + START_DATE = new Date(someDaysAgo.setDate(today.getDate() - 7)).toISOString().split('T')[0]; + END_DATE = new Date(someDaysAgo.setDate(today.getDate() - 1)).toISOString().split('T')[0]; +} +console.log(`今天是:${today},开始日期:${START_DATE},结束日期:${END_DATE}`); + +const fetchPromises = submodulesKeys.map(async project => { + console.log(`开始处理${project}项目`); + const changelogUrl = submodules[project].changelogUrl; + console.log(changelogUrl); + // 读取 CHANGELOG.md 文件内容 + const response = await fetch(changelogUrl); + const changelogContent = await response.text(); + + // 使用正则表达式提取版本标题行,确保以"##"开头并以日期结尾 + const versions = changelogContent.match(/^##.+?`\d{4}-\d{2}-\d{2}`\s*$/gm); + + const projectOutput: string[] = []; + + versions?.forEach((versionLine) => { + const dateMatch = versionLine.match(/\d{4}-\d{2}-\d{2}/); + if (dateMatch) { + const versionContent = getVersionContent(versionLine, changelogContent); + const tag = versionLine.match(/\d+\.\d+\.\d+/); + if (!tag) { + throw new Error('tag is null'); + } + + const date = new Date(dateMatch[0]); + // 检查日期是否在指定范围内,[2024-06-01, 2024-06-07] 闭区间 + if (date >= new Date(START_DATE) && date <= new Date(END_DATE)) { + const desc = getProjectDesc(project, tag[0], submodules[project]['title'], '详情见:'); + projectOutput.push(`${desc[0]}\n${versionContent}\n${desc[1]}\n`); + } + } + }); + + return projectOutput.join('\n'); +}); + +Promise.all(fetchPromises).then(projectOutputs => { + const output = projectOutputs.join('\n'); + + // 标题 + const monthShort = today.toLocaleString('en-US', { month: 'short' }); + const year = today.getFullYear(); + let times = "1st"; + + console.log('today', today.getDate()); + switch (today.getDate()) { + case 1: + times = "4th"; + break; + case 8: + times = "1st"; + break; + case 15: + times = "2nd"; + break; + case 22: + times = "3rd"; + break; + default: + times = "1st"; + break; + } + + const tag = `v${today.getFullYear()}.${today.getMonth() + 1}.${today.getDate()}`; + const title = `TDesign Weekly Release (${monthShort} ${times} ${year})`; + + console.log('tag', tag); + console.log('title', title); + console.log('output', output); + + // 发布release + + const githubToken = process.env.GITHUB_TOKEN; + + if (!githubToken) { + throw new Error('GITHUB_TOKEN is undefined'); + } + + console.log('tag', tag); + console.log('title', title); + console.log('output', output); + console.log('GitHub Token:', githubToken); + const octokit = github.getOctokit(githubToken); + console.log('身份验证成功'); + + try { + octokit.rest.repos.createRelease({ + owner: "Tencent", + repo: "tdesign", + tag_name: tag, // 添加缺少的 tag_name 参数 + name: title, // 可选参数,使用 title 作为发布名称 + body: output, // 可选参数,发布说明内容 + draft: true, // 可选参数,是否为草稿 + }) + } catch (error) { + console.error("Error:", error); + } +}); \ No newline at end of file