Skip to content

chore(deps): bump axios from 1.8.4 to 1.13.5 in /web #65

chore(deps): bump axios from 1.8.4 to 1.13.5 in /web

chore(deps): bump axios from 1.8.4 to 1.13.5 in /web #65

# .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 评论');
}