From d119b97d7e81d9f2af984f816afbdee4f6adaffb Mon Sep 17 00:00:00 2001 From: "Y." Date: Wed, 17 Jul 2024 11:09:19 +0800 Subject: [PATCH] ci: add some workflows (#385) * ci: add some workflows * fix: fix spelling errors --- .github/CODEOWNERS | 1 + .github/ISSUE_TEMPLATE/config.yml | 5 ++ .github/issue-shoot.md | 8 ++ .github/workflows/issue-label.yml | 50 ++++++++++++ .github/workflows/pr-comment-ci.yml | 95 ++++++++++++++++++++++ .github/workflows/pr-compressed-size.yml | 18 ++++ .github/workflows/pr-spelling.template.yml | 13 +++ .github/workflows/typos-config.toml | 8 ++ site/plugin-tdoc/md-to-react.js | 49 +++++++---- site/plugin-tdoc/transforms.js | 4 +- site/style/vars.less | 24 +++--- src/input/_example/special.jsx | 6 +- src/input/_example/style/index.less | 2 +- src/picker/PickerItem.tsx | 6 +- src/radio/_example/base.jsx | 4 +- src/radio/_example/leftStrokeLine.jsx | 4 +- src/radio/_example/right.jsx | 4 +- src/radio/_example/rightStrokeLine.jsx | 4 +- src/radio/_example/status.jsx | 10 +-- src/toast/methods.tsx | 4 +- src/toast/toast.md | 2 +- 21 files changed, 269 insertions(+), 52 deletions(-) create mode 100644 .github/CODEOWNERS create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/issue-shoot.md create mode 100644 .github/workflows/issue-label.yml create mode 100644 .github/workflows/pr-comment-ci.yml create mode 100644 .github/workflows/pr-compressed-size.yml create mode 100644 .github/workflows/pr-spelling.template.yml create mode 100644 .github/workflows/typos-config.toml diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..5295ad45 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @anlyyao @ZWkang @jarmywang diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..c4478897 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: true +contact_links: + - name: 使用 issue-helper 新建 + url: https://Tencent.github.io/tdesign/issue-helper/?lang=zh-CN&repo=Tencent/tdesign-mobile-react + about: 使用 https://Tencent.github.io/tdesign/issue-helper/ 创建 issue,其中包含 bug 和 feature,表单提交更加严格。 diff --git a/.github/issue-shoot.md b/.github/issue-shoot.md new file mode 100644 index 00000000..15541778 --- /dev/null +++ b/.github/issue-shoot.md @@ -0,0 +1,8 @@ +## IssueShoot +- 预估时长: {{ .duration }} +- 期望完成时间: {{ .deadline }} +- 开发难度: {{ .level }} +- 参与人数: 1 +- 需求对接人: anlyyao +- 验收标准: 实现期望改造效果,提 PR 并通过验收无误 +- 备注: 最终激励以实际提交 `pull request` 并合并为准 diff --git a/.github/workflows/issue-label.yml b/.github/workflows/issue-label.yml new file mode 100644 index 00000000..ec009a0c --- /dev/null +++ b/.github/workflows/issue-label.yml @@ -0,0 +1,50 @@ +name: issue on label +on: + issues: + types: ['labeled'] +jobs: + add-issueshoot-template: + runs-on: ubuntu-latest + if: contains(fromJSON('["easy", "middle", "hard"]'), github.event.label.name) + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Get token + id: token + run: | + label=${{ github.event.label.name }} + if [[ $label = "easy" ]] + then + echo "level=低" >> $GITHUB_OUTPUT + echo "duration=1" >> $GITHUB_OUTPUT + deadline=$(date -d "+3 days" +'%Y-%m-%d') + echo "deadline=${deadline}" >> $GITHUB_OUTPUT + elif [[ $label = "middle" ]] + then + echo "level=中" >> $GITHUB_OUTPUT + echo "duration=3" >> $GITHUB_OUTPUT + deadline=$(date -d "+7 days" +'%Y-%m-%d') + echo "deadline=${deadline}" >> $GITHUB_OUTPUT + else + echo "level=高" >> $GITHUB_OUTPUT + echo "duration=5" >> $GITHUB_OUTPUT + deadline=$(date -d "+10 days" +'%Y-%m-%d') + echo "deadline=${deadline}" >> $GITHUB_OUTPUT + fi + - name: Create template + id: template + uses: chuhlomin/render-template@v1.4 + with: + template: .github/issue-shoot.md + vars: | + level: ${{ steps.token.outputs.level }} + duration: ${{ steps.token.outputs.duration }} + deadline: ${{ steps.token.outputs.deadline }} + - name: Update issue + uses: actions-cool/issues-helper@v3 + with: + actions: 'update-issue' + token: ${{ secrets.GITHUB_TOKEN }} + issue-number: ${{ github.event.issue.number }} + body: ${{ steps.template.outputs.result }} + update-mode: 'append' \ No newline at end of file diff --git a/.github/workflows/pr-comment-ci.yml b/.github/workflows/pr-comment-ci.yml new file mode 100644 index 00000000..a489e620 --- /dev/null +++ b/.github/workflows/pr-comment-ci.yml @@ -0,0 +1,95 @@ +name: PR_COMMENT_CI + +on: + issue_comment: + types: [created] + +jobs: + check: + runs-on: ubuntu-latest + outputs: + next_action: ${{ steps.get-action.outputs.next_action }} + if: ${{ github.event.issue.pull_request }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 1 + - uses: actions/github-script@v7 + id: get-action + with: + script: | + const user = context.payload.comment.user.login + core.debug(`user: ${user}`) + + const fs = require('fs') + const CODEOWNERS = fs.readFileSync('.github/CODEOWNERS', 'utf8') + core.debug(`CODEOWNERS: ${CODEOWNERS}`) + + let isReviewer = false; + CODEOWNERS.match(/@\w+/g).forEach((owner) => { + if (owner === `@${user}`) { + isReviewer = true + } + }) + + let next_action = '' + if (isReviewer) { + const body = context.payload.comment.body + core.info(`body: ${body}`) + if (body.startsWith('/update-common')) { + next_action='update-common' + } + if (body.startsWith('/update-snapshot')) { + next_action='update-snapshot' + } + } else { + core.warning('You are not collaborator'); + } + core.info(`next_action: ${next_action}`) + core.setOutput('next_action', next_action) + + update-common: + needs: check + runs-on: ubuntu-latest + if: ${{ needs.check.outputs.next_action == 'update-common' }} + steps: + - uses: actions/checkout@v4 + with: + token: ${{ secrets.PERSONAL_TOKEN }} + - name: gh checkout pr + env: + GH_TOKEN: ${{ secrets.PERSONAL_TOKEN }} + run: gh pr checkout ${{ github.event.issue.number }} --recurse-submodules + - run: git submodule update --remote --merge + - name: Commit Common + run: | + git add . + git config --local user.email "github-actions[bot]@users.noreply.github.com" + git config --local user.name "github-actions[bot]" + git commit -m "chore: update common" + git push + + update-snapshot: + needs: check + runs-on: ubuntu-latest + if: ${{ needs.check.outputs.next_action == 'update-snapshot' }} + steps: + - uses: actions/checkout@v4 + with: + token: ${{ secrets.PERSONAL_TOKEN }} + - name: gh checkout pr + env: + GH_TOKEN: ${{ secrets.PERSONAL_TOKEN }} + run: gh pr checkout ${{ github.event.issue.number }} --recurse-submodules + - uses: actions/setup-node@v4 + with: + node-version: 18 + - run: npm install + - run: npm run test:update + - name: Commit Snapshot + run: | + git add . + git config --local user.email "github-actions[bot]@users.noreply.github.com" + git config --local user.name "github-actions[bot]" + git commit -m "chore: update snapshot" + git push \ No newline at end of file diff --git a/.github/workflows/pr-compressed-size.yml b/.github/workflows/pr-compressed-size.yml new file mode 100644 index 00000000..0f6492de --- /dev/null +++ b/.github/workflows/pr-compressed-size.yml @@ -0,0 +1,18 @@ +name: Compressed Size + +on: + pull_request: + types: [opened, synchronize] + +jobs: + compressed-size: + runs-on: ubuntu-latest + if: startsWith(github.head_ref, 'release/') + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + - uses: 94dreamer/compressed-size-action@master + with: + repo-token: '${{ secrets.GITHUB_TOKEN }}' + pattern: './dist/**/*.{js,css}' diff --git a/.github/workflows/pr-spelling.template.yml b/.github/workflows/pr-spelling.template.yml new file mode 100644 index 00000000..545613ca --- /dev/null +++ b/.github/workflows/pr-spelling.template.yml @@ -0,0 +1,13 @@ +name: pr-spell-check +on: [pull_request] + +jobs: + run: + name: Spell Check with Typos + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Check spelling + uses: crate-ci/typos@master + with: + config: .github/workflows/typos-config.toml diff --git a/.github/workflows/typos-config.toml b/.github/workflows/typos-config.toml new file mode 100644 index 00000000..723bfea6 --- /dev/null +++ b/.github/workflows/typos-config.toml @@ -0,0 +1,8 @@ +default.check-filename = true + +[default.extend-words] +actived = "actived" +colum = "colum" + +[files] +extend-exclude = ["CHANGELOG.md", "*.snap"] diff --git a/site/plugin-tdoc/md-to-react.js b/site/plugin-tdoc/md-to-react.js index 0f3acee8..b6b6fc2f 100644 --- a/site/plugin-tdoc/md-to-react.js +++ b/site/plugin-tdoc/md-to-react.js @@ -79,13 +79,14 @@ export default function mdToReact(options) { return ( <> ${ - mdSegment.tdDocHeader ? - `` : '' + >` + : '' } { isComponent ? ( @@ -95,15 +96,26 @@ export default function mdToReact(options) { ${mdSegment.demoMd.replace(/class=/g, 'className=')} - + - + -
-
+
+
- ) :
${mdSegment.docMd.replace(/class=/g, 'className=')}
+ ) :
${mdSegment.docMd.replace( + /class=/g, + 'className=', + )}
}
@@ -126,7 +138,7 @@ export default function mdToReact(options) { return { code: result.code, map: result.map }; } -const DEAULT_TABS = [ +const DEFAULT_TABS = [ { tab: 'demo', name: '示例' }, { tab: 'api', name: 'API' }, { tab: 'design', name: '指南' }, @@ -145,7 +157,7 @@ function customRender({ source, file, md }) { description: '', isComponent: false, tdDocHeader: true, - tdDocTabs: DEAULT_TABS, + tdDocTabs: DEFAULT_TABS, apiFlag: /#+\s*API/i, docClass: '', lastUpdated: Math.round(fs.statSync(file).mtimeMs), @@ -161,7 +173,7 @@ function customRender({ source, file, md }) { // fix table | render error demoMd = demoMd.replace(/`([^`]+)`/g, (str, codeStr) => { - codeStr = codeStr.replace(/"/g, '\''); + codeStr = codeStr.replace(/"/g, "'"); return ``; }); @@ -181,10 +193,19 @@ function customRender({ source, file, md }) { }; if (pageData.isComponent) { - mdSegment.demoMd = md.render.call(md, `${pageData.toc ? '[toc]\n' : ''}${demoMd.replace(//g, '')}`).html; - mdSegment.apiMd = md.render.call(md, `${pageData.toc ? '[toc]\n' : ''}${apiMd.replace(//g, '')}`).html; + mdSegment.demoMd = md.render.call( + md, + `${pageData.toc ? '[toc]\n' : ''}${demoMd.replace(//g, '')}`, + ).html; + mdSegment.apiMd = md.render.call( + md, + `${pageData.toc ? '[toc]\n' : ''}${apiMd.replace(//g, '')}`, + ).html; } else { - mdSegment.docMd = md.render.call(md, `${pageData.toc ? '[toc]\n' : ''}${content.replace(//g, '')}`).html; + mdSegment.docMd = md.render.call( + md, + `${pageData.toc ? '[toc]\n' : ''}${content.replace(//g, '')}`, + ).html; } // 移动端路由地址 diff --git a/site/plugin-tdoc/transforms.js b/site/plugin-tdoc/transforms.js index 65b53c6b..a3c06260 100644 --- a/site/plugin-tdoc/transforms.js +++ b/site/plugin-tdoc/transforms.js @@ -8,7 +8,7 @@ let demoCodesImports = {}; export default { before({ source, file }) { - const resouceDir = path.dirname(file); + const resourceDir = path.dirname(file); const reg = file.match(/src\/([\w-]+)\/([\w-]+)\.md/); const name = reg && reg[1]; demoCodesImports = {}; @@ -26,7 +26,7 @@ export default { // 替换成对应 demo 文件 source = source.replace(/\{\{\s+(.+)\s+\}\}/g, (demoStr, demoFileName) => { - const demoPath = path.resolve(resouceDir, `./_example/${demoFileName}.jsx`); + const demoPath = path.resolve(resourceDir, `./_example/${demoFileName}.jsx`); if (!fs.existsSync(demoPath)) { console.log('\x1B[36m%s\x1B[0m', `${name} 组件需要实现 _example/${demoFileName}.jsx 示例!`); return '\n

DEMO (🚧建设中)...

'; diff --git a/site/style/vars.less b/site/style/vars.less index ab8e77b6..8992443d 100644 --- a/site/style/vars.less +++ b/site/style/vars.less @@ -6,14 +6,14 @@ @primary-color-darken-3: darken(@primary-color, (43 - 19) * 1%); @primary-color-darken-4: darken(@primary-color, (43 - 11) * 1%); -@primary-color-ligher-1: lighten(@primary-color, (51 - 43) * 1%); -@primary-color-ligher-2: lighten(@primary-color, (59 - 43) * 1%); -@primary-color-ligher-3: lighten(@primary-color, (67 - 43) * 1%); -@primary-color-ligher-4: lighten(@primary-color, (75 - 43) * 1%); -@primary-color-ligher-5: lighten(@primary-color, (83 - 43) * 1%); -@primary-color-ligher-6: lighten(@primary-color, (91 - 43) * 1%); -@primary-color-ligher-7: lighten(@primary-color, (96 - 43) * 1%); -// @primary-color-ligher-6: hsl(217, 100, 91); +@primary-color-lighter-1: lighten(@primary-color, (51 - 43) * 1%); +@primary-color-lighter-2: lighten(@primary-color, (59 - 43) * 1%); +@primary-color-lighter-3: lighten(@primary-color, (67 - 43) * 1%); +@primary-color-lighter-4: lighten(@primary-color, (75 - 43) * 1%); +@primary-color-lighter-5: lighten(@primary-color, (83 - 43) * 1%); +@primary-color-lighter-6: lighten(@primary-color, (91 - 43) * 1%); +@primary-color-lighter-7: lighten(@primary-color, (96 - 43) * 1%); +// @primary-color-lighter-6: hsl(217, 100, 91); // 状态色 @success-color: #3ecc36; @@ -39,10 +39,11 @@ @font-size-base: 14px; @line-height-base: 1.5; -@font-family: "PingFang SC", -apple-system, "Helvetica Neue", Helvetica, BlinkMacSystemFont, "Microsoft YaHei", tahoma, Arial, "Open Sans", "Hiragino Sans GB", "Heiti SC", "WenQuanYi Micro Hei", sans-serif; +@font-family: 'PingFang SC', -apple-system, 'Helvetica Neue', Helvetica, BlinkMacSystemFont, 'Microsoft YaHei', tahoma, + Arial, 'Open Sans', 'Hiragino Sans GB', 'Heiti SC', 'WenQuanYi Micro Hei', sans-serif; /** - * 文字部分 + * 文字部分 * size 大小,line 行高, color 颜色 */ // 字体大小 @@ -99,7 +100,6 @@ @shadow-level-1: 3px 3px 8px 2px rgba(0, 0, 0, 0.06); @shadow-level-2: 6px 6px 12px 6px rgba(0, 0, 0, 0.08); - // border @border-color: #d9d9d9; @border-main: 1px solid @border-color; @@ -118,7 +118,7 @@ // layout @layoutMargin: 10px; -// header +// header @headerHeight: 81px; // footer diff --git a/src/input/_example/special.jsx b/src/input/_example/special.jsx index 7d08025e..d5bd4af2 100644 --- a/src/input/_example/special.jsx +++ b/src/input/_example/special.jsx @@ -52,13 +52,12 @@ export default function Base() { label={'价格'} placeholder="0.00" suffix="元" - suffixSeperate={false} align="right" value={value4} onChange={(value) => { setValue4(value); }} - className="t-input-suffix-noseperate" + className="t-input-suffix-noseparate" /> @@ -66,13 +65,12 @@ export default function Base() { label={'个数'} placeholder="请输入个数" suffix="个" - suffixSeperate={false} align="right" value={value5} onChange={(value) => { setValue5(value); }} - className="t-input-suffix-noseperate" + className="t-input-suffix-noseparate" /> diff --git a/src/input/_example/style/index.less b/src/input/_example/style/index.less index 3fbebe00..d46b77e2 100644 --- a/src/input/_example/style/index.less +++ b/src/input/_example/style/index.less @@ -1,4 +1,4 @@ -.t-input-suffix-noseperate { +.t-input-suffix-noseparate { .t-input__wrap--suffix { &::after { border: none; diff --git a/src/picker/PickerItem.tsx b/src/picker/PickerItem.tsx index 26175c69..02146735 100644 --- a/src/picker/PickerItem.tsx +++ b/src/picker/PickerItem.tsx @@ -73,7 +73,7 @@ const PickerItem: FC = memo((props) => { [api, getOffsetYList], ); - const hanldeChange = (value: number | string) => { + const handleChange = (value: number | string) => { const pickerValue = pickerContext.value?.slice(0) || []; pickerValue[itemIndex] = value; pickerContext.onChange?.(pickerValue, itemIndex); @@ -111,12 +111,12 @@ const PickerItem: FC = memo((props) => { api.start({ to: async (next) => { await next({ y: nextOffsetY }); - hanldeChange(options[nextIndex].value); + handleChange(options[nextIndex].value); }, }); } else { // 受控模式,onChange回调后等待value更新,如果不更新回退到原处 - hanldeChange(options[nextIndex].value); + handleChange(options[nextIndex].value); setTimeout(() => { if (lastIndex === lastIndexRef.current) { api.start({ y: offsetYList[lastIndex] || 0 }); diff --git a/src/radio/_example/base.jsx b/src/radio/_example/base.jsx index 11dbd43a..8f34b309 100644 --- a/src/radio/_example/base.jsx +++ b/src/radio/_example/base.jsx @@ -2,9 +2,9 @@ import React, { useState } from 'react'; import { Radio, RadioGroup } from 'tdesign-mobile-react'; export default function Base() { - const [defaultVaule, setDefaultValue] = useState('idx0'); + const [defaultValue, setDefaultValue] = useState('idx0'); return ( - setDefaultValue(value)}> + setDefaultValue(value)}> diff --git a/src/radio/_example/leftStrokeLine.jsx b/src/radio/_example/leftStrokeLine.jsx index 220b7bd2..fb612b75 100644 --- a/src/radio/_example/leftStrokeLine.jsx +++ b/src/radio/_example/leftStrokeLine.jsx @@ -3,11 +3,11 @@ import { Radio, RadioGroup } from 'tdesign-mobile-react'; import { CheckIcon } from 'tdesign-icons-react'; export default function Base() { - const [defaultVaule, setDefaultValue] = useState('idx0'); + const [defaultValue, setDefaultValue] = useState('idx0'); const CheckedIcon = ; return ( <> - setDefaultValue(value)}> + setDefaultValue(value)}> + diff --git a/src/radio/_example/rightStrokeLine.jsx b/src/radio/_example/rightStrokeLine.jsx index f9a12538..35462a51 100644 --- a/src/radio/_example/rightStrokeLine.jsx +++ b/src/radio/_example/rightStrokeLine.jsx @@ -3,11 +3,11 @@ import { Radio, RadioGroup } from 'tdesign-mobile-react'; import { CheckIcon } from 'tdesign-icons-react'; export default function () { - const [defaultVaule, setDefaultValue] = useState('idx1'); + const [defaultValue, setDefaultValue] = useState('idx1'); const CheckedIcon = ; return ( - + ; return ( <>
- + @@ -19,7 +19,7 @@ export default function () {
- + @@ -27,7 +27,7 @@ export default function () {
- + @@ -35,7 +35,7 @@ export default function () {
- + diff --git a/src/toast/methods.tsx b/src/toast/methods.tsx index 17b7b386..47f5b8d6 100644 --- a/src/toast/methods.tsx +++ b/src/toast/methods.tsx @@ -9,10 +9,10 @@ const createToast = (props, theme?: ToastThemeListEnum) => { const el = document.createElement('div'); document.body.appendChild(el); ReactDOM.render(, el); - const destory = () => { + const destroy = () => { document.body.removeChild(el); }; - return { destory }; + return { destroy }; }; export default { diff --git a/src/toast/toast.md b/src/toast/toast.md index 9eda04b7..fc7c3898 100644 --- a/src/toast/toast.md +++ b/src/toast/toast.md @@ -18,4 +18,4 @@ theme | String | -- | 提示类型, 可选值:loading \| success \| fail。 | 名称 | 描述 -- | -- -destory | 主动销毁toast,需要获取toast实例 \ No newline at end of file +destroy | 主动销毁toast,需要获取toast实例 \ No newline at end of file