هل سيرفرك يغفو في الثالثة صباحاً لأنك نسيت تشغيل الاختبارات؟ GitHub Actions ليس مجرد أداة أتمتة، بل هو مهندس DevOps افتراضي يعمل 24/7 دون راتب. هذا الدليل العملي يريك كيف تحول مشروعك إلى مصنع برمجيات ذكي في 2025.
في يوم من الأيام، كنت أعمل على مشروع ضخم مع فريق موزع بين القاهرة ودبي وسان فرانسيسكو. كنا نطلق ميزة جديدة كل أسبوع، لكن المشكلة الحقيقية لم تكن في الكود، بل في العمليات. كل مرة نضغط على زر merge إلى main، كنا ننتظر ساعتين حتى تنتهي الـ CI/CD Pipeline، وإذا فشل أحد الاختبارات، كنا نضطر لإعادة كل شيء من الصفر. المشكلة؟ كنا نستخدم Jenkins على سيرفر قديم في مكتبنا بالقاهرة، وكان الـ Disk I/O يصل إلى 100% بمجرد تشغيل build واحد. هنا أدركت أن الأتمتة ليست رفاهية، بل هي مسألة حياة أو موت للمشروع. GitHub Actions لم يكن مجرد بديل، بل كان ثورة حقيقية: لا سيرفرات لإدارتها، لا تحديثات أمنية، ولا قلق من أن ينقطع الإنترنت في المكتب.
لكن لماذا GitHub Actions تحديداً في 2025؟ لأن العالم تغير. الشركات الصغيرة أصبحت تنافس الكبار بفضل الأدوات السحابية، والمطورون أصبحوا يتوقعون أن كل شيء يعمل بضغطة زر. GitHub Actions ليس مجرد أداة CI/CD، بل هو نظام متكامل للأتمتة يسمح لك بتحويل أي عملية يدوية إلى workflow ذكي. تخيل أنك تستطيع تشغيل اختبارات الوحدات، بناء Docker images، نشرها على Kubernetes، وإرسال إشعار إلى Slack إذا فشل أي شيء، كل هذا تلقائياً بمجرد أن يضغط أحدهم على زر merge. هذا ليس حلماً، بل هو واقع يمكن تحقيقه في أقل من ساعة.
الكثير من المطورين يعتقدون أن ملف workflow.yaml هو مجرد قائمة أوامر لتشغيلها عند حدث معين. هذا فهم سطحي وخطير. في الحقيقة، ملف الـ Workflow هو برنامج صغير بحد ذاته، له منطق، شروط، وحالات فشل يجب التعامل معها. مثلاً، عندما تكتب `on: push`، فأنت لا تخبر GitHub فقط أن يشغل الـ Workflow عند كل push، بل تخبره أيضاً بأي branch يجب أن يستجيب، وما هي الـ paths التي يجب تجاهلها. هذا التفصيل مهم جداً، لأن تشغيل workflow غير ضروري يضيع مواردك ويبطئ فريقك.
لنأخذ مثالاً عملياً: تخيل أنك تعمل على مشروع فيه مجلدات متعددة، وكل مجلد يمثل خدمة مستقلة (microservice). إذا قمت بتشغيل workflow عند كل push على أي ملف، فستضيع وقتك الثمين في إعادة بناء خدمات لم تتغير. الحل؟ استخدم الـ `paths-ignore` أو `paths` لتحديد المجلدات أو الملفات التي يجب أن تطلق الـ Workflow. هذا ليس مجرد توفير للوقت، بل هو تحسين حقيقي لأداء الفريق. في أحد المشاريع التي عملت عليها، قمنا بتقليل وقت الـ CI من 45 دقيقة إلى 8 دقائق فقط باستخدام هذه التقنية، وكان الفرق مذهلاً.
# .github/workflows/build.yml
name: Build and Test
on:
push:
branches: [ main ]
paths-ignore:
- 'docs/**'
- 'README.md'
pull_request:
paths:
- 'services/auth/**'
- 'services/payment/**'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
env:
CI: trueواحدة من أقوى ميزات GitHub Actions هي الـ Matrix Strategy، وهي تسمح لك بتشغيل نفس الـ Job على عدة بيئات مختلفة في وقت واحد. مثلاً، إذا كنت تريد اختبار تطبيقك على Node.js 18 و20 و21، وعلى أنظمة تشغيل مختلفة مثل Ubuntu وWindows، فبدلاً من كتابة ثلاثة jobs منفصلة، يمكنك استخدام matrix لتشغيلها جميعاً في وقت واحد. هذا ليس مجرد توفير للوقت، بل هو ضمان أن تطبيقك يعمل بشكل متسق عبر جميع البيئات.
لكن هناك فخ شائع هنا: الكثير من المطورين يستخدمون الـ Matrix بدون فهم حقيقي لكيفية عمله خلف الكواليس. عندما تكتب `strategy: matrix`، فإن GitHub ينشئ نسخة مستقلة من الـ Job لكل مجموعة من المتغيرات التي حددتها. هذا يعني أنك إذا حددت 3 إصدارات من Node.js و3 أنظمة تشغيل، فسيتم إنشاء 9 jobs مستقلة، وكل منها سيستهلك موارد مختلفة. إذا لم تكن حذراً، فقد ينتهي بك الأمر إلى استنزاف الـ Minutes المجانية بسرعة، أو حتى تسبب فشل الـ Workflow بسبب مشاكل في الذاكرة أو الـ CPU.
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node: [18, 20, 21]
exclude:
- os: macos-latest
node: 18
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- run: npm testفي عام 2023، تعرضت شركة شهيرة لاختراق بسبب تسريب مفتاح API في ملف YAML عام. الخطأ؟ أحدهم نسي إزالة الـ Secret من ملف workflow بعد تجربة سريعة. هذا النوع من الأخطاء ليس مجرد إهمال، بل هو جريمة بحق الأمن السيبراني. GitHub Actions يوفر نظاماً قوياً لإدارة الـ Secrets، لكنه ليس سحرياً. إذا وضعت الـ Secret في مكان خاطئ، أو إذا سمحت للـ Workflow غير الموثوق بالوصول إليه، فأنت تفتح الباب للهكرز.
القاعدة الذهبية هنا هي: لا تضع أبداً الـ Secrets في ملفات الـ Workflow مباشرة. بدلاً من ذلك، استخدم ميزة Secrets في GitHub، والتي تقوم بتشفير القيم وتخزينها بشكل آمن. لكن حتى هذا ليس كافياً. يجب أن تفهم الفرق بين الـ Secrets و الـ Environment Variables. الـ Secrets تستخدم لتخزين بيانات حساسة مثل كلمات المرور ومفاتيح API، بينما الـ Environment Variables تستخدم لتخزين إعدادات عامة مثل أسماء الـ Branches أو الـ URLs. أيضاً، يجب أن تحد من الوصول إلى الـ Secrets باستخدام الـ Environment Protection Rules، والتي تسمح لك بتحديد من يمكنه تشغيل الـ Workflow الذي يستخدم هذه الـ Secrets.
jobs:
deploy:
runs-on: ubuntu-latest
environment:
name: production
url: https://example.com
steps:
- uses: actions/checkout@v4
- name: Deploy to production
run: ./deploy.sh
env:
API_KEY: ${{ secrets.PRODUCTION_API_KEY }}
DB_URL: ${{ vars.PRODUCTION_DB_URL }}واحدة من الميزات الأقل شهرة لكنها الأكثر أهمية في GitHub Actions هي الـ Environment Protection Rules. هذه الميزة تسمح لك بوضع شروط صارمة لتشغيل الـ Workflows التي تتعامل مع بيئات حساسة مثل الإنتاج. مثلاً، يمكنك تحديد أن الـ Workflow لا يمكن تشغيله إلا إذا تمت الموافقة عليه يدوياً من قبل شخص معين، أو إذا كان الـ Branch هو main فقط. هذا ليس مجرد أمان إضافي، بل هو حماية حقيقية ضد الأخطاء البشرية.
في أحد المشاريع التي عملت عليها، قمنا بإعداد بيئة production تتطلب موافقة من شخصين قبل أن يتم نشر أي شيء. هذا قد يبدو مبالغاً فيه، لكنه أنقذنا أكثر من مرة من نشر كود غير مستقر. أيضاً، يمكنك استخدام الـ Environment Protection Rules لفرض شروط أخرى، مثل أن يكون الـ Workflow قد نجح في جميع الـ Jobs السابقة، أو أن يكون الـ Commit قد تم توقيعه باستخدام GPG. هذه التفاصيل الصغيرة هي ما يميز الفرق المحترفة عن الهواة.
إذا كنت تعتقد أن الـ Caching هو مجرد تحسين بسيط، فأنت مخطئ. في عالم الـ CI/CD، الوقت هو المال، وكل ثانية تضيع في إعادة تثبيت الـ Dependencies هي ثانية تضيع من عمر فريقك. GitHub Actions يوفر نظاماً قوياً للـ Caching يسمح لك بتخزين الملفات المؤقتة مثل الـ node_modules أو الـ pip cache واستعادتها في الـ Runs اللاحقة. هذا ليس مجرد توفير للوقت، بل هو تغيير جذري في كيفية تعاملك مع الـ Workflows.
لكن هناك فخ هنا: الكثير من المطورين يستخدمون الـ Caching بدون فهم حقيقي لكيفية عمله. عندما تقوم بتخزين ملفات في الـ Cache، فإن GitHub يقوم بضغطها وإرسالها إلى مخزن بعيد. عند استعادة الـ Cache، يتم تحميل هذه الملفات مرة أخرى. إذا كانت ملفاتك كبيرة جداً، فقد يستغرق هذا وقتاً أطول من إعادة بناءها من الصفر. الحل؟ استخدم الـ Cache بحكمة، وحدد فقط الملفات التي تستحق التخزين. مثلاً، في مشروع Node.js، يمكنك تخزين مجلد الـ node_modules، لكن في مشروع Python، قد يكون من الأفضل تخزين مجلد الـ pip cache فقط.
steps:
- uses: actions/checkout@v4
- name: Cache node modules
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Install dependencies
run: npm ciأحد أكبر المشاكل مع الـ Caching هو الـ Cache Invalidation. عندما تقوم بتحديث الـ Dependencies في مشروعك، قد لا يتم تحديث الـ Cache تلقائياً، مما يؤدي إلى استخدام نسخة قديمة من الملفات. الحل التقليدي هو استخدام مفتاح فريد لكل نسخة من الـ Cache، مثل الـ hash لملف package-lock.json. لكن حتى هذا ليس مضموناً، خاصة إذا كنت تستخدم مكتبات تتغير بشكل متكرر.
في أحد المشاريع، واجهنا مشكلة غريبة: الـ Workflow كان يستخدم دائماً نسخة قديمة من الـ node_modules، حتى بعد تحديث الـ Dependencies. السبب؟ كنا نستخدم مفتاح الـ Cache بناءً على اسم الـ Branch فقط، ولم نأخذ في الاعتبار محتوى ملف package-lock.json. بعد تعديل المفتاح ليشمل الـ hash للملف، اختفت المشكلة تماماً. الدرس هنا هو: لا تعتمد على افتراضات عند استخدام الـ Caching، بل اختبر دائماً للتأكد من أن الـ Cache يتم تحديثه بشكل صحيح.
إذا كنت تكتب نفس الكود في أكثر من workflow، فأنت تفعل شيئاً خاطئاً. مبدأ DRY (Don’t Repeat Yourself) لا ينطبق فقط على الكود البرمجي، بل على الـ Workflows أيضاً. GitHub Actions يسمح لك بإنشاء workflows قابلة لإعادة الاستخدام، والتي يمكنك استدعاؤها من workflows أخرى. هذا ليس مجرد توفير للوقت، بل هو ضمان أن جميع الـ Workflows تتبع نفس المعايير وتستخدم نفس الإعدادات.
لنأخذ مثالاً عملياً: تخيل أنك تعمل على مشروع فيه عدة خدمات، وكل خدمة تحتاج إلى نفس خطوات البناء والاختبار. بدلاً من كتابة نفس الكود في كل workflow، يمكنك إنشاء workflow واحد قابل لإعادة الاستخدام، ثم استدعاؤه من workflows أخرى مع تمرير المتغيرات المناسبة. هذا ليس مجرد تحسين للكفاءة، بل هو أيضاً تحسين للصيانة. إذا احتجت إلى تغيير شيء ما في عملية البناء، فستحتاج إلى تعديله في مكان واحد فقط.
# .github/workflows/reusable-build.yml
name: Reusable Build
on:
workflow_call:
inputs:
service:
required: true
type: string
secrets:
API_KEY:
required: true
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build service
run: npm run build --workspace=${{ inputs.service }}
- name: Run tests
run: npm test --workspace=${{ inputs.service }}
env:
API_KEY: ${{ secrets.API_KEY }}# .github/workflows/build-auth.yml
name: Build Auth Service
on: [push, pull_request]
jobs:
build:
uses: ./.github/workflows/reusable-build.yml
with:
service: auth
secrets:
API_KEY: ${{ secrets.API_KEY }}أحد أسوأ الكوابيس لأي مطور هو أن يفشل الـ Workflow ولا تعرف السبب. ربما ترى رسالة خطأ غامضة مثل `Process completed with exit code 1`، أو ربما لا ترى أي خطأ على الإطلاق، فقط الـ Workflow يتوقف فجأة. في هذه اللحظات، تشعر وكأنك في متاهة بدون خريطة. لكن الحقيقة هي أن GitHub Actions يوفر أدوات قوية للـ Debugging، إذا كنت تعرف أين تبحث.
أول شيء يجب أن تفعله هو تشغيل الـ Workflow مع وضع الـ Debug Logging. يمكنك فعل ذلك ببساطة عن طريق إضافة متغير بيئة `ACTIONS_STEP_DEBUG` بقيمة `true`. هذا سيظهر لك معلومات تفصيلية عن كل خطوة في الـ Workflow، بما في ذلك الـ Commands التي تم تنفيذها والـ Outputات الكاملة. أيضاً، يمكنك استخدام الـ `run: echo` لطباعة قيم المتغيرات أو للتحقق من حالة الملفات. إذا كنت تواجه مشكلة مع خطوة معينة، فحاول تقسيمها إلى خطوات أصغر لفهم أين بالضبط يحدث الفشل.
jobs:
debug:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Debug step
run: |
echo "Current directory: $(pwd)"
echo "Files in directory: $(ls -la)"
echo "Node version: $(node -v)"
env:
ACTIONS_STEP_DEBUG: trueعندما يفشل الـ Workflow، فإن الـ Logs هي أفضل صديق لك. GitHub Actions يحتفظ بجميع الـ Logs لكل خطوة في الـ Workflow، ويمكنك الوصول إليها بسهولة من واجهة المستخدم. لكن أحياناً، قد تحتاج إلى أكثر من مجرد الـ Logs. مثلاً، إذا كان الـ Workflow ينتج ملفات مؤقتة مهمة، يمكنك استخدام الـ Artifacts لتحميلها واستعراضها لاحقاً. هذا مفيد جداً عندما تريد تحليل ملفات الـ Logs أو الـ Reports التي تم إنشاؤها خلال الـ Workflow.
في أحد المشاريع، كنا نواجه مشكلة غريبة: الـ Workflow كان ينجح أحياناً ويفشل أحياناً أخرى، بدون أي نمط واضح. بعد ساعات من الـ Debugging، اكتشفنا أن المشكلة كانت في أحد الـ Dependencies الذي كان يتغير بشكل عشوائي. الحل؟ قمنا بتحميل ملف package-lock.json كـ Artifact في كل مرة يعمل فيها الـ Workflow، ثم قمنا بمقارنته بين الـ Runs الناجحة والفاشلة. هذا ساعدنا على تحديد المشكلة بسرعة وحلها. الدرس هنا هو: لا تعتمد فقط على الـ Logs، بل استخدم جميع الأدوات المتاحة لك.
steps:
- name: Upload test results
uses: actions/upload-artifact@v3
if: always()
with:
name: test-results
path: test-results/
- name: Upload logs
uses: actions/upload-artifact@v3
if: failure()
with:
name: logs
path: logs/بعد عشر سنوات في عالم البرمجة، وخمس سنوات من استخدام GitHub Actions في مشاريع حقيقية، هذه هي نصائحي الذهبية لك: أولاً، لا تبدأ بكتابة workflow معقد من الصفر. ابدأ بشيء بسيط، مثل تشغيل اختبارات الوحدات، ثم أضف المزيد من الخطوات تدريجياً. ثانياً، استخدم الـ Matrix بحكمة، ولا تفرط في استخدامها وإلا ستجد نفسك تنتظر ساعات حتى ينتهي الـ Workflow. ثالثاً، احمِ الـ Secrets الخاص بك كما تحمي كلمات مرورك، لأن تسريب واحد يمكن أن يدمر مشروعك بالكامل. رابعاً، استخدم الـ Caching ولكن لا تعتمد عليه بشكل أعمى، واختبر دائماً للتأكد من أنه يعمل كما تتوقع. وأخيراً، لا تخف من الـ Debugging. عندما يفشل الـ Workflow، اعتبره تحدياً وليس كارثة، واستخدم جميع الأدوات المتاحة لك لحل المشكلة.
GitHub Actions ليس مجرد أداة، بل هو عقل إضافي لفريقك. إذا استخدمت بشكل صحيح، يمكنه تحويل مشروعك من مجموعة من الملفات إلى مصنع برمجيات ذكي يعمل بكفاءة عالية. لكن تذكر دائماً: الأتمتة ليست هدفاً بحد ذاتها، بل هي وسيلة لتحقيق هدف أكبر، وهو بناء برامج أفضل بأقل جهد ممكن. ابدأ اليوم، وجرب شيئاً صغيراً، ثم طوره تدريجياً. قبل أن تدرك، ستكون قد حولت مشروعك إلى آلة تعمل بكامل طاقتها، وأنت مسترخٍ تشرب قهوتك.