diff --git a/.github/workflows/package_lint.yml b/.github/workflows/package_lint.yml index 464e3f095b3..820b5a63c3e 100644 --- a/.github/workflows/package_lint.yml +++ b/.github/workflows/package_lint.yml @@ -15,4 +15,7 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 - - run: common/CI/package_checks.py --base=origin/${{ github.event.pull_request.base.ref }} + - run: | + sudo apt-get update + sudo apt-get install python3-ruamel.yaml + common/CI/package_checks.py --base=origin/${{ github.event.pull_request.base.ref }} diff --git a/.github/workflows/script_lint.yml b/.github/workflows/script_lint.yml index b385c58b650..add6b615638 100644 --- a/.github/workflows/script_lint.yml +++ b/.github/workflows/script_lint.yml @@ -33,7 +33,7 @@ jobs: with: path: common/CI common/Hooks common/Scripts/worklog.py python_version: "3.10" - requirements: types-PyYAML + requirements: ruamel.yaml types-PyYAML ShellCheck: name: ShellCheck runs-on: ubuntu-latest diff --git a/common/CI/package_checks.py b/common/CI/package_checks.py index ae4faae0829..a2c47480baa 100755 --- a/common/CI/package_checks.py +++ b/common/CI/package_checks.py @@ -10,12 +10,12 @@ from dataclasses import dataclass from datetime import datetime, timezone from enum import Enum +from ruamel.yaml import YAML +from ruamel.yaml.compat import StringIO from typing import Any, Callable, Dict, List, Optional, TextIO, Tuple, Union from urllib import request from xml.etree import ElementTree -import yaml - """Package is either a Package YML file or Pspec XML file.""" Package = Union['PackageYML', 'PspecXML'] @@ -29,7 +29,9 @@ class PackageYML: """Represents a Package YML file.""" def __init__(self, stream: Any): - self._data = dict(yaml.safe_load(stream)) + yaml = YAML(typ='safe', pure=True) + yaml.default_flow_style = False + self._data = dict(yaml.load(stream)) @property def name(self) -> str: @@ -92,7 +94,8 @@ class Config: @staticmethod def load(stream: Any) -> 'Config': - return Config(**yaml.safe_load(stream)) + yaml = YAML(typ='safe', pure=True) + return Config(**yaml.load(stream)) def __post_init__(self) -> None: self.freeze = FreezeConfig(**self.freeze) # type: ignore @@ -395,7 +398,9 @@ def run(self) -> List[Result]: def _includes_homepage(self, file: str) -> bool: with self._open(file) as f: - return 'homepage' in yaml.safe_load(f) + yaml = YAML(typ='safe', pure=True) + yaml.default_flow_style = False + return 'homepage' in yaml.load(f) class PackageBumped(PullRequestCheck): @@ -453,8 +458,18 @@ def _check_deps(self, deps: str, file: str) -> Optional[Result]: exp = self._sorted(cur) if cur != exp: + class Dumper(YAML): + def dump(self, data: Any, stream: Optional[StringIO] = None, **kw: int) -> Any: + self.default_flow_style = False + self.indent(offset=4, sequence=4) + self.prefix_colon = ' ' # type: ignore[assignment] + stream = StringIO() + YAML.dump(self, data, stream, **kw) + return stream.getvalue() + + yaml = Dumper(typ='safe', pure=True) return Result(file=file, level=self._level, line=self.file_line(file, '^' + deps + r'\s*:'), - message=f'{deps} are not in order, expected: \n' + yaml.safe_dump(exp)) + message=f'{deps} are not in order, expected: \n' + yaml.dump(exp)) return None