الوحدة 4 · عادات احترافية
حماية main: الـ CI مع Actions والـ Rulesets
17 دقراءة 4 داكتشف الخطأ
الدرس في لمحة
أضف workflow في GitHub Actions يفحص كل pull request، ثم احمِ main بـ ruleset بحيث لا تصل التغييرات إليه إلا عبر pull request نجحت فحوصه.
- 1أعطِ الموقع الشخصي شيئًا يُفحص
- 2أول workflow لك
- 3مشاهدته وهو يعمل
- 4احمِ main بـ ruleset
- 5ما الذي تستطيع فعله الآن
لا فيديو هنا، بل الشيء الحقيقي: درس مكتوب وأمثلة قابلة للتشغيل واختبار وتدريب.
كل ما سبق اعتمد على تذكّرك أنت. أن تتذكّر تشغيل فحص الـ HTML، وأن تفتح pull request بدل الرفع إلى main، وألّا ترفع بالقوة أبدًا. والناس ينسون، خصوصًا في الحادية عشرة ليلًا قبل التقدّم إلى وظيفة. ينقل هذا الدرس هذه العادات من رأسك إلى GitHub: آلة تشغّل الفحوص على كل pull request، وقواعد تجعل تغيير main بأي طريقة أخرى مستحيلًا.
أعطِ الموقع الشخصي شيئًا يُفحص
التكامل المستمر (continuous integration) يحتاج إلى أمر يفشل حين يكون هناك خطأ. ولموقع HTML، فإن أداة التحقّق (validator) بداية جيدة. في موقعك الشخصي، على فرع جديد:
git switch -c add-ci
npm init -y
npm install --save-dev html-validate
npm pkg set scripts.test="html-validate index.html projects.html"
echo '{ "extends": ["html-validate:recommended"] }' > .htmlvalidate.json
npm testnode_modules/ موجود أصلًا في .gitignore منذ درسين؛ سجّل في commit كلًا من package.json و package-lock.json و .htmlvalidate.json. وإن أبلغ npm test عن مشكلات، فهذا هو المقصود: أصلحها، أو دوّنها لأول تشغيل للـ CI. وفي موقع شخصي جديد كثيرًا ما يجد هذا:
index.html
1:1 error DOCTYPE should be uppercase doctype-styleأول workflow لك
تشغّل GitHub Actions الـ workflows المعرَّفة في ملفات YAML تحت .github/workflows/. أنشئ واحدًا:
name: CI
on:
pull_request:
branches: [main]
push:
branches: [main]
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 24
cache: npm
- run: npm ci
- run: npm testاقرأه من الأعلى إلى الأسفل:
onيسرد الأحداث (events) التي تبدأ الـ workflow: أي pull request إلىmain(عند فتحه، أو تحديثه بـ commits جديدة)، وعمليات الرفع إلىmainبعد الدمج.jobsيحتوي job واحدًا،check. هذا المعرّف يصبح اسم الـ status check الذي يعرضه GitHub على الـ pull request.runs-onيختار runner، وهو آلة افتراضية جديدة يوفّرها GitHub. وتبدأ فارغة في كل مرة.stepsتُنفَّذ بالترتيب.usesيشغّل action منشورًا:actions/checkoutينسخ الـ repository إلى الـ runner، وactions/setup-nodeيثبّت Node.js 24 ويخزّن تنزيلات npm مؤقتًا. وrunينفّذ أمر shell:npm ciيثبّت بالضبط ما يسردهpackage-lock.json، وnpm testيشغّل أداة التحقّق.
أي خطوة تنتهي بخطأ تُفشل الـ job. سجّل الـ workflow في commit، وارفع الفرع، وافتح pull request.
مشاهدته وهو يعمل
خلال ثوانٍ يعرض الـ pull request فحصًا، “CI / check (pull_request)”، بنقطة صفراء أثناء التشغيل. ثم علامة صح خضراء، أو علامة خطأ حمراء. انقر Details لترى السجلّ الكامل لكل خطوة؛ والخطوة الفاشلة تكون موسّعة، وتعرض ناتج أداة التحقّق نفسه الذي ستحصل عليه محليًا.
لإصلاح فحص أحمر، افعل ما تفعله مع ملاحظات المراجعة: أنشئ commit على الفرع نفسه وارفعه. يعمل الـ workflow مجددًا على الـ commit الجديد. اعتد على قراءة هذه السجلّات. الـ CI لا يحكم عليك؛ إنه زميل يعيد تشغيل الفحوص في كل مرة دون أن يملّ.
احمِ main بـ ruleset
الفحص الناجح لا يفيد إلا إذا انتظره الدمج. وهذا ما يفرضه الـ ruleset (مجموعة القواعد). على GitHub، افتح Settings في الـ repository، ثم Rules، ثم Rulesets، واختر New ruleset، ثم New branch ruleset:
- سمِّه “Protect main” واضبط Enforcement status على Active.
- تحت Target branches، أضف الفرع الافتراضي.
- أبقِ Restrict deletions و Block force pushes محدَّدين.
- حدّد Require a pull request before merging. في repository تعمل عليه وحدك اضبط عدد الموافقات المطلوبة على 0 (لا تستطيع الموافقة على الـ pull request الخاص بك)؛ وفي الفريق، 1 أو أكثر.
- حدّد Require status checks to pass، وأضف الفحص
check، واحفظ.
الآن حاول تخطّي العملية:
git switch main
git commit --allow-empty -m "Sneak a commit onto main"
git push origin mainremote: error: GH013: Repository rule violations found for refs/heads/main.يُرفض الرفع، ويبقى الـ commit المحلي دون أن يُمسّ. كل تغيير على main يمرّ الآن عبر pull request، ويبقى زر الدمج معطّلًا حتى يصبح الفحص أخضر. شغّل git reset --hard origin/main لتتخلّص من الـ commit الفارغ.
الـ rulesets مجانية في الـ repositories العامة؛ أما في الخاصة فتحتاج إلى خطة مدفوعة مثل GitHub Pro أو Team. وقد ترى أيضًا branch protection rules الأقدم في الإعدادات. إنها تؤدّي مهمّة مشابهة؛ لكن الـ rulesets أحدث، ويمكن تركيبها في طبقات، ويستطيع أي شخص لديه صلاحية القراءة أن يرى القواعد المطبّقة.
ما الذي تستطيع فعله الآن
انظر من أين بدأ الموقع الشخصي: مجلد فيه index.html. صار الآن repository بسجلّ مقروء، وفروع تُدمج أو يُعاد تأسيسها بنظافة، و remote على GitHub تصل إليه بمصادقة سليمة، و issues تشرح سبب وجود كل عمل، وإصدارات موسومة بـ tags، وفرع main لا يقبل إلا pull requests مراجَعة ومفحوصة آليًا. وتستطيع التراجع عن معظم الأخطاء، وتعرف أيّ طريقة تراجع تناسب كلًا منها.
وأهمّ من الأوامر، صار لديك النموذج: الـ commits لقطات مرتبطة بآبائها، والـ branches والـ tags أسماء دالّة، والـ HEAD هو حيث تقف، والـ remotes نسخ أخرى من الرسم البياني نفسه. وحين يفاجئك Git مستقبلًا، شغّل git log --oneline --graph --all، وارسم ما تراه، وغالبًا سيكون الأمر التالي واضحًا.
أهم النقاط
- الـ workflow ملف YAML في
.github/workflows/؛ يحدّدonالأحداث، وتعمل الـjobsعلى runners، وكل خطوة فيstepsإما تستخدم action عبرusesأو تنفّذ أمرًا عبرrun. - كل job يبلّغ عن status check على الـ pull request، يظهر كعلامة صح خضراء أو علامة خطأ حمراء مع السجلّات الكاملة.
- الـ branch ruleset على
mainيستطيع منع الرفع بالقوة والحذف، واشتراط pull request، واشتراط نجاح status checks مسمّاة. - الـ status check المطلوب يُطابَق باسم الـ job، ولا يقترح GitHub إلا الفحوص التي أبلغت عن نتيجتها من قبل، لذا شغّل الـ workflow قبل أن تشترطه.
- الحلقة المكتملة هي فرع، ثم رفع، ثم pull request، ثم فحص آلي، ثم مراجعة، ثم دمج، ولا أحد يستطيع تخطّي خطوة.