Loading gitlabci_local/parsers/gitlab.py +33 −23 Changes for gitlabci_local/parsers/gitlab.py: 33 added lines, 23 removed lines. Original line number Diff line number Diff line Loading @@ -256,15 +256,10 @@ class GitLab: variable_value = str(variable_data) self.__variables.globals[variable] = variable_value # Include, pylint: disable=too-many-locals,too-many-statements # Include def __include(self, data: YAML.Data, stack: List[str], root_directory: Path, working_directory: Path) -> None: # Variables data_additions: YAML.Data file_path: Path include_parent: str = stack[-1] if stack else '' # Parse nested include if data and 'include' in data and data['include']: Loading @@ -289,6 +284,19 @@ class GitLab: # Parse local nodes if 'local' in include_dict: self.__include_local(data, stack, root_directory, working_directory, include_dict) # Parse project node elif 'project' in include_dict: self.__include_project(data, stack, working_directory, include_dict) # Include local, pylint: disable=too-many-arguments,too-many-locals def __include_local(self, data: YAML.Data, stack: List[str], root_directory: Path, working_directory: Path, include_dict: dict) -> None: # Variables include_parent: str = stack[-1] if stack else '' include_path: str = include_dict['local'] # Handle include relative paths Loading @@ -302,10 +310,11 @@ class GitLab: # Already included file if resolved_path in stack: continue return # Existing file inclusion file_path = Path(working_directory) / resolved_path file_paths: Path = Path(working_directory) / resolved_path for file_path in Paths.wildcard(str(file_paths), strict=True): if file_path.is_file(): # Register included file Loading @@ -313,7 +322,7 @@ class GitLab: # Load included file with open(file_path, encoding='utf8', mode='r') as include_data: data_additions = YAML.load(include_data) data_additions: YAML.Data = YAML.load(include_data) if data_additions: # Nested includes (follow working directory) Loading @@ -328,16 +337,19 @@ class GitLab: # Empty included file else: raise SyntaxError( f'Empty "{file_path}" file included in "{include_parent}"' ) f'Empty "{file_path}" file included in "{include_parent}"') # Missing file failure else: raise FileNotFoundError( f'Missing "{file_path}" file included in "{include_parent}"') # Parse project node elif 'project' in include_dict: # Include project def __include_project(self, data: YAML.Data, stack: List[str], working_directory: Path, include_dict: dict) -> None: # Variables include_parent: str = stack[-1] if stack else '' project_path: str = '' project_url: str = include_dict['project'] Loading @@ -346,14 +358,13 @@ class GitLab: local = data[GitLab.LOCAL_NODE] # Acquire local include node if 'include' in local and project_url in local[ 'include'] and isinstance(local['include'][project_url], str): if 'include' in local and project_url in local['include'] and isinstance( local['include'][project_url], str): project_path = local['include'][project_url] # Exclude missing include node if not project_path: continue return # Parse file paths if 'file' in include_dict: Loading @@ -373,16 +384,16 @@ class GitLab: continue # Existing file inclusion file_path = Path(working_directory) / resolved_path file_paths: Path = Path(working_directory) / resolved_path for file_path in Paths.wildcard(str(file_paths), strict=True): if file_path.is_file(): # Register included file stack.append(resolved_path) # Load included file with open(file_path, encoding='utf8', mode='r') as include_data: data_additions = YAML.load(include_data) with open(file_path, encoding='utf8', mode='r') as include_data: data_additions: YAML.Data = YAML.load(include_data) if data_additions: # Nested includes (follow working directory) Loading @@ -407,8 +418,7 @@ class GitLab: # Missing file failure else: raise FileNotFoundError( f'Missing "{file_path}" file included in "{include_parent}"' ) f'Missing "{file_path}" file included in "{include_parent}"') # Local, pylint: disable=too-many-branches,too-many-statements def __local(self, data: YAML.Data) -> None: Loading gitlabci_local/types/paths.py +47 −1 Changes for gitlabci_local/types/paths.py: 47 added lines, 1 removed line. Original line number Diff line number Diff line #!/usr/bin/env python3 # Standard libraries from glob import glob from os.path import expanduser from pathlib import Path, PurePosixPath from typing import Union from typing import List, Union # Components from ..system.platform import Platform from .environment import Environment # Paths class Loading Loading @@ -86,3 +88,47 @@ class Paths: # Result return data # Wildcard @staticmethod def wildcard(path: str, strict: bool = False) -> List[Path]: # Variables paths: List[Path] = [] variants: List[str] = [] # Apply strict wildcards if strict: path = path.replace('**', '*/**') # Generate wildcard variants def wildcard_variants(path): variants: List[str] = [path] if path.startswith('*'): # pragma: no cover variants += ['.' + path] index = path.find(Platform.PATH_SEPARATOR + '*') while index != -1: variants_new = [] for variant in variants: new_variant = variant[:index + 1] + '.' + variant[index + 1:] variants_new.append(new_variant) for variant_new in variants_new: if variant_new not in variants: variants += [variant_new] index = variants[0].find(Platform.PATH_SEPARATOR + '*', index + 1) return variants # Evaluate wildcard variants variants = wildcard_variants(path) # Evaluate wildcards for variant in variants: for item in [Path(item) for item in glob(variant, recursive=True)]: paths += [Path(item)] # Fallback to input if not paths: paths += [Path(path)] # Result return paths tests/includes/.gitlab-ci.local.yml +1 −1 Changes for tests/includes/.gitlab-ci.local.yml: 1 added line, 1 removed line. Original line number Diff line number Diff line include: - local: '/job_local.yml' - local: '/check_local.yml' stages: - includes Loading tests/includes/.gitlab-ci.variables.yml +1 −1 Changes for tests/includes/.gitlab-ci.variables.yml: 1 added line, 1 removed line. Original line number Diff line number Diff line include: '/job_variables.yml' include: '/global_variables.yml' stages: - includes Loading tests/includes/.gitlab-ci.wildcards.local.missing.yml 0 → 100644 +5 −0 Changes for tests/includes/.gitlab-ci.wildcards.local.missing.yml: 5 added lines, 0 removed lines. Original line number Diff line number Diff line include: - local: 'job_*missing.yml' stages: - includes Loading
gitlabci_local/parsers/gitlab.py +33 −23 Changes for gitlabci_local/parsers/gitlab.py: 33 added lines, 23 removed lines. Original line number Diff line number Diff line Loading @@ -256,15 +256,10 @@ class GitLab: variable_value = str(variable_data) self.__variables.globals[variable] = variable_value # Include, pylint: disable=too-many-locals,too-many-statements # Include def __include(self, data: YAML.Data, stack: List[str], root_directory: Path, working_directory: Path) -> None: # Variables data_additions: YAML.Data file_path: Path include_parent: str = stack[-1] if stack else '' # Parse nested include if data and 'include' in data and data['include']: Loading @@ -289,6 +284,19 @@ class GitLab: # Parse local nodes if 'local' in include_dict: self.__include_local(data, stack, root_directory, working_directory, include_dict) # Parse project node elif 'project' in include_dict: self.__include_project(data, stack, working_directory, include_dict) # Include local, pylint: disable=too-many-arguments,too-many-locals def __include_local(self, data: YAML.Data, stack: List[str], root_directory: Path, working_directory: Path, include_dict: dict) -> None: # Variables include_parent: str = stack[-1] if stack else '' include_path: str = include_dict['local'] # Handle include relative paths Loading @@ -302,10 +310,11 @@ class GitLab: # Already included file if resolved_path in stack: continue return # Existing file inclusion file_path = Path(working_directory) / resolved_path file_paths: Path = Path(working_directory) / resolved_path for file_path in Paths.wildcard(str(file_paths), strict=True): if file_path.is_file(): # Register included file Loading @@ -313,7 +322,7 @@ class GitLab: # Load included file with open(file_path, encoding='utf8', mode='r') as include_data: data_additions = YAML.load(include_data) data_additions: YAML.Data = YAML.load(include_data) if data_additions: # Nested includes (follow working directory) Loading @@ -328,16 +337,19 @@ class GitLab: # Empty included file else: raise SyntaxError( f'Empty "{file_path}" file included in "{include_parent}"' ) f'Empty "{file_path}" file included in "{include_parent}"') # Missing file failure else: raise FileNotFoundError( f'Missing "{file_path}" file included in "{include_parent}"') # Parse project node elif 'project' in include_dict: # Include project def __include_project(self, data: YAML.Data, stack: List[str], working_directory: Path, include_dict: dict) -> None: # Variables include_parent: str = stack[-1] if stack else '' project_path: str = '' project_url: str = include_dict['project'] Loading @@ -346,14 +358,13 @@ class GitLab: local = data[GitLab.LOCAL_NODE] # Acquire local include node if 'include' in local and project_url in local[ 'include'] and isinstance(local['include'][project_url], str): if 'include' in local and project_url in local['include'] and isinstance( local['include'][project_url], str): project_path = local['include'][project_url] # Exclude missing include node if not project_path: continue return # Parse file paths if 'file' in include_dict: Loading @@ -373,16 +384,16 @@ class GitLab: continue # Existing file inclusion file_path = Path(working_directory) / resolved_path file_paths: Path = Path(working_directory) / resolved_path for file_path in Paths.wildcard(str(file_paths), strict=True): if file_path.is_file(): # Register included file stack.append(resolved_path) # Load included file with open(file_path, encoding='utf8', mode='r') as include_data: data_additions = YAML.load(include_data) with open(file_path, encoding='utf8', mode='r') as include_data: data_additions: YAML.Data = YAML.load(include_data) if data_additions: # Nested includes (follow working directory) Loading @@ -407,8 +418,7 @@ class GitLab: # Missing file failure else: raise FileNotFoundError( f'Missing "{file_path}" file included in "{include_parent}"' ) f'Missing "{file_path}" file included in "{include_parent}"') # Local, pylint: disable=too-many-branches,too-many-statements def __local(self, data: YAML.Data) -> None: Loading
gitlabci_local/types/paths.py +47 −1 Changes for gitlabci_local/types/paths.py: 47 added lines, 1 removed line. Original line number Diff line number Diff line #!/usr/bin/env python3 # Standard libraries from glob import glob from os.path import expanduser from pathlib import Path, PurePosixPath from typing import Union from typing import List, Union # Components from ..system.platform import Platform from .environment import Environment # Paths class Loading Loading @@ -86,3 +88,47 @@ class Paths: # Result return data # Wildcard @staticmethod def wildcard(path: str, strict: bool = False) -> List[Path]: # Variables paths: List[Path] = [] variants: List[str] = [] # Apply strict wildcards if strict: path = path.replace('**', '*/**') # Generate wildcard variants def wildcard_variants(path): variants: List[str] = [path] if path.startswith('*'): # pragma: no cover variants += ['.' + path] index = path.find(Platform.PATH_SEPARATOR + '*') while index != -1: variants_new = [] for variant in variants: new_variant = variant[:index + 1] + '.' + variant[index + 1:] variants_new.append(new_variant) for variant_new in variants_new: if variant_new not in variants: variants += [variant_new] index = variants[0].find(Platform.PATH_SEPARATOR + '*', index + 1) return variants # Evaluate wildcard variants variants = wildcard_variants(path) # Evaluate wildcards for variant in variants: for item in [Path(item) for item in glob(variant, recursive=True)]: paths += [Path(item)] # Fallback to input if not paths: paths += [Path(path)] # Result return paths
tests/includes/.gitlab-ci.local.yml +1 −1 Changes for tests/includes/.gitlab-ci.local.yml: 1 added line, 1 removed line. Original line number Diff line number Diff line include: - local: '/job_local.yml' - local: '/check_local.yml' stages: - includes Loading
tests/includes/.gitlab-ci.variables.yml +1 −1 Changes for tests/includes/.gitlab-ci.variables.yml: 1 added line, 1 removed line. Original line number Diff line number Diff line include: '/job_variables.yml' include: '/global_variables.yml' stages: - includes Loading
tests/includes/.gitlab-ci.wildcards.local.missing.yml 0 → 100644 +5 −0 Changes for tests/includes/.gitlab-ci.wildcards.local.missing.yml: 5 added lines, 0 removed lines. Original line number Diff line number Diff line include: - local: 'job_*missing.yml' stages: - includes