انتقل إلى المحتوى الرئيسي

الفصل 3: CI/CD مع GitHub Actions

مقدمة​

CI/CD (التكامل المستمر / النشر المستمر) يقوم بأتمتة البناء، الاختبارات والنشر. لا مزيد من النشر اليدوي، أخطاء بشرية أقل.


🎯 أهداف الفصل​

في نهاية هذا الفصل، ستعرف:

  1. ✅ فهم CI/CD
  2. ✅ إنشاء تدفقات عمل GitHub Actions
  3. ✅ أتمتة الاختبارات والبناء
  4. ✅ نشر صور Docker
  5. ✅ النشر التلقائي

1. مقدمة CI/CD​

التكامل المستمر (CI)​

دفع على GitHub
↓
┌─────────────────┐
│ GitHub Actions │
│ Workflow │
├─────────────────┤
│ 1. Checkout │
│ 2. Setup Java │
│ 3. Build │
│ 4. Tests │
│ 5. Analyse │
└─────────────────┘
↓
✅ أو ❌

النشر المستمر (CD)​

نجاح CI
↓
┌─────────────────┐
│ 1. Build Docker │
│ 2. Push Registry│
│ 3. Deploy │
└─────────────────┘
↓
🚀 في الإنتاج

2. أساسيات GitHub Actions​

الهيكل​

.github/
└── workflows/
├── ci.yml # اختبارات عند كل دفع
├── release.yml # نشر عند الوسوم
└── deploy.yml # نشر

الصياغة الأساسية​

name: CI Pipeline

on:
push:
branches: [main, develop]
pull_request:
branches: [main]

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'

- name: Build
run: mvn clean package

3. تدفق عمل CI كامل​

.github/workflows/ci.yml​

name: CI Pipeline

on:
push:
branches: [main, develop]
pull_request:
branches: [main]

jobs:
test:
name: Build and Test
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
cache: 'maven'

- name: Build with Maven
run: mvn clean compile

- name: Run Tests
run: mvn test

- name: Upload Test Results
uses: actions/upload-artifact@v4
if: always()
with:
name: test-results
path: target/surefire-reports/

- name: Generate Coverage Report
run: mvn jacoco:report

- name: Upload Coverage to Codecov
uses: codecov/codecov-action@v3
with:
files: target/site/jacoco/jacoco.xml

package:
name: Package Application
runs-on: ubuntu-latest
needs: test

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
cache: 'maven'

- name: Package JAR
run: mvn package -DskipTests

- name: Upload JAR
uses: actions/upload-artifact@v4
with:
name: app-jar
path: target/*.jar

4. تدفق عمل Docker​

.github/workflows/docker.yml​

name: Docker Build and Push

on:
push:
branches: [main]
tags: ['v*']

env:
REGISTRY: docker.io
IMAGE_NAME: ${{ github.repository }}

jobs:
build-and-push:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha

- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

إعداد الأسرار​

في GitHub Repository → Settings → Secrets → Actions:

DOCKERHUB_USERNAME=اسم المستخدم الخاص بك
DOCKERHUB_TOKEN=الرمز الخاص بك

5. تدفق عمل النشر​

النشر على Railway​

name: Deploy to Railway

on:
push:
branches: [main]

jobs:
deploy:
runs-on: ubuntu-latest
needs: [test, build-docker]

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Install Railway CLI
run: npm i -g @railway/cli

- name: Deploy to Railway
run: railway up
env:
RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}

النشر على Heroku​

name: Deploy to Heroku

on:
push:
branches: [main]

jobs:
deploy:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Deploy to Heroku
uses: akhileshns/heroku-deploy@v3.12.14
with:
heroku_api_key: ${{ secrets.HEROKU_API_KEY }}
heroku_app_name: ${{ secrets.HEROKU_APP_NAME }}
heroku_email: ${{ secrets.HEROKU_EMAIL }}
usedocker: true

6. تدفق عمل CI/CD كامل​

.github/workflows/main.yml​

name: CI/CD Pipeline

on:
push:
branches: [main]
pull_request:
branches: [main]

env:
REGISTRY: docker.io
IMAGE_NAME: myuser/myapp

jobs:
# ===== JOB 1: Test =====
test:
name: Test
runs-on: ubuntu-latest

services:
postgres:
image: postgres:15
env:
POSTGRES_DB: testdb
POSTGRES_USER: test
POSTGRES_PASSWORD: test
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5

steps:
- uses: actions/checkout@v4

- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
cache: 'maven'

- name: Run Tests
run: mvn test
env:
SPRING_DATASOURCE_URL: jdbc:postgresql://localhost:5432/testdb
SPRING_DATASOURCE_USERNAME: test
SPRING_DATASOURCE_PASSWORD: test

# ===== JOB 2: Build Docker =====
build:
name: Build Docker
runs-on: ubuntu-latest
needs: test
if: github.event_name == 'push'

outputs:
image-tag: ${{ steps.meta.outputs.tags }}

steps:
- uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.IMAGE_NAME }}

- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
cache-from: type=gha
cache-to: type=gha,mode=max

# ===== JOB 3: Deploy =====
deploy:
name: Deploy to Production
runs-on: ubuntu-latest
needs: build
if: github.ref == 'refs/heads/main'
environment: production

steps:
- uses: actions/checkout@v4

- name: Deploy to Railway
run: |
npm i -g @railway/cli
railway up
env:
RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}

7. أفضل الممارسات​

ذاكرة التخزين المؤقت لـ Maven​

- uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
cache: 'maven' # ← تفعيل ذاكرة التخزين المؤقت التلقائية

التوازي​

jobs:
test-unit:
runs-on: ubuntu-latest
steps: [...]

test-integration:
runs-on: ubuntu-latest
steps: [...]

build:
needs: [test-unit, test-integration] # ينتظر كلاهما
steps: [...]

البيئات المحمية​

deploy:
environment: production # يتطلب الموافقة

مصفوفة الإصدارات​

jobs:
test:
strategy:
matrix:
java: [17, 21]
os: [ubuntu-latest, windows-latest]

runs-on: ${{ matrix.os }}

steps:
- uses: actions/setup-java@v4
with:
java-version: ${{ matrix.java }}

8. ملخص​

هيكل تدفقات العمل​

.github/workflows/
├── ci.yml # اختبارات على PR و push
├── docker.yml # بناء ودفع الصورة
└── deploy.yml # نشر الإنتاج

الأسرار المطلوبة​

DOCKERHUB_USERNAME
DOCKERHUB_TOKEN
RAILWAY_TOKEN (أو HEROKU_API_KEY)

تدفق عمل بسيط​

name: CI
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
cache: 'maven'
- run: mvn test

🎯 الخطوة التالية​

جاهز خط أنابيب CI/CD! دعونا نرى خيارات النشر السحابي.

➡️ الفصل 4: النشر السحابي


⬅️ العودة إلى الوحدة 12