نوفيل
الرئيسيةالكورساتالتحديات⚔️ المبارزاتالمقالاتالأدواتتغريداتالمجتمع
دخولابدأ مجاناً
الرئيسيةالكورساتالتحديات⚔️ المبارزاتالمقالاتالأدواتتغريداتالمجتمع
نوفيل

منصة تعليم البرمجة الأولى بالعربي. تعلم من الصفر حتى الاحتراف مع كورسات احترافية وتحديات ذكاء اصطناعي.

المنصة

  • الكورسات
  • التحديات
  • المقالات
  • الأدوات

الحساب

  • إنشاء حساب
  • تسجيل الدخول
  • لوحة التحكم
  • الملف الشخصي

روابط

  • سياسة الخصوصية
  • شروط الاستخدام
  • عن نوفيل
  • تواصل معنا

© 2026 نوفيل. جميع الحقوق محفوظة.

صُنع بـ في مصر

نوفيل
الرئيسيةالكورساتالتحديات⚔️ المبارزاتالمقالاتالأدواتتغريداتالمجتمع
دخولابدأ مجاناً
الرئيسيةالكورساتالتحديات⚔️ المبارزاتالمقالاتالأدواتتغريداتالمجتمع
نوفيل

منصة تعليم البرمجة الأولى بالعربي. تعلم من الصفر حتى الاحتراف مع كورسات احترافية وتحديات ذكاء اصطناعي.

المنصة

  • الكورسات
  • التحديات
  • المقالات
  • الأدوات

الحساب

  • إنشاء حساب
  • تسجيل الدخول
  • لوحة التحكم
  • الملف الشخصي

روابط

  • سياسة الخصوصية
  • شروط الاستخدام
  • عن نوفيل
  • تواصل معنا

© 2026 نوفيل. جميع الحقوق محفوظة.

صُنع بـ في مصر

نوفيل
الرئيسيةالكورساتالتحديات⚔️ المبارزاتالمقالاتالأدواتتغريداتالمجتمع
دخولابدأ مجاناً
الرئيسيةالكورساتالتحديات⚔️ المبارزاتالمقالاتالأدواتتغريداتالمجتمع
نوفيل

منصة تعليم البرمجة الأولى بالعربي. تعلم من الصفر حتى الاحتراف مع كورسات احترافية وتحديات ذكاء اصطناعي.

المنصة

  • الكورسات
  • التحديات
  • المقالات
  • الأدوات

الحساب

  • إنشاء حساب
  • تسجيل الدخول
  • لوحة التحكم
  • الملف الشخصي

روابط

  • سياسة الخصوصية
  • شروط الاستخدام
  • عن نوفيل
  • تواصل معنا

© 2026 نوفيل. جميع الحقوق محفوظة.

صُنع بـ في مصر

نوفيل
الرئيسيةالكورساتالتحديات⚔️ المبارزاتالمقالاتالأدواتتغريداتالمجتمع
دخولابدأ مجاناً
الرئيسيةالكورساتالتحديات⚔️ المبارزاتالمقالاتالأدواتتغريداتالمجتمع
المقالات/DevOps
DevOps

GitHub Actions 2025: أتمتة كل شيء دون أن يفلت منك شيء

في 2025، لم يعد GitHub Actions مجرد أداة CI/CD بل نظام أتمتة شامل يسيطر على سير عمل المشاريع الكبيرة. هذا الدليل العملي يكشف كيف تبني pipelines ذكية تتعامل مع الـ I/O Bound، الـ Memory Leaks، وتتفادى الـ Blocking Calls التي تبطئ الإنتاجية.

فريق نوفيل٢١ أغسطس ٢٠٢٦12 دقائق قراءة١٠ مشاهدة

الـ Pipeline الذي يبني نفسه بنفسه ليس ضرباً من الخيال في 2025. تخيل أنك تضغط زر واحد في الصباح، فيقوم GitHub Actions بتشغيل اختبارات الوحدة، بناء حاويات Docker، نشرها على Kubernetes، وإرسال تقرير أداء كامل إلى Slack قبل أن تنتهي من قهوتك الأولى. هذا ليس سيناريو مثالياً، بل واقع يومي في فرق التطوير التي تفهم كيف تستغل GitHub Actions لأتمتة كل خطوة دون أن تفقد السيطرة على التفاصيل الدقيقة. المشكلة الحقيقية ليست في كتابة workflows، بل في كتابتها بطريقة لا تتحول إلى كابوس صيانة بعد ثلاثة أشهر عندما يتضاعف حجم الكود.

في هذا الدليل، لن نتحدث عن الأساسيات التي تجدها في كل مقال. سنغوص مباشرة في التفاصيل التي تجعل الفرق الكبيرة تتبنى GitHub Actions كعمود فقري لأتمتتها: كيف تتعامل مع الـ Event Loops المتداخلة، كيف تخفض زمن الـ CI من 12 دقيقة إلى 3 دقائق باستخدام الـ Caching الذكي، وكيف تبني workflows تتفاعل مع الـ API الخارجية دون أن تعلق في الـ Rate Limits. كل مثال هنا مأخوذ من مشاريع حقيقية في شركات مثل Spotify وNetflix، حيث تُدار آلاف الـ Jobs يومياً دون تدخل بشري.

لماذا GitHub Actions أصبح العمود الفقري للأتمتة في 2025؟

عندما أطلق GitHub Actions في 2018، كان مجرد بديل لـ Jenkins أو Travis CI. اليوم، هو نظام أتمتة متكامل يدير كل شيء من الـ Code Reviews إلى الـ Infrastructure as Code. السر ليس في الميزات الجديدة فقط، بل في كيفية تكامله مع بقية أدوات GitHub: الـ Security Scanning، الـ Dependabot، وحتى الـ Project Management. في 2024، أعلنت Microsoft أن أكثر من 70% من المشاريع النشطة على GitHub تستخدم Actions بشكل منتظم، وهذا الرقم يتزايد بسرعة لأن الفرق اكتشفت شيئاً مهماً: الأتمتة ليست مجرد توفير وقت، بل هي ضمان للجودة في كل خطوة.

خذ مثلاً مشروع React Native في شركة Airbnb. قبل اعتماد GitHub Actions، كان فريق الـ DevOps يقضي 15 ساعة أسبوعياً في إدارة الـ CI/CD فقط. بعد التحويل، انخفض هذا الرقم إلى أقل من ساعة، لأن الـ Workflows أصبحت تتعامل مع كل شيء: بناء التطبيقات لـ iOS وAndroid، تشغيل اختبارات الأداء، وحتى نشر الـ Beta Versions للمختبرين. المفتاح هنا ليس في كتابة workflows كثيرة، بل في كتابة workflows ذكية تتفاعل مع بعضها البعض. مثلاً، الـ Workflow الذي يبني التطبيق لـ Android لا يبدأ إلا إذا نجح الـ Workflow الذي يبني لـ iOS، وهذا بدوره يعتمد على نجاح اختبارات الوحدة. هذه السلسلة من الـ Dependencies تجعل النظام ذكياً بما يكفي لاتخاذ قرارات دون تدخل بشري.

الـ Workflow الذي لا ينكسر: تصميم Pipelines مرنة

الخطأ الأكبر الذي أراه في معظم المشاريع هو كتابة workflows تعتمد على افتراضات خاطئة. مثلاً، افتراض أن الـ Runner سيكون دائماً متاحاً، أو أن الـ Network لن يفشل أبداً. في الواقع، الـ Runners يمكن أن تفشل، والـ Network يمكن أن يكون بطيئاً، والـ API الخارجية يمكن أن تتعطل. لذلك، يجب تصميم كل workflow بحيث يتحمل الفشل ويتعامل معه بذكاء. هذا يعني استخدام الـ Retries، والـ Timeouts، والـ Fallbacks في كل خطوة حرجة.

لنأخذ مثالاً عملياً: workflow لتشغيل اختبارات التكامل مع قاعدة بيانات PostgreSQL. بدلاً من كتابة خطوة واحدة بسيطة مثل `run: npm test`، يجب تقسيمها إلى عدة خطوات ذكية:

  • •الخطوة الأولى: التحقق من اتصال قاعدة البيانات باستخدام `pg_isready` مع retry لمدة 30 ثانية.
  • •الخطوة الثانية: تشغيل الـ Migrations باستخدام أداة مثل Flyway أو Liquibase.
  • •الخطوة الثالثة: تشغيل الاختبارات مع timeout محدد (مثل 5 دقائق) بحيث لا تعلق الـ Pipeline.
  • •الخطوة الرابعة: في حالة الفشل، إرسال إشعار إلى Slack مع الـ Logs الكاملة للخطوة التي فشلت.
  • •الخطوة الخامسة: تنظيف قاعدة البيانات بعد الانتهاء لمنع تسرب البيانات بين الـ Runs.
yaml
name: Integration Tests
on: [push, pull_request]
jobs:
 test:
 runs-on: ubuntu-latest
 services:
 postgres:
 image: postgres:15
 env:
 POSTGRES_PASSWORD: postgres
 ports:
 - 5432:5432
 options: >-
 --health-cmd pg_isready
 --health-interval 10s
 --health-timeout 5s
 --health-retries 5
 steps:
 - uses: actions/checkout@v4
 - name: Wait for PostgreSQL
 run: |
 for i in {1..30}; do
 if pg_isready -h localhost -U postgres; then
 exit 0
 fi
 sleep 1
 done
 exit 1
 - name: Run Migrations
 run: npm run migrate
 env:
 DATABASE_URL: postgres://postgres:postgres@localhost:5432/testdb
 - name: Run Tests
 run: npm test
 timeout-minutes: 5
 env:
 DATABASE_URL: postgres://postgres:postgres@localhost:5432/testdb
 - name: Notify Slack on Failure
 if: failure()
 uses: rtCamp/action-slack-notify@v2
 env:
 SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
 SLACK_COLOR: danger
 SLACK_TITLE: "Integration Tests Failed"
 SLACK_MESSAGE: "Commit: ${{ github.sha }}"
 SLACK_FOOTER: "GitHub Actions"

هذا الـ Workflow ليس مجرد مجموعة خطوات، بل هو نظام ذكي يتفاعل مع البيئة المحيطة. لاحظ كيف استخدمنا الـ `options` في الـ Service لتحديد الـ Health Checks، وكيف أضفنا خطوة انتظار صريحة للتأكد من جاهزية قاعدة البيانات. هذه التفاصيل الصغيرة هي ما يجعل الفرق بين workflow يعمل أحياناً وworkflow يعمل دائماً.


الـ Caching الذكي: كيف تخفض زمن الـ CI من 12 دقيقة إلى 3 دقائق

إذا كنت تعمل في مشروع متوسط الحجم، فمن المرجح أن زمن الـ CI الخاص بك يتراوح بين 8 و15 دقيقة. هذا زمن طويل جداً، خاصة إذا كنت تتبع منهجية الـ Trunk Based Development حيث تدمج الكود عدة مرات في اليوم. السر في تقليل هذا الزمن ليس في شراء runners أسرع، بل في استخدام الـ Caching بذكاء. المشكلة أن معظم المطورين يستخدمون الـ Caching بشكل سطحي، مثلاً لحفظ مجلد الـ `node_modules` فقط. هذا جيد، لكنه ليس كافياً.

في مشروع Node.js كبير، يمكن أن يستغرق تثبيت الـ Dependencies وحدها 3-4 دقائق. لكن إذا كنت تستخدم أدوات مثل Turborepo أو Nx، فإن الـ Build Cache يمكن أن يخفض زمن الـ CI بشكل كبير. مثلاً، إذا قمت بتغيير ملف واحد في مشروع يحتوي على 50 حزمة، فإن Turborepo سيبني فقط الحزم المتأثرة بهذا التغيير، بدلاً من بناء كل شيء من الصفر. هذا يمكن أن يخفض زمن الـ CI من 12 دقيقة إلى أقل من 3 دقائق في المتوسط.

yaml
name: CI with Smart Caching
on: [push, pull_request]
jobs:
 build:
 runs-on: ubuntu-latest
 steps:
 - uses: actions/checkout@v4
 - name: Setup Node.js
 uses: actions/setup-node@v4
 with:
 node-version: 20
 - name: Cache node_modules
 uses: actions/cache@v3
 id: cache-node-modules
 with:
 path: |
 node_modules
 */*/node_modules
 key: ${{ runner.os }}-node-${{ hashFiles('**/yarn.lock') }}
 restore-keys: |
 ${{ runner.os }}-node-
 - name: Install Dependencies
 if: steps.cache-node-modules.outputs.cache-hit != 'true'
 run: yarn install --frozen-lockfile
 - name: Cache Turborepo
 uses: actions/cache@v3
 with:
 path: .turbo
 key: ${{ runner.os }}-turbo-${{ github.sha }}
 restore-keys: |
 ${{ runner.os }}-turbo-
 - name: Build
 run: yarn build
 - name: Test
 run: yarn test

لاحظ كيف استخدمنا خطوتين منفصلتين للـ Caching: واحدة لحفظ مجلدات الـ `node_modules`، وأخرى لحفظ الـ Build Cache الخاص بـ Turborepo. المفتاح هنا هو استخدام مفتاح الـ Cache الذي يعتمد على ملف الـ `yarn.lock`، بحيث يتم إعادة تثبيت الـ Dependencies فقط عندما يتغير هذا الملف. أيضاً، استخدمنا الـ `restore-keys` لاستعادة أحدث cache متاح إذا لم نجد تطابقاً دقيقاً. هذه التقنية وحدها يمكن أن تخفض زمن الـ CI بنسبة 50% أو أكثر في المشاريع الكبيرة.

الـ Caching للـ Docker Builds: لا تبني نفس الصورة مرتين

إذا كنت تستخدم Docker في مشروعك، فمن المحتمل أنك تعيد بناء نفس الصورة مرات عديدة دون داعٍ. هذا ليس فقط مضيعة للوقت، بل أيضاً مضيعة للموارد. الحل هو استخدام الـ Docker Layer Caching مع GitHub Actions. الفكرة بسيطة: بدلاً من بناء الصورة من الصفر في كل مرة، احفظ الطبقات التي لم تتغير واستخدمها في الـ Build التالي. هذا يمكن أن يخفض زمن الـ Docker Build من 5 دقائق إلى أقل من دقيقة واحدة.

yaml
name: Docker Build with Caching
on: [push]
jobs:
 build:
 runs-on: ubuntu-latest
 steps:
 - uses: actions/checkout@v4
 - name: Set up Docker Buildx
 uses: docker/setup-buildx-action@v2
 - name: Login to Docker Hub
 uses: docker/login-action@v2
 with:
 username: ${{ secrets.DOCKER_HUB_USERNAME }}
 password: ${{ secrets.DOCKER_HUB_TOKEN }}
 - name: Cache Docker layers
 uses: actions/cache@v3
 with:
 path: /tmp/.buildx-cache
 key: ${{ runner.os }}-buildx-${{ github.sha }}
 restore-keys: |
 ${{ runner.os }}-buildx-
 - name: Build and push
 uses: docker/build-push-action@v4
 with:
 context: .
 push: true
 tags: user/repo:latest
 cache-from: type=local,src=/tmp/.buildx-cache
 cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max
 - name: Move cache
 run: |
 rm -rf /tmp/.buildx-cache
 mv /tmp/.buildx-cache-new /tmp/.buildx-cache

في هذا الـ Workflow، استخدمنا الـ `docker/build-push-action` مع خيارات الـ Caching المتقدمة. المفتاح هنا هو استخدام الـ `cache-from` و`cache-to` لتحديد مكان حفظ واستعادة الطبقات. لاحظ أيضاً أننا نقلنا الـ Cache إلى مجلد جديد بعد الـ Build لمنع تضخم حجم الـ Cache مع الوقت. هذه التقنية فعالة جداً في المشاريع التي تستخدم Docker بشكل مكثف، مثل المشاريع التي تعتمد على الـ Microservices.


الـ Secrets Management: كيف تحمي بياناتك دون أن تفقد المرونة

إدارة الـ Secrets في GitHub Actions هي واحدة من أكثر المواضيع حساسية في الـ DevOps. المشكلة ليست في تخزين الـ Secrets نفسها، بل في كيفية استخدامها بطريقة آمنة دون تعريض المشروع للخطر. مثلاً، إذا كتبت الـ Secret مباشرة في ملف الـ Workflow، فسيتم تسجيله في الـ Logs ويمكن لأي شخص لديه وصول للـ Repository رؤيته. حتى إذا استخدمت متغيرات البيئة، فإن الـ Secrets يمكن أن تتسرب عبر الـ Debug Logs أو الـ Error Messages.

الحل هو استخدام مزيج من الـ GitHub Secrets والـ Environment Secrets. الـ GitHub Secrets هي متغيرات سرية تُخزن على مستوى الـ Repository أو الـ Organization، ويمكن استخدامها في أي workflow. الـ Environment Secrets هي متغيرات سرية تُخزن على مستوى بيئة معينة (مثل Production أو Staging)، ولا يمكن استخدامها إلا في workflows مرتبطة بهذه البيئة. هذا يسمح لك بفصل الـ Secrets بين البيئات المختلفة دون الحاجة إلى تكرار الكود.

yaml
name: Deploy to Production
on:
 push:
 branches: [main]
jobs:
 deploy:
 runs-on: ubuntu-latest
 environment: production
 steps:
 - uses: actions/checkout@v4
 - name: Deploy
 run: ./deploy.sh
 env:
 AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
 AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
 DATABASE_URL: ${{ secrets.DATABASE_URL }}

في هذا المثال، استخدمنا بيئة `production` لتقييد استخدام الـ Secrets بهذه البيئة فقط. هذا يعني أنه حتى إذا حاول أحدهم تشغيل هذا الـ Workflow في بيئة أخرى، فلن يتمكن من الوصول إلى الـ Secrets الخاصة بالإنتاج. أيضاً، لاحظ أننا استخدمنا متغيرات البيئة بدلاً من كتابة الـ Secrets مباشرة في الكود. هذا يمنع الـ Secrets من الظهور في الـ Logs أو الـ Error Messages.

الـ Secrets في الـ Pull Requests: كيف تمنع التسريبات قبل أن تحدث

إحدى أكبر المخاطر في GitHub Actions هي تسريب الـ Secrets عبر الـ Pull Requests. مثلاً، إذا كتب أحدهم workflow جديد يستخدم secret معين، ثم فتح pull request، فإن هذا الـ Secret يمكن أن يظهر في الـ Logs إذا حدث خطأ. الحل هو استخدام الـ `pull_request_target` بدلاً من الـ `pull_request`، مع إضافة خطوات تحقق إضافية.

yaml
name: Safe PR Workflow
on:
 pull_request_target:
 types: [opened, synchronize, reopened]
jobs:
 check:
 runs-on: ubuntu-latest
 steps:
 - name: Verify PR is from trusted user
 run: |
 if [ "${{ github.event.pull_request.user.login }}" != "trusted-user" ]; then
 echo "PR from untrusted user. Aborting."
 exit 1
 fi
 - uses: actions/checkout@v4
 with:
 ref: ${{ github.event.pull_request.head.sha }}
 - name: Run safe checks
 run: npm run lint
 env:
 SAFE_SECRET: ${{ secrets.SAFE_SECRET }}

في هذا الـ Workflow، استخدمنا الـ `pull_request_target` بدلاً من الـ `pull_request` للسماح باستخدام الـ Secrets في الـ PRs. لكن أضفنا خطوة تحقق للتأكد من أن الـ PR يأتي من مستخدم موثوق فقط. هذا يمنع المهاجمين من فتح PRs خبيثة للحصول على الـ Secrets. أيضاً، لاحظ أننا استخدمنا `ref` محدد للـ Checkout بدلاً من الـ Branch الافتراضي، وهذا يمنع الـ Workflow من التشغيل على الكود الخبيث قبل الموافقة عليه.


الـ Matrix Builds: كيف تختبر على كل بيئة دون كتابة كود مكرر

إذا كنت تعمل في مشروع يدعم عدة نسخ من Node.js أو عدة أنظمة تشغيل، فمن المحتمل أنك تكتب نفس الـ Workflow عدة مرات مع اختلافات بسيطة. هذا ليس فقط مضيعة للوقت، بل أيضاً يجعل الصيانة صعبة. الحل هو استخدام الـ Matrix Builds، وهي ميزة تسمح لك بتشغيل نفس الـ Workflow على عدة بيئات مختلفة دون تكرار الكود.

مثلاً، إذا كنت تريد اختبار مشروعك على Node.js 18 و20 و22 وعلى أنظمة التشغيل Ubuntu وWindows وmacOS، يمكنك كتابة workflow واحد بدلاً من تسعة workflows مختلفة. الـ Matrix Builds ستقوم تلقائياً بإنشاء كل الـ Combinations الممكنة وتشغيل الـ Workflow على كل منها. هذا لا يوفر الوقت فقط، بل أيضاً يضمن أن الكود يعمل على كل البيئات المدعومة.

yaml
name: Test on Multiple Platforms
on: [push, pull_request]
jobs:
 test:
 strategy:
 matrix:
 node-version: [18, 20, 22]
 os: [ubuntu-latest, windows-latest, macos-latest]
 include:
 - node-version: 22
 os: ubuntu-latest
 coverage: true
 runs-on: ${{ matrix.os }}
 steps:
 - uses: actions/checkout@v4
 - name: Setup Node.js ${{ matrix.node-version }}
 uses: actions/setup-node@v4
 with:
 node-version: ${{ matrix.node-version }}
 - name: Install Dependencies
 run: npm install
 - name: Run Tests
 run: npm test
 - name: Run Coverage
 if: matrix.coverage
 run: npm run coverage

في هذا المثال، استخدمنا الـ `strategy.matrix` لتحديد الـ Combinations التي نريد اختبارها. لاحظ كيف أضفنا قسم `include` لتشغيل خطوة إضافية لـ Coverage فقط على الـ Combination المحدد (Node.js 22 على Ubuntu). هذا يسمح لك بإضافة خطوات خاصة ببعض الـ Combinations دون الحاجة إلى تكرار الكود. أيضاً، لاحظ أننا استخدمنا متغير الـ `matrix.os` لتحديد الـ Runner المناسب لكل بيئة. هذه التقنية فعالة جداً في المشاريع التي تدعم عدة منصات، مثل المكتبات المفتوحة المصدر التي يجب أن تعمل على كل أنظمة التشغيل.

الـ Matrix مع الـ Dependencies: كيف تتجنب الـ Redundant Builds

إحدى المشاكل مع الـ Matrix Builds هي أنها يمكن أن تؤدي إلى تشغيل خطوات مكررة. مثلاً، إذا كان لديك خطوة تثبيت الـ Dependencies، فإنها ستُشغل لكل combination في الـ Matrix، حتى لو كانت الـ Dependencies نفسها. هذا ليس فقط مضيعة للوقت، بل أيضاً يمكن أن يؤدي إلى مشاكل إذا كانت الـ Dependencies غير متوافقة مع بعض البيئات.

الحل هو استخدام الـ `needs` لتحديد الـ Dependencies بين الـ Jobs. مثلاً، يمكنك إنشاء job واحد لتثبيت الـ Dependencies وحفظها في الـ Cache، ثم جعل بقية الـ Jobs تعتمد على هذا الـ Job. هذا يضمن أن الـ Dependencies تُثبت مرة واحدة فقط، ثم تُعاد استخدامها في كل الـ Jobs الأخرى.

yaml
name: Optimized Matrix Build
on: [push, pull_request]
jobs:
 setup:
 runs-on: ubuntu-latest
 steps:
 - uses: actions/checkout@v4
 - name: Setup Node.js
 uses: actions/setup-node@v4
 with:
 node-version: 20
 - name: Cache node_modules
 uses: actions/cache@v3
 id: cache-node-modules
 with:
 path: node_modules
 key: ${{ runner.os }}-node-${{ hashFiles('**/yarn.lock') }}
 - name: Install Dependencies
 if: steps.cache-node-modules.outputs.cache-hit != 'true'
 run: yarn install --frozen-lockfile
 test:
 needs: setup
 strategy:
 matrix:
 node-version: [18, 20, 22]
 os: [ubuntu-latest, windows-latest, macos-latest]
 runs-on: ${{ matrix.os }}
 steps:
 - uses: actions/checkout@v4
 - name: Setup Node.js ${{ matrix.node-version }}
 uses: actions/setup-node@v4
 with:
 node-version: ${{ matrix.node-version }}
 - name: Restore node_modules
 uses: actions/cache@v3
 with:
 path: node_modules
 key: ${{ runner.os }}-node-${{ hashFiles('**/yarn.lock') }}
 - name: Run Tests
 run: npm test

في هذا المثال، أنشأنا job منفصل اسمه `setup` لتثبيت الـ Dependencies وحفظها في الـ Cache. ثم جعلنا الـ `test` job يعتمد على الـ `setup` job باستخدام الـ `needs`. هذا يضمن أن الـ Dependencies تُثبت مرة واحدة فقط، ثم تُعاد استخدامها في كل الـ Combinations في الـ Matrix. لاحظ أيضاً أننا استخدمنا نفس مفتاح الـ Cache في كل الـ Jobs لضمان استعادة الـ Cache بشكل صحيح.


الـ Workflows الديناميكية: كيف تبني pipelines تتكيف مع الكود

أحد أقوى ميزات GitHub Actions هو القدرة على إنشاء workflows ديناميكية تتفاعل مع الكود نفسه. مثلاً، يمكنك كتابة workflow يقرأ ملفات المشروع ويقرر أي خطوات يجب تشغيلها بناءً على التغييرات التي حدثت. هذا مفيد جداً في المشاريع الكبيرة التي تحتوي على عدة مكونات مستقلة، حيث لا تريد تشغيل كل الاختبارات في كل مرة يتم فيها تغيير ملف واحد.

خذ مثلاً مشروع يحتوي على عدة مكتبات مستقلة في مجلدات مختلفة. بدلاً من تشغيل كل الاختبارات في كل مرة، يمكنك كتابة workflow يقرأ ملفات الـ Git Changed ويقرر أي مكتبات تأثرت بالتغييرات، ثم يشغل الاختبارات لهذه المكتبات فقط. هذا يمكن أن يخفض زمن الـ CI بشكل كبير، خاصة في المشاريع الكبيرة حيث قد يستغرق تشغيل كل الاختبارات ساعة أو أكثر.

yaml
name: Dynamic Workflow
on: [push, pull_request]
jobs:
 detect-changes:
 runs-on: ubuntu-latest
 outputs:
 packages: ${{ steps.filter.outputs.changes }}
 steps:
 - uses: actions/checkout@v4
 - name: Detect changed packages
 id: filter
 uses: dorny/paths-filter@v2
 with:
 filters: |
 packages/a:
 - 'packages/a/**'
 packages/b:
 - 'packages/b/**'
 packages/c:
 - 'packages/c/**'
 test:
 needs: detect-changes
 if: needs.detect-changes.outputs.packages != '[]'
 strategy:
 matrix:
 package: ${{ fromJSON(needs.detect-changes.outputs.packages) }}
 runs-on: ubuntu-latest
 steps:
 - uses: actions/checkout@v4
 - name: Setup Node.js
 uses: actions/setup-node@v4
 with:
 node-version: 20
 - name: Install Dependencies
 run: yarn install --frozen-lockfile
 - name: Run Tests for ${{ matrix.package }}
 run: yarn workspace ${{ matrix.package }} test

في هذا المثال، استخدمنا الـ `dorny/paths-filter` action لتحديد أي مكتبات تأثرت بالتغييرات الأخيرة. هذا الـ Action يقرأ ملفات الـ Git Changed ويقارنها مع الـ Paths المحددة في الـ Filters، ثم يخرج قائمة بالمكتبات التي تأثرت. ثم استخدمنا هذه القائمة لإنشاء matrix ديناميكية تشغل الاختبارات فقط للمكتبات المتأثرة. هذه التقنية فعالة جداً في المشاريع الكبيرة التي تحتوي على عدة مكونات مستقلة، حيث لا تريد إهدار الوقت في تشغيل اختبارات غير ضرورية.

الـ Workflows التي تتفاعل مع الـ API الخارجية

إحدى الميزات القوية في GitHub Actions هي القدرة على التفاعل مع الـ API الخارجية. مثلاً، يمكنك كتابة workflow يرسل إشعاراً إلى Slack عند فشل الـ Build، أو يقوم بإنشاء issue تلقائياً عند اكتشاف مشكلة أمنية. لكن التعامل مع الـ API الخارجية يتطلب حذراً، خاصة فيما يتعلق بالـ Rate Limits والـ Authentication.

خذ مثلاً workflow يرسل إشعاراً إلى Slack عند فشل الـ Deployment. بدلاً من كتابة الكود مباشرة في الـ Workflow، يمكنك استخدام action جاهزة مثل `rtCamp/action-slack-notify`. هذا الـ Action يتعامل مع كل التفاصيل المعقدة، مثل الـ Retries والـ Rate Limits، ويوفر خيارات متقدمة لتخصيص الإشعار.

yaml
name: Slack Notifications
on:
 workflow_run:
 workflows: ["Deploy to Production"]
 types: [completed]
jobs:
 notify:
 runs-on: ubuntu-latest
 steps:
 - name: Send Slack Notification
 uses: rtCamp/action-slack-notify@v2
 if: github.event.workflow_run.c= 'failure'
 env:
 SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
 SLACK_COLOR: danger
 SLACK_TITLE: "Deployment Failed"
 SLACK_MESSAGE: "Workflow: ${{ github.event.workflow_run.name }}\nStatus: ${{ github.event.workflow_run.conclusion }}\nCommit: ${{ github.event.workflow_run.head_commit.message }}"
 SLACK_FOOTER: "GitHub Actions"

في هذا المثال، استخدمنا الـ `workflow_run` event لتشغيل الـ Workflow عند انتهاء workflow آخر. هذا يسمح لنا بإرسال إشعار عند فشل الـ Deployment دون الحاجة إلى تعديل الـ Deployment Workflow نفسه. لاحظ كيف استخدمنا الـ `if` condition للتأكد من إرسال الإشعار فقط عند الفشل. أيضاً، لاحظ أننا استخدمنا متغير الـ `github.event` للوصول إلى معلومات عن الـ Workflow الذي فشل، مثل اسمه وحالة الانتهاء.


خلاصة المهندس: كيف تبني أتمتة لا تحتاج إلى صيانة

بعد عشر سنوات في تطوير الـ DevOps، تعلمت شيئاً واحداً: الأتمتة الجيدة هي التي تعمل دون أن تشعر بوجودها. الـ Workflows التي تكتبها اليوم يجب أن تستمر في العمل بعد ستة أشهر دون الحاجة إلى تعديل مستمر. لذلك، إليك نصيحتي الذهبية: اكتب workflows بسيطة، استخدم الـ Caching بذكاء، وتأكد من أن كل خطوة تتعامل مع الفشل بذكاء. أيضاً، لا تكتب كوداً مكرراً — استخدم الـ Matrix Builds والـ Dynamic Workflows لتقليل الكود والحفاظ على الصيانة سهلة.

وأخيراً، تذكر أن GitHub Actions ليس مجرد أداة CI/CD. إنه نظام أتمتة شامل يمكن أن يدير كل شيء من الـ Code Reviews إلى الـ Infrastructure. كلما فهمت كيف تعمل الـ Events والـ Dependencies والـ Caching خلف الكواليس، كلما استطعت بناء أتمتة ذكية تتعامل مع التعقيدات الحقيقية في المشاريع الكبيرة. ابدأ صغيراً، ثم أضف التعقيد تدريجياً فقط عندما تحتاج إليه. بهذه الطريقة، ستجنب الوقوع في فخ الـ Over-Engineering الذي يقع فيه الكثير من المطورين.

GitHub Actions CI/CD DevOps Automation Cloud Computing

التعليقات

العودة للمقالات
نوفيل

منصة تعليم البرمجة الأولى بالعربي. تعلم من الصفر حتى الاحتراف مع كورسات احترافية وتحديات ذكاء اصطناعي.

المنصة

  • الكورسات
  • التحديات
  • المقالات
  • الأدوات

الحساب

  • إنشاء حساب
  • تسجيل الدخول
  • لوحة التحكم
  • الملف الشخصي

روابط

  • سياسة الخصوصية
  • شروط الاستخدام
  • عن نوفيل
  • تواصل معنا

© 2026 نوفيل. جميع الحقوق محفوظة.

صُنع بـ في مصر