@@ -64,12 +64,16 @@ def _msg(self, tag: str, value: str, reformatted: str) -> str:
6464 """Generate error message."""
6565 return self ._tag2msg [tag ].format (value = value , reformatted = reformatted )
6666
67- # pylint: disable=too-many-branches
67+ # pylint: disable=too-many-branches,too-many-locals
6868 def matchtask ( # noqa: C901
6969 self , task : dict [str , Any ], file : Lintable | None = None
70- ) -> bool | str | MatchError :
70+ ) -> list [MatchError ]:
71+ result = []
7172 try :
72- for key , v , _ in nested_items_path (task ):
73+ for key , v , path in nested_items_path (
74+ task ,
75+ ignored_keys = ("block" , "ansible.builtin.block" , "ansible.legacy.block" ),
76+ ):
7377 if isinstance (v , str ):
7478 try :
7579 template (
@@ -122,29 +126,34 @@ def matchtask( # noqa: C901
122126 # AnsibleError: template error while templating string: expected token ':', got '}'. String: {{ {{ '1' }} }}
123127 # AnsibleError: template error while templating string: unable to locate collection ansible.netcommon. String: Foo {{ buildset_registry.host | ipwrap }}
124128 if not bypass :
125- return self .create_matcherror (
126- message = str (exc ),
127- linenumber = task [LINE_NUMBER_KEY ],
128- filename = file ,
129- tag = f"{ self .id } [invalid]" ,
129+ result .append (
130+ self .create_matcherror (
131+ message = str (exc ),
132+ linenumber = _get_error_line (task , path ),
133+ filename = file ,
134+ tag = f"{ self .id } [invalid]" ,
135+ )
130136 )
137+ continue
131138 reformatted , details , tag = self .check_whitespace (
132139 v , key = key , lintable = file
133140 )
134141 if reformatted != v :
135- return self .create_matcherror (
136- message = self ._msg (
137- tag = tag , value = v , reformatted = reformatted
138- ),
139- linenumber = task [LINE_NUMBER_KEY ],
140- details = details ,
141- filename = file ,
142- tag = f"{ self .id } [{ tag } ]" ,
142+ result .append (
143+ self .create_matcherror (
144+ message = self ._msg (
145+ tag = tag , value = v , reformatted = reformatted
146+ ),
147+ linenumber = _get_error_line (task , path ),
148+ details = details ,
149+ filename = file ,
150+ tag = f"{ self .id } [{ tag } ]" ,
151+ )
143152 )
144153 except Exception as exc :
145154 _logger .info ("Exception in JinjaRule.matchtask: %s" , exc )
146155 raise
147- return False
156+ return result
148157
149158 def matchyaml (self , file : Lintable ) -> list [MatchError ]:
150159 """Return matches for variables defined in vars files."""
@@ -344,7 +353,7 @@ def blacken(text: str) -> str:
344353 @pytest .fixture (name = "error_expected_lines" )
345354 def fixture_error_expected_lines () -> list [int ]:
346355 """Return list of expected error lines."""
347- return [31 , 34 , 37 , 40 , 43 , 46 , 72 ]
356+ return [33 , 36 , 39 , 42 , 45 , 48 , 74 ]
348357
349358 # 21 68
350359 @pytest .fixture (name = "lint_error_lines" )
@@ -636,9 +645,13 @@ def test_jinja_invalid() -> None:
636645 collection .register (JinjaRule ())
637646 success = "examples/playbooks/rule-jinja-invalid.yml"
638647 errs = Runner (success , rules = collection ).run ()
639- assert len (errs ) == 1
640- assert errs [0 ].tag == "jinja[invalid ]"
648+ assert len (errs ) == 2
649+ assert errs [0 ].tag == "jinja[spacing ]"
641650 assert errs [0 ].rule .id == "jinja"
651+ assert errs [0 ].linenumber == 9
652+ assert errs [1 ].tag == "jinja[invalid]"
653+ assert errs [1 ].rule .id == "jinja"
654+ assert errs [1 ].linenumber == 9
642655
643656 def test_jinja_valid () -> None :
644657 """Tests our ability to parse jinja, even when variables may not be defined."""
@@ -647,3 +660,16 @@ def test_jinja_valid() -> None:
647660 success = "examples/playbooks/rule-jinja-valid.yml"
648661 errs = Runner (success , rules = collection ).run ()
649662 assert len (errs ) == 0
663+
664+
665+ def _get_error_line (task : dict [str , Any ], path : list [str | int ]) -> int :
666+ """Return error line number."""
667+ line = task [LINE_NUMBER_KEY ]
668+ ctx = task
669+ for _ in path :
670+ ctx = ctx [_ ]
671+ if LINE_NUMBER_KEY in ctx :
672+ line = ctx [LINE_NUMBER_KEY ]
673+ if not isinstance (line , int ):
674+ raise RuntimeError ("Line number is not an integer" )
675+ return line
0 commit comments