Mengintegrasikan kait .pre-commit ke proyek Django

Selamat siang!

Nama saya Andrey Sobolev dan hari ini saya akan memberi tahu Anda bagaimana kami menyiapkan .pre-commit hook pada proyek kami.

pengantar


Untuk mulai dengan, beberapa kata tentang apa kait secara umum dan mengapa mereka mungkin diperlukan. Git out of the box menyediakan alat yang dapat menjalankan skrip Anda ketika suatu peristiwa terjadi (misalnya, mendorong ke server, dll.)

Pra-komit adalah add-on yang nyaman untuk kait pre-komit git default git yang menjalankan skrip yang dijelaskan dalam .pre-commit-config.yaml sebelum melakukan. Secara teori, kedengarannya sederhana, mari kita berlatih.

Instalasi


Atur dependensi yang diperlukan:

pre-commit
#   https://pre-commit.com/

autoflake
#     (  )
black
#  
pyupgrade
#     
reorder-python-imports
#   
yesqa
#   noqa  ( )

# 
flake8
flake8-annotations
flake8-annotations-coverage
flake8-bandit
flake8-broken-line
flake8-bugbear
flake8-builtins
flake8-commas
flake8-comprehensions
flake8-debugger
flake8-eradicate
flake8-executable
flake8-fixme
flake8-future-import
flake8-pyi
flake8-pytest
flake8-pytest-style
flake8-mutable
flake8-string-format
flake8-todo
flake8-unused-arguments

# 
pytest

Saya akan menyampaikan pendapat saya tentang flake-8 dan linter secara umum. Jika Anda sudah memiliki proyek besar dengan banyak kode lawas, maka Anda dapat menghapus linter dengan aman. Biaya yang akan dihabiskan untuk "membawa ke ideal", pihak berwenang tidak akan menghargai. Kami menempatkan linter untuk proyek-proyek baru (dan kecil). Saya ulangi, ini adalah pendapat pribadi saya, saya tidak memaksakannya pada siapa pun.

Integrasi Lingkungan


Kami pergi ke direktori root dari lingkungan pengembangan dan menjalankan perintah berikut

$ pre-commit install
pre-commit installed at .git/hooks/pre-commit
$ pre-commit --version
pre-commit 2.4.0

Jika .pre-commit akan bersumpah pada sqlite, maka Anda harus menginstalnya (misalnya $ yum install sqlite) dan kompilasi python lagi

Menyiapkan file .pre-commit-config.yaml


Di direktori root lingkungan, buat file .pre-commit-config.yaml

- repo: https://github.com/pre-commit/pre-commit-hooks
  rev: "v2.5.0"
  hooks:
    - id: check-merge-conflict
    - id: debug-statements

- repo: local

  hooks:
    - id: black
      name: black
      entry: black
      language: system
      types: [python]
      args: [--line-length=200, --target-version=py37]

    - id: autoflake
      name: autoflake
      entry: autoflake
      language: system
      types: [python]
      args: [--in-place, --remove-all-unused-imports, --remove-duplicate-keys]

    # -   id: flake8
    #     name: flake8
    #     entry: flake8
    #     language: system
    #     types: [python]
    #     args: [
    #         "--ignore=E203,W503,FI10,FI11,FI12,FI13,FI14,FI15,FI16,FI17,FI58,PT013",
    #         # black
    #             # E203 whitespace before ':'
    #             # W503 line break before binary operator
    #         # flake8-future-import
    #             # FI10 __future__ import "division" missing
    #             # FI11 __future__ import "absolute_import" missing
    #             # FI12 __future__ import "with_statement" missing
    #             # FI13 __future__ import "print_function" missing
    #             # FI14 __future__ import "unicode_literals" missing
    #             # FI15 __future__ import "generator_stop" missing
    #             # FI16 __future__ import "nested_scopes" missing
    #             # FI17 __future__ import "generators" missing
    #             # FI58 __future__ import "annotations" present
    #         # flake8-pytest-style
    #             # PT013 found incorrect import of pytest, use simple 'import pytest' instead
    #         "--max-line-length=110",
    #         "--per-file-ignores=tests/*.py:S101"
    #         # S101 Use of assert detected
    #     ]

    - id: pyupgrade
      name: pyupgrade
      entry: pyupgrade
      language: system
      types: [python]
      args: [--py37-plus]

    - id: reorder-python-imports
      name: reorder-python-imports
      entry: reorder-python-imports
      language: system
      types: [python]
      args: [--py37-plus]

    - id: yesqa
      name: yesqa
      entry: yesqa
      language: system
      types: [python]

    - id: tests
      name: Run tests
      entry: "bash tests.sh"
      language: system
      verbose: true


Tes


Selain memeriksa dan memformat kode, kami akan melakukan tes pada tahap membuat komit. Untuk melakukan ini, kita akan menggunakan pytest (https://docs.pytest.org/en/latest/) dan mengkonfigurasinya untuk kebutuhan kita.

Di direktori root lingkungan, buat folder tes dan letakkan file berikut ini
test_example_without_db.py, test_example_with_db.py di sana

untuk kenyamanan, konfigurasikan tes sehingga Anda dapat menggunakan database saat ini (misalnya, salinan database dari server pertempuran), dan tidak membuat yang baru setiap kali .

Tes sederhana test_example_without_db.py

def inc(x):
    return x + 1

def test_answer():
    assert inc(3) == 4

Dalam tes sederhana, kita dapat terhubung misalnya webbot dan memotong node sistem kami untuk mengotomatiskan pekerjaan manual tester.

Uji menggunakan database test_example_with_db.py

import pytest
from chat.models import ChatRoom
from settings import POSTGRES_DB, POSTGRES_USER, POSTGRES_PASSWORD, \
                    POSTGRES_HOST, POSTGRES_PORT

@pytest.fixture(scope='session')
def django_db_setup():
    settings.DATABASES['default'] = {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': POSTGRES_DB,
        'USER': POSTGRES_USER,
        'PASSWORD': POSTGRES_PASSWORD,
        'HOST': POSTGRES_HOST,
        'PORT': POSTGRES_PORT,
    }   
    
    
@pytest.fixture
def db_access_without_rollback_and_truncate(request, django_db_setup, django_db_blocker):
    django_db_blocker.unblock()
    request.addfinalizer(django_db_blocker.restore)

def chat():
    return ChatRoom.objects.all().count()

@pytest.mark.django_db
def test_chat():
    assert chat() > 0

Contohnya agak buatan dan dibuat khusus untuk catatan ini, namun demikian memungkinkan kita untuk mengakses database saat ini dan melakukan tes kompleks yang melampaui pengujian manual.

Kami menyertakan tes dalam .pre-commit


Untuk menghubungkan tes, kita memerlukan skrip shell di direktori root lingkungan, yang akan kita panggil tests.sh:

source ../../python38_env/bin/activate && python -m pytest -v tests

Isinya sangat jelas, tetapi Anda mungkin memperhatikan bahwa aktivasi lingkungan virtual secara eksplisit ditulis dalam kode. Ini bisa merepotkan jika tim Anda mengembangkan di stasiun kerja yang berbeda (misalnya, yang menyebarkan lingkungan pada mesin lokal, dan seseorang berkembang di server).

Anda dapat memecahkan masalah ini melalui variabel dalam .env

Contoh penerapan :

github.com/Sobolev5/starlette-vue-backend/blob/master/.env.example (perhatikan variabel ENV_ACTIVATE)

github.com/Sobolev5/starlette-vue-backend /blob/master/tests.sh (parse ENV_ACTIVATE dan aktifkan lingkungan)

Buat komit


Sekarang tinggal membuat komit dan melihat cara kerjanya

$ git add .
$ git commit -m Sobolev:TestPreCommitHook
Check for merge conflicts................................................Passed
Debug Statements (Python)................................................Passed
black....................................................................Failed
- hook id: black
- files were modified by this hook

reformatted /var/www/file.py
All done!   
1 file reformatted, 2 files left unchanged.

autoflake................................................................Passed
pyupgrade................................................................Passed
reorder-python-imports...................................................Failed
- hook id: reorder-python-imports
- exit code: 1
- files were modified by this hook

Reordering imports in file.py

yesqa....................................................................Passed
Run tests................................................................Passed
- hook id: tests
- duration: 2.85s

tests/test_example_with_db.py::test_chat PASSED                          [ 66%]
tests/test_example_without_db.py::test_answer PASSED                     [100%]

Komit sekarang dibuat dalam dua langkah. Pada tahap pertama, kait memformat kode, jadi setelah mereka bekerja, kita hanya perlu "mengulang" perintah.

Ternyata urutan berikut.

$ git add .
$ git commit -m Sobolev:TestPreCommitHook
$ git add .
$ git commit -m Sobolev:TestPreCommitHook

Sekian, terima kasih atas perhatiannya.

Tautan situs


Daftar lengkap kait

All Articles