From 23c3cbd0c1edf2bf7678b31ff0c344522c87f4b0 Mon Sep 17 00:00:00 2001 From: Roald Nefs Date: Fri, 29 Jan 2021 15:44:02 +0100 Subject: [PATCH 1/2] fix: ignore Jinja rules in Jinja escaped blocks Ignore Jinja specific rules in Jinja escaped blocks. Fixes #201 Signed-off-by: Roald Nefs --- CHANGELOG.md | 1 + saltlint/linter/rule.py | 40 ++++++++++++++++++- saltlint/rules/JinjaCommentHasSpacesRule.py | 9 ++--- .../rules/JinjaPillarGrainsGetFormatRule.py | 9 ++--- saltlint/rules/JinjaStatementHasSpacesRule.py | 9 ++--- saltlint/rules/JinjaVariableHasSpacesRule.py | 9 ++--- tests/unit/TestJinjaCommentHasSpaces.py | 6 +++ tests/unit/TestJinjaStatementHasSpaces.py | 6 +++ tests/unit/TestJinjaVariableHasSpaces.py | 28 ++++++++++++- 9 files changed, 91 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 82eff64..7d78e56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ All notable changes in **salt-lint** are documented below. ## [Unreleased] ### Fixed - Append the contents of the `CHANGELOG.md` file to the long description of the package instead of the duplicate `README.md` contents ([#234](https://github.com/warpnet/salt-lint/pull/234)). +- Ignore Jinja specific rules in Jinja escaped blocks ([#236](https://github.com/warpnet/salt-lint/pull/236)). ## [0.5.1] (2021-01-19) ### Fixed diff --git a/saltlint/linter/rule.py b/saltlint/linter/rule.py index e006699..bb6d03f 100644 --- a/saltlint/linter/rule.py +++ b/saltlint/linter/rule.py @@ -7,7 +7,7 @@ from saltlint.utils import get_rule_skips_from_line, get_file_type from saltlint.linter.match import Match -from saltlint.utils import LANGUAGE_SLS +from saltlint.utils import LANGUAGE_SLS, LANGUAGE_JINJA class Rule(object): @@ -89,6 +89,44 @@ def matchfulltext(self, file, text): return matches +class JinjaRule(Rule): + languages = [LANGUAGE_SLS, LANGUAGE_JINJA] + tags = ['formatting', 'jinja'] + + # Regex for matching all escaped Jinja blocks in the text + jinja_escape_regex = re.compile( + r"{%[+-]?\s?raw\s?[+-]?%}.*{%[+-]?\s?endraw\s?[+-]?%}", + re.DOTALL | re.MULTILINE + ) + + def matchlines(self, file, text): + """ + Match the text line by line but ignore all escaped Jinja blocks, e.g. + content between {% raw %} and {% endraw %}. + + Returns a list of Match objects. + """ + escaped_text = text + # Replace escaped Jinja blocks with the same number of empty lines + for match in self.jinja_escape_regex.finditer(text): + start = match.start() + end = match.end() + # Get the number of newlines in the escaped match + lines = text[start:end].splitlines() + num_of_lines = len(lines) - 1 + + # Replace escaped Jinja block in the escaped text by newlines to + # keep all the line numbers consistent + pre_text = escaped_text[:start] + post_text = escaped_text[end:] + newlines = '\n' * num_of_lines + escaped_text = pre_text + newlines + post_text + + # Call the matchlines() on the parent class with the escaped text + matches = super().matchlines(file, escaped_text) + return matches + + class DeprecationRule(Rule): id = None state = None diff --git a/saltlint/rules/JinjaCommentHasSpacesRule.py b/saltlint/rules/JinjaCommentHasSpacesRule.py index cb93f30..ce61646 100644 --- a/saltlint/rules/JinjaCommentHasSpacesRule.py +++ b/saltlint/rules/JinjaCommentHasSpacesRule.py @@ -1,20 +1,17 @@ # -*- coding: utf-8 -*- # Copyright (c) 2016 Will Thames and contributors # Copyright (c) 2018 Ansible Project -# Modified work Copyright (c) 2020 Warpnet B.V. +# Modified work Copyright (c) 2020-2021 Warpnet B.V. import re -from saltlint.linter.rule import Rule -from saltlint.utils import LANGUAGE_JINJA, LANGUAGE_SLS +from saltlint.linter.rule import JinjaRule -class JinjaCommentHasSpacesRule(Rule): +class JinjaCommentHasSpacesRule(JinjaRule): id = '209' shortdesc = "Jinja comment should have spaces before and after: '{# comment #}'" description = "Jinja comment should have spaces before and after: '{# comment #}'" severity = 'LOW' - languages = [LANGUAGE_SLS, LANGUAGE_JINJA] - tags = ['formatting', 'jinja'] version_added = 'v0.0.5' bracket_regex = re.compile(r"{#[^ \-\+]|{#[\-\+][^ ]|[^ \-\+]#}|[^ ][\-\+]#}") diff --git a/saltlint/rules/JinjaPillarGrainsGetFormatRule.py b/saltlint/rules/JinjaPillarGrainsGetFormatRule.py index accace3..8b53c5e 100644 --- a/saltlint/rules/JinjaPillarGrainsGetFormatRule.py +++ b/saltlint/rules/JinjaPillarGrainsGetFormatRule.py @@ -1,22 +1,19 @@ # -*- coding: utf-8 -*- # Copyright (c) 2016 Will Thames and contributors # Copyright (c) 2018 Ansible Project -# Modified work Copyright (c) 2020 Warpnet B.V. +# Modified work Copyright (c) 2020-2021 Warpnet B.V. import re -from saltlint.linter.rule import Rule -from saltlint.utils import LANGUAGE_JINJA, LANGUAGE_SLS +from saltlint.linter.rule import JinjaRule -class JinjaPillarGrainsGetFormatRule(Rule): +class JinjaPillarGrainsGetFormatRule(JinjaRule): id = '211' shortdesc = 'pillar.get or grains.get should be formatted differently' description = "pillar.get and grains.get should always be formatted " \ "like salt['pillar.get']('item'), grains['item1'] or " \ " pillar.get('item')" severity = 'HIGH' - languages = [LANGUAGE_SLS, LANGUAGE_JINJA] - tags = ['formatting', 'jinja'] version_added = 'v0.0.10' bracket_regex = re.compile(r"{{( |\-|\+)?.(pillar|grains).get\[.+}}") diff --git a/saltlint/rules/JinjaStatementHasSpacesRule.py b/saltlint/rules/JinjaStatementHasSpacesRule.py index 0ef024e..696f591 100644 --- a/saltlint/rules/JinjaStatementHasSpacesRule.py +++ b/saltlint/rules/JinjaStatementHasSpacesRule.py @@ -1,20 +1,17 @@ # -*- coding: utf-8 -*- # Copyright (c) 2016 Will Thames and contributors # Copyright (c) 2018 Ansible Project -# Modified work Copyright (c) 2020 Warpnet B.V. +# Modified work Copyright (c) 2020-2021 Warpnet B.V. import re -from saltlint.linter.rule import Rule -from saltlint.utils import LANGUAGE_JINJA, LANGUAGE_SLS +from saltlint.linter.rule import JinjaRule -class JinjaStatementHasSpacesRule(Rule): +class JinjaStatementHasSpacesRule(JinjaRule): id = '202' shortdesc = "Jinja statement should have spaces before and after: '{% statement %}'" description = "Jinja statement should have spaces before and after: '{% statement %}'" severity = 'LOW' - languages = [LANGUAGE_SLS, LANGUAGE_JINJA] - tags = ['formatting', 'jinja'] version_added = 'v0.0.2' bracket_regex = re.compile(r"{%[^ \-\+]|{%[\-\+][^ ]|[^ \-\+]%}|[^ ][\-\+]%}") diff --git a/saltlint/rules/JinjaVariableHasSpacesRule.py b/saltlint/rules/JinjaVariableHasSpacesRule.py index 946222b..03433b6 100644 --- a/saltlint/rules/JinjaVariableHasSpacesRule.py +++ b/saltlint/rules/JinjaVariableHasSpacesRule.py @@ -1,20 +1,17 @@ # -*- coding: utf-8 -*- # Copyright (c) 2016 Will Thames and contributors # Copyright (c) 2018 Ansible Project -# Modified work Copyright (c) 2020 Warpnet B.V. +# Modified work Copyright (c) 2020-2021 Warpnet B.V. import re -from saltlint.linter.rule import Rule -from saltlint.utils import LANGUAGE_JINJA, LANGUAGE_SLS +from saltlint.linter.rule import JinjaRule -class JinjaVariableHasSpacesRule(Rule): +class JinjaVariableHasSpacesRule(JinjaRule): id = '206' shortdesc = "Jinja variables should have spaces before and after: '{{ var_name }}'" description = "Jinja variables should have spaces before and after: '{{ var_name }}'" severity = 'LOW' - languages = [LANGUAGE_SLS, LANGUAGE_JINJA] - tags = ['formatting', 'jinja'] version_added = 'v0.0.1' bracket_regex = re.compile(r"{{[^ \-\+\d]|{{[-\+][^ ]|[^ \-\+\d]}}|[^ {][-\+\d]}}") diff --git a/tests/unit/TestJinjaCommentHasSpaces.py b/tests/unit/TestJinjaCommentHasSpaces.py index 60796fe..ea5e59e 100644 --- a/tests/unit/TestJinjaCommentHasSpaces.py +++ b/tests/unit/TestJinjaCommentHasSpaces.py @@ -12,6 +12,12 @@ GOOD_COMMENT_LINE = ''' {#- set example='good' +#} + +{% raw %} + # The following line should be ignored as it is placed in a Jinja escape + # block + {#-set example='bad'+#} +{% endraw %} ''' BAD_COMMENT_LINE = ''' diff --git a/tests/unit/TestJinjaStatementHasSpaces.py b/tests/unit/TestJinjaStatementHasSpaces.py index 947a876..f1534f6 100644 --- a/tests/unit/TestJinjaStatementHasSpaces.py +++ b/tests/unit/TestJinjaStatementHasSpaces.py @@ -12,6 +12,12 @@ GOOD_STATEMENT_LINE = ''' {%- set example='good' +%} + +{% raw %} + # The following line should be ignored as it is placed in a Jinja escape + # block + {%-set example='bad'+%} +{% endraw %} ''' BAD_STATEMENT_LINE = ''' diff --git a/tests/unit/TestJinjaVariableHasSpaces.py b/tests/unit/TestJinjaVariableHasSpaces.py index 301cb8d..4e53f33 100644 --- a/tests/unit/TestJinjaVariableHasSpaces.py +++ b/tests/unit/TestJinjaVariableHasSpaces.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # Copyright (c) 2013-2018 Will Thames # Copyright (c) 2018 Ansible by Red Hat -# Modified work Copyright (c) 2020 Warpnet B.V. +# Modified work Copyright (c) 2020-2021 Warpnet B.V. import unittest @@ -14,6 +14,19 @@ {{- variable +}} ''' +GOOD_VARIABLE_LINE_RAW = ''' +{% raw %} +{{variable}} +{% endraw %} +''' + +BAD_VARIABLE_LINE_RAW = ''' +{% raw %} +{{variable}} +{% endraw %} +{{variable}} # line 5 +''' + BAD_VARIABLE_LINE = ''' {{-variable+}} ''' @@ -49,6 +62,19 @@ def test_statement_positive(self): results = self.runner.run_state(GOOD_VARIABLE_LINE) self.assertEqual(0, len(results)) + def test_statement_jinja_raw_positive(self): + """Check if Jinja looking variables between raw-blocks are ignored.""" + results = self.runner.run_state(GOOD_VARIABLE_LINE_RAW) + self.assertEqual(0, len(results)) + + def test_statement_jinja_raw_negative(self): + """Check if Jinja looking variables between raw-blocks are ignored.""" + results = self.runner.run_state(BAD_VARIABLE_LINE_RAW) + # Check if the correct number of matches are found + self.assertEqual(1, len(results)) + # Check if the match occurred on the correct line + self.assertEqual(results[0].linenumber, 5) + def test_statement_negative(self): results = self.runner.run_state(BAD_VARIABLE_LINE) self.assertEqual(1, len(results)) From 74b46c51c208abf727839e41e57509053871d526 Mon Sep 17 00:00:00 2001 From: Roald Nefs Date: Fri, 29 Jan 2021 15:52:33 +0100 Subject: [PATCH 2/2] fix: use python 2.7 compatible super() Signed-off-by: Roald Nefs --- saltlint/linter/rule.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/saltlint/linter/rule.py b/saltlint/linter/rule.py index bb6d03f..fc3fded 100644 --- a/saltlint/linter/rule.py +++ b/saltlint/linter/rule.py @@ -123,7 +123,7 @@ def matchlines(self, file, text): escaped_text = pre_text + newlines + post_text # Call the matchlines() on the parent class with the escaped text - matches = super().matchlines(file, escaped_text) + matches = super(JinjaRule, self).matchlines(file, escaped_text) # pylint: disable=R1725 return matches