mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-09-20 01:06:03 +02:00
tests: ignore Jinja variables inside raw blocks in variable definitions check
- Added regex masking to skip {{ var }} usages inside {% raw %}…{% endraw %} blocks. - Simplified code by removing redundant comments. - Cleaned up task file for XWiki role by removing outdated note. Ref: https://chatgpt.com/share/68cd2558-e92c-800f-a80a-a79d3c81476e
This commit is contained in:
@@ -9,7 +9,6 @@
|
|||||||
#
|
#
|
||||||
# Notes:
|
# Notes:
|
||||||
# - We print machine-readable markers so Ansible can assert deterministically.
|
# - We print machine-readable markers so Ansible can assert deterministically.
|
||||||
# - We protect XWiki's {{groovy}} wiki macro from Jinja by using {% raw %}…{% endraw %}.
|
|
||||||
|
|
||||||
- name: "XWIKI | Build Groovy installer code from static file (base64 payload)"
|
- name: "XWIKI | Build Groovy installer code from static file (base64 payload)"
|
||||||
vars:
|
vars:
|
||||||
|
@@ -34,6 +34,14 @@ class TestVariableDefinitions(unittest.TestCase):
|
|||||||
# File extensions to scan for Jinja usage/inline definitions
|
# File extensions to scan for Jinja usage/inline definitions
|
||||||
self.scan_extensions = {'.yml', '.j2'}
|
self.scan_extensions = {'.yml', '.j2'}
|
||||||
|
|
||||||
|
# -----------------------
|
||||||
|
# Raw-block pattern (ignore any Jinja inside {% raw %}...{% endraw %})
|
||||||
|
# Supports trimmed variants: {%- raw -%} ... {%- endraw -%}
|
||||||
|
self.raw_block_re = re.compile(
|
||||||
|
r'{%\s*-?\s*raw\s*-?\s*%}.*?{%\s*-?\s*endraw\s*-?\s*%}',
|
||||||
|
re.DOTALL,
|
||||||
|
)
|
||||||
|
|
||||||
# -----------------------
|
# -----------------------
|
||||||
# Regex patterns
|
# Regex patterns
|
||||||
# -----------------------
|
# -----------------------
|
||||||
@@ -121,18 +129,14 @@ class TestVariableDefinitions(unittest.TestCase):
|
|||||||
# Block mapping: keys on subsequent indented lines
|
# Block mapping: keys on subsequent indented lines
|
||||||
in_set_fact = True
|
in_set_fact = True
|
||||||
set_fact_indent = indent
|
set_fact_indent = indent
|
||||||
# continue to next iteration to avoid double-processing this line
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if in_set_fact:
|
if in_set_fact:
|
||||||
# Still inside set_fact child mapping?
|
|
||||||
if indent > set_fact_indent and stripped.strip():
|
if indent > set_fact_indent and stripped.strip():
|
||||||
m = self.mapping_key.match(stripped)
|
m = self.mapping_key.match(stripped)
|
||||||
if m:
|
if m:
|
||||||
self.defined.add(m.group(1))
|
self.defined.add(m.group(1))
|
||||||
# do not continue; still scan for Jinja defs below
|
|
||||||
else:
|
else:
|
||||||
# Leaving the block when indentation decreases or a new key at same level appears
|
|
||||||
if indent <= set_fact_indent and stripped:
|
if indent <= set_fact_indent and stripped:
|
||||||
in_set_fact = False
|
in_set_fact = False
|
||||||
|
|
||||||
@@ -140,48 +144,37 @@ class TestVariableDefinitions(unittest.TestCase):
|
|||||||
if self.ansible_vars_block.match(stripped):
|
if self.ansible_vars_block.match(stripped):
|
||||||
in_vars_block = True
|
in_vars_block = True
|
||||||
vars_block_indent = indent
|
vars_block_indent = indent
|
||||||
# continue to next line to avoid double-processing this line
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if in_vars_block:
|
if in_vars_block:
|
||||||
# Inside vars: collect top-level mapping keys
|
|
||||||
if indent > vars_block_indent and stripped.strip():
|
if indent > vars_block_indent and stripped.strip():
|
||||||
m = self.mapping_key.match(stripped)
|
m = self.mapping_key.match(stripped)
|
||||||
if m:
|
if m:
|
||||||
self.defined.add(m.group(1))
|
self.defined.add(m.group(1))
|
||||||
# do not continue; still scan for Jinja defs below
|
|
||||||
else:
|
else:
|
||||||
# Leaving vars block
|
|
||||||
if indent <= vars_block_indent and stripped:
|
if indent <= vars_block_indent and stripped:
|
||||||
in_vars_block = False
|
in_vars_block = False
|
||||||
|
|
||||||
# --- Always scan every line (including inside blocks) for Jinja definitions
|
# --- Always scan every line (including inside blocks) for Jinja definitions
|
||||||
|
|
||||||
# {% set var = ... %}
|
|
||||||
for m in self.jinja_set_def.finditer(line):
|
for m in self.jinja_set_def.finditer(line):
|
||||||
self.defined.add(m.group(1))
|
self.defined.add(m.group(1))
|
||||||
|
|
||||||
# {% for x [, y] in ... %}
|
|
||||||
for m in self.jinja_for_def.finditer(line):
|
for m in self.jinja_for_def.finditer(line):
|
||||||
self.defined.add(m.group(1))
|
self.defined.add(m.group(1))
|
||||||
if m.group(2):
|
if m.group(2):
|
||||||
self.defined.add(m.group(2))
|
self.defined.add(m.group(2))
|
||||||
|
|
||||||
# {% macro name(params...) %}
|
|
||||||
for m in self.jinja_macro_def.finditer(line):
|
for m in self.jinja_macro_def.finditer(line):
|
||||||
params_blob = m.group(1)
|
params_blob = m.group(1)
|
||||||
params = [p.strip() for p in params_blob.split(',')]
|
params = [p.strip() for p in params_blob.split(',')]
|
||||||
for p in params:
|
for p in params:
|
||||||
if not p:
|
if not p:
|
||||||
continue
|
continue
|
||||||
# Strip * / ** for varargs/kwargs
|
|
||||||
p = p.lstrip('*')
|
p = p.lstrip('*')
|
||||||
# Drop default value part: name=...
|
|
||||||
name = p.split('=', 1)[0].strip()
|
name = p.split('=', 1)[0].strip()
|
||||||
if re.match(r'^[a-zA-Z_]\w*$', name):
|
if re.match(r'^[a-zA-Z_]\w*$', name):
|
||||||
self.defined.add(name)
|
self.defined.add(name)
|
||||||
|
|
||||||
# --- loop_var and register names
|
|
||||||
m_loop = self.ansible_loop_var.match(stripped)
|
m_loop = self.ansible_loop_var.match(stripped)
|
||||||
if m_loop:
|
if m_loop:
|
||||||
self.defined.add(m_loop.group(1))
|
self.defined.add(m_loop.group(1))
|
||||||
@@ -191,7 +184,6 @@ class TestVariableDefinitions(unittest.TestCase):
|
|||||||
self.defined.add(m_reg.group(1))
|
self.defined.add(m_reg.group(1))
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
# Ignore unreadable files
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test_all_used_vars_are_defined(self):
|
def test_all_used_vars_are_defined(self):
|
||||||
@@ -210,19 +202,28 @@ class TestVariableDefinitions(unittest.TestCase):
|
|||||||
path = os.path.join(root, fn)
|
path = os.path.join(root, fn)
|
||||||
try:
|
try:
|
||||||
with open(path, 'r', encoding='utf-8', errors='ignore') as f:
|
with open(path, 'r', encoding='utf-8', errors='ignore') as f:
|
||||||
for lineno, line in enumerate(f, 1):
|
content = f.read()
|
||||||
|
|
||||||
|
# Mask {% raw %} ... {% endraw %} blocks
|
||||||
|
def _mask_raw(m):
|
||||||
|
s = m.group(0)
|
||||||
|
return re.sub(r'[^\n]', ' ', s)
|
||||||
|
|
||||||
|
content_wo_raw = self.raw_block_re.sub(_mask_raw, content)
|
||||||
|
|
||||||
|
for lineno, line in enumerate(content_wo_raw.splitlines(True), 1):
|
||||||
for m in self.simple_var_pattern.finditer(line):
|
for m in self.simple_var_pattern.finditer(line):
|
||||||
var = m.group(1)
|
var = m.group(1)
|
||||||
|
|
||||||
# Skip well-known Jinja/Ansible builtins and frequent loop aliases
|
|
||||||
if var in (
|
if var in (
|
||||||
'lookup', 'role_name', 'domains', 'item', 'host_type',
|
'lookup', 'role_name', 'domains', 'item', 'host_type',
|
||||||
'inventory_hostname', 'role_path', 'playbook_dir',
|
'inventory_hostname', 'role_path', 'playbook_dir',
|
||||||
'ansible_become_password', 'inventory_dir', 'ansible_memtotal_mb', 'omit', 'group_names', 'ansible_processor_vcpus'
|
'ansible_become_password', 'inventory_dir',
|
||||||
|
'ansible_memtotal_mb', 'omit', 'group_names',
|
||||||
|
'ansible_processor_vcpus'
|
||||||
):
|
):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Accept if defined directly or via fallback defaults
|
|
||||||
if (
|
if (
|
||||||
var not in self.defined
|
var not in self.defined
|
||||||
and f"default_{var}" not in self.defined
|
and f"default_{var}" not in self.defined
|
||||||
@@ -232,7 +233,6 @@ class TestVariableDefinitions(unittest.TestCase):
|
|||||||
f"{path}:{lineno}: '{{{{ {var} }}}}' used but not defined"
|
f"{path}:{lineno}: '{{{{ {var} }}}}' used but not defined"
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
# Ignore unreadable files
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if undefined_uses:
|
if undefined_uses:
|
||||||
|
Reference in New Issue
Block a user