يا جماعة الخير، السلام عليكم ورحمة الله وبركاته. معكم أخوكم أبو عمر.
خليني أحكيلكم قصة صارت معي قبل كم سنة، قصة الله وكيلكم كل ما أتذكرها بضحك وبنفس الوقت بحمد ربنا على النعمة اللي إحنا فيها اليوم. كنا في نص الليل، والمفروض نسلم تحديث مهم للعميل الصبح. معنا شب جديد بالفريق، شاطر ومتحمس، خلينا نسميه “سامر”. سامر خلص الشغل المطلوب منه، عمل push للكود على الـ repository وقال بكل ثقة: “يا شباب، كل شي تمام، جاهز للـ deployment”.
أنا، بحكم الخبرة، قلبي نقزني شوي. سألته: “سامر، جربت كل شي عندك؟”. رد علي الجملة المشؤومة اللي كل مبرمج بكرهها: “أكيد أبو عمر، شغّال مية بالمية على جهازي!“.
توكلنا على الله وبدأنا عملية النشر اليدوية. كان عنا ملف `deploy.sh` عبارة عن مجموعة سكربتات باش (Bash) معقدة، كل واحد فينا عدّل عليها شوي مع الزمن. شغلنا السكربت… وانتظرنا. دقيقة، دقيقتين، خمسة… وفجأة، ولّعت الدنيا. السيرفر صار يرجع خطأ 500، الموقع وقع، ورسائل الدعم الفني بلشت توصلنا زي المطر.
قضينا الساعتين اللي بعدهم في كابوس حقيقي، نحاول نعرف شو القصة. اكتشفنا بالنهاية إن نسخة مكتبة معينة على جهاز سامر كانت أحدث من النسخة اللي على السيرفر، والسكربت تبعنا ما كان يثبّت النسخ المحددة بالضبط. كانت ليلة طويلة ومتعبة، وفي نهايتها قلت للفريق: “خلص، بكفي. لازم نلاقي حل جذري لهالمشكلة”. ومن هنا بدأت رحلتنا مع GitHub Actions.
ما هو جحيم “يعمل على جهازي”؟ ولماذا هو كارثة؟
جملة “It works on my machine” هي عرض لمرض خطير في عملية تطوير البرمجيات. المرض هو انعدام التوحيد في البيئات (Lack of Environment Consistency). المشكلة لا تكمن في كود المبرمج بالضرورة، بل في أن البيئة التي يكتب ويختبر فيها الكود (جهازه الشخصي) تختلف عن البيئات الأخرى مثل بيئة الاختبار (Staging) أو البيئة الإنتاجية (Production).
هذه الاختلافات قد تكون:
- إصدارات مختلفة من اللغات والمكتبات: مثل ما صار معنا، Node.js v16 على جهاز المطور و v14 على السيرفر.
- متغيرات البيئة (Environment Variables): مفاتيح API أو إعدادات قاعدة البيانات الموجودة على جهازك وليست على السيرفر.
- نظام التشغيل: تطوير على Windows والنشر على Linux يمكن أن يسبب مشاكل في مسارات الملفات أو الأوامر.
- خطوات يدوية منسية: قد يقوم المطور بتشغيل أمر يدوي على جهازه وينسى توثيقه أو إضافته لسكربت النشر.
هذا الجحيم يؤدي إلى ضياع ساعات طويلة في تصحيح الأخطاء، تأخير في إطلاق الميزات، وفقدان الثقة في عملية النشر.
متاهة السكربتات القديمة: تشخيص المشكلة
قبل GitHub Actions، كانت عمليتنا عبارة عن مجموعة من السكربتات المتناثرة. كان لدينا `build.sh`، `test.py`، و `deploy.sh` الأسطوري. هذه الطريقة، ورغم أنها كانت “تؤدي الغرض” في البداية، إلا أنها كانت تعاني من مشاكل جوهرية:
صعوبة الصيانة والتطوير
أي تغيير بسيط، مثل إضافة خطوة جديدة لعملية الـ build، كان يتطلب التعديل على سكربت معقد ومخيف، مع الخوف الدائم من كسر شيء ما بالخطأ. كانت السكربتات غير موثقة جيدًا، وفهمها كان تحديًا بحد ذاته.
انعدام التوحيد
كل مطور كان لديه نسخة “محلية” من هذه السكربتات، وأحيانًا يقوم بتعديلها لتناسب جهازه دون إعلام الفريق. هذا كان يزيد من فجوة “يعمل على جهازي”.
المعرفة القبلية (Tribal Knowledge)
كان هناك شخص واحد أو اثنان فقط في الفريق (وأنا منهم للأسف) يفهمون تمامًا كيف تعمل هذه السكربتات. إذا كان هذا الشخص في إجازة أو ترك الشركة، تحدث الكارثة. المعرفة كانت محصورة في رؤوس الأفراد وليس في نظام موثق.
الأمان والثقة
كنا أحيانًا نضطر لوضع مفاتيح حساسة (مثل مفاتيح SSH أو tokens) داخل السكربتات نفسها، وهو ما يمثل ثغرة أمنية كبيرة. الله ستر وما حدا سرقها!
المنقذ GitHub Actions: بداية الرحلة نحو الأتمتة
عندما قررنا أن نجد حلاً، كان GitHub Actions خيارًا طبيعيًا لأن كل كودنا موجود بالفعل على GitHub. الفكرة بسيطة وعبقرية: بدلاً من تشغيل السكربتات يدويًا، دع GitHub يقوم بذلك بالنيابة عنا في كل مرة يحدث فيها شيء معين (مثل push أو pull request).
GitHub Actions هي أداة CI/CD (Continuous Integration / Continuous Deployment) مدمجة مباشرة في GitHub. تسمح لك بأتمتة كل شيء: بناء الكود، تشغيل الاختبارات، ونشره على الخوادم، كل ذلك بطريقة موحدة وموثوقة.
الجمال يكمن في أنها تستخدم ملفات YAML بسيطة ومقروءة لوصف سير العمل (Workflow)، وتعمل داخل حاويات (containers) نظيفة ومعزولة في كل مرة، مما يقضي تمامًا على مشكلة “يعمل على جهازي”. البيئة دائمًا واحدة للجميع.
بناء أول Workflow: من النظرية إلى التطبيق العملي
دعونا نأخذ مثالاً عمليًا. لنفترض أن لدينا تطبيق Node.js بسيط. نريد إنشاء workflow يقوم تلقائيًا بتشغيل الاختبارات في كل مرة يقوم فيها مطور بعمل push لفرع `main`.
المكونات الأساسية لملف الـ Workflow
يتم تعريف الـ workflow في ملف YAML يوضع داخل مجلد `.github/workflows` في مشروعك. الملف يتكون من عدة أجزاء رئيسية:
name: اسم الـ workflow الذي سيظهر في واجهة GitHub.on: الحدث الذي سيُفعّل الـ workflow (مثلاً:push,pull_request).jobs: مجموعة من المهام التي سيتم تنفيذها. كل مهمة تعمل على “runner” (خادم افتراضي).runs-on: يحدد نظام التشغيل للـ runner (مثلubuntu-latest).steps: سلسلة من الخطوات التي تنفذها المهمة.uses: يستخدم “action” جاهز من المجتمع أو من GitHub (مثلactions/checkoutلجلب الكود).run: يقوم بتشغيل أمر في الـ command line.
مثال عملي: Workflow بسيط لتطبيق Node.js
سنقوم بإنشاء ملف باسم .github/workflows/ci.yml:
# اسم الـ Workflow
name: Node.js CI
# متى يتم تشغيل هذا الـ Workflow
on:
push:
branches: [ "main" ] # عند الدفع إلى الفرع الرئيسي
pull_request:
branches: [ "main" ] # عند فتح طلب سحب إلى الفرع الرئيسي
# المهام التي سيتم تنفيذها
jobs:
build-and-test: # اسم المهمة
# الخادم الافتراضي الذي ستعمل عليه المهمة
runs-on: ubuntu-latest
# الخطوات التي سيتم تنفيذها بالترتيب
steps:
# الخطوة 1: سحب الكود من الـ repository
# هذا Action رسمي من GitHub
- name: Checkout repository code
uses: actions/checkout@v3
# الخطوة 2: إعداد بيئة Node.js
# هذا Action يثبت Node.js بالنسخة التي نحددها
- name: Use Node.js 18.x
uses: actions/setup-node@v3
with:
node-version: '18.x'
cache: 'npm' # لتسريع عملية تثبيت الحزم في المرات القادمة
# الخطوة 3: تثبيت الاعتماديات (Dependencies)
# نستخدم npm ci لأنه أسرع وأكثر أمانًا للـ CI/CD من npm install
- name: Install dependencies
run: npm ci
# الخطوة 4: تشغيل الاختبارات
- name: Run tests
run: npm test
# يمكنك إضافة خطوة للـ build إذا كان مشروعك يحتاج
- name: Build project
run: npm run build --if-present
بهذا الملف البسيط، قمنا بأتمتة عملية الاختبار بالكامل. الآن، لا يمكن لأي كود أن يصل إلى فرع `main` دون أن يجتاز الاختبارات بنجاح في بيئة نظيفة وموحدة. وداعًا لـ “يعمل على جهازي”! 🎉
تطوير الـ Workflow: من الاختبار إلى النشر (Deployment)
الخطوة التالية هي أتمتة عملية النشر. لنضف خطوة لنشر تطبيقنا على خادم افتراضي (VPS) باستخدام SSH بعد نجاح كل الاختبارات على فرع `main`.
إضافة خطوة النشر والتعامل مع الأسرار (Secrets)
أكبر خطأ هو وضع كلمات المرور أو مفاتيح SSH مباشرة في ملف الـ YAML. GitHub Actions توفر حلاً آمنًا ورائعًا اسمه “Secrets”. يمكنك إضافة أسرارك في إعدادات الـ repository تحت `Settings > Secrets and variables > Actions`.
سنضيف سرًا لمفتاح SSH الخاص بنا (SSH_PRIVATE_KEY)، واسم المستخدم (SSH_USER)، وعنوان الخادم (SSH_HOST).
الآن، سنعدل على الـ workflow ليقوم بالنشر:
# ... (نفس الجزء العلوي من الملف السابق) ...
jobs:
build-and-test:
# ... (نفس خطوات الـ build والاختبار) ...
# مهمة جديدة للنشر، لن تعمل إلا إذا نجحت المهمة السابقة
deploy:
needs: build-and-test # تعتمد على نجاح مهمة build-and-test
runs-on: ubuntu-latest
# لا تقم بالنشر إلا عند الدفع لفرع main، وليس عند طلبات السحب
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
steps:
- name: Checkout repository code
uses: actions/checkout@v3
# يمكنك هنا إضافة خطوة لتحميل الـ build artifacts من المهمة السابقة
# لكن للتبسيط، سنقوم بعملية build جديدة هنا
- name: Use Node.js 18.x
uses: actions/setup-node@v3
with:
node-version: '18.x'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build project
run: npm run build
# الخطوة السحرية: النشر باستخدام SSH
- name: Deploy to server
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SSH_HOST }} # استخدام السر من إعدادات GitHub
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /var/www/my-app
git pull
npm install --production
pm2 restart app-name # مثال على إعادة تشغيل التطبيق باستخدام pm2
ملاحظة هامة: المثال أعلاه هو مجرد توضيح. هناك طرق أكثر تطورًا للنشر، مثل بناء Docker image ودفعها إلى registry، ثم سحبها على الخادم، أو استخدام actions مخصصة لمنصات مثل AWS, Azure, أو Vercel. لكن المبدأ يظل واحدًا: أتمتة آمنة وموثوقة.
نصائح من قلب الميدان (خبرة أبو عمر)
بعد سنوات من استخدام GitHub Actions، خليني أعطيكم كم نصيحة عملية من أخوكم:
- ابدأ بسيطًا ثم تدرّج: لا تحاول أتمتة كل شيء من اليوم الأول. ابدأ بـ workflow بسيط للاختبارات (CI). عندما تشعر بالثقة، أضف خطوات الـ build ثم النشر (CD).
- استغل الـ Marketplace: سوق GitHub Actions مليء بآلاف الـ actions الجاهزة التي صنعها المجتمع. قبل أن تكتب سكربتًا معقدًا، ابحث في الـ Marketplace. هناك actions لكل شيء تقريبًا: من فحص الثغرات الأمنية (Snyk, Trivy) إلى النشر على كل منصة سحابية تخطر ببالك.
- أسرارك في أمان مع Secrets: استخدم دائمًا GitHub Secrets للمعلومات الحساسة. لا تضع أي مفاتيح أو كلمات مرور في الكود أبدًا. هذه قاعدة ذهبية.
- نظّم الـ Workflows: إذا أصبح ملف الـ workflow كبيرًا جدًا، يمكنك تقسيمه إلى “Reusable Workflows” أو استخدام actions مخصصة (Composite Actions) لتنظيم الكود وإعادة استخدامه.
- تعلّم من الأخطاء: في البداية، ستفشل بعض الـ workflows. لا تيأس! سجلات (logs) التنفيذ في GitHub Actions مفصلة جدًا وتساعدك على معرفة مكان الخطأ بالضبط. تصحيح أخطاء الـ workflow هو مهارة بحد ذاتها.
الخلاصة: وداعاً للفوضى، ومرحباً بالإنتاجية 🧘♂️
الانتقال من متاهة السكربتات اليدوية إلى عالم GitHub Actions المنظم كان نقلة نوعية لفريقنا. لم نعد نقضي ساعات في حل مشاكل “يعمل على جهازي”. أصبحت عملية النشر تتم بكبسة زر (أو تلقائيًا)، وبثقة تامة. استعدنا وقتنا الذي كان يضيع في عمليات يدوية مملة، ووجهناه نحو ما يهم حقًا: كتابة كود أفضل وبناء ميزات جديدة.
نصيحتي الأخيرة لك: إذا كنت لا تزال تعتمد على سكربتات يدوية أو عمليات نشر غير موثوقة، فتوقف الآن. استثمر القليل من الوقت في تعلم أداة CI/CD مثل GitHub Actions. هذا الاستثمار سيعود عليك وعلى فريقك بأضعاف مضاعفة من الإنتاجية، راحة البال، والثقة في برمجياتكم. صدقني، لن تندم أبدًا.
والله ولي التوفيق.