Skip to content

Commit 2ce81ed

Browse files
Qalthosssbarnea
andauthored
Fix cmd args with no-free-form transformer (#4215)
Co-authored-by: Sorin Sbarnea <[email protected]>
1 parent c37e909 commit 2ce81ed

File tree

4 files changed

+51
-19
lines changed

4 files changed

+51
-19
lines changed

examples/playbooks/transform-no-free-form.transformed.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@
88
cmd: touch foo
99
changed_when: false
1010

11+
- name: Create a placefolder file
12+
ansible.builtin.command: # <-- command can also go first
13+
chdir: /tmp
14+
cmd: touch bar
15+
changed_when: false
16+
1117
- name: Use raw to echo
1218
ansible.builtin.raw: echo foo # <-- don't use executable=
1319
args:
@@ -17,3 +23,8 @@
1723
- name: Example task with usage for '=' as module params
1824
ansible.builtin.debug:
1925
msg: "'Hello there world'"
26+
changed_when: false
27+
28+
- name: Task that has a non-debug string with spaces
29+
ansible.builtin.set_fact:
30+
foo: '"String with spaces"'

examples/playbooks/transform-no-free-form.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,17 @@
66
ansible.builtin.command: chdir=/tmp touch foo # <-- don't use shorthand
77
changed_when: false
88

9+
- name: Create a placefolder file
10+
ansible.builtin.command: touch bar chdir=/tmp # <-- command can also go first
11+
changed_when: false
12+
913
- name: Use raw to echo
1014
ansible.builtin.raw: executable=/bin/bash echo foo # <-- don't use executable=
1115
changed_when: false
1216

1317
- name: Example task with usage for '=' as module params
1418
ansible.builtin.debug: msg='Hello there world'
19+
changed_when: false
20+
21+
- name: Task that has a non-debug string with spaces
22+
ansible.builtin.set_fact: foo="String with spaces"

src/ansiblelint/rules/no_free_form.py

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def matchtask(
8080
"win_command",
8181
"win_shell",
8282
):
83-
if self.cmd_shell_re.match(action_value):
83+
if self.cmd_shell_re.search(action_value):
8484
fail = True
8585
else:
8686
fail = True
@@ -107,33 +107,46 @@ def filter_values(
107107
val: str,
108108
filter_key: str,
109109
filter_dict: dict[str, Any],
110-
) -> bool:
111-
"""Return True if module option is not present in the string."""
110+
) -> str:
111+
"""Pull out key=value pairs from a string and set them in filter_dict.
112+
113+
Returns unmatched strings.
114+
"""
112115
if filter_key not in val:
113-
return True
116+
return val
117+
118+
extra = ""
119+
[k, v] = val.split(filter_key, 1)
120+
if " " in k:
121+
extra, k = k.rsplit(" ", 1)
122+
123+
if v[0] in "\"'":
124+
# Keep quoted strings together
125+
quote = v[0]
126+
_, v, remainder = v.split(quote, 2)
127+
v = f"{quote}{v}{quote}"
128+
else:
129+
try:
130+
v, remainder = v.split(" ", 1)
131+
except ValueError:
132+
remainder = ""
114133

115-
[k, v] = val.split(filter_key)
116134
filter_dict[k] = v
117-
return False
135+
136+
extra = " ".join(
137+
(extra, filter_values(remainder, filter_key, filter_dict)),
138+
)
139+
return extra.strip()
118140

119141
if match.tag == "no-free-form":
120142
module_opts: dict[str, Any] = {}
121143
for _ in range(len(task)):
122144
k, v = task.popitem(False)
123145
# identify module as key and process its value
124146
if len(k.split(".")) == 3 and isinstance(v, str):
125-
# if it is a message
126-
if "msg" in v:
127-
filter_values(v, "=", module_opts)
128-
else:
129-
# Filter the module options and command
130-
module_opts["cmd"] = " ".join(
131-
[
132-
item
133-
for item in v.split(" ")
134-
if filter_values(item, "=", module_opts)
135-
],
136-
)
147+
cmd = filter_values(v, "=", module_opts)
148+
if cmd:
149+
module_opts["cmd"] = cmd
137150

138151
sorted_module_opts = {}
139152
for key in sorted(

test/test_transformer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ def fixture_runner_result(
143143
),
144144
pytest.param(
145145
"examples/playbooks/transform-no-free-form.yml",
146-
3,
146+
5,
147147
True,
148148
True,
149149
id="no_free_form_transform",

0 commit comments

Comments
 (0)