diff --git a/lib/ansible/executor/task_result.py b/lib/ansible/executor/task_result.py index db73f1ccb95..457a094b734 100644 --- a/lib/ansible/executor/task_result.py +++ b/lib/ansible/executor/task_result.py @@ -40,11 +40,16 @@ class TaskResult: return self._check_key('changed') def is_skipped(self): + # loop results if 'results' in self._result and self._task.loop: results = self._result['results'] - return results and all(isinstance(res, dict) and res.get('skipped', False) for res in results) - else: - return self._result.get('skipped', False) + # Loop tasks are only considered skipped if all items were skipped. + # some squashed results (eg, yum) are not dicts and can't be skipped individually + if results and all(isinstance(res, dict) and res.get('skipped', False) for res in results): + return True + + # regular tasks and squashed non-dict results + return self._result.get('skipped', False) def is_failed(self): if 'failed_when_result' in self._result or \ diff --git a/test/units/executor/test_task_result.py b/test/units/executor/test_task_result.py index a0af67edbd1..c83d7b44892 100644 --- a/test/units/executor/test_task_result.py +++ b/test/units/executor/test_task_result.py @@ -85,6 +85,15 @@ class TestTaskResult(unittest.TestCase): tr = TaskResult(mock_host, mock_task, dict(results=[dict(skipped=True), dict(skipped=True), dict(skipped=True)])) self.assertTrue(tr.is_skipped()) + # test with multiple squashed results (list of strings) + # first with the main result having skipped=False + mock_task.loop = 'foo' + tr = TaskResult(mock_host, mock_task, dict(results=["a", "b", "c"], skipped=False)) + self.assertFalse(tr.is_skipped()) + # then with the main result having skipped=True + tr = TaskResult(mock_host, mock_task, dict(results=["a", "b", "c"], skipped=True)) + self.assertTrue(tr.is_skipped()) + def test_task_result_is_unreachable(self): mock_host = MagicMock() mock_task = MagicMock()