Pengenalan

Tujuan : Membimbing pembaca dalam menyiapkan pipeline CI/CD minimalis namun fungsional untuk aplikasi Python, dengan deployment otomatis ke PyPI.

Otomatisasi proses pengembangan telah menjadi tidak terelakkan dalam proyek-proyek modern. Sebuah pipeline CI/CD yang dirancang dengan baik tidak hanya memungkinkan deteksi regresi lebih awal dalam siklus pengembangan, tetapi juga mengotomatisasi seluruh proses penyebaran.

Dalam artikel ini, kita akan menjelajahi cara menyiapkan pipeline lengkap dengan GitHub Actions untuk aplikasi Python, dari integrasi berkelanjutan (CI) hingga deploy berkelanjutan (CD) ke PyPI.

Arsitektur Pipeline

Pipeline kami terdiri dari dua alur kerja yang berbeda:

  1. Alur CI: Dieksekusi pada setiap push dan pull request

  2. Pipeline CDDemicu hanya selama rilis GitHub

@startuml
!theme plain

package "GitHub Repositori" {
  [Source Code] as source
  [GitHub Actions] as actions
}

package "Alur CI" {
  [Checkout] as checkout_ci
  [Setup Python] as python_ci
  [Install Dependencies] as deps_ci
  [Linting (Ruff)] as lint
  [Unit Tests] as tests
}

package "CD Pipeline" {
  [Checkout] as checkout_cd
  [Setup Python] as python_cd
  [Build Package] as build
  [Publish to PyPI] as pypi
}

source --> actions : Push/PR
actions --> checkout_ci
checkout_ci --> python_ci
python_ci --> deps_ci
deps_ci --> lint
lint --> tests

source --> actions : Release
actions --> checkout_cd : On Release
checkout_cd --> python_cd
python_cd --> build
build --> pypi

@enduml

Konfigurasi Pipeline Integrasi Berkelanjutan (CI)

Struktur alur kerja CI

Alur kerja CI dirancang untuk memvalidasi setiap kontribusi ke kode. Berikut konfigurasi lengkapnya :

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

Analisis Langkah CI

1. Pemicu (on)

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

Pipeline dipicu pada : - Setiap push ke cabang`main` - Setiap pull request menuju`main`

Pendekatan ini memastikan bahwa kode utama tetap stabil dan bahwa semua kontribusi divalidasi sebelum integrasi.

==== 2. Lingkungan Eksekusi

----

runs-on: ubuntu-latest

Ubuntu Latest menawarkan kompromi yang baik antara performa, biaya, dan kompatibilitas untuk sebagian besar proyek Python.

==== 3. Checkout Kode

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

tindakan
</think>
tindakan`checkout@v4`Mengambil kode sumber dari repositori. Versi v4 memberikan peningkatan performa dan keamanan.

==== 4. Konfigurasi Python

----

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

penggunaan`'3.x'`memungkinkan penggunaan otomatis versi stabil terbaru dari Python 3, memudahkan pemeliharaan.

==== 5. Instalasi Dependensi

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

Tahap ini : - Memperbarui pip ke versi terbaru - Instal dependensi proyek - Tambahkan alat pengembangan (linting dan ujian)

==== 6. Linting dengan Ruff

----

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

**Ruff**adalah linter Python yang sangat cepat yang ditulis dalam Rust. Dia menggabungkan fitur dari beberapa alat (Flake8, Black, isort) menjadi satu alat yang kuat.

==== 7. Pelaksanaan Tes

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

Pytest menjalankan seluruh suite tes, memastikan bahwa perubahan tidak memperkenalkan regresi.

== Konfigurasi Pipeline Penerapan (CD)

=== Struktur Workflow CD

Workflow CD hanya terpicu selama rilis GitHub dan mengotomatiskan publikasi ke 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/*
----

=== Analisis Tahap CD

==== 1. Pemicu Pelepasan

----

on: release: types: - published

Pipeline CD hanya dipicu saat mempublikasikan rilis GitHub. Pendekatan ini memastikan kontrol yang tepat atas penerapan.

==== 2. Instalasi Alat Pembangunan

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

- **setuptools**: Alat packaging Python - **roda**: Format distribusi Python modern - **benang**: Alat aman untuk mengunggah ke PyPI

==== 3. Konfigurasi Otentikasi

----

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

Autentikasi menggunakan token API PyPI yang disimpan sebagai rahasia GitHub, lebih aman daripada kredensial konvensional.

==== 4. Build dan publikasi

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

- `sdist`: Buat distribusi sumber - `bdist_wheel`: Membuat sebuah wheel (distribusi biner) - `twine upload`Mempublikasikan distribusi pada PyPI

== Konfigurasi Paket Python

=== Struktur setup.py

Agar pipeline berfungsi, proyek Anda harus menyertakan sebuah file`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",
        ],
    },
)
----

=== poin-poin kunci setup.py

1. **metadata**: Nama, versi, penulis, deskripsi
2. **Ketergantungan**: Daftar packages yang diperlukan
3. **Titik Masuk**: Perintah CLI yang diekspos
4. **klasifikasi**: metadata untuk PyPI

== Keamanan dengan GitHub Secrets

=== Konfigurasi Token PyPI

1. **Membuat token API di PyPI**:

- Masuk ke PyPI Buka Pengaturan Akun > API tokens - Buat token baru dengan izin yang sesuai

1. **Tambahkan rahasia di GitHub**:

- Pengaturan Repositori > Rahasia dan variabel > Tindakan - Buat rahasia baru yang dinamai`PYPI_API_TOKEN` - Tempelkan token PyPI Anda

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

actor Developer as dev
participant "Repositori GitHub" as repo
participant "GitHub Actions" as actions
participant PyPI

dev -> repo : Configure PYPI_API_TOKEN secret
repo -> actions : Trigger CD pipeline on release
actions -> actions : Access secret securely
actions -> PyPI : Authenticate with token
PyPI -> PyPI : Validate and publish package

note over actions, PyPI
  Token never exposed in logs
  Automatic rotation possible
end note

@enduml
----

== Workflow Deployment Lengkap

=== Urutan Penyebaran

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

actor Developer as dev
participant "Git lokal" as git
participant "GitHub" as github
participant "GitHub Tindakan" as actions
participant PyPI
participant "Pengguna akhir" as users

dev -> git : git tag v1.0.0
dev -> git : git push origin v1.0.0
git -> github : Push tag
dev -> github : Create release from tag
github -> actions : Trigger CD pipeline
actions -> actions : Checkout code
actions -> actions : Setup Python environment
actions -> actions : Install build tools
actions -> actions : Build distributions (sdist + wheel)
actions -> PyPI : Upload to PyPI with token
PyPI -> PyPI : Validate and publish
users -> PyPI : pip install playlist-downloader

note over dev, github
  Release creation can be automated
  or done manually through GitHub UI
end note

@enduml
----

=== Status Pipeline

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

[*] --> Idle

Idle --> CI_Running : Push/PR created
CI_Running --> CI_Success : All checks pass
CI_Running --> CI_Failed : Linting/Tests fail
CI_Success --> Idle : Merge completed
CI_Failed --> Idle : Fix and retry

Idle --> CD_Running : Release published
CD_Running --> CD_Success : Package published
CD_Running --> CD_Failed : Build/Upload error
CD_Success --> Idle : Package available on PyPI
CD_Failed --> Idle : Fix and retry release

note on link #red : Blocks merge
note on link #green : Allows deployment

@enduml
----

== Praktik Baik dan Optimasi

=== Manajemen Versi

Gunakan tag Git semantik :

----

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

=== 2. Uji Matriks

Untuk menguji pada beberapa versi Python:

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

=== 3. Cache Dependensi

Percepat build dengan cache :

----

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

=== 4. lingkungan penerapan

Gunakan lingkungan GitHub untuk penerapan yang terkontrol :

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

== Kasus Penggunaan dan Arsitektur

=== Diagram Kasus Penggunaan

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

left to right direction

actor "Pengembang" as dev
actor "GitHub Actions" as ga
actor "Pengguna akhir" as user

package "Sistem CI/CD" {
  usecase "Jalankan Linting" as lint
  usecase "Menjalankan tes" as test
  usecase "Membangun Paket" as build
  usecase "Terbitkan ke PyPI" as publish
  usecase "Buat Rilis" as release
}

dev --> lint : Pushes code
dev --> test : Pushes code
dev --> release : Creates release
ga --> build : On release trigger
ga --> publish : After successful build
user --> publish : Downloads package

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

@enduml
----

=== Arsitektur Penyebaran

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

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

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

node "Alur 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
  Secure token-based
  authentication
end note

[Secrets Store] .. N1

@enduml
----

== Pengawasan dan Debugging

=== Log dan Pemantauan

GitHub Actions memberikan log terperinci untuk setiap langkah. Untuk debug:

1. **Periksa log**setiap step
2. **Aktifkan debug**dengan`ACTIONS_STEP_DEBUG`
3. **Gunakan artefak**untuk menyimpan file build

----

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

=== Notifikasi

Tambahkan notifikasi Slack atau email :

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

== Kesimpulan

Penerapan pipeline CI/CD yang kuat dengan GitHub Actions secara radikal mengubah pengalaman pengembangan. Dengan mengotomatisasi linting, pengujian, dan penyebaran, Anda :

- **Kurangi kesalahan**dalam produksi - **Percepat siklus**pengembangan - **Tingkatkan kepercayaan**dalam rilis Anda - **Mudahkan kolaborasi**dalam tim

Pipeline ini dapat disesuaikan dengan berbagai jenis proyek Python dengan menyesuaikan alat linting, kerangka kerja pengujian, atau destinasi penerapan.

Investasi awal dalam konfigurasi workflow-nya segera menguntungkan melalui penghematan waktu dan penurunan kesalahan manual selama penerapan.

== Sumber Daya Tambahan

- https://docs.github.com/en/actions[Dokumentasi GitHub Actions] - https://packaging.python.org/[Panduan Pengemasan Python] - https://docs.pytest.org/[Dokumentasi Pytest] - https://docs.astral.sh/ruff/[Dokumentasi Ruff] - https://twine.readthedocs.io/[Dokumentasi Twine]

✅ Pipeline fungsional tercapai! Anda kini memiliki pipeline CI/CD sederhana yang memungkinkan Anda mengotomatiskan pengujian dan menerbitkan paket Python Anda ke PyPI langsung dari GitHub Actions.

Namun, pipeline ini tetap sengaja minimalis. Ia belum mencakup beberapa aspek penting dalam konteks profesional :

Uji multi-versi Python,

Analisis keamanan otomatis,

Penyebaran bertahap melalui Test PyPI,

Pemantauan dan metrik pipeline,

Otomatisasi versioning dan integrasi praktik terbaik modern (pyproject.toml).

Di bagian berikutnya, kita akan melangkah ke tingkat yang lebih tinggi. Anda akan belajar mengubah pipeline dasar ini menjadi benar-benar rangkaian penyebaran industri, kuat dan aman, siap untuk proyek-produksi Python.
----

Artikel terkait