From c5fce78f712a48bc59cb802c2b10c12215b058f9 Mon Sep 17 00:00:00 2001 From: Thomas Bechtold Date: Mon, 6 May 2024 12:14:02 +0200 Subject: [PATCH] Story 2011116: recursively find jinja2 vars from templates Don't only try to find undeclared variables from the current template but also recursively find undeclared variables from included and imported jinja2 templates. Otherwise included/imported templates with variables can not be used. Change-Id: Iebdce1accf74f27901d80a41c85624ba819bf2a8 --- jenkins_jobs/yaml_objects.py | 19 +++++++++++++++++-- .../job_fixtures/jinja-include03.j2.inc | 2 ++ .../job_fixtures/jinja-include03.yaml | 18 ++++++++++++++++++ .../job_fixtures/jinja-include03.yaml.inc | 3 +++ 4 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 tests/yamlparser/job_fixtures/jinja-include03.j2.inc create mode 100644 tests/yamlparser/job_fixtures/jinja-include03.yaml create mode 100644 tests/yamlparser/job_fixtures/jinja-include03.yaml.inc diff --git a/jenkins_jobs/yaml_objects.py b/jenkins_jobs/yaml_objects.py index e0b52fae3..21d1e33dd 100644 --- a/jenkins_jobs/yaml_objects.py +++ b/jenkins_jobs/yaml_objects.py @@ -294,10 +294,25 @@ class J2Template(J2BaseYamlObject): self._template_text = template_text self._template = self._jinja2_env.from_string(template_text) + def _params_from_referenced_templates(self, template_text): + """ + Find recursively undeclared jinja2 variables from any + (nested) included template(s) + """ + required_params = set() + ast = self._jinja2_env.parse(template_text) + for rt in jinja2.meta.find_referenced_templates(ast): + # recursive call to find params also from nested includes + template_text = Path(self._find_file(rt, 0)).read_text() + required_params.update( + self._params_from_referenced_templates(template_text) + ) + required_params.update(jinja2.meta.find_undeclared_variables(ast)) + return required_params + @cached_property def required_params(self): - ast = self._jinja2_env.parse(self._template_text) - return jinja2.meta.find_undeclared_variables(ast) + return self._params_from_referenced_templates(self._template_text) def _render(self, params): return self._render_template( diff --git a/tests/yamlparser/job_fixtures/jinja-include03.j2.inc b/tests/yamlparser/job_fixtures/jinja-include03.j2.inc new file mode 100644 index 000000000..9fc5b773e --- /dev/null +++ b/tests/yamlparser/job_fixtures/jinja-include03.j2.inc @@ -0,0 +1,2 @@ +{# make sure the variable "globalvar1" is available in a nested include #} +{{ globalvar1 }} diff --git a/tests/yamlparser/job_fixtures/jinja-include03.yaml b/tests/yamlparser/job_fixtures/jinja-include03.yaml new file mode 100644 index 000000000..1dac1c218 --- /dev/null +++ b/tests/yamlparser/job_fixtures/jinja-include03.yaml @@ -0,0 +1,18 @@ +- defaults: + name: global + globalvar1: "global-var-1" + globalvar2: "global-var-2" + +- project: + name: "test-project" + var1: !j2: | + {% include 'jinja-include03.yaml.inc' %} + jobs: + - "job-{globalvar1}" + +- job-template: + name: "job-{globalvar1}" + description: | + {var1} + {globalvar1} + {globalvar2} diff --git a/tests/yamlparser/job_fixtures/jinja-include03.yaml.inc b/tests/yamlparser/job_fixtures/jinja-include03.yaml.inc new file mode 100644 index 000000000..484197d70 --- /dev/null +++ b/tests/yamlparser/job_fixtures/jinja-include03.yaml.inc @@ -0,0 +1,3 @@ +{%- import 'jinja-include03.j2.inc' as common with context -%} +{# make sure the variable "globalvar1" is available in a nested include #} +{{ globalvar1 }}