Usage

Command Line Options

The tool produces output on both stdout and stderr, first one being used to display any matching rule violations while the second one being used for logging and free form messages, like displaying stats.

In most of our examples we will be using the pep8 output format (-p) which is machine parseable. The default output format is more verbose and likely to contain more information, like long description of the rule and its associated tags.

$ ansible-lint --help
usage: ansible-lint [-h] [-L] [-f {rich,plain,rst,codeclimate,quiet,pep8}]
                    [-q] [-p] [--parseable-severity] [--progressive]
                    [--project-dir PROJECT_DIR] [-r RULESDIR] [-R]
                    [--show-relpath] [-t TAGS] [-T] [-v] [-x SKIP_LIST]
                    [-w WARN_LIST] [--enable-list ENABLE_LIST] [--nocolor]
                    [--force-color] [--exclude EXCLUDE_PATHS] [-c CONFIG_FILE]
                    [--offline] [--version]
                    [lintables [lintables ...]]

positional arguments:
  lintables             One or more files or paths. When missing it will
                        enable auto-detection mode.

optional arguments:
  -h, --help            show this help message and exit
  -L                    list all the rules
  -f {rich,plain,rst,codeclimate,quiet,pep8}
                        Format used rules output, (default: rich)
  -q                    quieter, reduce verbosity, can be specified twice.
  -p                    parseable output, same as '-f pep8'
  --parseable-severity  parseable output including severity of rule
  --progressive         Return success if it detects a reduction in number of
                        violations compared with previous git commit. This
                        feature works only in git repositories.
  --project-dir PROJECT_DIR
                        Location of project/repository, autodetected based on
                        location of configuration file.
  -r RULESDIR           Specify custom rule directories. Add -R to keep using
                        embedded rules from /home/docs/checkouts/readthedocs.o
                        rg/user_builds/ansible-
                        lint/envs/latest/lib/python3.8/site-
                        packages/ansiblelint/rules
  -R                    Keep default rules when using -r
  --show-relpath        Display path relative to CWD
  -t TAGS               only check rules whose id/tags match these values
  -T                    list all the tags
  -v                    Increase verbosity level (-vv for more)
  -x SKIP_LIST          only check rules whose id/tags do not match these
                        values
  -w WARN_LIST          only warn about these rules, unless overridden in
                        config file defaults to 'experimental'
  --enable-list ENABLE_LIST
                        activate optional rules by their tag name
  --nocolor             disable colored output, same as NO_COLOR=1
  --force-color         Force colored output, same as FORCE_COLOR=1
  --exclude EXCLUDE_PATHS
                        path to directories or files to skip. This option is
                        repeatable.
  -c CONFIG_FILE        Specify configuration file to use. Defaults to
                        ".ansible-lint"
  --offline             Disable installation of requirements.yml
  --version

Temporary files

As part of the execution, the linter will likely need to create a cache of installed or mocked roles, collections and modules. This is done inside {project_dir}/.cache folder. The project directory is either given as a command line argument, determined by location of the configuration file, git project top-level directory or user home directory as fallback. In order to speed-up reruns, the linter does not clean this folder by itself.

If you are using git, you will likely want to add this folder to your .gitignore file.

Progressive mode

In order to ease tool adoption, git users can enable the progressive mode using --progressive option. This makes the linter return a success even if some failures are found, as long the total number of violations did not increase since the previous commit.

As expected, this mode makes the linter run twice if it finds any violations. The second run is performed against a temporary git working copy that contains the previous commit. All the violations that were already present are removed from the list and the final result is displayed.

The most notable benefit introduced by this mode it does not prevent merging new code while allowing developer to address historical violation at his own speed.

CI/CD

If execution under Github Actions is detected via the presence of GITHUB_ACTIONS=true and GITHUB_WORKFLOW=... variables, the linter will also print errors using their annotation format.

Linting Playbooks and Roles

We recommend following the collection structure layout regardless if you are planning to build a collection or not. Following that layout assures the best integration with all ecosystem tools as it helps them better distinguish between random YAML files and files managed by ansible.

When you call ansible-lint without arguments the tool will use its internal heuristics to determine file types.

ansible-lint also accepts a list of roles or playbooks as arguments. The following command lints examples/playbooks/play.yml and examples/roles/bobbins role:

$ ansible-lint -p examples/playbooks/play.yml examples/roles/bobbins
examples/playbooks/play.yml:5: command-instead-of-module service used in place of service module
examples/playbooks/play.yml:5: fqcn-builtins Use FQCN for builtin actions
examples/playbooks/play.yml:5: no-changed-when Commands should not change things if nothing needs doing
examples/roles/bobbins/tasks/main.yml:2: fqcn-builtins Use FQCN for builtin actions

Examples

Included in ansible-lint/examples are some example playbooks with undesirable features. Running ansible-lint on them works, as demonstrated in the following:

$ ansible-lint -p examples/playbooks/example.yml
examples/playbooks/example.yml:9: fqcn-builtins Use FQCN for builtin actions
examples/playbooks/example.yml:9: no-changed-when Commands should not change things if nothing needs doing
examples/playbooks/example.yml:9: var-spacing Variables should have spaces before and after: {{thisvariable}}
examples/playbooks/example.yml:12: fqcn-builtins Use FQCN for builtin actions
examples/playbooks/example.yml:12: no-changed-when Commands should not change things if nothing needs doing
examples/playbooks/example.yml:15: fqcn-builtins Use FQCN for builtin actions
examples/playbooks/example.yml:18: fqcn-builtins Use FQCN for builtin actions
examples/playbooks/example.yml:21: fqcn-builtins Use FQCN for builtin actions
examples/playbooks/example.yml:24: command-instead-of-module git used in place of git module
examples/playbooks/example.yml:24: fqcn-builtins Use FQCN for builtin actions
examples/playbooks/example.yml:24: no-changed-when Commands should not change things if nothing needs doing
examples/playbooks/example.yml:27: command-instead-of-module git used in place of git module
examples/playbooks/example.yml:27: fqcn-builtins Use FQCN for builtin actions
examples/playbooks/example.yml:30: fqcn-builtins Use FQCN for builtin actions
examples/playbooks/example.yml:33: fqcn-builtins Use FQCN for builtin actions
examples/playbooks/example.yml:33: var-spacing Variables should have spaces before and after: {{item}}
examples/playbooks/example.yml:39: fqcn-builtins Use FQCN for builtin actions
examples/playbooks/example.yml:39: package-latest Package installs should not use latest
examples/playbooks/example.yml:42: fqcn-builtins Use FQCN for builtin actions
examples/playbooks/example.yml:42: unnamed-task All tasks should be named
examples/playbooks/example.yml:44: fqcn-builtins Use FQCN for builtin actions
examples/playbooks/example.yml:44: package-latest Package installs should not use latest
examples/playbooks/example.yml:47: fqcn-builtins Use FQCN for builtin actions
examples/playbooks/example.yml:47: unnamed-task All tasks should be named

If playbooks include other playbooks, or tasks, or handlers or roles, these are also handled:

$ ansible-lint --force-color --offline -p examples/playbooks/include.yml
examples/playbooks/handlers/y.yml:1: fqcn-builtins Use FQCN for builtin actions
examples/playbooks/include.yml:10: yaml too many spaces inside braces (braces)
examples/playbooks/play.yml:5: command-instead-of-module service used in place of service module
examples/playbooks/play.yml:5: fqcn-builtins Use FQCN for builtin actions
examples/playbooks/play.yml:5: no-changed-when Commands should not change things if nothing needs doing
examples/playbooks/roles/hello/meta/main.yml:1: meta-no-info No 'galaxy_info' found
examples/playbooks/roles/morecomplex/handlers/main.yml:1: command-instead-of-module service used in place of service module
examples/playbooks/roles/morecomplex/handlers/main.yml:1: fqcn-builtins Use FQCN for builtin actions
examples/playbooks/roles/morecomplex/tasks/main.yml:1: deprecated-command-syntax mkdir used in place of argument state=directory to file module
examples/playbooks/roles/morecomplex/tasks/main.yml:1: fqcn-builtins Use FQCN for builtin actions
examples/playbooks/roles/morecomplex/tasks/main.yml:1: no-changed-when Commands should not change things if nothing needs doing
examples/playbooks/roles/morecomplex/tasks/main.yml:4: deprecated-command-syntax mkdir used in place of argument state=directory to file module
examples/playbooks/roles/morecomplex/tasks/main.yml:4: fqcn-builtins Use FQCN for builtin actions
examples/playbooks/roles/morecomplex/tasks/main.yml:4: no-changed-when Commands should not change things if nothing needs doing
examples/playbooks/roles/morecomplex/tasks/main.yml:7: command-instead-of-shell Use shell only when shell functionality is required
examples/playbooks/roles/morecomplex/tasks/main.yml:7: fqcn-builtins Use FQCN for builtin actions
examples/playbooks/roles/morecomplex/tasks/main.yml:7: no-changed-when Commands should not change things if nothing needs doing
examples/playbooks/roles/morecomplex/tasks/main.yml:8: deprecated-local-action Do not use 'local_action', use 'delegate_to: localhost'
examples/playbooks/tasks/x.yml:1: yaml too few spaces before comment (comments)

A codeclimate report in JSON format can be generated with ansible-lint.

$ ansible-lint -f codeclimate examples/playbooks/norole.yml
[{"type": "issue", "check_name": "[internal-error] the role 'node' was not found in /home/docs/checkouts/readthedocs.org/user_builds/ansible-lint/checkouts/latest/examples/playbooks/roles:/home/docs/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles:/home/docs/.cache/ansible-lint/b2755e/roles:/home/docs/.cache/ansible-lint/b2755e/roles:/home/docs/.cache/ansible-lint/b2755e/roles:/home/docs/checkouts/readthedocs.org/user_builds/ansible-lint/checkouts/latest/examples/playbooks", "categories": ["core"], "severity": "blocker", "description": "This error can be caused by internal bugs but also by custom rules. Instead of just stopping linter we generate there errors and continue processing. This allows users to add this rule to warn list until the root cause is fixed.", "fingerprint": "2a4bda3713fb1154852c7f497ea694b80b511c83c1c15eeb33a0becb6e782f36", "location": {"path": "examples/playbooks/norole.yml", "lines": {"begin": {"line": 5, "column": 5}}}, "content": {"body": "[WARNING]: No inventory was parsed, only implicit localhost is available\n[WARNING]: provided hosts list is empty, only localhost is available. Note that\nthe implicit localhost does not match 'all'\nERROR! the role 'node' was not found in /home/docs/checkouts/readthedocs.org/user_builds/ansible-lint/checkouts/latest/examples/playbooks/roles:/home/docs/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles:/home/docs/.cache/ansible-lint/b2755e/roles:/home/docs/.cache/ansible-lint/b2755e/roles:/home/docs/.cache/ansible-lint/b2755e/roles:/home/docs/checkouts/readthedocs.org/user_builds/ansible-lint/checkouts/latest/examples/playbooks\n\nThe error appears to be in '/home/docs/checkouts/readthedocs.org/user_builds/ansible-lint/checkouts/latest/examples/playbooks/norole.yml': line 5, column 5, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n  roles:\n  - name: node\n    ^ here\n"}}]