اتخطّى للمحتوى

المرحلة 05 · الأداء والتشغيلدرس 30 من 3416 دقيقة قراءةآخر تحديث:

Lesson 30 / 34

CI/CDلمشروع شغّال.

إزاي تبني pipeline لمشروع Magento موجود وبيبيع دلوقتي — من غير ما توقّفه ومن غير ما تبدأ من الصفر. التحضير، الـ workflow، النشر بأقل توقّف، والرجوع للخلف لما حاجة تقع.

● عملي GitHub Actions Zero-downtime Rollback

الـ CI/CD لـ Magento 2 بيقوم على فكرة Build ثم Switch: الـ CI بيعمل composer install والـ di:compile والـ static-content:deploy ويغلّف حزمة جاهزة، والسيرفر بيفكّها في مجلد release جديد ويربط env.php و media المشتركين ويشغّل setup:upgrade وبعدين يحوّل symlink اسمه current في لحظة. الرجوع تحويل الـ symlink للنسخة السابقة، والانتقال على مشروع شغّال بيتم بالتدريج.

// الفكرة اللي تمشي عليها أخطر حاجة في الموضوع ده إنك تحاول تعمل كل حاجة مرة واحدة على مشروع بيبيع. الطريقة الصح: تبني الـ pipeline على staging الأول، وتنقل لـ production بالتدريج، وتسيب الطريقة اليدوية شغّالة لحد ما تتأكد. الجزء الأخير في الدرس ده عن الانتقال التدريجي — اقراه قبل ما تبدأ.
◆ Part 1 — الفهم
01

المشكلة اللي بنحلّها

قبل ما تبني حاجة، اعرف إنت بتشتري إيه بالوقت ده.

اللي بيحصل دلوقتي في أغلب المشاريع

حد بيدخل على السيرفر بالـ SSH، يعمل git pull، يشغّل شوية أوامر من دماغه، ويقفل. لو نسي أمر أو غيّر الترتيب، الموقع يقع — والناس تكتشف من العملاء مش من النظام.

المشاكل الحقيقية
  • معرفة في دماغ واحد — لو مسافر أو ساب الشركة، محدش يعرف ينشر.
  • الترتيب بيتنسي — أمر ناقص = صفحات بيضا أو CSS مكسور.
  • مفيش رجوع سريع — لما حاجة تقع، بتصلّح تحت ضغط بدل ما ترجّع.
  • البناء على production — الـ compile والـ static deploy بياكلوا CPU وذاكرة على نفس السيرفر اللي بيخدم العملاء.
  • بيئات مختلفة — staging شغّالة والـ production لأ، لأن حد عدّل حاجة يدوي ونسي.
اللي الـ pipeline بيديهولك

نفس الخطوات بنفس الترتيب كل مرة، من غير ما حد يفتكر. والبناء بيحصل على سيرفر الـ CI، فالـ production بياخد ملفات جاهزة بس. ولو حاجة وقعت، بترجّع بأمر واحد.

تشبيه النشر اليدوي زي طبّاخ بيطبخ من دماغه — النتيجة بتختلف كل مرة وبتعتمد على مزاجه. الـ pipeline زي وصفة مكتوبة بمقادير — أي حد يمشي عليها يطلع نفس النتيجة.
• • •
02

ليه deploy ماجنتو مختلف

مش زي أي تطبيق PHP — فيه خطوات بناء إجبارية.

ليه مش مجرد git pull

Magento بيولّد كود (factories، proxies، interceptors) وبيجمّع ملفات ثابتة (CSS، JS) قبل ما يشتغل. الملفات دي مش في الـ git، فلازم تتولّد مع كل نشر.

the required sequencebash
# 1. الاعتماديات (بدون dev في production)
composer install --no-dev --optimize-autoloader

# 2. تحديث قاعدة البيانات (schema + data patches)
bin/magento setup:upgrade --keep-generated

# 3. توليد الكود (factories, proxies, interceptors)
bin/magento setup:di:compile

# 4. تجميع الملفات الثابتة لكل لغة مستخدمة
bin/magento setup:static-content:deploy -f ar_SA en_US

# 5. تنضيف الكاش
bin/magento cache:flush
!
الـ setup:upgrade هو الوحيد اللي محتاج قاعدة البيانات، وهو الوحيد اللي بيعمل تغييرات مش بترجع لوحدها (schema و data patches). ده هيحدّد شكل الـ pipeline كله: كل حاجة تانية تتعمل على الـ CI، وده يتعمل على السيرفر.
مشكلة الوقت

الـ di:compile وstatic-content:deploy ممكن ياخدوا من دقيقة لعشرة حسب حجم المشروع وعدد اللغات. لو عملتهم على production، دي مدة الموقع فيها بطيء أو واقع. ولو عملتهم على الـ CI، الـ production بياخد الناتج جاهز في ثواني.

• • •
◆ Part 2 — التحضير
03

فحص الحالة الحالية

أغلب الـ pipelines بتفشل بسبب حاجات هنا، مش بسبب الـ workflow نفسه.

  • الـ vendor في الـ git؟ لازم يتشال ويتبني بالـ composer.
  • الـ composer.lock متسجّل؟ لازم — هو اللي بيضمن نفس النسخ في كل بيئة.
  • فيه تعديلات على الـ core؟ هتضيع مع أول composer install نضيف.
  • فيه ملفات على السيرفر مش في الـ git؟ حد رفع patch يدوي ونسي.
  • الـ app/etc/env.php في الـ git؟ ماينفعش — فيه كلمات سر.
  • فيه staging شبه الـ production؟ لازم، وإلا مش هتقدر تجرّب.
افحص بنفسكbash
# هل فيه تعديلات على الـ core؟
composer status

# هل فيه ملفات على السيرفر مش في الـ git؟
git status --porcelain

# الفرق الفعلي بين السيرفر وآخر commit
git diff HEAD --stat
!
لو composer status رجّع تعديلات على vendor/magento، وقّف هنا. لازم تحوّلها لـ patches مُدارة (عن طريق composer-patches) قبل أي أتمتة — وإلا أول deploy هيمسحها والموقع هيتغيّر سلوكه فجأة.
.gitignore — الأساسياتgitignore
# اللي بيتولّد، مايتسجّلش
/vendor/
/generated/
/pub/static/
/var/
/pub/media/

# أسرار وإعدادات بيئة
/app/etc/env.php

# استثناء: ده لازم يتسجّل
!/app/etc/config.php
• • •
04

فصل الإعدادات

الفرق بين config.php و env.php — ده اللي بيخلّي النشر ممكن أصلاً.

app/etc/config.phpقائمة الموديولات المفعّلة + إعدادات مشتركة بين كل البيئات. يتسجّل في الـ git.
app/etc/env.phpقاعدة البيانات، الـ Redis، مفاتيح التشفير، وضع التشغيل. خاص بكل بيئة، مايتسجّلش.
ليه ده مهم للـ CI

لو قائمة الموديولات مش في الـ git، الـ CI مش هيعرف يبني — كل بيئة هتبقى مختلفة. الـ config.php بيخلّي "إيه المفعّل" جزء من الكود، فالبناء بيبقى متكرّر ومتوقّع.

تصدير الإعدادات المشتركةbash
# بيكتب الإعدادات في config.php
bin/magento app:config:dump

# بعدها سجّل الملف
git add app/etc/config.php
git commit -m "lock shared configuration"
!
خد بالك: أي إعداد بيتنقل لـ config.php بيبقى للقراءة بس في لوحة الأدمن (بيظهر مقفول). ده مقصود — الإعداد بقى جزء من الكود ويتغيّر بـ commit. بس بلّغ الفريق قبل ما تعملها، لأن حد من التسويق ممكن يفضل يحاول يغيّر إعداد ومش فاهم ليه مش راضي.
الأسرار

الـ env.php بيفضل على السيرفر ومايتلمسش في النشر. في الـ pipeline، بيتربط بالـ symlink من مجلد مشترك — الجزء الجاي.

• • •
05

بنية السيرفر

البنية اللي بتخلّي النشر لحظي والرجوع لحظي.

/var/www/shop/tree
releases/
├─ 2026-03-01-101500/   # نسخة قديمة
├─ 2026-03-04-093000/   # نسخة قديمة
└─ 2026-03-07-141200/   # الجديدة
shared/                  # بيعيش عبر كل النسخ
├─ app/etc/env.php
├─ pub/media/
└─ var/log/
current -> releases/2026-03-07-141200/
الفكرة

الـ web server بيشاور على current، وده symlink. النشر = ترفع نسخة جديدة جنب القديمة، تجهّزها، وبعدين تحوّل الـ symlink. التحويل ده عملية لحظية.

تشبيه زي مسرح بستارة. بتجهّز الديكور الجديد ورا الستارة والعرض شغّال، ولما يخلص بتفتح الستارة مرة واحدة. الجمهور مايشوفش التجهيز، ولو حصلت مشكلة بترجّع الستارة على الديكور القديم.
اللي لازم يبقى مشترك
  • app/etc/env.php — إعدادات البيئة والأسرار.
  • pub/media/ — صور المنتجات. لو نسيتها هتضيع.
  • var/log/ — عشان التاريخ ميضيعش مع كل نشر.
!
الـ pub/media هو أخطر واحد. لو اتعامل كأنه جزء من النسخة، كل نشر هيبدأ بمجلد فاضي وكل صور المنتجات هتختفي من الموقع. اتأكد إنه symlink للمشترك قبل أول نشر آلي.
• • •
◆ Part 3 — البناء
06

الاستراتيجية: Build ثم Switch

أهم قرار معماري في الـ pipeline كله.

Push
CI: فحص + بناء
حزمة جاهزة
السيرفر: نشر + تحويل
تقسيم المهام
على الـ CIcomposer install · di:compile · static-content:deploy · الاختبارات · تغليف الناتج
على السيرفراستقبال الحزمة · ربط المشترك · setup:upgrade · تحويل الـ symlink · cache:flush
ليه التقسيم ده

الجزء التقيل (البناء) بيحصل على سيرفر مالوش علاقة بالعملاء. الـ production بياخد ملفات جاهزة، فوقت النشر بيبقى ثواني بدل دقايق. وكمان لو البناء فشل، الموقع مااتلمسش أصلاً.

!
فخ معروف: الـ di:compile محتاج ملف env.php موجود عشان يشتغل، حتى لو مش هيوصل لقاعدة البيانات. على الـ CI مفيش env.php حقيقي — الحل إنك تولّد واحد مؤقت ببيانات وهمية في بداية الـ build.
• • •
07

الـ CI — الفحص والبناء

الـ workflow اللي بيشتغل مع كل push.

يشتغل امتى

مع كل pull request. الهدف إنه يمسك الغلط قبل ما يدخل الفرع الرئيسي — ودي أرخص لحظة تمسك فيها غلط.

.github/workflows/ci.ymlyaml
name: CI

on:
  pull_request:
    branches: [ main, develop ]

jobs:
  checks:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: '8.2'
          extensions: intl, soap, bcmath, gd, zip
          tools: composer:v2

      # مفاتيح repo.magento.com من الـ secrets
      - name: Composer auth
        run: |
          composer config -g http-basic.repo.magento.com \
            "${{ secrets.MAGENTO_PUBLIC_KEY }}" \
            "${{ secrets.MAGENTO_PRIVATE_KEY }}"

      - name: Cache vendor
        uses: actions/cache@v4
        with:
          path: vendor
          key: vendor-${{ hashFiles('composer.lock') }}

      - name: Install
        run: composer install --no-interaction --no-progress

      # فحص صحة الـ XML — بيمسك أخطاء بتوقع الموقع
      - name: Validate XML
        run: |
          find app/code -name "*.xml" -print0 \
            | xargs -0 -n1 xmllint --noout

      # معايير الكود على الموديولات بتاعتك بس
      - name: Coding standard
        run: |
          vendor/bin/phpcs --standard=Magento2 \
            --severity=8 app/code/

      - name: Static analysis
        run: vendor/bin/phpstan analyse app/code --level=1

      - name: Unit tests
        run: vendor/bin/phpunit --testsuite="Unit"
i
ابدأ بـ --severity=8 و--level=1. على مشروع قديم، المعايير الكاملة هتطلّع آلاف الأخطاء والفريق هيتجاهل الـ CI خالص. ارفع الدرجة بالتدريج لما الكود ينضف — pipeline بيتجاهله الناس أسوأ من مفيش pipeline.
ليه فحص الـ XML الأول

لأنه أرخص فحص وأكتر واحد بيمسك أعطال حقيقية. ملف di.xml فيه خطأ صغير بيوقّع الموقع كله بـ 500، والفحص ده بياخد ثانية.

الفكرة

بعد ما الفحص ينجح على الفرع الرئيسي، نبني حزمة جاهزة للنشر — فيها كل حاجة اتولّدت، فالسيرفر مش هيحتاج يبني أي حاجة.

.github/workflows/deploy.yml — البناءyaml
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: shivammathur/setup-php@v2
        with: { php-version: '8.2' }

      - name: Install (production)
        run: |
          composer install --no-dev --no-interaction \
            --optimize-autoloader

      # env.php مؤقت — di:compile محتاجه موجود
      - name: Stub env.php for build
        run: |
          mkdir -p app/etc
          printf '<?php return ["MAGE_MODE"=>"production"];' \
            > app/etc/env.php

      - name: Compile DI
        run: bin/magento setup:di:compile

      - name: Deploy static content
        run: |
          bin/magento setup:static-content:deploy -f \
            ar_SA en_US --jobs=4

      # شيل الـ stub عشان ميروحش للسيرفر
      - name: Drop stub
        run: rm -f app/etc/env.php

      - name: Package
        run: |
          tar -czf release.tar.gz \
            --exclude='.git' --exclude='var/*' \
            --exclude='pub/media/*' .

      - uses: actions/upload-artifact@v4
        with:
          name: release
          path: release.tar.gz
!
لاحظ استبعاد pub/media وvar من الحزمة. لو دخلوا، هتدهس صور المنتجات والـ logs على السيرفر. الاستبعاد ده مش تحسين — هو حماية.
• • •
08

الـ CD — النشر

الخطوات على السيرفر، بالترتيب اللي بيقلّل التوقّف.

  • ارفع الحزمة وفكّها في مجلد نسخة جديدة.
  • اربط المشترك — env.php و media و logs بالـ symlink.
  • شغّل setup:upgrade — ده الوحيد اللي بيلمس قاعدة البيانات.
  • حوّل الـ symlink — النسخة الجديدة بقت هي الحية.
  • نضّف الكاش وأعد تشغيل الـ PHP.
  • اتأكد إن الموقع شغّال — وإلا رجّع فوراً.
deploy.sh (على السيرفر)bash
#!/usr/bin/env bash
# يقف عند أول خطأ — مهم جداً
set -euo pipefail

BASE=/var/www/shop
REL=$BASE/releases/$(date +%Y-%m-%d-%H%M%S)

mkdir -p "$REL"
tar -xzf /tmp/release.tar.gz -C "$REL"

# اربط الملفات المشتركة
ln -sfn $BASE/shared/app/etc/env.php "$REL/app/etc/env.php"
rm -rf "$REL/pub/media" "$REL/var"
ln -sfn $BASE/shared/pub/media "$REL/pub/media"
ln -sfn $BASE/shared/var       "$REL/var"

# تحديث قاعدة البيانات — النسخة القديمة لسه شغّالة
cd "$REL"
bin/magento setup:upgrade --keep-generated

# التحويل — لحظي
ln -sfn "$REL" $BASE/current

# نضّف وأعد التشغيل
cd $BASE/current
bin/magento cache:flush
sudo systemctl reload php8.2-fpm

# احتفظ بآخر 5 نسخ بس
ls -dt $BASE/releases/*/ | tail -n +6 | xargs -r rm -rf

echo "deployed: $REL"
ليه الترتيب ده

الـ setup:upgrade بيشتغل قبل التحويل، وهو ماشي على النسخة الجديدة بينما الزوار لسه على القديمة. فالوقت الوحيد اللي فيه تغيير فعلي هو لحظة التحويل.

!
الصراحة المطلوبة عن "zero downtime": البنية دي بتوصّل التوقّف لثواني لما التغييرات متوافقة للخلف — إضافة عمود أو جدول. لكن لو الـ patch بيشيل عمود أو يغيّر نوعه، فيه لحظة النسخة القديمة بتقرا schema اتغيّر. الحالات دي محتاجة نافذة صيانة، أو تقسيم التغيير على نشرتين (ضيف الجديد → انقل البيانات → شيل القديم في نشرة تانية).
deploy.yml — الاتصال بالسيرفرyaml
  deploy:
    needs: build
    runs-on: ubuntu-latest
    # بيئة محمية — تقدر تطلب موافقة يدوية
    environment: production
    steps:
      - uses: actions/download-artifact@v4
        with: { name: release }

      - name: Copy to server
        uses: appleboy/scp-action@v0.1.7
        with:
          host: ${{ secrets.SSH_HOST }}
          username: ${{ secrets.SSH_USER }}
          key: ${{ secrets.SSH_KEY }}
          source: release.tar.gz
          target: /tmp

      - name: Run deploy
        uses: appleboy/ssh-action@v1.0.3
        with:
          host: ${{ secrets.SSH_HOST }}
          username: ${{ secrets.SSH_USER }}
          key: ${{ secrets.SSH_KEY }}
          script: bash /var/www/shop/deploy.sh
i
الـ environment: production في GitHub بيسمحلك تطلب موافقة يدوية قبل النشر. على مشروع بيبيع، خلّي ده مفعّل من أول يوم — الأتمتة الكاملة تيجي بعد ما تثق في الـ pipeline.
• • •
09

الرجوع للخلف

الجزء اللي الناس بتفتكر إنها مش هتحتاجه.

rollback.shbash
#!/usr/bin/env bash
set -euo pipefail
BASE=/var/www/shop

# النسخة اللي قبل الحالية
PREV=$(ls -dt $BASE/releases/*/ | sed -n '2p')

ln -sfn "${PREV%/}" $BASE/current
cd $BASE/current
bin/magento cache:flush
sudo systemctl reload php8.2-fpm

echo "rolled back to: $PREV"
!
الحد اللي لازم تفهمه: الـ rollback ده بيرجّع الملفات بس. لو النشرة شغّلت data patch غيّر بيانات، أو schema patch شال عمود، الرجوع مش هيلغيهم. الـ patches مصمّمة إنها تتنفّذ مرة واحدة ومفيش فيها رجوع.
اللي بيخلّي الرجوع ممكن فعلاً
  • backup لقاعدة البيانات قبل كل نشرة فيها patches — دي شبكة الأمان الحقيقية.
  • خلّي الـ patches متوافقة للخلف — ضيف، ما تشيلش. الشيل يتعمل في نشرة لاحقة بعد ما تتأكد.
  • جرّب الـ rollback على staging — أول مرة تجرّبه ماينفعش تكون وقت أزمة.
تشبيه الـ rollback زي عجلة الاحتياطي — وجودها مش كفاية، لازم تكون جرّبت تركّبها مرة على الأقل قبل ما تحتاجها على الطريق بالليل.
• • •
10

الانتقال التدريجي والفخاخ

إزاي تعمل ده على مشروع بيبيع من غير ما تكسره.

بالترتيب — كل خطوة مستقلة ومفيدة لوحدها
  • الـ CI بس — فحص على الـ PRs، من غير أي نشر. مفيش مخاطرة، وبيبدأ يمسك أخطاء من أول يوم.
  • نشر آلي على staging — جرّب الـ pipeline كامل على بيئة مش بتبيع.
  • جهّز بنية الـ releases على production — من غير ما تستخدمها. انشر يدوي لأسبوع والبنية موجودة.
  • نشر بموافقة يدوية — الـ pipeline بينشر، بس بعد ما حد يضغط موافق.
  • جرّب الـ rollback على production في وقت هادي، متعمّد.
  • أتمتة كاملة — لما تبقى واثق. وكتير من الفرق بتفضل توقف عند خطوة 4 عن قصد.
i
سيب الطريقة اليدوية شغّالة وموثّقة طول فترة الانتقال. أول مرة الـ pipeline يقع في وقت حرج، هتحتاجها.
  • نسيان اللغات في static deploy — تنشر en_US بس فالمتجر العربي يطلع بدون CSS. اكتب كل اللغات المستخدمة.
  • الـ media مش مشترك — كل نشرة بتمسح صور المنتجات.
  • صلاحيات الملفات — الحزمة بتتفك بمستخدم مختلف عن اللي بيشغّل الـ web server، فـ var/ تبقى مش قابلة للكتابة.
  • الـ cron بيشاور على نسخة قديمة — لازم يشاور على current مش على مسار نسخة محددة.
  • الـ consumers شغّالة على كود قديم — عمليات الـ queue لازم تتعاد تشغيلها بعد النشر.
  • مفيش تنبيه لما النشر يفشل — لو محدش عرف، الفايدة اتلغت. اربطه بـ Slack أو إيميل.
  • تسجيل الأسرار في الـ git — ولو مرة واحدة، لازم تغيّرها كلها، لأن التاريخ بيفضل.
!
الفخ اللي بيتكرّر أكتر من غيره: أول نشر آلي على production من غير ما تجرّبه على staging. البنية والصلاحيات والمسارات بتختلف بين البيئتين بطرق مش متوقّعة، والاكتشاف ده وقته مش وقت النشر الحقيقي.
• • •
11

أسئلة الإنترفيو

ده موضوع بيحب المديرين التقنيين يسألوا فيه.

Q1إزاي تعمل deploy لماجنتو من غير downtime؟
الإجابة: بنية releases مع symlink — تبني النسخة الجديدة جنب القديمة، تجهّزها بالكامل، وتحوّل الـ symlink في لحظة. والبناء (compile و static) بيحصل على الـ CI مش على السيرفر. وأضيف الصراحة: ده بيوصّل التوقّف لثواني، لكن التغييرات غير المتوافقة للخلف في الـ schema لسه محتاجة نافذة صيانة أو تقسيم على نشرتين.
Q2ليه تبني على الـ CI مش على السيرفر؟
الإجابة: عشان الـ compile والـ static deploy بياخدوا دقايق وبياكلوا موارد. لو حصلوا على production، ده وقت الموقع فيه بطيء. وكمان لو البناء فشل، الموقع مااتلمسش أصلاً — الفشل بيبقى في مرحلة مالهاش أثر على العملاء.
Q3إيه الفرق بين config.php و env.php؟
الإجابة: config.php فيه الموديولات المفعّلة والإعدادات المشتركة بين البيئات، وبيتسجّل في الـ git. env.php فيه إعدادات البيئة والأسرار، خاص بكل سيرفر ومايتسجّلش. الفصل ده هو اللي بيخلّي البناء متكرّر ومتوقّع.
Q4إزاي ترجع لو نشرة وقعت؟
الإجابة: ترجّع الـ symlink للنسخة السابقة وتنضّف الكاش — ثواني. بس الملفات بس هي اللي بترجع — لو النشرة شغّلت data أو schema patches، دول مش بيرجعوا، عشان كده لازم backup لقاعدة البيانات قبل أي نشرة فيها patches، وتفضيل الـ patches المتوافقة للخلف.
Q5إزاي تبدأ CI/CD على مشروع قديم شغّال؟
الإجابة: بالتدريج. CI للفحص بس الأول (مفيش مخاطرة)، بعدين نشر آلي على staging، بعدين بنية releases على production من غير استخدام، بعدين نشر بموافقة يدوية. والطريقة اليدوية تفضل شغّالة طول الفترة. الـ big bang على مشروع بيبيع بيفشل.

CI/CD لمشروع شغّال ✓

دلوقتي عندك الصورة كاملة: التحضير اللي بيخلّي الأتمتة ممكنة، الـ workflow بجزئيه، النشر بأقل توقّف، الرجوع للخلف، وخطة الانتقال التدريجي.

الخلاصة: ابنِ على الـ CI، انشر بالتحويل، خلّي الرجوع ممكن، وانتقل بالتدريج. والـ pipeline اللي الفريق بيثق فيه أهم من الـ pipeline المثالي.

// magento 2 · ci/cd · github actions

خلّصت الدرس؟علّمه عشان تتابع تقدّمك في الكورس.

كاتب الدرس

Abdulrahman Masoud

عندك سؤال على الدرس أو محتاج مساعدة في مشروع Magento؟ كلّمني.

أسئلة شائعة

إزاي أعمل deploy لـ Magento 2 من غير downtime؟

ببنية releases مع symlink: كل نشرة مجلد جديد جنب القديم، والـ web server بيشاور على current اللي هو symlink. تبني النسخة الجديدة بالكامل وتربط المشترك وتشغّل setup:upgrade والزوار لسه على القديمة، وبعدين تحوّل الـ symlink في لحظة. ده بيوصّل التوقّف لثواني، لكن تغييرات الـ schema غير المتوافقة للخلف لسه محتاجة نافذة صيانة أو نشرتين.

ليه أبني Magento على الـ CI مش على السيرفر؟

لأن setup:di:compile و setup:static-content:deploy بياخدوا من دقيقة لعشرة وبياكلوا CPU وذاكرة. لو حصلوا على production ده وقت الموقع فيه بطيء أو واقع. على الـ CI بتعمل composer install بدون dev والـ compile والـ static deploy وتغلّف الناتج، والسيرفر بياخد حزمة جاهزة ويشغّل setup:upgrade بس. ولو البناء فشل الموقع مااتلمسش أصلًا.

إيه الفرق بين config.php و env.php في Magento 2؟

app/etc/config.php فيه قائمة الموديولات المفعّلة والإعدادات المشتركة بين البيئات اللي بتصدّرها بـ app:config:dump، وبيتسجّل في الـ git. app/etc/env.php فيه قاعدة البيانات و Redis ومفاتيح التشفير ووضع التشغيل، خاص بكل بيئة ومايتسجّلش. الإعدادات اللي بتتنقل لـ config.php بتبقى للقراءة بس في الأدمن.

إيه الملفات اللي لازم تكون مشتركة بين نشرات Magento؟

app/etc/env.php لأنه فيه الأسرار، و pub/media لأنها صور المنتجات، و var/log عشان التاريخ مايضيعش. بتحطهم في مجلد shared وتربطهم بـ symlink جوّه كل نسخة. الـ pub/media أخطر واحد: لو اتعامل كجزء من النسخة كل نشر هيبدأ بمجلد فاضي وكل صور المنتجات هتختفي. واستبعدهم من الحزمة اللي بتتبني على الـ CI.

إزاي أرجع للخلف لو نشرة Magento وقعت؟

ترجّع الـ symlink للنسخة السابقة وتنضّف الكاش وتعيد تشغيل PHP-FPM، وده ثواني. بس ده بيرجّع الملفات بس. لو النشرة شغّلت data patch أو schema patch شال عمود، الرجوع مش هيلغيهم لأن الـ patches بتتنفّذ مرة واحدة. عشان كده backup لقاعدة البيانات قبل أي نشرة فيها patches، وخلّي الـ patches متوافقة للخلف، وجرّب الـ rollback على staging قبل ما تحتاجه.

ليه setup:di:compile بيفشل على الـ CI؟

غالبًا لأن app/etc/env.php مش موجود، والأمر محتاجه موجود حتى لو مش هيوصل لقاعدة البيانات. الحل تولّد ملف مؤقت ببيانات وهمية في بداية الـ build زي MAGE_MODE production، وتشيله قبل التغليف عشان مايروحش للسيرفر. ومتنساش مفاتيح repo.magento.com في الـ secrets، وكل اللغات المستخدمة في static-content:deploy وإلا المتجر العربي يطلع من غير CSS.

إزاي أبدأ CI/CD على مشروع Magento قديم شغّال؟

بالتدريج وكل خطوة مفيدة لوحدها: CI للفحص على الـ pull requests بس من غير نشر، وبعدين نشر آلي على staging، وبعدين جهّز بنية الـ releases على production وانشر يدوي لأسبوع، وبعدين نشر بموافقة يدوية بـ environment: production في GitHub، وجرّب الـ rollback في وقت هادي. سيب الطريقة اليدوية موثّقة طول الفترة، لأن الـ big bang على مشروع بيبيع بيفشل.