مقدمة

الهدف : مرافقة القارئ في إعداد مسار CI/CD بسيط لكن وظيفي لتطبيق بايثون، مع نشر تلقائي على PyPI.

أصبحت أتمتة عمليات التطوير لا غنى عنها في المشاريع الحديثة. يتيح خط أنابيب CI/CD مصمم جيدًا ليس فقط اكتشاف التراجعات مبكرًا في دورة التطوير، بل أيضًا أتمتة عملية النشر بالكامل.

في هذه المقالة، سنستكشف كيفية إعداد مسار كامل باستخدام GitHub Actions لتطبيق بايثون، من التكامل المستمر (CI) إلى النشر المستمر (CD) على PyPI.

بنية الـPipeline

يتألف خط الأنابيب الخاص بنا من سيرتي عمل مختلفتين :

  1. سلسلة CIيتم التنفيذ في كل push وpull request

  2. خط أنابيب CD: يتم تشغيله فقط في إصدارات GitHub

@startuml
!theme plain

package "GitHub مستودع" {
  [Source Code] as source
  [GitHub Actions] as actions
}

package "خط أنابيب التكامل المستمر" {
  [Checkout] as checkout_ci
  [Setup Python] as python_ci
  [Install Dependencies] as deps_ci
  [Linting (Ruff)] as lint
  [Unit Tests] as tests
}

package "خط أنابيب التسليم المستمر" {
  [Checkout] as checkout_cd
  [Setup Python] as python_cd
  [Build Package] as build
  [Publish to PyPI] as pypi
}

source --> actions : ادفع/PR
actions --> checkout_ci
checkout_ci --> python_ci
python_ci --> deps_ci
deps_ci --> lint
lint --> tests

source --> actions : إصدار
actions --> checkout_cd : عند الإصدار
checkout_cd --> python_cd
python_cd --> build
build --> pypi

@enduml

إعداد خط أنابيب التكامل المستمر (CI)

هيكل سير عمل التكامل المستمر

تم تصميم سير عمل CI لتحقق كل مساهمة في الكود. إليك إعداده الكامل :

name: CI/CD Pipeline

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest

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

    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: '3.x'

    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install -r requirements.txt
        pip install ruff pytest pytest-mock

    - name: Run Linting (Ruff)
      run: ruff check .

    - name: Run Tests (Pytest)
      run: pytest

تحليل مراحل CI

المُحفِّزات (on)

----
----
on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main
----

يُشغَّل الـpipeline عند : - كل دفع على الفرع`main` - كل طلب سحب نحو`main`

هذه المنهجية تضمن أن يظل الكود الرئيسي مستقرًا وأن يتم التحقق من أي مساهمة قبل دمجهما.

==== بيئة التنفيذ

----

runs-on: ubuntu-latest

أوبنتو لايتس يقدم توازنًا جيدًا بين الأداء، التكلفة، والتوافق لمعظم مشروعات بايثون

==== 3. سحب الكود

```yaml
----
----
- name: Checkout code
  uses: actions/checkout@v4
----

الإجراء`checkout@v4`يسترجع كود المصدر من المستودع. الإصدار v4 يجلب تحسينات في الأداء والأمان.

==== 4. التكوين بايثون

----

- name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.x'

استخدام`'3.x'`permet باستخدام التحديث التلقائي لأحدث نسخة مستقرة من بايثون 3، مما يبسط الصيانة.

==== 5. تثبيت التبعيات

```yaml
----
----
- name: Install dependencies
  run: |
    python -m pip install --upgrade pip
    pip install -r requirements.txt
    pip install ruff pytest pytest-mock
----

هذه الخطوة : - تحديث pip إلى أحدث نسخة - قم بتثبيت تبعيات المشروع - أضف أدوات التطوير (التدقيق والاختبارات)

==== 6. فحص الكود مع Ruff

----

- name: Run Linting (Ruff) run: ruff check .

**Ruff**هو مدقق Python سريع للغاية مكتوب بلغة Rust. يجمع ميزات عدة أدوات (Flake8, Black, isort) في أداة واحدة عالية الأداء.

==== 7. تنفيذ الاختبارات

```yaml
----
----
- name: Run Tests (Pytest)
  run: pytest
----

يقوم Pytest بتنفيذ مجموعة الاختبار بالكامل، مما يضمن أن التعديلات لا تسبب تراجعات.

== إعداد مسار النشر (CD)

=== هيكل سير عمل CD

يتم تشغيل سير العمل CD فقط عند الإصدارات في جيت هاب، ويؤتمت عملية النشر إلى PyPI :

[source,yaml]
----
name: Publish to PyPI

on:
  release:
    types:
      - published

jobs:
  deploy:
    runs-on: ubuntu-latest

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

    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: '3.x'

    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install setuptools wheel twine

    - name: Build and publish
      env:
        TWINE_USERNAME: __token__
        TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
      run: |
        python setup.py sdist bdist_wheel
        twine upload dist/*
----

=== تحليل المراحل CD

==== مشغل الإصدار

----

on: release: types: - published

لا يتم تشغيل خط أنابيب التسليم المستمر (CD) إلا عند نشر إصدار جيت هب. يضمن هذا النهج تحكمًا دقيقًا في عمليات النشر.

==== 2. تثبيت أدوات البناء

```yaml
----
----
pip install setuptools wheel twine
----

- **setuptools**أدوات حزم بايثون - **عجلة**: تنسيق توزيع بايثون حديث - **خيط**أداة آمنة لتحميل إلى PyPI

==== 3. تكوين المصادقة

----

env: TWINE_USERNAME: __token__ TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}

المصادقة تستخدم توكن API PyPI مخزّنًا كسِرٍّ في GitHub، وهو أكثر أمانًا من بيانات الاعتماد التقليدية.

==== 4. البناء والنشر

```yaml
----
----
run: |
  python setup.py sdist bdist_wheel
  twine upload dist/*
----

- `sdist`: أنشئ توزيعًا مصدريًا - `bdist_wheel`أنشئ عجلة (توزيع ثنائي) - `twine upload`: ينشر التوزيعات على PyPI

== إعداد حزمة بايثون

=== بنية setup.py

لكي يعمل الـpipeline، يجب أن يحتوي مشروعك على ملفًا`setup.py`:

[source,python]
----
from setuptools import setup, find_packages

with open("README.adoc", "r", encoding="utf-8") as fh:
    long_description = fh.read()

setup(
    name="playlist-downloader",
    version="1.0.0",
    author="Votre Nom",
    author_email="[email protected]",
    description="CLI tool for managing YouTube playlists",
    long_description=long_description,
    long_description_content_type="text/plain",
    url="https://github.com/cheroliv/playlist-downloader",
    packages=find_packages(),
    classifiers=[
        "Development Status :: 4 - Beta",
        "Intended Audience :: Developers",
        "License :: OSI Approved :: MIT License",
        "Operating System :: OS Independent",
        "Programming Language :: Python :: 3",
        "Programming Language :: Python :: 3.8",
        "Programming Language :: Python :: 3.9",
        "Programming Language :: Python :: 3.10",
        "Programming Language :: Python :: 3.11",
    ],
    python_requires=">=3.8",
    install_requires=[
        "typer>=0.9.0",
        "yt-dlp>=2023.1.6",
        "google-api-python-client>=2.70.0",
        "google-auth-oauthlib>=0.7.1",
        "pymonad>=2.4.0",
        "pyyaml>=6.0",
    ],
    entry_points={
        "console_scripts": [
            "playlist-downloader=cli:app",
        ],
    },
)
----

=== النقاط الأساسية لملف setup.py

1. **بيانات تعريفية**الاسم, الإصدار, المؤلف, الوصف
2. **الاعتماديات**قائمة الحزم المطلوبة
3. **نقاط الدخول**الأوامر CLI المعروضة
4. **المصنفات**: بيانات تعريفية لـ PyPI

== التأمين باستخدام أسرار GitHub

=== إعداد توكن PyPI

1. **إنشاء رمز API على PyPI** :

- قم بتسجيل الدخول إلى PyPI انتقل إلى إعدادات الحساب > رموز API - أنشئ رمزًا جديدًا مع الأذونات المناسبة

1. **إضافة السر في GitHub**:

- إعدادات المستودع > الأسرار والمتغيرات > إجراءات - أنشئ سرًا جديدًا باسم`PYPI_API_TOKEN` لصق رمز PyPI الخاص بك

[plantuml, secrets-flow, svg]
----
@startuml
!theme plain

actor Developer as dev
participant "GitHub مستودع" as repo
participant "GitHub إجراءات" as actions
participant PyPI

dev -> repo : ضبط السر PYPI_API_TOKEN
repo -> actions : تشغيل CD pipeline عند الإصدار
actions -> actions : الوصول إلى السر بأمان
actions -> PyPI : مصادقة باستخدام الرمز
PyPI -> PyPI : تحقق من الحزمة وانشرها

note over actions, PyPI
الرمز لا يُكشف أبداً في السجلات
التدوير التلقائي ممكن
end note

@enduml
----

== سير عمل النشر الكامل

=== سلسلة النشر

[plantuml, deployment-sequence, svg]
----
@startuml
!theme plain

actor Developer as dev
participant "Git محلي" as git
participant "GitHub" as github
participant "GitHub الإجراءات" as actions
participant PyPI
participant "المستخدمون النهائيون" as users

dev -> git : git tag v1.0.0
dev -> git : git push origin v1.0.0
git -> github : دفع العلامة
dev -> github : إنشاء إصدار من الوسم
github -> actions : تشغيل خط أنابيب CD
actions -> actions : كود الدفع
actions -> actions : إعداد بيئة بايثون
actions -> actions : تثبيت أدوات البناء
actions -> actions : بناء التوزيعات (sdist + wheel)
actions -> PyPI : ارفع إلى PyPI مع الرمز
PyPI -> PyPI : تحقق ونشر
users -> PyPI : pip تثبيت playlist-downloader

note over dev, github
يمكن أتمتة إنشاء الإصدارات
أو يتم إجراؤه يدويًا عبر واجهة GitHub
end note

@enduml
----

=== États du Pipeline

[plantuml, pipeline-states, svg]
----
@startuml
!theme plain

[*] --> Idle

Idle --> CI_Running : Push/PR تم الإنشاء
CI_Running --> CI_Success : كل الاختبارات ناجحة
CI_Running --> CI_Failed : Linting/Tests فشل
CI_Success --> Idle : الدمج مكتمل
CI_Failed --> Idle : أصلح وأعد المحاولة

Idle --> CD_Running : الإصدار المنشور
CD_Running --> CD_Success : تم نشر الحزمة
CD_Running --> CD_Failed : بناء/Upload خطأ
CD_Success --> Idle : الحزمة متوفرة على PyPI
CD_Failed --> Idle : إصلاح وإعادة المحاولة للإصدار

note on link #red : تندمج الكتل
note on link #green : يسمح بالنشر

@enduml
----

== الممارسات الجيدة والتحسينات

=== إدارة الإصدارات

استخدم وسوم Git دلالية :

----

git tag -a v1.2.3 -m "Release version 1.2.3" git push origin v1.2.3

=== اختبارات المصفوفة

لاختبار على عدة إصدارات بايثون:

```yaml
----
----
strategy:
  matrix:
    python-version: [3.8, 3.9, "3.10", "3.11"]
----

=== 3. ذاكرة التخزين المؤقت للاعتماديات

سرّع عمليات البناء باستخدام التخزين المؤقت:

----

- name: Cache pip dependencies uses: actions/cache@v3 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}

=== بيئات النشر

استخدم بيئات GitHub للنشر المتحكم فيه:

```yaml
----
----
jobs:
  deploy:
    environment: production
    runs-on: ubuntu-latest
----

== حالة الاستخدام والهندسة المعمارية

=== مخطط حالة الاستخدام

[plantuml, use-cases, svg]
----
@startuml
!theme plain

left to right direction

actor "مطور" as dev
actor "GitHub الإجراءات" as ga
actor "مستخدم نهائي" as user

package "CI/CD نظام" {
  usecase "تشغيل الفحص" as lint
  usecase "تنفيذ الاختبارات" as test
  usecase "بناء الحزمة" as build
  usecase "نشر إلى PyPI" as publish
  usecase "إنشاء إصدار" as release
}

dev --> lint : يدفع الكود
dev --> test : يدفع الكود
dev --> release : يُنشر إصدار
ga --> build : عند تحرير الزناد
ga --> publish : بعد بناء ناجح
user --> publish : تنزيل الحزمة

lint .> test : triggers
test .> build : on success
build .> publish : on success

@enduml
----

=== معمارية النشر

[plantuml, deployment-architecture, svg]
----
@startuml
!theme plain

cloud "GitHub" {
  [Source Repository]
  [GitHub Actions]
  [Secrets Store]
}

cloud "PyPI" {
  [Package Registry]
  [Distribution Files]
}

node "CI/CD خط أنابيب" {
  [Linting]
  [Testing]
  [Building]
  [Publishing]
}

[Source Repository] --> [GitHub Actions] : Triggers
[GitHub Actions] --> [Linting]
[Linting] --> [Testing]
[Testing] --> [Building]
[Building] --> [Publishing]
[Publishing] --> [Package Registry] : Uploads
[Secrets Store] --> [Publishing] : Provides token

note as N1
مصادقة آمنة تعتمد على الرموز
end note

[Secrets Store] .. N1

@enduml
----

== المراقبة والتصحيح

=== السجلات والرصد

يوفر GitHub Actions سجلات مفصلة لكل خطوة. للتصحيح :

1. **افحص السجلات**من كل خطوة
2. **فعّل التصحيح**مع`ACTIONS_STEP_DEBUG`
3. **استخدم القطع الأثرية**لحفظ ملفات البناء

----

- name: Upload build artifacts uses: actions/upload-artifact@v3 if: failure() with: name: build-logs path: build/

=== إشعارات

أضف إشعارات Slack أو بريد إلكتروني :

```yaml
----
----
- name: Notify on failure
  if: failure()
  uses: 8398a7/action-slack@v3
  with:
    status: ${{ job.status }}
    webhook_url: ${{ secrets.SLACK_WEBHOOK }}
----

== الاستنتاج

إعداد خط أنابيب CI/CD قوي باستخدام GitHub Actions يغير تجربة التطوير بشكل جذري. من خلال أتمتة الفحص الثابت، والاختبارات والنشر، أنت :

- **قلل الأخطاء**قيد الإنتاج - **سرّعوا الدورات**من التطوير - **حسّنوا الثقة**في إصداراتكم - **سَهّلو التعاون**في فريق

يمكن تعديل هذا pipeline ليتوافق مع مختلف أنواع مشروعات بايثون عن طريق تعديل أدوات اللينط، أطر عمل الاختبار، أو وجهات النشر.

الاستثمار الأولي في إعداد هذه العمليات يتم استرداده بسرعة بفضل توفير الوقت وتقليل الأخطاء اليدوية أثناء النشر.

== مصادر إضافية

- https://docs.github.com/en/actions[توثيق GitHub Actions] - https://packaging.python.org/[دليل تغليف بايثون] - https://docs.pytest.org/[توثيق Pytest] - https://docs.astral.sh/ruff/[توثيق Ruff] - https://twine.readthedocs.io/[توثيق تاوين]

تم الوصول إلى خط أنابيب وظيفي ! الآن لديك خط أنابيب CI/CD بسيط يسمح لك بأتمتة اختباراتك ونشر حزمة Python الخاصة بك على PyPI مباشرةً من GitHub Actions.

ومع ذلك، يظل هذا الخط الأنبوبي مقصودًا أن يكون بسيطًا. لا يغطي بعد بعض الجوانب الأساسية في سياق احترافي:

اختبارات الإصدارات المتعددة من بايثون،

تحليل الأمان التلقائي،

النشر التدريجي عبر اختبار PyPI،

مراقبة ومقاييس خط الأنابيب

أتمتة الإصدار ودمج الممارسات الجيدة الحديثة (pyproject.toml).

في الجزء التالي، سننتقل إلى المستوى الأعلى. ستتعلم تحويل هذا الخط الأساسي إلى سلسلة توزيع صناعية حقيقية، قوية وآمنة، جاهزة لمشاريع بايثون للإنتاج.
----

مقالات ذات صلة