¡Buen día!Mi nombre es Andrey Sobolev y hoy les diré cómo preparamos .pre-commit hook en nuestro proyecto.Introducción
Para empezar, algunas palabras sobre qué son los ganchos en general y por qué podrían ser necesarios. Git fuera de la caja proporciona una herramienta que puede ejecutar sus scripts cuando ocurre un evento (por ejemplo, empujar a un servidor, etc.).Pre-commit es un complemento conveniente para el gancho predeterminado de pre-commit de git que ejecuta los scripts descritos en .pre-commit-config.yaml antes de comprometerse. En teoría, suena simple, pasemos a la práctica.Instalación
Establezca las dependencias necesarias:pre-commit
autoflake
black
pyupgrade
reorder-python-imports
yesqa
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
Expresaré mi opinión sobre flake-8 y linter en general. Si ya tiene un proyecto grande con un montón de código heredado, puede eliminar linters de forma segura. Los costos que se gastarán en "llevar al ideal", las autoridades no lo apreciarán. Ponemos linters para proyectos nuevos (y pequeños). Repito, esta es mi opinión personal, no se la impongo a nadie.Integración Ambiental
Vamos al directorio raíz del entorno de desarrollo y ejecutamos los siguientes comandos$ pre-commit install
pre-commit installed at .git/hooks/pre-commit
$ pre-commit --version
pre-commit 2.4.0
Si .pre-commit jurará en sqlite, entonces deberá instalarlo (por ejemplo, $ yum install sqlite) y construir python nuevamente
Configurar el archivo .pre-commit-config.yaml
En el directorio raíz del entorno, cree el archivo .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: 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
Pruebas
Además de verificar y formatear el código, realizaremos pruebas en la etapa de creación de la confirmación. Para hacer esto, usaremos pytest (https://docs.pytest.org/en/latest/) y lo configuraremos para nuestras necesidades.En el directorio raíz del entorno, cree la carpeta de pruebas y coloque los siguientes archivostest_example_without_db.py, test_example_with_db.py allípor conveniencia, configure las pruebas para que pueda usar la base de datos actual (por ejemplo, una copia de la base de datos del servidor de batalla), y no cree una nueva cada vez. .Prueba simple test_example_without_db.pydef inc(x):
return x + 1
def test_answer():
assert inc(3) == 4
En pruebas simples, podemos conectar, por ejemplo, webbot y omitir los nodos de nuestro sistema para automatizar el trabajo manual del probador.Prueba usando la base de datos test_example_with_db.pyimport 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
El ejemplo es bastante artificial y creado exclusivamente para esta nota, pero sin embargo nos permite acceder a la base de datos actual y realizar pruebas complejas que van más allá de las pruebas manuales.Incluimos pruebas en .pre-commit
Para conectar las pruebas, necesitamos un script de shell en el directorio raíz del entorno, al que llamaremos tests.sh:source ../../python38_env/bin/activate && python -m pytest -v tests
Su contenido es muy obvio, pero puede notar que la activación del entorno virtual está explícitamente escrita en el código. Esto puede ser inconveniente si su equipo está desarrollando en diferentes estaciones de trabajo (por ejemplo, quién implementó el entorno en una máquina local y alguien desarrolla en un servidor).Puede resolver este problema a través de variables en .envEjemplo de implementación :github.com/Sobolev5/starlette-vue-backend/blob/master/.env.example (tenga en cuenta la variable ENV_ACTIVATE)github.com/Sobolev5/starlette-vue-backend /blob/master/tests.sh (analizar ENV_ACTIVATE y activar el entorno)Crear un compromiso
Ahora queda crear un commit y ver cómo funciona$ 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%]
Una confirmación ahora se crea en dos pasos. En la primera etapa, los ganchos formatean el código, por lo que después de su trabajo solo necesitamos "repetir" los comandos.Resulta la siguiente secuencia.$ git add .
$ git commit -m Sobolev:TestPreCommitHook
$ git add .
$ git commit -m Sobolev:TestPreCommitHook
Eso es todo, gracias por su atención.Enlaces de sitio
→ Lista completa de ganchos