1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
"""Implementation of meta-runtime rule."""
from __future__ import annotations
import sys
from typing import TYPE_CHECKING
from packaging.specifiers import SpecifierSet
from ansiblelint.rules import AnsibleLintRule
# Copyright (c) 2018, Ansible Project
if TYPE_CHECKING:
from typing import Any
from ansiblelint.errors import MatchError
from ansiblelint.file_utils import Lintable
class CheckRequiresAnsibleVersion(AnsibleLintRule):
"""Required ansible version in meta/runtime.yml must be a supported version."""
id = "meta-runtime"
description = (
"The ``requires_ansible`` key in runtime.yml must specify "
"a supported platform version of ansible-core and be a valid version."
)
severity = "VERY_HIGH"
tags = ["metadata"]
version_added = "v6.11.0 (last update)"
# Refer to https://access.redhat.com/support/policy/updates/ansible-automation-platform
# Also add devel to this list
supported_ansible = ["2.9.10", "2.11.", "2.12.", "2.13.", "2.14.", "2.15."]
def matchyaml(self, file: Lintable) -> list[MatchError]:
"""Find violations inside meta files.
:param file: Input lintable file that is a match for `meta-runtime`
:returns: List of errors matched to the input file
"""
results = []
if file.kind != "meta-runtime":
return []
version_required = file.data.get("requires_ansible", None)
if version_required:
if not any(
version in version_required for version in self.supported_ansible
):
results.append(
self.create_matcherror(
message="requires_ansible key must be set to a supported version.",
tag="meta-runtime[unsupported-version]",
filename=file,
)
)
try:
SpecifierSet(version_required)
except ValueError:
results.append(
self.create_matcherror(
message="'requires_ansible' is not a valid requirement specification",
tag="meta-runtime[invalid-version]",
filename=file,
)
)
return results
return []
# testing code to be loaded only with pytest or when executed the rule file
if "pytest" in sys.modules:
import pytest
from ansiblelint.rules import RulesCollection # pylint: disable=ungrouped-imports
from ansiblelint.runner import Runner # pylint: disable=ungrouped-imports
@pytest.mark.parametrize(
("test_file", "failures", "tags"),
(
pytest.param(
"examples/meta_runtime_version_checks/pass/meta/runtime.yml",
0,
"meta-runtime[unsupported-version]",
id="pass",
),
pytest.param(
"examples/meta_runtime_version_checks/fail_0/meta/runtime.yml",
1,
"meta-runtime[unsupported-version]",
id="fail0",
),
pytest.param(
"examples/meta_runtime_version_checks/fail_1/meta/runtime.yml",
1,
"meta-runtime[unsupported-version]",
id="fail1",
),
pytest.param(
"examples/meta_runtime_version_checks/fail_2/meta/runtime.yml",
1,
"meta-runtime[invalid-version]",
id="fail2",
),
),
)
def test_meta_supported_version(
default_rules_collection: RulesCollection,
test_file: str,
failures: int,
tags: str,
) -> None:
"""Test rule matches."""
default_rules_collection.register(CheckRequiresAnsibleVersion())
results = Runner(test_file, rules=default_rules_collection).run()
for result in results:
assert result.rule.id == CheckRequiresAnsibleVersion().id
assert result.tag == tags
assert len(results) == failures
|