مقدمة: لماذا لا يكفي CI/CD الأساسي؟
المستوى الأولي من CI/CD لمشاريع C# عادةً ما يقتصر على تشغيل بسيط لـ dotnet build و dotnet test. ومع ذلك، عندما ينمو المشروع ليصبح بنية خدمات مصغرة، أو مستودعًا واحدًا (monorepo)، أو يتطلب دعم إصدارات متعددة من .NET، يصبح النهج القياسي غير كافٍ. يزداد وقت التجميع، وتتكرر الاختبارات، وتتحول عملية نشر حزم NuGet إلى روتين.
في هذه المقالة، سنستعرض التقنيات المتقدمة لإعداد GitHub Actions لمشاريع C# (.NET). ستتعلم كيفية تسريع خطوط الأنابيب باستخدام التخزين المؤقت، وتنظيم الاختبارات المتوازية، وتنفيذ التجميعات المصفوفية، وإعداد النشر التلقائي إلى NuGet. جميع أمثلة الكود جاهزة للاستخدام في مشاريعك.
1. التجميع المصفوفي واختبار إصدارات متعددة من .NET
المصفوفة (matrix) هي أداة قوية في GitHub Actions، تتيح تشغيل نفس سير العمل (workflow) بمعاملات مختلفة. بالنسبة لـ C#، هذا لا غنى عنه عندما تحتاج إلى التحقق من توافق الكود مع .NET 6 و .NET 8 و .NET 9.
مثال على تكوين مصفوفي
أنشئ ملفًا باسم .github/workflows/ci-matrix.yml:
name: Matrix Build and Test
on: push: branches: [ main, develop ] pull_request: branches: [ main ]
jobs: build: runs-on: ubuntu-latest strategy: matrix: dotnet-version: ['6.0.x', '8.0.x', '9.0.x'] configuration: ['Release', 'Debug'] fail-fast: false # استمر في التجميع حتى لو فشل إصدار واحد
steps: - uses: actions/checkout@v4 - name: Setup .NET ${{ matrix.dotnet-version }} uses: actions/setup-dotnet@v4 with: dotnet-version: ${{ matrix.dotnet-version }} - name: Restore dependencies run: dotnet restore - name: Build run: dotnet build --configuration ${{ matrix.configuration }} --no-restore - name: Run tests run: dotnet test --configuration ${{ matrix.configuration }} --no-build --verbosity normalالنقاط الرئيسية:
fail-fast: false— يسمح برؤية النتائج لجميع الإصدارات، حتى لو فشل أحدها.- يمكن أن تتضمن المصفوفة ليس فقط إصدارات .NET، ولكن أيضًا أنظمة التشغيل (مثل
os: [ubuntu-latest, windows-latest]). - بالنسبة للمستودع الواحد (monorepo)، يمكن إضافة معامل
project-pathواختبار وحدات مختلفة.
2. التخزين المؤقت للتبعيات: تسريع التجميع بمقدار 3 مرات
كل تشغيل لـ GitHub Actions يبدأ ببيئة نظيفة. بدون التخزين المؤقت، سيقوم dotnet restore في كل مرة بتنزيل جميع حزم NuGet من جديد. بالنسبة للمشاريع الكبيرة، قد يستغرق هذا من 2 إلى 5 دقائق. الحل هو التخزين المؤقت لمجلد ~/.nuget/packages.
إعداد متقدم للتخزين المؤقت
استخدم action actions/cache مع مفتاح صحيح يأخذ في الاعتبار ملف القفل:
steps: - uses: actions/checkout@v4
- name: Cache NuGet packages uses: actions/cache@v4 with: path: ~/.nuget/packages # المفتاح: تجزئة ملف القفل + اسم نظام التشغيل key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }} # الرجوع إلى المفتاح السابق إذا لم يتغير ملف القفل restore-keys: | ${{ runner.os }}-nuget-
- name: Setup .NET uses: actions/setup-dotnet@v4 with: dotnet-version: '8.0.x'
- name: Restore dependencies run: dotnet restoreنصيحة: إذا كان المشروع يحتوي على عدة ملفات .csproj، استخدم hashFiles('**/*.csproj', '**/packages.lock.json') للحصول على تجزئة أكثر دقة.
3. التشغيل المتوازي للاختبارات وإنشاء التقارير
عندما يحتوي المشروع على مئات الاختبارات، قد يستغرق التشغيل التسلسلي عشرات الدقائق. يدعم GitHub Actions التوازي على مستوى المهام (jobs). ولكن بالنسبة لـ