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.
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 sys
@ -84,7 +84,8 @@ def _role_entry(entry):
if isinstance(entry, str):
return (entry if _static_str(entry) else None, set())
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):
return (None, set())
tags_value = entry.get("tags")
@ -100,7 +101,9 @@ def _role_entry(entry):
def _walk_roles(node, problems):
if isinstance(node, dict):
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:
name, tags = _role_entry(entry)
if name is not None and name not in tags:
@ -178,7 +181,10 @@ def main():
)
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__":

View file

@ -141,3 +141,39 @@ def test_role_tag_problems_skips_templated_role():
tags: [foo]
"""
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) == []