From 37a78cbdde0f6b274202ec715b8735acf4b2165b Mon Sep 17 00:00:00 2001 From: Alexander Jaeger Date: Wed, 18 Apr 2018 15:02:43 +0200 Subject: [PATCH] doc: additional tests planned --- .../rules/ADFINIS0002RegisterPrefixRule.py | 51 ++++++++++++++++ .planned/rules/TWSH101PlaybookExtension.py | 21 +++++++ .planned/rules/TWSH201RoleRelativePath.py | 42 +++++++++++++ .planned/rules/TWSH301TaskShouldHaveName.py | 32 ++++++++++ .../rules/TWSH302TaskIncludeShouldHaveTags.py | 17 ++++++ .planned/rules/TWSH303TaskManyArgs.py | 18 ++++++ .planned/rules/TWSH304TaskNoLocalAction.py | 12 ++++ .planned/rules/TWSH305TaskVariableHasSpace.py | 19 ++++++ .../rules/TWSH401ModuleOctalPermissions.py | 59 +++++++++++++++++++ .planned/rules/TWSH402ModuleTemplateExt.py | 16 +++++ .planned/rules/TWSH501ShellAltChmod.py | 14 +++++ .planned/rules/TWSH502ShellAltChown.py | 14 +++++ .planned/rules/TWSH503ShellAltHostname.py | 15 +++++ .planned/rules/TWSH504ShellAltMount.py | 15 +++++ .planned/rules/TWSH505ShellAltNmcli.py | 14 +++++ .planned/rules/TWSH506ShellAltRpm.py | 14 +++++ .planned/rules/TWSH507ShellAltService.py | 20 +++++++ .planned/rules/TWSH508ShellAltSysctl.py | 15 +++++ .planned/rules/TWSH509ShellAltUfw.py | 14 +++++ .planned/rules/TWSH510ShellAltUnarchive.py | 17 ++++++ .planned/rules/TWSH511ShellHasCreates.py | 16 +++++ .planned/rules/TWSH512ShellAltFile.py | 17 ++++++ .planned/rules/TWSH513ShellAltPatch.py | 14 +++++ .../rules/TWSH601TrailingWhitespaceRule.py | 31 ++++++++++ .planned/rules/TWSH602LineTooLong.py | 14 +++++ .planned/tests/formatting.yml | 5 ++ .planned/tests/included.yml | 2 + .planned/tests/modules.yml | 5 ++ .planned/tests/roles.retry | 1 + .planned/tests/roles.yml | 5 ++ .planned/tests/shell.yml | 23 ++++++++ .planned/tests/tasks.yml | 14 +++++ 32 files changed, 586 insertions(+) create mode 100644 .planned/rules/ADFINIS0002RegisterPrefixRule.py create mode 100644 .planned/rules/TWSH101PlaybookExtension.py create mode 100644 .planned/rules/TWSH201RoleRelativePath.py create mode 100644 .planned/rules/TWSH301TaskShouldHaveName.py create mode 100644 .planned/rules/TWSH302TaskIncludeShouldHaveTags.py create mode 100644 .planned/rules/TWSH303TaskManyArgs.py create mode 100644 .planned/rules/TWSH304TaskNoLocalAction.py create mode 100644 .planned/rules/TWSH305TaskVariableHasSpace.py create mode 100644 .planned/rules/TWSH401ModuleOctalPermissions.py create mode 100644 .planned/rules/TWSH402ModuleTemplateExt.py create mode 100644 .planned/rules/TWSH501ShellAltChmod.py create mode 100644 .planned/rules/TWSH502ShellAltChown.py create mode 100644 .planned/rules/TWSH503ShellAltHostname.py create mode 100644 .planned/rules/TWSH504ShellAltMount.py create mode 100644 .planned/rules/TWSH505ShellAltNmcli.py create mode 100644 .planned/rules/TWSH506ShellAltRpm.py create mode 100644 .planned/rules/TWSH507ShellAltService.py create mode 100644 .planned/rules/TWSH508ShellAltSysctl.py create mode 100644 .planned/rules/TWSH509ShellAltUfw.py create mode 100644 .planned/rules/TWSH510ShellAltUnarchive.py create mode 100644 .planned/rules/TWSH511ShellHasCreates.py create mode 100644 .planned/rules/TWSH512ShellAltFile.py create mode 100644 .planned/rules/TWSH513ShellAltPatch.py create mode 100644 .planned/rules/TWSH601TrailingWhitespaceRule.py create mode 100644 .planned/rules/TWSH602LineTooLong.py create mode 100644 .planned/tests/formatting.yml create mode 100644 .planned/tests/included.yml create mode 100644 .planned/tests/modules.yml create mode 100644 .planned/tests/roles.retry create mode 100644 .planned/tests/roles.yml create mode 100644 .planned/tests/shell.yml create mode 100644 .planned/tests/tasks.yml diff --git a/.planned/rules/ADFINIS0002RegisterPrefixRule.py b/.planned/rules/ADFINIS0002RegisterPrefixRule.py new file mode 100644 index 0000000..366aa23 --- /dev/null +++ b/.planned/rules/ADFINIS0002RegisterPrefixRule.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +# Copyright (c) 2017, Adfinis SyGroup AG +# All rights reserved. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# src-repo: https://github.com/adfinis-sygroup/ansible-lint-rules/blob/master/RegisterPrefixRule.py + +from ansiblelint import AnsibleLintRule + + +class RegisterPrefixRule(AnsibleLintRule): + id = 'ADFINIS0002' + shortdesc = "Registered variable must always have a prefix " \ + "\"$ROLENAME_register_\"" + description = """ + Each registered variable name must have a prefix "$ROLENAME_register_", + because each variable should be unique. + """ + tags = ['formatting'] + + def matchtask(self, file, task): + if 'register' in task: + register = task['register'] + try: + role = self.rolename(file['path']) + prefix = '{0}_register_'.format(role) + except BaseException: + prefix = 'register_' + return not register.startswith(prefix) + return False + + def rolename(self, file): + elements = file.split('/') + if 'tasks' in elements: + idx = elements.index('tasks') - 1 + return elements[idx] + raise IndexError('tasks not in path') diff --git a/.planned/rules/TWSH101PlaybookExtension.py b/.planned/rules/TWSH101PlaybookExtension.py new file mode 100644 index 0000000..a7efe10 --- /dev/null +++ b/.planned/rules/TWSH101PlaybookExtension.py @@ -0,0 +1,21 @@ +from ansiblelint import AnsibleLintRule + +import os + +class PlaybookExtension(AnsibleLintRule): + id = 'TWSH101' + shortdesc = 'Playbooks should have the ".yml" extension' + description = '' + tags = ['playbook'] + done = [] # already noticed path list + + def match(self, file, text): + if file['type'] != 'playbook': + return False + + path = file['path'] + ext = os.path.splitext(path) + if ext[1] != ".yml" and path not in self.done: + self.done.append(path) + return True + return False diff --git a/.planned/rules/TWSH201RoleRelativePath.py b/.planned/rules/TWSH201RoleRelativePath.py new file mode 100644 index 0000000..ff7b0e2 --- /dev/null +++ b/.planned/rules/TWSH201RoleRelativePath.py @@ -0,0 +1,42 @@ +from ansiblelint import AnsibleLintRule + + +format = "{}" + +class RoleRelativePath(AnsibleLintRule): + id = 'TWSH201' + shortdesc = "Doesn't need a relative path in role" + description = '' + tags = ['role'] + + def matchplay(self, file, play): + # assume if 'roles' in path, inside a role. + if 'roles' not in file['path']: + return [] + if 'template' in play: + if not isinstance(play['template'], dict): + return False + if "../templates" in play['template']['src']: + return [({'': play['template']}, + self.shortdesc)] + if 'win_template' in play: + if not isinstance(play['win_template'], dict): + return False + if "../win_templates" in play['win_template']['src']: + return ({'win_template': play['win_template']}, + self.shortdesc) + if 'copy' in play: + if not isinstance(play['copy'], dict): + return False + if 'src' in play['copy']: + if "../files" in play['copy']['src']: + return ({'sudo': play['copy']}, + self.shortdesc) + if 'win_copy' in play: + if not isinstance(play['win_copy'], dict): + return False + if "../files" in play['win_copy']['src']: + return ({'sudo': play['win_copy']}, + self.shortdesc) + return [] + diff --git a/.planned/rules/TWSH301TaskShouldHaveName.py b/.planned/rules/TWSH301TaskShouldHaveName.py new file mode 100644 index 0000000..a25acfe --- /dev/null +++ b/.planned/rules/TWSH301TaskShouldHaveName.py @@ -0,0 +1,32 @@ +# Copyright (c) 2016 Will Thames +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# 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 ansiblelint import AnsibleLintRule + + +class TaskShouldHaveName(AnsibleLintRule): + id = 'TWSH301' + shortdesc = 'All tasks should be named' + description = 'All tasks should have a distinct name for readability ' + \ + 'and for --start-at-task to work' + tags = ['task'] + + def matchtask(self, file, task): + return task.get('name', '') == '' diff --git a/.planned/rules/TWSH302TaskIncludeShouldHaveTags.py b/.planned/rules/TWSH302TaskIncludeShouldHaveTags.py new file mode 100644 index 0000000..9975f8c --- /dev/null +++ b/.planned/rules/TWSH302TaskIncludeShouldHaveTags.py @@ -0,0 +1,17 @@ +from ansiblelint import AnsibleLintRule + +# FIXME: how to get include task? +class TaskIncludeShouldHaveTags(AnsibleLintRule): + id = 'TWSH302' + shortdesc = 'Include should have tags' + description = '' + tags = ['task'] + + def matchplay(self, file, play): + ret = [] + + if isinstance(play, dict) and 'tasks' in play: + for item in play['tasks']: + if 'include' in item and 'tags' not in item: + ret.append((file, self.shortdesc)) + return ret diff --git a/.planned/rules/TWSH303TaskManyArgs.py b/.planned/rules/TWSH303TaskManyArgs.py new file mode 100644 index 0000000..3cb3301 --- /dev/null +++ b/.planned/rules/TWSH303TaskManyArgs.py @@ -0,0 +1,18 @@ +from ansiblelint import AnsibleLintRule + +class TaskManyArgs(AnsibleLintRule): + id = 'TWSH303' + shortdesc = 'Use ":" YAML format when arguments are over 4' + description = '' + tags = ['task'] + + def match(self, file, text): + count = 0 + for action in text.split(" "): + if "=" in action: + count += 1 + + if count > 4: + return True + + return False diff --git a/.planned/rules/TWSH304TaskNoLocalAction.py b/.planned/rules/TWSH304TaskNoLocalAction.py new file mode 100644 index 0000000..bdfada5 --- /dev/null +++ b/.planned/rules/TWSH304TaskNoLocalAction.py @@ -0,0 +1,12 @@ +from ansiblelint import AnsibleLintRule + +class TaskNoLocalAction(AnsibleLintRule): + id = 'TWSH304' + shortdesc = 'Do not use local_action. use delegate_to: localhost instead' + description = '' + tags = ['task'] + + def match(self, file, text): + if 'local_action' in text: + return True + return False diff --git a/.planned/rules/TWSH305TaskVariableHasSpace.py b/.planned/rules/TWSH305TaskVariableHasSpace.py new file mode 100644 index 0000000..ebdc255 --- /dev/null +++ b/.planned/rules/TWSH305TaskVariableHasSpace.py @@ -0,0 +1,19 @@ +from ansiblelint import AnsibleLintRule + +import re + +class TaskVariableHasSpace(AnsibleLintRule): + id = 'TWSH305' + shortdesc = 'Variables should be enclosed by spaces "{{ foo }}"' + description = '' + tags = ['task'] + + compiled = re.compile(ur'{{(\w*)}}') + + def match(self, file, text): + m = self.compiled.search(text) + if m: + return True + return False + + diff --git a/.planned/rules/TWSH401ModuleOctalPermissions.py b/.planned/rules/TWSH401ModuleOctalPermissions.py new file mode 100644 index 0000000..b144089 --- /dev/null +++ b/.planned/rules/TWSH401ModuleOctalPermissions.py @@ -0,0 +1,59 @@ +# Copyright (c) 2013-2014 Will Thames +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# 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 ansiblelint import AnsibleLintRule +import re + + +class ModuleOctalPermissions(AnsibleLintRule): + id = 'TWSH401' + shortdesc = 'Octal file permissions must contain leading zero' + description = 'Numeric file permissions without leading zero can behave' + \ + 'in unexpected ways. See ' + \ + 'http://docs.ansible.com/ansible/file_module.html' + tags = ['module'] + + _modules = {'assemble', 'copy', 'file', 'ini_file', 'lineinfile', + 'replace', 'synchronize', 'template', 'unarchive'} + + mode_regex = re.compile(r'^\s*[0-9]+\s*$') + valid_mode_regex = re.compile(r'^\s*0[0-7]{3,4}\s*$') + + def matchtask(self, file, task): + if task["action"]["__ansible_module__"] in self._modules: + mode = task['action'].get('mode', None) + if isinstance(mode, basestring) and self.mode_regex.match(mode): + return not self.valid_mode_regex.match(mode) + if isinstance(mode, int): + # sensible file permission modes don't + # have write or execute bit set when read bit is + # not set + # also, user permissions are more generous than + # group permissions and user and group permissions + # are more generous than world permissions + + result = (mode % 8 and mode % 8 < 4 or + (mode >> 3) % 8 and (mode >> 3) % 8 < 4 or + (mode >> 6) % 8 and (mode >> 6) % 8 < 4 or + mode & 8 < (mode << 3) & 8 or + mode & 8 < (mode << 6) & 8 or + (mode << 3) & 8 < (mode << 6) & 8) + + return result diff --git a/.planned/rules/TWSH402ModuleTemplateExt.py b/.planned/rules/TWSH402ModuleTemplateExt.py new file mode 100644 index 0000000..a4ed00a --- /dev/null +++ b/.planned/rules/TWSH402ModuleTemplateExt.py @@ -0,0 +1,16 @@ +from ansiblelint import AnsibleLintRule +import os + +class ModuleTemplateExt(AnsibleLintRule): + id = 'TWSH402' + shortdesc = "Template files should have the extension '.j2' " + description = '' + tags = ['module'] + + def matchtask(self, file, task): + if task['action']['__ansible_module__'] != 'template': + return False + ext = os.path.splitext(task['action']['src']) + if ext[1] != ".j2": + return True + return False diff --git a/.planned/rules/TWSH501ShellAltChmod.py b/.planned/rules/TWSH501ShellAltChmod.py new file mode 100644 index 0000000..c37efde --- /dev/null +++ b/.planned/rules/TWSH501ShellAltChmod.py @@ -0,0 +1,14 @@ +from ansiblelint import AnsibleLintRule + +class ShellAltChmod(AnsibleLintRule): + id = 'TWSH501' + shortdesc = 'Use chmod module' + description = '' + tags = ['shell'] + + def matchtask(self, file, task): + if task['action']['__ansible_module__'] not in ['shell', 'command']: + return False + if 'chmod' in task['action']['__ansible_arguments__']: + return True + return False diff --git a/.planned/rules/TWSH502ShellAltChown.py b/.planned/rules/TWSH502ShellAltChown.py new file mode 100644 index 0000000..c8ceaca --- /dev/null +++ b/.planned/rules/TWSH502ShellAltChown.py @@ -0,0 +1,14 @@ +from ansiblelint import AnsibleLintRule + +class ShellAltChown(AnsibleLintRule): + id = 'TWSH502' + shortdesc = 'Use chown module' + description = '' + tags = ['shell'] + + def matchtask(self, file, task): + if task['action']['__ansible_module__'] not in ['shell', 'command']: + return False + if 'chown' in task['action']['__ansible_arguments__']: + return True + return False diff --git a/.planned/rules/TWSH503ShellAltHostname.py b/.planned/rules/TWSH503ShellAltHostname.py new file mode 100644 index 0000000..33281d6 --- /dev/null +++ b/.planned/rules/TWSH503ShellAltHostname.py @@ -0,0 +1,15 @@ +from ansiblelint import AnsibleLintRule + +class ShellAltHostname(AnsibleLintRule): + id = 'TWSH503' + shortdesc = 'Use hostname module' + description = '' + tags = ['shell'] + + def matchtask(self, file, task): + if task['action']['__ansible_module__'] not in ['shell', 'command']: + return False + if ('hostname' in task['action']['__ansible_arguments__'] and + 'register' not in task): + return True + return False diff --git a/.planned/rules/TWSH504ShellAltMount.py b/.planned/rules/TWSH504ShellAltMount.py new file mode 100644 index 0000000..e960d32 --- /dev/null +++ b/.planned/rules/TWSH504ShellAltMount.py @@ -0,0 +1,15 @@ +from ansiblelint import AnsibleLintRule + +class ShellAltMount(AnsibleLintRule): + id = 'TWSH504' + shortdesc = 'Use mount module' + description = '' + tags = ['shell'] + + def matchtask(self, file, task): + if task['action']['__ansible_module__'] not in ['shell', 'command']: + return False + if ('mount' in task['action']['__ansible_arguments__'] and + 'register' not in task): + return True + return False diff --git a/.planned/rules/TWSH505ShellAltNmcli.py b/.planned/rules/TWSH505ShellAltNmcli.py new file mode 100644 index 0000000..ee0e9cf --- /dev/null +++ b/.planned/rules/TWSH505ShellAltNmcli.py @@ -0,0 +1,14 @@ +from ansiblelint import AnsibleLintRule + +class ShellAltNmcli(AnsibleLintRule): + id = 'TWSH505' + shortdesc = 'Use nmcli module' + description = '' + tags = ['shell'] + + def matchtask(self, file, task): + if task['action']['__ansible_module__'] not in ['shell', 'command']: + return False + if 'nmcli' in task['action']['__ansible_arguments__']: + return True + return False diff --git a/.planned/rules/TWSH506ShellAltRpm.py b/.planned/rules/TWSH506ShellAltRpm.py new file mode 100644 index 0000000..bdfdec4 --- /dev/null +++ b/.planned/rules/TWSH506ShellAltRpm.py @@ -0,0 +1,14 @@ +from ansiblelint import AnsibleLintRule + +class ShellAltRpm(AnsibleLintRule): + id = 'TWSH506' + shortdesc = 'Use yum module with file path' + description = '' + tags = ['shell'] + + def matchtask(self, file, task): + if task['action']['__ansible_module__'] not in ['shell', 'command']: + return False + if 'rpm' in task['action']['__ansible_arguments__']: + return True + return False diff --git a/.planned/rules/TWSH507ShellAltService.py b/.planned/rules/TWSH507ShellAltService.py new file mode 100644 index 0000000..1bd0533 --- /dev/null +++ b/.planned/rules/TWSH507ShellAltService.py @@ -0,0 +1,20 @@ +from ansiblelint import AnsibleLintRule + +class ShellAltService(AnsibleLintRule): + id = 'TWSH507' + shortdesc = 'Use service module' + description = '' + tags = ['shell'] + + def matchtask(self, file, task): + if task['action']['__ansible_module__'] not in ['shell', 'command']: + return False + args = task['action']['__ansible_arguments__'] + + if 'service' in args: + return True + if 'systemctl' in args: + return True + if '/etc/rc.d/init.d/' in args: + return True + return False diff --git a/.planned/rules/TWSH508ShellAltSysctl.py b/.planned/rules/TWSH508ShellAltSysctl.py new file mode 100644 index 0000000..909830c --- /dev/null +++ b/.planned/rules/TWSH508ShellAltSysctl.py @@ -0,0 +1,15 @@ +from ansiblelint import AnsibleLintRule + +class ShellAltSysctl(AnsibleLintRule): + id = 'TWSH508' + shortdesc = 'Use sysctl module' + description = '' + tags = ['shell'] + + def matchtask(self, file, task): + if task['action']['__ansible_module__'] not in ['shell', 'command']: + return False + if ('sysctl' in task['action']['__ansible_arguments__'] and + 'register' not in task): + return True + return False diff --git a/.planned/rules/TWSH509ShellAltUfw.py b/.planned/rules/TWSH509ShellAltUfw.py new file mode 100644 index 0000000..0c63c50 --- /dev/null +++ b/.planned/rules/TWSH509ShellAltUfw.py @@ -0,0 +1,14 @@ +from ansiblelint import AnsibleLintRule + +class ShellAltUfw(AnsibleLintRule): + id = 'TWSH509' + shortdesc = 'Use ufw module' + description = '' + tags = ['shell'] + + def matchtask(self, file, task): + if task['action']['__ansible_module__'] not in ['shell', 'command']: + return False + if 'ufw' in task['action']['__ansible_arguments__']: + return True + return False diff --git a/.planned/rules/TWSH510ShellAltUnarchive.py b/.planned/rules/TWSH510ShellAltUnarchive.py new file mode 100644 index 0000000..b6a5f02 --- /dev/null +++ b/.planned/rules/TWSH510ShellAltUnarchive.py @@ -0,0 +1,17 @@ +from ansiblelint import AnsibleLintRule + +class ShellAltUnarchive(AnsibleLintRule): + id = 'TWSH510' + shortdesc = 'Use unarchive module' + description = '' + tags = ['shell'] + + def matchtask(self, file, task): + if task['action']['__ansible_module__'] not in ['shell', 'command']: + return False + args = task['action']['__ansible_arguments__'] + if 'unzip' in args: + return True + if 'tar' in args and 'xf' in args: + return True + return False diff --git a/.planned/rules/TWSH511ShellHasCreates.py b/.planned/rules/TWSH511ShellHasCreates.py new file mode 100644 index 0000000..dcf6cfb --- /dev/null +++ b/.planned/rules/TWSH511ShellHasCreates.py @@ -0,0 +1,16 @@ +from ansiblelint import AnsibleLintRule + +class ShellHasCreates(AnsibleLintRule): + id = 'TWSH511' + shortdesc = 'Shell/command module must contain creates or removes' + description = '' + tags = ['shell'] + + def matchtask(self, file, task): + if task['action']['__ansible_module__'] not in ['shell', 'command']: + return False + if 'creates' in task['action'] or 'removes' in task['action']: + return False + if 'register' in task: + return False + return True diff --git a/.planned/rules/TWSH512ShellAltFile.py b/.planned/rules/TWSH512ShellAltFile.py new file mode 100644 index 0000000..48d22df --- /dev/null +++ b/.planned/rules/TWSH512ShellAltFile.py @@ -0,0 +1,17 @@ +from ansiblelint import AnsibleLintRule + +class ShellAltFile(AnsibleLintRule): + id = 'TWSH512' + shortdesc = 'Use file module instead of mkdir, ln -s and so on' + description = '' + tags = ['shell'] + alt_commands = ["ln -s", "mkdir"] + + def matchtask(self, file, task): + if task['action']['__ansible_module__'] not in ['shell', 'command']: + return False + for c in self.alt_commands: + if c in task['action']['__ansible_arguments__']: + self.shortdesc += " ({})".format(c) + return True + return False diff --git a/.planned/rules/TWSH513ShellAltPatch.py b/.planned/rules/TWSH513ShellAltPatch.py new file mode 100644 index 0000000..eaf0431 --- /dev/null +++ b/.planned/rules/TWSH513ShellAltPatch.py @@ -0,0 +1,14 @@ +from ansiblelint import AnsibleLintRule + +class ShellAltPatch(AnsibleLintRule): + id = 'TWSH513' + shortdesc = 'Use patch module' + description = '' + tags = ['shell'] + + def matchtask(self, file, task): + if task['action']['__ansible_module__'] not in ['shell', 'command']: + return False + if 'patch' in task['action']['__ansible_arguments__']: + return True + return False diff --git a/.planned/rules/TWSH601TrailingWhitespaceRule.py b/.planned/rules/TWSH601TrailingWhitespaceRule.py new file mode 100644 index 0000000..1f2ab78 --- /dev/null +++ b/.planned/rules/TWSH601TrailingWhitespaceRule.py @@ -0,0 +1,31 @@ +# Copyright (c) 2013-2014 Will Thames +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# 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 ansiblelint import AnsibleLintRule + + +class TrailingWhitespaceRule(AnsibleLintRule): + id = 'TWSH601' + shortdesc = 'Trailing whitespace' + description = 'There should not be any trailing whitespace' + tags = ['formatting'] + + def match(self, file, line): + return line.rstrip() != line diff --git a/.planned/rules/TWSH602LineTooLong.py b/.planned/rules/TWSH602LineTooLong.py new file mode 100644 index 0000000..009528c --- /dev/null +++ b/.planned/rules/TWSH602LineTooLong.py @@ -0,0 +1,14 @@ +from ansiblelint import AnsibleLintRule + + +class LineTooLong(AnsibleLintRule): + id = 'TWSH602' + shortdesc = 'Line too long' + description = 'Line too long' + tags = ['formatting'] + + def match(self, file, line): + if len(line) > 80: + self.shortdesc += " ({} characters)".format(len(line)) + return True + return False diff --git a/.planned/tests/formatting.yml b/.planned/tests/formatting.yml new file mode 100644 index 0000000..c7b5510 --- /dev/null +++ b/.planned/tests/formatting.yml @@ -0,0 +1,5 @@ +- hosts: localhost + gather_facts: no + tasks: + - name: line is toooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo long + debug: msg="line too long" diff --git a/.planned/tests/included.yml b/.planned/tests/included.yml new file mode 100644 index 0000000..b78c2ac --- /dev/null +++ b/.planned/tests/included.yml @@ -0,0 +1,2 @@ +- name: dummy + debug: msg="dummy" diff --git a/.planned/tests/modules.yml b/.planned/tests/modules.yml new file mode 100644 index 0000000..906f367 --- /dev/null +++ b/.planned/tests/modules.yml @@ -0,0 +1,5 @@ +- name: playbook for roles category + hosts: localhost + gather_facts: no + tasks: + - template: src="hoge.noj2" dest="/tmp/hoge" diff --git a/.planned/tests/roles.retry b/.planned/tests/roles.retry new file mode 100644 index 0000000..2fbb50c --- /dev/null +++ b/.planned/tests/roles.retry @@ -0,0 +1 @@ +localhost diff --git a/.planned/tests/roles.yml b/.planned/tests/roles.yml new file mode 100644 index 0000000..435d664 --- /dev/null +++ b/.planned/tests/roles.yml @@ -0,0 +1,5 @@ +- name: playbook for roles category + hosts: localhost + gather_facts: no + roles: + - relative diff --git a/.planned/tests/shell.yml b/.planned/tests/shell.yml new file mode 100644 index 0000000..b777f7b --- /dev/null +++ b/.planned/tests/shell.yml @@ -0,0 +1,23 @@ +- name: playbook for shell category + hosts: localhost + gather_facts: no + tasks: + - name: does not have creates + shell: echo "hoge" + - name: use mount + shell: mount + args: + creates: /tmp + - name: use sysctl module + shell: sysctl -a + args: + creates: /tmp + - name: use file module to chown + shell: chown -R hoge . + args: + creates: /tmp + - name: use file module to chmod + shell: chmod ugo+r . + args: + creates: /tmp + diff --git a/.planned/tests/tasks.yml b/.planned/tests/tasks.yml new file mode 100644 index 0000000..038c0f7 --- /dev/null +++ b/.planned/tests/tasks.yml @@ -0,0 +1,14 @@ +- name: playbook for task category + hosts: localhost + gather_facts: no + vars: + foo: "tasks" + tasks: + - name: use local action + local_action: file path=/tmp/tasks state=touch + - name: many argument with = + file: path="/tmp/tasks" state=touch group=wheel mode=0700 force=yes + - name: variable with no space + file: path="/tmp/{{foo}}" state=touch + - name: variable with space # lint does not match + file: path="/tmp/{{ foo }}" state=touch