def run_dev_packages(self) -> int: """Runs the Lint command on all given packages. Returns: int. 0 on success and 1 if any package failed """ good_pkgs = [] fail_pkgs = [] if not self.parallel: for project_dir in self.pkgs: linter = Linter(project_dir, no_test=not self.run_args['tests'], 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, no_bandit=not self.run_args['bandit'], requirements_3=self.requirements_for_python3, requirements_2=self.requirements_for_python2) run_status_code = linter.run_dev_packages() if run_status_code > 0: fail_pkgs.append(project_dir) else: good_pkgs.append(project_dir) self._print_final_results(good_pkgs=good_pkgs, fail_pkgs=fail_pkgs) return 1 if fail_pkgs else 0 else: # we run parallel processes return self.run_parallel_packages(self.pkgs)
def _run_single_package_thread(self, package_dir: str) -> Tuple[int, str]: """Run a thread of lint command. Args: package_dir (str): The package directory to run the command on. Returns: Tuple[int, str]. The result code for the lint command and the package name. """ try: linter = Linter(package_dir, no_test=not self.run_args['tests'], no_pylint=not self.run_args['pylint'], no_flake8=not self.run_args['flake8'], no_mypy=not self.run_args['mypy'], 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'], no_vulture=not self.run_args['vulture'], no_pslint=not self.run_args['pslint'], requirements_3=self.requirements_for_python3, requirements_2=self.requirements_for_python2) return linter.run_dev_packages(), package_dir except Exception as ex: print_error( f'Failed running lint for: {package_dir}. Exception: {ex}') return 1, package_dir
def test_run_pytest(self, mocker, linter_obj: Linter, exp_container_exit_code: int, exp_exit_code: int): exp_test_json = mocker.MagicMock() if exp_container_exit_code in [ 0, 1, 2, 5 ] else {} # Docker client mocking mocker.patch( 'demisto_sdk.commands.lint.docker_helper.Docker.create_container') linter.Docker.create_container().wait.return_value = { "StatusCode": exp_container_exit_code } # Docker related mocking mocker.patch.object(linter, 'json') linter.json.loads.return_value = exp_test_json mocker.patch.object(linter, 'get_file_from_container') act_container_exit_code, act_output, act_test_json = linter_obj._docker_run_pytest( test_image='test-image', keep_container=False, test_xml="", no_coverage=True) assert exp_exit_code == act_container_exit_code assert exp_test_json == act_test_json
def test_build_image_no_errors(self, linter_obj: Linter, mocker): # Expected returns exp_test_image_id = 'test-image' exp_errors = "" # Jinja2 mocking mocker.patch.multiple(linter, Environment=DEFAULT, FileSystemLoader=DEFAULT, exceptions=DEFAULT, hashlib=DEFAULT, copy_dir_to_container=DEFAULT) # Facts mocking mocker.patch.dict(linter_obj._facts, { "images": [], "python_version": 0, "test": False, "lint_files": [], "additional_requirements": [], "docker_engine": True, "env_vars": { "CI": True, "DEMISTO_LINT_UPDATE_CERTS": "yes" } }) mocker.patch.object(linter, 'io') # Docker client mocking mocker.patch.object(linter_obj, '_docker_client') docker_build_response = mocker.MagicMock() docker_build_response.short_id = exp_test_image_id linter_obj._docker_client.containers.create().commit().short_id = exp_test_image_id act_test_image_id, act_errors = linter_obj._docker_image_create(docker_base_image=[exp_test_image_id, 3.7]) assert act_test_image_id == exp_test_image_id assert act_errors == exp_errors assert linter_obj._docker_client.images.build.call_count == 0
def linter_obj(mocker) -> Linter: mocker.patch.object(linter, 'docker') return Linter(pack_dir=Path(__file__).parent / 'content' / 'Integrations' / 'Sample_integration', content_repo=Path(__file__).parent / 'data', req_3=["pytest==3.0"], req_2=["pytest==2.0"], docker_engine=True)
def _run_single_package_thread(self, package_dir: str) -> Tuple[int, str]: """Run a thread of lint command. Args: package_dir (str): The package directory to run the command on. Returns: Tuple[int, str]. The result code for the lint command and the package name. """ linter = Linter(package_dir, no_test=not self.run_args['tests'], 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) return linter.run_dev_packages(), package_dir
def test_run_mypy_success(self, linter_obj: Linter, lint_files: List[Path], mocker): from demisto_sdk.commands.lint import linter mocker.patch.object(linter, 'run_command_os') linter.run_command_os.return_value = ('Success: no issues found', '', 0) exit_code, output = linter_obj._run_mypy(lint_files=lint_files, py_num=3.7) assert exit_code == 0b0, "Exit code should be 0" assert output == '', "Output should be empty"
def test_run_bandit_usage_stderr(self, linter_obj: Linter, lint_files: List[Path], mocker): from demisto_sdk.commands.lint import linter mocker.patch.object(linter, 'run_command_os') expected_output = 'Error code found' linter.run_command_os.return_value = ('not good', expected_output, 1) exit_code, output = linter_obj._run_bandit(lint_files=lint_files) assert exit_code == 0b1, "Exit code should be 1" assert output == expected_output, "Output should be empty"
def test_run_mypy_fail_lint(self, linter_obj: Linter, lint_files: List[Path], mocker): from demisto_sdk.commands.lint import linter mocker.patch.object(linter, 'run_command_os') expected_output = 'Error code found' linter.run_command_os.return_value = (expected_output, '', 1) exit_code, output = linter_obj._run_mypy(lint_files=lint_files, py_num=3.7) assert exit_code == 0b1, "Exit code should be 1" assert output == expected_output, "Output should be empty"
def test_run_pylint_with_errors(self, mocker, linter_obj: Linter, exp_container_exit_code: int, exp_container_log: str, exp_exit_code: int, exp_output: str): # Docker client mocking mocker.patch.object(linter_obj, '_docker_client') linter_obj._docker_client.containers.run().wait.return_value = {"StatusCode": exp_container_exit_code} linter_obj._docker_client.containers.run().logs.return_value = exp_container_log.encode('utf-8') act_exit_code, act_output = linter_obj._docker_run_pylint(test_image='test-image', keep_container=False) assert act_exit_code == exp_exit_code assert act_output == exp_output
def test_run_pylint_no_errors(self, mocker, linter_obj: Linter): # Expected values exp_container_exit_code = 0 exp_container_log = "" # Docker client mocking mocker.patch.object(linter_obj, '_docker_client') linter_obj._docker_client.containers.run().wait.return_value = {"StatusCode": exp_container_exit_code} linter_obj._docker_client.containers.run().logs.return_value = exp_container_log.encode('utf-8') act_container_exit_code, act_container_log = linter_obj._docker_run_pylint(test_image='test-image', keep_container=False) assert exp_container_exit_code == act_container_exit_code assert exp_container_log == act_container_log
def test_run_pylint_with_errors(self, mocker, linter_obj: Linter, exp_container_exit_code: int, exp_container_log: str, exp_exit_code: int, exp_output: str): # Docker client mocking mocker.patch( 'demisto_sdk.commands.lint.docker_helper.Docker.create_container') linter.Docker.create_container().wait.return_value = { "StatusCode": exp_container_exit_code } linter.Docker.create_container( ).logs.return_value = exp_container_log.encode('utf-8') act_exit_code, act_output = linter_obj._docker_run_pylint( test_image='test-image', keep_container=False) assert act_exit_code == exp_exit_code assert act_output == exp_output
def test_run_pytest(self, mocker, linter_obj: Linter, exp_container_exit_code: int, exp_exit_code: int): exp_test_json = mocker.MagicMock() # Docker client mocking mocker.patch.object(linter_obj, '_docker_client') linter_obj._docker_client.containers.run().wait.return_value = {"StatusCode": exp_container_exit_code} # Docker related mocking mocker.patch.object(linter, 'json') linter.json.loads.return_value = exp_test_json mocker.patch.object(linter, 'get_file_from_container') act_container_exit_code, act_output, act_test_json = linter_obj._docker_run_pytest(test_image='test-image', keep_container=False, test_xml="") assert exp_exit_code == act_container_exit_code assert exp_test_json == act_test_json
def run_dev_packages(self, parallel: int, no_flake8: bool, no_bandit: bool, no_mypy: bool, no_pylint: bool, no_vulture: bool, no_test: bool, no_pwsh_analyze: bool, no_pwsh_test: bool, keep_container: bool, test_xml: str, failure_report: str) -> int: """ Runs the Lint command on all given packages. Args: parallel(int): Whether to run command on multiple threads no_flake8(bool): Whether to skip flake8 no_bandit(bool): Whether to skip bandit no_mypy(bool): Whether to skip mypy no_vulture(bool): Whether to skip vulture no_pylint(bool): Whether to skip pylint no_test(bool): Whether to skip pytest no_pwsh_analyze(bool): Whether to skip powershell code analyzing no_pwsh_test(bool): whether to skip powershell tests keep_container(bool): Whether to keep the test container test_xml(str): Path for saving pytest xml results failure_report(str): Path for store failed packs report Returns: int: exit code by fail exit codes by var EXIT_CODES """ lint_status: Dict = { "fail_packs_flake8": [], "fail_packs_bandit": [], "fail_packs_mypy": [], "fail_packs_vulture": [], "fail_packs_pylint": [], "fail_packs_pytest": [], "fail_packs_pwsh_analyze": [], "fail_packs_pwsh_test": [], "fail_packs_image": [], } # Python or powershell or both pkgs_type = [] # Detailed packages status pkgs_status = {} # Skiped lint and test codes skipped_code = build_skipped_exit_code( no_flake8=no_flake8, no_bandit=no_bandit, no_mypy=no_mypy, no_vulture=no_vulture, no_pylint=no_pylint, no_test=no_test, no_pwsh_analyze=no_pwsh_analyze, no_pwsh_test=no_pwsh_test, docker_engine=self._facts["docker_engine"]) with concurrent.futures.ThreadPoolExecutor( max_workers=parallel) as executor: return_exit_code: int = 0 results = [] # Executing lint checks in different threads for pack in self._pkgs: linter: Linter = Linter( pack_dir=pack, content_repo="" if not self._facts["content_repo"] else Path(self._facts["content_repo"].working_dir), req_2=self._facts["requirements_2"], req_3=self._facts["requirements_3"], docker_engine=self._facts["docker_engine"]) results.append( executor.submit(fn=linter.run_dev_packages, no_flake8=no_flake8, no_bandit=no_bandit, no_mypy=no_mypy, no_vulture=no_vulture, no_pylint=no_pylint, no_test=no_test, no_pwsh_analyze=no_pwsh_analyze, no_pwsh_test=no_pwsh_test, modules=self._facts["test_modules"], keep_container=keep_container, test_xml=test_xml)) try: for future in concurrent.futures.as_completed(results): pkg_status = future.result() pkgs_status[pkg_status["pkg"]] = pkg_status if pkg_status["exit_code"]: for check, code in EXIT_CODES.items(): if pkg_status["exit_code"] & code: lint_status[f"fail_packs_{check}"].append( pkg_status["pkg"]) if not return_exit_code & pkg_status["exit_code"]: return_exit_code += pkg_status["exit_code"] if pkg_status["pack_type"] not in pkgs_type: pkgs_type.append(pkg_status["pack_type"]) except KeyboardInterrupt: print_warning("Stop demisto-sdk lint - Due to 'Ctrl C' signal") try: executor.shutdown(wait=False) except Exception: pass return 1 except Exception as e: print_warning(f"Stop demisto-sdk lint - Due to Exception {e}") try: executor.shutdown(wait=False) except Exception: pass return 1 self._report_results(lint_status=lint_status, pkgs_status=pkgs_status, return_exit_code=return_exit_code, skipped_code=int(skipped_code), pkgs_type=pkgs_type) self._create_failed_packs_report(lint_status=lint_status, path=failure_report) return return_exit_code
def test_run_bandit(self, directory): linter = Linter(directory) linter.run_bandit(3.7)
def test_run_mypy(self, directory): linter = Linter(directory) linter.run_mypy("2.7")
def test_get_common_server_python(self, directory): linter = Linter(directory) ans = linter.get_common_server_python() linter.remove_common_server_python() assert ans
def test_run_vulture(self, directory): linter = Linter(directory) linter.run_vulture(3.7)