mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-08-29 23:08:06 +02:00
Huge role refactoring/cleanup. Other commits will propably follow. Because some bugs will exist. Still important for longrun and also for auto docs/help/slideshow generation
This commit is contained in:
74
tests/integration/test_role_include_import_roles_exist.py
Normal file
74
tests/integration/test_role_include_import_roles_exist.py
Normal file
@@ -0,0 +1,74 @@
|
||||
import unittest
|
||||
import os
|
||||
import glob
|
||||
import yaml
|
||||
import re
|
||||
|
||||
class TestIncludeImportRoleExistence(unittest.TestCase):
|
||||
def setUp(self):
|
||||
# Determine project root and roles directory
|
||||
tests_dir = os.path.dirname(__file__)
|
||||
project_root = os.path.abspath(os.path.join(tests_dir, os.pardir, os.pardir))
|
||||
self.roles_dir = os.path.join(project_root, 'roles')
|
||||
# Collect all .yml files in project (recursive), excluding .git and tests dirs
|
||||
self.files_to_scan = []
|
||||
for filepath in glob.glob(os.path.join(project_root, '**', '*.yml'), recursive=True):
|
||||
# Skip .git, tests folders
|
||||
if '/.git/' in filepath or '/tests/' in filepath:
|
||||
continue
|
||||
self.files_to_scan.append(filepath)
|
||||
|
||||
def _collect_includes(self, data):
|
||||
"""
|
||||
Recursively collect all roles referenced via include_role or import_role.
|
||||
Supports scalar, block, and block-list syntax, plus templating and wildcards.
|
||||
"""
|
||||
roles = []
|
||||
if isinstance(data, dict):
|
||||
for key, val in data.items():
|
||||
if key in ('include_role', 'import_role'):
|
||||
# Scalar syntax: include_role: role_name
|
||||
if isinstance(val, str):
|
||||
roles.append(val)
|
||||
# Block syntax: include_role: { name: role_name }
|
||||
elif isinstance(val, dict) and 'name' in val:
|
||||
roles.append(val['name'])
|
||||
# Block-list syntax: include_role:
|
||||
# - name: foo
|
||||
# - name: bar
|
||||
elif isinstance(val, list):
|
||||
for item in val:
|
||||
if isinstance(item, dict) and 'name' in item:
|
||||
roles.append(item['name'])
|
||||
else:
|
||||
roles.extend(self._collect_includes(val))
|
||||
elif isinstance(data, list):
|
||||
for item in data:
|
||||
roles.extend(self._collect_includes(item))
|
||||
return roles
|
||||
|
||||
def test_include_import_roles_exist(self):
|
||||
missing = []
|
||||
for file_path in self.files_to_scan:
|
||||
with open(file_path) as f:
|
||||
try:
|
||||
docs = list(yaml.safe_load_all(f))
|
||||
except yaml.YAMLError:
|
||||
self.fail(f"Failed to parse YAML in {file_path}")
|
||||
|
||||
for doc in docs:
|
||||
for role_name in self._collect_includes(doc):
|
||||
# Convert Jinja2 templates and wildcards to glob patterns
|
||||
pattern = re.sub(r"\{\{.*?\}\}", '*', role_name)
|
||||
glob_path = os.path.join(self.roles_dir, pattern)
|
||||
# Check for matching role directories
|
||||
matches = [p for p in glob.glob(glob_path) if os.path.isdir(p)]
|
||||
if not matches:
|
||||
missing.append((file_path, role_name))
|
||||
|
||||
if missing:
|
||||
messages = [f"File '{fp}' references missing role '{rn}'" for fp, rn in missing]
|
||||
self.fail("\n".join(messages))
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
Reference in New Issue
Block a user