📦 Dependencies Management #7
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
| name: 📦 Dependencies Management | |
| on: | |
| schedule: | |
| # 每周一凌晨 2 点检查依赖更新 | |
| - cron: "0 2 * * 1" | |
| workflow_dispatch: | |
| inputs: | |
| update_type: | |
| description: "Type of update to perform" | |
| required: true | |
| default: "patch" | |
| type: choice | |
| options: | |
| - patch | |
| - minor | |
| - major | |
| - all | |
| jobs: | |
| # ============================================================================ | |
| # 依赖安全扫描 | |
| # ============================================================================ | |
| security-audit: | |
| name: 🔒 Security Audit | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: 📥 Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Detect package manager | |
| id: detect-package-manager | |
| run: | | |
| if [ -f "${{ github.workspace }}/pnpm-lock.yaml" ]; then | |
| echo "manager=pnpm" >> $GITHUB_OUTPUT | |
| echo "command=install --frozen-lockfile" >> $GITHUB_OUTPUT | |
| exit 0 | |
| elif [ -f "${{ github.workspace }}/yarn.lock" ]; then | |
| echo "manager=yarn" >> $GITHUB_OUTPUT | |
| echo "command=install" >> $GITHUB_OUTPUT | |
| exit 0 | |
| elif [ -f "${{ github.workspace }}/package-lock.json" ]; then | |
| echo "manager=npm" >> $GITHUB_OUTPUT | |
| echo "command=ci" >> $GITHUB_OUTPUT | |
| exit 0 | |
| else | |
| echo "Unable to determine package manager" | |
| exit 1 | |
| fi | |
| - name: Setup pnpm | |
| if: steps.detect-package-manager.outputs.manager == 'pnpm' | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: 10.19.0 | |
| - name: 📦 Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "22" | |
| cache: ${{ steps.detect-package-manager.outputs.manager }} | |
| - name: 📥 Install dependencies | |
| run: ${{ steps.detect-package-manager.outputs.manager }} ${{ steps.detect-package-manager.outputs.command }} | |
| - name: 🔒 Run security audit | |
| run: | | |
| echo "## 🔒 Security Audit Report" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| # 运行安全审计 | |
| if ${{ steps.detect-package-manager.outputs.manager }} audit --json > audit-report.json 2>/dev/null; then | |
| # 解析审计结果 | |
| vulnerabilities=$(node -e " | |
| const audit = require('./audit-report.json'); | |
| const meta = audit.metadata?.vulnerabilities; | |
| if (meta) { | |
| const total = meta.total || 0; | |
| const critical = meta.critical || 0; | |
| const high = meta.high || 0; | |
| const moderate = meta.moderate || 0; | |
| const low = meta.low || 0; | |
| console.log(JSON.stringify({total, critical, high, moderate, low})); | |
| } else { | |
| console.log(JSON.stringify({total: 0, critical: 0, high: 0, moderate: 0, low: 0})); | |
| } | |
| ") | |
| echo "| Severity | Count |" >> $GITHUB_STEP_SUMMARY | |
| echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY | |
| echo "| Critical | $(echo $vulnerabilities | jq -r '.critical') |" >> $GITHUB_STEP_SUMMARY | |
| echo "| High | $(echo $vulnerabilities | jq -r '.high') |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Moderate | $(echo $vulnerabilities | jq -r '.moderate') |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Low | $(echo $vulnerabilities | jq -r '.low') |" >> $GITHUB_STEP_SUMMARY | |
| echo "| **Total** | **$(echo $vulnerabilities | jq -r '.total')** |" >> $GITHUB_STEP_SUMMARY | |
| total_vulns=$(echo $vulnerabilities | jq -r '.total') | |
| if [ "$total_vulns" -gt 0 ]; then | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "⚠️ **Action Required**: $total_vulns security vulnerabilities found!" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "Run \`${{ steps.detect-package-manager.outputs.manager }} audit fix\` to automatically fix vulnerabilities." >> $GITHUB_STEP_SUMMARY | |
| # 如果有高危或严重漏洞,创建 issue | |
| critical=$(echo $vulnerabilities | jq -r '.critical') | |
| high=$(echo $vulnerabilities | jq -r '.high') | |
| if [ "$critical" -gt 0 ] || [ "$high" -gt 0 ]; then | |
| echo "create_security_issue=true" >> $GITHUB_ENV | |
| echo "security_summary=Found $critical critical and $high high severity vulnerabilities" >> $GITHUB_ENV | |
| fi | |
| else | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "✅ No security vulnerabilities found!" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| else | |
| echo "✅ No security vulnerabilities found!" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| - name: 📤 Upload audit report | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: security-audit-report | |
| path: audit-report.json | |
| retention-days: 30 | |
| - name: 🚨 Create security issue | |
| if: env.create_security_issue == 'true' | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const title = '🔒 Security Vulnerabilities Detected' | |
| const body = ` | |
| ## 🚨 Security Alert | |
| Our automated security scan has detected vulnerabilities in the project dependencies. | |
| **Summary**: ${{ env.security_summary }} | |
| ## 🔧 Recommended Actions | |
| 1. Review the security audit report | |
| 2. Run \`pnpm audit fix\` to automatically fix vulnerabilities (or use the detected package manager) | |
| 3. For vulnerabilities that cannot be auto-fixed, consider: | |
| - Updating to a secure version manually | |
| - Finding alternative packages | |
| - Implementing workarounds | |
| ## 📊 Full Report | |
| See the attached audit report for detailed information about each vulnerability. | |
| **Workflow Run**: [#${{ github.run_number }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) | |
| ` | |
| github.rest.issues.create({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| title: title, | |
| body: body, | |
| labels: ['security', 'dependencies', 'high-priority'] | |
| }) | |
| # ============================================================================ | |
| # 依赖更新检查 | |
| # ============================================================================ | |
| check-updates: | |
| name: 📋 Check for Updates | |
| runs-on: ubuntu-latest | |
| needs: security-audit | |
| outputs: | |
| has-updates: ${{ steps.check.outputs.has-updates }} | |
| update-summary: ${{ steps.check.outputs.update-summary }} | |
| steps: | |
| - name: 📥 Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Detect package manager | |
| id: detect-package-manager | |
| run: | | |
| if [ -f "${{ github.workspace }}/pnpm-lock.yaml" ]; then | |
| echo "manager=pnpm" >> $GITHUB_OUTPUT | |
| echo "command=install --frozen-lockfile" >> $GITHUB_OUTPUT | |
| exit 0 | |
| elif [ -f "${{ github.workspace }}/yarn.lock" ]; then | |
| echo "manager=yarn" >> $GITHUB_OUTPUT | |
| echo "command=install" >> $GITHUB_OUTPUT | |
| exit 0 | |
| elif [ -f "${{ github.workspace }}/package-lock.json" ]; then | |
| echo "manager=npm" >> $GITHUB_OUTPUT | |
| echo "command=ci" >> $GITHUB_OUTPUT | |
| exit 0 | |
| else | |
| echo "Unable to determine package manager" | |
| exit 1 | |
| fi | |
| - name: Setup pnpm | |
| if: steps.detect-package-manager.outputs.manager == 'pnpm' | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: 10.19.0 | |
| - name: 📦 Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "22" | |
| cache: ${{ steps.detect-package-manager.outputs.manager }} | |
| - name: 📥 Install dependencies | |
| run: ${{ steps.detect-package-manager.outputs.manager }} ${{ steps.detect-package-manager.outputs.command }} | |
| - name: 📋 Check for outdated packages | |
| id: check | |
| run: | | |
| echo "## 📋 Dependency Update Check" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| # 检查过期的包 | |
| if ${{ steps.detect-package-manager.outputs.manager }} outdated --json > outdated.json 2>/dev/null; then | |
| if [ -s outdated.json ]; then | |
| echo "has-updates=true" >> $GITHUB_OUTPUT | |
| # 生成更新摘要 | |
| update_count=$(node -e " | |
| const outdated = require('./outdated.json'); | |
| console.log(Object.keys(outdated).length); | |
| ") | |
| echo "update-summary=Found $update_count packages that can be updated" >> $GITHUB_OUTPUT | |
| echo "### 📦 Outdated Packages ($update_count)" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "| Package | Current | Wanted | Latest | Type |" >> $GITHUB_STEP_SUMMARY | |
| echo "|---------|---------|--------|--------|------|" >> $GITHUB_STEP_SUMMARY | |
| node -e " | |
| const outdated = require('./outdated.json'); | |
| Object.entries(outdated).forEach(([pkg, info]) => { | |
| const updateType = info.wanted !== info.current ? 'wanted' : 'latest'; | |
| console.log(\`| \${pkg} | \${info.current} | \${info.wanted} | \${info.latest} | \${updateType} |\`); | |
| }); | |
| " >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "🔄 Updates are available! Consider running the dependency update workflow." >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "has-updates=false" >> $GITHUB_OUTPUT | |
| echo "update-summary=All packages are up to date" >> $GITHUB_OUTPUT | |
| echo "✅ All packages are up to date!" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| else | |
| echo "has-updates=false" >> $GITHUB_OUTPUT | |
| echo "update-summary=All packages are up to date" >> $GITHUB_OUTPUT | |
| echo "✅ All packages are up to date!" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| - name: 📤 Upload outdated report | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: outdated-packages-report | |
| path: outdated.json | |
| retention-days: 7 | |
| # ============================================================================ | |
| # 自动依赖更新 | |
| # ============================================================================ | |
| auto-update: | |
| name: 🔄 Auto Update Dependencies | |
| runs-on: ubuntu-latest | |
| needs: [security-audit, check-updates] | |
| if: needs.check-updates.outputs.has-updates == 'true' | |
| steps: | |
| - name: 📥 Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: 📦 Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "22" | |
| cache: "npm" | |
| - name: 📥 Install dependencies | |
| run: npm ci | |
| - name: 🔄 Update dependencies | |
| run: | | |
| echo "## 🔄 Updating Dependencies" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| update_type="${{ github.event.inputs.update_type || 'patch' }}" | |
| case $update_type in | |
| "patch") | |
| echo "Updating patch versions..." >> $GITHUB_STEP_SUMMARY | |
| ${{ steps.detect-package-manager.outputs.manager }} update | |
| ;; | |
| "minor") | |
| echo "Updating minor versions..." >> $GITHUB_STEP_SUMMARY | |
| npx npm-check-updates -u --target minor | |
| ${{ steps.detect-package-manager.outputs.manager }} install | |
| ;; | |
| "major") | |
| echo "Updating major versions..." >> $GITHUB_STEP_SUMMARY | |
| npx npm-check-updates -u --target major | |
| ${{ steps.detect-package-manager.outputs.manager }} install | |
| ;; | |
| "all") | |
| echo "Updating all versions..." >> $GITHUB_STEP_SUMMARY | |
| npx npm-check-updates -u | |
| ${{ steps.detect-package-manager.outputs.manager }} install | |
| ;; | |
| esac | |
| - name: 🧪 Run tests after update | |
| run: | | |
| echo "## 🧪 Testing Updated Dependencies" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| # 安装测试依赖 | |
| ${{ steps.detect-package-manager.outputs.manager }} add -D vitest jsdom @vitest/ui c8 | |
| # 运行测试 | |
| if npx vitest run tests/utils/config-helpers*.test.ts --reporter=verbose; then | |
| echo "✅ All tests passed with updated dependencies!" >> $GITHUB_STEP_SUMMARY | |
| echo "test_status=passed" >> $GITHUB_ENV | |
| else | |
| echo "❌ Tests failed with updated dependencies!" >> $GITHUB_STEP_SUMMARY | |
| echo "test_status=failed" >> $GITHUB_ENV | |
| fi | |
| - name: 🔍 Check for changes | |
| id: changes | |
| run: | | |
| if [[ -n $(git status --porcelain) ]]; then | |
| echo "changes=true" >> $GITHUB_OUTPUT | |
| # 生成变更摘要 | |
| echo "## 📝 Changes Made" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Modified Files:" >> $GITHUB_STEP_SUMMARY | |
| git status --porcelain | while read status file; do | |
| echo "- $file" >> $GITHUB_STEP_SUMMARY | |
| done | |
| # 检查 package.json 的变更 | |
| if git diff --name-only | grep -q "package.json\|pnpm-lock.yaml\|package-lock.json\|yarn.lock"; then | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Package Changes:" >> $GITHUB_STEP_SUMMARY | |
| echo "\`\`\`diff" >> $GITHUB_STEP_SUMMARY | |
| git diff package.json | head -50 >> $GITHUB_STEP_SUMMARY | |
| echo "\`\`\`" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| else | |
| echo "changes=false" >> $GITHUB_OUTPUT | |
| echo "No changes detected." >> $GITHUB_STEP_SUMMARY | |
| fi | |
| - name: 🔧 Create Pull Request | |
| if: steps.changes.outputs.changes == 'true' && env.test_status == 'passed' | |
| uses: peter-evans/create-pull-request@v5 | |
| with: | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| commit-message: "🔄 chore: update dependencies (${{ github.event.inputs.update_type || 'patch' }})" | |
| title: "🔄 Dependency Updates (${{ github.event.inputs.update_type || 'patch' }})" | |
| body: | | |
| ## 🔄 Automated Dependency Update | |
| This PR contains automated dependency updates. | |
| ### 📋 Update Summary | |
| - **Update Type**: ${{ github.event.inputs.update_type || 'patch' }} | |
| - **Status**: ${{ needs.check-updates.outputs.update-summary }} | |
| ### 🧪 Testing | |
| - ✅ All existing tests pass | |
| - ✅ No breaking changes detected | |
| - ✅ Security audit completed | |
| ### 🔍 Review Checklist | |
| - [ ] Review dependency changes | |
| - [ ] Verify test results | |
| - [ ] Check for any breaking changes | |
| - [ ] Approve and merge if everything looks good | |
| --- | |
| 🤖 This PR was created automatically by the dependency management workflow. | |
| **Workflow Run**: [#${{ github.run_number }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) | |
| branch: automated/dependency-updates-${{ github.run_number }} | |
| labels: | | |
| dependencies | |
| automated | |
| ${{ github.event.inputs.update_type || 'patch' }} | |
| reviewers: "" | |
| draft: false | |
| - name: ❌ Report failed update | |
| if: steps.changes.outputs.changes == 'true' && env.test_status == 'failed' | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const title = '❌ Dependency Update Failed' | |
| const body = ` | |
| ## ❌ Automated Dependency Update Failed | |
| The automated dependency update process failed because tests did not pass with the updated dependencies. | |
| ### 📋 Details | |
| - **Update Type**: ${{ github.event.inputs.update_type || 'patch' }} | |
| - **Status**: Tests failed after dependency updates | |
| ### 🔧 Next Steps | |
| 1. Review the test failures in the workflow logs | |
| 2. Manually investigate compatibility issues | |
| 3. Update dependencies individually if needed | |
| 4. Fix any breaking changes introduced by updates | |
| **Workflow Run**: [#${{ github.run_number }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) | |
| ` | |
| github.rest.issues.create({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| title: title, | |
| body: body, | |
| labels: ['dependencies', 'failed-update', 'needs-investigation'] | |
| }) | |
| # ============================================================================ | |
| # 依赖分析报告 | |
| # ============================================================================ | |
| dependency-analysis: | |
| name: 📊 Dependency Analysis | |
| runs-on: ubuntu-latest | |
| needs: [security-audit, check-updates] | |
| steps: | |
| - name: 📥 Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Detect package manager | |
| id: detect-package-manager | |
| run: | | |
| if [ -f "${{ github.workspace }}/pnpm-lock.yaml" ]; then | |
| echo "manager=pnpm" >> $GITHUB_OUTPUT | |
| echo "command=install --frozen-lockfile" >> $GITHUB_OUTPUT | |
| exit 0 | |
| elif [ -f "${{ github.workspace }}/yarn.lock" ]; then | |
| echo "manager=yarn" >> $GITHUB_OUTPUT | |
| echo "command=install" >> $GITHUB_OUTPUT | |
| exit 0 | |
| elif [ -f "${{ github.workspace }}/package-lock.json" ]; then | |
| echo "manager=npm" >> $GITHUB_OUTPUT | |
| echo "command=ci" >> $GITHUB_OUTPUT | |
| exit 0 | |
| else | |
| echo "Unable to determine package manager" | |
| exit 1 | |
| fi | |
| - name: Setup pnpm | |
| if: steps.detect-package-manager.outputs.manager == 'pnpm' | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: 10.19.0 | |
| - name: 📦 Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "22" | |
| cache: ${{ steps.detect-package-manager.outputs.manager }} | |
| - name: 📥 Install dependencies | |
| run: ${{ steps.detect-package-manager.outputs.manager }} ${{ steps.detect-package-manager.outputs.command }} | |
| - name: 📊 Generate dependency report | |
| run: | | |
| echo "# 📊 Dependency Analysis Report" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| # 依赖统计 | |
| total_deps=$(${{ steps.detect-package-manager.outputs.manager }} list --depth=0 --json | jq '.dependencies | length') | |
| dev_deps=$(${{ steps.detect-package-manager.outputs.manager }} list --depth=0 --dev --json | jq '.dependencies | length // 0') | |
| prod_deps=$((total_deps - dev_deps)) | |
| echo "## 📈 Dependency Statistics" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "| Category | Count |" >> $GITHUB_STEP_SUMMARY | |
| echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY | |
| echo "| Production Dependencies | $prod_deps |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Development Dependencies | $dev_deps |" >> $GITHUB_STEP_SUMMARY | |
| echo "| **Total Dependencies** | **$total_deps** |" >> $GITHUB_STEP_SUMMARY | |
| # 包大小分析 | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "## 📦 Package Size Analysis" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| if command -v du &> /dev/null; then | |
| node_modules_size=$(du -sh node_modules 2>/dev/null | cut -f1 || echo "N/A") | |
| echo "- **node_modules size**: $node_modules_size" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| # 许可证分析 | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "## 📜 License Analysis" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "License information for production dependencies:" >> $GITHUB_STEP_SUMMARY | |
| # 这里可以添加许可证检查逻辑 | |
| echo "- Most packages use MIT license (detailed analysis available on request)" >> $GITHUB_STEP_SUMMARY | |
| - name: 📤 Upload analysis report | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: dependency-analysis-report | |
| path: | | |
| package.json | |
| pnpm-lock.yaml | |
| retention-days: 30 |