From 1daa69d685471f219a6b318fbaa2536d9f5d565f Mon Sep 17 00:00:00 2001 From: Matt Clay Date: Tue, 4 Apr 2017 15:21:55 -0700 Subject: [PATCH] Initial pylint support for ansible-test sanity. --- test/runner/lib/sanity.py | 86 ++++++++++++++++++++++++ test/runner/requirements/constraints.txt | 1 + test/sanity/pylint/disable.txt | 30 +++++++++ test/sanity/pylint/skip.txt | 0 4 files changed, 117 insertions(+) create mode 100644 test/sanity/pylint/disable.txt create mode 100644 test/sanity/pylint/skip.txt diff --git a/test/runner/lib/sanity.py b/test/runner/lib/sanity.py index de1c5975826..8aa23b80a86 100644 --- a/test/runner/lib/sanity.py +++ b/test/runner/lib/sanity.py @@ -53,6 +53,8 @@ COMMAND = 'sanity' PEP8_SKIP_PATH = 'test/sanity/pep8/skip.txt' PEP8_LEGACY_PATH = 'test/sanity/pep8/legacy-files.txt' +PYLINT_SKIP_PATH = 'test/sanity/pylint/skip.txt' + def command_sanity(args): """ @@ -431,6 +433,89 @@ def command_sanity_pep8(args, targets): return SanitySuccess(test) +def command_sanity_pylint(args, targets): + """ + :type args: SanityConfig + :type targets: SanityTargets + :rtype: SanityResult + """ + test = 'pylint' + + with open(PYLINT_SKIP_PATH, 'r') as skip_fd: + skip_paths = skip_fd.read().splitlines() + + with open('test/sanity/pylint/disable.txt', 'r') as disable_fd: + disable = set(disable_fd.read().splitlines()) + + skip_paths_set = set(skip_paths) + + paths = sorted(i.path for i in targets.include if os.path.splitext(i.path)[1] == '.py' and i.path not in skip_paths_set) + + if not paths: + return SanitySkipped(test) + + cmd = [ + 'pylint', + '--jobs', '0', + '--reports', 'n', + '--max-line-length', '160', + '--rcfile', '/dev/null', + '--output-format', 'json', + '--disable', ','.join(sorted(disable)), + ] + paths + + env = ansible_environment(args) + + try: + stdout, stderr = run_command(args, cmd, env=env, capture=True) + status = 0 + except SubprocessError as ex: + stdout = ex.stdout + stderr = ex.stderr + status = ex.status + + if stderr or status >= 32: + raise SubprocessError(cmd=cmd, status=status, stderr=stderr, stdout=stdout) + + if args.explain: + return SanitySkipped(test) + + if stdout: + messages = json.loads(stdout) + else: + messages = [] + + errors = [SanityMessage( + message=m['message'], + path=m['path'], + line=int(m['line']), + column=int(m['column']), + level=m['type'], + code=m['symbol'], + ) for m in messages] + + line = 0 + + for path in skip_paths: + line += 1 + + if not os.path.exists(path): + # Keep files out of the list which no longer exist in the repo. + errors.append(SanityMessage( + code='A101', + message='Remove "%s" since it does not exist' % path, + path=PYLINT_SKIP_PATH, + line=line, + column=1, + confidence=calculate_best_confidence(((PYLINT_SKIP_PATH, line), (path, 0)), args.metadata) if args.metadata.changes else None, + )) + + if errors: + return SanityFailure(test, messages=errors) + + return SanitySuccess(test) + + def command_sanity_yamllint(args, targets): """ :type args: SanityConfig @@ -642,6 +727,7 @@ class SanityFunc(SanityTest): SANITY_TESTS = ( SanityFunc('shellcheck', command_sanity_shellcheck, intercept=False), SanityFunc('pep8', command_sanity_pep8, intercept=False), + SanityFunc('pylint', command_sanity_pylint, intercept=False), SanityFunc('yamllint', command_sanity_yamllint, intercept=False), SanityFunc('validate-modules', command_sanity_validate_modules, intercept=False), SanityFunc('ansible-doc', command_sanity_ansible_doc), diff --git a/test/runner/requirements/constraints.txt b/test/runner/requirements/constraints.txt index 686b5e1305b..c963028d92f 100644 --- a/test/runner/requirements/constraints.txt +++ b/test/runner/requirements/constraints.txt @@ -1,2 +1,3 @@ coverage >= 4.2, != 4.3.2 # features in 4.2+ required, avoid known bug in 4.3.2 on python 2.6 pywinrm >= 0.2.1 # 0.1.1 required, but 0.2.1 provides better performance +pylint >= 1.5.3 # 1.4.1 adds JSON output, but 1.5.3 fixes bugs related to JSON output diff --git a/test/sanity/pylint/disable.txt b/test/sanity/pylint/disable.txt new file mode 100644 index 00000000000..82410745876 --- /dev/null +++ b/test/sanity/pylint/disable.txt @@ -0,0 +1,30 @@ +access-member-before-definition +assignment-from-no-return +bad-format-character +C +function-redefined +import-error +locally-disabled +locally-enabled +method-hidden +misplaced-bare-raise +no-member +no-name-in-module +no-value-for-parameter +not-a-mapping +not-an-iterable +not-callable +R +raising-bad-type +raising-non-exception +return-in-init +too-few-format-args +too-many-format-args +too-many-function-args +truncated-format-string +undefined-variable +unexpected-keyword-arg +unsubscriptable-object +unsupported-membership-test +used-before-assignment +W diff --git a/test/sanity/pylint/skip.txt b/test/sanity/pylint/skip.txt new file mode 100644 index 00000000000..e69de29bb2d