Skip to content

Commit 0efeea5

Browse files
ret2libcclaude
andauthored
Add Jinja2 template validation test and pre-commit hook (#45)
* Remove escaped chars in comments * Add Jinja2 template validation test and pre-commit hook Catch template syntax errors early with a unit test that parses and renders the default cloud-init template, and a pre-commit hook that validates all templates in dropkit/templates/ on change. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent fde89df commit 0efeea5

3 files changed

Lines changed: 64 additions & 1 deletion

File tree

.pre-commit-config.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,16 @@ repos:
3434
types: [python]
3535
pass_filenames: false
3636

37+
# Jinja2 template validation
38+
- repo: local
39+
hooks:
40+
- id: jinja2-check
41+
name: jinja2 template syntax
42+
entry: uv run python -c "import sys; from jinja2 import Template; [Template(open(f).read()) for f in sys.argv[1:]]"
43+
language: system
44+
files: ^dropkit/templates/.*\.yaml$
45+
types: [file]
46+
3747
# Shell script linting
3848
- repo: https://github.com/koalaman/shellcheck-precommit
3949
rev: v0.10.0

dropkit/templates/default-cloud-init.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#cloud-config
2-
# Warning: This whole file will be evaluated by Jinja. Escape any special literals (`{{`, `{%`, `{#`).
2+
# Warning: This whole file will be evaluated by Jinja. Escape any special literals
33

44
# Update and upgrade system packages
55
package_update: true

tests/test_cloudinit.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
"""Tests for cloud-init template parsing and rendering."""
2+
3+
from jinja2 import Template, TemplateSyntaxError
4+
5+
from dropkit.config import Config
6+
7+
8+
def _load_default_template() -> str:
9+
"""Load the default cloud-init template content."""
10+
path = Config.get_default_template_path()
11+
return path.read_text()
12+
13+
14+
def test_default_template_parses():
15+
"""Verify the default template is valid Jinja2 syntax."""
16+
content = _load_default_template()
17+
try:
18+
Template(content)
19+
except TemplateSyntaxError as exc:
20+
raise AssertionError(f"Template has Jinja2 syntax error: {exc}") from exc
21+
22+
23+
def test_default_template_renders():
24+
"""Verify the template renders with sample variables."""
25+
content = _load_default_template()
26+
template = Template(content)
27+
rendered = template.render(
28+
username="testuser",
29+
full_name="Test User",
30+
email="test@example.com",
31+
ssh_keys=["ssh-ed25519 AAAAC3... test@host"],
32+
tailscale_enabled=True,
33+
)
34+
assert "testuser" in rendered
35+
assert "ssh-ed25519 AAAAC3... test@host" in rendered
36+
assert "git config --global user.name 'Test User'" in rendered
37+
assert "git config --global user.email 'test@example.com'" in rendered
38+
assert "tailscale" in rendered
39+
40+
41+
def test_default_template_renders_without_tailscale():
42+
"""Verify the Tailscale section is absent when disabled."""
43+
content = _load_default_template()
44+
template = Template(content)
45+
rendered = template.render(
46+
username="testuser",
47+
full_name="Test User",
48+
email="test@example.com",
49+
ssh_keys=["ssh-ed25519 AAAAC3... test@host"],
50+
tailscale_enabled=False,
51+
)
52+
assert "testuser" in rendered
53+
assert "tailscale.com/install.sh" not in rendered

0 commit comments

Comments
 (0)