Skip to content

Commit a35ef9c

Browse files
authored
Make fix more resilient to syntax-check errors (#4125)
1 parent 30eb96e commit a35ef9c

File tree

8 files changed

+63
-6
lines changed

8 files changed

+63
-6
lines changed

.github/workflows/tox.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ jobs:
7171
env:
7272
# Number of expected test passes, safety measure for accidental skip of
7373
# tests. Update value if you add/remove tests.
74-
PYTEST_REQPASS: 855
74+
PYTEST_REQPASS: 856
7575
steps:
7676
- uses: actions/checkout@v4
7777
with:
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
- name: Reproducer for bug 4114
3+
hosts: localhost
4+
roles:
5+
- this_role_is_missing
6+
tasks:
7+
- name: Task referring to a missing module
8+
this_module_does_not_exist:
9+
foo: bar
10+
11+
- name: Use raw to echo
12+
ansible.builtin.debug: # <-- this should be converted to fqcn
13+
msg: some message!
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
- name: Reproducer for bug 4114
3+
hosts: localhost
4+
roles:
5+
- this_role_is_missing
6+
tasks:
7+
- name: Task referring to a missing module
8+
this_module_does_not_exist:
9+
foo: bar
10+
11+
- name: Use raw to echo
12+
debug: # <-- this should be converted to fqcn
13+
msg: some message!

src/ansiblelint/config.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,12 @@ class Options: # pylint: disable=too-many-instance-attributes
174174
ignore_file: Path | None = None
175175
max_tasks: int = 100
176176
max_block_depth: int = 20
177-
nodeps: bool = bool(int(os.environ.get("ANSIBLE_LINT_NODEPS", "0")))
177+
178+
@property
179+
def nodeps(self) -> bool:
180+
"""Returns value of nodeps feature."""
181+
# We do not want this to be cached as it would affect our testings.
182+
return bool(int(os.environ.get("ANSIBLE_LINT_NODEPS", "0")))
178183

179184
def __post_init__(self) -> None:
180185
"""Extra initialization logic."""

src/ansiblelint/rules/fqcn.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@
66
import sys
77
from typing import TYPE_CHECKING, Any
88

9+
from ruamel.yaml.comments import CommentedSeq
10+
911
from ansiblelint.constants import LINE_NUMBER_KEY
1012
from ansiblelint.rules import AnsibleLintRule, TransformMixin
1113
from ansiblelint.utils import load_plugin
1214

1315
if TYPE_CHECKING:
14-
from ruamel.yaml.comments import CommentedMap, CommentedSeq
16+
from ruamel.yaml.comments import CommentedMap
1517

1618
from ansiblelint.errors import MatchError
1719
from ansiblelint.file_utils import Lintable
@@ -242,6 +244,8 @@ def transform(
242244
current_action = match.message.split("`")[3]
243245
new_action = match.message.split("`")[1]
244246
for _ in range(len(target_task)):
247+
if isinstance(target_task, CommentedSeq):
248+
continue
245249
k, v = target_task.popitem(False)
246250
target_task[new_action if k == current_action else k] = v
247251
match.fixed = True

src/ansiblelint/rules/syntax_check.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,14 @@ class KnownError:
5555
re.MULTILINE | re.S | re.DOTALL,
5656
),
5757
),
58+
# "ERROR! the role 'this_role_is_missing' was not found in ROLE_INCLUDE_PATHS\n\nThe error appears to be in 'FILE_PATH': line 5, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n roles:\n - this_role_is_missing\n ^ here\n"
59+
KnownError(
60+
tag="specific",
61+
regex=re.compile(
62+
r"^ERROR! (?P<title>the role '.*' was not found in[^\n]*)'(?P<filename>[\w\/\.\-]+)': line (?P<line>\d+), column (?P<column>\d+)",
63+
re.MULTILINE | re.S | re.DOTALL,
64+
),
65+
),
5866
)
5967

6068

src/ansiblelint/runner.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,10 @@ def _get_ansible_syntax_check_matches(
393393
filename = lintable
394394
column = int(groups.get("column", 1))
395395

396-
if pattern.tag == "unknown-module" and app.options.nodeps:
396+
if (
397+
pattern.tag in ("unknown-module", "specific")
398+
and app.options.nodeps
399+
):
397400
ignore_rc = True
398401
else:
399402
results.append(

test/test_transformer.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,11 @@ def fixture_runner_result(
2828
config_options: Options,
2929
default_rules_collection: RulesCollection,
3030
playbook_str: str,
31+
monkeypatch: pytest.MonkeyPatch,
3132
) -> LintResult:
3233
"""Fixture that runs the Runner to populate a LintResult for a given file."""
34+
# needed for testing transformer when roles/modules are missing:
35+
monkeypatch.setenv("ANSIBLE_LINT_NODEPS", "1")
3336
config_options.lintables = [playbook_str]
3437
result = get_matches(rules=default_rules_collection, options=config_options)
3538
return result
@@ -191,6 +194,13 @@ def fixture_runner_result(
191194
True,
192195
id="name_case_roles",
193196
),
197+
pytest.param(
198+
"examples/playbooks/4114/transform-with-missing-role-and-modules.yml",
199+
1,
200+
True,
201+
True,
202+
id="4114",
203+
),
194204
),
195205
)
196206
@mock.patch.dict(os.environ, {"ANSIBLE_LINT_WRITE_TMP": "1"}, clear=True)
@@ -210,12 +220,13 @@ def test_transformer( # pylint: disable=too-many-arguments
210220
assert Lintable(playbook_str).is_owned_by_ansible() == is_owned_by_ansible
211221
playbook = Path(playbook_str)
212222
config_options.write_list = ["all"]
213-
transformer = Transformer(result=runner_result, options=config_options)
214-
transformer.run()
215223

216224
matches = runner_result.matches
217225
assert len(matches) == matches_count
218226

227+
transformer = Transformer(result=runner_result, options=config_options)
228+
transformer.run()
229+
219230
orig_content = playbook.read_text(encoding="utf-8")
220231
if transformed:
221232
expected_content = playbook.with_suffix(

0 commit comments

Comments
 (0)