From fac438cc928d6f8f28e877299ca401cc0aae8c5b Mon Sep 17 00:00:00 2001 From: sjat Date: Sat, 6 Jun 2026 15:20:09 +0200 Subject: [PATCH] fix(tags): recognize name: role key; only check roles: in plays Co-Authored-By: Claude Sonnet 4.6 --- scripts/check-tags.py | 14 ++++++++++---- tests/test_check_tags.py | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/scripts/check-tags.py b/scripts/check-tags.py index 3e02bd1..8be24d7 100644 --- a/scripts/check-tags.py +++ b/scripts/check-tags.py @@ -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__": diff --git a/tests/test_check_tags.py b/tests/test_check_tags.py index d82d134..77c7d27 100644 --- a/tests/test_check_tags.py +++ b/tests/test_check_tags.py @@ -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) == []