Skip to content

Commit 3f54c36

Browse files
committed
fix: resolve auto-fix failures and detection for short module names (#4750)
1 parent 901003b commit 3f54c36

File tree

4 files changed

+45
-10
lines changed

4 files changed

+45
-10
lines changed

examples/playbooks/rule-no-free-form-fail.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,12 @@
1414
ansible.builtin.raw:
1515
args: "123"
1616
changed_when: false
17+
18+
- name: Short name with multiple params (Issue 4750)
19+
file: path=/tmp/short1 state=directory mode=0755
20+
21+
- name: FQCN builtin with free-form
22+
ansible.builtin.uri: url=http://example.com return_content=yes
23+
24+
- name: Short name without a task name
25+
template: src=foo.j2 dest=/tmp/foo

src/ansiblelint/rules/no_free_form.py

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ def matchtask(
9292
message=f"Avoid using free-form when calling module actions. ({action})",
9393
lineno=task.line,
9494
filename=file,
95+
details=action,
9596
),
9697
)
9798
return results
@@ -125,7 +126,10 @@ def filter_values(
125126
if v[0] in "\"'":
126127
# Keep quoted strings together
127128
quote = v[0]
128-
_, v, remainder = v.split(quote, 2)
129+
try:
130+
_, v, remainder = v.split(quote, 2)
131+
except ValueError:
132+
return val
129133
v = (
130134
DoubleQuotedScalarString
131135
if quote == '"'
@@ -146,10 +150,12 @@ def filter_values(
146150

147151
if match.tag == "no-free-form":
148152
module_opts: dict[str, Any] = {}
153+
target_module = match.details
154+
149155
for _ in range(len(task)):
150156
k, v = task.popitem(False)
151157
# identify module as key and process its value
152-
if len(k.split(".")) == 3 and isinstance(v, str):
158+
if k == target_module and isinstance(v, str):
153159
cmd = filter_values(v, "=", module_opts)
154160
if cmd:
155161
module_opts["cmd"] = cmd
@@ -196,7 +202,7 @@ def filter_values(
196202
("file", "expected"),
197203
(
198204
pytest.param("examples/playbooks/rule-no-free-form-pass.yml", 0, id="pass"),
199-
pytest.param("examples/playbooks/rule-no-free-form-fail.yml", 3, id="fail"),
205+
pytest.param("examples/playbooks/rule-no-free-form-fail.yml", 6, id="fail"),
200206
),
201207
)
202208
def test_rule_no_free_form(
@@ -207,6 +213,26 @@ def test_rule_no_free_form(
207213
"""Validate that rule works as intended."""
208214
results = Runner(file, rules=default_rules_collection).run()
209215

210-
for result in results:
216+
rule_results = [r for r in results if r.rule.id == NoFreeFormRule.id]
217+
218+
for result in rule_results:
211219
assert result.rule.id == NoFreeFormRule.id, result
212-
assert len(results) == expected
220+
assert len(rule_results) == expected
221+
222+
def test_no_free_form_transform_error_handling() -> None:
223+
"""Test that transform handles malformed quoted strings."""
224+
from ruamel.yaml.comments import CommentedMap
225+
226+
from ansiblelint.errors import MatchError
227+
228+
rule = NoFreeFormRule()
229+
task = CommentedMap({"ansible.builtin.shell": 'chdir=" /tmp echo foo'})
230+
match = MatchError(
231+
message="test",
232+
rule=rule,
233+
details="ansible.builtin.shell",
234+
tag="no-free-form",
235+
)
236+
237+
rule.transform(match, None, task) # type: ignore[arg-type]
238+
assert task["ansible.builtin.shell"] == {"cmd": 'chdir=" /tmp echo foo'}

src/ansiblelint/schemas/__store__.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"url": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/ansible-lint-config.json"
55
},
66
"ansible-navigator-config": {
7-
"etag": "730a0572f872af3ce271fb5116bc9d4609da10dc2e35448b5ec1050f12b72e2b",
7+
"etag": "5f454fdaeb3d92c4bb2cc15dcc48faa67925fecfbdb72efffeddee01860d6bcb",
88
"url": "https://raw.githubusercontent.com/ansible/ansible-navigator/main/src/ansible_navigator/data/ansible-navigator.json"
99
},
1010
"changelog": {
@@ -24,7 +24,7 @@
2424
"url": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/inventory.json"
2525
},
2626
"meta": {
27-
"etag": "fa83d61b00b254d54a7c9a69e4fb8b722f356adec906da7beb733cadda1342bc",
27+
"etag": "2f5c7deb174136b48a4bc1d8d4399b1a175379dd4b8a863baa9c9bd56ffda489",
2828
"url": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/meta.json"
2929
},
3030
"meta-runtime": {

src/ansiblelint/schemas/ansible-navigator-config.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"$schema": "http://json-schema.org/draft-07/schema",
33
"additionalProperties": false,
4-
"description": "See https://docs.ansible.com/projects/navigator/settings/",
4+
"description": "See https://ansible.readthedocs.io/projects/navigator/settings/",
55
"properties": {
66
"ansible-navigator": {
77
"additionalProperties": false,
@@ -525,7 +525,7 @@
525525
"required": [
526526
"ansible-navigator"
527527
],
528-
"title": "ansible-navigator settings v25",
528+
"title": "ansible-navigator settings v26",
529529
"type": "object",
530-
"version": "25"
530+
"version": "26"
531531
}

0 commit comments

Comments
 (0)