ما يحدث أولاً في خط أنابيب CI/CD: سحب الكود وإعداد البيئة

تقوم بدفع commit. يكتشف أداة CI/CD الخاصة بك التغيير ويبدأ تشغيل pipeline جديد. ولكن قبل أن يحدث أي بناء أو اختبار أو نشر، يحتاج الـ pipeline إلى الإجابة على ثلاثة أسئلة أساسية: ما الكود الذي أعمل عليه؟ ما الأدوات المتاحة؟ وهل مساحة العمل نظيفة؟

من السهل التغاضي عن هذه المرحلة الأولى، لكنها غالبًا ما تكون مصدر العديد من إخفاقات الـ pipeline. مساحة عمل غير نظيفة، أو إصدار أداة غير متطابق، أو اعتماد مفقود يمكن أن يعطل الـ pipeline بأكمله قبل أن يبدأ العمل الفعلي. دعنا نستعرض ما يحدث أثناء سحب الكود والتحضير الأولي، ولماذا يعد إتقان هذه المرحلة أمرًا حيويًا لكل pipeline يتبعها.

خطوة سحب الكود: الحصول على الكود الصحيح

عند تشغيل pipeline، فإنه يحمل معلومات من الحدث المشغل: hash commit، أو اسم فرع، أو علامة (tag). تستخدم خطوة سحب الكود هذه المعلومات لسحب الإصدار الدقيق من الكود من المستودع إلى مساحة عمل الـ pipeline.

مساحة العمل هي مجلد مؤقت على الجهاز الذي يقوم بتشغيل الـ pipeline. يُطلق على هذا الجهاز عادةً اسم runner أو agent، اعتمادًا على أداة CI/CD التي تستخدمها. يقوم الـ pipeline بتنزيل الكود في هذا المجلد، ويتم كل شيء آخر من بناء واختبار ونشر داخل هذه المساحة.

فكر في الأمر مثل الوصول إلى مكتب جديد في العمل. تحتاج إلى معرفة المشروع الذي تعمل عليه، وأي إصدار من المشروع يجب استخدامه، وما هي الأدوات المتاحة في مكتبك. بدون ذلك، لا يمكنك البدء.

يوضح مخطط التدفق التالي تسلسل الإجراءات التي تحدث في المرحلة الأولى من خط أنابيب CI/CD:

فيما يلي مثال عملي باستخدام GitHub Actions:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Node.js 18
        uses: actions/setup-node@v4
        with:
          node-version: '18'
          cache: 'npm'
flowchart TD A[حدث مشغل: commit، فرع، أو علامة] --> B[سحب الكود: سحب hash commit دقيق] B --> C[تنظيف مساحة العمل: إزالة الملفات المتبقية] C --> D[تعريف البناء: تسمية القطعة الأثرية حسب الفرع/العلامة] D --> E[إعداد البيئة: تثبيت الأدوات والاعتماديات] E --> F{ذاكرة تخزين مؤقت متاحة؟} F -- نعم --> G[استعادة الاعتماديات المخزنة مؤقتًا] F -- لا --> H[تنزيل اعتماديات جديدة] G --> I[جاهز لمرحلة البناء] H --> I

لماذا تعتبر مساحة العمل النظيفة مهمة

يجب أن يبدأ كل تشغيل pipeline بمساحة عمل نظيفة. إذا بقيت ملفات من تشغيل سابق، فقد تلوث البناء الحالي. يمكن لملف تكوين متبقي، أو ملف ثنائي مترجم قديم، أو اعتماد قديم أن يتسبب في إنتاج الـ pipeline لقطعة أثرية لا تتطابق مع الكود الحالي. تصحيح هذا النوع من المشكلات أمر صعب لأن المشكلة ليست في الكود الخاص بك، بل في الملفات المتبقية من تشغيل سابق.

تقدم معظم أدوات CI/CD خيار مساحة عمل نظيفة. بعضها يفعلها افتراضيًا، والبعض الآخر يتطلب تكوينًا يدويًا. إذا كنت تقوم بإعداد pipeline، فتأكد من تفعيل هذا الخيار. إنه إعداد صغير يمنع فئة كبيرة من الأخطاء التي يصعب العثور عليها.

تحديد ما تقوم ببنائه

بعد سحب الكود، يحتاج الـ pipeline إلى معرفة الفرع أو العلامة التي يعالجها. تحدد هذه المعلومات كيفية تسمية القطعة الأثرية الناتجة وأين تذهب بعد ذلك.

على سبيل المثال، قد ينتج عن commit إلى الفرع main قطعة أثرية مسماة latest أو stable. قد ينتج عن commit إلى فرع ميزة قطعة أثرية تحمل اسم الفرع ورقم البناء. يجب أن تنتج العلامة مثل v1.2.3 قطعة أثرية مسماة بهذا الإصدار بالضبط.

هذه التسمية مهمة لأنها تساعد الفرق على تتبع القطع الأثرية إلى مصدرها. عندما يسأل شخص ما "أي إصدار من الكود أنتج هذه القطعة الأثرية؟"، يجب أن تعطي التسمية إجابة واضحة. بدون تسمية متسقة، تصبح إدارة القطع الأثرية تخمينًا.

إعداد البيئة

بمجرد أن يصبح الكود في مكانه، يحتاج الـ pipeline إلى إعداد بيئته. البيئة هنا تعني أكثر من مجرد المجلد الذي يعيش فيه الكود. وهي تشمل جميع الأدوات والاعتماديات المطلوبة لبناء واختبار ونشر التطبيق.

يحتاج تطبيق Java إلى إصدار JDK محدد. يحتاج تطبيق Node.js إلى وقت تشغيل Node.js الصحيح و npm. يحتاج ترحيل قاعدة البيانات إلى أداة ترحيل مثل Flyway أو Liquibase. يجب أن تكون كل هذه الأدوات متاحة في بيئة الـ pipeline، بالإصدار الصحيح.

مشكلة "إنه يعمل على جهازي"

أحد أكثر الإحباطات شيوعًا في CI/CD هو عدم التطابق بين البيئة المحلية للمطور وبيئة الـ pipeline. يقوم المطور بتشغيل البناء على جهاز الكمبيوتر المحمول الخاص به، كل شيء ينجح، ثم يدفع الكود. يلتقط الـ pipeline الكود، ويقوم بتشغيل نفس البناء، ويفشل.

السبب دائمًا تقريبًا هو اختلاف في البيئة. المطور لديه JDK 17 مثبت محليًا، لكن الـ pipeline يستخدم JDK 11. المطور لديه حزمة npm عامة لا يمتلكها الـ pipeline. جهاز الكمبيوتر المحمول للمطور لديه نظام تشغيل أو بنية مختلفة.

هذه هي مشكلة "إنه يعمل على جهازي" الكلاسيكية، وهي علامة على أن بيئة الـ pipeline لم يتم تعريفها بشكل صريح بما فيه الكفاية.

جعل البيئات قابلة للتكرار

الحل هو تعريف بيئة الـ pipeline بشكل صريح، بحيث يمكن تكرارها في أي مكان. هناك عدة طرق شائعة:

  • صور Docker: قم بتجميع جميع الأدوات المطلوبة في صورة Docker. يعمل الـ pipeline داخل حاوية بناءً على تلك الصورة، مما يضمن نفس البيئة في كل مرة.
  • ملفات إصدار الأداة: استخدم ملفات مثل .tool-versions (لـ asdf)، أو .nvmrc (لـ Node.js)، أو .ruby-version للإعلان عن إصدارات الأدوات الدقيقة. يقرأ الـ pipeline هذه الملفات ويقوم بتثبيت الإصدارات المحددة.
  • مديري البيئة: يمكن لأدوات مثل Conda للـ Python أو SDKMAN للـ Java إدارة إصدارات الأدوات بشكل تصريحي.

الهدف هو نفسه: يجب أن تكون بيئة الـ pipeline قابلة للتكرار أينما يعمل الـ pipeline. إذا كان بإمكانك تشغيل الـ pipeline على جهاز الكمبيوتر المحمول الخاص بك، وعلى خادم CI، وعلى جهاز زميل، والحصول على نفس النتيجة، فقد حللت مشكلة اتساق البيئة.

التخزين المؤقت: السرعة مقابل النضارة

تضيف بعض خطوط الأنابيب التخزين المؤقت في هذه المرحلة لتسريع عمليات التشغيل اللاحقة. يمكن تخزين الاعتماديات التي تم تنزيلها في تشغيل سابق وإعادة استخدامها. هذا منطقي لمجموعات الاعتماديات الكبيرة، مثل node_modules الخاصة بـ Node.js أو venv الخاصة بـ Python.

لكن التخزين المؤقت يقدم مقايضة. يمكن أن يتسبب التخزين المؤقت القديم في استخدام الـ pipeline لاعتماديات قديمة كان يجب استبدالها. إذا تم تحديث اعتماد في المستودع، لكن التخزين المؤقت لا يزال يحتفظ بالإصدار القديم، فقد يقوم الـ pipeline بالبناء على كود قديم.

إذا كنت تستخدم التخزين المؤقت، فتأكد من أن مفتاح التخزين المؤقت يتضمن معلومات كافية لإبطاله عندما تتغير الاعتماديات. النهج الشائع هو تجزئة ملف الاعتماديات (مثل package-lock.json أو requirements.txt) واستخدام هذا التجزئة كجزء من مفتاح التخزين المؤقت. عندما يتغير ملف الاعتماديات، يتغير مفتاح التخزين المؤقت، ويحدث تنزيل جديد.

ما يمتلكه الـ Pipeline بعد هذه المرحلة

بحلول الوقت الذي يكتمل فيه سحب الكود وإعداد البيئة، يكون الـ pipeline قد حصل على:

  • الكود الدقيق من commit أو الفرع أو العلامة المشغلة
  • مساحة عمل نظيفة بدون ملفات متبقية
  • تسمية معروفة للقطعة الأثرية التي سينتجها
  • جميع الأدوات والاعتماديات اللازمة للمراحل التالية

هذا هو الأساس. بدونه، كل مرحلة لاحقة بناء، اختبار، نشر مبنية على عدم اليقين. معه، يمكن للـ pipeline المضي قدمًا بثقة.

قائمة مراجعة سريعة للمرحلة الأولى من الـ Pipeline الخاص بك

  • تم تفعيل أو تكوين مساحة العمل النظيفة
  • يستخدم سحب الكود hash commit الدقيق من المشغل
  • تتطابق تسمية القطعة الأثرية مع اصطلاحات الفرع أو العلامة
  • تم الإعلان عن إصدارات الأدوات بشكل صريح (Docker، ملفات إصدار الأداة، أو مدير البيئة)
  • تتضمن مفاتيح التخزين المؤقت تجزئة ملف الاعتماديات إذا تم استخدام التخزين المؤقت

الخلاصة

تحدد الثواني القليلة الأولى من تشغيل pipeline ما إذا كان باقي الـ pipeline يعمل على أرض صلبة. مساحة العمل النظيفة، والكود الصحيح، والبيئة القابلة للتكرار ليست تفاصيل اختيارية. إنها الأساس الذي يجعل كل مرحلة لاحقة قابلة للتنبؤ وقابلة للتصحيح. استثمر الوقت في إتقان هذه المرحلة، وستوفر وقتًا أطول بكثير في استكشاف أخطاء وإصلاحها التي تتحول إلى مشكلات بيئية بدلاً من مشكلات في الكود.