diff --git a/.ansible-lint b/.ansible-lint index a2955847b4..caf18ee17d 100644 --- a/.ansible-lint +++ b/.ansible-lint @@ -22,14 +22,14 @@ use_default_rules: true # This makes linter to fully ignore rules/tags listed below skip_list: - skip_this_tag - - '401' + - git-latest # Report only a subset of tags and fully ignore any others # tags: -# - '206' +# - var-spacing # This makes the linter display but not fail for rules/tags listed below: warn_list: - skip_this_tag - - '401' + - git-latest - experimetal # experimental is included in the implicit list diff --git a/docs/rules.rst b/docs/rules.rst index bcf39a93d5..ac1fd536ef 100644 --- a/docs/rules.rst +++ b/docs/rules.rst @@ -26,26 +26,11 @@ for each available rule, use the ``-T`` option. The following shows the available tags in an example set of rules, and the rules associated with each tag: -.. code-block:: console - $ ansible-lint -v -T - - behaviour ['[503]'] - bug ['[304]'] - command-shell ['[305]', '[302]', '[304]', '[306]', '[301]', '[303]'] - deprecations ['[105]', '[104]', '[103]', '[101]', '[102]'] - experimental ['[208]'] - formatting ['[104]', '[203]', '[201]', '[204]', '[206]', '[205]', '[202]'] - idempotency ['[301]'] - idiom ['[601]', '[602]'] - metadata ['[701]', '[704]', '[703]', '[702]'] - module ['[404]', '[401]', '[403]', '[402]'] - oddity ['[501]'] - readability ['[502]'] - repeatability ['[401]', '[403]', '[402]'] - resources ['[302]', '[303]'] - safety ['[305]'] - task ['[502]', '[503]', '[504]', '[501]'] +.. command-output:: ansible-lint -v -T + :cwd: .. + :returncode: 0 + :nostderr: To run just the *idempotency* rules, for example, run the following: @@ -56,20 +41,13 @@ To run just the *idempotency* rules, for example, run the following: Excluding Rules ``````````````` -To exclude rules from the available set of rules, use the ``-x SKIP_LIST`` +To exclude rules using their identifiers or tags, use the ``-x SKIP_LIST`` option. For example, the following runs all of the rules except those with the -tags *readability* and *safety*: - -.. code-block:: bash - - $ ansible-lint -x readability,safety playbook.yml - -It's also possible to skip specific rules by passing the rule ID. For example, -the following excludes rule *502*: +tags *formatting* and *metadata*: .. code-block:: bash - $ ansible-lint -x 502 playbook.yml + $ ansible-lint -x formatting,metadata playbook.yml Ignoring Rules `````````````` @@ -101,8 +79,8 @@ a space-separated list. .. code-block:: yaml - - name: this would typically fire GitHasVersionRule 401 and BecomeUserWithoutBecomeRule 501 - become_user: alice # noqa 401 501 + - name: this would typically fire git-latest and partial-become + become_user: alice # noqa git-latest partial-become git: src=/path/to/git/repo dest=checkout If the rule is line-based, ``# noqa [rule_id]`` must be at the end of the @@ -110,10 +88,10 @@ particular line to be skipped .. code-block:: yaml - - name: this would typically fire LineTooLongRule 204 and VariableHasSpacesRule 206 + - name: this would typically fire LineTooLongRule 204 and var-spacing get_url: url: http://example.com/really_long_path/really_long_path/really_long_path/really_long_path/really_long_path/really_long_path/file.conf # noqa 204 - dest: "{{dest_proj_path}}/foo.conf" # noqa 206 + dest: "{{dest_proj_path}}/foo.conf" # noqa var-spacing It's also a good practice to comment the reasons why a task is being skipped. @@ -128,15 +106,15 @@ works with the *command* or *shell* modules only. Examples: .. code-block:: yaml - - name: this would typically fire CommandsInsteadOfArgumentRule 302 + - name: this would typically fire deprecated-command-syntax command: warn=no chmod 644 X - - name: this would typically fire CommandsInsteadOfModuleRule 303 + - name: this would typically fire command-instead-of-module command: git pull --rebase args: warn: False - - name: this would typically fire GitHasVersionRule 401 + - name: this would typically fire git-latest git: src=/path/to/git/repo dest=checkout tags: - skip_ansible_lint diff --git a/examples/playbooks/skiptasks.yml b/examples/playbooks/skiptasks.yml index c6a130b0ca..d186b2b768 100644 --- a/examples/playbooks/skiptasks.yml +++ b/examples/playbooks/skiptasks.yml @@ -3,68 +3,63 @@ tasks: - - name: test 401 + - name: test git-latest action: git - - name: test 402 + - name: test hg-latest action: hg - - name: test 303 + - name: test command-instead-of-module command: git log changed_when: False - - name: test 302 + - name: test deprecated-command-syntax command: creates=B chmod 644 A - - name: test invalid action (skip) - foo: bar - tags: - - skip_ansible_lint - - - name: test 401 (skip) + - name: test git-latest (skip) action: git tags: - skip_ansible_lint - - name: test 402 (skip) + - name: test hg-latest (skip) action: hg tags: - skip_ansible_lint - - name: test 303 (skip) + - name: test command-instead-of-module (skip) command: git log tags: - skip_ansible_lint - - name: test 302 (skip) + - name: test deprecated-command-syntax (skip) command: chmod 644 A tags: - skip_ansible_lint - - name: test 401 (don't warn) + - name: test git-latest (don't warn) command: git log args: warn: False changed_when: False - - name: test 402 (don't warn) + - name: test hg-latest (don't warn) command: chmod 644 A args: warn: False creates: B - - name: test 402 (warn) + - name: test hg-latest (warn) command: chmod 644 A args: warn: yes creates: B - - name: test 401 (don't warn single line) + - name: test git-latest (don't warn single line) command: warn=False chdir=/tmp/blah git log changed_when: False - - name: test 402 (don't warn single line) + - name: test hg-latest (don't warn single line) command: warn=no creates=B chmod 644 A - - name: test 402 (warn single line) + - name: test hg-latest (warn single line) command: warn=yes creates=B chmod 644 A diff --git a/examples/playbooks/tasks/directory with spaces/main.yml b/examples/playbooks/tasks/directory with spaces/main.yml index 600463ab81..dc6bc74a38 100644 --- a/examples/playbooks/tasks/directory with spaces/main.yml +++ b/examples/playbooks/tasks/directory with spaces/main.yml @@ -1,3 +1,3 @@ -# this should generate: 502: All tasks should be named +# this should generate: unnamed-task: All tasks should be named - assert: fail_msg: tasks in directory with spaces included diff --git a/examples/playbooks/tasks/simpletask.yml b/examples/playbooks/tasks/simpletask.yml index c35d592b98..59062ffa70 100644 --- a/examples/playbooks/tasks/simpletask.yml +++ b/examples/playbooks/tasks/simpletask.yml @@ -1,4 +1,4 @@ --- -# 502: All tasks should be named +# unnamed-task: All tasks should be named - assert: fail_msg: foo diff --git a/examples/playbooks/206.yml b/examples/playbooks/var-spacing.yml similarity index 92% rename from examples/playbooks/206.yml rename to examples/playbooks/var-spacing.yml index 30b91f28d7..09973adc1c 100644 --- a/examples/playbooks/206.yml +++ b/examples/playbooks/var-spacing.yml @@ -1,4 +1,4 @@ -# Should raise 206 at lines 25, 28, 31 +# Should raise var-spacing at lines 25, 28, 31 - hosts: all tasks: - name: good variable format @@ -29,7 +29,7 @@ - name: bad variable format debug: msg: "{{bad_format }}" - - name: not a jinja variable # noqa 206 + - name: not a jinja variable # noqa var-spacing debug: msg: "data = ${lookup{$local_part}lsearch{/etc/aliases}}" - name: JSON inside jinja is valid diff --git a/examples/roles/role_with_task_inclusions/tasks/imported_tasks.yml b/examples/roles/role_with_task_inclusions/tasks/imported_tasks.yml index 504d51e259..7a5eb09ca2 100644 --- a/examples/roles/role_with_task_inclusions/tasks/imported_tasks.yml +++ b/examples/roles/role_with_task_inclusions/tasks/imported_tasks.yml @@ -1,2 +1,2 @@ -# this task is missing a name (502) +# this task is missing a name (unnamed-task) - ping: diff --git a/examples/roles/role_with_task_inclusions/tasks/included_tasks.yml b/examples/roles/role_with_task_inclusions/tasks/included_tasks.yml index 504d51e259..7a5eb09ca2 100644 --- a/examples/roles/role_with_task_inclusions/tasks/included_tasks.yml +++ b/examples/roles/role_with_task_inclusions/tasks/included_tasks.yml @@ -1,2 +1,2 @@ -# this task is missing a name (502) +# this task is missing a name (unnamed-task) - ping: diff --git a/src/ansiblelint/__main__.py b/src/ansiblelint/__main__.py index e93bde46a6..3f85dee732 100755 --- a/src/ansiblelint/__main__.py +++ b/src/ansiblelint/__main__.py @@ -35,8 +35,9 @@ from ansiblelint._prerun import check_ansible_presence, prepare_environment from ansiblelint.app import App from ansiblelint.color import console, console_options, console_stderr, reconfigure, render_yaml -from ansiblelint.config import options +from ansiblelint.config import options, used_old_tags from ansiblelint.file_utils import cwd +from ansiblelint.skip_utils import normalize_tag from ansiblelint.version import __version__ if TYPE_CHECKING: @@ -84,6 +85,11 @@ def initialize_options(arguments: List[str]): for k, v in new_options.__dict__.items(): setattr(options, k, v) + # rename deprecated ids/tags to newer names + options.tags = [normalize_tag(tag) for tag in options.tags] + options.skip_list = [normalize_tag(tag) for tag in options.skip_list] + options.warn_list = [normalize_tag(tag) for tag in options.warn_list] + def report_outcome(result: "LintResult", options, mark_as_success=False) -> int: """Display information about how to skip found rules. @@ -106,13 +112,22 @@ def report_outcome(result: "LintResult", options, mark_as_success=False) -> int: else: warnings += 1 + entries = [] for key in sorted(matched_rules.keys()): if {key, *matched_rules[key].tags}.isdisjoint(options.warn_list): - msg += f" - '{key}' # {matched_rules[key].shortdesc}\n" + entries.append(f" - {key} # {matched_rules[key].shortdesc}\n") for match in result.matches: if "experimental" in match.rule.tags: - msg += " - experimental # all rules tagged as experimental\n" + entries.append(" - experimental # all rules tagged as experimental\n") break + msg += "".join(sorted(entries)) + + for k, v in used_old_tags.items(): + _logger.warning( + "Replaced deprecated tag '%s' with '%s' but it will become an " + "error in the future.", + k, + v) if result.matches and not options.quiet: console_stderr.print( diff --git a/src/ansiblelint/_internal/rules.py b/src/ansiblelint/_internal/rules.py index f3e7294b15..c0b02d6943 100644 --- a/src/ansiblelint/_internal/rules.py +++ b/src/ansiblelint/_internal/rules.py @@ -19,6 +19,7 @@ class BaseRule: version_added: str = "" severity: str = "" link: str = "" + has_dynamic_tags: bool = False def getmatches(self, file: "Lintable") -> List["MatchError"]: """Return all matches while ignoring exceptions.""" @@ -71,7 +72,7 @@ def __lt__(self, other: "BaseRule") -> bool: class RuntimeErrorRule(BaseRule): """Used to identify errors.""" - id = '999' + id = 'internal-error' shortdesc = 'Unexpected internal error' description = ( 'This error can be caused by internal bugs but also by ' @@ -86,7 +87,7 @@ class RuntimeErrorRule(BaseRule): class AnsibleParserErrorRule(BaseRule): """Used to mark errors received from Ansible.""" - id = '998' + id = 'parser-error' shortdesc = 'AnsibleParserError' description = ( 'Ansible parser fails, this usually indicate invalid file.') @@ -98,7 +99,7 @@ class AnsibleParserErrorRule(BaseRule): class LoadingFailureRule(BaseRule): """File loading failure.""" - id = '901' + id = 'load-failure' shortdesc = 'Failed to load or parse file' description = 'Linter failed to process a YAML file, possible not an Ansible file.' severity = 'VERY_HIGH' diff --git a/src/ansiblelint/config.py b/src/ansiblelint/config.py index a60b6f2279..3117c9bd9a 100644 --- a/src/ansiblelint/config.py +++ b/src/ansiblelint/config.py @@ -1,5 +1,6 @@ """Store configuration options as a singleton.""" from argparse import Namespace +from typing import Dict DEFAULT_KINDS = [ # Do not sort this list, order matters. @@ -41,3 +42,6 @@ mock_roles=[], loop_var_prefix=None ) + +# Used to store detected tag deprecations +used_old_tags: Dict[str, str] = {} diff --git a/src/ansiblelint/constants.py b/src/ansiblelint/constants.py index b12adaa82a..a807a0853b 100644 --- a/src/ansiblelint/constants.py +++ b/src/ansiblelint/constants.py @@ -57,3 +57,39 @@ def main(): from collections import OrderedDict as odict # noqa: 401 except ImportError: pass + +# Deprecated tags/ids and their newer names +RENAMED_TAGS = { + '102': 'no-jinja-when', + '104': 'deprecated-bare-vars', + '105': 'deprecated-module', + '106': 'role-name', + '202': 'risky-octal', + '203': 'no-tabs', + '205': 'playbook-extension', + '206': 'var-spacing', + '207': 'no-jinja-nesting', + '208': 'risky-file-permissions', + '301': 'no-changed-when', + '302': 'deprecated-command-syntax', + '303': 'command-instead-of-module', + '304': 'inline-env-var', + '305': 'command-instead-of-shell', + '306': 'risky-shell-pipe', + '401': 'git-latest', + '402': 'hg-latest', + '403': 'package-latest', + '404': 'no-relative-paths', + '501': 'partial-become', + '502': 'unnamed-task', + '503': 'no-handler', + '504': 'deprecated-local-action', + '505': 'missing-import', + '601': 'literal-compare', + '602': 'empty-string-compare', + '701': 'meta-no-info', + '702': 'meta-no-tags', + '703': 'meta-incorrect', + '704': 'meta-video-links', + '911': 'syntax-check', +} diff --git a/src/ansiblelint/formatters/__init__.py b/src/ansiblelint/formatters/__init__.py index e310e740a6..24ee9d24bb 100644 --- a/src/ansiblelint/formatters/__init__.py +++ b/src/ansiblelint/formatters/__init__.py @@ -118,7 +118,7 @@ def format(self, match: "MatchError") -> str: col = "" return ( f"::{level} file={file_path},line={line_num}{col},severity={severity}" - f"::E{rule_id} {violation_details}" + f"::{rule_id} {violation_details}" ) @staticmethod diff --git a/src/ansiblelint/generate_docs.py b/src/ansiblelint/generate_docs.py index 7a022d85e6..a9af1d3582 100644 --- a/src/ansiblelint/generate_docs.py +++ b/src/ansiblelint/generate_docs.py @@ -30,26 +30,14 @@ def rules_as_rst(rules: RulesCollection) -> str: r = DOC_HEADER for d in rules: - if not hasattr(d, 'id'): - _logger.warning( - "Rule %s skipped from being documented as it does not have an `id` attribute.", - d.__class__.__name__) - continue - if d.id.endswith('01'): - - section = '{} Rules ({}xx)'.format( - d.tags[0].title(), - d.id[-3:-2]) - r += f'\n\n{section}\n{ "-" * len(section) }' - - title = f"{d.id}: {d.shortdesc}" + title = f"{d.id}" description = d.description if d.link: description += " `(more) <%s>`_" % d.link - r += f"\n\n.. _{d.id}:\n\n{title}\n{'*' * len(title)}\n\n{description}" + r += f"\n\n.. _{d.id}:\n\n{title}\n{'*' * len(title)}\n\n{d.shortdesc}\n\n{description}" return r diff --git a/src/ansiblelint/rules/AnsibleSyntaxCheckRule.py b/src/ansiblelint/rules/AnsibleSyntaxCheckRule.py index 6e55c7e587..ad3766a096 100644 --- a/src/ansiblelint/rules/AnsibleSyntaxCheckRule.py +++ b/src/ansiblelint/rules/AnsibleSyntaxCheckRule.py @@ -24,7 +24,7 @@ class AnsibleSyntaxCheckRule(AnsibleLintRule): """Ansible syntax check report failure.""" - id = "911" + id = "syntax-check" shortdesc = "Ansible syntax check failed" description = "Running ansible-playbook --syntax-check ... reported an error." severity = "VERY_HIGH" diff --git a/src/ansiblelint/rules/BecomeUserWithoutBecomeRule.py b/src/ansiblelint/rules/BecomeUserWithoutBecomeRule.py index 15b32d5135..cf32541d31 100644 --- a/src/ansiblelint/rules/BecomeUserWithoutBecomeRule.py +++ b/src/ansiblelint/rules/BecomeUserWithoutBecomeRule.py @@ -74,11 +74,11 @@ def _become_user_without_become(becomeuserabove: bool, data: "odict[str, Any]") class BecomeUserWithoutBecomeRule(AnsibleLintRule): - id = '501' + id = 'partial-become' shortdesc = 'become_user requires become to work as expected' description = '``become_user`` without ``become`` will not actually change user' severity = 'VERY_HIGH' - tags = ['task', 'unpredictability'] + tags = ['unpredictability'] version_added = 'historic' def matchplay(self, file: "Lintable", data: "odict[str, Any]") -> List["MatchError"]: diff --git a/src/ansiblelint/rules/CommandHasChangesCheckRule.py b/src/ansiblelint/rules/CommandHasChangesCheckRule.py index 83ac6d71bc..1677a830f3 100644 --- a/src/ansiblelint/rules/CommandHasChangesCheckRule.py +++ b/src/ansiblelint/rules/CommandHasChangesCheckRule.py @@ -24,7 +24,7 @@ class CommandHasChangesCheckRule(AnsibleLintRule): - id = '301' + id = 'no-changed-when' shortdesc = 'Commands should not change things if nothing needs doing' description = ( 'Commands should either read information (and thus set ' diff --git a/src/ansiblelint/rules/CommandsInsteadOfArgumentsRule.py b/src/ansiblelint/rules/CommandsInsteadOfArgumentsRule.py index c77966e361..26da570aa8 100644 --- a/src/ansiblelint/rules/CommandsInsteadOfArgumentsRule.py +++ b/src/ansiblelint/rules/CommandsInsteadOfArgumentsRule.py @@ -26,14 +26,14 @@ class CommandsInsteadOfArgumentsRule(AnsibleLintRule): - id = '302' + id = 'deprecated-command-syntax' shortdesc = 'Using command rather than an argument to e.g. file' description = ( 'Executing a command when there are arguments to modules ' 'is generally a bad idea' ) severity = 'VERY_HIGH' - tags = ['command-shell', 'resources'] + tags = ['command-shell', 'deprecations'] version_added = 'historic' _commands = ['command', 'shell', 'raw'] diff --git a/src/ansiblelint/rules/CommandsInsteadOfModulesRule.py b/src/ansiblelint/rules/CommandsInsteadOfModulesRule.py index 721ed7d88f..cc7e64153d 100644 --- a/src/ansiblelint/rules/CommandsInsteadOfModulesRule.py +++ b/src/ansiblelint/rules/CommandsInsteadOfModulesRule.py @@ -26,14 +26,14 @@ class CommandsInsteadOfModulesRule(AnsibleLintRule): - id = '303' + id = 'command-instead-of-module' shortdesc = 'Using command rather than module' description = ( 'Executing a command when there is an Ansible module ' 'is generally a bad idea' ) severity = 'HIGH' - tags = ['command-shell', 'resources'] + tags = ['command-shell', 'idiom'] version_added = 'historic' _commands = ['command', 'shell'] diff --git a/src/ansiblelint/rules/ComparisonToEmptyStringRule.py b/src/ansiblelint/rules/ComparisonToEmptyStringRule.py index df27c0132b..1b6faa9759 100644 --- a/src/ansiblelint/rules/ComparisonToEmptyStringRule.py +++ b/src/ansiblelint/rules/ComparisonToEmptyStringRule.py @@ -8,7 +8,7 @@ class ComparisonToEmptyStringRule(AnsibleLintRule): - id = '602' + id = 'empty-string-compare' shortdesc = "Don't compare to empty string" description = ( 'Use ``when: var|length > 0`` rather than ``when: var != ""`` (or ' diff --git a/src/ansiblelint/rules/ComparisonToLiteralBoolRule.py b/src/ansiblelint/rules/ComparisonToLiteralBoolRule.py index e34125bc9b..4b574d064c 100644 --- a/src/ansiblelint/rules/ComparisonToLiteralBoolRule.py +++ b/src/ansiblelint/rules/ComparisonToLiteralBoolRule.py @@ -7,7 +7,7 @@ class ComparisonToLiteralBoolRule(AnsibleLintRule): - id = '601' + id = 'literal-compare' shortdesc = "Don't compare to literal True/False" description = ( 'Use ``when: var`` rather than ``when: var == True`` ' diff --git a/src/ansiblelint/rules/DeprecatedModuleRule.py b/src/ansiblelint/rules/DeprecatedModuleRule.py index 8225ffbd0e..701be85f42 100644 --- a/src/ansiblelint/rules/DeprecatedModuleRule.py +++ b/src/ansiblelint/rules/DeprecatedModuleRule.py @@ -6,7 +6,7 @@ class DeprecatedModuleRule(AnsibleLintRule): - id = '105' + id = 'deprecated-module' shortdesc = 'Deprecated module' description = ( 'These are deprecated modules, some modules are kept ' diff --git a/src/ansiblelint/rules/EnvVarsInCommandRule.py b/src/ansiblelint/rules/EnvVarsInCommandRule.py index bad9f2207b..36d14ec56f 100644 --- a/src/ansiblelint/rules/EnvVarsInCommandRule.py +++ b/src/ansiblelint/rules/EnvVarsInCommandRule.py @@ -25,14 +25,14 @@ class EnvVarsInCommandRule(AnsibleLintRule): - id = '304' + id = 'inline-env-var' shortdesc = "Command module does not accept setting environment variables inline" description = ( 'Use ``environment:`` to set environment variables ' 'or use ``shell`` module which accepts both' ) severity = 'VERY_HIGH' - tags = ['command-shell', 'bug'] + tags = ['command-shell', 'idiom'] version_added = 'historic' expected_args = ['chdir', 'creates', 'executable', 'removes', 'stdin', 'warn', diff --git a/src/ansiblelint/rules/GitHasVersionRule.py b/src/ansiblelint/rules/GitHasVersionRule.py index e4102fad73..94ff7a3665 100644 --- a/src/ansiblelint/rules/GitHasVersionRule.py +++ b/src/ansiblelint/rules/GitHasVersionRule.py @@ -24,14 +24,14 @@ class GitHasVersionRule(AnsibleLintRule): - id = '401' + id = 'git-latest' shortdesc = 'Git checkouts must contain explicit version' description = ( 'All version control checkouts must point to ' 'an explicit commit or tag, not just ``latest``' ) severity = 'MEDIUM' - tags = ['module', 'repeatability'] + tags = ['idempotency'] version_added = 'historic' def matchtask(self, task: Dict[str, Any]) -> Union[bool, str]: diff --git a/src/ansiblelint/rules/IncludeMissingFileRule.py b/src/ansiblelint/rules/IncludeMissingFileRule.py index 9042cbd07c..b7e13e82a9 100644 --- a/src/ansiblelint/rules/IncludeMissingFileRule.py +++ b/src/ansiblelint/rules/IncludeMissingFileRule.py @@ -17,15 +17,15 @@ class IncludeMissingFileRule(AnsibleLintRule): - id = '505' + id = 'missing-import' shortdesc = 'referenced files must exist' description = ( - 'All files referenced by by include / import tasks ' + 'All files referenced by include / import tasks ' 'must exist. The check excludes files with jinja2 ' 'templates in the filename.' ) severity = 'MEDIUM' - tags = ['task', 'bug'] + tags = ['idiom'] version_added = 'v4.3.0' def matchplay(self, file: "Lintable", data: "odict[str, Any]") -> List["MatchError"]: diff --git a/src/ansiblelint/rules/MercurialHasRevisionRule.py b/src/ansiblelint/rules/MercurialHasRevisionRule.py index a0ef8ff84b..d2d69f849a 100644 --- a/src/ansiblelint/rules/MercurialHasRevisionRule.py +++ b/src/ansiblelint/rules/MercurialHasRevisionRule.py @@ -24,14 +24,14 @@ class MercurialHasRevisionRule(AnsibleLintRule): - id = '402' + id = 'hg-latest' shortdesc = 'Mercurial checkouts must contain explicit revision' description = ( 'All version control checkouts must point to ' 'an explicit commit or tag, not just ``latest``' ) severity = 'MEDIUM' - tags = ['module', 'repeatability'] + tags = ['idempotency'] version_added = 'historic' def matchtask(self, task: Dict[str, Any]) -> Union[bool, str]: diff --git a/src/ansiblelint/rules/MetaChangeFromDefaultRule.py b/src/ansiblelint/rules/MetaChangeFromDefaultRule.py index 37e979adfd..40caa639e9 100644 --- a/src/ansiblelint/rules/MetaChangeFromDefaultRule.py +++ b/src/ansiblelint/rules/MetaChangeFromDefaultRule.py @@ -13,7 +13,7 @@ class MetaChangeFromDefaultRule(AnsibleLintRule): - id = '703' + id = 'meta-incorrect' shortdesc = 'meta/main.yml default values should be changed' field_defaults = [ ('author', 'your name'), diff --git a/src/ansiblelint/rules/MetaMainHasInfoRule.py b/src/ansiblelint/rules/MetaMainHasInfoRule.py index 70c00a4e3e..3271372306 100644 --- a/src/ansiblelint/rules/MetaMainHasInfoRule.py +++ b/src/ansiblelint/rules/MetaMainHasInfoRule.py @@ -52,7 +52,7 @@ def _galaxy_info_errors_itr( class MetaMainHasInfoRule(AnsibleLintRule): - id = '701' + id = 'meta-no-info' shortdesc = 'meta/main.yml should contain relevant info' str_info = META_STR_INFO info = META_INFO diff --git a/src/ansiblelint/rules/MetaTagValidRule.py b/src/ansiblelint/rules/MetaTagValidRule.py index f79391559f..8fe731f703 100644 --- a/src/ansiblelint/rules/MetaTagValidRule.py +++ b/src/ansiblelint/rules/MetaTagValidRule.py @@ -15,7 +15,7 @@ class MetaTagValidRule(AnsibleLintRule): - id = '702' + id = 'meta-no-tags' shortdesc = 'Tags must contain lowercase letters and digits only' description = ( 'Tags must contain lowercase letters and digits only, ' diff --git a/src/ansiblelint/rules/MetaVideoLinksRule.py b/src/ansiblelint/rules/MetaVideoLinksRule.py index 16daae01ee..a783424a95 100644 --- a/src/ansiblelint/rules/MetaVideoLinksRule.py +++ b/src/ansiblelint/rules/MetaVideoLinksRule.py @@ -14,7 +14,7 @@ class MetaVideoLinksRule(AnsibleLintRule): - id = '704' + id = 'meta-video-links' shortdesc = "meta/main.yml video_links should be formatted correctly" description = ( 'Items in ``video_links`` in meta/main.yml should be ' diff --git a/src/ansiblelint/rules/MissingFilePermissionsRule.py b/src/ansiblelint/rules/MissingFilePermissionsRule.py index 1cca5ca397..876cc5c997 100644 --- a/src/ansiblelint/rules/MissingFilePermissionsRule.py +++ b/src/ansiblelint/rules/MissingFilePermissionsRule.py @@ -29,7 +29,7 @@ class MissingFilePermissionsRule(AnsibleLintRule): - id = "208" + id = "risky-file-permissions" shortdesc = 'File permissions unset or incorrect' description = ( "Missing or unsupported mode parameter can cause unexpected file " diff --git a/src/ansiblelint/rules/NestedJinjaRule.py b/src/ansiblelint/rules/NestedJinjaRule.py index 64dadbbb66..73792ae00e 100644 --- a/src/ansiblelint/rules/NestedJinjaRule.py +++ b/src/ansiblelint/rules/NestedJinjaRule.py @@ -28,7 +28,7 @@ class NestedJinjaRule(AnsibleLintRule): - id = '207' + id = 'no-jinja-nesting' shortdesc = 'Nested jinja pattern' description = ( "There should not be any nested jinja pattern. " diff --git a/src/ansiblelint/rules/NoFormattingInWhenRule.py b/src/ansiblelint/rules/NoFormattingInWhenRule.py index c684c834e2..eb3e978030 100644 --- a/src/ansiblelint/rules/NoFormattingInWhenRule.py +++ b/src/ansiblelint/rules/NoFormattingInWhenRule.py @@ -9,7 +9,7 @@ class NoFormattingInWhenRule(AnsibleLintRule): - id = '102' + id = 'no-jinja-when' shortdesc = 'No Jinja2 in when' description = '``when`` is a raw Jinja2 expression, remove redundant {{ }} from variable(s).' severity = 'HIGH' diff --git a/src/ansiblelint/rules/NoTabsRule.py b/src/ansiblelint/rules/NoTabsRule.py index c576cea997..a44fc142a9 100644 --- a/src/ansiblelint/rules/NoTabsRule.py +++ b/src/ansiblelint/rules/NoTabsRule.py @@ -7,7 +7,7 @@ class NoTabsRule(AnsibleLintRule): - id = '203' + id = 'no-tabs' shortdesc = 'Most files should not contain tabs' description = 'Tabs can cause unexpected display issues, use spaces' severity = 'LOW' diff --git a/src/ansiblelint/rules/OctalPermissionsRule.py b/src/ansiblelint/rules/OctalPermissionsRule.py index 6ad7fd37b7..b514dc213d 100644 --- a/src/ansiblelint/rules/OctalPermissionsRule.py +++ b/src/ansiblelint/rules/OctalPermissionsRule.py @@ -24,7 +24,7 @@ class OctalPermissionsRule(AnsibleLintRule): - id = '202' + id = 'risky-octal' shortdesc = 'Octal file permissions must contain leading zero or be a string' description = ( 'Numeric file permissions without leading zero can behave ' diff --git a/src/ansiblelint/rules/PackageIsNotLatestRule.py b/src/ansiblelint/rules/PackageIsNotLatestRule.py index 18a902b537..ddf61c14c2 100644 --- a/src/ansiblelint/rules/PackageIsNotLatestRule.py +++ b/src/ansiblelint/rules/PackageIsNotLatestRule.py @@ -24,14 +24,14 @@ class PackageIsNotLatestRule(AnsibleLintRule): - id = '403' + id = 'package-latest' shortdesc = 'Package installs should not use latest' description = ( 'Package installs should use ``state=present`` ' 'with or without a version' ) severity = 'VERY_LOW' - tags = ['module', 'repeatability'] + tags = ['idempotency'] version_added = 'historic' _package_managers = [ diff --git a/src/ansiblelint/rules/PlaybookExtension.py b/src/ansiblelint/rules/PlaybookExtension.py index 5996ad6cac..a49376377b 100644 --- a/src/ansiblelint/rules/PlaybookExtension.py +++ b/src/ansiblelint/rules/PlaybookExtension.py @@ -10,7 +10,7 @@ class PlaybookExtension(AnsibleLintRule): - id = '205' + id = 'playbook-extension' shortdesc = 'Use ".yml" or ".yaml" playbook extension' description = 'Playbooks should have the ".yml" or ".yaml" extension' severity = 'MEDIUM' diff --git a/src/ansiblelint/rules/RoleLoopVarPrefix.py b/src/ansiblelint/rules/RoleLoopVarPrefix.py index 1905dc9608..ac2ca3576d 100644 --- a/src/ansiblelint/rules/RoleLoopVarPrefix.py +++ b/src/ansiblelint/rules/RoleLoopVarPrefix.py @@ -25,7 +25,7 @@ class RoleLoopVarPrefix(AnsibleLintRule): Looping inside roles has the risk of clashing with loops from user-playbooks.\ """ - tags = ['no-loop-var-prefix', 'safety'] + tags = ['idiom'] prefix = "" severity = 'MEDIUM' diff --git a/src/ansiblelint/rules/RoleNames.py b/src/ansiblelint/rules/RoleNames.py index eeae96819b..71a0c6c236 100644 --- a/src/ansiblelint/rules/RoleNames.py +++ b/src/ansiblelint/rules/RoleNames.py @@ -39,7 +39,7 @@ def _remove_prefix(text: str, prefix: str) -> str: class RoleNames(AnsibleLintRule): - id = '106' + id = 'role-name' shortdesc = ( "Role name {0} does not match ``%s`` pattern" % ROLE_NAME_REGEX ) diff --git a/src/ansiblelint/rules/RoleRelativePath.py b/src/ansiblelint/rules/RoleRelativePath.py index 7a5c5793ac..06f58328f2 100644 --- a/src/ansiblelint/rules/RoleRelativePath.py +++ b/src/ansiblelint/rules/RoleRelativePath.py @@ -7,11 +7,11 @@ class RoleRelativePath(AnsibleLintRule): - id = '404' + id = 'no-relative-paths' shortdesc = "Doesn't need a relative path in role" description = '``copy`` and ``template`` do not need to use relative path for ``src``' severity = 'HIGH' - tags = ['module'] + tags = ['idiom'] version_added = 'v4.0.0' _module_to_path_folder = { diff --git a/src/ansiblelint/rules/ShellWithoutPipefail.py b/src/ansiblelint/rules/ShellWithoutPipefail.py index 373b4c081c..801f9a2d63 100644 --- a/src/ansiblelint/rules/ShellWithoutPipefail.py +++ b/src/ansiblelint/rules/ShellWithoutPipefail.py @@ -5,7 +5,7 @@ class ShellWithoutPipefail(AnsibleLintRule): - id = '306' + id = 'risky-shell-pipe' shortdesc = 'Shells that use pipes should set the pipefail option' description = ( 'Without the pipefail option set, a shell command that ' diff --git a/src/ansiblelint/rules/TaskHasNameRule.py b/src/ansiblelint/rules/TaskHasNameRule.py index f4ee1bbdea..661910844c 100644 --- a/src/ansiblelint/rules/TaskHasNameRule.py +++ b/src/ansiblelint/rules/TaskHasNameRule.py @@ -24,14 +24,14 @@ class TaskHasNameRule(AnsibleLintRule): - id = '502' + id = 'unnamed-task' shortdesc = 'All tasks should be named' description = ( 'All tasks should have a distinct name for readability ' 'and for ``--start-at-task`` to work' ) severity = 'MEDIUM' - tags = ['task', 'readability'] + tags = ['idiom'] version_added = 'historic' _nameless_tasks = ['meta', 'debug', 'include_role', 'import_role', diff --git a/src/ansiblelint/rules/TaskNoLocalAction.py b/src/ansiblelint/rules/TaskNoLocalAction.py index 96b9e279fe..04afaa13ad 100644 --- a/src/ansiblelint/rules/TaskNoLocalAction.py +++ b/src/ansiblelint/rules/TaskNoLocalAction.py @@ -5,11 +5,11 @@ class TaskNoLocalAction(AnsibleLintRule): - id = '504' + id = 'deprecated-local-action' shortdesc = "Do not use 'local_action', use 'delegate_to: localhost'" description = 'Do not use ``local_action``, use ``delegate_to: localhost``' severity = 'MEDIUM' - tags = ['task'] + tags = ['deprecations'] version_added = 'v4.0.0' def match(self, line: str) -> bool: diff --git a/src/ansiblelint/rules/UseCommandInsteadOfShellRule.py b/src/ansiblelint/rules/UseCommandInsteadOfShellRule.py index f22a3e15bb..221fa58a67 100644 --- a/src/ansiblelint/rules/UseCommandInsteadOfShellRule.py +++ b/src/ansiblelint/rules/UseCommandInsteadOfShellRule.py @@ -24,7 +24,7 @@ class UseCommandInsteadOfShellRule(AnsibleLintRule): - id = '305' + id = 'command-instead-of-shell' shortdesc = 'Use shell only when shell functionality is required' description = ( 'Shell should only be used when piping, redirecting ' @@ -32,7 +32,7 @@ class UseCommandInsteadOfShellRule(AnsibleLintRule): 'for some of those!)' ) severity = 'HIGH' - tags = ['command-shell', 'safety'] + tags = ['command-shell', 'idiom'] version_added = 'historic' def matchtask(self, task: Dict[str, Any]) -> Union[bool, str]: diff --git a/src/ansiblelint/rules/UseHandlerRatherThanWhenChangedRule.py b/src/ansiblelint/rules/UseHandlerRatherThanWhenChangedRule.py index 44bd9e4279..b34fdf93f9 100644 --- a/src/ansiblelint/rules/UseHandlerRatherThanWhenChangedRule.py +++ b/src/ansiblelint/rules/UseHandlerRatherThanWhenChangedRule.py @@ -31,14 +31,14 @@ def _changed_in_when(item: str) -> bool: class UseHandlerRatherThanWhenChangedRule(AnsibleLintRule): - id = '503' + id = 'no-handler' shortdesc = 'Tasks that run when changed should likely be handlers' description = ( 'If a task has a ``when: result.changed`` setting, it is effectively ' 'acting as a handler' ) severity = 'MEDIUM' - tags = ['task', 'behaviour'] + tags = ['idiom'] version_added = 'historic' def matchtask(self, task: Dict[str, Any]) -> Union[bool, str]: diff --git a/src/ansiblelint/rules/UsingBareVariablesIsDeprecatedRule.py b/src/ansiblelint/rules/UsingBareVariablesIsDeprecatedRule.py index 12110c7021..06f108643c 100644 --- a/src/ansiblelint/rules/UsingBareVariablesIsDeprecatedRule.py +++ b/src/ansiblelint/rules/UsingBareVariablesIsDeprecatedRule.py @@ -26,7 +26,7 @@ class UsingBareVariablesIsDeprecatedRule(AnsibleLintRule): - id = '104' + id = 'deprecated-bare-vars' shortdesc = 'Using bare variables is deprecated' description = ( 'Using bare variables is deprecated. Update your ' @@ -34,7 +34,7 @@ class UsingBareVariablesIsDeprecatedRule(AnsibleLintRule): 'syntax ``{{ your_variable }}``' ) severity = 'VERY_HIGH' - tags = ['deprecations', 'formatting'] + tags = ['deprecations'] version_added = 'historic' _jinja = re.compile(r"{{.*}}", re.DOTALL) diff --git a/src/ansiblelint/rules/VariableHasSpacesRule.py b/src/ansiblelint/rules/VariableHasSpacesRule.py index 1f15da0740..e8eac89204 100644 --- a/src/ansiblelint/rules/VariableHasSpacesRule.py +++ b/src/ansiblelint/rules/VariableHasSpacesRule.py @@ -10,7 +10,7 @@ class VariableHasSpacesRule(AnsibleLintRule): - id = '206' + id = 'var-spacing' base_msg = 'Variables should have spaces before and after: ' shortdesc = base_msg + ' {{ var_name }}' description = 'Variables should have spaces before and after: ``{{ var_name }}``' @@ -37,12 +37,12 @@ def matchtask(self, task: Dict[str, Any]) -> Union[bool, str]: from ansiblelint.rules import RulesCollection from ansiblelint.runner import Runner - def test_206() -> None: + def test_var_spacing() -> None: """Verify rule.""" collection = RulesCollection() collection.register(VariableHasSpacesRule()) - lintable = Lintable("examples/playbooks/206.yml") + lintable = Lintable("examples/playbooks/var-spacing.yml") results = Runner( lintable, rules=collection).run() diff --git a/src/ansiblelint/rules/YamllintRule.py b/src/ansiblelint/rules/YamllintRule.py index 0d076d5fa8..f56f4be205 100644 --- a/src/ansiblelint/rules/YamllintRule.py +++ b/src/ansiblelint/rules/YamllintRule.py @@ -42,13 +42,14 @@ class YamllintRule(AnsibleLintRule): - id = 'YAML' + id = 'yaml' shortdesc = 'Violations reported by yamllint' description = DESCRIPTION severity = 'VERY_LOW' - tags = ['formatting', 'experimental', 'yamllint'] + tags = ['formatting', 'yaml'] version_added = 'v5.0.0' config = None + has_dynamic_tags = True if "yamllint.config" in sys.modules: config = YamlLintConfig(content=YAMLLINT_CONFIG) # if we detect local yamllint config we use it but raise a warning diff --git a/src/ansiblelint/rules/__init__.py b/src/ansiblelint/rules/__init__.py index b3b309f41f..4a51bdde95 100644 --- a/src/ansiblelint/rules/__init__.py +++ b/src/ansiblelint/rules/__init__.py @@ -231,7 +231,10 @@ def run(self, file: Lintable, tags=set(), skip_list: List[str] = []) -> List[Mat )] for rule in self.rules: - if not tags or not set(rule.tags).union([rule.id]).isdisjoint(tags): + if ( + not tags or + rule.has_dynamic_tags or + not set(rule.tags).union([rule.id]).isdisjoint(tags)): rule_definition = set(rule.tags) rule_definition.add(rule.id) if set(rule_definition).isdisjoint(skip_list): @@ -251,7 +254,6 @@ def __repr__(self) -> str: def listtags(self) -> str: tag_desc = { "behaviour": "Indicates a bad practice or behavior", - "bug": "Likely wrong usage pattern", "command-shell": "Specific to use of command and shell modules", "core": "Related to internal implementation of the linter", "deprecations": "Indicate use of features that are removed from Ansible", @@ -261,25 +263,21 @@ def listtags(self) -> str: "Possible indication that consequent runs would produce different results", "idiom": "Anti-pattern detected, likely to cause undesired behavior", "metadata": "Invalid metadata, likely related to galaxy, collections or roles", - "module": "Incorrect module usage", - "readability": "Reduce code readability", - "repeatability": "Action that may produce different result between runs", - "resources": "Unoptimal feature use", - "safety": "Increase security risk", - "task": "Rules specific to tasks", - "unpredictability": "This will produce unexpected behavior when run", + "yaml": "External linter which will also produce its own rule codes." } tags = defaultdict(list) for rule in self.rules: for tag in rule.tags: tags[tag].append(rule.id) - result = "# List of tags and how they are used\n" + result = "# List of tags and rules they cover\n" for tag in sorted(tags): desc = tag_desc.get(tag, None) if desc: result += f"{tag}: # {desc}\n" else: result += f"{tag}:\n" - result += f" rules: [{', '.join(tags[tag])}]\n" + # result += f" rules:\n" + for name in tags[tag]: + result += f" - {name}\n" return result diff --git a/src/ansiblelint/skip_utils.py b/src/ansiblelint/skip_utils.py index 13aed425af..4467363955 100644 --- a/src/ansiblelint/skip_utils.py +++ b/src/ansiblelint/skip_utils.py @@ -26,7 +26,8 @@ import ruamel.yaml -from ansiblelint.constants import FileType +from ansiblelint.config import used_old_tags +from ansiblelint.constants import RENAMED_TAGS, FileType _logger = logging.getLogger(__name__) @@ -192,4 +193,12 @@ def traverse_yaml(obj: Any) -> None: for line in comment_obj_str.split(r'\n'): rule_id_list.extend(get_rule_skips_from_line(line)) - return rule_id_list + return [normalize_tag(tag) for tag in rule_id_list] + + +def normalize_tag(tag: str) -> str: + """Return current name of tag.""" + if tag in RENAMED_TAGS: + used_old_tags[tag] = RENAMED_TAGS[tag] + return RENAMED_TAGS[tag] + return tag diff --git a/test/TestCliRolePaths.py b/test/TestCliRolePaths.py index 1d264ad2f8..514e06dae6 100644 --- a/test/TestCliRolePaths.py +++ b/test/TestCliRolePaths.py @@ -91,7 +91,8 @@ def test_run_role_name_invalid(self): role_path = 'roles/invalid-name' result = run_ansible_lint(role_path, cwd=cwd) - assert '106: Role name invalid-name does not match' in strip_ansi_escape(result.stdout) + assert 'role-name: Role name invalid-name does not match' in strip_ansi_escape( + result.stdout) def test_run_role_name_with_prefix(self): cwd = self.local_test_dir @@ -116,7 +117,7 @@ def test_run_invalid_role_name_from_meta(self): role_path = 'roles/invalid_due_to_meta' result = run_ansible_lint(role_path, cwd=cwd) - assert ('106: Role name invalid-due-to-meta does not match' in + assert ('role-name: Role name invalid-due-to-meta does not match' in strip_ansi_escape(result.stdout)) def test_run_single_role_path_with_roles_path_env(self): @@ -153,7 +154,7 @@ def test_run_playbook_github(result, env): result_gh = run_ansible_lint(role_path, cwd=cwd, env=env) expected = ( - '::warning file=examples/playbooks/example.yml,line=44,severity=VERY_LOW::E403 ' + '::warning file=examples/playbooks/example.yml,line=44,severity=VERY_LOW::package-latest ' 'Package installs should not use latest' ) assert (expected in result_gh.stdout) is result diff --git a/test/TestExamples.py b/test/TestExamples.py index 9f58b88f99..283544b5db 100644 --- a/test/TestExamples.py +++ b/test/TestExamples.py @@ -18,7 +18,7 @@ def test_example_plain_string(default_rules_collection): assert len(result) >= 1 passed = False for match in result: - if match.rule.id == "911": + if match.rule.id == "syntax-check": passed = True assert passed, result diff --git a/test/TestImportPlaybook.py b/test/TestImportPlaybook.py index bb027e0c17..7474aba954 100644 --- a/test/TestImportPlaybook.py +++ b/test/TestImportPlaybook.py @@ -15,5 +15,5 @@ def test_task_hook_import_playbook(default_rules_collection): assert len(results) == 2 # Assures we detected the issues from imported playbook assert 'Commands should not change things' in results_text - assert '502' in results_text + assert 'unnamed-task' in results_text assert 'All tasks should be named' in results_text diff --git a/test/TestImportWithMalformed.py b/test/TestImportWithMalformed.py index 8be4658ba1..94249df8e2 100644 --- a/test/TestImportWithMalformed.py +++ b/test/TestImportWithMalformed.py @@ -34,6 +34,6 @@ def test_import_tasks_with_malformed_import(runner): results = runner.run() passed = False for result in results: - if result.rule.id == '911': + if result.rule.id == 'syntax-check': passed = True assert passed, results diff --git a/test/TestIncludeMissingFileRule.py b/test/TestIncludeMissingFileRule.py index 51fe94b4ee..b72c45e022 100644 --- a/test/TestIncludeMissingFileRule.py +++ b/test/TestIncludeMissingFileRule.py @@ -17,7 +17,7 @@ PLAY_INCLUDING_NOQA = Lintable('playbook.yml', u'''\ - hosts: all tasks: - - include: some_file.yml # noqa 505 + - include: some_file.yml # noqa missing-import ''') PLAY_INCLUDED = Lintable('some_file.yml', u'''\ diff --git a/test/TestMatchError.py b/test/TestMatchError.py index c6fb7a9743..60e95a8345 100644 --- a/test/TestMatchError.py +++ b/test/TestMatchError.py @@ -5,7 +5,6 @@ import pytest from ansiblelint.errors import MatchError -from ansiblelint.rules import AnsibleLintRule from ansiblelint.rules.BecomeUserWithoutBecomeRule import BecomeUserWithoutBecomeRule from ansiblelint.rules.CommandHasChangesCheckRule import CommandHasChangesCheckRule @@ -58,10 +57,6 @@ def test_matcherror_compare(left_match_error, right_match_error): assert left_match_error == right_match_error -class AnsibleLintRuleWithStringId(AnsibleLintRule): - id = "ANSIBLE200" - - def test_matcherror_invalid(): """Ensure that MatchError requires message or rule.""" expected_err = r"^MatchError\(\) missing a required argument: one of 'message' or 'rule'$" @@ -75,12 +70,9 @@ def test_matcherror_invalid(): (MatchError("z"), MatchError("a")), # filenames takes priority in sorting (MatchError("a", filename="b"), MatchError("a", filename="a")), - # rule id 501 > rule id 301 + # rule id partial-become > rule id no-changed-when (MatchError(rule=BecomeUserWithoutBecomeRule()), MatchError(rule=CommandHasChangesCheckRule())), - # rule id 'ANSIBLE200' > rule id 301 - (MatchError(rule=AnsibleLintRuleWithStringId()), - MatchError(rule=CommandHasChangesCheckRule())), # details are taken into account (MatchError("a", details="foo"), MatchError("a", details="bar")), # columns are taken into account diff --git a/test/TestNestedJinjaRule.py b/test/TestNestedJinjaRule.py index e017281acb..632c6b4402 100644 --- a/test/TestNestedJinjaRule.py +++ b/test/TestNestedJinjaRule.py @@ -177,7 +177,7 @@ def _playbook_file(tmp_path, request): @pytest.mark.usefixtures('_playbook_file') def test_including_wrong_nested_jinja(runner): rule_violations = runner.run() - assert rule_violations[0].rule.id == '207' + assert rule_violations[0].rule.id == 'no-jinja-nesting' @pytest.mark.parametrize( diff --git a/test/TestRulesCollection.py b/test/TestRulesCollection.py index 278e20519d..f953e09550 100644 --- a/test/TestRulesCollection.py +++ b/test/TestRulesCollection.py @@ -20,6 +20,7 @@ import collections import os +import re import pytest @@ -117,3 +118,12 @@ def test_rich_rule_listing(): assert rule.shortdesc in result.stdout # description could wrap inside table, so we do not check full length assert rule.description[:30] in result.stdout + + +def test_rules_id_format() -> None: + """Asure all our rules have consistent format.""" + rule_id_re = re.compile("^[a-z-]{4,30}$") + rules = RulesCollection([os.path.abspath('./src/ansiblelint/rules')]) + for rule in rules: + assert rule_id_re.match(rule.id), f"R rule id {rule.id} did not match our required format." + assert len(rules) == 37 diff --git a/test/TestSkipImportPlaybook.py b/test/TestSkipImportPlaybook.py index 5c51717cb1..e21ea9be37 100644 --- a/test/TestSkipImportPlaybook.py +++ b/test/TestSkipImportPlaybook.py @@ -14,7 +14,7 @@ - hosts: all tasks: - - name: should be shell # noqa 305 301 + - name: should be shell # noqa command-instead-of-shell no-changed-when shell: echo lol - import_playbook: imported_playbook.yml diff --git a/test/TestSkipInsideYaml.py b/test/TestSkipInsideYaml.py index 07bd48babd..e4feb87700 100644 --- a/test/TestSkipInsideYaml.py +++ b/test/TestSkipInsideYaml.py @@ -2,33 +2,33 @@ ROLE_TASKS = '''\ --- -- name: test 303 +- name: test command-instead-of-module command: git log changed_when: false -- name: test 303 (skipped) - command: git log # noqa 303 +- name: test command-instead-of-module (skipped) + command: git log # noqa command-instead-of-module changed_when: false ''' ROLE_TASKS_WITH_BLOCK = '''\ --- -- name: bad git 1 # noqa 401 +- name: bad git 1 # noqa git-latest action: git a=b c=d - name: bad git 2 action: git a=b c=d - name: Block with rescue and always section block: - - name: bad git 3 # noqa 401 + - name: bad git 3 # noqa git-latest action: git a=b c=d - name: bad git 4 action: git a=b c=d rescue: - - name: bad git 5 # noqa 401 + - name: bad git 5 # noqa git-latest action: git a=b c=d - name: bad git 6 action: git a=b c=d always: - - name: bad git 7 # noqa 401 + - name: bad git 7 # noqa git-latest action: git a=b c=d - name: bad git 8 action: git a=b c=d @@ -37,42 +37,42 @@ PLAYBOOK = '''\ - hosts: all tasks: - - name: test 402 + - name: test hg-latest action: hg - - name: test 402 (skipped) # noqa 402 + - name: test hg-latest (skipped) # noqa hg-latest action: hg - - name: test 401 and 501 + - name: test git-latest and partial-become become_user: alice action: git - - name: test 401 and 501 (skipped) # noqa 401 501 + - name: test git-latest and partial-become (skipped) # noqa git-latest partial-become become_user: alice action: git - - name: test YAML and 206 + - name: test YAML and var-spacing get_url: url: http://example.com/really_long_path/really_long_path/really_long_path/really_long_path/really_long_path/really_long_path/really_long_path/really_long_path/file.conf dest: "{{dest_proj_path}}/foo.conf" - - name: test YAML and 206 (skipped) + - name: test YAML and var-spacing (skipped) get_url: - url: http://example.com/really_long_path/really_long_path/really_long_path/really_long_path/really_long_path/really_long_path/really_long_path/really_long_path/file.conf # noqa YAML - dest: "{{dest_proj_path}}/foo.conf" # noqa 206 + url: http://example.com/really_long_path/really_long_path/really_long_path/really_long_path/really_long_path/really_long_path/really_long_path/really_long_path/file.conf # noqa yaml + dest: "{{dest_proj_path}}/foo.conf" # noqa var-spacing - - name: test 302 + - name: test deprecated-command-syntax command: creates=B chmod 644 A - - name: test 302 + - name: test deprecated-command-syntax command: warn=yes creates=B chmod 644 A - - name: test 302 (skipped via no warn) + - name: test deprecated-command-syntax (skipped via no warn) command: warn=no creates=B chmod 644 A - - name: test 302 (skipped via skip_ansible_lint) + - name: test deprecated-command-syntax (skipped via skip_ansible_lint) command: creates=B chmod 644 A tags: - skip_ansible_lint ''' ROLE_META = '''\ -galaxy_info: # noqa 701 - author: your name # noqa 703 +galaxy_info: # noqa meta-no-info + author: your name # noqa meta-incorrect description: missing min_ansible_version and platforms. author default not changed license: MIT ''' diff --git a/test/TestSkipPlaybookItems.py b/test/TestSkipPlaybookItems.py index 6b6542d47e..2115c5b66e 100644 --- a/test/TestSkipPlaybookItems.py +++ b/test/TestSkipPlaybookItems.py @@ -3,12 +3,12 @@ PLAYBOOK_PRE_TASKS = '''\ - hosts: all tasks: - - name: bad git 1 # noqa 401 + - name: bad git 1 # noqa git-latest action: git a=b c=d - name: bad git 2 action: git a=b c=d pre_tasks: - - name: bad git 3 # noqa 401 + - name: bad git 3 # noqa git-latest action: git a=b c=d - name: bad git 4 action: git a=b c=d @@ -17,12 +17,12 @@ PLAYBOOK_POST_TASKS = '''\ - hosts: all tasks: - - name: bad git 1 # noqa 401 + - name: bad git 1 # noqa git-latest action: git a=b c=d - name: bad git 2 action: git a=b c=d post_tasks: - - name: bad git 3 # noqa 401 + - name: bad git 3 # noqa git-latest action: git a=b c=d - name: bad git 4 action: git a=b c=d @@ -31,12 +31,12 @@ PLAYBOOK_HANDLERS = '''\ - hosts: all tasks: - - name: bad git 1 # noqa 401 + - name: bad git 1 # noqa git-latest action: git a=b c=d - name: bad git 2 action: git a=b c=d handlers: - - name: bad git 3 # noqa 401 + - name: bad git 3 # noqa git-latest action: git a=b c=d - name: bad git 4 action: git a=b c=d @@ -45,14 +45,14 @@ PLAYBOOK_TWO_PLAYS = '''\ - hosts: all tasks: - - name: bad git 1 # noqa 401 + - name: bad git 1 # noqa git-latest action: git a=b c=d - name: bad git 2 action: git a=b c=d - hosts: all tasks: - - name: bad git 3 # noqa 401 + - name: bad git 3 # noqa git-latest action: git a=b c=d - name: bad git 4 action: git a=b c=d @@ -61,23 +61,23 @@ PLAYBOOK_WITH_BLOCK = '''\ - hosts: all tasks: - - name: bad git 1 # noqa 401 + - name: bad git 1 # noqa git-latest action: git a=b c=d - name: bad git 2 action: git a=b c=d - name: Block with rescue and always section block: - - name: bad git 3 # noqa 401 + - name: bad git 3 # noqa git-latest action: git a=b c=d - name: bad git 4 action: git a=b c=d rescue: - - name: bad git 5 # noqa 401 + - name: bad git 5 # noqa git-latest action: git a=b c=d - name: bad git 6 action: git a=b c=d always: - - name: bad git 7 # noqa 401 + - name: bad git 7 # noqa git-latest action: git a=b c=d - name: bad git 8 action: git a=b c=d diff --git a/test/TestUtils.py b/test/TestUtils.py index 8e635229b1..27d771046e 100644 --- a/test/TestUtils.py +++ b/test/TestUtils.py @@ -263,7 +263,7 @@ def test_cli_auto_detect(capfd): assert "Discovering files to lint: git ls-files *.yaml *.yml" in err # An expected rule match from our examples assert "examples/playbooks/empty_playbook.yml:0: " \ - "911 Empty playbook, nothing to do" in out + "syntax-check Empty playbook, nothing to do" in out # assures that our .ansible-lint exclude was effective in excluding github files assert "Identified: .github/" not in out # assures that we can parse playbooks as playbooks diff --git a/test/TestWithSkipTagId.py b/test/TestWithSkipTagId.py index a8b8bc82f4..e0b7992608 100644 --- a/test/TestWithSkipTagId.py +++ b/test/TestWithSkipTagId.py @@ -19,16 +19,17 @@ def test_negative_no_param(self) -> None: self.assertGreater(len(errs), 0) def test_negative_with_id(self) -> None: - with_id = 'YAML' + with_id = 'yaml' bad_runner = Runner( self.file, rules=self.collection, - tags=frozenset([with_id])) + tags=frozenset([with_id]) + ) errs = bad_runner.run() self.assertGreater(len(errs), 0) def test_negative_with_tag(self) -> None: - with_tag = 'formatting' + with_tag = 'trailing-spaces' bad_runner = Runner( self.file, rules=self.collection, @@ -37,7 +38,7 @@ def test_negative_with_tag(self) -> None: self.assertGreater(len(errs), 0) def test_positive_skip_id(self) -> None: - skip_id = 'YAML' + skip_id = 'yaml' good_runner = Runner( self.file, rules=self.collection, @@ -45,7 +46,7 @@ def test_positive_skip_id(self) -> None: self.assertEqual([], good_runner.run()) def test_positive_skip_tag(self) -> None: - skip_tag = 'formatting' + skip_tag = 'trailing-spaces' good_runner = Runner( self.file, rules=self.collection, diff --git a/test/playbook-import/playbook_imported.yml b/test/playbook-import/playbook_imported.yml index 9ff8c4d378..741f320e7b 100644 --- a/test/playbook-import/playbook_imported.yml +++ b/test/playbook-import/playbook_imported.yml @@ -3,7 +3,7 @@ connection: local gather_facts: false tasks: - - command: echo "no name" # should generate 502 + - command: echo "no name" # should generate unnamed-task - name: Another task debug: msg: debug message