Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vulture #215

Merged
merged 10 commits into from
Mar 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions demisto_sdk/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,10 +268,10 @@ def secrets(config, **kwargs):

# ====================== lint ====================== #
@main.command(name="lint",
short_help="Run lintings (flake8, mypy, pylint, bandit) and pytest. pylint and pytest will run within the"
"docker image of an integration/script. Meant to be used with integrations/scripts that use "
"the folder (package) structure. Will lookup up what docker image to use and will setup the "
"dev dependencies and file in the target folder. ")
short_help="Run lintings (flake8, mypy, pylint, bandit, vulture) and pytest. pylint and pytest will run "
"within the docker image of an integration/script. Meant to be used with integrations/scripts "
"that use the folder (package) structure. Will lookup up what docker image to use and will "
"setup the dev dependencies and file in the target folder. ")
@click.help_option(
'-h', '--help'
)
Expand All @@ -285,6 +285,8 @@ def secrets(config, **kwargs):
"--no-flake8", is_flag=True, help="Do NOT run flake8 linter")
@click.option(
"--no-bandit", is_flag=True, help="Do NOT run bandit linter")
@click.option(
"--no-vulture", is_flag=True, help="Do NOT run vulture linter")
@click.option(
"--no-test", is_flag=True, help="Do NOT test (skip pytest)")
@click.option(
Expand Down
12 changes: 7 additions & 5 deletions demisto_sdk/commands/lint/lint_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class LintManager:
no_flake8 (bool): Whether to skip flake8.
no_mypy (bool): Whether to skip mypy.
no_bandit (bool): Whether to skip bandit.
no_bc_check (bool): Whether to skip backwards compatibility checks.
no_vulture (bool): Whether to skip vulture.
verbose (bool): Whether to output a detailed response.
root (bool): Whether to run pytest container with root user.
keep_container (bool): Whether to keep the test container.
Expand All @@ -37,7 +37,7 @@ class LintManager:
def __init__(self, project_dir_list: str, no_test: bool = False, no_pylint: bool = False, no_flake8: bool = False,
no_mypy: bool = False, verbose: bool = False, root: bool = False, keep_container: bool = False,
cpu_num: int = 0, parallel: bool = False, max_workers: int = 10, no_bandit: bool = False,
git: bool = False, run_all_tests: bool = False, outfile: str = '',
no_vulture: bool = False, git: bool = False, run_all_tests: bool = False, outfile: str = '',
configuration: Configuration = Configuration()):

if no_test and no_pylint and no_flake8 and no_mypy and no_bandit:
Expand All @@ -55,7 +55,8 @@ def __init__(self, project_dir_list: str, no_test: bool = False, no_pylint: bool
'flake8': not no_flake8,
'mypy': not no_mypy,
'tests': not no_test,
'bandit': not no_bandit
'bandit': not no_bandit,
'vulture': not no_vulture
}

if run_all_tests or (not project_dir_list and git):
Expand Down Expand Up @@ -118,6 +119,7 @@ def run_dev_packages(self) -> int:
no_mypy=not self.run_args['mypy'], verbose=self.log_verbose, root=self.root,
keep_container=self.keep_container, cpu_num=self.cpu_num,
configuration=self.configuration, no_bandit=not self.run_args['bandit'],
no_vulture=not self.run_args['vulture'],
requirements_3=self.requirements_for_python3,
requirements_2=self.requirements_for_python2)
run_status_code = linter.run_dev_packages()
Expand Down Expand Up @@ -235,8 +237,8 @@ def _run_single_package_thread(self, package_dir: str) -> Tuple[int, str]:
no_pylint=not self.run_args['pylint'], no_flake8=not self.run_args['flake8'],
no_mypy=not self.run_args['mypy'], verbose=self.log_verbose, root=self.root,
keep_container=self.keep_container, cpu_num=self.cpu_num, configuration=self.configuration,
lock=LOCK, no_bandit=not self.run_args['bandit'], requirements_3=self.requirements_for_python3,
requirements_2=self.requirements_for_python2)
lock=LOCK, no_bandit=not self.run_args['bandit'], no_vulture=not self.run_args['vulture'],
requirements_3=self.requirements_for_python3, requirements_2=self.requirements_for_python2)

return linter.run_dev_packages(), package_dir

Expand Down
46 changes: 42 additions & 4 deletions demisto_sdk/commands/lint/linter.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ def __init__(self, project_dir: str, no_test: bool = False, no_pylint: bool = Fa
no_mypy: bool = False, verbose: bool = False, root: bool = False, keep_container: bool = False,
cpu_num: int = 0, configuration: Configuration = Configuration(),
lock: threading.Lock = threading.Lock(), no_bandit: bool = False, requirements_3: str = '',
requirements_2: str = ''):
requirements_2: str = '', no_vulture: bool = False):

if no_test and no_pylint and no_flake8 and no_mypy and no_bandit:
if no_test and no_pylint and no_flake8 and no_mypy and no_bandit and no_vulture:
raise ValueError("Nothing to run as all --no-* options specified.")

self.configuration = configuration
Expand All @@ -69,7 +69,8 @@ def __init__(self, project_dir: str, no_test: bool = False, no_pylint: bool = Fa
'flake8': not no_flake8,
'mypy': not no_mypy,
'bandit': not no_bandit,
'tests': not no_test
'tests': not no_test,
'vulture': not no_vulture
}
self.lock = lock
self.requirements_3 = requirements_3
Expand Down Expand Up @@ -99,7 +100,7 @@ def remove_common_server_python(self):
if self.common_server_created:
os.remove(os.path.join(self.project_dir, self.common_server_target_path))

def run_dev_packages(self) -> int:
def run_dev_packages(self) -> int: # noqa: C901
return_code = 0
# load yaml
_, yml_path = get_yml_paths_in_dir(self.project_dir, Errors.no_yml_file(self.project_dir))
Expand Down Expand Up @@ -143,6 +144,11 @@ def run_dev_packages(self) -> int:
if result_val:
return_code = result_val

if self.run_args['vulture']:
result_val = self.run_vulture(py_num)
if result_val:
return_code = result_val

for docker in dockers:
for try_num in (1, 2):
print_v("Using docker image: {}".format(docker))
Expand Down Expand Up @@ -287,6 +293,38 @@ def run_bandit(self, py_num) -> int:
self.lock.release()
return 1

def run_vulture(self, py_num) -> int:
"""Run vulture

Args:
py_num: The python version in use

Returns:
int. 0 on successful vulture run, 1 otherwise.
"""
lint_files = self._get_lint_files()
python_exe = 'python2' if py_num < 3 else 'python3'
cmd_args = [python_exe, '-m', 'vulture', lint_files, '--min-confidence',
os.environ.get('VULTURE_MIN_CONFIDENCE_LEVEL', '100')]
vulture_whitelist_path = os.path.join(self.project_dir, '.vulture_whitelist.py')
if os.path.isfile(vulture_whitelist_path):
cmd_args.insert(4, vulture_whitelist_path)
output = run_command(' '.join(cmd_args), cwd=self.project_dir)
self.lock.acquire()
print("========= Running vulture on: {} ===============".format(lint_files))
print_v('Using: {} to run vulture'.format(python_exe))
if len(output) == 0:
print_color("vulture completed for: {}\n".format(lint_files), LOG_COLORS.GREEN)
if self.lock.locked():
self.lock.release()
return 0

else:
print_error(output)
if self.lock.locked():
self.lock.release()
return 1

def _docker_login(self):
if self.docker_login_completed:
return True
Expand Down
5 changes: 5 additions & 0 deletions demisto_sdk/commands/lint/tests/linter_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,8 @@ def test_run_mypy(self, directory):
def test_run_bandit(self, directory):
linter = Linter(directory)
linter.run_bandit(3.7)

@pytest.mark.parametrize("directory", DIR_LIST)
def test_run_vulture(self, directory):
linter = Linter(directory)
linter.run_vulture(3.7)
2 changes: 1 addition & 1 deletion demisto_sdk/commands/unify/unifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ def get_code_file(self, script_type):
"""

ignore_regex = (r'CommonServerPython\.py|CommonServerUserPython\.py|demistomock\.py|_test\.py'
r'|conftest\.py|__init__\.py|ApiModule\.py')
r'|conftest\.py|__init__\.py|ApiModule\.py|vulture_whitelist\.py')

if self.package_path.endswith('Scripts/CommonServerPython'):
return os.path.join(self.package_path, 'CommonServerPython.py')
Expand Down
Empty file.
11 changes: 9 additions & 2 deletions docs/lint_command.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
### Lint

Run lintings (flake8, mypy, pylint, bandit) and pytest.
Run lintings (flake8, mypy, pylint, bandit, vulture) and pytest.
pylint and pytest will run within all the docker images of an integration/script.
Meant to be used with integrations/scripts that use the folder (package) structure.

Expand All @@ -21,6 +21,8 @@ make sure the code works as intended.
Do NOT run flake8 linter (default: False)
* **--no-bandit**
Do NOT run bandit linter (default: False)
* **--no-vulture**
Do NOT run vulture linter (default: False)
* **--no-test**
Do NOT test (skip pytest) (default: False)
* **-r, --root**
Expand Down Expand Up @@ -57,11 +59,16 @@ Also this will check the amount of CPU's available to run pytest on and use them
<br/><br/>

`demisto-sdk lint -d Scripts/HelloWorldScript --no-pytest --no-pylint`
This will run only the linters (flake8, mypy, bandit) on "Scripts/HelloWorldScript".
This will run only the linters (flake8, mypy, bandit, vulture) on "Scripts/HelloWorldScript".
<br/><br/>

`demisto-sdk lint -d Integrations/HelloWorld --no-mypy --no-flake8 --no-pytest -k -r`
This will run only pylint and pytest on "Integrations/HelloWorld" using the root user for the pytest and will also keep the test container with the docker image after the operation is over.

`demisto-sdk lint -g --outfile ~/failures.txt`
This indicates lint runs only on changed packages from content repo's 'origin/master' branch and saves the failed packages to failures.txt file.


**Notes**
Vulture reports dead code with confidence level of 100% by default.
The minimum confidence level can be set by changing the environment variable `VULTURE_MIN_CONFIDENCE_LEVEL`, i.e. `export VULTURE_MIN_CONFIDENCE_LEVEL=60`.
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ PyPDF2>=1.26.0
PyYAML>=5.1.2
requests>=2.22.0
ruamel.yaml>=0.16.5
vulture>=1.3
yamlordereddictloader>=0.4.0