diff --git a/.gitignore b/.gitignore index 481cc4a..8a442a4 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,6 @@ *.pyc html/ venv/ -.cache/ \ No newline at end of file +.cache/ +.tox +.coverage diff --git a/.travis.yml b/.travis.yml index 4832d8d..0722577 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,18 +1,54 @@ language: python -python: - - 2.6 - - 2.7 - - 3.3 - - 3.4 - - 3.5 - - pypy - - pypy3.3-5.2-alpha1 +matrix: + include: + - python: 2.6 + env: TOXENV=py26 + - python: 2.7 + env: TOXENV=py27 + - python: 3.3 + env: TOXENV=py33 + - python: 3.4 + env: TOXENV=py34 + - python: 3.5 + env: TOXENV=py35 + - python: 3.6 + env: TOXENV=py36 + - python: 3.7-dev + env: TOXENV=py37 + - python: nightly + env: TOXENV=py37 + - python: pypy + env: TOXENV=pypy + - python: pypy3 + env: TOXENV=pypy3 + - python: pypy3.3-5.2-alpha1 + env: TOXENV=pypy3 + - python: pypy3.3-5.5-alpha + env: TOXENV=pypy3 + allow_failures: + - python: pypy3 + - python: 3.7-dev + - python: nightly install: - - pip install --upgrade pytest - - pip install --upgrade pytest-cov - - pip install --upgrade coveralls + - pip install --upgrade tox coveralls codecov script: - - py.test --cov-report= --cov=ssh-audit -v test + - if [ -z "${TOXENV##*py3*}" ]; then + export MYPYBASE=python; + if [ -z "${TOXENV##*pypy3*}" ]; then + _pydir=$(dirname $(which python)); + ln -s -- "${_pydir}/python" "${_pydir}/pypy3"; + export TOXENV=${TOXENV},cov,lint; + else + export TOXENV=${TOXENV},cov,type,lint; + fi + else + export MYPYBASE=python-unknown; + export TOXENV=${TOXENV},cov,lint; + fi + - tox -e $TOXENV after_success: - coveralls - + - codecov +after_failure: + - cat .tox/log/* + - cat .tox/*/log/* diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..b5e5acc --- /dev/null +++ b/tox.ini @@ -0,0 +1,161 @@ +[tox] +envlist = py26,py27,py33,py34,py35,py36,py37,jython,pypy,pypy3,cov,type,lint +skipsdist = true +skip_missing_interpreters = true + +[testenv] +deps = + pytest==3.0.7 + coverage==4.3.4 + colorama==0.3.7 +setenv = + SSHAUDIT = {toxinidir}/ssh-audit.py + COVERAGE_FILE = {toxinidir}/.coverage.{envname} +commands = + coverage run --source ssh-audit -m -- pytest -v {posargs:test} + coverage report --show-missing + coverage html -d {toxinidir}/html/coverage.{envname} + +[testenv:cov] +deps = + coverage==4.3.4 +setenv = + COVERAGE_FILE = {toxinidir}/.coverage +commands = + coverage erase + coverage combine + coverage report --show-missing + coverage html -d {toxinidir}/html/coverage +ignore_outcome = true + +[testenv:mypy] +basepython = + {env:MYPYBASE:python3.5} +deps = + colorama==0.3.7 + mypy==0.501 + lxml==3.7.3 +setenv = + {[testenv]setenv} + MYPYPATH = {toxinidir}/test/stubs + MYPYHTML = {toxinidir}/html/mypy +commands = + mypy \ + --show-error-context \ + --config-file {toxinidir}/tox.ini \ + --html-report {env:MYPYHTML}.py3 \ + {posargs:{env:SSHAUDIT}} + mypy \ + -2 \ + --no-warn-incomplete-stub \ + --show-error-context \ + --config-file {toxinidir}/tox.ini \ + --html-report {env:MYPYHTML}.py2 \ + {posargs:{env:SSHAUDIT}} + +[testenv:pylint] +deps = + mccabe + pylint +commands = + pylint \ + --rcfile tox.ini \ + --load-plugins=pylint.extensions.bad_builtin \ + --load-plugins=pylint.extensions.check_elif \ + --load-plugins=pylint.extensions.mccabe \ + {posargs:{env:SSHAUDIT}} + +[testenv:flake8] +deps = + flake8 +commands = + flake8 {posargs:{env:SSHAUDIT}} + +[testenv:vulture] +deps = vulture +commands = + python -c "import sys; from subprocess import Popen, PIPE; \ + a = ['vulture'] + r'{posargs:{env:SSHAUDIT}}'.split(' '); \ + o = Popen(a, shell=False, stdout=PIPE).communicate()[0]; \ + l = [x for x in o.split('\n') if x and 'Unused import' not in x]; \ + print('\n'.join(l)); \ + sys.exit(1 if len(l) > 0 else 0)" + +[testenv:type] +basepython = + {[testenv:mypy]basepython} +deps = + {[testenv:mypy]deps} +setenv = + {[testenv:mypy]setenv} +commands = + {[testenv:mypy]commands} +ignore_outcome = true + +[testenv:lint] +deps = + {[testenv:pylint]deps} + {[testenv:flake8]deps} + {[testenv:vulture]deps} +commands = + {[testenv:pylint]commands} + {[testenv:flake8]commands} + {[testenv:vulture]commands} +ignore_outcome = true + + +[mypy] +ignore_missing_imports = False +follow_imports = error +disallow_untyped_calls = True +disallow_untyped_defs = True +check_untyped_defs = True +disallow_subclassing_any = True +warn_incomplete_stub = True +warn_redundant_casts = True +warn_return_any = True +warn_unused_ignores = True +strict_optional = True +#strict_boolean = False + +[pylint] +reports = no +#output-format = colorized +indent-string = \t +disable = locally-disabled, bad-continuation, multiple-imports, invalid-name, trailing-whitespace, missing-docstring +max-complexity = 15 +max-args = 8 +max-locals = 20 +max-returns = 6 +max-branches = 15 +max-statements = 60 +max-parents = 7 +max-attributes = 8 +min-public-methods = 1 +max-public-methods = 20 +max-bool-expr = 5 +max-nested-blocks = 6 +max-line-length = 80 +ignore-long-lines = ^\s*(#\s+type:\s+.*|[A-Z0-9_]+\s+=\s+.*|('.*':\s+)?\[.*\],?)$ +max-module-lines = 2500 + +[flake8] +ignore = + # indentation contains tabs + W191, + # blank line contains whitespace + W293, + # indentation contains mixed spaces and tabs + E101, + # multiple spaces before operator + E221, + # multiple spaces after operator + E241, + # multiple imports on one line + E401, + # line too long + E501, + # module imported but unused + F401, + # undefined name + F821