Skip to content

Commit 9fd8947

Browse files
KB-perBytepre-commit-ci[bot]ssbarnea
authored
Add rule to verify that galaxy.yml collection version is present and >= 1.0.0 (#2383)
* add rule * chore: auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Some linting fixes * fixed linting errors * Renamed rule to galaxy * chore: auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Sorin Sbarnea <[email protected]>
1 parent ef90bc0 commit 9fd8947

File tree

6 files changed

+165
-3
lines changed

6 files changed

+165
-3
lines changed

.github/workflows/tox.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ jobs:
166166
WSLENV: FORCE_COLOR:PYTEST_REQPASS:TOXENV:TOX_PARALLEL_NO_SPINNER
167167
# Number of expected test passes, safety measure for accidental skip of
168168
# tests. Update value if you add/remove tests.
169-
PYTEST_REQPASS: 703
169+
PYTEST_REQPASS: 705
170170

171171
steps:
172172
- name: Activate WSL1

examples/meta/galaxy.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
name: foo
3+
namespace: bar
4+
version: 0.2.3 # <-- that version is not valid, should be 1.0.0 or greater
5+
authors:
6+
- John
7+
readme: ../README.md
8+
description: "..."
9+
dependencies:
10+
other_namespace.collection1: ">=1.0.0"
11+
other_namespace.collection2: ">=2.0.0,<3.0.0"
12+
anderson55.my_collection: "*" # note: "*" selects the highest version available
13+
license:
14+
- Apache-2.0

src/ansiblelint/rules/galaxy.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# galaxy
2+
3+
This rule identifies if the collection version mentioned in galaxy.yml is ideal in terms of the version number being greater than or equal to `1.0.0`.
4+
5+
This rule can produce messages such:
6+
7+
- `galaxy[version-missing]` - `galaxy.yaml` should have version tag.
8+
- `galaxy[version-incorrect]` - collection version should be greater than or equal to `1.0.0`
9+
10+
If you want to ignore some of the messages above, you can add any of them to
11+
the `ignore_list`.
12+
13+
## Problematic code
14+
15+
```yaml
16+
# galaxy.yml
17+
---
18+
name: foo
19+
namespace: bar
20+
version: 0.2.3 # <-- collection version should be >= 1.0.0
21+
authors:
22+
- John
23+
readme: ../README.md
24+
description: "..."
25+
```
26+
27+
## Correct code
28+
29+
```yaml
30+
# galaxy.yml
31+
---
32+
name: foo
33+
namespace: bar
34+
version: 1.0.0
35+
authors:
36+
- John
37+
readme: ../README.md
38+
description: "..."
39+
```

src/ansiblelint/rules/galaxy.py

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
"""Implementation of GalaxyRule."""
2+
from __future__ import annotations
3+
4+
import sys
5+
from functools import total_ordering
6+
from typing import TYPE_CHECKING, Any
7+
8+
from ansiblelint.errors import MatchError
9+
from ansiblelint.rules import AnsibleLintRule
10+
from ansiblelint.utils import LINE_NUMBER_KEY
11+
12+
if TYPE_CHECKING:
13+
from typing import Optional
14+
15+
from ansiblelint.constants import odict
16+
from ansiblelint.file_utils import Lintable
17+
18+
19+
class GalaxyRule(AnsibleLintRule):
20+
"""Rule for checking collection version is greater than 1.0.0."""
21+
22+
id = "galaxy"
23+
description = "Confirm via galaxy.yml file if collection version is greater than or equal to 1.0.0"
24+
severity = "MEDIUM"
25+
tags = ["metadata"]
26+
version_added = "v6.5.0 (last update)"
27+
28+
def matchplay(self, file: Lintable, data: odict[str, Any]) -> list[MatchError]:
29+
"""Return matches found for a specific play (entry in playbook)."""
30+
if file.kind != "galaxy": # type: ignore
31+
return []
32+
if "version" not in data:
33+
return [
34+
self.create_matcherror(
35+
message="galaxy.yaml should have version tag.",
36+
linenumber=data[LINE_NUMBER_KEY],
37+
tag="galaxy[version-missing]",
38+
filename=file,
39+
)
40+
]
41+
if Version(data.get("version")) < Version("1.0.0"):
42+
return [
43+
self.create_matcherror(
44+
message="collection version should be greater than or equal to 1.0.0",
45+
linenumber=data[LINE_NUMBER_KEY],
46+
tag="galaxy[version-incorrect]",
47+
filename=file,
48+
)
49+
]
50+
return []
51+
52+
53+
@total_ordering
54+
class Version:
55+
"""Simple class to compare arbitrary versions."""
56+
57+
def __init__(self, version_string: str):
58+
"""Construct a Version object."""
59+
self.components = version_string.split(".")
60+
61+
def __eq__(self, other: object) -> bool:
62+
"""Implement equality comparison."""
63+
other = _coerce(other)
64+
if not isinstance(other, Version):
65+
return NotImplemented
66+
67+
return self.components == other.components
68+
69+
def __lt__(self, other: Version) -> bool:
70+
"""Implement lower-than operation."""
71+
other = _coerce(other)
72+
if not isinstance(other, Version):
73+
return NotImplemented
74+
75+
return self.components < other.components
76+
77+
78+
def _coerce(other: object) -> Version:
79+
if isinstance(other, str):
80+
other = Version(other)
81+
if isinstance(other, (int, float)):
82+
other = Version(str(other))
83+
if isinstance(other, Version):
84+
return other
85+
raise NotImplementedError(f"Unable to coerce object type {type(other)} to Version")
86+
87+
88+
if "pytest" in sys.modules: # noqa: C901
89+
90+
from ansiblelint.rules import RulesCollection
91+
from ansiblelint.runner import Runner
92+
93+
def test_galaxy_collection_version_positive() -> None:
94+
"""Positive test for collection version in galaxy."""
95+
collection = RulesCollection()
96+
collection.register(GalaxyRule())
97+
success = "examples/galaxy.yml"
98+
good_runner = Runner(success, rules=collection)
99+
assert [] == good_runner.run()
100+
101+
def test_galaxy_collection_version_negative() -> None:
102+
"""Negative test for collection version in galaxy."""
103+
collection = RulesCollection()
104+
collection.register(GalaxyRule())
105+
failure = "examples/meta/galaxy.yml"
106+
bad_runner = Runner(failure, rules=collection)
107+
errs = bad_runner.run()
108+
assert len(errs) == 1

src/ansiblelint/schemas/ansible-lint-config.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@
9595
"empty-string-compare",
9696
"fqcn-builtins",
9797
"latest",
98+
"galaxy-collection-version",
9899
"ignore-errors",
99100
"inline-env-var",
100101
"internal-error",

test/test_rules_collection.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,5 +166,5 @@ def test_rules_id_format() -> None:
166166
rule.help != "" or rule.description or rule.__doc__
167167
), f"Rule {rule.id} must have at least one of: .help, .description, .__doc__"
168168
assert "yaml" in keys, "yaml rule is missing"
169-
assert len(rules) == 41 # update this number when adding new rules!
170-
assert len(keys) == 41, "Duplicate rule ids?"
169+
assert len(rules) == 42 # update this number when adding new rules!
170+
assert len(keys) == 42, "Duplicate rule ids?"

0 commit comments

Comments
 (0)