Files
computer-playbook/tests/unit/cli/meta/test_graph.py
T
kevinveenbirkenbachandClaude Opus 4.7 f6c8c85b1b test(lint): role-file-spot guard + 139-file mapping migration
Add tests/lint/repository/test_role_file_spot.py: AST-walks every .py
file under the production trees and tests/, flags any reference to a
role file (standalone literal, f-string segment, pathlib `/` chain,
`+` concat chain, os.path.join / Path.joinpath / posixpath.join /
ntpath.join call) whose value or joined trailing operands match a
ROLE_FILE_* constant in utils.roles.mapping. The flag set is
auto-discovered from the module so adding a new constant extends
coverage without further edits. ROLE_FILE_README is exempt as too
generic. Per-line `# nocheck: role-file-spot` (same-or-above) is the
documented opt-out, catalog row added in
docs/contributing/actions/testing/suppression.md.

Migrate 139 .py files (377 occurrences) to use the constants:

- 135 files via direct constant import (`from utils.roles.mapping
  import ROLE_FILE_*`), with the symbol used in pathlib chains, in
  os.path.join / Path.joinpath calls, in f-string interpolation, and
  in glob patterns.
- 4 files via `# nocheck: role-file-spot` where the literal lives in
  argparse help text or in an allowlist tuple meant to declare the
  literal path.

Adjust utils/roles/dependency_resolver.py to use lazy-formatting
positional args in the logger.exception call (G003-clean) instead of
string concatenation against the constant.

Drop a redundant `if cond: return True; return False` guard in the
new test for `return cond` (SIM103-clean).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 13:21:22 +02:00

60 lines
1.9 KiB
Python

import shutil
import tempfile
import unittest
from pathlib import Path
from cli.build import graph
from utils.cache.yaml import dump_yaml
from utils.roles.mapping import ROLE_FILE_META_MAIN, ROLE_FILE_TASKS_MAIN
class TestGraphLogic(unittest.TestCase):
def setUp(self):
self.temp_dir = tempfile.mkdtemp()
self.role_name = "role_a"
self.role_path = str(Path(self.temp_dir) / self.role_name)
Path(str(Path(self.role_path) / "meta")).mkdir(parents=True)
Path(str(Path(self.role_path) / "tasks")).mkdir(parents=True)
# Write meta/main.yml
dump_yaml(
str(Path(self.role_path) / ROLE_FILE_META_MAIN),
{
"galaxy_info": {"author": "tester", "run_after": []},
"dependencies": [],
},
)
# Write tasks/main.yml
dump_yaml(
str(Path(self.role_path) / ROLE_FILE_TASKS_MAIN),
[
{"include_role": "some_other_role"},
{"import_role": {"name": "another_role"}},
],
)
def tearDown(self):
shutil.rmtree(self.temp_dir)
def test_load_meta_returns_dict(self):
meta_path = graph.find_role_meta(self.temp_dir, self.role_name)
meta = graph.load_meta(meta_path)
self.assertIsInstance(meta, dict)
self.assertIn("galaxy_info", meta)
def test_load_tasks_include_role(self):
task_path = graph.find_role_tasks(self.temp_dir, self.role_name)
includes = graph.load_tasks(task_path, "include_role")
self.assertIn("some_other_role", includes)
def test_build_mappings_structure(self):
result = graph.build_mappings(self.role_name, self.temp_dir, max_depth=1)
self.assertIsInstance(result, dict)
for key in graph.ALL_KEYS:
self.assertIn(key, result)
if __name__ == "__main__":
unittest.main()