Skip to content

Commit 76317f1

Browse files
authored
Mark galaxy rule as required only for shared profile (#2441)
- makes galaxy rule opt-in, so it would not be executed when a profile is not selected - adds galaxy rule to shared profile, so we check requirements when before uploading (production profile inherits shared one)
1 parent 9614067 commit 76317f1

File tree

7 files changed

+51
-22
lines changed

7 files changed

+51
-22
lines changed

src/ansiblelint/__main__.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -192,18 +192,13 @@ def main(argv: list[str] | None = None) -> int: # noqa: C901
192192
from ansiblelint.rules import RulesCollection
193193
from ansiblelint.runner import _get_matches
194194

195-
rules = RulesCollection(options.rulesdirs)
195+
rules = RulesCollection(options.rulesdirs, profile=options.profile)
196196

197197
if options.profile == []:
198198
from ansiblelint.generate_docs import profiles_as_rich
199199

200200
console.print(profiles_as_rich())
201201
return 0
202-
if options.profile:
203-
from ansiblelint.rules import filter_rules_with_profile
204-
205-
filter_rules_with_profile(rules, options.profile[0])
206-
# When profile is mentioned, we filter-out the rules based on it
207202

208203
if options.listrules or options.listtags:
209204
return _do_list(rules)

src/ansiblelint/data/profiles.yml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,14 @@ shared:
7272
extends: safety
7373
description: >
7474
The shared profile is for those that want to publish their content, roles
75-
or collection to either [galaxy](https://galaxy.ansible.com) or to another
76-
automation-hub instance. In addition to all the rules related to packaging
77-
and publishing, like metadata checks, this also includes some rules that
78-
are known to be good practices for keeping the code readable and
75+
or collection to either [galaxy.ansible.com](https://galaxy.ansible.com),
76+
[automation-hub](https://console.redhat.com/ansible/automation-hub) or
77+
another private instance of these. In addition to all the rules related to
78+
packaging and publishing, like metadata checks, this also includes some
79+
rules that are known to be good practices for keeping the code readable and
7980
maintainable.
8081
rules:
82+
galaxy: # <-- applies to both galaxy and automation-hub
8183
ignore-errors:
8284
layout:
8385
url: https://github.com/ansible/ansible-lint/issues/1900

src/ansiblelint/generate_docs.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,12 @@ def profiles_as_md(header: bool = False, docs_url: str = RULE_DOC_URL) -> str:
144144
The rules that have a `*` suffix, are not implemented yet but we documented
145145
them with links to their issues.
146146
147+
```{note}
148+
Special rule tags such `opt-in` and `experimental` are automatically removed
149+
when a rule is included in a profile, directly or indirectly. This means that
150+
they will always execute once included.
151+
```
152+
147153
"""
148154

149155
for name, profile in PROFILES.items():

src/ansiblelint/rules/__init__.py

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -364,9 +364,12 @@ def __init__(
364364
self,
365365
rulesdirs: list[str] | None = None,
366366
options: Namespace = default_options,
367+
profile: list[str] | None = None,
368+
conditional: bool = True,
367369
) -> None:
368370
"""Initialize a RulesCollection instance."""
369371
self.options = options
372+
self.profile = profile or []
370373
if rulesdirs is None:
371374
rulesdirs = []
372375
self.rulesdirs = expand_paths_vars(rulesdirs)
@@ -377,15 +380,21 @@ def __init__(
377380
[RuntimeErrorRule(), AnsibleParserErrorRule(), LoadingFailureRule()]
378381
)
379382
for rule in load_plugins(rulesdirs):
380-
self.register(rule)
383+
self.register(rule, conditional=conditional)
381384
self.rules = sorted(self.rules)
382385

383-
def register(self, obj: AnsibleLintRule) -> None:
386+
# when we have a profile we unload some of the rules
387+
if self.profile:
388+
filter_rules_with_profile(self.rules, self.profile[0])
389+
390+
def register(self, obj: AnsibleLintRule, conditional: bool = False) -> None:
384391
"""Register a rule."""
385392
# We skip opt-in rules which were not manually enabled.
386393
# But we do include opt-in rules when listing all rules or tags
387394
if any(
388395
[
396+
not conditional,
397+
self.profile, # when profile is used we load all rules and filter later
389398
"opt-in" not in obj.tags,
390399
obj.id in self.options.enable_list,
391400
self.options.listrules,
@@ -497,19 +506,36 @@ def listtags(self) -> str:
497506
return result
498507

499508

500-
def filter_rules_with_profile(rule_col: RulesCollection, profile: str) -> None:
509+
def filter_rules_with_profile(rule_col: list[BaseRule], profile: str) -> None:
501510
"""Unload rules that are not part of the specified profile."""
502511
included = set()
503512
extends = profile
513+
total_rules = len(rule_col)
504514
while extends:
505515
for rule in PROFILES[extends]["rules"]:
516+
_logger.debug("Activating rule `%s` due to profile `%s`", rule, extends)
506517
included.add(rule)
507518
extends = PROFILES[extends].get("extends", None)
508-
for rule in list(rule_col.rules):
519+
for rule in rule_col:
509520
if rule.id not in included:
510521
_logger.debug(
511522
"Unloading %s rule due to not being part of %s profile.",
512523
rule.id,
513524
profile,
514525
)
515-
rule_col.rules.remove(rule)
526+
rule_col.remove(rule)
527+
else:
528+
for tag in ("opt-in", "experimental"):
529+
if tag in rule.tags:
530+
_logger.debug(
531+
"Removing tag `%s` from `%s` rule because `%s` profile makes it mandatory.",
532+
tag,
533+
rule.id,
534+
profile,
535+
)
536+
rule.tags.remove(tag)
537+
# rule_col.rules.remove(rule)
538+
# break
539+
if "opt-in" in rule.tags:
540+
rule.tags.remove("opt-in")
541+
_logger.debug("%s/%s rules included in the profile", len(rule_col), total_rules)

src/ansiblelint/rules/galaxy.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ class GalaxyRule(AnsibleLintRule):
2222
id = "galaxy"
2323
description = "Confirm via galaxy.yml file if collection version is greater than or equal to 1.0.0"
2424
severity = "MEDIUM"
25-
tags = ["metadata"]
26-
version_added = "v6.5.0 (last update)"
25+
tags = ["metadata", "opt-in", "experimental"]
26+
version_added = "v6.6.0 (last update)"
2727

2828
def matchplay(self, file: Lintable, data: odict[str, Any]) -> list[MatchError]:
2929
"""Return matches found for a specific play (entry in playbook)."""

test/test_profiles.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def test_profile_min() -> None:
1717
collection.register(ShellWithoutPipefail())
1818
assert len(collection.rules) == 4, "Failed to register new rule."
1919

20-
filter_rules_with_profile(collection, "min")
20+
filter_rules_with_profile(collection.rules, "min")
2121
assert (
2222
len(collection.rules) == 3
2323
), "Failed to unload rule that is not part of 'min' profile."

test/test_rules_collection.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,9 @@ def test_rich_rule_listing() -> None:
152152
def test_rules_id_format() -> None:
153153
"""Assure all our rules have consistent format."""
154154
rule_id_re = re.compile("^[a-z-]{4,30}$")
155-
options.enable_list = ["no-same-owner", "no-log-password", "no-same-owner"]
155+
# options.enable_list = ["no-same-owner", "no-log-password", "no-same-owner"]
156156
rules = RulesCollection(
157-
[os.path.abspath("./src/ansiblelint/rules")], options=options
157+
[os.path.abspath("./src/ansiblelint/rules")], options=options, conditional=False
158158
)
159159
keys: set[str] = set()
160160
for rule in rules:
@@ -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) == 42 # update this number when adding new rules!
170-
assert len(keys) == 42, "Duplicate rule ids?"
169+
assert len(rules) == 45 # update this number when adding new rules!
170+
assert len(keys) == len(rules), "Duplicate rule ids?"

0 commit comments

Comments
 (0)