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 | -T]
                    [-f {rich,plain,md,json,codeclimate,quiet,pep8,sarif}]
                    [-q] [-p] [--progressive] [--project-dir PROJECT_DIR]
                    [-r RULESDIR] [-R] [--write [WRITE_LIST]] [--show-relpath]
                    [-t TAGS] [-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-rules      List all the rules. For listing rules only the
                        following formats for argument -f are supported:
                        {plain, rich, md}
  -T, --list-tags       List all the tags and the rules they cover. Increase
                        the verbosity level with `-v` to include 'opt-in' tag
                        and its rules.
  -f {rich,plain,md,json,codeclimate,quiet,pep8,sarif}, --format {rich,plain,md,json,codeclimate,quiet,pep8,sarif}
                        stdout formatting, json being an alias for
                        codeclimate. (default: rich)
  -q                    quieter, reduce verbosity, can be specified twice.
  -p, --parseable       parseable output, same as '-f pep8'
  --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, --rules-dir 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
  --write [WRITE_LIST]  Allow ansible-lint to reformat YAML files and run rule
                        transforms (Reformatting YAML files standardizes
                        spacing, quotes, etc. A rule transform can fix or
                        simplify fixing issues identified by that rule). You
                        can limit the effective rule transforms (the
                        'write_list') by passing a keywords 'all' or 'none' or
                        a comma separated list of rule ids or rule tags. YAML
                        reformatting happens whenever '--write' or '--write='
                        is used. '--write' and '--write=all' are equivalent:
                        they allow all transforms to run. The effective list
                        of transforms comes from 'write_list' in the config
                        file, followed whatever '--write' args are provided on
                        the commandline. '--write=none' resets the list of
                        transforms to allow reformatting YAML without running
                        any of the transforms (ie '--write=none,rule-id' will
                        ignore write_list in the config file and only run the
                        rule-id transform).
  --show-relpath        Display path relative to CWD
  -t TAGS, --tags TAGS  only check rules whose id/tags match these values
  -v                    Increase verbosity level (-vv for more)
  -x SKIP_LIST, --skip-list SKIP_LIST
                        only check rules whose id/tags do not match these
                        values
  -w WARN_LIST, --warn-list 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, --config-file CONFIG_FILE
                        Specify configuration file to use. By default it will
                        look for '.ansible-lint' or '.config/ansible-lint.yml'
  --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: 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:1: schema: None should not be valid under {'required': ['block']} (schema[playbook])
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: { var_name }.
examples/playbooks/example.yml:12: no-changed-when: Commands should not change things if nothing needs doing.
examples/playbooks/example.yml:24: command-instead-of-module: git used in place of git module
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:33: var-spacing: Variables should have spaces before and after: { var_name }.
examples/playbooks/example.yml:39: package-latest: Package installs should not use latest.
examples/playbooks/example.yml:42: unnamed-task: All tasks should be named.
examples/playbooks/example.yml:44: package-latest: Package installs should not use latest.
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/include.yml:13:7: syntax-check: Invalid options for ansible.builtin.include_tasks: y

A JSON report, based on codeclimate specification, can be generated with ansible-lint.

$ ansible-lint -f json examples/playbooks/norole.yml
[{"type": "issue", "check_name": "internal-error", "categories": ["core"], "severity": "blocker", "description": "the role 'node' was not found in /home/docs/checkouts/readthedocs.org/user_builds/ansible-lint/checkouts/latest/examples/playbooks/roles:/home/docs/.cache/ansible-compat/5e1e2b/roles:/home/docs/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles:/home/docs/checkouts/readthedocs.org/user_builds/ansible-lint/checkouts/latest/examples/playbooks", "fingerprint": "604fd3d9f78d68b1524e0d682e5d57597bd2460d01fd131e286f3a44d3a76a33", "location": {"path": "examples/playbooks/norole.yml", "lines": {"begin": {"line": 5, "column": 7}}}, "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/.cache/ansible-compat/5e1e2b/roles:/home/docs/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/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 7, 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"}}]