diff --git a/tests/j2lint.py b/tests/j2lint.py new file mode 100755 index 0000000000..65189c38f9 --- /dev/null +++ b/tests/j2lint.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 + +# Copyright 2020 StackHPC Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Original license: +@author Gerard van Helden +@license DBAD, see +@url https://github.com/drm/jinja2-lint +Simple j2 linter, useful for checking jinja2 template syntax + +Adapted for OpenStack Kolla/Kolla-Ansible purposes +""" + +from ansible.plugins.filter.core import to_json +from functools import reduce +from jinja2 import BaseLoader +from jinja2 import Environment +from jinja2 import exceptions +from jinja2 import TemplateNotFound +from kolla_ansible import kolla_address +from kolla_ansible import put_address_in_context +import os.path + + +class AbsolutePathLoader(BaseLoader): + def get_source(self, environment, template): + if not os.path.exists(template): + raise TemplateNotFound(template) + mtime = os.path.getmtime(template) + with open(template) as file: + source = file.read() + return source, template, lambda: mtime == os.path.getmtime(template) + + +def check(template, out, err, env=Environment(loader=AbsolutePathLoader(), + autoescape=True)): + try: + env.filters['basename'] = os.path.basename + env.filters['bool'] = bool + env.filters['hash'] = hash + env.filters['to_json'] = to_json + env.filters['kolla_address'] = kolla_address + env.filters['put_address_in_context'] = put_address_in_context + env.get_template(template) + out.write("%s: Syntax OK\n" % template) + return 0 + except TemplateNotFound: + err.write("%s: File not found\n" % template) + return 2 + except exceptions.TemplateSyntaxError as ex: + err.write("%s: Syntax check failed: %s in %s at %d\n" + % (template, ex.message, ex.filename, ex.lineno)) + return 1 + + +def main(**kwargs): + import sys + try: + sys.exit(reduce(lambda r, fn: r + + check(fn, sys.stdout, sys.stderr, **kwargs), + sys.argv[1:], 0)) + except IndexError: + sys.stdout.write("Usage: j2lint.py filename [filename ...]\n") + + +if __name__ == "__main__": + main() diff --git a/tox.ini b/tox.ini index d64225677d..0b1932289a 100644 --- a/tox.ini +++ b/tox.ini @@ -87,6 +87,7 @@ commands = {[testenv:doc8]commands} {[testenv:bandit]commands} {[testenv:bashate]commands} + {[testenv:j2lint]commands} {[testenv:yamllint]commands} {[testenv:ansible-lint]commands} @@ -121,6 +122,11 @@ commands = deps = {[testenv:linters]deps} commands = bandit --skip B303 -r ansible kolla_ansible tests tools +[testenv:j2lint] +deps = {[testenv:linters]deps} +commands = + find {toxinidir} -type f -name "*.j2" -not -path "*/.tox/*" -exec {toxinidir}/tests/j2lint.py \{\} + + [testenv:ansible-lint] # Lint only code in ansible/* - ignore tests/ and roles/ used by CI setenv = {[testenv:linters]setenv}