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

feat(yaml): implement YAML document with 'spec: inputs:' defaults

Issue: #277
---

Signed-off-by: default avatarAdrian DC <radian.dc@gmail.com>
parent 1e4d7b37
Loading
Loading
Loading
Loading
Loading
+65 −0
Changes for src/types/yaml.py: 65 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@
# Standard libraries
from copy import deepcopy
from io import TextIOWrapper
from re import sub as regex_sub
from sys import maxsize
from typing import Any, Dict, List, Optional

@@ -98,6 +99,64 @@ class YAML:
            # Result
            return changed

    # Parse spec inputs
    @staticmethod
    def parse_spec_inputs(spec: Data, file_path: str) -> Dict[str, str]:

        # Variables
        inputs: Dict[str, str] = {}

        # Validate YAML spec syntax
        if 'spec' not in spec or 'inputs' not in spec['spec']:
            return inputs

        # Parse YAML spec inputs
        for key, value in spec['spec']['inputs'].items():
            if isinstance(value, dict) and 'default' in value and isinstance(
                    value['default'], str):
                inputs[key] = str(value.get('default'))
            else:
                raise SyntaxError(f'Missing value for input \'{key}\' in \'{file_path}\'')

        # Result
        return inputs

    # Evaluate string
    @staticmethod
    def evaluate_spec_field(field: str, inputs: Dict[str, str]) -> str:

        # Variables
        result: str = field

        # Evaluate inputs
        for variable, value in inputs.items():
            result = regex_sub(fr'\$\[\[\s*inputs\.{variable}\s*\]\]', value, result)

        # Result
        return result

    # Evaluate spec
    @staticmethod
    def evaluate_spec(data: Data, inputs: Dict[str, str]) -> Data:

        # Recurse on keys
        if isinstance(data, dict):
            return {
                YAML.evaluate_spec_field(key, inputs): YAML.evaluate_spec(value, inputs)
                for key, value in data.items()
            }

        # Recurse on items
        if isinstance(data, list):
            return [YAML.evaluate_spec(value, inputs) for value in data]

        # Evaluate string items
        if isinstance(data, str):
            return YAML.evaluate_spec_field(data, inputs)

        # Fallback
        return data # pragma: no cover

    # Load
    @staticmethod
    def load(stream: TextIOWrapper) -> Optional[Data]:
@@ -105,6 +164,7 @@ class YAML:
        # Variables
        data: Optional[YAML.Data]
        documents: List[YAML.Data]
        inputs: Dict[str, str]

        # Prepare loader class
        loader = yaml_SafeLoader
@@ -121,6 +181,11 @@ class YAML:
        elif len(documents) == 1:
            data = documents[0]

        # Acquire YAML component data
        elif len(documents) == 2:
            inputs = YAML.parse_spec_inputs(documents[0], stream.name)
            data = YAML.evaluate_spec(documents[1], inputs)

        # Unsupport YAML data
        else:
            raise SyntaxError(
+14 −0
Changes for tests/components/.gitlab-ci.d/test/templates/component.yml: 14 added lines, 0 removed lines.
Original line number Diff line number Diff line
spec:
  inputs:
    stage:
      default: test
      description: 'Defines the commits job name (Default: commits)'
    name:
      default: component
      description: 'Defines the commits stage (Default: test)'
---

$[[ inputs.name ]]:
  stage: $[[ inputs.stage ]]
  script:
    - echo ' [Job] Component'
+0 −0

Empty file added.

+10 −0
Changes for tests/components/.gitlab-ci.d/test/templates/documents.3.yml: 10 added lines, 0 removed lines.
Original line number Diff line number Diff line
stages:
  - components
---

stages:
  - components
---

stages:
  - components
+12 −0
Changes for tests/components/.gitlab-ci.d/test/templates/mandatory.yml: 12 added lines, 0 removed lines.
Original line number Diff line number Diff line
spec:
  inputs:
    stage:
      description: 'Defines the commits job name (Default: commits)'
    name:
      description: 'Defines the commits stage (Default: test)'
---

$[[ inputs.name ]]:
  stage: $[[ inputs.stage ]]
  script:
    - echo ' [Job] Component'
Loading