From 9c2b672f964458e63cc7cc84ceae51cfc3feac25 Mon Sep 17 00:00:00 2001 From: Sorin Sbarnea Date: Sat, 13 Mar 2021 09:26:09 +0000 Subject: [PATCH] Add ability to recognize base file types (#1461) --- examples/galaxy.yml | 14 ++++++++++++++ src/ansiblelint/config.py | 18 ++++++++++++++++++ src/ansiblelint/file_utils.py | 21 +++++++++++++++++---- src/ansiblelint/rules/YamllintRule.py | 2 +- test/TestUtils.py | 1 + 5 files changed, 51 insertions(+), 5 deletions(-) create mode 100644 examples/galaxy.yml diff --git a/examples/galaxy.yml b/examples/galaxy.yml new file mode 100644 index 0000000000..2d314cc14f --- /dev/null +++ b/examples/galaxy.yml @@ -0,0 +1,14 @@ +name: foo +namespace: bar +version: 1.2.3 +authors: + - John +readme: ../README.md +description: ... +dependencies: + "other_namespace.collection1": ">=1.0.0" + "other_namespace.collection2": ">=2.0.0,<3.0.0" + "anderson55.my_collection": "*" # note: "*" selects the highest version available +license: + - GPL + - Apache diff --git a/src/ansiblelint/config.py b/src/ansiblelint/config.py index a57acdec9c..1ffb2b30f1 100644 --- a/src/ansiblelint/config.py +++ b/src/ansiblelint/config.py @@ -14,6 +14,8 @@ DEFAULT_KINDS = [ # Do not sort this list, order matters. {"requirements": "**/meta/requirements.yml"}, # v1 only + # https://docs.ansible.com/ansible/latest/dev_guide/collections_galaxy_meta.html + {"galaxy": "**/galaxy.yml"}, # Galaxy collection meta {"reno": "**/releasenotes/*/*.{yaml,yml}"}, # reno release notes {"playbook": "**/playbooks/*.{yml,yaml}"}, {"playbook": "**/*playbook*.{yml,yaml}"}, @@ -29,10 +31,26 @@ {"yaml": "**/molecule/*/{base,molecule}.{yaml,yml}"}, # molecule config {"requirements": "**/requirements.yml"}, # v2 and v1 {"playbook": "**/molecule/*/*.{yaml,yml}"}, # molecule playbooks + {"yaml": "**/{.ansible-lint,.yamllint}"}, {"yaml": "**/*.{yaml,yml}"}, {"yaml": "**/.*.{yaml,yml}"}, ] +BASE_KINDS = [ + # These assignations are only for internal use and are only inspired by + # MIME/IANA model. Their purpose is to be able to process a file based on + # it type, including generic processing of text files using the prefix. + {"text/json": "**/*.json"}, # standardized + {"text/markdown": "**/*.md"}, # https://tools.ietf.org/html/rfc7763 + {"text/rst": "**/*.rst"}, # https://en.wikipedia.org/wiki/ReStructuredText + {"text/ini": "**/*.ini"}, + # YAML has no official IANA assignation + {"text/yaml": "**/{.ansible-lint,.yamllint}"}, + {"text/yaml": "**/*.{yaml,yml}"}, + {"text/yaml": "**/.*.{yaml,yml}"}, +] + + options = Namespace( colored=True, cwd=".", diff --git a/src/ansiblelint/file_utils.py b/src/ansiblelint/file_utils.py index adc5237353..575286d1f1 100644 --- a/src/ansiblelint/file_utils.py +++ b/src/ansiblelint/file_utils.py @@ -13,7 +13,7 @@ import wcmatch.pathlib -from ansiblelint.config import options +from ansiblelint.config import BASE_KINDS, options from ansiblelint.constants import FileType if TYPE_CHECKING: @@ -67,12 +67,17 @@ def expand_paths_vars(paths: List[str]) -> List[str]: return paths -def kind_from_path(path: Path) -> str: - """Determine the file kind based on its name.""" +def kind_from_path(path: Path, base=False) -> str: + """Determine the file kind based on its name. + + When called with base=True, it will return the base file type instead + of the explicit one. That is expected to return 'yaml' for any yaml files. + """ # pathlib.Path.match patterns are very limited, they do not support *a*.yml # glob.glob supports **/foo.yml but not multiple extensions pathex = wcmatch.pathlib.PurePath(path.absolute().resolve()) - for entry in options.kinds: + kinds = options.kinds if not base else BASE_KINDS + for entry in kinds: for k, v in entry.items(): if pathex.globmatch( v, @@ -83,6 +88,11 @@ def kind_from_path(path: Path) -> str: ), ): return str(k) + + if base: + # Unknown base file type is default + return "" + if path.is_dir(): return "role" @@ -146,6 +156,9 @@ def __init__( else: self.dir = str(self.path.parent.resolve()) + # determine base file kind (yaml, xml, ini, ...) + self.base_kind = kind_from_path(self.path, base=True) + def __getitem__(self, key: Any) -> Any: """Provide compatibility subscriptable support.""" if key == 'path': diff --git a/src/ansiblelint/rules/YamllintRule.py b/src/ansiblelint/rules/YamllintRule.py index 31363db76b..14708a2b44 100644 --- a/src/ansiblelint/rules/YamllintRule.py +++ b/src/ansiblelint/rules/YamllintRule.py @@ -76,7 +76,7 @@ def matchyaml(self, file: Lintable) -> List["MatchError"]: """Return matches found for a specific YAML text.""" matches: List["MatchError"] = [] filtered_matches = [] - if file.kind == 'role': + if file.base_kind != 'text/yaml': return matches if YamllintRule.config: diff --git a/test/TestUtils.py b/test/TestUtils.py index 5eaed2f3a0..20e5e9ee0f 100644 --- a/test/TestUtils.py +++ b/test/TestUtils.py @@ -364,6 +364,7 @@ def test_is_playbook(): "../roles/geerlingguy.mysql/tasks/configure.yml", "tasks", ), # relative path involved + ("galaxy.yml", "galaxy"), ), ) def test_default_kinds(monkeypatch, path: str, kind: FileType) -> None: