Pythontr

husonet | Tarih: 26.03.2020

Git Hooks Nedir? - Otomatik Kod Kalite Kontrolleri

Git Hooks nedir uygulayarak öğrenelim ve daha kaliteli kodlama yapılması için ortam hazırlayalım.

Git hooks, Git'in "commit, push, receive" gibi komut kullanımlarının öncesinde ve sonrasında tetiklenmesini sağlayan kabuk "shell, bash" dosyalarıdır. Git hooks standart Git yüklemesi ile gelen yerleşik bir özelliktir, ayrıca indirilmesine ve kurulmasına gerek yoktur. Git hooks, local olarak çalıştırılır.


Git hooks, geliştiricinin hayal gücüne bağlı olarak kullanılabilir.


Bazı tetikleyiciler "triggers";
  • pre-commit: Yazılımla ilgili hataları kontrol edebiliriz.
  • pre-receive: Benzer hata ile ilgili yada yazılım standartlarıyla ilgili kontroller yapılabilir.
  • pre-push: Push'lamadan önceki süreç için kontrol oluşturulabilir.
  • post-commit: Takım üyelerine bildirimler gönderilebilir. E-Posta gibi
  • post-receive: Prod'a gönderirken gereken konular gibi

Git hooks nasıl çalışır?


Her deponun kendine ait bir .git/hooks klasörü ve içinde her hooks için bir dosyası bulunur.


Otomatik Kod Kalite Kontrolleri


Konun daha iyi anlaşılması için aşağıda yazdığımız kodları git üzerinde commit yapmadan kontrol eden bir script yazacağız. Python programlama dili ile geliştirdiğimiz https://github.com/huseyinozdemir/pythontr_api deposu için bu yapıyı uygulayabiliriz.


Senaryomda yapmak istediğim commitlemeden yada pushlamadan önce git tarafından yazdığım unit testleri çalıştırılsın ve ardından flake8 için uygunluğu kontrol edilsin ve ben bu projeyi docker-compose kullandığım için yapıma uygun bir şekilde çalışsın.


Önümüzde belirlediğim iki seçenek var bunlar;
  • pre-commit, commit'i önleyebilir verdiği commit mesajını değiştirebilir.
  • pre-push, uzak sunucuya gönderilmesini önleyebilir.

Benim tercihim pre-commit şimdi bunun üzerinde senaryomuzu uygulamamıza uygulayalım. .git klasörünün bulunduğu dizininde olduğumuzu varsayıyorum.


mkdir scripts
vim scripts/run-django-tests.sh

#!/usr/bin/env bash

# kod icerisinde herhangi bir dosya hata dondururse cık ve olusan hatayi döndur
set -e

# hangi dizinde olursak olalım uygulamamızın kok dizini uzerinden calismasi icin
cd "${0%/*}/.."

echo "Running unit test and flake 8 for Django Framework on Docker Container"
echo "............................"
docker-compose run --rm app sh -c "python manage.py test && flake8"

Yukarıdaki kod satırlarında açıklamalara yer vermeye çalıştım bu kodumuz bizim unit test imizi ve flake8 çalıştırır ardından yazılım çıktısını verir ayrıca uygulama sonlandığı zaman bunun flag değerini döndürecektir.


Farklı diller için ve docker kullanmıyor iseniz aşağıdaki kullanımlara bakabilirsiniz.


  • eslint . # JS kod kalite kontrolü
  • npm test # JS unit tests
  • flake8 . # python kod kalite kontrolü
  • Django python manage.py test && flake8
  • nosetests # python nose

vim scripts/pre-commit.sh


#!/usr/bin/env bash

echo "Running pre-commit hook"
./scripts/run-django-tests.sh

# $? son komut sonlanma degerini saklar
if [ $? -ne 0 ]; then
echo "Unit Tests or Flake8 must pass before commit!"
exit 1
fi

Bu betik dosyamız ise bir önceki yazdığımız kontrol dosyasını tetikler sonlanma değerine göre süreci devam ettirir yada sonlandırır.


vim scripts/install-hooks.sh

#!/usr/bin/env bash

GIT_DIR=$(git rev-parse --git-dir)

echo "Installing hooks..."
ln -s ../../scripts/pre-commit.sh $GIT_DIR/hooks/pre-commit
echo "Done!"

Install işleminde aslında yaptığımız iş path verme symblink link oluşturma işlemidir.


Yazdığımız dosyaları çalıştırabilir hale getirmek için gerekli izinlerimizi verelim.


chmod +x scripts/run-django-tests.sh scripts/pre-commit.sh scripts/install-hooks.sh

Ardından aşağıdaki şekilde install betik dosyamızı çalıştıralım.


./scripts/install-hooks.sh
Installing hooks...
Done!

Evet şimdi testlerimizi yapalım örnek olarak yazdığım ünit testlerden birinde değişiklik yapıyorum bakalım sonuç ne olacak.


git add .
git commit -m "test"
Running pre-commit hook
Running unit test and flake 8 for Django Framework on Docker Container
............................
Starting pythontr_api_db_1 ... done
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
.........Waiting for database...
Database unavailable, waiting 1 second...
Database unavailable, waiting 1 second...
Database unavailable, waiting 1 second...
Database unavailable, waiting 1 second...
Database unavailable, waiting 1 second...
Database available!
.Waiting for database...
Database available!
....................F............
======================================================================
FAIL: test_comment_create (recipe.tests.test_comment_api.PublicCommentApiTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/app/recipe/tests/test_comment_api.py", line 41, in test_comment_create
self.assertEqual(res.status_code+2, status.HTTP_201_CREATED)
AssertionError: 203 != 201

----------------------------------------------------------------------
Ran 43 tests in 7.685s

FAILED (failures=1)
Destroying test database for alias 'default'...
Unit Tests or Flake8 must pass before commit!

Süper tam istediğim şekilde çalıştı. Fakat burada bilmemiz gereken bir konu var continuous integration süreçleriyle ilgili takım üyelerinin bu konuda bilinçlendirilmesi önemlidir. Evet bu yapı git sunucu tarafında kurulabilir fakat ben localde kullanmayı tavsiye ediyorum. Ayrıca son olarak aşağıdaki şekilde bu yapıyı atlayabiliriz.


--no-verify

--no-verify flagı kullanarak bu hooks a takılmada commitleyebiliriz.


git commit --no-verify -m "test"