chore(deps): bump axios from 1.8.4 to 1.13.5 in /web #65
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # .github/workflows/frontend-quality-check.yml (安全修复版本) | |
| name: Frontend Code Quality Check | |
| # 🔒 工作流级权限控制 | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| issues: write | |
| actions: read | |
| on: | |
| pull_request: | |
| branches: [main, master, develop] | |
| paths: | |
| - "web/**" | |
| - "*.json" | |
| - "*.js" | |
| - "*.ts" | |
| - "*.tsx" | |
| - "*.vue" | |
| - "*.jsx" | |
| # 专门用于 PR 评论的触发器 | |
| pull_request_target: | |
| types: [opened, synchronize, reopened] | |
| branches: [main, master, develop] | |
| push: | |
| branches: [main, master, develop] | |
| paths: | |
| - "web/**" | |
| - "*.json" | |
| - "*.js" | |
| - "*.ts" | |
| - "*.tsx" | |
| - "*.vue" | |
| - "*.jsx" | |
| workflow_dispatch: | |
| jobs: | |
| # 主要的 CI 检查 job(使用 pull_request,安全执行外部代码) | |
| frontend-check: | |
| name: Frontend Code Quality Check | |
| runs-on: ubuntu-latest | |
| # 只在 pull_request 和 push 事件时运行,不在 pull_request_target 时运行 | |
| if: github.event_name != 'pull_request_target' | |
| outputs: | |
| frontend-exists: ${{ steps.check-frontend.outputs.exists }} | |
| framework: ${{ steps.analyze-config.outputs.framework }} | |
| is-typescript: ${{ steps.analyze-config.outputs.is_typescript }} | |
| has-lint: ${{ steps.analyze-config.outputs.has_lint }} | |
| has-test: ${{ steps.analyze-config.outputs.has_test }} | |
| has-build: ${{ steps.analyze-config.outputs.has_build }} | |
| lint-status: ${{ steps.set-status.outputs.lint_status }} | |
| typecheck-status: ${{ steps.set-status.outputs.typecheck_status }} | |
| test-status: ${{ steps.set-status.outputs.test_status }} | |
| build-status: ${{ steps.set-status.outputs.build_status }} | |
| steps: | |
| # ✅ 使用官方推荐的最新稳定版本 | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Check frontend project | |
| id: check-frontend | |
| run: | | |
| if [ -d "web" ] && [ -f "web/package.json" ]; then | |
| echo "✅ 发现前端项目" | |
| echo "exists=true" >> $GITHUB_OUTPUT | |
| echo "FRONTEND_EXISTS=true" >> $GITHUB_ENV | |
| else | |
| echo "ℹ️ 未发现前端项目,跳过前端检查" | |
| echo "exists=false" >> $GITHUB_OUTPUT | |
| echo "FRONTEND_EXISTS=false" >> $GITHUB_ENV | |
| fi | |
| - name: Setup Node.js | |
| if: steps.check-frontend.outputs.exists == 'true' | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "23.10.0" | |
| - name: Install pnpm | |
| if: steps.check-frontend.outputs.exists == 'true' | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: 10.11.0 | |
| - name: Get pnpm store directory | |
| if: steps.check-frontend.outputs.exists == 'true' | |
| id: pnpm-cache | |
| shell: bash | |
| run: | | |
| echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT | |
| # ✅ 使用 v4 - 官方推荐的稳定版本 | |
| - name: Setup pnpm cache | |
| if: steps.check-frontend.outputs.exists == 'true' | |
| uses: actions/cache@v4 | |
| with: | |
| path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} | |
| key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pnpm-store- | |
| - name: Analyze project configuration | |
| if: steps.check-frontend.outputs.exists == 'true' | |
| id: analyze-config | |
| run: | | |
| cd web | |
| echo "🔍 分析前端项目配置..." | |
| # 检查package.json中的脚本 | |
| if grep -q '"lint"' package.json; then | |
| echo "✅ 发现 lint 脚本" | |
| echo "has_lint=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "⚠️ 未配置 lint 脚本" | |
| echo "has_lint=false" >> $GITHUB_OUTPUT | |
| fi | |
| if grep -q '"test"' package.json; then | |
| echo "✅ 发现 test 脚本" | |
| echo "has_test=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "⚠️ 未配置 test 脚本" | |
| echo "has_test=false" >> $GITHUB_OUTPUT | |
| fi | |
| if grep -q '"build"' package.json; then | |
| echo "✅ 发现 build 脚本" | |
| echo "has_build=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "⚠️ 未配置 build 脚本" | |
| echo "has_build=false" >> $GITHUB_OUTPUT | |
| fi | |
| # 检查TypeScript配置 | |
| if [ -f "tsconfig.json" ]; then | |
| echo "✅ 发现 TypeScript 项目" | |
| echo "is_typescript=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "ℹ️ 非 TypeScript 项目" | |
| echo "is_typescript=false" >> $GITHUB_OUTPUT | |
| fi | |
| # 检查框架类型 | |
| if grep -q '"vue"' package.json; then | |
| echo "📦 检测到 Vue.js 项目" | |
| echo "framework=vue" >> $GITHUB_OUTPUT | |
| elif grep -q '"react"' package.json; then | |
| echo "📦 检测到 React 项目" | |
| echo "framework=react" >> $GITHUB_OUTPUT | |
| elif grep -q '"next"' package.json; then | |
| echo "📦 检测到 Next.js 项目" | |
| echo "framework=nextjs" >> $GITHUB_OUTPUT | |
| else | |
| echo "📦 普通 JavaScript 项目" | |
| echo "framework=vanilla" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Install dependencies | |
| if: steps.check-frontend.outputs.exists == 'true' | |
| run: | | |
| cd web | |
| echo "📦 安装前端依赖..." | |
| # 🔒 使用 --frozen-lockfile 确保依赖一致性 | |
| pnpm install --frozen-lockfile | |
| echo "✅ 依赖安装完成" | |
| # 运行 ESLint | |
| - name: Run ESLint | |
| if: steps.check-frontend.outputs.exists == 'true' && steps.analyze-config.outputs.has_lint == 'true' | |
| run: | | |
| cd web | |
| echo "🔍 运行 ESLint 代码检查..." | |
| if pnpm lint; then | |
| echo "✅ ESLint 检查通过" | |
| echo "LINT_STATUS=success" >> $GITHUB_ENV | |
| else | |
| echo "❌ ESLint 检查失败" | |
| echo "LINT_STATUS=failed" >> $GITHUB_ENV | |
| exit 1 | |
| fi | |
| - name: Skip ESLint (not configured) | |
| if: steps.check-frontend.outputs.exists == 'true' && steps.analyze-config.outputs.has_lint == 'false' | |
| run: | | |
| echo "⚠️ 项目未配置 ESLint,跳过代码检查" | |
| echo "LINT_STATUS=skipped" >> $GITHUB_ENV | |
| # 运行 TypeScript 类型检查 | |
| - name: Run TypeScript check | |
| if: steps.check-frontend.outputs.exists == 'true' && steps.analyze-config.outputs.is_typescript == 'true' | |
| run: | | |
| cd web | |
| echo "🔍 运行 TypeScript 类型检查..." | |
| if pnpm tsc --noEmit; then | |
| echo "✅ TypeScript 类型检查通过" | |
| echo "TYPECHECK_STATUS=success" >> $GITHUB_ENV | |
| else | |
| echo "❌ TypeScript 类型检查失败" | |
| echo "TYPECHECK_STATUS=failed" >> $GITHUB_ENV | |
| exit 1 | |
| fi | |
| - name: Skip TypeScript check (not TypeScript project) | |
| if: steps.check-frontend.outputs.exists == 'true' && steps.analyze-config.outputs.is_typescript == 'false' | |
| run: | | |
| echo "ℹ️ 非 TypeScript 项目,跳过类型检查" | |
| echo "TYPECHECK_STATUS=skipped" >> $GITHUB_ENV | |
| # 运行测试 | |
| - name: Run tests | |
| if: steps.check-frontend.outputs.exists == 'true' && steps.analyze-config.outputs.has_test == 'true' | |
| run: | | |
| cd web | |
| echo "🧪 运行前端测试..." | |
| if pnpm test --passWithNoTests; then | |
| echo "✅ 前端测试通过" | |
| echo "TEST_STATUS=success" >> $GITHUB_ENV | |
| else | |
| echo "❌ 前端测试失败" | |
| echo "TEST_STATUS=failed" >> $GITHUB_ENV | |
| exit 1 | |
| fi | |
| - name: Skip tests (not configured) | |
| if: steps.check-frontend.outputs.exists == 'true' && steps.analyze-config.outputs.has_test == 'false' | |
| run: | | |
| echo "⚠️ 项目未配置测试,跳过测试" | |
| echo "TEST_STATUS=skipped" >> $GITHUB_ENV | |
| # 检查构建 | |
| - name: Test build | |
| if: steps.check-frontend.outputs.exists == 'true' && steps.analyze-config.outputs.has_build == 'true' | |
| run: | | |
| cd web | |
| echo "🏗️ 测试前端构建..." | |
| if pnpm build; then | |
| echo "✅ 前端构建成功" | |
| echo "BUILD_STATUS=success" >> $GITHUB_ENV | |
| else | |
| echo "❌ 前端构建失败" | |
| echo "BUILD_STATUS=failed" >> $GITHUB_ENV | |
| exit 1 | |
| fi | |
| - name: Skip build (not configured) | |
| if: steps.check-frontend.outputs.exists == 'true' && steps.analyze-config.outputs.has_build == 'false' | |
| run: | | |
| echo "⚠️ 项目未配置构建脚本,跳过构建测试" | |
| echo "BUILD_STATUS=skipped" >> $GITHUB_ENV | |
| # 📤 设置输出状态(修复VS Code警告) | |
| - name: Set job outputs | |
| id: set-status | |
| if: always() | |
| run: | | |
| echo "lint_status=${LINT_STATUS:-skipped}" >> $GITHUB_OUTPUT | |
| echo "typecheck_status=${TYPECHECK_STATUS:-skipped}" >> $GITHUB_OUTPUT | |
| echo "test_status=${TEST_STATUS:-skipped}" >> $GITHUB_OUTPUT | |
| echo "build_status=${BUILD_STATUS:-skipped}" >> $GITHUB_OUTPUT | |
| # 🔒 可选:安全审计步骤 | |
| - name: Security Audit | |
| if: steps.check-frontend.outputs.exists == 'true' | |
| run: | | |
| cd web | |
| echo "🔍 运行安全审计..." | |
| # 检查已知漏洞 | |
| if command -v pnpm &> /dev/null; then | |
| pnpm audit --audit-level moderate || echo "⚠️ 发现安全问题,建议检查" | |
| fi | |
| continue-on-error: true | |
| # 生成检查报告 | |
| - name: Generate Frontend check summary | |
| if: always() | |
| run: | | |
| echo "## 🎨 Frontend Code Quality Check Report" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| if [ "$FRONTEND_EXISTS" = "false" ]; then | |
| echo "### ℹ️ Project Status" >> $GITHUB_STEP_SUMMARY | |
| echo "No frontend project found, skipping frontend code checks." >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "If your frontend code is not in the \`web/\` directory, please adjust the workflow configuration." >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "### 📋 Check Results" >> $GITHUB_STEP_SUMMARY | |
| echo "| Check Item | Status | Description |" >> $GITHUB_STEP_SUMMARY | |
| echo "|---------|------|------|" >> $GITHUB_STEP_SUMMARY | |
| # ESLint状态 | |
| case "$LINT_STATUS" in | |
| "success") echo "| Code Standards (ESLint) | ✅ Passed | Code meets standards |" >> $GITHUB_STEP_SUMMARY ;; | |
| "failed") echo "| Code Standards (ESLint) | ❌ Failed | Found code standard issues |" >> $GITHUB_STEP_SUMMARY ;; | |
| *) echo "| Code Standards (ESLint) | ⚠️ Skipped | No lint script configured |" >> $GITHUB_STEP_SUMMARY ;; | |
| esac | |
| # TypeScript状态 | |
| case "$TYPECHECK_STATUS" in | |
| "success") echo "| Type Check (TypeScript) | ✅ Passed | Type definitions correct |" >> $GITHUB_STEP_SUMMARY ;; | |
| "failed") echo "| Type Check (TypeScript) | ❌ Failed | Found type errors |" >> $GITHUB_STEP_SUMMARY ;; | |
| *) echo "| Type Check (TypeScript) | ⚠️ Skipped | Not a TypeScript project |" >> $GITHUB_STEP_SUMMARY ;; | |
| esac | |
| # 测试状态 | |
| case "$TEST_STATUS" in | |
| "success") echo "| Unit Tests | ✅ Passed | All tests passed |" >> $GITHUB_STEP_SUMMARY ;; | |
| "failed") echo "| Unit Tests | ❌ Failed | Test cases failed |" >> $GITHUB_STEP_SUMMARY ;; | |
| *) echo "| Unit Tests | ⚠️ Skipped | No test script configured |" >> $GITHUB_STEP_SUMMARY ;; | |
| esac | |
| # 构建状态 | |
| case "$BUILD_STATUS" in | |
| "success") echo "| Build Test | ✅ Passed | Build successful |" >> $GITHUB_STEP_SUMMARY ;; | |
| "failed") echo "| Build Test | ❌ Failed | Build process error |" >> $GITHUB_STEP_SUMMARY ;; | |
| *) echo "| Build Test | ⚠️ Skipped | No build script configured |" >> $GITHUB_STEP_SUMMARY ;; | |
| esac | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### 📊 Project Information" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Framework**: ${{ steps.analyze-config.outputs.framework }}" >> $GITHUB_STEP_SUMMARY | |
| echo "- **TypeScript**: ${{ steps.analyze-config.outputs.is_typescript == 'true' && '✅ Yes' || '❌ No' }}" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Node.js Version**: 23.10.0" >> $GITHUB_STEP_SUMMARY | |
| echo "- **pnpm Version**: 10.11.0" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### 📊 Runtime Information" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Commit SHA**: \`${{ github.sha }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Branch**: \`${{ github.ref_name }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Triggered by**: @${{ github.actor }}" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Check Time**: $(date '+%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY | |
| # 🔒 安全的 PR 评论 job(使用 pull_request_target,但不 checkout 外部代码) | |
| pr-comment: | |
| name: PR Comment Handler | |
| runs-on: ubuntu-latest | |
| # 只在 pull_request_target 事件时运行 | |
| if: github.event_name == 'pull_request_target' | |
| steps: | |
| # 🔒 重要:不 checkout 任何代码,特别是 PR 代码! | |
| # 🔒 只使用 GitHub API 获取工作流运行结果 | |
| - name: Wait for main check to complete | |
| uses: actions/github-script@v7 | |
| id: wait-for-check | |
| with: | |
| script: | | |
| const { owner, repo } = context.repo; | |
| const headSha = context.payload.pull_request.head.sha; | |
| console.log(`等待 commit ${headSha} 的检查完成...`); | |
| // 等待最多 10 分钟 | |
| const maxWaitTime = 10 * 60 * 1000; // 10 minutes | |
| const startTime = Date.now(); | |
| while (Date.now() - startTime < maxWaitTime) { | |
| try { | |
| // 获取 commit 的所有 check runs | |
| const { data: checkRuns } = await github.rest.checks.listForRef({ | |
| owner, | |
| repo, | |
| ref: headSha, | |
| }); | |
| // 查找我们的前端检查工作流 | |
| const frontendCheck = checkRuns.check_runs.find(run => | |
| run.name === 'Frontend Code Quality Check' | |
| ); | |
| if (frontendCheck) { | |
| console.log(`发现检查: ${frontendCheck.name}, 状态: ${frontendCheck.status}`); | |
| if (frontendCheck.status === 'completed') { | |
| console.log(`检查完成,结论: ${frontendCheck.conclusion}`); | |
| return { | |
| completed: true, | |
| conclusion: frontendCheck.conclusion, | |
| details_url: frontendCheck.details_url | |
| }; | |
| } | |
| } | |
| // 等待 30 秒后重试 | |
| await new Promise(resolve => setTimeout(resolve, 30000)); | |
| } catch (error) { | |
| console.log(`获取检查状态时出错: ${error.message}`); | |
| await new Promise(resolve => setTimeout(resolve, 30000)); | |
| } | |
| } | |
| // 超时情况 | |
| console.log('等待超时,使用默认值'); | |
| return { | |
| completed: false, | |
| conclusion: 'timed_out', | |
| details_url: null | |
| }; | |
| - name: Comment on PR | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const checkResult = ${{ steps.wait-for-check.outputs.result }}; | |
| const prNumber = context.payload.pull_request.number; | |
| let emoji, statusEn, statusCn, conclusion; | |
| if (!checkResult.completed) { | |
| emoji = '⏰'; | |
| statusEn = 'In Progress'; | |
| statusCn = '进行中'; | |
| conclusion = 'pending'; | |
| } else { | |
| switch(checkResult.conclusion) { | |
| case 'success': | |
| emoji = '✅'; | |
| statusEn = 'Passed'; | |
| statusCn = '通过'; | |
| conclusion = 'success'; | |
| break; | |
| case 'failure': | |
| emoji = '❌'; | |
| statusEn = 'Failed'; | |
| statusCn = '失败'; | |
| conclusion = 'failure'; | |
| break; | |
| default: | |
| emoji = '⚠️'; | |
| statusEn = 'Unknown'; | |
| statusCn = '未知'; | |
| conclusion = 'neutral'; | |
| } | |
| } | |
| // 构建中文报告 | |
| let chineseReport = `### 中文报告\n\n`; | |
| if (!checkResult.completed) { | |
| chineseReport += `**⏰ 状态:** 前端代码质量检查正在进行中,请稍候查看结果。`; | |
| } else if (checkResult.conclusion === 'success') { | |
| chineseReport += `**🎉 结果:** 前端代码质量检查全部通过!\n\n`; | |
| chineseReport += `**📋 检查项目:**\n`; | |
| chineseReport += `- ✅ 代码规范检查 (ESLint)\n`; | |
| chineseReport += `- ✅ 类型检查 (TypeScript)\n`; | |
| chineseReport += `- ✅ 单元测试\n`; | |
| chineseReport += `- ✅ 构建测试`; | |
| } else if (checkResult.conclusion === 'failure') { | |
| chineseReport += `**⚠️ 需要关注:** 发现需要修复的问题,请查看详细日志。\n\n`; | |
| chineseReport += `点击下方链接查看详细检查结果。`; | |
| } else { | |
| chineseReport += `**ℹ️ 状态:** 检查状态异常,请检查工作流配置。`; | |
| } | |
| // 构建英文报告 | |
| let englishReport = `### English Report\n\n`; | |
| if (!checkResult.completed) { | |
| englishReport += `**⏰ Status:** Frontend code quality check is in progress, please wait for results.`; | |
| } else if (checkResult.conclusion === 'success') { | |
| englishReport += `**🎉 Result:** All frontend code quality checks passed!\n\n`; | |
| englishReport += `**📋 Check Items:**\n`; | |
| englishReport += `- ✅ Code Standards (ESLint)\n`; | |
| englishReport += `- ✅ Type Check (TypeScript)\n`; | |
| englishReport += `- ✅ Unit Tests\n`; | |
| englishReport += `- ✅ Build Test`; | |
| } else if (checkResult.conclusion === 'failure') { | |
| englishReport += `**⚠️ Attention Required:** Issues found that need to be fixed. Please check the detailed logs.\n\n`; | |
| englishReport += `Click the link below to view detailed check results.`; | |
| } else { | |
| englishReport += `**ℹ️ Status:** Check status is abnormal, please check workflow configuration.`; | |
| } | |
| // 组合最终内容 | |
| let body = `## 🎨 Frontend Code Quality Check ${statusEn} ${emoji}\n\n`; | |
| body += `**PR #${prNumber}** frontend code check completed.\n\n`; | |
| body += `${chineseReport}\n\n---\n\n${englishReport}`; | |
| // 如果有详细链接,添加到报告中 | |
| if (checkResult.details_url) { | |
| body += `\n\n**🔗 View Details:** [Click here to see the full check results](${checkResult.details_url})`; | |
| } | |
| // 查找并更新现有评论 | |
| const { data: comments } = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: prNumber, | |
| }); | |
| const botComment = comments.find(comment => | |
| comment.user.type === 'Bot' && | |
| comment.body.includes('🎨 Frontend Code Quality Check') | |
| ); | |
| if (botComment) { | |
| await github.rest.issues.updateComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: botComment.id, | |
| body: body | |
| }); | |
| console.log('已更新现有的 PR 评论'); | |
| } else { | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: prNumber, | |
| body: body | |
| }); | |
| console.log('已创建新的 PR 评论'); | |
| } |