أتمتة المهام على GitHub Actions: تشغيل الكود عند كل تحديث.
أتمتة المهام على GitHub Actions: تشغيل الكود عند كل تحديث
أصبحت الأتمتة جزءاً أساسياً من أي مشروع برمجي حديث، لأن نقل المهام المتكررة من الإنسان إلى النظام يقلل الأخطاء ويرفع سرعة التسليم بشكل واضح. وإذا كنت قد قرأت سابقاً لماذا نحتاج الأتمتة؟ كيف توفر الشركات آلاف الساعات فستدرك أن الفكرة ليست مجرد راحة للمطور، بل بناء خط تشغيل موثوق يعمل بنفس الجودة في كل مرة.
من بين أقوى الأدوات في هذا السياق تأتي GitHub Actions، وهي خدمة مدمجة داخل GitHub تسمح لك بتشغيل سلسلة من المهام تلقائياً عند حدوث أحداث محددة مثل push أو pull_request أو الجدولة الزمنية. النتيجة هي تنفيذ الاختبارات، بناء المشروع، فحص الجودة، أو حتى إرسال إشعار خارجي فور تحديث المستودع.
في هذا المقال سنشرح كيف يعمل هذا النظام من الداخل، وكيف تبني ملف workflow احترافي، وكيف توصل GitHub بخدمات خارجية عبر API أو Webhook بدون التضحية بالأمان أو الاستقرار.
ما هي GitHub Actions ولماذا تعد محوراً في الأتمتة الحديثة؟
GitHub Actions هي محرك أتمتة يعتمد على الأحداث. أي أن كل عملية تبدأ عندما يقع حدث داخل المستودع: رفع كود جديد، فتح طلب دمج، إنشاء إصدار، أو تشغيل يدوي. عندها يقرأ GitHub ملف إعداد مكتوباً بصيغة YAML ويبدأ بتنفيذ الخطوات المحددة واحدة تلو الأخرى.
هذا النموذج قريب جداً من المفاهيم التي نشرحها عند الحديث عن الفرق بين الـ API والـ Webhook: “لا تتصل بنا، نحن سنتصل بك”. بدلاً من أن تراقب التغييرات يدوياً، يقوم الحدث نفسه بإطلاق التنفيذ. وهنا تتحول الأتمتة من فكرة عامة إلى تدفق عمليات حقيقي يربط الكود بالاختبار والنشر والتنبيهات.
المكونات الأساسية داخل أي Workflow
- الحدث المشغّل: مثل
pushأوpull_request. - الوظائف: وهي
jobsتعمل على بيئات تشغيل منفصلة. - الخطوات: وهي
stepsتنفذ أوامر shell أو تستدعي إجراءات جاهزة. - الإجراءات الجاهزة: وهي
actionsقابلة لإعادة الاستخدام مثل جلب الكود أو تثبيت بيئةNode.js. - الأسرار: مثل مفاتيح الوصول المخزنة في
Secretsلحماية بيانات الاعتماد.
كيف يعمل التشغيل عند كل تحديث؟
عندما يرسل المطور تحديثاً إلى الفرع الرئيسي باستخدام git push، يسجل GitHub الحدث ويبحث داخل المسار .github/workflows عن ملفات سير العمل. إذا وجد ملفاً يطابق الحدث، يبدأ تشغيله على جهاز افتراضي يسمى runner.
هذا runner يقوم بنسخ المستودع، تثبيت الاعتماديات، تشغيل الأوامر المطلوبة، ثم إرجاع النتيجة. فإذا نجحت الاختبارات يمكن المتابعة إلى البناء أو النشر، وإذا فشلت يتوقف المسار ويظهر تقرير واضح داخل واجهة GitHub. هذه الرؤية مهمة لفهم قيمة CI وليس فقط التنفيذ الآلي.
بناء أول ملف Workflow لتشغيل كود JavaScript عند كل Push
إذا كنت تدير مشروع Node.js، فغالباً تريد تشغيل الاختبارات أو سكربت مخصص بعد كل تحديث. ملف الإعداد التالي يوضح بنية عملية وعملية في الوقت نفسه.
name: Run Code On Every Update
on:
push:
branches:
- main
- develop
jobs:
execute-script:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Run custom automation script
run: node scripts/sync-data.js
ضع هذا الملف داخل .github/workflows/run-on-push.yml. بعد أول push إلى main أو develop سيبدأ GitHub في تنفيذ الخطوات تلقائياً.
لماذا هذه الخطوات مهمة؟
- الخطوة
actions/checkoutتجلب نسخة من الكود إلى بيئة التنفيذ. - الخطوة
actions/setup-nodeتضبط إصدارNode.jsالمناسب. - الأمر
npm ciيثبت الاعتماديات بشكل متسق وسريع. - الأمر
npm testيكشف الأعطال مبكراً قبل وصول الكود إلى الإنتاج. - تشغيل السكربت المخصص يفتح الباب لأتمتة حقيقية مثل مزامنة بيانات أو إنشاء تقارير أو دفع تنبيه إلى خدمة خارجية.
تكامل GitHub Actions مع API خارجي بعد كل تحديث
القوة الحقيقية لا تظهر فقط في تشغيل الاختبارات، بل في جعل المستودع نقطة انطلاق لتدفقات أعمال أكبر. يمكنك مثلاً بعد كل تحديث إرسال بيانات إلى نظام داخلي، أو إشعار منصة تعلم، أو إطلاق خدمة نشر. إذا كنت بحاجة إلى أساسيات الطلبات فراجع تشريح طلب الـ API: الـ Endpoint، الـ Headers، والـ Body ولغة الـ JSON: كيف تقرأ وتكتب البيانات التي تفهمها الآلات.
في المثال التالي نستخدم سكربت JavaScript يرسل ملخصاً عن آخر تحديث إلى خدمة خارجية عبر POST.
const payload = {
repository: process.env.GITHUB_REPOSITORY,
commitSha: process.env.GITHUB_SHA,
actor: process.env.GITHUB_ACTOR,
message: "A new update was pushed successfully"
};
async function notifyExternalService() {
const response = await fetch("https://example.com/api/deployments", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${process.env.EXTERNAL_API_TOKEN}`
},
body: JSON.stringify(payload)
});
if (!response.ok) {
throw new Error(`Request failed with status ${response.status}`);
}
const data = await response.json();
console.log("External API response:", data);
}
notifyExternalService().catch(error => {
console.error("Automation failed:", error.message);
process.exit(1);
});
توثيق نقطة الاتصال المقترحة:
المسار:POST /api/deployments
الرؤوس المطلوبة:Content-Type: application/jsonوAuthorization: Bearer <token>
الاستجابة الناجحة:200أو201
الأخطاء الحرجة المحتملة:401عند فشل التوثيق،429عند تجاوز الحد المسموح، و500إذا تعطل الخادم البعيد.
إدارة الأسرار والمفاتيح بأمان
من أكثر الأخطاء خطورة أن يضع المطور مفتاح الخدمة داخل الكود مباشرة. الأفضل هو تخزينه في GitHub Secrets ثم استدعاؤه أثناء التنفيذ. هذا متوافق مع أفضل ممارسات الأمان التي تناولناها في مفاتيح الوصول (API Keys): كيف تحمي بابك الخلفي وأمن البيانات: كيفية تخزين المفاتيح السرية في ملفات .env.
بعد إنشاء السر مثلاً باسم EXTERNAL_API_TOKEN يمكنك تمريره إلى الخطوة التشغيلية بسهولة من ملف سير العمل. وهنا يفصل GitHub بين الكود العام والبيانات الحساسة، وهي نقطة بالغة الأهمية في المشاريع الجماعية والمفتوحة المصدر.
- name: Notify external API
env:
EXTERNAL_API_TOKEN: ${{ secrets.EXTERNAL_API_TOKEN }}
run: node scripts/notify.js
أفضل الممارسات لتجنب الأعطال المتكررة
أي أتمتة ناجحة لا تكتفي بالتشغيل، بل تتوقع الفشل أيضاً. عند التعامل مع خدمات خارجية، قد تواجه تأخيراً أو انقطاعاً أو استجابة غير متوقعة. لذلك من المفيد الرجوع إلى معالجة الأخطاء (Error Handling): كيف تجعل نظامك “مضاداً للكسر” والـ Retries و Backoff: ماذا تفعل عندما يفشل الـ API مؤقتاً؟.
- نفّذ اختباراتك قبل أي خطوة نشر أو إشعار خارجي.
- استخدم فروعاً واضحة مثل
mainوdevelopلتجنب التشغيل غير المقصود. - أضف سجلات
logsمفهومة لتسهيل التشخيص. - تعامل مع حالات
HTTP Status Codesبوضوح، ويمكنك تعميق الفهم عبر رموز الحالة (HTTP Status Codes): ماذا يخبرك السيرفر بـ 200 أو 404؟. - راقب حدود الاستدعاء إذا كانت الجهة الخارجية تفرض
Rate Limitingكما شرحنا في تحديد معدل الطلبات (Rate Limiting): كيف تتجنب الحظر من الخوادم.
متى تكون GitHub Actions كافية، ومتى تحتاج منصة أوسع؟
إذا كان الحدث يبدأ من الكود نفسه، فإن GitHub Actions غالباً تكفي تماماً. أما إذا كان التدفق يمر عبر عشرات التطبيقات غير البرمجية، فقد تحتاج إلى أدوات أوسع مثل قوة Zapier: ربط أكثر من 5000 تطبيق بضغطات زر أو مقدمة في منصة Make (Integromat سابقاً): بناء سيناريوهات معقدة. الاختيار هنا يعتمد على مصدر الحدث، مستوى التحكم المطلوب، وطبيعة البنية التقنية لديك.
لكن في سياق المشاريع البرمجية وعمليات CI/CD، تظل GitHub Actions خياراً ممتازاً لأنها قريبة من المستودع، سهلة التتبع، وتمنحك رؤية مباشرة حول كل تحديث وكل فشل وكل خطوة تنفيذ.
خاتمة
تشغيل الكود عند كل تحديث لم يعد رفاهية، بل آلية دفاعية وإنتاجية في آن واحد. باستخدام GitHub Actions يمكنك تحويل كل push إلى سلسلة عمليات مدروسة: اختبار، تحقق، مزامنة، إشعار، أو نشر. وعندما تضبط ملف workflow بشكل صحيح، فأنت لا تكتب أوامر فقط، بل تبني نظاماً يتخذ القرار المناسب تلقائياً عند كل تغيير في الكود.
السر ليس في كتابة ملف YAML فحسب، بل في فهم تدفق الحدث، وتأمين المفاتيح، ومعالجة الأخطاء، وربط المستودع بباقي منظومتك التقنية. هنا تتحول الأتمتة من تنفيذ آلي بسيط إلى بنية تشغيل احترافية قابلة للتوسع.