Verified Commit a58ea9d6 authored by Adrian DC's avatar Adrian DC
Browse files

feat(gitlab): implement YAML support for GitLab 'components'

Issue: #277
---

Signed-off-by: default avatarAdrian DC <radian.dc@gmail.com>
parent 661e2e05
Loading
Loading
Loading
Loading
Loading
+90 −0
Changes for src/parsers/gitlab.py: 90 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -351,6 +351,16 @@ class GitLab:
                        parent_path,
                    )

                # Parse component node
                elif 'component' in include_dict:
                    GitLab.__include_component(
                        data,
                        stack,
                        working_directory,
                        include_dict,
                        parent_path,
                    )

    # Include local, pylint: disable=too-many-arguments,too-many-locals,too-many-positional-arguments
    @staticmethod
    def __include_local(
@@ -515,6 +525,86 @@ class GitLab:
                    raise FileNotFoundError(
                        f'Missing "{file_path}" file included in "{parent_path}"')

    # Include component
    @staticmethod
    def __include_component(
        data: YAML.Data,
        stack: List[str],
        working_directory: Path,
        include_dict: dict, # type: ignore[type-arg]
        parent_path: str,
    ) -> None:

        # Variables
        component_path: str = ''
        component_url: str = include_dict['component']

        # Acquire local node
        if GitLab.LOCAL_NODE in data and data[GitLab.LOCAL_NODE]:
            local = data[GitLab.LOCAL_NODE]

            # Acquire local include node
            if 'include' in local and component_url in local['include'] and isinstance(
                    local['include'][component_url], str):
                component_path = local['include'][component_url]

        # Exclude missing include node
        if not component_path:
            return

        # Parse inputs
        file_inputs: YAML.Data = {}
        if 'inputs' in include_dict and isinstance(include_dict['inputs'], dict):
            file_inputs = include_dict['inputs']

        # Already included file
        resolved_path = Paths.resolve(working_directory / component_path)
        if resolved_path in stack:
            return

        # Existing file inclusion
        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: Optional[YAML.Data] = YAML.load(
                        include_data,
                        inputs=file_inputs,
                    )
                    if data_additions:

                        # Nested includes (follow working directory)
                        component_working_directory: Path = Path(
                            working_directory) / Paths.resolve(
                                working_directory / component_path)
                        GitLab.__include(
                            data_additions,
                            stack,
                            component_working_directory,
                            component_working_directory,
                            str(file_path),
                        )

                        # Agregate data
                        GitLab.__merges(data_additions, data)
                        data.clear()
                        data.update(data_additions)

                    # Empty included file
                    else:
                        raise SyntaxError(
                            f'Empty "{file_path}" file included in "{parent_path}"')

            # Missing file failure
            else:
                raise FileNotFoundError(
                    f'Missing "{file_path}" file included in "{parent_path}"')

    # Local, pylint: disable=too-many-branches,too-many-statements
    @staticmethod
    def __local(
+14 −0
Changes for tests/inputs/.gitlab-ci.component.duplicates.yml: 14 added lines, 0 removed lines.
Original line number Diff line number Diff line
include:
  - component: gitlab.com/RadianDevCore/tools/gcil/component@1.2.3
    inputs:
      stage: components
  - component: gitlab.com/RadianDevCore/tools/gcil/component@1.2.3
    inputs:
      stage: components

stages:
  - components

.local:
  include:
    'gitlab.com/RadianDevCore/tools/gcil/component@1.2.3': '.gitlab-ci.d/test/templates/component.yml'
+9 −0
Changes for tests/inputs/.gitlab-ci.component.empty.yml: 9 added lines, 0 removed lines.
Original line number Diff line number Diff line
include:
  - component: gitlab.com/RadianDevCore/tools/gcil/empty@1.2.3

stages:
  - components

.local:
  include:
    'gitlab.com/RadianDevCore/tools/gcil/empty@1.2.3': '.gitlab-ci.d/test/templates/documents.0.yml'
+5 −0
Changes for tests/inputs/.gitlab-ci.component.missing.yml: 5 added lines, 0 removed lines.
Original line number Diff line number Diff line
include:
  - component: gitlab.com/RadianDevCore/tools/gcil/missing@1.2.3

stages:
  - components
+11 −0
Changes for tests/inputs/.gitlab-ci.component.notfound.yml: 11 added lines, 0 removed lines.
Original line number Diff line number Diff line
include:
  - component: gitlab.com/RadianDevCore/tools/gcil/component@1.2.3
    inputs:
      stage: components

stages:
  - components

.local:
  include:
    'gitlab.com/RadianDevCore/tools/gcil/component@1.2.3': '/templates/notfound.yml'
Loading