Files
computer-playbook/tests/integration/roles/applications/id/test_domain.py
kevinveenbirkenbachandClaude Fable 5 40e553069d refactor(structure): nest prefix-grouped sibling files into subfolders
Move files that share a delimiter-bounded name prefix within a folder (threshold 2) into a subfolder named after the prefix, dropping the prefix from the filename. Covers plugins/filter (docker, generate, has, merge, get/all), env handler subpackages, utils/roles/entity, utils/tests/swarm/write, role SQL/scripts/templates, keycloak/mailu task-includes, shared tasks/utils/load, and CI scripts. Update every import, query_file/script/include_tasks/src/lookup target, compose bind mount, and python -m path to the new locations.

Extend the prefix-grouped-files lint to threshold 2 with dir-level .nocheck and file-head nocheck opt-outs, and skip groups whose shortest member's stem equals the shared prefix. Keep flat only where a loader forbids nesting: WordPress mu-plugins and the docs/requirements namespace. Ansible filter discovery is recursive, so nested filters stay Jinja-resolvable.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 20:00:03 +02:00

77 lines
2.6 KiB
Python

import os
import re
import unittest
from plugins.filter.get.all.application_ids import get_all_application_ids
from utils.cache.files import iter_project_files_with_content
def collect_domain_keys():
"""
Scan all YAML and Python files under the project for usages of
domains.get('...') and domains['...'] and return a dict mapping each
domain key to a list of file:line locations where it's used.
Ignores the integration test file itself.
"""
pattern = re.compile(
r"domains(?:\.get\(\s*['\"](?P<id>[^'\"]+)['\"]\s*\)|\[['\"](?P<id2>[^'\"]+)['\"]\])"
)
locations: dict[str, list[str]] = {}
ignore_path = os.path.normpath(__file__)
for path, text in iter_project_files_with_content(
extensions=(".yml", ".yaml", ".py")
):
if os.path.normpath(path) == ignore_path:
continue
for lineno, line in enumerate(text.splitlines(), start=1):
for m in pattern.finditer(line):
key = m.group("id") or m.group("id2")
locations.setdefault(key, []).append(f"{path}:{lineno}")
return locations
class TestDomainApplicationIds(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.valid_ids = set(get_all_application_ids(roles_dir="roles"))
if not cls.valid_ids:
raise RuntimeError(
"No application_ids found in roles/*/vars/main.yml" # nocheck: role-file-spot
)
cls.domain_locations = collect_domain_keys()
if not cls.domain_locations:
raise RuntimeError(
"No domains.get(...) or domains[...] usages found to validate"
)
cls.ignore_keys = {"canonical", "aliases"}
def test_all_keys_are_valid(self):
"""Ensure every domains.get/[] key matches a valid application_id (excluding ignored keys)."""
def is_placeholder(key):
return bool(re.match(r"^\{.+\}$", key))
invalid = {}
for key, locs in self.domain_locations.items():
if key in self.ignore_keys or is_placeholder(key):
continue
if key not in self.valid_ids:
invalid[key] = locs
if invalid:
details = []
for key, locs in invalid.items():
locations_str = ", ".join(locs)
details.append(f"'{key}' at {locations_str}")
detail_msg = "; ".join(details)
self.fail(
f"Found usages of domains with invalid application_ids: {detail_msg}. "
f"Valid application_ids are: {sorted(self.valid_ids)}"
)
if __name__ == "__main__":
unittest.main()