fix(tags): recognize name: role key; only check roles: in plays

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
sjat 2026-06-06 15:20:09 +02:00
parent 5aeeb094eb
commit fac438cc92
2 changed files with 46 additions and 4 deletions

View file

@ -11,7 +11,7 @@ It also checks that every role imported in a play's roles: block carries its own
role name as a tag (extra tags allowed); ADR-019. role name as a tag (extra tags allowed); ADR-019.
Usage: python3 scripts/check-tags.py Usage: python3 scripts/check-tags.py
Exit 0 = all tags allowed; exit 1 = unknown tag(s) found. Exit 0 = OK; exit 1 = unknown tag(s) or role import(s) missing their role-name tag.
""" """
import pathlib import pathlib
import sys import sys
@ -84,7 +84,8 @@ def _role_entry(entry):
if isinstance(entry, str): if isinstance(entry, str):
return (entry if _static_str(entry) else None, set()) return (entry if _static_str(entry) else None, set())
if isinstance(entry, dict): if isinstance(entry, dict):
name = entry.get("role") # Ansible accepts both `role:` and `name:` as the role identifier; `role:` wins.
name = entry.get("role") or entry.get("name")
if not _static_str(name): if not _static_str(name):
return (None, set()) return (None, set())
tags_value = entry.get("tags") tags_value = entry.get("tags")
@ -100,7 +101,9 @@ def _role_entry(entry):
def _walk_roles(node, problems): def _walk_roles(node, problems):
if isinstance(node, dict): if isinstance(node, dict):
roles = node.get("roles") roles = node.get("roles")
if isinstance(roles, list): # Only a play has a role-import `roles:` block, and a play always has `hosts:`.
# The `hosts` guard avoids misreading a `roles` variable/fact in a task file.
if "hosts" in node and isinstance(roles, list):
for entry in roles: for entry in roles:
name, tags = _role_entry(entry) name, tags = _role_entry(entry)
if name is not None and name not in tags: if name is not None and name not in tags:
@ -178,7 +181,10 @@ def main():
) )
sys.exit(1) sys.exit(1)
print(f"check-tags: OK ({len(allowed)} tags allowed across {len(SCAN_DIRS)} dirs)") print(
f"check-tags: OK ({len(allowed)} tags allowed across {len(SCAN_DIRS)} dirs; "
"role imports verified)"
)
if __name__ == "__main__": if __name__ == "__main__":

View file

@ -141,3 +141,39 @@ def test_role_tag_problems_skips_templated_role():
tags: [foo] tags: [foo]
""" """
assert ct.role_tag_problems(text) == [] assert ct.role_tag_problems(text) == []
def test_role_tag_problems_recognizes_name_key():
text = """
- hosts: all
roles:
- name: base
tags: [firewall]
"""
assert ct.role_tag_problems(text) == [("base", ["firewall"])]
def test_role_tag_problems_ignores_roles_variable_in_tasks():
text = """
- hosts: all
tasks:
- name: Set a fact that happens to be named roles
ansible.builtin.set_fact:
roles:
- base
- docker_host
tags: [config]
"""
assert ct.role_tag_problems(text) == []
def test_role_tag_problems_no_roles_key():
text = """
- hosts: all
tasks:
- name: noop
ansible.builtin.debug:
msg: hi
tags: [config]
"""
assert ct.role_tag_problems(text) == []