Fix templating tags on plays and roles (#82314)

Fixes #69903

ci_complete

(cherry picked from commit 532edf4c35)
pull/85305/head
Martin Krizek 6 months ago committed by Matt Davis
parent aae5734e0e
commit 33c55b9c25

@ -0,0 +1,2 @@
bugfixes:
- Fix templating ``tags`` on plays and roles. (https://github.com/ansible/ansible/issues/69903)

@ -17,6 +17,8 @@
from __future__ import annotations
import typing as t
from ansible.errors import AnsibleError
from ansible.module_utils.six import string_types
from ansible.module_utils.common.sentinel import Sentinel
@ -25,7 +27,7 @@ from ansible.playbook.attribute import FieldAttribute
from ansible._internal._templating._engine import TemplateEngine
def _flatten_tags(tags: list) -> list:
def _flatten_tags(tags: list[str | int]) -> list[str | int]:
rv = set()
for tag in tags:
if isinstance(tag, list):
@ -49,16 +51,28 @@ class Taggable:
raise AnsibleError('tags must be specified as a list', obj=ds)
def _get_all_taggable_objects(self) -> t.Iterable[Taggable]:
obj = self
while obj is not None:
yield obj
if (role := getattr(obj, "_role", Sentinel)) is not Sentinel:
yield role # type: ignore[misc]
obj = obj._parent
yield self.get_play()
def evaluate_tags(self, only_tags, skip_tags, all_vars):
""" this checks if the current item should be executed depending on tag options """
"""Check if the current item should be executed depending on the specified tags.
NOTE this method is assumed to be called only on Task objects.
"""
if self.tags:
templar = TemplateEngine(loader=self._loader, variables=all_vars)
obj = self
while obj is not None:
for obj in self._get_all_taggable_objects():
if (_tags := getattr(obj, "_tags", Sentinel)) is not Sentinel:
obj._tags = _flatten_tags(templar.template(_tags))
obj = obj._parent
tags = set(self.tags)
else:
# this makes isdisjoint work for untagged

@ -82,3 +82,21 @@ ansible-playbook test_template_parent_tags.yml --tags tag1 "$@" 2>&1 | tee out.t
ansible-playbook test_template_parent_tags.yml --skip-tags tag1 "$@" 2>&1 | tee out.txt
[ "$(grep out.txt -ce 'Tagged_task')" = "0" ]; rm out.txt
ansible-playbook test_template_play_tags.yml "$@" 2>&1 | tee out.txt
[ "$(grep out.txt -ce 'Tagged_task')" = "1" ]; rm out.txt
ansible-playbook test_template_play_tags.yml --tags tag1 "$@" 2>&1 | tee out.txt
[ "$(grep out.txt -ce 'Tagged_task')" = "1" ]; rm out.txt
ansible-playbook test_template_play_tags.yml --skip-tags tag1 "$@" 2>&1 | tee out.txt
[ "$(grep out.txt -ce 'Tagged_task')" = "0" ]; rm out.txt
ansible-playbook test_template_role_tags.yml "$@" 2>&1 | tee out.txt
[ "$(grep out.txt -ce 'Tagged_task')" = "1" ]; rm out.txt
ansible-playbook test_template_role_tags.yml --tags tag1 "$@" 2>&1 | tee out.txt
[ "$(grep out.txt -ce 'Tagged_task')" = "1" ]; rm out.txt
ansible-playbook test_template_role_tags.yml --skip-tags tag1 "$@" 2>&1 | tee out.txt
[ "$(grep out.txt -ce 'Tagged_task')" = "0" ]; rm out.txt

@ -0,0 +1,8 @@
- hosts: localhost
gather_facts: false
vars:
t: tag1
tags: "{{ t }}"
tasks:
- debug:
msg: Tagged_task

@ -0,0 +1,7 @@
- hosts: localhost
gather_facts: false
vars:
t: tag1
roles:
- name: a
tags: "{{ t }}"

@ -29,6 +29,9 @@ class TaggableTestObj(Taggable):
self.tags = []
self._parent = None
def get_play(self):
return None
class TestTaggable(unittest.TestCase):

Loading…
Cancel
Save