diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml deleted file mode 100644 index 6fd0af3b6..000000000 --- a/.github/workflows/e2e-tests.yml +++ /dev/null @@ -1,91 +0,0 @@ -name: E2E Tests -# 运行时显示的名称 -run-name: E2E Tests - -on: - push: - branches: [ develop, main ] - pull_request: - branches: [ develop, main ] - -jobs: - e2e-tests: - timeout-minutes: 60 - # 指定运行环境为最新版本的ubuntu - runs-on: ubuntu-latest - - steps: - # 步骤1: 检出代码 (处理所有情况) - - # 场景 A: 当工作流由 push 事件触发时 (例如合并到 develop 分支) - # 或者由仓库内部成员创建的 PR 触发时,执行此步骤。 - - name: Checkout for Develop Repo Push or PR - # 条件:事件不是来自 fork 的 PR - if: github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'push' - uses: actions/checkout@v4 - with: - # 对于源仓库 PR,确认检出最新的代码 - ref: ${{ github.event.pull_request.head.sha || github.sha }} - - # 场景 B: 当工作流由外部 fork 仓库的 PR 触发时,执行此步骤 - - name: Checkout for Fork PR - # 条件:事件是来自 fork 的 PR - if: github.event.pull_request.head.repo.full_name != github.repository - uses: actions/checkout@v4 - with: - repository: ${{ github.event.pull_request.head.repo.full_name }} - ref: ${{ github.head_ref }} - - # 步骤2: 设置pnpm包管理器 - - name: Setup pnpm - uses: pnpm/action-setup@v4 - - # 步骤3: 设置Node.js环境 - - name: Setup Node - uses: actions/setup-node@v4 - with: - node-version: 20 # 使用Node.js 20版本 - registry-url: 'https://registry.npmjs.org' # 设置npm registry地址 - - # 步骤4: 获取pnpm缓存目录路径 - - name: Get pnpm store directory - id: pnpm-cache - run: | - echo "pnpm_cache_dir=$(pnpm store path)" >> $GITHUB_OUTPUT - - # 步骤5: 配置pnpm缓存 - - uses: actions/cache@v3 - name: Setup pnpm cache - with: - path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }} - # 使用操作系统类型和pnpm-lock.yaml的哈希值作为缓存键 - key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} - restore-keys: | - ${{ runner.os }}-pnpm-store- - - # 步骤6: 安装项目依赖 - - name: Install dependencies - run: pnpm i --no-frozen-lockfile - - # 步骤7: 构建组件 - - name: Run Build Components - run: pnpm build - - # 步骤8: 安装 Playwright 浏览器 - - name: Install Playwright Browser - run: | - cd packages/test - npx playwright install --with-deps chromium - - # 步骤9: 运行 E2E 测试 - - name: Run Playwright Tests - run: pnpm test - - # 步骤10: 上传 Playwright 测试报告 - - name: Upload Playwright Test Report - uses: actions/upload-artifact@v4 - if: always() - with: - name: playwright-report - path: packages/test/playwright-report/ - retention-days: 13 \ No newline at end of file diff --git a/.github/workflows/pr-ci-build.yml b/.github/workflows/pr-ci-build.yml new file mode 100644 index 000000000..d4caa4441 --- /dev/null +++ b/.github/workflows/pr-ci-build.yml @@ -0,0 +1,53 @@ +name: 'CI: Build' + +on: + workflow_call: + inputs: + skip-playground: + description: 'Skip playground build' + type: boolean + default: false + +jobs: + build-job: + name: build + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Get pnpm store directory + id: pnpm-cache + run: echo "pnpm_cache_dir=$(pnpm store path)" >> $GITHUB_OUTPUT + + - name: Setup pnpm cache + uses: actions/cache@v4 + with: + path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install dependencies + run: pnpm i --no-frozen-lockfile + + - name: Build components + run: pnpm build + + - name: Upload build artifacts + uses: actions/upload-artifact@v4 + with: + name: build-${{ github.sha }} + path: | + packages/components/dist + packages/kit/dist + packages/svgs/dist + retention-days: 1 diff --git a/.github/workflows/pr-ci-e2e-test.yml b/.github/workflows/pr-ci-e2e-test.yml new file mode 100644 index 000000000..600ad414f --- /dev/null +++ b/.github/workflows/pr-ci-e2e-test.yml @@ -0,0 +1,58 @@ +name: 'CI: E2E Test' + +on: + workflow_call: + +jobs: + test-job: + name: e2e-test + runs-on: ubuntu-latest + timeout-minutes: 60 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Get pnpm store directory + id: pnpm-cache + run: echo "pnpm_cache_dir=$(pnpm store path)" >> $GITHUB_OUTPUT + + - name: Setup pnpm cache + uses: actions/cache@v4 + with: + path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install dependencies + run: pnpm i --no-frozen-lockfile + + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + name: build-${{ github.sha }} + path: packages + + - name: Install Playwright Browser + run: | + cd packages/test + npx playwright install --with-deps chromium + + - name: Run Playwright Tests + run: pnpm test + + - name: Upload Playwright Test Report + uses: actions/upload-artifact@v4 + if: always() + with: + name: playwright-report-${{ github.sha }} + path: packages/test/playwright-report/ + retention-days: 13 diff --git a/.github/workflows/pr-ci-preview.yml b/.github/workflows/pr-ci-preview.yml new file mode 100644 index 000000000..17f7153e4 --- /dev/null +++ b/.github/workflows/pr-ci-preview.yml @@ -0,0 +1,160 @@ +name: 'CI: Preview' + +on: + workflow_call: + inputs: + pr-number: + description: 'Pull Request number' + type: number + required: true + +jobs: + preview-job: + name: preview + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + registry-url: 'https://registry.npmjs.org' + + - name: Get pnpm store directory + id: pnpm-cache + run: echo "pnpm_cache_dir=$(pnpm store path)" >> $GITHUB_OUTPUT + + - name: Setup pnpm cache + uses: actions/cache@v4 + with: + path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install dependencies + run: pnpm i --no-frozen-lockfile + + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + name: build-${{ github.sha }} + path: packages + + - name: Build docs only (components already built) + run: pnpm -F docs build + + - name: Comment build generating + if: github.event_name == 'pull_request' + uses: actions-cool/maintain-one-comment@v3.1.1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + body: | + [](#) + + 🔨 Building packages... + + body-include: '' + number: ${{ inputs.pr-number }} + + - name: Publish to pkg.pr.new + id: pkg-pr-new + run: | + npx pkg-pr-new publish \ + ./packages/components \ + ./packages/kit \ + ./packages/svgs \ + --pnpm \ + --json output.json \ + --comment=off + + - name: Post or update pkg.pr.new comment + if: github.event_name == 'pull_request' + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const fs = require('fs'); + const output = JSON.parse(fs.readFileSync('output.json', 'utf8')); + + const sha = context.payload.pull_request.head.sha.substring(0, 7); + + const packages = output.packages.map((p) => { + const shortUrl = p.url.replace(/@[a-f0-9]{40}/, '@' + sha); + return 'pnpm add ' + shortUrl; + }).join('\n\n'); + + const commitUrl = 'https://github.com/' + context.repo.owner + '/' + context.repo.repo + '/commit/' + sha; + + const body = '## 📦 Package Preview\n\n' + packages + '\n\n**commit:** [' + sha + '](' + commitUrl + ')\n\n'; + const botCommentIdentifier = ''; + + const comments = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + }); + + const existingComment = comments.data.find((comment) => + comment.body.includes(botCommentIdentifier) + ); + + if (existingComment) { + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: existingComment.id, + body: body, + }); + } else { + await github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: body, + }); + } + + - name: Deploy Site to Surge + id: deploy + run: | + DEPLOY_DOMAIN=preview-${{ inputs.pr-number }}-tiny-robot.surge.sh + echo "Deploying to: https://$DEPLOY_DOMAIN" + npx surge --project ./docs/dist --domain $DEPLOY_DOMAIN --token $SURGE_TOKEN + echo "url=https://$DEPLOY_DOMAIN" >> $GITHUB_OUTPUT + env: + SURGE_TOKEN: ${{ secrets.SURGE_TOKEN }} + + - name: Comment build success + if: ${{ success() && github.event_name == 'pull_request' }} + uses: actions-cool/maintain-one-comment@v3.1.1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + body: | + [](https://preview-${{ inputs.pr-number }}-tiny-robot.surge.sh) + + ✅ Preview build completed successfully! + + > Click the image above to preview. + > Preview will be automatically removed when this PR is closed. + + body-include: '' + number: ${{ inputs.pr-number }} + + - name: Comment build failed + if: ${{ failure() && github.event_name == 'pull_request' }} + uses: actions-cool/maintain-one-comment@v3.1.1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + body: | + [](#) + + ❌ Build failed. Please check the logs for details. + + body-include: '' + number: ${{ inputs.pr-number }} diff --git a/.github/workflows/pr-ci.yml b/.github/workflows/pr-ci.yml new file mode 100644 index 000000000..a1c4d353d --- /dev/null +++ b/.github/workflows/pr-ci.yml @@ -0,0 +1,43 @@ +name: ci + +on: + push: + branches: [ develop, main ] + pull_request: + types: [opened, synchronize, reopened] + +# 取消同一 PR 的旧运行 +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + # 构建组件 + build: + # 跳过不需要构建的 PR(仅检查 PR 标题) + if: | + !( + github.event_name == 'pull_request' && ( + contains(github.event.pull_request.title, 'docs:') || + contains(github.event.pull_request.title, 'chore: release') || + startsWith(github.event.pull_request.title, 'v') || + startsWith(github.event.pull_request.title, 'V') + ) + ) + uses: ./.github/workflows/pr-ci-build.yml + with: + skip-playground: true + + # 生成预览(依赖构建,仅 PR 事件) + preview: + needs: [build] + if: github.event_name == 'pull_request' + uses: ./.github/workflows/pr-ci-preview.yml + with: + pr-number: ${{ github.event.pull_request.number }} + secrets: inherit + + # E2E 测试(依赖构建,与预览并行) + e2e-test: + needs: [build] + uses: ./.github/workflows/pr-ci-e2e-test.yml diff --git a/.github/workflows/pr-cleanup.yml b/.github/workflows/pr-cleanup.yml new file mode 100644 index 000000000..11b74472a --- /dev/null +++ b/.github/workflows/pr-cleanup.yml @@ -0,0 +1,31 @@ +name: PR Docs Cleanup + +on: + pull_request: + types: [closed] + +jobs: + cleanup: + runs-on: ubuntu-latest + steps: + - name: Remove Surge deployment + run: | + DEPLOY_DOMAIN=preview-${{ github.event.pull_request.number }}-tiny-robot.surge.sh + echo "Removing deployment: $DEPLOY_DOMAIN" + npx surge teardown $DEPLOY_DOMAIN --token $SURGE_TOKEN + env: + SURGE_TOKEN: ${{ secrets.SURGE_TOKEN }} + continue-on-error: true + + - name: Comment cleanup status + uses: actions-cool/maintain-one-comment@v3.1.1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + body: | + ## 🧹 Preview Cleaned Up + + The preview deployment has been removed. + + + body-include: '' + number: ${{ github.event.pull_request.number }}