diff --git a/src/ansiblelint/runner.py b/src/ansiblelint/runner.py index daf21b9e33..16638499aa 100644 --- a/src/ansiblelint/runner.py +++ b/src/ansiblelint/runner.py @@ -246,6 +246,7 @@ def _run(self) -> list[MatchError]: def worker(lintable: Lintable) -> list[MatchError]: return self._get_ansible_syntax_check_matches( lintable=lintable, + inventory_opts=inventory_opts, app=self.app, ) @@ -257,6 +258,15 @@ def worker(lintable: Lintable) -> list[MatchError]: continue files.append(lintable) + inventory_opts = [ + inventory_opt + for inventory_opts in [ + ("-i", inventory_file) + for inventory_file in self._get_inventory_files(self.app) + ] + for inventory_opt in inventory_opts + ] + # avoid resource leak warning, https://github.com/python/cpython/issues/90549 # pylint: disable=unused-variable global_resource = multiprocessing.Semaphore() # noqa: F841 @@ -304,6 +314,7 @@ def worker(lintable: Lintable) -> list[MatchError]: def _get_ansible_syntax_check_matches( self, lintable: Lintable, + inventory_opts: list[str], app: App, ) -> list[MatchError]: """Run ansible syntax check and return a list of MatchError(s).""" @@ -346,14 +357,7 @@ def _get_ansible_syntax_check_matches( playbook_path = str(lintable.path.expanduser()) cmd = [ "ansible-playbook", - *[ - inventory_opt - for inventory_opts in [ - ("-i", inventory_file) - for inventory_file in self._get_inventory_files(app) - ] - for inventory_opt in inventory_opts - ], + *inventory_opts, "--syntax-check", playbook_path, ] diff --git a/test/test_app.py b/test/test_app.py index eee8e5cb1c..e498754fb3 100644 --- a/test/test_app.py +++ b/test/test_app.py @@ -97,3 +97,26 @@ def test_with_inventory_via_ansible_cfg(tmp_path: Path) -> None: result = run_ansible_lint(lintable.filename, cwd=tmp_path) assert result.returncode == RC.SUCCESS + + +def test_with_inventory_concurrent_syntax_checks(tmp_path: Path) -> None: + """Validate using inventory file with concurrent syntax checks aren't faulty.""" + (tmp_path / "ansible.cfg").write_text("[defaults]\ninventory = foo\n") + (tmp_path / "foo").write_text("[group_name]\nhost1\nhost2\n") + lintable1 = Lintable(tmp_path / "playbook1.yml") + lintable2 = Lintable(tmp_path / "playbook2.yml") + lintable1.content = "---\n- name: Test\n hosts:\n - group_name\n serial: \"{{ batch | default(groups['group_name'] | length) }}\"\n" + lintable2.content = "---\n- name: Test\n hosts:\n - group_name\n serial: \"{{ batch | default(groups['group_name'] | length) }}\"\n" + lintable1.kind = "playbook" + lintable2.kind = "playbook" + lintable1.write(force=True) + lintable2.write(force=True) + + counter = 0 + while counter < 3: + result = run_ansible_lint(lintable1.filename, lintable2.filename, cwd=tmp_path) + assert result.returncode == RC.SUCCESS + # AttributeError err is expected to look like what's reported here, + # https://github.com/ansible/ansible-lint/issues/4446. + assert "AttributeError" not in result.stderr + counter += 1 diff --git a/tox.ini b/tox.ini index e71763c4a7..247ec006ea 100644 --- a/tox.ini +++ b/tox.ini @@ -75,7 +75,7 @@ setenv = PRE_COMMIT_COLOR = always # Number of expected test passes, safety measure for accidental skip of # tests. Update value if you add/remove tests. (tox-extra) - PYTEST_REQPASS = 905 + PYTEST_REQPASS = 906 FORCE_COLOR = 1 pre: PIP_PRE = 1 allowlist_externals =