Skip to content

Commit

Permalink
change: make file: Lintable given to <rule_class>.match{,task} methods
Browse files Browse the repository at this point in the history
Make file: Lintable given to match and matchtask methods of the rule
classes as an argument because there are cases that it is necessary to
do some analyses depends on the context, that is, file: Lintable, such
like the following.

- want to restrict tasks in 'main.yml' use include_tasks only
- want to restrict the level of inclusions with include_tasks to 2
- restrict keywords can be used depends on file path or name
- inhibit some keywords are used in the line depends on file name

Signed-Off-By: Satoru SATOH <satoru.satoh@gmail.com>
  • Loading branch information
ssato committed Apr 18, 2021
1 parent 1dc3533 commit 9076ebf
Show file tree
Hide file tree
Showing 27 changed files with 175 additions and 52 deletions.
6 changes: 4 additions & 2 deletions src/ansiblelint/_internal/rules.py
Expand Up @@ -43,7 +43,9 @@ def matchlines(self, file: "Lintable") -> List["MatchError"]:
"""Return matches found for a specific line."""
return []

def matchtask(self, task: Dict[str, Any]) -> Union[bool, str]:
def matchtask(
self, file: "Lintable", task: Dict[str, Any]
) -> Union[bool, str]:
"""Confirm if current rule is matching a specific task."""
return False

Expand All @@ -69,7 +71,7 @@ def verbose(self) -> str:
"""Return a verbose representation of the rule."""
return self.id + ": " + self.shortdesc + "\n " + self.description

def match(self, line: str) -> Union[bool, str]:
def match(self, file: "Lintable", line: str) -> Union[bool, str]:
"""Confirm if current rule matches the given string."""
return False

Expand Down
9 changes: 7 additions & 2 deletions src/ansiblelint/rules/CommandHasChangesCheckRule.py
Expand Up @@ -18,10 +18,13 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

from typing import Any, Dict, Union
from typing import TYPE_CHECKING, Any, Dict, Union

from ansiblelint.rules import AnsibleLintRule

if TYPE_CHECKING:
from ansiblelint.file_utils import Lintable


class CommandHasChangesCheckRule(AnsibleLintRule):
id = 'no-changed-when'
Expand All @@ -38,7 +41,9 @@ class CommandHasChangesCheckRule(AnsibleLintRule):

_commands = ['command', 'shell', 'raw']

def matchtask(self, task: Dict[str, Any]) -> Union[bool, str]:
def matchtask(
self, file: 'Lintable', task: Dict[str, Any]
) -> Union[bool, str]:
if task["__ansible_action_type__"] == 'task':
if task["action"]["__ansible_module__"] in self._commands:
return (
Expand Down
9 changes: 7 additions & 2 deletions src/ansiblelint/rules/CommandsInsteadOfArgumentsRule.py
Expand Up @@ -19,11 +19,14 @@
# THE SOFTWARE.

import os
from typing import Any, Dict, Union
from typing import TYPE_CHECKING, Any, Dict, Union

from ansiblelint.rules import AnsibleLintRule
from ansiblelint.utils import convert_to_boolean, get_first_cmd_arg

if TYPE_CHECKING:
from ansiblelint.file_utils import Lintable


class CommandsInsteadOfArgumentsRule(AnsibleLintRule):
id = 'deprecated-command-syntax'
Expand All @@ -47,7 +50,9 @@ class CommandsInsteadOfArgumentsRule(AnsibleLintRule):
'rm': 'state=absent',
}

def matchtask(self, task: Dict[str, Any]) -> Union[bool, str]:
def matchtask(
self, file: 'Lintable', task: Dict[str, Any]
) -> Union[bool, str]:
if task["action"]["__ansible_module__"] in self._commands:
first_cmd_arg = get_first_cmd_arg(task)
if not first_cmd_arg:
Expand Down
9 changes: 7 additions & 2 deletions src/ansiblelint/rules/CommandsInsteadOfModulesRule.py
Expand Up @@ -19,11 +19,14 @@
# THE SOFTWARE.

import os
from typing import Any, Dict, Union
from typing import TYPE_CHECKING, Any, Dict, Union

from ansiblelint.rules import AnsibleLintRule
from ansiblelint.utils import convert_to_boolean, get_first_cmd_arg

if TYPE_CHECKING:
from ansiblelint.file_utils import Lintable


class CommandsInsteadOfModulesRule(AnsibleLintRule):
id = 'command-instead-of-module'
Expand Down Expand Up @@ -59,7 +62,9 @@ class CommandsInsteadOfModulesRule(AnsibleLintRule):
'yum': 'yum',
}

def matchtask(self, task: Dict[str, Any]) -> Union[bool, str]:
def matchtask(
self, file: 'Lintable', task: Dict[str, Any]
) -> Union[bool, str]:
if task['action']['__ansible_module__'] not in self._commands:
return False

Expand Down
9 changes: 7 additions & 2 deletions src/ansiblelint/rules/ComparisonToEmptyStringRule.py
Expand Up @@ -3,11 +3,14 @@

import re
import sys
from typing import Any, Dict, Union
from typing import TYPE_CHECKING, Any, Dict, Union

from ansiblelint.rules import AnsibleLintRule
from ansiblelint.utils import nested_items

if TYPE_CHECKING:
from ansiblelint.file_utils import Lintable


class ComparisonToEmptyStringRule(AnsibleLintRule):
id = 'empty-string-compare'
Expand All @@ -22,7 +25,9 @@ class ComparisonToEmptyStringRule(AnsibleLintRule):

empty_string_compare = re.compile("[=!]= ?(\"{2}|'{2})")

def matchtask(self, task: Dict[str, Any]) -> Union[bool, str]:
def matchtask(
self, file: 'Lintable', task: Dict[str, Any]
) -> Union[bool, str]:
for k, v, _ in nested_items(task):
if k == 'when':
if isinstance(v, str):
Expand Down
9 changes: 7 additions & 2 deletions src/ansiblelint/rules/ComparisonToLiteralBoolRule.py
Expand Up @@ -2,11 +2,14 @@
# Copyright (c) 2018-2021, Ansible Project

import re
from typing import Any, Dict, Union
from typing import TYPE_CHECKING, Any, Dict, Union

from ansiblelint.rules import AnsibleLintRule
from ansiblelint.utils import nested_items

if TYPE_CHECKING:
from ansiblelint.file_utils import Lintable


class ComparisonToLiteralBoolRule(AnsibleLintRule):
id = 'literal-compare'
Expand All @@ -21,7 +24,9 @@ class ComparisonToLiteralBoolRule(AnsibleLintRule):

literal_bool_compare = re.compile("[=!]= ?(True|true|False|false)")

def matchtask(self, task: Dict[str, Any]) -> Union[bool, str]:
def matchtask(
self, file: 'Lintable', task: Dict[str, Any]
) -> Union[bool, str]:
for k, v, _ in nested_items(task):
if k == 'when':
if isinstance(v, str):
Expand Down
9 changes: 7 additions & 2 deletions src/ansiblelint/rules/DeprecatedModuleRule.py
@@ -1,9 +1,12 @@
# Copyright (c) 2018, Ansible Project

from typing import Any, Dict, Union
from typing import TYPE_CHECKING, Any, Dict, Union

from ansiblelint.rules import AnsibleLintRule

if TYPE_CHECKING:
from ansiblelint.file_utils import Lintable


class DeprecatedModuleRule(AnsibleLintRule):
id = 'deprecated-module'
Expand Down Expand Up @@ -60,7 +63,9 @@ class DeprecatedModuleRule(AnsibleLintRule):
'include',
]

def matchtask(self, task: Dict[str, Any]) -> Union[bool, str]:
def matchtask(
self, file: 'Lintable', task: Dict[str, Any]
) -> Union[bool, str]:
module = task["action"]["__ansible_module__"]
if module in self._modules:
message = '{0} {1}'
Expand Down
9 changes: 7 additions & 2 deletions src/ansiblelint/rules/EnvVarsInCommandRule.py
Expand Up @@ -18,11 +18,14 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

from typing import Any, Dict, Union
from typing import TYPE_CHECKING, Any, Dict, Union

from ansiblelint.rules import AnsibleLintRule
from ansiblelint.utils import FILENAME_KEY, LINE_NUMBER_KEY, get_first_cmd_arg

if TYPE_CHECKING:
from ansiblelint.file_utils import Lintable


class EnvVarsInCommandRule(AnsibleLintRule):
id = 'inline-env-var'
Expand Down Expand Up @@ -51,7 +54,9 @@ class EnvVarsInCommandRule(AnsibleLintRule):
FILENAME_KEY,
]

def matchtask(self, task: Dict[str, Any]) -> Union[bool, str]:
def matchtask(
self, file: 'Lintable', task: Dict[str, Any]
) -> Union[bool, str]:
if task["action"]["__ansible_module__"] in ['command']:
first_cmd_arg = get_first_cmd_arg(task)
if not first_cmd_arg:
Expand Down
9 changes: 7 additions & 2 deletions src/ansiblelint/rules/GitHasVersionRule.py
Expand Up @@ -18,10 +18,13 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

from typing import Any, Dict, Union
from typing import TYPE_CHECKING, Any, Dict, Union

from ansiblelint.rules import AnsibleLintRule

if TYPE_CHECKING:
from ansiblelint.file_utils import Lintable


class GitHasVersionRule(AnsibleLintRule):
id = 'git-latest'
Expand All @@ -34,7 +37,9 @@ class GitHasVersionRule(AnsibleLintRule):
tags = ['idempotency']
version_added = 'historic'

def matchtask(self, task: Dict[str, Any]) -> Union[bool, str]:
def matchtask(
self, file: 'Lintable', task: Dict[str, Any]
) -> Union[bool, str]:
return bool(
task['action']['__ansible_module__'] == 'git'
and task['action'].get('version', 'HEAD') == 'HEAD'
Expand Down
9 changes: 7 additions & 2 deletions src/ansiblelint/rules/MercurialHasRevisionRule.py
Expand Up @@ -18,10 +18,13 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

from typing import Any, Dict, Union
from typing import TYPE_CHECKING, Any, Dict, Union

from ansiblelint.rules import AnsibleLintRule

if TYPE_CHECKING:
from ansiblelint.file_utils import Lintable


class MercurialHasRevisionRule(AnsibleLintRule):
id = 'hg-latest'
Expand All @@ -34,7 +37,9 @@ class MercurialHasRevisionRule(AnsibleLintRule):
tags = ['idempotency']
version_added = 'historic'

def matchtask(self, task: Dict[str, Any]) -> Union[bool, str]:
def matchtask(
self, file: 'Lintable', task: Dict[str, Any]
) -> Union[bool, str]:
return bool(
task['action']['__ansible_module__'] == 'hg'
and task['action'].get('revision', 'default') == 'default'
Expand Down
10 changes: 8 additions & 2 deletions src/ansiblelint/rules/MissingFilePermissionsRule.py
Expand Up @@ -17,10 +17,14 @@
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
from typing import Any, Dict, Union
from typing import TYPE_CHECKING, Any, Dict, Union

from ansiblelint.rules import AnsibleLintRule

if TYPE_CHECKING:
from ansiblelint.file_utils import Lintable


# Despite documentation mentioning 'preserve' only these modules support it:
_modules_with_preserve = (
'copy',
Expand Down Expand Up @@ -60,7 +64,9 @@ class MissingFilePermissionsRule(AnsibleLintRule):
'lineinfile': False,
}

def matchtask(self, task: Dict[str, Any]) -> Union[bool, str]:
def matchtask(
self, file: 'Lintable', task: Dict[str, Any]
) -> Union[bool, str]:
module = task["action"]["__ansible_module__"]
mode = task['action'].get('mode', None)

Expand Down
10 changes: 7 additions & 3 deletions src/ansiblelint/rules/NestedJinjaRule.py
Expand Up @@ -22,10 +22,13 @@
# THE SOFTWARE.

import re
from typing import Any, Dict, Union
from typing import TYPE_CHECKING, Any, Dict, Union

from ansiblelint.rules import AnsibleLintRule

if TYPE_CHECKING:
from ansiblelint.file_utils import Lintable


class NestedJinjaRule(AnsibleLintRule):
id = 'no-jinja-nesting'
Expand All @@ -42,8 +45,9 @@ class NestedJinjaRule(AnsibleLintRule):

pattern = re.compile(r"{{(?:[^{}]*)?[^'\"]{{")

def matchtask(self, task: Dict[str, Any]) -> Union[bool, str]:

def matchtask(
self, file: 'Lintable', task: Dict[str, Any]
) -> Union[bool, str]:
command = "".join(
str(value)
# task properties are stored in the 'action' key
Expand Down
6 changes: 4 additions & 2 deletions src/ansiblelint/rules/NoFormattingInWhenRule.py
Expand Up @@ -31,7 +31,7 @@ def matchplay(
if 'roles' not in data or data['roles'] is None:
return errors
for role in data['roles']:
if self.matchtask(role):
if self.matchtask(file, role):
errors.append(self.create_matcherror(details=str({'when': role})))
if isinstance(data, list):
for play_item in data:
Expand All @@ -40,5 +40,7 @@ def matchplay(
errors = errors + sub_errors
return errors

def matchtask(self, task: Dict[str, Any]) -> Union[bool, str]:
def matchtask(
self, file: 'Lintable', task: Dict[str, Any]
) -> Union[bool, str]:
return 'when' in task and not self._is_valid(task['when'])
9 changes: 7 additions & 2 deletions src/ansiblelint/rules/NoTabsRule.py
@@ -1,11 +1,14 @@
# Copyright (c) 2016, Will Thames and contributors
# Copyright (c) 2018, Ansible Project
import sys
from typing import Any, Dict, Union
from typing import TYPE_CHECKING, Any, Dict, Union

from ansiblelint.rules import AnsibleLintRule
from ansiblelint.utils import nested_items

if TYPE_CHECKING:
from ansiblelint.file_utils import Lintable


class NoTabsRule(AnsibleLintRule):
id = 'no-tabs'
Expand All @@ -21,7 +24,9 @@ class NoTabsRule(AnsibleLintRule):
("lineinfile", "line"),
]

def matchtask(self, task: Dict[str, Any]) -> Union[bool, str]:
def matchtask(
self, file: 'Lintable', task: Dict[str, Any]
) -> Union[bool, str]:
for k, v, parent in nested_items(task):
if isinstance(k, str) and '\t' in k:
return True
Expand Down
9 changes: 7 additions & 2 deletions src/ansiblelint/rules/OctalPermissionsRule.py
Expand Up @@ -18,10 +18,13 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

from typing import Any, Dict, Union
from typing import TYPE_CHECKING, Any, Dict, Union

from ansiblelint.rules import AnsibleLintRule

if TYPE_CHECKING:
from ansiblelint.file_utils import Lintable


class OctalPermissionsRule(AnsibleLintRule):
id = 'risky-octal'
Expand Down Expand Up @@ -80,7 +83,9 @@ def is_invalid_permission(self, mode: int) -> bool:
or group_more_generous_than_user
)

def matchtask(self, task: Dict[str, Any]) -> Union[bool, str]:
def matchtask(
self, file: 'Lintable', task: Dict[str, Any]
) -> Union[bool, str]:
if task["action"]["__ansible_module__"] in self._modules:
mode = task['action'].get('mode', None)

Expand Down

0 comments on commit 9076ebf

Please sign in to comment.