Skip to content

Commit a3d9cae

Browse files
audgirkassbarnea
andauthored
Add auto-fixing implementation for key-order[task] rule (#3705)
Co-authored-by: Sorin Sbarnea <[email protected]>
1 parent 5e80a5b commit a3d9cae

File tree

5 files changed

+106
-3
lines changed

5 files changed

+106
-3
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
WSLENV: FORCE_COLOR:PYTEST_REQPASS:TOXENV:GITHUB_STEP_SUMMARY
7272
# Number of expected test passes, safety measure for accidental skip of
7373
# tests. Update value if you add/remove tests.
74-
PYTEST_REQPASS: 818
74+
PYTEST_REQPASS: 819
7575
steps:
7676
- name: Activate WSL1
7777
if: "contains(matrix.shell, 'wsl')"
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
- name: Fixture
3+
hosts: localhost
4+
tasks:
5+
# comment before keys
6+
- name: Task with no_log on top # name comment
7+
no_log: true # no_log comment
8+
ansible.builtin.command: echo hello # command comment
9+
changed_when: false # changed_when comment
10+
# comment after keys
11+
- name: Task with when on top
12+
when: true
13+
ansible.builtin.command: echo hello
14+
changed_when: false
15+
- name: Delegate_to on top
16+
delegate_to: localhost
17+
ansible.builtin.command: echo hello
18+
changed_when: false
19+
- name: Loopy
20+
loop:
21+
- 1
22+
- 2
23+
ansible.builtin.command: echo {{ item }}
24+
changed_when: false
25+
- name: Become first
26+
become: true
27+
ansible.builtin.command: echo hello
28+
changed_when: false
29+
- name: Register first
30+
register: test
31+
ansible.builtin.command: echo hello
32+
changed_when: false
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
- name: Fixture
3+
hosts: localhost
4+
tasks:
5+
- # comment before keys
6+
no_log: true # no_log comment
7+
ansible.builtin.command: echo hello # command comment
8+
name: Task with no_log on top # name comment
9+
changed_when: false # changed_when comment
10+
# comment after keys
11+
- when: true
12+
name: Task with when on top
13+
ansible.builtin.command: echo hello
14+
changed_when: false
15+
- delegate_to: localhost
16+
name: Delegate_to on top
17+
ansible.builtin.command: echo hello
18+
changed_when: false
19+
- loop:
20+
- 1
21+
- 2
22+
name: Loopy
23+
ansible.builtin.command: echo {{ item }}
24+
changed_when: false
25+
- become: true
26+
name: Become first
27+
ansible.builtin.command: echo hello
28+
changed_when: false
29+
- register: test
30+
ansible.builtin.command: echo hello
31+
name: Register first
32+
changed_when: false

src/ansiblelint/rules/key_order.py

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,15 @@
33

44
import functools
55
import sys
6+
from dataclasses import dataclass
67
from typing import TYPE_CHECKING
78

8-
from ansiblelint.rules import AnsibleLintRule
9+
from ansiblelint.errors import RuleMatchTransformMeta
10+
from ansiblelint.rules import AnsibleLintRule, TransformMixin
911

1012
if TYPE_CHECKING:
13+
from ruamel.yaml.comments import CommentedMap, CommentedSeq
14+
1115
from ansiblelint.errors import MatchError
1216
from ansiblelint.file_utils import Lintable
1317
from ansiblelint.utils import Task
@@ -46,7 +50,21 @@ def task_property_sorter(property1: str, property2: str) -> int:
4650
return (v_1 > v_2) - (v_1 < v_2)
4751

4852

49-
class KeyOrderRule(AnsibleLintRule):
53+
@dataclass(frozen=True)
54+
class KeyOrderTMeta(RuleMatchTransformMeta):
55+
"""Key Order transform metadata.
56+
57+
:param fixed: tuple with updated key order
58+
"""
59+
60+
fixed: tuple[str | int, ...]
61+
62+
def __str__(self) -> str:
63+
"""Return string representation."""
64+
return f"Fixed to {self.fixed}"
65+
66+
67+
class KeyOrderRule(AnsibleLintRule, TransformMixin):
5068
"""Ensure specific order of keys in mappings."""
5169

5270
id = "key-order"
@@ -74,10 +92,25 @@ def matchtask(
7492
f"You can improve the task key order to: {', '.join(sorted_keys)}",
7593
filename=file,
7694
tag="key-order[task]",
95+
transform_meta=KeyOrderTMeta(fixed=tuple(sorted_keys)),
7796
),
7897
)
7998
return result
8099

100+
def transform(
101+
self,
102+
match: MatchError,
103+
lintable: Lintable,
104+
data: CommentedMap | CommentedSeq | str,
105+
) -> None:
106+
if match.tag == "key-order[task]":
107+
task = self.seek(match.yaml_path, data)
108+
sorted_keys = match.message.split(":")[1].split(",")
109+
for key in sorted_keys:
110+
key = key.strip()
111+
task[key] = task.pop(key)
112+
match.fixed = True
113+
81114

82115
# testing code to be loaded only with pytest or when executed the rule file
83116
if "pytest" in sys.modules:

test/test_transformer.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,12 @@ def fixture_runner_result(
120120
True,
121121
id="nested",
122122
),
123+
pytest.param(
124+
"examples/playbooks/transform-key-order.yml",
125+
6,
126+
True,
127+
id="key_order_transform",
128+
),
123129
),
124130
)
125131
def test_transformer( # pylint: disable=too-many-arguments, too-many-locals

0 commit comments

Comments
 (0)