core -- Add black,isort,flake8 to CI and pre-commit hook

On CI:
- black and isort in check mode must pass.
- flake8 only prints errors
  WIP: make it also failed.

On pre-commit:
- black and isort will format staged files, if installed on path.
- flake8 prints its output if necessary.
This commit is contained in:
Aurélien Delobelle 2018-10-06 03:14:49 +02:00
parent b23810917d
commit 104e71dcf6
6 changed files with 186 additions and 16 deletions

View file

@ -22,25 +22,41 @@ variables:
# psql password authentication # psql password authentication
PGPASSWORD: $POSTGRES_PASSWORD PGPASSWORD: $POSTGRES_PASSWORD
cache:
paths:
- vendor/
before_script:
- mkdir -p vendor/{pip,apt}
- apt-get update -q && apt-get -o dir::cache::archives="vendor/apt" install -yqq postgresql-client
- sed -E 's/^REDIS_HOST.*/REDIS_HOST = "redis"/' cof/settings/secret_example.py > cof/settings/secret.py
- sed -i.bak -E 's;^REDIS_PASSWD = .*$;REDIS_PASSWD = "";' cof/settings/secret.py
# Remove the old test database if it has not been done yet
- psql --username=$POSTGRES_USER --host=$DBHOST -c "DROP DATABASE IF EXISTS test_$POSTGRES_DB"
- pip install --upgrade -r requirements.txt
- pip install coverage
- python --version
test: test:
stage: test stage: test
before_script:
- mkdir -p vendor/{pip,apt}
- apt-get update -q && apt-get -o dir::cache::archives="vendor/apt" install -yqq postgresql-client
- sed -E 's/^REDIS_HOST.*/REDIS_HOST = "redis"/' cof/settings/secret_example.py > cof/settings/secret.py
- sed -i.bak -E 's;^REDIS_PASSWD = .*$;REDIS_PASSWD = "";' cof/settings/secret.py
# Remove the old test database if it has not been done yet
- psql --username=$POSTGRES_USER --host=$DBHOST -c "DROP DATABASE IF EXISTS test_$POSTGRES_DB"
- pip install --upgrade -r requirements.txt coverage
- python --version
script: script:
- coverage run manage.py test - coverage run manage.py test
after_script:
- coverage report - coverage report
# For GitLab, keep this commented. cache:
key: test
paths:
- vendor/
# For GitLab CI to get coverage from build.
# Keep this disabled for now, at it may kill GitLab...
# coverage: '/TOTAL.*\s(\d+\.\d+)\%$/' # coverage: '/TOTAL.*\s(\d+\.\d+)\%$/'
linters:
image: python:3.6
stage: test
before_script:
- mkdir -p vendor/pip
- pip install --upgrade black isort flake8
script:
- black --check .
- isort --recursive --check-only --diff bda cof gestioncof kfet provisioning shared utils
# Print errors only
- flake8 --exit-zero bda cof gestioncof kfet provisioning shared utils
cache:
key: linters
paths:
- vendor/

106
.pre-commit.sh Executable file
View file

@ -0,0 +1,106 @@
#!/usr/bin/env bash
# pre-commit hook for gestioCOF project.
#
# Run formatters first, then checkers.
# Formatters which changed a file must set the flag 'formatter_updated'.
exit_code=0
formatter_updated=0
checker_dirty=0
# TODO(AD): We should check only staged changes.
# Working? -> Stash unstaged changes, run it, pop stash
STAGED_PYTHON_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep ".py$")
# Formatter: black
printf "> black ... "
if type black &>/dev/null; then
if [ -z $STAGED_PYTHON_FILES ]; then
printf "OK\n"
else
BLACK_OUTPUT="/tmp/gc-black-output.log"
touch $BLACK_OUTPUT
black --check $STAGED_PYTHON_FILES &>$BLACK_OUTPUT
printf "OK\n"
if [ $? -ne 0 ]; then
black $STAGED_PYTHON_FILES &>$BLACK_OUTPUT
tail -1 $BLACK_OUTPUT
formatter_updated=1
fi
fi
else
printf "SKIP: program not found\n"
printf "HINT: Install black with 'pip3 install black' (black requires Python>=3.6)\n"
fi
# Formatter: isort
printf "> isort ... "
if type isort &>/dev/null; then
if [ -z $STAGED_PYTHON_FILES ]; then
printf "OK\n"
else
ISORT_OUTPUT="/tmp/gc-isort-output.log"
touch $ISORT_OUTPUT
isort --check-only $STAGED_PYTHON_FILES &>$ISORT_OUTPUT
printf "OK\n"
if [ $? -ne 0 ]; then
isort $STAGED_PYTHON_FILES &>$ISORT_OUTPUT
printf "Reformatted.\n"
formatter_updated=1
fi
fi
else
printf "SKIP: program not found\n"
printf "HINT: Install isort with 'pip install isort'\n"
fi
# Checker: flake8
printf "> flake8 ... "
if type flake8 &>/dev/null; then
if [ -z $STAGED_PYTHON_FILES ]; then
printf "OK\n"
else
FLAKE8_OUTPUT="/tmp/gc-flake8-output.log"
touch $FLAKE8_OUTPUT
flake8 $STAGED_PYTHON_FILES &>$FLAKE8_OUTPUT
if [ $? -eq 0 ]; then
printf "OK\n"
else
printf "FAIL\n"
cat $FLAKE8_OUTPUT
checker_dirty=1
fi
fi
else
printf "SKIP: program not found\n"
printf "HINT: Install flake8 with 'pip install flake8'\n"
fi
# End
if [ $checker_dirty -ne 0 ]
then
printf ">>> Checker(s) detect(s) issue(s)\n"
printf " You can still commit and push :)\n"
printf " Be warned that our CI may cause you more trouble.\n"
fi
if [ $formatter_updated -ne 0 ]
then
printf ">>> Working tree updated by formatter(s)\n"
printf " Add changes to staging area and retry.\n"
exit_code=1
fi
printf "\n"
exit $exit_code

View file

@ -44,6 +44,16 @@ pour profiter de façon transparente des mises à jour du fichier:
ln -s secret_example.py cof/settings/secret.py ln -s secret_example.py cof/settings/secret.py
Nous avons un git hook de pre-commit pour formatter et vérifier que votre code
vérifie nos conventions. Pour bénéficier des mises à jour du hook, préférez
encore l'installation *via* un lien symbolique:
ln -s ../../.pre-commit.sh .git/hooks/pre-commit
Pour plus d'informations à ce sujet, consulter la
[page](https://git.eleves.ens.fr/cof-geek/gestioCOF/wikis/coding-style)
du wiki gestioCOF liée aux conventions.
#### Fin d'installation #### Fin d'installation

9
pyproject.toml Normal file
View file

@ -0,0 +1,9 @@
[tool.black]
# Automatically ignore files in .gitignore (opened at this time):
# https://github.com/ambv/black/issues/475
exclude = '''
/(
\.pyc
| venv
)/
'''

View file

@ -2,3 +2,8 @@
django-debug-toolbar django-debug-toolbar
django-debug-panel django-debug-panel
ipython ipython
# Tools
# black # Uncomment when GC & most distros run with Python>=3.6
flake8
isort

View file

@ -14,3 +14,27 @@ branch = true
[coverage:report] [coverage:report]
precision = 2 precision = 2
show_missing = true show_missing = true
[flake8]
exclude = migrations
max-line-length = 88
ignore =
# whitespace before ':' (not PEP8-compliant for slicing)
E203,
# lambda expression
E731,
# line break before binary operator (not PEP8-compliant)
W503
[isort]
# For black compat: https://github.com/ambv/black#how-black-wraps-lines
combine_as_imports = true
default_section = THIRDPARTY
force_grid_wrap = 0
include_trailing_comma = true
known_django = django
known_first_party = bda,cof,gestioncof,kfet,shared,utils
line_length = 88
multi_line_output = 3
not_skip = __init__.py
sections = FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER