将.pre-commit钩子集成到Django项目中

美好的一天!

我叫Andrey Sobolev,今天我将告诉您我们如何准备项目中的.pre-commit挂钩。

介绍


首先,简要介绍一下什么是钩子以及为什么需要它们。开箱即用的Git提供了一个工具,可以在事件发生时(例如,推送到服务器等)运行脚本

。Pre-commit是默认的git pre-commit钩子的便捷附加组件,该钩子运行下面描述的脚本.pre-commit-config.yaml,然后再提交。从理论上讲,这听起来很简单,让我们继续练习。

安装


设置必要的依赖关系:

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

我将大体上对flake-8和linter表示意见。如果您已经有一个带有大量遗留代码的大型项目,则可以安全地删除linters。当局将不会花在“实现理想”上的费用。我们将短绒棉布用于新的(和小型的)项目。我再说一遍,这是我的个人观点,我不强加于任何人。

环境整合


我们进入开发环境的根目录并执行以下命令

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

如果.pre-commit将在sqlite上发誓,那么您将需要安装它(例如$ yum install sqlite)并再次构建python

设置.pre-commit-config.yaml文件


在环境的根目录中,创建文件.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


测验


除了检查和格式化代码外,我们还将在创建提交的阶段执行测试。为此,我们将使用pytest(https://docs.pytest.org/en/latest/)并根据需要对其进行配置。 为了方便起见,

在环境的根目录中,创建测试文件夹,并将以下文件
test_example_without_db.py,test_example_with_db.py放在此处

,配置测试,以便可以使用当前数据库(例如,作战服务器的数据库副本),而不必每次都创建一个新数据库。 。

简单测试test_example_without_db.py

def inc(x):
    return x + 1

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

在简单的测试中,我们可以连接例如网络机器人并绕过我们系统的节点,以自动化测试仪的手动工作。

使用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

该示例是非常人为的,是专门为该注释创建的,但是它仍然使我们能够访问当前数据库并进行复杂的测试,这些测试超出了手动测试的范围。

我们在.pre-commit中包含测试


要连接测试,我们需要在环境的根目录中有一个shell脚本,我们将其称为tests.sh:

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

它的内容非常明显,但是您可能会注意到,虚拟环境的激活是在代码中明确编写的。如果您的团队在不同的工作站上进行开发(例如,谁将环境部署在本地计算机上,而有人在服务器上进行开发),这可能会带来不便。

您可以通过.env实现

示例中的变量解决此问题

github.com/Sobolev5/starlette-vue-backend/blob/master/.env.example(请注意变量ENV_ACTIVATE)

github.com/Sobolev5/starlette-vue-backend /blob/master/tests.sh(解析ENV_ACTIVATE并激活环境)

创建一个提交


现在剩下的工作就是创建提交并查看其工作原理

$ 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%]

现在,分两个步骤创建提交。在第一阶段,钩子会格式化代码,因此在工作之后,我们只需要“重复”命令即可。

结果如下。

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

就这样,谢谢您的关注。

网站连结


钩子的完整列表

All Articles