From 88361cf4d3249e63db6d946ee822943722f58c84 Mon Sep 17 00:00:00 2001 From: John Vandenberg Date: Sat, 3 Aug 2019 21:34:10 +0700 Subject: [PATCH] CPDBear: Detect appropriate linter executable Describe current executable requirements of cpd or run.sh, replacing check_prerequisites with Requirement classes. Also remove explicit invocation using `bash`, which was ineffective as which('run.sh') would only be successful if the script was executable, and the run.sh script is not written to be compatible with invocation on Windows. This de-supports any usage where `pmd` existed and was a script which could invoke `cpd`. It fixes usage where `pmd` is not a script, like it is an executable shim when installed with choco. Also remove duplication of `CPDBear` in generate_bear_metadata.py which was intended to make 'cpd' deselectable, but was broken. It is now mostly unnecessary as the ExecutableRequirement classes provide the `cpd` tag, however the `java` tag is still manual. Reduce the required coverage percentage to 98%. Fixes https://github.com/coala/coala-bears/issues/2937 Related to https://github.com/coala/coala-bears/issues/2908 --- .ci/generate_bear_metadata.py | 8 +------- .ci/generate_coverage_thresholds.py | 2 ++ bear-metadata.yaml | 6 ++++++ bears/general/CPDBear.py | 30 +++++++++++++++++------------ tests/general/CPDBearTest.py | 12 ------------ 5 files changed, 27 insertions(+), 31 deletions(-) diff --git a/.ci/generate_bear_metadata.py b/.ci/generate_bear_metadata.py index d6389145bb..bcc8e5567b 100755 --- a/.ci/generate_bear_metadata.py +++ b/.ci/generate_bear_metadata.py @@ -322,11 +322,6 @@ def get_bear_tags(bear, metadata): tags.remove('java') tags.add('opam') - elif bear.name == 'CPDBear': - # Has no requirements defined yet - tags.remove('noreqs') - tags.add('java') - elif bear.name == 'LanguageToolBear': # Has no requirements defined yet tags.add('java') @@ -337,8 +332,7 @@ def get_bear_tags(bear, metadata): tags.add('pmd') elif bear.name == 'CPDBear': - # Has no executable defined - tags.add('cpd') + tags.add('java') elif bear.name == 'VHDLLintBear': # Has no executable defined diff --git a/.ci/generate_coverage_thresholds.py b/.ci/generate_coverage_thresholds.py index 0d5bb8d814..b9af475d13 100755 --- a/.ci/generate_coverage_thresholds.py +++ b/.ci/generate_coverage_thresholds.py @@ -24,6 +24,8 @@ def main(): bear = bear.replace('/', '\\\\') if 'CheckstyleBear' in bear or 'CMakeLintBear' in bear: threshold = 90 + elif 'CPDBear' in bear: + threshold = 98 thresholds[bear] = threshold diff --git a/bear-metadata.yaml b/bear-metadata.yaml index c2edf69382..dfd72c3532 100644 --- a/bear-metadata.yaml +++ b/bear-metadata.yaml @@ -154,6 +154,9 @@ bear_metadata: subdir: general filename: CPDBear.py requirements: + exe: + cpd: + run.sh: languages: - C# - CPP @@ -174,8 +177,11 @@ bear_metadata: - Scala - Swift tags: + - cpd + - exe - general - java + - run.sh CPPCheckBear: name: CPPCheckBear subdir: c_languages diff --git a/bears/general/CPDBear.py b/bears/general/CPDBear.py index 4914194646..c50c51833a 100644 --- a/bears/general/CPDBear.py +++ b/bears/general/CPDBear.py @@ -1,6 +1,11 @@ from shutil import which from xml.etree import ElementTree +from dependency_management.requirements.AnyOneOfRequirements import ( + AnyOneOfRequirements) +from dependency_management.requirements.ExecutableRequirement import ( + ExecutableRequirement) + from coalib.bears.GlobalBear import GlobalBear from coalib.misc.Shell import run_shell_command from coalib.results.Result import Result @@ -30,21 +35,18 @@ class CPDBear(GlobalBear): 'Swift': 'swift'} LANGUAGES = set(language_dict.keys()) + REQUIREMENTS = { + AnyOneOfRequirements( + [ExecutableRequirement('cpd'), + ExecutableRequirement('run.sh'), + ] + ), + } AUTHORS = {'The coala developers'} AUTHORS_EMAILS = {'coala-devel@googlegroups.com'} LICENSE = 'AGPL-3.0' CAN_DETECT = {'Duplication'} - @classmethod - def check_prerequisites(cls): - if which('bash') is None: - return 'bash is not installed.' - if which('pmd') is None and which('run.sh') is None: - return ('PMD is missing. Make sure to install it from ' - '.') - else: - return True - def run(self, language: language, minimum_tokens: int = 20, ignore_annotations: bool = False, @@ -93,8 +95,11 @@ def run(self, language: language, '--skip-duplicate-files': skip_duplicate_files} files = ','.join(self.file_dict.keys()) - executable = which('pmd') or which('run.sh') - arguments = ('bash', executable, 'cpd', '--skip-lexical-errors', + executable = which('cpd') or which('run.sh') + executable = tuple([executable] if not executable.endswith('run.sh') + else [executable, 'cpd']) + + arguments = ('--skip-lexical-errors', '--minimum-tokens', str(minimum_tokens), '--language', cpd_language, '--files', files, @@ -104,6 +109,7 @@ def run(self, language: language, for option, enable in options.items() if enable is True) + arguments = executable + arguments stdout_output, _ = run_shell_command(arguments) if stdout_output: diff --git a/tests/general/CPDBearTest.py b/tests/general/CPDBearTest.py index aa33e08b68..3984febdd9 100644 --- a/tests/general/CPDBearTest.py +++ b/tests/general/CPDBearTest.py @@ -1,6 +1,5 @@ import os import unittest -from unittest import mock from queue import Queue import logging @@ -68,14 +67,3 @@ def test_unsupported_language(self): self.uut.message_queue.queue[0].log_level, logging.ERROR) self.assertIn('Hypertext Markup Language', self.uut.message_queue.queue[0].message) - - def test_check_prerequisites(self): - with mock.patch('bears.general.CPDBear.which') as mock_which: - mock_which.side_effect = [None, None, None] - self.assertEqual(CPDBear.check_prerequisites(), - 'bash is not installed.') - - mock_which.side_effect = ['path/to/bash', None, None] - self.assertEqual(CPDBear.check_prerequisites(), - 'PMD is missing. Make sure to install it ' - 'from .')