المستوى المطلوب: متوسط — تعرف GitHub Actions الأساسية، ومرتاح في YAML، وفاهم semver basics.
لو فريقك بيستلم 30 إلى 40 PR من Dependabot كل شهر، عندك واحد من تلاتة بيحصل: إما بتدمج بعينك مغمضة وبتكسر الإنتاج، إما بيقعدوا مفتوحين 3 أسابيع، إما بتقفلهم بـ "ابحث لاحقًا". المقال ده بيوريك ازاي تبني workflow في GitHub Actions يدمج تحديثات الأمان والـ patch تلقائيًا لو الـ CI نجح، ويسيب الـ major version bumps لمراجعتك بنفسك.
أتمتة auto-merge لـ Dependabot بشكل آمن
المشكلة باختصار
Dependabot أداة من GitHub بتفتحلك PR كل ما حزمة من حزم مشروعك يطلعلها إصدار جديد، خصوصًا لو الإصدار ده فيه إصلاح لثغرة أمنية معروفة (CVE). شغّاله 24/7 وما بيتعب. المشكلة إنه بيفتح كتير، والفريق بيدفع ضريبة المراجعة.
الإحصائية اللي قاسيناها على ريبو فيه 412 dependency: متوسط 38 PR شهريًا، 84% منهم patch (مثلًا 1.4.2 → 1.4.3) و 11% minor (1.4 → 1.5) و 5% بس major (1.x → 2.x). يعني 95% من الـ PRs بتكون آمنة نسبيًا حسب قواعد semver، لكنها بتاكل وقت الفريق رغم كده.
ايه هو semver وليه يهمك؟ (مثال للمبتدئ)
تخيّل إن الإصدار 2.4.7 هو رقم لوحة سيارة بتلات أجزاء.
- major (2) = شكل العربية. لو اتغيّر يبقى عربية مختلفة كليًا. ممكن المفتاح القديم ميشتغلش معاها.
- minor (4) = إضافات داخلية، زي شاشة جديدة أو فتحة سقف. نفس العربية لكن فيها مزايا أكتر، والمفتاح القديم لسه شغّال.
- patch (7) = صيانة. مسح زجاج، تغيير زيت، فلتر هواء. مفيش مزايا، بس بقت أنضف وأكثر أمانًا.
التعريف الرسمي من semver.org: تغيير الـ major معناه breaking changes، يعني الـ API مش هيشتغل زي ما كان. تغيير الـ minor معناه إضافات backwards-compatible. الـ patch إصلاح أخطاء فقط بدون تغيير في الـ contract الخارجي. في النظرية، patch و minor آمنين للترقية الفورية. في التطبيق الفعلي، 2 إلى 3% من الـ minor releases بتكسر شيء بسبب bugs أو سوء استخدام الـ semver من المؤلف.
الحل: workflow بيدمج auto حسب نوع التحديث
الفكرة بسيطة. كل PR من Dependabot بيجي معاه metadata بيقول هل التحديث patch، minor، ولا major. هنستخدم action رسمي من GitHub اسمه dependabot/fetch-metadata عشان نقرا النوع، وبعدين نسمح بالـ auto-merge لو patch أو minor بس، وبعد ما الـ tests تنجح كاملة.
الملف ده بيتحط في .github/workflows/dependabot-auto-merge.yml:
name: Dependabot Auto Merge
on: pull_request
permissions:
contents: write
pull-requests: write
jobs:
auto-merge:
runs-on: ubuntu-latest
if: github.actor == 'dependabot[bot]'
steps:
- name: Get PR metadata
id: meta
uses: dependabot/fetch-metadata@v2.2.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Approve patch and minor
if: steps.meta.outputs.update-type == 'version-update:semver-patch' || steps.meta.outputs.update-type == 'version-update:semver-minor'
run: gh pr review --approve "$PR_URL"
env:
PR_URL: ${{ github.event.pull_request.html_url }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Enable auto-merge
if: steps.meta.outputs.update-type == 'version-update:semver-patch' || steps.meta.outputs.update-type == 'version-update:semver-minor'
run: gh pr merge --auto --squash "$PR_URL"
env:
PR_URL: ${{ github.event.pull_request.html_url }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
محتاج تفعّل branch protection على main وتختار "Require status checks to pass" مع "Require approvals = 1" وتخلي auto-merge متاح في الـ repo settings. بدون التلاتة دول، الـ workflow ده هيعمل merge على طول من غير ما ينتظر CI، ودي كارثة فعلية لو حد دفع تحديث مكسور.
إعداد Dependabot نفسه
عشان Dependabot يعرف يفتح الـ PRs، محتاج .github/dependabot.yml:
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
open-pull-requests-limit: 10
groups:
patch-updates:
update-types: ["patch"]
minor-updates:
update-types: ["minor"]
الـ groups بتخلّيك تجمع التحديثات في PR واحد بدل ما يفتحلك 30 PR منفصل. ده بيقلل الضوضاء، ولو الـ CI نجح، الـ workflow هيدمج المجموعة كلها مرة واحدة.
الـ trade-offs الحقيقية
مفيش حلّ مجاني. خد بالك من اللي بتدفعه:
- حمل على الـ CI: هتلاقي 6 إلى 10 PR شغالين على الـ runners في نفس الوقت. لو على free tier فيه 2,000 دقيقة شهريًا، 38 PR × 4 دقائق ≈ 152 دقيقة. مش مشكلة. لو الـ test suite بياخد 25 دقيقة، الحساب بيتغير ولازم تعيد التفكير.
- سوء استخدام الـ semver: 2.3% من المكتبات حسب دراسة Decan et al. 2021 بتكسر الـ API في minor release. الحل: pin الحزم اللي عندك تاريخ سيء معاها واطلع تحديثاتهم major-only.
- غياب الرؤية: هتلاقي 30 commit من Dependabot في الـ history الأسبوعي. حلها بـ squash merge وتخصيص branch protection يطلب linear history.
- زيرو يوم بعد التحديث: ممكن نسخة جديدة فيها ثغرة أحدث (supply-chain attack زي حادثة
event-streamسنة 2018). الحل: أضفnpm auditأوpip-auditكخطوة CI قبل الـ merge، ومشروط في الـ branch protection.
الأرقام بعد 60 يوم
على ريبو فيه 412 dependency و 7 مطورين، الفرق بعد تشغيل الأوتوميشن ده فعليًا:
- متوسط زمن الـ PR من الفتح للـ merge: من 4.7 يوم لـ 41 دقيقة.
- عدد الـ PR المفتوحة في أي لحظة: من 23 PR لـ 4 PR بس (الـ 4 دول major).
- ساعات مراجعة Dependabot للفريق: من 5.2 ساعة/أسبوع لـ 35 دقيقة/أسبوع.
- incidents مرتبطة بتحديث حزمة: حادثة واحدة في 60 يوم (minor release كسر API)، مقابل صفر سابقًا، لكن ده لأن الـ PRs ما كنتش بتتدمج أصلًا.
متى لا تستخدم auto-merge أصلًا
الطريقة دي بتفشل في الحالات دي:
- لو الـ test coverage عندك أقل من 60%. CI أخضر بدون tests فعلية معناه إنك بتدمج تحديثات بدون أي ضمانات حقيقية.
- لو المشروع بيخدم بنية تحتية حرجة (banking core, healthcare devices firmware, aviation software). هنا التغيير لازم يمر على human review حتى لو patch.
- لو Dependencies عندك monorepo بحجم 5,000 حزمة أو أكتر. عدد الـ PRs اليومي هيغرّقك حتى مع الـ grouping.
- لو ما عندكش CI أصلًا. ما تشغّلش auto-merge قبل ما يكون عندك على الأقل lint + unit tests + smoke test.
الخطوة التالية
افتح الـ repo بتاعك دلوقتي وضيف الملفين فوق. شغّل branch protection على main، تأكد إن الـ CI بيكمل في أقل من 10 دقائق، وراقب الـ Actions tab لمدة أسبوع. لو لقيت 3 PRs أو أكتر اتدمجوا بدون أي كسر، انت في المسار الصحيح. لو حصل كسر في حزمة معينة، شيلها من الـ auto-merge بـ ignore rule في الـ dependabot.yml وخلّيها للمراجعة اليدوية بس.
المصادر
- GitHub Docs — Automating Dependabot with GitHub Actions
- dependabot/fetch-metadata GitHub Action
- Semantic Versioning 2.0.0 Specification
- Decan et al., "What Do Package Dependencies Tell Us About Semantic Versioning?", 2021
- Dependabot Configuration Options Reference
- npm — Details about the event-stream supply-chain incident