سير العمل والوظائف والخطوات
سير العمل والوظائف والخطوات
GitHub Actions هي منصة CI/CD المدمجة مباشرة في GitHub. كل شركة تقنية كبرى — Google وMicrosoft وStripe وShopify — تستخدمها أو ما يعادلها. لاستخدامها بفعالية، يجب أن تفهم نموذج التنفيذ المكوّن من ثلاث طبقات: سير العمل (Workflows) تحتوي وظائف (Jobs)، والوظائف تحتوي خطوات (Steps). الخلط بين هذه الطبقات ينتج pipelines هشة وبطيئة وصعبة التصحيح في الإنتاج.
تشريح ملف سير العمل
سير العمل هو ملف YAML مخزن في مستودعك تحت المسار .github/workflows/. يفحص GitHub هذا المجلد تلقائياً — أي ملف .yml هناك يصبح workflow مسجلاً. المفاتيح الرئيسية التي يجب أن يحتوي عليها كل workflow هي name وon وjobs.
إليك workflow على مستوى الإنتاج يُظهر كل عنصر هيكلي رئيسي. اقرأه بعناية قبل أن نشرح كل جزء.
الأحداث والمشغّلات: مفتاح on
يحدد مفتاح on ما يُسبّب تشغيل سير العمل. تدعم GitHub Actions أكثر من 35 نوعاً من الأحداث. اختيار أحداث خاطئة هو أحد أكثر أخطاء تصميم الـ pipeline شيوعاً — الـ workflows التي تعمل على نطاق واسع جداً تهدر الدقائق وتستنزف الحصة المجانية؛ تلك التي تعمل على نطاق ضيق جداً تُغفل الانتكاسات.
أهم الأحداث في العمل الهندسي اليومي هي:
push— يُطلَق عند دفع commits إلى فرع. استخدم فلاترbranchesلتجنب الإطلاق على كل فرع في المستودع. أضفpaths-ignoreلتخطي التغييرات التوثيقية فقط (CI لا يحتاج للتشغيل لأن أحدهم أصلح خطأ إملائياً في README).pull_request— يُطلَق عند فتح PR أو تحديثه أو مزامنته. هذا الحدث الأهم في CI: يُبوّب الدمج. دائماً اقرنه بفلترbranchesلتُطلق فقط PRs التي تستهدف الفروع المهمة تشغيلات مكلفة.workflow_dispatch— يُطلَق حين ينقر إنسان "Run workflow" في واجهة GitHub. استخدمه للعمليات عند الطلب: قطع الإصدارات، عمليات الترحيل المفردة، تشغيل مجموعات الاختبارات البطيئة. كتلةinputsتعرّف نموذجاً يُقدمه GitHub في واجهة المستخدم.schedule— يُطلَق وفق جدول cron. استخدمه لعمليات الفحص الأمني الليلية، تدقيق التبعيات، أو أي فحص يجب تشغيله بشكل مستقل عن تغييرات الكود. التوقيت دائماً UTC.
concurrency، ستكون هناك خمس تشغيلات في الطابور لنفس PR، مما يهدر الـ runners ويُربك فحوصات الحالة. دائماً أضف مجموعة concurrency مرتبطة بـ github.workflow وgithub.ref، مع cancel-in-progress: true. هذا يضمن أن التشغيل الأخير فقط لفرع معين هو النشط، وتُلغى الأقدم تلقائياً.needs يجعل test ينتظر نجاح lint؛ المصفوفة تُدوّر runnerين متوازيين لـ Python 3.11 و3.12.الوظائف: وحدة العزل
الوظيفة هي وحدة العزل في GitHub Actions. كل وظيفة تعمل على آلة افتراضية جديدة — لا شيء من نظام ملفات وظيفة ما، أو متغيرات بيئتها، أو أدواتها المثبّتة ينتقل إلى وظيفة أخرى ما لم تُمرره صراحة عبر artifacts. هذا اختيار تصميمي متعمد: يمنع الاقتران الخفي بين مراحل CI.
حقول تهيئة الوظيفة الرئيسية:
runs-on— نظام تشغيل وإصدار الـ runner. ثبّت دائماً على إصدار محدد مثلubuntu-24.04بدلاً من علامةubuntu-latestالقابلة للتغيير. تُغيّر GitHub ما يشير إليهubuntu-latestبدون إشعار، مما يسبب انتكاسات بيئة صامتة في pipeline.needs— مصفوفة من معرّفات الوظائف التي يجب أن تكتمل بنجاح قبل أن تبدأ هذه الوظيفة. افتراضياً، جميع الوظائف في workflow تعمل بالتوازي. استخدمneedsللتعبير عن التبعيات: الاختبار لا يجب أن يعمل إن فشل الـ lint؛ النشر لا يجب أن يعمل إن فشلت الاختبارات.environment— يربط الوظيفة بـ GitHub Environment (مُغطى في درس لاحق)، مما يتيح قواعد حماية النشر والـ secrets المُحدّدة لبيئات بعينها (staging وproduction).outputs— يتيح لوظيفة نشر أزواج key-value يمكن للوظائف التالية قراءتها. يُستخدم لتمرير أسماء حزم البناء، أرقام الإصدارات المحسوبة، أو نتائج الاختبارات بين الوظائف.timeout-minutes— الوقت الأقصى المسموح به للوظيفة قبل أن تُلغيه GitHub. الافتراضي 360 دقيقة (6 ساعات). دائماً حدد حداً أضيق — اختبار تكامل متوقف لا يجب أن يستهلك ست ساعات من وقت الـ runner قبل إيقافه.
node_modules/ أو venv/. لكن الوظيفة B لا ترى ما كتبته الوظيفة A على القرص. إن بنت الوظيفة A صورة Docker تحتاجها الوظيفة B للدفع، يجب على A رفع الصورة كـ artifact (أو دفعها إلى registry) وتنزيلها B.الخطوات: حيث يحدث العمل
الخطوة هي وحدة عمل واحدة داخل وظيفة. تعمل كأمر shell (run) أو تستدعي action جاهزة (uses). تُنفَّذ الخطوات بالتسلسل داخل الوظيفة، بالترتيب الذي عُرِّفت به — لا تزامن على مستوى الخطوة.
كل خطوة يمكن أن تحتوي اختيارياً على:
name— التسمية المعروضة في واجهة GitHub وفي مخرجات السجل. دائماً اكتب أسماء ذات معنى — "Run tests" مفيد بالحد الأدنى، "Unit tests (src/)" مفيد، "pytest src/ -x --tb=short -q" هو بالضبط ما تحتاجه حين تُصحّح فشلاً في الساعة الثانية صباحاً.id— معرّف ثابت يُستخدم للإشارة إلى مخرجات هذه الخطوة ونتيجتها من الخطوات اللاحقة في نفس الوظيفة.if— تعبير شرطي يحدد ما إذا كانت هذه الخطوة ستُنفَّذ. يُستخدم شائعاً للخطوات التي يجب تنفيذها عند الفشل فقط (if: failure()) أو على فروع محددة.env— متغيرات بيئة مُحدّدة لهذه الخطوة، تتجاوز متغيرات مستوى الوظيفة أو سير العمل لهذه الخطوة فقط. لا تضع secrets مباشرة في قيمenv— دائماً ارجع إليها عبر${{ secrets.MY_SECRET }}.continue-on-error— إن كانتtrue، تستمر الوظيفة حتى إن فشلت هذه الخطوة. مفيد للتشخيصات الاختيارية كتقرير التغطية التي لا يجب أن تعيق الـ pipeline.
GITHUB_OUTPUT لا set-output: صيغة echo "::set-output name=key::value" القديمة مهجورة ومعطّلة على الـ runners الجديدة. دائماً اكتب المخرجات باستخدام نهج ملف البيئة: echo "key=value" >> "$GITHUB_OUTPUT". كذلك استخدم echo "MY_VAR=value" >> "$GITHUB_ENV" لتعيين متغيرات بيئة تستمر عبر الخطوات في نفس الوظيفة. كلا الملفين GITHUB_OUTPUT وGITHUB_ENV ملفات مؤقتة تنشئها GitHub؛ الإلحاق بهما هو الآلية المعتمدة الآمنة من الحقن.رسم بيان التبعيات: تصميم ترتيب الوظائف
على نطاق الشركات الكبرى، رسم بيان تبعيات الوظائف هو الرافعة الأكبر لسرعة الـ pipeline. النموذج الذهني هو رسم بيان موجّه غير دوري (DAG): الوظائف بلا تبعيات تعمل بالتوازي؛ الوظائف ذات needs تُشكّل سلاسل. يُشغّل pipeline مُصمَّم جيداً أكبر قدر ممكن بالتوازي، ويُسلسل فقط ما هو تابع حقاً.
نمط إنتاجي شائع لخدمة ويب:
- المرحلة الأولى المتوازية:
lintوtype-checkوdependency-audit— تعمل جميعها في آنٍ واحد بلا تبعيات. كلها رخيصة (تحت دقيقتين) ومستقلة تماماً. - المرحلة الثانية (تحتاج المرحلة الأولى):
unit-tests— تعمل فقط إن نجح الـ lint والتحقق من النوع. تشغيل الاختبارات بعد فشل الـ lint ضوضاء لا معنى لها. - المرحلة الثالثة (تحتاج unit-tests):
build— تجميع وتغليف الـ artifact. - المرحلة الرابعة (تحتاج build):
integration-tests— تشغيل التبعيات (قاعدة البيانات، ناقل الرسائل) واختبار الـ artifact المغلّف من البداية للنهاية. - المرحلة الخامسة (تحتاج integration-tests، على main فقط):
deploy-staging— النشر على بيئة staging، مُبوَّبة بموافقة GitHub Environment.
أنماط الإنتاج الشائعة
بعض إعدادات مستوى سير العمل التي يجب أن يتضمنها كل pipeline إنتاجي:
كل إعداد في ذلك الهيكل له سبب. concurrency يمنع هدر الـ runner. permissions: contents: read يتبع مبدأ أقل الصلاحيات — GITHUB_TOKEN الافتراضي قوي جداً لوظيفة اختبار، وaction مخترقة في سلسلة تبعياتك لا يجب أن تكون قادرة على الدفع إلى مستودعك. timeout-minutes: 20 شبكة أمان ضد العمليات المتوقفة التي ستستهلك طاقة الـ runner ساعات.
فهم سير العمل والوظائف والخطوات بهذا العمق هو الأساس لكل ما يلي في هذا الدرس التعليمي: بنيات المصفوفة، والتخزين المؤقت، وسير العمل القابلة للإعادة الاستخدام، ومصادقة OIDC، والنشر الآمن — كلها تُبنى مباشرة على هذا النموذج المكوّن من ثلاث طبقات. اضبط الهيكل صح وسيبدو باقي الدرس التعليمي منطقياً. اضبطه خطأً وستُصارع الأداة في كل منعطف.