Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 12

Automating Code Quality with Pre-Commit Hooks

Recommended resources

Merhaba! Bir önceki dersimizde, ruff aracını kullanarak PySpark ETL projemizdeki kod kalitesini artırmak için linting ve formatting kurallarını nasıl yapılandıracağımızı öğrendik. Bu kuralları manuel olarak çalıştırmak, kodumuzu belirli bir standarda getirmek için harika bir yöntem. Ancak, bu süreci her seferinde hatırlamak ve manuel olarak tetiklemek zamanla verimsiz hale gelebilir.

Bu derste, bu kalite kontrol sürecini otomatikleştireceğiz. Hedefimiz, "kirli" veya standart dışı kodun Git reposuna dahil edilmesini en başından, yani commit aşamasında engellemek.

Öğrenme Hedefimiz: git commit işlemi öncesinde ruff ile linting ve formatting kontrollerini otomatik olarak çalıştırmak için pre-commit hook'ları kurmak.

Bu, CI/CD'ye giden yolda "sola kaydırma" (shift-left) prensibinin mükemmel bir örneğidir: Hataları ve tutarsızlıkları geliştirme döngüsünün mümkün olan en erken aşamasında yakalamak.

Git Workflow Comparison: Without and With Pre-commit Hooks
Bu şema, pre-commit hook'larının Git iş akışını nasıl iyileştirdiğini gösteriyor. Solda, kalite kontrolleri olmadan yapılan standart bir commit süreci görülüyor. Sağda ise, `git commit` komutundan sonra pre-commit'in otomatik olarak kalite kontrollerini (formatlama, linting, testler) nasıl çalıştırdığını ve sadece tüm kontroller başarılı olduğunda commit işlemine izin verdiğini görüyoruz. Bu, repoya yalnızca yüksek kaliteli kodun girmesini sağlar.

Git Hooks ve pre-commit Çerçevesi Nedir?

Projenizdeki .git klasörünü hiç merak ettiniz mi? Bu klasör, versiyon geçmişinizin yanı sıra "hooks" adı verilen bir mekanizma da içerir. Git hook'ları, commit, push gibi belirli Git olayları gerçekleşmeden önce veya sonra çalışan betiklerdir (script'ler). pre-commit hook'u, bir commit mesajı yazılıp commit işlemi tamamlanmadan hemen önce çalışır.

Bu hook'ları manuel olarak yönetmek karmaşık olabilir. İşte bu noktada pre-commit Python paketi devreye giriyor. Bu araç:

  • .pre-commit-config.yaml adlı basit bir yapılandırma dosyası ile hook'ları yönetmenizi sağlar.
  • Farklı dillerde yazılmış yüzlerce hazır hook'u kolayca projenize eklemenize olanak tanır.
  • Ekipteki herkesin aynı hook'ları kullanmasını sağlayarak tutarlılığı artırır.

Bu konsepti daha iyi anlamak için kısa bir video izleyelim.

The easy way to keep your repos tidy.

mCoding kanalından bu video, Git hook'larının ne olduğunu ve pre-commit çerçevesinin bu süreci nasıl basitleştirdiğini mükemmel bir şekilde açıklıyor.

Videonun ilk 1 dakika 32 saniyesini (00:00 - 01:32) izleyin. Konuşmacının, Git'in .git/hooks dizinini nasıl kullandığını ve pre-commit aracının neden bu hook'ları yönetmek için daha pratik bir çözüm olduğunu nasıl açıkladığına dikkat edin.


Projemize pre-commit Kurulumu

Şimdi bu güçlü otomasyon aracını projemize entegre edelim.

1. Kurulum

Öncelikle, pre-commit paketini Python ortamımıza kuralım. Projenizin ana dizinindeki terminalde şu komutu çalıştırın:

pip install pre-commit

2. Yapılandırma Dosyası Oluşturma

pre-commit, yapılandırmasını projenizin ana dizinindeki .pre-commit-config.yaml dosyasından okur. Bu dosyayı şimdi oluşturun ve içine aşağıdaki temel yapıyı ekleyin.




# .pre-commit-config.yaml

repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.6.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml
      - id: check-added-large-files

  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.4.4
    hooks:
      - id: ruff
        args: [--fix, --exit-non-zero-on-fix]
      - id: ruff-format

Bu yapılandırma ne anlama geliyor?

  • repos: Hook'ları içeren Git repolarının bir listesidir.
  • repo: Hook'un bulunduğu GitHub reposunun URL'si.
  • rev: Kullanılacak reponun spesifik bir etiketi (versiyonu). Bu, hook'ların zamanla beklenmedik şekilde değişmesini engeller.
  • hooks: Bu repodan kullanmak istediğimiz hook'ların listesi.
    • id: Hook'un benzersiz kimliği.
    • args: Hook çalıştırılırken kullanılacak komut satırı argümanları. ruff için --fix argümanı, bulunabilen hataları otomatik olarak düzeltmesini söyler. exit-non-zero-on-fix ise bir dosya düzeltildiğinde commit işlemini durdurur, böylece düzeltilmiş halini kontrol edip yeniden git add yapabilirsiniz.

Bu örnekte iki repo tanımladık:

  1. pre-commit-hooks: Dosya sonu boşlukları, YAML sözdizimi doğruluğu gibi genel dosya temizliği görevleri için standart hook'lar içerir.
  2. ruff-pre-commit: Önceki derste yapılandırdığımız ruff linter'ını ve formatlayıcısını çalıştıran resmi hook'ları içerir.

Bu yapılandırma sürecini adım adım görmek için aşağıdaki kaynağı inceleyebilirsiniz.

Top pre-commit hooks for Data / ML / Analytics projects

Bu Medium makalesi, veri projeleri için popüler pre-commit hook'larını listelerken, ruff için yapılandırmayı net bir şekilde gösteriyor.

Makalenin 'pre-commit configuration' bölümündeki YAML örneğini ve hemen altındaki 'Python lint + format — Ruff' başlığını inceleyin. ruff-pre-commit reposunun nasıl eklendiğine ve amacının ne olduğuna odaklanın.

3. Git Hook'unu Yükleme

Yapılandırma dosyamız hazır. Şimdi pre-commit'e bu yapılandırmayı kullanarak asıl Git hook betiğini oluşturmasını söylemeliyiz. Bu işlemi projenizde yalnızca bir kez yapmanız yeterlidir:

pre-commit install

Bu komut, .git/hooks/pre-commit yolunda bir betik oluşturur. Artık git commit komutunu her çalıştırdığınızda, bu betik otomatik olarak .pre-commit-config.yaml dosyanızdaki hook'ları çalıştıracaktır.


pre-commit'i İş Başında Görelim

Teoriyi pratiğe dökme zamanı!

Uygulama Adımları:

  1. Projenizdeki herhangi bir Python dosyasına (örneğin, transformations.py) gidin ve kasıtlı olarak bir stil hatası yapın. Örneğin, bir fonksiyonun başına kullanılmayan bir import ekleyin veya formatlamayı bozun.
    import os  # Kullanılmayan import
    
    def my_function ( a, b ) : # Kötü formatlama
        return a+b
    
  2. Bu değişikliği Git'e ekleyin ve commit etmeye çalışın:
    git add .
    git commit -m "Test: pre-commit ile hatalı kod"
    
  3. Terminal çıktısını izleyin. pre-commit'in devreye girdiğini ve tanımladığınız hook'ları sırayla çalıştırdığını göreceksiniz.
Pre-commit Hook Execution Output
`git commit` çalıştırıldığında terminalde göreceğiniz çıktı buna benzer olacaktır. `pre-commit`, her bir hook'u çalıştırır ve sonucunu (Passed, Failed, Skipped) gösterir. Bir hook başarısız olursa (Failed), genellikle hangi dosyayı neden düzelttiğini belirtir ve commit işlemini durdurur.

ruff hook'u, yaptığınız hataları (kullanılmayan import, kötü formatlama) tespit edecek ve --fix argümanı sayesinde bunları otomatik olarak düzeltecektir. Ancak, dosyalar değiştirildiği için commit işlemi başarısız olacaktır. Çıktıda "files were modified by this hook" gibi bir mesaj görmelisiniz.

  1. Bu çok önemlidir: pre-commit dosyalarınızı düzeltti, ancak bu düzeltilmiş halleri henüz "staged" (hazırlık aşamasında) değil. git status komutunu çalıştırırsanız, ruff tarafından değiştirilen dosyaları göreceksiniz.
  2. Düzeltilmiş dosyaları tekrar git add komutuyla hazırlık alanına ekleyin ve commit işlemini tekrarlayın:
    git add .
    git commit -m "Test: pre-commit ile hatalı kod"
    
  3. Bu sefer, hook'lar tekrar çalışacak, ancak düzeltilecek bir sorun bulamadıkları için hepsi "Passed" durumunda olacak ve commit işleminiz başarıyla tamamlanacaktır.

Bu döngüyü (commit -> fail -> re-add -> re-commit) gösteren videoyu izleyerek süreci pekiştirelim.

The easy way to keep your repos tidy.

mCoding'in videosundaki bu bölüm, bir commit'in pre-commit tarafından nasıl engellendiğini ve düzeltmelerden sonra nasıl başarıyla tamamlandığını canlı olarak gösteriyor.

Videonun 2:37 - 3:47 arasındaki bölümünü izleyin. Konuşmacının hatalı kodu commit etmeye çalıştığında commit'in nasıl başarısız olduğuna, formatlayıcının dosyayı nasıl düzelttiğine ve dosyayı tekrar ekledikten sonra commit'in nasıl başarılı olduğuna dikkat edin.


Hook'ları Manuel Çalıştırma

Bazen tüm projedeki dosyaları commit yapmadan kontrol etmek isteyebilirsiniz. Bunun için şu komutu kullanabilirsiniz:

pre-commit run --all-files

Bu komut, yapılandırmanızdaki tüm hook'ları projenizdeki ilgili tüm dosyalara karşı çalıştırır.


Sonuç

Tebrikler! Artık projenizin kod kalitesini otomatik olarak güvence altına alan bir sisteminiz var. pre-commit hook'ları sayesinde, tutarsız formatlama veya basit linting hataları gibi sorunlar, kod tabanınıza hiç girmeden engellenir. Bu, özellikle ekip olarak çalışırken veya sizin gibi kurumsal ölçekte sürdürülebilir veri işlem hatları geliştirirken paha biçilmez bir pratiktir.

Temel Çıkarımlar:

  • pre-commit, Git commit döngüsüne otomatik kalite kontrolleri ekleyen bir çerçevedir.
  • Yapılandırma, projenin kök dizinindeki .pre-commit-config.yaml dosyası ile yönetilir.
  • pre-commit install komutu, hook'ları yerel Git reponuz için etkinleştirir.
  • Bir hook dosyayı değiştirirse, commit başarısız olur. Düzeltilmiş dosyaları git add ile tekrar ekleyip yeniden commit etmeniz gerekir.
  • Bu otomasyon, kod kalitesini artırır ve kod incelemelerinde stil tartışmalarını azaltır.

Gelecek Dersin Önizlemesi:
Yerel ortamımızdaki kalite kontrollerini otomatikleştirdik. Peki ya bu kod, ana repoya gönderildiğinde ne olacak? Ekipteki başka birinin bu kontrolleri atlamadığından nasıl emin olabiliriz? Bir sonraki modülde, bulutta çalışan ve kod her itildiğinde (push) veya birleştirme isteği (pull request) açıldığında otomatik olarak tetiklenen bir Sürekli Entegrasyon (Continuous Integration - CI) işlem hattı kurmaya başlayacağız. İlk adımımız, bu CI iş akışlarını tanımlamak için GitHub Actions'ın temel bileşenlerini öğrenmek olacak.