Workflow GitHub Actions untuk lint, test, dan release Python membantu tim menjaga kualitas kode sekaligus mengurangi pekerjaan manual saat merge dan rilis. Untuk proyek Python, pipeline yang baik biasanya memisahkan validasi cepat seperti lint dan format check dari proses yang lebih berat seperti test matrix dan publish artifact.
Artikel ini menunjukkan pendekatan praktis untuk membangun pipeline yang realistis: cache dependency, lint dengan ruff atau flake8, pemeriksaan format, unit test dengan pytest, matrix versi Python bila diperlukan, penyimpanan artifact, dan release berbasis tag. Sebagai konteks, pendekatan ini relevan untuk repositori tool Python di GitHub seperti repo referensi Codex-5.5-codex-instruct-5.5, tanpa mengasumsikan detail internal repo yang belum jelas.
Tujuan pipeline: cepat gagal, mudah dibaca, dan aman dirilis
Pipeline CI/CD yang efektif untuk Python sebaiknya menjawab tiga kebutuhan:
- Feedback cepat untuk developer: pull request harus segera menunjukkan error lint, format, atau test yang gagal.
- Reproducible build: dependency dan langkah build konsisten di setiap run.
- Release yang terkontrol: hanya tag yang valid yang memicu proses rilis atau publish.
Dalam praktiknya, Anda tidak perlu langsung membuat workflow yang kompleks. Untuk tim kecil, struktur paling masuk akal biasanya terdiri dari:
- CI workflow untuk lint, format check, dan test pada push atau pull_request.
- Release workflow yang berjalan saat tag dibuat, lalu membangun artifact dan membuat release.
Pemisahan ini membuat debugging lebih mudah. Jika release gagal, Anda tidak perlu menelusuri semua langkah CI harian. Sebaliknya, jika test gagal di pull request, proses rilis tidak ikut tercampur.
Struktur dasar workflow GitHub Actions untuk Python
Berikut struktur minimal yang umum dipakai:
- Trigger:
push,pull_request, danpush.tags. - Setup Python: menggunakan
actions/setup-python. - Dependency cache: mempercepat instalasi package.
- Lint:
ruff checkatauflake8. - Format check: misalnya
ruff format --checkataublack --check. - Test:
pytest. - Artifact: menyimpan hasil build seperti wheel atau sdist.
- Release: membuat GitHub Release berbasis tag.
Jika proyek Anda adalah library atau CLI Python, artifact seperti .whl dan .tar.gz layak dibangun saat release. Jika proyek lebih ke aplikasi internal, artifact bisa berupa log test, coverage report, atau bundle deploy.
Contoh workflow CI minimal yang realistis
Contoh berikut memecah job lint dan test agar sinyal kegagalan lebih jelas. Workflow ini juga memakai cache dependency dan matrix Python untuk memastikan kompatibilitas lintas versi.
name: ci
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: 'pip'
cache-dependency-path: |
requirements.txt
requirements-dev.txt
pyproject.toml
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt -r requirements-dev.txt
- name: Ruff lint
run: ruff check .
- name: Format check
run: ruff format --check .
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ['3.10', '3.11']
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
cache-dependency-path: |
requirements.txt
requirements-dev.txt
pyproject.toml
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt -r requirements-dev.txt
- name: Run tests
run: pytest -qMengapa dipisah antara lint dan test?
Pemisahan job memberi beberapa keuntungan:
- Diagnostik lebih jelas: error style tidak bercampur dengan error runtime.
- Paralelisme: lint dan test bisa berjalan bersamaan.
- Perluasan lebih mudah: coverage, integration test, atau build bisa ditambahkan tanpa membuat satu job terlalu panjang.
Untuk proyek kecil, semua langkah memang bisa digabung dalam satu job. Namun, begitu tim mulai aktif membuka pull request, pemisahan job biasanya lebih nyaman.
Kenapa menggunakan cache dependency?
Instalasi dependency adalah salah satu bagian paling sering menghabiskan waktu pada CI Python. Dengan actions/setup-python dan opsi cache pip, runner akan menyimpan package berdasarkan file dependency. Hasilnya, run berikutnya lebih cepat selama dependency tidak berubah.
Perlu diperhatikan:
- Cache tidak menggantikan file lock atau pinning versi.
- Jika dependency berubah tetapi file yang dijadikan key tidak ikut berubah, cache bisa terasa “aneh” atau tidak akurat.
- Pastikan
cache-dependency-pathmencakup file yang benar-benar menjadi sumber dependency Anda.
Memilih tool lint dan format: ruff vs flake8
Untuk pipeline modern, ruff sering menjadi pilihan praktis karena cepat dan bisa menangani lint sekaligus format check. Namun flake8 masih relevan jika proyek lama Anda sudah bergantung pada plugin tertentu.
Kapan memilih ruff?
- Ingin setup lebih ringkas.
- Performa lint menjadi prioritas.
- Ingin satu tool untuk lint dan format check.
Kapan mempertahankan flake8?
- Proyek sudah stabil dengan ekosistem plugin flake8 tertentu.
- Tim belum siap migrasi rule lint.
- Konfigurasi existing sudah menjadi standar internal.
Jika memakai flake8, langkah lint bisa diganti menjadi:
- name: Flake8 lint
run: flake8 .Sedangkan format check dapat memakai tool terpisah seperti black --check .. Trade-off-nya: lebih banyak tool berarti lebih banyak konfigurasi, tetapi kadang migrasi bertahap menjadi lebih aman untuk tim.
Menambahkan build artifact dan release berbasis tag
Release berbasis tag cocok jika Anda ingin memastikan hanya versi yang disengaja yang menghasilkan artifact final. Pola umum:
- Developer atau maintainer membuat tag, misalnya
v0.3.0. - Workflow release berjalan.
- Pipeline membangun package Python.
- Artifact diunggah.
- GitHub Release dibuat dari tag tersebut.
Contoh workflow release minimal:
name: release
on:
push:
tags:
- 'v*'
jobs:
build-and-release:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: 'pip'
cache-dependency-path: |
requirements.txt
requirements-dev.txt
pyproject.toml
- name: Install build tools
run: |
python -m pip install --upgrade pip
pip install build
- name: Build package
run: python -m build
- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: python-dist
path: dist/
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
files: dist/*Mengapa artifact tetap diunggah meski file sudah masuk ke release?
Artifact dan release asset punya tujuan berbeda:
- Artifact CI berguna untuk inspeksi internal, debugging build, atau konsumsi langkah berikutnya dalam workflow.
- Release asset ditujukan untuk distribusi ke pengguna dari halaman GitHub Release.
Menyimpan keduanya membantu ketika Anda ingin memeriksa output build walau release step gagal atau perlu audit ulang hasil build.
Jika ingin publish ke package registry
Jika nanti Anda ingin publish ke indeks package seperti PyPI, tambahkan job terpisah setelah build sukses. Sebaiknya jangan langsung mencampur publish registry dengan pembuatan release GitHub pada iterasi pertama. Pisahkan dulu agar jalur kegagalan lebih mudah dipahami, terutama untuk tim kecil.
Strategi fail-fast yang masuk akal
Fail-fast berarti pipeline berhenti secepat mungkin saat syarat dasar gagal. Tujuannya menghemat waktu runner dan mempercepat feedback. Namun ada nuance penting.
Kapan fail-fast sebaiknya aktif?
- Pada langkah berurutan dalam satu job, misalnya jika install dependency gagal maka test memang tidak perlu jalan.
- Pada lint atau format check yang menjadi gate wajib sebelum merge.
Kapan fail-fast matrix sebaiknya dimatikan?
Pada strategy.matrix, menggunakan fail-fast: false sering lebih berguna. Alasannya, jika Python 3.10 gagal tetapi 3.11 juga punya masalah berbeda, Anda ingin melihat semua hasil sekaligus. Ini mengurangi siklus commit-perbaikan yang berulang.
Untuk tim kecil, kombinasi yang sering efektif adalah:
- Lint: wajib lulus dan cepat.
- Test matrix:
fail-fast: falseagar semua versi tetap dilaporkan. - Release: hanya jalan setelah tag, dan sebaiknya bergantung pada branch yang sudah terlindungi.
Proteksi branch dan aturan merge
Workflow yang bagus akan jauh lebih efektif jika didukung aturan repository.
Rekomendasi branch protection
- Wajib pull request untuk merge ke
main. - Wajib status check CI lulus.
- Batasi siapa yang boleh mendorong langsung ke branch utama.
- Opsional: wajib review minimal satu orang.
Tanpa branch protection, pipeline hanya menjadi alat observasi, bukan alat pengendali kualitas. Seseorang tetap bisa mendorong kode rusak langsung ke branch utama.
Prinsip praktis: jika release diambil dari tag pada commit di
main, maka kualitas release sangat bergantung pada kualitas gate menujumain.
Secret handling yang aman
Workflow release kadang membutuhkan secret, misalnya token registry atau kredensial signing. Beberapa aturan dasar yang sebaiknya diikuti:
- Jangan hardcode secret di YAML.
- Simpan secret di GitHub Actions Secrets atau gunakan environment dengan approval jika proses rilis sensitif.
- Berikan permission minimum yang diperlukan.
- Hindari mencetak variabel sensitif ke log.
Untuk release GitHub sederhana, GITHUB_TOKEN bawaan biasanya cukup jika permission contents: write diatur sesuai kebutuhan. Untuk publish ke layanan eksternal, gunakan secret terpisah dan batasi hanya pada workflow release.
Kesalahan umum terkait secret
- Menggunakan satu token dengan cakupan terlalu luas untuk semua workflow.
- Menjalankan workflow release pada event yang terlalu terbuka.
- Tidak membatasi siapa yang bisa membuat tag rilis.
Jika tim Anda kecil, pengamanan minimal yang efektif adalah: tag rilis hanya dibuat maintainer, branch utama diproteksi, dan secret publish hanya tersedia pada workflow release.
Debugging masalah umum di GitHub Actions Python
1. Cache tidak terasa mempercepat
Biasanya penyebabnya adalah file dependency tidak konsisten atau cache key tidak mewakili dependency yang sebenarnya. Pastikan file seperti requirements-dev.txt atau pyproject.toml ikut dicantumkan.
2. Lint lulus lokal tetapi gagal di CI
Sering terjadi karena versi tool lokal berbeda dari CI. Solusinya, pin dependency dev secara lebih konsisten dan dokumentasikan cara menjalankan tool yang sama secara lokal.
3. Test gagal hanya pada satu versi Python
Ini justru nilai utama matrix testing. Periksa dependency conditional, syntax yang tidak kompatibel, atau asumsi perilaku library yang berubah antar versi.
4. Release terpicu pada tag yang tidak semestinya
Gunakan pola tag yang jelas, misalnya v*, dan batasi kebiasaan membuat tag sembarangan. Untuk kebutuhan lebih ketat, Anda dapat menambahkan validasi nama tag sebelum build.
5. Workflow terlalu lambat
Kurangi pekerjaan yang tidak perlu pada pull request. Misalnya:
- Jalankan lint di satu versi Python saja.
- Batasi integration test berat ke branch utama atau workflow terjadwal.
- Pisahkan release build dari CI harian.
Checklist adopsi bertahap untuk tim kecil
Jika tim Anda belum punya pipeline yang matang, jangan langsung mengejar semua fitur. Gunakan urutan adopsi berikut:
- Tahap 1: tambahkan workflow CI dengan lint dan pytest pada
pull_request. - Tahap 2: aktifkan cache dependency dan format check.
- Tahap 3: tambahkan matrix Python bila proyek memang mendukung lebih dari satu versi.
- Tahap 4: aktifkan branch protection dan wajibkan status check.
- Tahap 5: tambahkan build artifact pada branch utama atau saat tag.
- Tahap 6: buat workflow release berbasis tag.
- Tahap 7: jika perlu, pisahkan publish ke registry dengan secret yang lebih ketat.
Urutan ini penting untuk menjaga developer experience. Pipeline yang terlalu rumit di awal justru sering di-bypass karena dianggap lambat atau sulit dipahami.
Penutup
Workflow GitHub Actions untuk proyek Python tidak harus rumit agar berguna. Mulailah dari lint, format check, dan unit test yang cepat, lalu tambahkan matrix, artifact, dan release berbasis tag ketika proses tim mulai stabil.
Untuk proyek tool Python di GitHub, termasuk yang konteksnya mirip repo referensi Codex-5.5-codex-instruct-5.5, desain pipeline yang baik adalah yang mudah dirawat, cepat memberi feedback, dan aman saat rilis. Jika tiga hal itu tercapai, CI/CD benar-benar membantu tim, bukan menambah beban operasional.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!