def manage_activation(self, params): # Default value is false in case ENABLE variables are used if len(params["enable_descriptors"]) > 0 or len( params["enable_linters"]) > 0: self.is_active = False # Activate or not the linter if self.name in params["enable_linters"]: self.is_active = True elif self.name in params["disable_linters"]: self.is_active = False elif (self.descriptor_id in params["disable_descriptors"] or self.name in params["disable_linters"]): self.is_active = False elif self.descriptor_id in params["enable_descriptors"]: self.is_active = True elif (config.exists("VALIDATE_" + self.name) and config.get("VALIDATE_" + self.name) == "false"): self.is_active = False elif (config.exists("VALIDATE_" + self.descriptor_id) and config.get("VALIDATE_" + self.descriptor_id) == "false"): self.is_active = False elif (config.exists("VALIDATE_" + self.name) and config.get("VALIDATE_" + self.name) == "true"): self.is_active = True elif (config.exists("VALIDATE_" + self.descriptor_id) and config.get("VALIDATE_" + self.descriptor_id) == "true"): self.is_active = True # check activation rules if self.is_active is True and len(self.activation_rules) > 0: self.is_active = utils.check_activation_rules( self.activation_rules, self)
def manage_activation(self, params): if self.name in params["enable_linters"]: self.is_active = True elif self.name in params["disable_linters"]: self.is_active = False elif ( self.descriptor_id in params["disable_descriptors"] or self.name in params["disable_linters"] ): self.is_active = False elif self.descriptor_id in params["enable_descriptors"]: self.is_active = True elif ( config.exists("VALIDATE_" + self.name) and config.get("VALIDATE_" + self.name) == "false" ): self.is_active = False elif ( config.exists("VALIDATE_" + self.descriptor_id) and config.get("VALIDATE_" + self.descriptor_id) == "false" ): self.is_active = False elif ( config.exists("VALIDATE_" + self.name) and config.get("VALIDATE_" + self.name) == "true" ): self.is_active = True elif ( config.exists("VALIDATE_" + self.descriptor_id) and config.get("VALIDATE_" + self.descriptor_id) == "true" ): self.is_active = True
def produce_report(self): if ( config.exists("GITHUB_REPOSITORY") and config.exists("GITHUB_SHA") and config.exists("GITHUB_TOKEN") and config.exists("GITHUB_RUN_ID") ): github_repo = config.get("GITHUB_REPOSITORY") sha = config.get("GITHUB_SHA") run_id = config.get("GITHUB_RUN_ID") success_msg = "No errors were found in the linting process" error_not_blocking = "Errors were detected but are considered not blocking" error_msg = "Errors were detected, please view logs" url = f"{self.github_api_url}/repos/{github_repo}/statuses/{sha}" headers = { "accept": "application/vnd.github.v3+json", "authorization": f"Bearer {config.get('GITHUB_TOKEN')}", "content-type": "application/json", } target_url = f"https://github.com/{github_repo}/actions/runs/{run_id}" description = ( success_msg if self.master.status == "success" and self.master.return_code == 0 else error_not_blocking if self.master.status == "error" and self.master.return_code == 0 else error_msg ) if self.master.show_elapsed_time is True: description += f" ({str(round(self.master.elapsed_time_s, 2))}s)" data = { "state": "success" if self.master.return_code == 0 else "error", "target_url": target_url, "description": description, "context": f"--> Lint: {self.master.descriptor_id} with {self.master.linter_name}", } response = requests.post(url, headers=headers, json=data) if 200 <= response.status_code < 299: logging.debug( f"Successfully posted Github Status for {self.master.descriptor_id} with {self.master.linter_name}" ) else: logging.error( f"Error posting Github Status for {self.master.descriptor_id}" f"with {self.master.linter_name}: {response.status_code}" ) logging.error(f"GitHub API response: {response.text}") else: logging.debug( f"Skipped post of Github Status for {self.master.descriptor_id} with {self.master.linter_name}" )
def linter_test_setup(params=None): config.init_config(None) if params is None: params = {} # Root to lint sub_lint_root = (params["sub_lint_root"] if "sub_lint_root" in params else f"{os.path.sep}.automation{os.path.sep}test") # Ignore report folder config.set_value("FILTER_REGEX_EXCLUDE", "\\/(report)\\/") # TAP Output deactivated by default config.set_value("OUTPUT_FORMAT", "text") config.set_value("OUTPUT_DETAIL", "detailed") # Root path of default rules root_dir = ("/tmp/lint" if os.path.isdir("/tmp/lint") else os.path.relpath( os.path.relpath(os.path.dirname(os.path.abspath(__file__))) + "/../../../..")) config.set_value("VALIDATE_ALL_CODEBASE", "true") # Root path of files to lint config.set_value( "DEFAULT_WORKSPACE", (config.get("DEFAULT_WORKSPACE") + sub_lint_root if config.exists("DEFAULT_WORKSPACE") and os.path.isdir(config.get("DEFAULT_WORKSPACE") + sub_lint_root) else root_dir + sub_lint_root), ) assert os.path.isdir( config.get("DEFAULT_WORKSPACE")), ("DEFAULT_WORKSPACE " + config.get("DEFAULT_WORKSPACE") + " is not a valid folder")
def load_config_vars(self): # Linter rules root path if config.exists("LINTER_RULES_PATH"): self.linter_rules_path = (self.github_workspace + os.path.sep + config.get("LINTER_RULES_PATH")) # Filtering regex (inclusion) if config.exists("FILTER_REGEX_INCLUDE"): self.filter_regex_include = config.get("FILTER_REGEX_INCLUDE") # Filtering regex (exclusion) if config.exists("FILTER_REGEX_EXCLUDE"): self.filter_regex_exclude = config.get("FILTER_REGEX_EXCLUDE") # Disable all fields validation if VALIDATE_ALL_CODEBASE is 'false' if (config.exists("VALIDATE_ALL_CODEBASE") and config.get("VALIDATE_ALL_CODEBASE") == "false"): self.validate_all_code_base = False
def linter_test_setup(params=None): for key in [ "MEGALINTER_CONFIG", "EXTENDS", "FILTER_REGEX_INCLUDE", "FILTER_REGEX_EXCLUDE", "SHOW_ELAPSED_TIME", ]: if key in os.environ: del os.environ[key] config.delete() if params is None: params = {} # Root to lint sub_lint_root = ( params["sub_lint_root"] if "sub_lint_root" in params else f"{os.path.sep}.automation{os.path.sep}test" ) # Root path of default rules root_dir = ( "/tmp/lint" if os.path.isdir("/tmp/lint") else os.path.relpath( os.path.relpath(os.path.dirname(os.path.abspath(__file__))) + "/../../../.." ) ) workspace = None config_file_path = root_dir + sub_lint_root + os.path.sep + ".mega-linter.yml" if os.path.isfile(config_file_path): workspace = root_dir + sub_lint_root elif params.get("required_config_file", False) is True: raise Exception( f"[test] There should be a .mega-linter.yml file in test folder {config_file_path}" ) config.init_config(workspace) # Ignore report folder config.set_value("FILTER_REGEX_EXCLUDE", r"\/report\/") # TAP Output deactivated by default config.set_value("OUTPUT_FORMAT", "text") config.set_value("OUTPUT_DETAIL", "detailed") config.set_value("PLUGINS", "") config.set_value("VALIDATE_ALL_CODEBASE", "true") # Root path of files to lint config.set_value( "DEFAULT_WORKSPACE", ( config.get("DEFAULT_WORKSPACE") + sub_lint_root if config.exists("DEFAULT_WORKSPACE") and os.path.isdir(config.get("DEFAULT_WORKSPACE") + sub_lint_root) else root_dir + sub_lint_root ), ) assert os.path.isdir(config.get("DEFAULT_WORKSPACE")), ( "DEFAULT_WORKSPACE " + config.get("DEFAULT_WORKSPACE") + " is not a valid folder" )
def load_config_vars(self): # Linter rules root path if config.exists("LINTER_RULES_PATH"): linter_rules_path_val = config.get("LINTER_RULES_PATH") if linter_rules_path_val.startswith("http"): self.linter_rules_path = linter_rules_path_val else: self.linter_rules_path = (self.github_workspace + os.path.sep + linter_rules_path_val) # Filtering regex (inclusion) if config.exists("FILTER_REGEX_INCLUDE"): self.filter_regex_include = config.get("FILTER_REGEX_INCLUDE") # Filtering regex (exclusion) if config.exists("FILTER_REGEX_EXCLUDE"): self.filter_regex_exclude = config.get("FILTER_REGEX_EXCLUDE") # Disable all fields validation if VALIDATE_ALL_CODEBASE is 'false' if (config.exists("VALIDATE_ALL_CODEBASE") and config.get("VALIDATE_ALL_CODEBASE") == "false"): self.validate_all_code_base = False # Manage IGNORE_GITIGNORED_FILES if config.exists("IGNORE_GITIGNORED_FILES"): self.ignore_gitignore_files = (config.get( "IGNORE_GITIGNORED_FILES", "true") == "true") # Manage IGNORE_GENERATED_FILES if config.exists("IGNORE_GENERATED_FILES"): self.ignore_generated_files = (config.get("IGNORE_GENERATED_FILES", "false") == "true")
def produce_report(self): if ( config.exists("GITHUB_REPOSITORY") and config.exists("GITHUB_SHA") and config.exists("GITHUB_TOKEN") ): github_repo = config.get("GITHUB_REPOSITORY") github_server_url = config.get("GITHUB_SERVER_URL", self.github_server_url) github_api_url = config.get("GITHUB_API_URL", self.github_api_url) sha = config.get("GITHUB_SHA") run_id = config.get("GITHUB_RUN_ID") success_msg = "No errors were found in the linting process" error_not_blocking = "Errors were detected but are considered not blocking" error_msg = f"Found {self.master.total_number_errors}, please check logs" url = f"{github_api_url}/repos/{github_repo}/statuses/{sha}" headers = { "accept": "application/vnd.github.v3+json", "authorization": f"Bearer {config.get('GITHUB_TOKEN')}", "content-type": "application/json", } if config.exists("GITHUB_RUN_ID"): target_url = f"{github_server_url}/{github_repo}/actions/runs/{run_id}" else: target_url = config.get("GITHUB_TARGET_URL") description = ( success_msg if self.master.status == "success" and self.master.return_code == 0 else error_not_blocking if self.master.status == "error" and self.master.return_code == 0 else error_msg ) if self.master.show_elapsed_time is True: description += f" ({str(round(self.master.elapsed_time_s, 2))}s)" data = { "state": "success" if self.master.return_code == 0 else "error", "target_url": target_url, "description": description, "context": f"--> Lint: {self.master.descriptor_id} with {self.master.linter_name}", } try: response = requests.post(url, headers=headers, json=data) if 200 <= response.status_code < 299: logging.debug( f"Successfully posted Github Status for {self.master.descriptor_id} " f"with {self.master.linter_name}" ) else: logging.warning( f"[GitHub Status Reporter] Error posting Status for {self.master.descriptor_id}" f"with {self.master.linter_name}: {response.status_code}\n" f"GitHub API response: {response.text}" ) except ConnectionError as e: logging.warning( f"[GitHub Status Reporter] Error posting Status for {self.master.descriptor_id}" f"with {self.master.linter_name}: Connection error {str(e)}" ) except Exception as e: logging.warning( f"[GitHub Status Reporter] Error posting Status for {self.master.descriptor_id}" f"with {self.master.linter_name}: Error {str(e)}" ) else: logging.debug( f"Skipped post of Github Status for {self.master.descriptor_id} with {self.master.linter_name}" )
def manage_activation(self): # Disable status for each linter if MULTI_STATUS is 'false' if config.exists("MULTI_STATUS") and config.get("MULTI_STATUS") == "false": self.is_active = False elif config.get("GITHUB_STATUS_REPORTER", "true") != "true": self.is_active = False
def load_config_vars(self): # Configuration file name: try first NAME + _FILE_NAME, then LANGUAGE + _FILE_NAME # _CONFIG_FILE = _FILE_NAME (config renaming but keeping config ascending compatibility) if config.exists(self.name + "_CONFIG_FILE"): self.config_file_name = config.get(self.name + "_CONFIG_FILE") elif config.exists(self.descriptor_id + "_CONFIG_FILE"): self.config_file_name = config.get(self.descriptor_id + "_CONFIG_FILE") elif config.exists(self.name + "_FILE_NAME"): self.config_file_name = config.get(self.name + "_FILE_NAME") elif config.exists(self.descriptor_id + "_FILE_NAME"): self.config_file_name = config.get(self.descriptor_id + "_FILE_NAME") # Linter rules path: try first NAME + _RULE_PATH, then LANGUAGE + _RULE_PATH if config.exists(self.name + "_RULES_PATH"): self.linter_rules_path = config.get(self.name + "_RULES_PATH") elif config.exists(self.descriptor_id + "_RULES_PATH"): self.linter_rules_path = config.get(self.descriptor_id + "_RULES_PATH") # Linter config file: # 0: LINTER_DEFAULT set in user config: let the linter find it, do not reference it in cli arguments # 1: http rules path: fetch remove file and copy it locally (then delete it after linting) # 2: repo + config_file_name # 3: linter_rules_path + config_file_name # 4: mega-linter default rules path + config_file_name if (self.config_file_name is not None and self.config_file_name != "LINTER_DEFAULT"): if self.linter_rules_path.startswith("http"): if not self.linter_rules_path.endswith("/"): self.linter_rules_path += "/" remote_config_file = self.linter_rules_path + self.config_file_name local_config_file = self.workspace + os.path.sep + self.config_file_name existing_before = os.path.isfile(local_config_file) try: with urllib.request.urlopen( remote_config_file) as response, open( local_config_file, "wb") as out_file: shutil.copyfileobj(response, out_file) self.config_file_label = remote_config_file if existing_before is False: self.remote_config_file_to_delete = local_config_file except urllib.error.HTTPError as e: self.config_file_error = ( f"Unable to fetch {remote_config_file}\n{str(e)}\n" f" fallback to repository config or Mega-Linter default config" ) except Exception as e: self.config_file_error = ( f"Unable to fetch {remote_config_file}\n{str(e)}\n" f" fallback to repository config or Mega-Linter default config" ) # in repo root (already here or fetched by code above) if os.path.isfile(self.workspace + os.path.sep + self.config_file_name): self.config_file = self.workspace + os.path.sep + self.config_file_name # in user repo ./github/linters folder elif os.path.isfile(self.linter_rules_path + os.path.sep + self.config_file_name): self.config_file = (self.linter_rules_path + os.path.sep + self.config_file_name) # in user repo directory provided in <Linter>RULES_PATH or LINTER_RULES_PATH elif os.path.isfile(self.default_rules_location + os.path.sep + self.config_file_name): self.config_file = (self.default_rules_location + os.path.sep + self.config_file_name) # Set config file label if not set by remote rule if self.config_file is not None and self.config_file_label is None: self.config_file_label = self.config_file.replace( "/tmp/lint", "").replace("/action/lib/.automation/", "") # Include regex :try first NAME + _FILTER_REGEX_INCLUDE, then LANGUAGE + _FILTER_REGEX_INCLUDE if config.exists(self.name + "_FILTER_REGEX_INCLUDE"): self.filter_regex_include = config.get(self.name + "_FILTER_REGEX_INCLUDE") elif config.exists(self.descriptor_id + "_FILTER_REGEX_INCLUDE"): self.filter_regex_include = config.get(self.descriptor_id + "_FILTER_REGEX_INCLUDE") # User arguments from config if config.get(self.name + "_ARGUMENTS", "") != "": self.cli_lint_user_args = config.get_list_args(self.name + "_ARGUMENTS") # Disable errors for this linter NAME + _DISABLE_ERRORS, then LANGUAGE + _DISABLE_ERRORS if config.get(self.name + "_DISABLE_ERRORS_IF_LESS_THAN"): self.disable_errors_if_less_than = int( config.get(self.name + "_DISABLE_ERRORS_IF_LESS_THAN")) if self.disable_errors_if_less_than is not None: self.disable_errors = False elif config.get(self.name + "_DISABLE_ERRORS", "false") == "true": self.disable_errors = True elif config.get(self.descriptor_id + "_DISABLE_ERRORS", "false") == "true": self.disable_errors = True # Exclude regex: try first NAME + _FILTER_REGEX_EXCLUDE, then LANGUAGE + _FILTER_REGEX_EXCLUDE if config.exists(self.name + "_FILTER_REGEX_EXCLUDE"): self.filter_regex_exclude = config.get(self.name + "_FILTER_REGEX_EXCLUDE") elif config.exists(self.descriptor_id + "_FILTER_REGEX_EXCLUDE"): self.filter_regex_exclude = config.get(self.descriptor_id + "_FILTER_REGEX_EXCLUDE") # Override default docker image version if config.exists(self.name + "_DOCKER_IMAGE_VERSION"): self.cli_docker_image_version = config.get(self.name + "_DOCKER_IMAGE_VERSION")
def print_output(output): if config.exists("OUTPUT_DETAILS") and config.get( "OUTPUT_DETAILS") == "detailed": for line in output.splitlines(): print(line)