From 10096795a16d683a00aeced4274c0d428987cd95 Mon Sep 17 00:00:00 2001 From: YHH <359807859@qq.com> Date: Sun, 19 Oct 2025 10:03:35 +0800 Subject: [PATCH] =?UTF-8?q?ci(deps):=20=E4=BC=98=E5=8C=96=20Dependabot=20?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=8C=96=E6=B5=81=E7=A8=8B=E5=87=8F=E5=B0=91?= =?UTF-8?q?=E7=BB=B4=E6=8A=A4=E8=B4=9F=E6=8B=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/dependabot.yml | 58 +++++++-- .github/workflows/cleanup-dependabot.yml | 146 +++++++++++++++++++++++ .mergify.yml | 105 +++++++++++++++- 3 files changed, 297 insertions(+), 12 deletions(-) create mode 100644 .github/workflows/cleanup-dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml index e353bc0f..5c4ec58c 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,47 +4,87 @@ updates: - package-ecosystem: "npm" directory: "/packages/core" schedule: - interval: "weekly" - open-pull-requests-limit: 5 + interval: "monthly" # 改为每月更新,减少干扰 + open-pull-requests-limit: 3 # 减少同时打开的 PR 数量 labels: - "dependencies" - "core" commit-message: prefix: "chore(deps)" include: "scope" + groups: + # 将开发依赖打包在一起 + dev-dependencies: + dependency-type: "development" + # 将生产依赖的 patch 更新打包在一起 + production-dependencies: + dependency-type: "production" + update-types: + - "patch" + - "minor" + # 忽略频繁更新但不重要的包 + ignore: + - dependency-name: "@types/*" + update-types: ["version-update:semver-patch"] # 编辑器应用依赖 - package-ecosystem: "npm" directory: "/packages/editor-app" schedule: - interval: "weekly" - open-pull-requests-limit: 5 + interval: "monthly" + open-pull-requests-limit: 3 labels: - "dependencies" - "editor" commit-message: prefix: "chore(deps)" include: "scope" + groups: + dev-dependencies: + dependency-type: "development" + production-dependencies: + dependency-type: "production" + update-types: + - "patch" + - "minor" + ignore: + - dependency-name: "@types/*" + update-types: ["version-update:semver-patch"] # 根目录依赖 - package-ecosystem: "npm" directory: "/" schedule: - interval: "weekly" - open-pull-requests-limit: 5 + interval: "monthly" + open-pull-requests-limit: 3 labels: - "dependencies" commit-message: prefix: "chore(deps)" + groups: + dev-dependencies: + dependency-type: "development" + production-dependencies: + dependency-type: "production" + update-types: + - "patch" + - "minor" + ignore: + - dependency-name: "@types/*" + update-types: ["version-update:semver-patch"] - # GitHub Actions + # GitHub Actions - 保持更新以获取安全修复 - package-ecosystem: "github-actions" directory: "/" schedule: - interval: "weekly" - open-pull-requests-limit: 5 + interval: "monthly" + open-pull-requests-limit: 2 labels: - "dependencies" - "github-actions" commit-message: prefix: "chore(deps)" + groups: + github-actions: + patterns: + - "*" diff --git a/.github/workflows/cleanup-dependabot.yml b/.github/workflows/cleanup-dependabot.yml new file mode 100644 index 00000000..1010e9e4 --- /dev/null +++ b/.github/workflows/cleanup-dependabot.yml @@ -0,0 +1,146 @@ +name: Cleanup Old Dependabot PRs + +# 手动触发的 workflow,用于清理堆积的 Dependabot PR +on: + workflow_dispatch: + inputs: + days_old: + description: '关闭多少天前创建的 PR(默认 7 天)' + required: false + default: '7' + dry_run: + description: '试运行模式(true=仅显示,不关闭)' + required: false + default: 'true' + type: choice + options: + - 'true' + - 'false' + +jobs: + cleanup: + runs-on: ubuntu-latest + permissions: + pull-requests: write + issues: write + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: List and Close Old Dependabot PRs + uses: actions/github-script@v7 + with: + script: | + const daysOld = parseInt('${{ github.event.inputs.days_old }}') || 7; + const dryRun = '${{ github.event.inputs.dry_run }}' === 'true'; + const cutoffDate = new Date(); + cutoffDate.setDate(cutoffDate.getDate() - daysOld); + + console.log(`🔍 查找超过 ${daysOld} 天的 Dependabot PR...`); + console.log(`📅 截止日期: ${cutoffDate.toISOString()}`); + console.log(`🏃 模式: ${dryRun ? '试运行(不会实际关闭)' : '实际执行'}`); + console.log('---'); + + // 获取所有 Dependabot PR + const { data: pulls } = await github.rest.pulls.list({ + owner: context.repo.owner, + repo: context.repo.repo, + state: 'open', + per_page: 100 + }); + + const dependabotPRs = pulls.filter(pr => + pr.user.login === 'dependabot[bot]' && + new Date(pr.created_at) < cutoffDate + ); + + console.log(`📊 找到 ${dependabotPRs.length} 个符合条件的 Dependabot PR`); + console.log(''); + + if (dependabotPRs.length === 0) { + console.log('✅ 没有需要清理的 PR'); + return; + } + + // 按类型分组 + const byType = { + dev: [], + prod: [], + actions: [], + other: [] + }; + + for (const pr of dependabotPRs) { + const title = pr.title.toLowerCase(); + const labels = pr.labels.map(l => l.name); + + let type = 'other'; + if (title.includes('dev-dependencies') || title.includes('development')) { + type = 'dev'; + } else if (title.includes('production-dependencies')) { + type = 'prod'; + } else if (labels.includes('github-actions')) { + type = 'actions'; + } + + byType[type].push(pr); + } + + console.log('📋 PR 分类统计:'); + console.log(` 🔧 开发依赖: ${byType.dev.length} 个`); + console.log(` 📦 生产依赖: ${byType.prod.length} 个`); + console.log(` ⚙️ GitHub Actions: ${byType.actions.length} 个`); + console.log(` ❓ 其他: ${byType.other.length} 个`); + console.log(''); + + // 处理每个 PR + for (const pr of dependabotPRs) { + const age = Math.floor((Date.now() - new Date(pr.created_at)) / (1000 * 60 * 60 * 24)); + + console.log(`${dryRun ? '🔍' : '🗑️ '} #${pr.number}: ${pr.title}`); + console.log(` 创建时间: ${pr.created_at} (${age} 天前)`); + console.log(` 链接: ${pr.html_url}`); + + if (!dryRun) { + await github.rest.pulls.update({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: pr.number, + state: 'closed' + }); + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: pr.number, + body: `🤖 **自动关闭旧的 Dependabot PR** + +此 PR 已超过 ${daysOld} 天未合并,已被自动关闭以清理积压。 + +📌 **下一步:** +- Dependabot 已配置为月度运行,届时会创建新的分组更新 +- 新的 Mergify 规则会智能处理不同类型的依赖更新 +- 开发依赖和 GitHub Actions 会自动合并(即使 CI 失败) +- 生产依赖需要 CI 通过才会自动合并 + +如果需要立即应用此更新,请手动更新依赖。 + +--- +*此操作由仓库维护者手动触发的清理工作流执行*` + }); + + console.log(' ✅ 已关闭并添加说明'); + } else { + console.log(' ℹ️ 试运行模式 - 未执行操作'); + } + console.log(''); + } + + console.log('---'); + if (dryRun) { + console.log(`✨ 试运行完成!共发现 ${dependabotPRs.length} 个待清理的 PR`); + console.log('💡 要实际执行清理,请将 dry_run 参数设为 false 重新运行'); + } else { + console.log(`✅ 清理完成!已关闭 ${dependabotPRs.length} 个 Dependabot PR`); + } diff --git a/.mergify.yml b/.mergify.yml index 66d243c3..8ebea390 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -4,19 +4,118 @@ queue_rules: - check-success=CI - check-success=Commit Lint + # 开发依赖队列 - 只需要 Commit Lint 通过 + - name: dev-dependencies + conditions: + - check-success=Commit Lint + pull_request_rules: - # 自动合并 Dependabot 的更新 - - name: 自动合并 Dependabot 更新 + # 自动合并 Dependabot 开发依赖分组更新(风险低,允许 CI 失败) + - name: 自动合并 Dependabot 开发依赖 conditions: - author=dependabot[bot] + - or: + - title~=(?i)dev.dependencies + - label=dependencies + - body~=(?i)development.dependencies + - check-success=Commit Lint + # 排除主要版本更新 + - -title~=(?i)major + actions: + review: + type: APPROVE + message: | + 🤖 自动批准开发依赖更新 + + 开发依赖更新风险较低,即使测试失败也不影响生产环境。 + 如有问题会在后续开发中发现并修复。 + queue: + name: dev-dependencies + label: + add: + - auto-merged + + # 自动合并 Dependabot 生产依赖的 patch 更新(必须 CI 通过) + - name: 自动合并 Dependabot 生产依赖 patch 更新 + conditions: + - author=dependabot[bot] + - or: + - title~=(?i)production.dependencies + - and: + - label=dependencies + - -body~=(?i)development.dependencies + - title~=(?i)patch - check-success=CI - check-success=Commit Lint actions: review: type: APPROVE - message: 自动批准 Dependabot 更新 + message: 🤖 自动批准生产依赖 patch 更新(测试通过) queue: name: default + label: + add: + - auto-merged + + # 自动合并 GitHub Actions 更新(风险低) + - name: 自动合并 GitHub Actions 更新 + conditions: + - author=dependabot[bot] + - label=github-actions + - check-success=Commit Lint + actions: + review: + type: APPROVE + message: 🤖 自动批准 GitHub Actions 更新 + queue: + name: dev-dependencies + label: + add: + - auto-merged + + # 标记需要人工审核的重要更新 + - name: 标记需要人工审核的生产依赖更新 + conditions: + - author=dependabot[bot] + - or: + - title~=(?i)production.dependencies + - and: + - label=dependencies + - -body~=(?i)development.dependencies + - or: + - title~=(?i)minor + - title~=(?i)major + - -check-success=CI + actions: + label: + add: + - needs-manual-review + comment: + message: | + ⚠️ **需要人工审核** + + 此更新属于以下情况之一,建议人工审核: + - 生产依赖的 minor/major 版本更新 + - CI 测试未通过 + + Please review this update manually. + + # 自动关闭超过 30 天未合并的 Dependabot PR(避免堆积) + - name: 关闭过期的 Dependabot PR + conditions: + - author=dependabot[bot] + - updated-at<30 days ago + - -merged + - -closed + actions: + close: + message: | + 🤖 自动关闭此 PR + + 此 PR 已超过 30 天未合并。Dependabot 会在下次运行时创建新的更新。 + 如果需要此更新,请手动更新依赖或等待下次自动更新。 + + This PR has been open for over 30 days. Dependabot will create a new update in the next run if needed. # 自动合并有 'automerge' 标签且测试通过的 PR - name: 自动合并标记的 PR