Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package ansible-lint for openSUSE:Factory checked in at 2022-11-25 13:13:06 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/ansible-lint (Old) and /work/SRC/openSUSE:Factory/.ansible-lint.new.1597 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ansible-lint" Fri Nov 25 13:13:06 2022 rev:11 rq:1038040 version:6.9.0 Changes: -------- --- /work/SRC/openSUSE:Factory/ansible-lint/ansible-lint.changes 2022-11-22 16:10:45.706206190 +0100 +++ /work/SRC/openSUSE:Factory/.ansible-lint.new.1597/ansible-lint.changes 2022-11-25 13:23:00.455632078 +0100 @@ -1,0 +2,23 @@ +Thu Nov 24 16:00:09 UTC 2022 - Johannes Kastl <ka...@b1-systems.de> + +- update to 6.9.0: + * Minor Changes + - Enable dynamic schema refresh (#2703) @ssbarnea + - Allow additional collections in only-builtins (#2710) @evgeni + * Bugfixes + - Avoid Object of type PosixPath is not JSON serializable with jinja2 (#2724) @ssbarnea + - Expand ~ in PATH and warn user (#2723) @ssbarnea + - Fix only builtins fail test (#2719) @evgeni + - Allow profile to be set in config file (#2720) @shatakshiiii + - Decouple profile listing from profile selecting on CLI (#2721) @ssbarnea + - Update url in docs (#2718) @ssbarnea + - Prevent installation on Windows (#2712) @ssbarnea + - Respect warn_list and skip_list (#2706) @rekup + - Avoid version checking when version info is absent (#2714) @ssbarnea + - Improve installation documentation (#2707) @oraNod + - Docs: usage content edits (#2682) @oraNod + - Sort dependencies (#2711) @ssbarnea + - Fix loop_var_prefix message list in the docs (#2709) @evgeni + - Clarify progressive mode documentation (#2708) @MarcinWieczorek + +------------------------------------------------------------------- Old: ---- ansible-lint-6.8.7.tar.gz New: ---- ansible-lint-6.9.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ ansible-lint.spec ++++++ --- /var/tmp/diff_new_pack.LY0B43/_old 2022-11-25 13:23:00.955634775 +0100 +++ /var/tmp/diff_new_pack.LY0B43/_new 2022-11-25 13:23:00.963634819 +0100 @@ -20,7 +20,7 @@ %global lib_name ansiblelint %{?python_enable_dependency_generator} Name: ansible-lint -Version: 6.8.7 +Version: 6.9.0 Release: 0%{?dist} Summary: Best practices checker for Ansible License: MIT @@ -35,10 +35,11 @@ # https://github.com/ansible/ansible-lint/blob/main/setup.cfg#L98 # SECTION tests BuildRequires: python3-flaky >= 3.7.0 +BuildRequires: python3-pytest BuildRequires: python3-pytest-cov BuildRequires: python3-pytest-xdist >= 2.1.0 BuildRequires: python3-psutil -BuildRequires: python3-black >= 22.1.0 +BuildRequires: python3-black >= 22.8.0 BuildRequires: python3-mypy BuildRequires: python3-pylint BuildRequires: python3-flake8 @@ -46,33 +47,35 @@ # Add runtime requirements (unless required for tests) # to make sure this only builds if they are present +# https://github.com/ansible/ansible-lint/blob/main/setup.cfg#L64 BuildRequires: ansible-core >= 2.12 -BuildRequires: python3-ansible-compat >= 2.2.1 +BuildRequires: python3-ansible-compat >= 2.2.5 BuildRequires: python3-enrich >= 1.2.6 -BuildRequires: python3-jsonschema >= 4.9.0 -BuildRequires: python3-packaging -BuildRequires: python3-PyYAML -BuildRequires: python3-rich >= 9.5.1 -BuildRequires: python3-ruamel.yaml >= 0.15.37 +BuildRequires: python3-filelock >= 3.8.0 +BuildRequires: python3-jsonschema >= 4.17.0 +BuildRequires: python3-packaging >= 21.3 +BuildRequires: python3-PyYAML >= 5.4.1 +BuildRequires: python3-rich >= 12.0.0 +BuildRequires: python3-ruamel.yaml >= 0.17.21 BuildRequires: python3-six BuildRequires: python3-tenacity -BuildRequires: python3-wcmatch >= 7.0 -BuildRequires: python3-yamllint >= 1.25.0 +BuildRequires: python3-wcmatch >= 8.3.2 +BuildRequires: python3-yamllint >= 1.26.3 # https://github.com/ansible/ansible-lint/blob/main/setup.cfg#L69 Requires: ansible-core >= 2.12 -Requires: python3-ansible-compat >= 2.2.1 -Requires: python3-black >= 22.1.0 +Requires: python3-ansible-compat >= 2.2.5 +Requires: python3-black >= 22.8.0 Requires: python3-enrich >= 1.2.6 -Requires: python3-jsonschema >= 4.9.0 -Requires: python3-packaging -Requires: python3-PyYAML -Requires: python3-rich >= 9.5.1 -Requires: python3-ruamel.yaml >= 0.15.37 +Requires: python3-jsonschema >= 4.17.0 +Requires: python3-packaging >= 21.3 +Requires: python3-PyYAML >= 5.4.1 +Requires: python3-rich >= 12.0.0 +Requires: python3-ruamel.yaml >= 0.17.21 Requires: python3-six Requires: python3-tenacity -Requires: python3-wcmatch >= 7.0 -Requires: python3-yamllint >= 1.25.0 +Requires: python3-wcmatch >= 8.3.2 +Requires: python3-yamllint >= 1.26.3 %description Checks playbooks for practices and behavior that could potentially be improved. ++++++ ansible-lint-6.8.7.tar.gz -> ansible-lint-6.9.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/.ansible-lint new/ansible-lint-6.9.0/.ansible-lint --- old/ansible-lint-6.8.7/.ansible-lint 2022-11-21 01:17:27.000000000 +0100 +++ new/ansible-lint-6.9.0/.ansible-lint 2022-11-24 02:08:43.000000000 +0100 @@ -1,5 +1,8 @@ --- # .ansible-lint + +profile: null # min, basic, moderate,safety, shared, production + # exclude_paths included in this file are parsed relative to this file's location # and not relative to the CWD of execution. CLI arguments passed to the --exclude # option are parsed relative to the CWD of execution. @@ -72,6 +75,11 @@ # Offline mode disables installation of requirements.yml offline: false +# Return success if number of violations compared with previous git +# commit has not increased. This feature works only in git +# repositories. +progressive: false + # Define required Ansible's variables to satisfy syntax check extra_vars: foo: bar diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/.config/dictionary.txt new/ansible-lint-6.9.0/.config/dictionary.txt --- old/ansible-lint-6.8.7/.config/dictionary.txt 2022-11-21 01:17:27.000000000 +0100 +++ new/ansible-lint-6.9.0/.config/dictionary.txt 2022-11-24 02:08:43.000000000 +0100 @@ -18,6 +18,7 @@ TOXENV TYPECHECK WSLENV +aarch64 abspath addoption addopts @@ -73,6 +74,7 @@ darglint dataclasses dbservers +deannotate debops decryptable delenv @@ -139,8 +141,6 @@ linkcheck lintable lintables -listrules -listtags literalinclude localectl matchdir diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/.git_archival.txt new/ansible-lint-6.9.0/.git_archival.txt --- old/ansible-lint-6.8.7/.git_archival.txt 2022-11-21 01:17:27.000000000 +0100 +++ new/ansible-lint-6.9.0/.git_archival.txt 2022-11-24 02:08:43.000000000 +0100 @@ -1 +1 @@ -ref-names: HEAD -> main, tag: v6.8.7 +ref-names: tag: v6.9.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/.github/workflows/tox.yml new/ansible-lint-6.9.0/.github/workflows/tox.yml --- old/ansible-lint-6.8.7/.github/workflows/tox.yml 2022-11-21 01:17:27.000000000 +0100 +++ new/ansible-lint-6.9.0/.github/workflows/tox.yml 2022-11-24 02:08:43.000000000 +0100 @@ -163,7 +163,7 @@ WSLENV: FORCE_COLOR:PYTEST_REQPASS:TOXENV:TOX_PARALLEL_NO_SPINNER # Number of expected test passes, safety measure for accidental skip of # tests. Update value if you add/remove tests. - PYTEST_REQPASS: 713 + PYTEST_REQPASS: 717 steps: - name: Activate WSL1 @@ -209,7 +209,7 @@ - name: Initialize tox envs ${{ matrix.tox_env }} run: python3 -m tox --notest --skip-missing-interpreters false -vv -e ${{ matrix.tox_env }} - timeout-minutes: 3 # average is under 1 + timeout-minutes: 5 # average is under 1, but macos can be over 3 # sequential run improves browsing experience (almost no speed impact) - name: "Test with tox: ${{ matrix.tox_env }}" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/.packit.yaml new/ansible-lint-6.9.0/.packit.yaml --- old/ansible-lint-6.8.7/.packit.yaml 2022-11-21 01:17:27.000000000 +0100 +++ new/ansible-lint-6.9.0/.packit.yaml 2022-11-24 02:08:43.000000000 +0100 @@ -17,10 +17,13 @@ - job: copr_build metadata: targets: - # - fedora-34 # has no https://src.fedoraproject.org/rpms/python-build - - fedora-35 - - fedora-36 - # - centos-stream-9 # has no https://src.fedoraproject.org/rpms/python-build + # See https://packit.dev/docs/configuration/#aliases + # API to get available targets: https://api.dev.testing-farm.io/v0.1/composes/public + - fedora-stable + - fedora-development + # Missing python3-build see https://bugzilla.redhat.com/show_bug.cgi?id=2129071 + # - centos-stream-9-aarch64 + # - centos-stream-9-x86_64 trigger: pull_request # - job: tests # trigger: pull_request diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/.pre-commit-config.yaml new/ansible-lint-6.9.0/.pre-commit-config.yaml --- old/ansible-lint-6.8.7/.pre-commit-config.yaml 2022-11-21 01:17:27.000000000 +0100 +++ new/ansible-lint-6.9.0/.pre-commit-config.yaml 2022-11-24 02:08:43.000000000 +0100 @@ -188,7 +188,7 @@ hooks: - id: schemas name: update json schemas - entry: python3 src/ansiblelint/schemas/__init__.py + entry: python3 src/ansiblelint/schemas/__main__.py language: python stages: [manual] - id: pip-compile diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/docs/installing.md new/ansible-lint-6.9.0/docs/installing.md --- old/ansible-lint-6.8.7/docs/installing.md 2022-11-21 01:17:27.000000000 +0100 +++ new/ansible-lint-6.9.0/docs/installing.md 2022-11-24 02:08:43.000000000 +0100 @@ -6,34 +6,44 @@ ``` -Installing on Windows is not supported because we use symlinks inside Python -packages. +Install Ansible-lint to apply rules and follow best practices with your automation content. -Our project does not ship a container. Please avoid raising any bugs -related to containers and use the [discussions](https://github.com/ansible/ansible-lint/discussions) forum instead. +```{note} +Ansible-lint does not currently support installation on Windows systems. +``` + +For a container image, we recommend using [creator-ee](https://github.com/ansible/creator-ee/), which includes Ansible-lint. +If you have a use case that the `creator-ee` container does satisfy, please contact the team through the [discussions](https://github.com/ansible/ansible-lint/discussions) forum. + +You can also run Ansible-lint on your source code with the [Ansible-lint GitHub action](https://github.com/marketplace/actions/ansible-lint) instead of installing it directly. -We recommend you to try [creator-ee](https://github.com/ansible/creator-ee/), -which is a container that also carries ansible-lint. +## Installing the latest version -## Using pip or pipx - -You can use either [pip3] or [pipx] to install it; the latter one -automatically isolates the linter from your current python environment. -That approach may avoid having to deal with particularities of installing -python packages, like creating a virtual environment, activating it, installing -using `--user` or fixing potential conflicts if not using virtualenvs. +You can install the most recent version of Ansible-lint with the [pip3] or [pipx] Python package manager. +Use [pipx] to isolate Ansible-lint from your current Python environment as an alternative to creating a virtual environment. ```bash -# This will also install ansible-core if needed +# This also installs ansible-core if it is not already installed pip3 install "ansible-lint" ``` -(installing-from-source)= +## Installing on Fedora and RHEL + +You can install Ansible-lint on Fedora, or Red Hat Enterprise Linux (RHEL) with the `dnf` package manager. + +```bash +dnf install ansible-lint +``` + +```{note} +On RHEL, `ansible-lint` package is part of "Red Hat Ansible Automation Platform" subscription, which needs +to be activated. +``` -## From Source +## Installing from source code -**Note**: pip 19.0+ is required for installation. Please consult with the -[PyPA User Guide] to learn more about managing Pip versions. +**Note**: pip 19.0+ is required for installation from the source repository. +Please consult the [PyPA User Guide] to learn more about managing Pip versions. ```bash pip3 install git+https://github.com/ansible/ansible-lint.git diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/docs/usage.md new/ansible-lint-6.9.0/docs/usage.md --- old/ansible-lint-6.8.7/docs/usage.md 2022-11-21 01:17:27.000000000 +0100 +++ new/ansible-lint-6.9.0/docs/usage.md 2022-11-24 02:08:43.000000000 +0100 @@ -1,74 +1,63 @@ (using-lint)= -# Usage +# Using ```{contents} Topics ``` -## Command Line Options +## Using commands -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. +After you install Ansible-lint, run `ansible-lint --help` to display available commands and their options. ```{command-output} ansible-lint --help :cwd: .. :returncode: 0 ``` -## Temporary files +### Command output -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. +Ansible-lint prints output on both `stdout` and `stderr`. -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. +- `stdout` displays rule violations. +- `stderr` displays logging and free-form messages like statistics. + +Most `ansible-lint` examples use pep8 as the output format (`-p`) which is machine parseable. -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. +Ansible-lint also print errors using their [annotation] format when it detects the `GITHUB_ACTIONS=true` and `GITHUB_WORKFLOW=...` variables. + +[annotation]: https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-error-message -## CI/CD +## Caching -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. +For optimal performance, Ansible-lint creates caches with installed or mocked roles, collections, and modules in the `{project_dir}/.cache` folder. +The location of `{project_dir}` is passed with a command line argument, determined by the location of the configuration file, git project top-level directory, or user home directory. -## Linting Playbooks and Roles +To perform faster re-runs, Ansible-lint does not automatically clean the cache. +If required you can do this manually by simply deleting the `.cache` folder. +Ansible-lint creates a new cache on the next invocation. -We recommend following the {ref}`collection structure layout <collection_structure>` 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. +You should add the `.cache` folder to the `.gitignore` file in your git repositories. -When you call ansible-lint without arguments the tool will use its internal -heuristics to determine file types. +## Using progressive mode + +For easier adoption, Ansible-lint can alert for rule violations that occur since the last commit. +This allows new code to be merged without any rule violations while allowing content developers to address historical violations at a different pace. + +The `--progressive` option runs Ansible-lint twice if rule violations exist in your content. +The second run is performed against a temporary git working copy that contains +the last commit. +Rule violations that exist in the last commit are ignored and Ansible-lint displays only the violations that exist in the new commit. -`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: +## Linting playbooks and roles + +Ansible-lint recommends following the {ref}`collection structure layout <collection_structure>` whether you plan to build a collection or not. + +Following that layout assures the best integration with all ecosystem tools because it helps those tools better distinguish between random YAML files and files managed by Ansible. +When you call `ansible-lint` without arguments, it uses internal heuristics to determine file types. + +You can specify the list of **roles** or **playbooks** that you want to lint with the `-p` argument. +For example, to lint `examples/playbooks/play.yml` and `examples/roles/bobbins`, use the following command: ```{command-output} ansible-lint -p examples/playbooks/play.yml examples/roles/bobbins :cwd: .. @@ -76,11 +65,10 @@ :nostderr: true ``` -## Examples +## Running example playbooks -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 includes an `ansible-lint/examples` folder that contains example playbooks with different rule violations and undesirable characteristics. +You can run `ansible-lint` on the example playbooks to observe Ansible-lint in action, as follows: ```{command-output} ansible-lint -p examples/playbooks/example.yml :cwd: .. @@ -88,8 +76,7 @@ :nostderr: true ``` -If playbooks include other playbooks, or tasks, or handlers or roles, these -are also handled: +Ansible-lint also handles playbooks that include other playbooks, tasks, handlers, or roles, as the `examples/playbooks/include.yml` example demonstrates. ```{command-output} ansible-lint --force-color --offline -p examples/playbooks/include.yml :cwd: .. @@ -97,8 +84,7 @@ :nostderr: true ``` -A `JSON` report, based on codeclimate specification, can be generated with -ansible-lint. +You can generate `JSON` reports based on the codeclimate specification as the `examples/playbooks/norole.yml` example demonstrates. ```{command-output} ansible-lint -f json examples/playbooks/norole.yml :cwd: .. @@ -106,28 +92,27 @@ :nostderr: true ``` -[annotation]: https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-error-message -[github actions]: https://github.com/features/actions +## Specifying rules at runtime -## Specifying Rules at Runtime +By default, `ansible-lint` applies rules found in `ansible-lint/src/ansiblelint/rules`. +Use the `-r /path/to/custom-rules` option to specify the directory path to a set of custom rules. +For multiple custom rule sets, pass each set with a separate `-r` option. -By default, `ansible-lint` uses the rules found in -`ansible-lint/src/ansiblelint/rules`. To override this behavior and use a -custom set of rules, use the `-r /path/to/custom-rules` option to provide a -directory path containing the custom rules. For multiple rule sets, pass -multiple `-r` options. +You can also combine the default rules with custom rules with the `-R` option along with one or more `-r` options. -It's also possible to use the default rules, plus custom rules. This can be -done by passing the `-R` to indicate that the default rules are to be used, -along with one or more `-r` options. +### Including rules with tags -### Using Tags to Include Rules +Each rule has an associated set of one or more tags. +Use the `-T` option to view the list of tags for each available rule. -Each rule has an associated set of one or more tags. To view the list of tags -for each available rule, use the `-T` option. +You can then use the `-t` option to specify a tag and include the associated rules in the lint run. +For example, the following `ansible-lint` command applies only the rules associated with the _idempotency_ tag: -The following shows the available tags in an example set of rules, and the -rules associated with each tag: +```bash +$ ansible-lint -t idempotency playbook.yml +``` + +The following shows the available tags in an example set of rules and the rules associated with each tag: ```{command-output} ansible-lint -T :cwd: .. @@ -135,56 +120,46 @@ :nostderr: true ``` -To run just the _idempotency_ rules, for example, run the following: - -```bash -$ ansible-lint -t idempotency playbook.yml -``` - -### Excluding Rules +### Excluding rules with tags -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 _formatting_ and _metadata_: +To exclude rules by identifiers or tags, use the `-x SKIP_LIST` option. +For example, the following command applies all rules except those with the _formatting_ and _metadata_ tags: ```bash $ ansible-lint -x formatting,metadata playbook.yml ``` -### Ignoring Rules +### Ignoring rules -To only warn about rules, use the `-w WARN_LIST` option. In this example all -rules are run, but if rules with the `experimental` tag match they only show -an error message but don't change the exit code: +To only warn about rules, use the `-w WARN_LIST` option. +For example, the following command displays only warns about violations with rules associated with the `experimental` tag: ```console $ ansible-lint -w experimental playbook.yml ``` -The default value for `WARN_LIST` is `['experimental']` if you don't -define your own either on the cli or in the config file. If you do define your -own `WARN_LIST` you will need to add `'experimental'` to it if you don't -want experimental rules to change your exit code. - -## False Positives: Skipping Rules - -Some rules are a bit of a rule of thumb. Advanced _git_, _yum_ or _apt_ usage, -for example, is typically difficult to achieve through the modules. In this -case, you should mark the task so that warnings aren't produced. - -To skip a specific rule for a specific task, inside your ansible yaml add -`# noqa [rule_id]` at the end of the line. If the rule is task-based (most -are), add at the end of any line in the task. You can skip multiple rules via -a space-separated list. +By default, the `WARN_LIST` includes the `['experimental']` tag. +If you define a custom `WARN_LIST` you must add `'experimental'` so that Ansible-lint does not fail against experimental rules. + +## Muting warnings to avoid false positives + +Not all linting rules are precise, some are general rules of thumb. +Advanced _git_, _yum_ or _apt_ usage, for example, can be difficult to achieve in a playbook. +In cases like this, Ansible-lint can incorrectly trigger rule violations. + +To disable rule violations for specific tasks, and mute false positives, add `# noqa [rule_id]` to the end of the line. +It is best practice to add a comment that explains why rules are disabled. + +You can add the `# noqa [rule_id]` comment to the end of any line in a task. +You can also skip multiple rules with a space-separated list. ```yaml -- name: This would typically fire git-latest and partial-become +- name: This task would typically fire git-latest and partial-become rules become_user: alice # noqa git-latest partial-become - git: src=/path/to/git/repo dest=checkout + ansible.builtin.git: src=/path/to/git/repo dest=checkout ``` -If the rule is line-based, `# noqa [rule_id]` must be at the end of the -particular line to be skipped +If the rule is line-based, `# noqa [rule_id]` must be at the end of the line. ```yaml - name: This would typically fire LineTooLongRule 204 and jinja[spacing] @@ -193,15 +168,10 @@ dest: "{{dest_proj_path}}/foo.conf" # noqa jinja[spacing] ``` -It's also a good practice to comment the reasons why a task is being skipped. - -If you want skip running a rule entirely, you can use either use `-x` command -line argument, or add it to `skip_list` inside the configuration file. +If you want Ansible-lint to skip a rule entirely, use the `-x` command line argument or add it to `skip_list` in your configuration. -A less-preferred method of skipping is to skip all task-based rules for a task -(this does not skip line-based rules). There are two mechanisms for this: the -`skip_ansible_lint` tag works with all tasks, and the `warn` parameter -works with the _command_ or _shell_ modules only. Examples: +The least preferred method of skipping rules is to skip all task-based rules for a task, which does not skip line-based rules. +You can use the `skip_ansible_lint` tag with all tasks or the `warn` parameter with the _command_ or _shell_ modules, for example: ```yaml - name: This would typically fire deprecated-command-syntax diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/docs/using-profiles.md new/ansible-lint-6.9.0/docs/using-profiles.md --- old/ansible-lint-6.8.7/docs/using-profiles.md 2022-11-21 01:17:27.000000000 +0100 +++ new/ansible-lint-6.9.0/docs/using-profiles.md 2022-11-24 02:08:43.000000000 +0100 @@ -17,10 +17,10 @@ After you install and configure `ansible-lint`, you can apply profiles as follows: -1. View available profiles with the `-P` flag. +1. View available profiles with the `--list-profiles` flag. ```bash - ansible-lint -P + ansible-lint --list-profiles ``` 2. Specify a profile with the `--profile` parameter to lint your content with those rules, for example: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/examples/playbooks/.ansible-lint-only-builtins-allow-collections new/ansible-lint-6.9.0/examples/playbooks/.ansible-lint-only-builtins-allow-collections --- old/ansible-lint-6.8.7/examples/playbooks/.ansible-lint-only-builtins-allow-collections 1970-01-01 01:00:00.000000000 +0100 +++ new/ansible-lint-6.9.0/examples/playbooks/.ansible-lint-only-builtins-allow-collections 2022-11-24 02:08:43.000000000 +0100 @@ -0,0 +1,6 @@ +# Mock modules or roles in order to pass ansible-playbook --syntax-check +mock_modules: + - fake_namespace.fake_collection.fake_module + +only_builtins_allow_collections: + - fake_namespace.fake_collection diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/examples/playbooks/rule-jinja-valid.yml new/ansible-lint-6.9.0/examples/playbooks/rule-jinja-valid.yml --- old/ansible-lint-6.8.7/examples/playbooks/rule-jinja-valid.yml 2022-11-21 01:17:27.000000000 +0100 +++ new/ansible-lint-6.9.0/examples/playbooks/rule-jinja-valid.yml 2022-11-24 02:08:43.000000000 +0100 @@ -26,3 +26,23 @@ vars: ns_vars: {} x: "{{ lookup('ansible.builtin.template', 'namespace.yaml.j2', template_vars=ns_vars) | from_yaml }}" + +# https://github.com/ansible/ansible-lint/issues/2697 +- name: Test linter + hosts: localhost + gather_facts: false + tasks: + - name: Passed linter + ansible.builtin.debug: + msg: "{{ test | to_json }}" + vars: + test: + one: two + param: "{{ ansible_host }}" + - name: Failed linter + ansible.builtin.debug: + msg: "{{ test | to_json }}" + vars: + test: + one: two + param: no jinja diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/examples/reqs_v1/requirements.yml new/ansible-lint-6.9.0/examples/reqs_v1/requirements.yml --- old/ansible-lint-6.8.7/examples/reqs_v1/requirements.yml 2022-11-21 01:17:27.000000000 +0100 +++ new/ansible-lint-6.9.0/examples/reqs_v1/requirements.yml 2022-11-24 02:08:43.000000000 +0100 @@ -1,3 +1,10 @@ --- # v1 requirements test file -- src: geerlingguy.mysql + +# As Jeff never created releases on hit repo, we are unable to download tar.gz +# archives, so we need to use the slower git cloning instead. +# - src: https://github.com/geerlingguy/mysql/archive/refs/tags/4.2.0.tar.gz + +- name: geerlingguy.mysql + src: https://github.com/geerlingguy/ansible-role-mysql + version: 4.2.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/examples/reqs_v2/requirements.yml new/ansible-lint-6.9.0/examples/reqs_v2/requirements.yml --- old/ansible-lint-6.8.7/examples/reqs_v2/requirements.yml 2022-11-21 01:17:27.000000000 +0100 +++ new/ansible-lint-6.9.0/examples/reqs_v2/requirements.yml 2022-11-24 02:08:43.000000000 +0100 @@ -1,5 +1,8 @@ --- roles: - name: geerlingguy.mysql + src: https://github.com/geerlingguy/ansible-role-mysql + version: 4.2.0 + collections: - - name: ssbarnea.molecule + - name: https://galaxy.ansible.com/download/community-molecule-0.1.0.tar.gz diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/examples/roles/invalid-name/tasks/main.yaml new/ansible-lint-6.9.0/examples/roles/invalid-name/tasks/main.yaml --- old/ansible-lint-6.8.7/examples/roles/invalid-name/tasks/main.yaml 2022-11-21 01:17:27.000000000 +0100 +++ new/ansible-lint-6.9.0/examples/roles/invalid-name/tasks/main.yaml 2022-11-24 02:08:43.000000000 +0100 @@ -1,4 +1,4 @@ --- - name: Foo - debug: + ansible.builtin.debug: msg: foo diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/requirements.yml new/ansible-lint-6.9.0/requirements.yml --- old/ansible-lint-6.8.7/requirements.yml 2022-11-21 01:17:27.000000000 +0100 +++ new/ansible-lint-6.9.0/requirements.yml 2022-11-24 02:08:43.000000000 +0100 @@ -2,9 +2,13 @@ collections: # that collection is used during ansible-lint testing for validating our # ability to import_playbook from a collection. - - name: community.molecule - # that collection is used during ansible-lint testing for validating our - # ability to detect non-core modules. - - name: ansible.posix - # that collection is used during ansible-lint own testing - - name: community.general + # - name: community.molecule + # # that collection is used during ansible-lint testing for validating our + # # ability to detect non-core modules. + # - name: ansible.posix + # # that collection is used during ansible-lint own testing + # - name: community.general + # We use URLs to avoid hitting galaxy API, which may fail: + - name: https://galaxy.ansible.com/download/ansible-posix-1.4.0.tar.gz + - name: https://galaxy.ansible.com/download/community-general-6.0.1.tar.gz + - name: https://galaxy.ansible.com/download/community-molecule-0.1.0.tar.gz diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/setup.cfg new/ansible-lint-6.9.0/setup.cfg --- old/ansible-lint-6.8.7/setup.cfg 2022-11-21 01:17:27.000000000 +0100 +++ new/ansible-lint-6.9.0/setup.cfg 2022-11-24 02:08:43.000000000 +0100 @@ -70,20 +70,21 @@ # end-up downloading a huge amount of wheels in its attempt to find one that # is compatible. install_requires = - ansible-compat>=2.2.5 # GPLv3 + # Special order section for helping pip: + will-not-work-on-windows-try-from-wsl-instead; platform_system=="Windows" ansible-core>=2.12.0,<2.14.0; python_version<"3.9" # GPLv3 ansible-core>=2.12.0; python_version>="3.9" # GPLv3 - black>=22.1.0 # MIT - filelock # The Unlicense + ansible-compat>=2.2.5 # GPLv3 + # alphabetically sorted: + black>=22.8.0 # MIT + filelock>=3.8.0 # The Unlicense jsonschema>=4.17.0 # MIT, version needed for improved errors - packaging + packaging>=21.3 # Apache-2.0,BSD-2-Clause pyyaml>=5.4.1 # MIT (centos 9 has 5.3.1) - rich>=12.6.0 - # The next version is planned to have breaking changes - ruamel.yaml>=0.17.21,< 0.18 - # NOTE: per issue #509 0.15.34 included in debian backports - wcmatch>=8.4.1 # MIT - yamllint >= 1.28.0 # GPLv3 + rich>=12.0.0 # MIT + ruamel.yaml >= 0.17.21, < 0.18 # MIT, next version is planned to have breaking changes + yamllint >= 1.26.3 # GPLv3 + wcmatch>=8.3.2 # MIT [options.entry_points] console_scripts = diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/src/ansiblelint/__main__.py new/ansible-lint-6.9.0/src/ansiblelint/__main__.py --- old/ansible-lint-6.8.7/src/ansiblelint/__main__.py 2022-11-21 01:17:27.000000000 +0100 +++ new/ansible-lint-6.9.0/src/ansiblelint/__main__.py 2022-11-24 02:08:43.000000000 +0100 @@ -132,7 +132,7 @@ rules_as_str, ) - if options.listrules: + if options.list_rules: _rule_format_map: dict[str, Callable[..., Any]] = { "plain": rules_as_str, @@ -144,8 +144,8 @@ console.print(_rule_format_map[options.format](rules), highlight=False) return 0 - if options.listtags: - console.print(render_yaml(rules.listtags())) + if options.list_tags: + console.print(render_yaml(rules.list_tags())) return 0 # we should not get here! @@ -170,7 +170,7 @@ transformer.run() -# pylint: disable=too-many-branches +# pylint: disable=too-many-branches,too-many-statements def main(argv: list[str] | None = None) -> int: # noqa: C901 """Linter CLI entry point.""" # alter PATH if needed (venv support) @@ -196,19 +196,28 @@ _logger.debug("Options: %s", options) _logger.debug(os.getcwd()) + if not options.offline: + # refresh schemas must happen before loading rules + if "ansiblelint.schemas" in sys.modules: + raise RuntimeError("ansiblelint.schemas should not be loaded yet") + # pylint: disable=import-outside-toplevel + from ansiblelint.schemas import refresh_schemas + + refresh_schemas() + # pylint: disable=import-outside-toplevel from ansiblelint.rules import RulesCollection from ansiblelint.runner import _get_matches - rules = RulesCollection(options.rulesdirs, profile=options.profile) + rules = RulesCollection(options.rulesdirs, profile_name=options.profile) - if options.profile == []: + if options.list_profiles: from ansiblelint.generate_docs import profiles_as_rich console.print(profiles_as_rich()) return 0 - if options.listrules or options.listtags: + if options.list_rules or options.list_tags: return _do_list(rules) app = get_app() @@ -336,6 +345,19 @@ # This must be run before we do run any subprocesses, and loading config # does this as part of the ansible detection. paths = [x for x in os.environ.get("PATH", "").split(os.pathsep) if x] + + # Expand ~ in PATH as it known to break many tools + expanded = False + for idx, path in enumerate(paths): + if "~" in path: + paths[idx] = os.path.expanduser(path) + expanded = True + if expanded: + print( + "WARNING: PATH altered to expand ~ in it. Read https://stackoverflow.com/a/44704799/99834 and correct your system configuration.", + file=sys.stderr, + ) + inject_paths = [] userbase_bin_path = f"{site.getuserbase()}/bin" @@ -353,6 +375,7 @@ f"WARNING: PATH altered to include {', '.join(inject_paths)} :: This is usually a sign of broken local setup, which can cause unexpected behaviors.", file=sys.stderr, ) + if inject_paths or expanded: os.environ["PATH"] = os.pathsep.join([*inject_paths, *paths]) # We do know that finding ansible in PATH does not guarantee that it is diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/src/ansiblelint/app.py new/ansible-lint-6.9.0/src/ansiblelint/app.py --- old/ansible-lint-6.8.7/src/ansiblelint/app.py 2022-11-21 01:17:27.000000000 +0100 +++ new/ansible-lint-6.9.0/src/ansiblelint/app.py 2022-11-24 02:08:43.000000000 +0100 @@ -333,9 +333,17 @@ # Make linter use the cache dir from compat default_options.cache_dir = app.runtime.cache_dir + role_name_check = 0 + if "role-name" in app.options.warn_list: + role_name_check = 1 + elif "role-name" in app.options.skip_list: + role_name_check = 2 + # mocking must happen before prepare_environment or galaxy install might # fail. _perform_mockings() - app.runtime.prepare_environment(install_local=True, offline=offline) + app.runtime.prepare_environment( + install_local=True, offline=offline, role_name_check=role_name_check + ) return app diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/src/ansiblelint/cli.py new/ansible-lint-6.9.0/src/ansiblelint/cli.py --- old/ansible-lint-6.8.7/src/ansiblelint/cli.py 2022-11-21 01:17:27.000000000 +0100 +++ new/ansible-lint-6.9.0/src/ansiblelint/cli.py 2022-11-24 02:08:43.000000000 +0100 @@ -218,9 +218,17 @@ listing_group = parser.add_mutually_exclusive_group() listing_group.add_argument( + "-P", + "--list-profiles", + dest="list_profiles", + default=False, + action="store_true", + help="List all profiles, no formatting options available.", + ) + listing_group.add_argument( "-L", "--list-rules", - dest="listrules", + dest="list_rules", default=False, action="store_true", help="List all the rules. For listing rules only the following formats " @@ -229,7 +237,7 @@ listing_group.add_argument( "-T", "--list-tags", - dest="listtags", + dest="list_tags", action="store_true", help="List all the tags and the rules they cover. Increase the verbosity level " "with `-v` to include 'opt-in' tag and its rules.", @@ -260,16 +268,12 @@ help="quieter, reduce verbosity, can be specified twice.", ) parser.add_argument( - "-P", "--profile", - # * allow to distinguish between calling without -P, with -P and - # with -P=foo, while '?' does not. We do not support a real list. - nargs="*", dest="profile", - default=None, # when called with -P but no arg will load as empty list [] + default=None, action="store", choices=PROFILES.keys(), - help="Specify which rules profile to be used, or displays available profiles when no argument is given.", + help="Specify which rules profile to be used.", ) parser.add_argument( "-p", @@ -284,9 +288,9 @@ dest="progressive", default=False, action="store_true", - help="Return success if it detects a reduction in number" - " of violations compared with previous git commit. This " - "feature works only in git repositories.", + help="Return success if number of violations compared with" + "previous git commit has not increased. This feature works" + "only in git repositories.", ) parser.add_argument( "--project-dir", @@ -457,12 +461,14 @@ "mock_modules": [], "mock_roles": [], "enable_list": [], + "only_builtins_allow_collections": [], # do not include "write_list" here. See special logic below. } scalar_map = { "loop_var_prefix": None, "project_dir": ".", + "profile": None, } if not file_config: @@ -525,7 +531,7 @@ options = parser.parse_args(arguments) # docs is not document, being used for internal documentation building - if options.listrules and options.format not in ["plain", "rich", "md", "docs"]: + if options.list_rules and options.format not in ["plain", "rich", "md", "docs"]: parser.error( f"argument -f: invalid choice: '{options.format}'. " f"In combination with argument -L only 'plain', " diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/src/ansiblelint/config.py new/ansible-lint-6.9.0/src/ansiblelint/config.py --- old/ansible-lint-6.8.7/src/ansiblelint/config.py 2022-11-21 01:17:27.000000000 +0100 +++ new/ansible-lint-6.9.0/src/ansiblelint/config.py 2022-11-24 02:08:43.000000000 +0100 @@ -107,8 +107,8 @@ exclude_paths=[], format="rich", lintables=[], - listrules=False, - listtags=False, + list_rules=False, + list_tags=False, write_list=[], parseable=False, quiet=False, @@ -122,6 +122,7 @@ mock_modules=[], mock_roles=[], loop_var_prefix=None, + only_builtins_allow_collections=[], var_naming_pattern=None, offline=False, project_dir=".", # default should be valid folder (do not use None here) @@ -130,6 +131,7 @@ skip_action_validation=True, strict=False, rules={}, # Placeholder to set and keep configurations for each rule. + profile=None, ) # Used to store detected tag deprecations @@ -229,9 +231,14 @@ def get_version_warning() -> str: """Display warning if current version is outdated.""" + # 0.1dev1 is special fallback version + if __version__ == "0.1.dev1": + return "" + msg = "" data = {} current_version = Version(__version__) + if not os.path.exists(CACHE_DIR): os.makedirs(CACHE_DIR) cache_file = f"{CACHE_DIR}/latest.json" @@ -260,7 +267,6 @@ html_url = data["html_url"] new_version = Version(data["tag_name"][1:]) # removing v prefix from tag - # breakpoint() if current_version > new_version: msg = "[dim]You are using a pre-release version of ansible-lint.[/]" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/src/ansiblelint/data/profiles.yml new/ansible-lint-6.9.0/src/ansiblelint/data/profiles.yml --- old/ansible-lint-6.8.7/src/ansiblelint/data/profiles.yml 2022-11-21 01:17:27.000000000 +0100 +++ new/ansible-lint-6.9.0/src/ansiblelint/data/profiles.yml 2022-11-24 02:08:43.000000000 +0100 @@ -65,7 +65,6 @@ risky-octal: risky-shell-pipe: shared: - extends: safety description: > The `shared` profile ensures that content follows best practices for packaging and publishing. This profile is intended for content creators who want to make Ansible @@ -73,6 +72,7 @@ [galaxy.ansible.com](https://galaxy.ansible.com), [automation-hub](https://console.redhat.com/ansible/automation-hub), or a private instance. + extends: safety rules: galaxy: # <-- applies to both galaxy and automation-hub ignore-errors: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/src/ansiblelint/rules/__init__.py new/ansible-lint-6.9.0/src/ansiblelint/rules/__init__.py --- old/ansible-lint-6.8.7/src/ansiblelint/rules/__init__.py 2022-11-21 01:17:27.000000000 +0100 +++ new/ansible-lint-6.9.0/src/ansiblelint/rules/__init__.py 2022-11-24 02:08:43.000000000 +0100 @@ -371,12 +371,14 @@ self, rulesdirs: list[str] | None = None, options: Namespace = default_options, - profile: list[str] | None = None, + profile_name: str | None = None, conditional: bool = True, ) -> None: """Initialize a RulesCollection instance.""" self.options = options - self.profile = profile or [] + self.profile = [] + if profile_name: + self.profile = PROFILES[profile_name] if rulesdirs is None: rulesdirs = [] self.rulesdirs = expand_paths_vars(rulesdirs) @@ -396,8 +398,8 @@ self.rules = sorted(self.rules) # when we have a profile we unload some of the rules - if self.profile: - filter_rules_with_profile(self.rules, self.profile[0]) + if profile_name: + filter_rules_with_profile(self.rules, profile_name) def register(self, obj: AnsibleLintRule, conditional: bool = False) -> None: """Register a rule.""" @@ -409,8 +411,8 @@ self.profile, # when profile is used we load all rules and filter later "opt-in" not in obj.tags, obj.id in self.options.enable_list, - self.options.listrules, - self.options.listtags, + self.options.list_rules, + self.options.list_tags, ] ): self.rules.append(obj) @@ -483,7 +485,7 @@ [rule.verbose() for rule in sorted(self.rules, key=lambda x: x.id)] ) - def listtags(self) -> str: + def list_tags(self) -> str: """Return a string with all the tags in the RulesCollection.""" tag_desc = { "command-shell": "Specific to use of command and shell modules", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/src/ansiblelint/rules/fqcn.md new/ansible-lint-6.9.0/src/ansiblelint/rules/fqcn.md --- old/ansible-lint-6.8.7/src/ansiblelint/rules/fqcn.md 2022-11-21 01:17:27.000000000 +0100 +++ new/ansible-lint-6.9.0/src/ansiblelint/rules/fqcn.md 2022-11-24 02:08:43.000000000 +0100 @@ -17,7 +17,7 @@ ``` ```{warning} -This rule does not take [`collections` keyword](https://docs.ansible.com/ansible/latest/user_guide/collections_using.html#simplifying-module-names-with-the-collections-keyword) into consideration. +This rule does not take [`collections` keyword](https://docs.ansible.com/ansible/latest/collections_guide/collections_using_playbooks.html#simplifying-module-names-with-the-collections-keyword) into consideration. The `collections` keyword provided a temporary mechanism transitioning to Ansible 2.9. You should rewrite any content that uses the `collections:` key and avoid it where possible. ``` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/src/ansiblelint/rules/jinja.py new/ansible-lint-6.9.0/src/ansiblelint/rules/jinja.py --- old/ansible-lint-6.8.7/src/ansiblelint/rules/jinja.py 2022-11-21 01:17:27.000000000 +0100 +++ new/ansible-lint-6.9.0/src/ansiblelint/rules/jinja.py 2022-11-24 02:08:43.000000000 +0100 @@ -29,6 +29,24 @@ Token = namedtuple("Token", "lineno token_type value") +DEANNOTATE_KEYS = ("__file__", "__line__", "__start_line__", "__end_line__") + + +def deannotate(data: Any) -> Any: + """Remove our annotations like __file__ and __line__ and return a JSON serializable object.""" + if isinstance(data, dict): + result = data.copy() + for key, value in data.items(): + if key in DEANNOTATE_KEYS: + del result[key] + elif isinstance(value, list): + for i, item in enumerate(value): + value[i] = deannotate(item) + elif isinstance(value, dict): + result[key] = deannotate(value) + return result + return result + class JinjaRule(AnsibleLintRule): """Rule that looks inside jinja2 templates.""" @@ -62,7 +80,7 @@ template( basedir=file.dir if file else ".", value=v, - variables=task.get("vars", {}), + variables=deannotate(task.get("vars", {})), fail_on_error=True, # we later decide which ones to ignore or not ) # ValueError RepresenterError diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/src/ansiblelint/rules/loop_var_prefix.md new/ansible-lint-6.9.0/src/ansiblelint/rules/loop_var_prefix.md --- old/ansible-lint-6.8.7/src/ansiblelint/rules/loop_var_prefix.md 2022-11-21 01:17:27.000000000 +0100 +++ new/ansible-lint-6.9.0/src/ansiblelint/rules/loop_var_prefix.md 2022-11-24 02:08:43.000000000 +0100 @@ -6,8 +6,8 @@ This rule can produce the following messages: -- `[loop-var-prefix[missing]` - Replace any unsafe implicit `item` loop variable by adding `loop_var: <loop_var_prefix>...`. -- `[loop-var-prefix[wrong]` - Ensure loop variables start with `<loop_var_prefix>`. +- `loop-var-prefix[missing]` - Replace any unsafe implicit `item` loop variable by adding `loop_var: <loop_var_prefix>...`. +- `loop-var-prefix[wrong]` - Ensure loop variables start with `<loop_var_prefix>`. This is an opt-in rule. You must enable it in your Ansible-lint configuration as follows: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/src/ansiblelint/rules/only_builtins.py new/ansible-lint-6.9.0/src/ansiblelint/rules/only_builtins.py --- old/ansible-lint-6.8.7/src/ansiblelint/rules/only_builtins.py 2022-11-21 01:17:27.000000000 +0100 +++ new/ansible-lint-6.9.0/src/ansiblelint/rules/only_builtins.py 2022-11-24 02:08:43.000000000 +0100 @@ -4,6 +4,7 @@ import sys from typing import Any +from ansiblelint.config import options from ansiblelint.file_utils import Lintable from ansiblelint.rules import AnsibleLintRule @@ -23,11 +24,16 @@ def matchtask( self, task: dict[str, Any], file: Lintable | None = None ) -> bool | str: - fqcn_builtin = task["action"]["__ansible_module_original__"].startswith( - "ansible.builtin." + module = task["action"]["__ansible_module_original__"] + + is_builtin = module.startswith("ansible.builtin.") or module in builtins + + is_manually_allowed = any( + module.startswith(f"{prefix}.") + for prefix in options.only_builtins_allow_collections ) - non_fqcn_builtin = task["action"]["__ansible_module_original__"] in builtins - return not fqcn_builtin and not non_fqcn_builtin and not is_nested_task(task) + + return not is_builtin and not is_manually_allowed and not is_nested_task(task) # testing code to be loaded only with pytest or when executed the rule file @@ -36,7 +42,7 @@ # pylint: disable=ungrouped-imports import pytest - from ansiblelint.constants import VIOLATIONS_FOUND_RC + from ansiblelint.constants import SUCCESS_RC, VIOLATIONS_FOUND_RC from ansiblelint.testing import RunFromText, run_ansible_lint SUCCESS_PLAY = """ @@ -48,10 +54,9 @@ ansible.builtin.shell: echo This rule should not get matched by the only-builtins rule """ - def test_only_builtin_fail() -> None: + def test_only_builtins_fail() -> None: """Test rule matches.""" result = run_ansible_lint( - "--config-file=/dev/null", "--strict", "--warn-list=", "--enable-list", @@ -60,8 +65,22 @@ ) assert result.returncode == VIOLATIONS_FOUND_RC assert "Failed" in result.stderr - assert "1 failure(s)" in result.stderr - assert "only-builtins" in result.stdout + assert "1 warning(s)" in result.stderr + assert "only-builtins: Use only builtin actions" in result.stdout + + def test_only_builtins_allow_collections() -> None: + """Test rule doesn't match.""" + conf_path = "examples/playbooks/.ansible-lint-only-builtins-allow-collections" + result = run_ansible_lint( + f"--config-file={conf_path}", + "--strict", + "--warn-list=", + "--enable-list", + "only-builtins", + "examples/playbooks/rule-only-builtins.yml", + ) + assert "only-builtins" not in result.stdout + assert result.returncode == SUCCESS_RC @pytest.mark.parametrize( "rule_runner", (OnlyBuiltinsRule,), indirect=["rule_runner"] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/src/ansiblelint/rules/role_name.py new/ansible-lint-6.9.0/src/ansiblelint/rules/role_name.py --- old/ansible-lint-6.8.7/src/ansiblelint/rules/role_name.py 2022-11-21 01:17:27.000000000 +0100 +++ new/ansible-lint-6.9.0/src/ansiblelint/rules/role_name.py 2022-11-24 02:08:43.000000000 +0100 @@ -66,7 +66,6 @@ results = [] if task["action"]["__ansible_module__"] in ROLE_IMPORT_ACTION_NAMES: name = task["action"].get("name", "") - # breakpoint() if "/" in name: results.append( self.create_matcherror( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/src/ansiblelint/rules/syntax_check.py new/ansible-lint-6.9.0/src/ansiblelint/rules/syntax_check.py --- old/ansible-lint-6.8.7/src/ansiblelint/rules/syntax_check.py 2022-11-21 01:17:27.000000000 +0100 +++ new/ansible-lint-6.9.0/src/ansiblelint/rules/syntax_check.py 2022-11-24 02:08:43.000000000 +0100 @@ -140,7 +140,6 @@ if pattern.tag == "empty-playbook": rule = WarningRule() - # breakpoint() results.append( MatchError( message=title, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/src/ansiblelint/schemas/__init__.py new/ansible-lint-6.9.0/src/ansiblelint/schemas/__init__.py --- old/ansible-lint-6.8.7/src/ansiblelint/schemas/__init__.py 2022-11-21 01:17:27.000000000 +0100 +++ new/ansible-lint-6.9.0/src/ansiblelint/schemas/__init__.py 2022-11-24 02:08:43.000000000 +0100 @@ -1,63 +1,4 @@ """Module containing cached JSON schemas.""" -import logging -import os -import sys -import urllib.request +from ansiblelint.schemas.main import JSON_SCHEMAS, refresh_schemas -_logger = logging.getLogger(__package__) - - -# Maps kinds to JSON schemas -# See https://www.schemastore.org/json/ -JSON_SCHEMAS = { - # Do not use anchors in these URLs because python-jsonschema does not support them: - "playbook": "https://raw.githubusercontent.com/ansible/schemas/main/f/ansible-playbook.json", - "tasks": "https://raw.githubusercontent.com/ansible/schemas/main/f/ansible-tasks.json", - "vars": "https://raw.githubusercontent.com/ansible/schemas/main/f/ansible-vars.json", - "requirements": "https://raw.githubusercontent.com/ansible/schemas/main/f/ansible-requirements.json", - "meta": "https://raw.githubusercontent.com/ansible/schemas/main/f/ansible-meta.json", - "galaxy": "https://raw.githubusercontent.com/ansible/schemas/main/f/ansible-galaxy.json", - "execution-environment": "https://raw.githubusercontent.com/ansible/schemas/main/f/ansible-ee.json", - "meta-runtime": "https://raw.githubusercontent.com/ansible/schemas/main/f/ansible-meta-runtime.json", - "inventory": "https://raw.githubusercontent.com/ansible/schemas/main/f/ansible-inventory.json", - "ansible-lint-config": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/ansible-lint-config.json", - "ansible-navigator-config": "https://raw.githubusercontent.com/ansible/ansible-navigator/main/src/ansible_navigator/data/ansible-navigator.json", - "arg_specs": "https://raw.githubusercontent.com/ansible/schemas/main/f/ansible-argument-specs.json", -} - - -def refresh_schemas() -> int: - """Refresh JSON schemas by downloading latest versions. - - Returns number of changed schemas. - """ - changed = 0 - for kind, url in sorted(JSON_SCHEMAS.items()): - if url.startswith("https://raw.githubusercontent.com/ansible/ansible-lint"): - _logger.warning( - "Skipped updating schema that is part of the ansible-lint repository: %s", - url, - ) - continue - path = f"{os.path.relpath(os.path.dirname(__file__))}/{kind}.json" - print(f"Refreshing {path} ...") - with urllib.request.urlopen(url) as response: - content = response.read().decode("utf-8") - with open(f"{path}", "r+", encoding="utf-8") as f_out: - if f_out.read() != content: - f_out.seek(0) - f_out.write(content) - f_out.truncate() - changed += 1 - return changed - - -if __name__ == "__main__": - - if refresh_schemas(): - print( - "Schemas are outdated, please update them in a separate pull request.", - ) - sys.exit(1) - else: - print("Schemas already updated", 0) +__all__ = ("JSON_SCHEMAS", "refresh_schemas") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/src/ansiblelint/schemas/__main__.py new/ansible-lint-6.9.0/src/ansiblelint/schemas/__main__.py --- old/ansible-lint-6.8.7/src/ansiblelint/schemas/__main__.py 1970-01-01 01:00:00.000000000 +0100 +++ new/ansible-lint-6.9.0/src/ansiblelint/schemas/__main__.py 2022-11-24 02:08:43.000000000 +0100 @@ -0,0 +1,12 @@ +"""Module containing cached JSON schemas.""" +import sys + +from .main import refresh_schemas + +if __name__ == "__main__": + + if refresh_schemas(): + print("Schemas were updated.") + sys.exit(1) + else: + print("Schemas not updated", 0) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/src/ansiblelint/schemas/__store__.json new/ansible-lint-6.9.0/src/ansiblelint/schemas/__store__.json --- old/ansible-lint-6.8.7/src/ansiblelint/schemas/__store__.json 1970-01-01 01:00:00.000000000 +0100 +++ new/ansible-lint-6.9.0/src/ansiblelint/schemas/__store__.json 2022-11-24 02:08:43.000000000 +0100 @@ -0,0 +1,49 @@ +{ + "ansible-lint-config": { + "url": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/ansible-lint-config.json" + }, + "ansible-navigator-config": { + "etag": "259a168c473dc88b5def7ea8c7ed28365e46a8abf894cd08fcd57613508e1f26", + "url": "https://raw.githubusercontent.com/ansible/ansible-navigator/main/src/ansible_navigator/data/ansible-navigator.json" + }, + "arg_specs": { + "etag": "cf3e180b9f9a1980ce491905db37bae4968be10bd0e45fb2096e0e360d4a4912", + "url": "https://raw.githubusercontent.com/ansible/schemas/main/f/ansible-argument-specs.json" + }, + "execution-environment": { + "etag": "b2c0e183aabbef8fd83e61e26af2fb1d9a2c8f6549599a24ebf7ccada4c11a81", + "url": "https://raw.githubusercontent.com/ansible/schemas/main/f/ansible-ee.json" + }, + "galaxy": { + "etag": "2bf1bc8df72c9063463daabddcb707e9ec6923633e4b66343237e39be102f63b", + "url": "https://raw.githubusercontent.com/ansible/schemas/main/f/ansible-galaxy.json" + }, + "inventory": { + "etag": "4bf635a87d034c9316c441ab441ef63689059bf96ecd652339ee86200a707f0f", + "url": "https://raw.githubusercontent.com/ansible/schemas/main/f/ansible-inventory.json" + }, + "meta": { + "etag": "ffa1e3f48e1f3dbc2b6a0f18fd27676980bac4c94b39e6c072d55ee5ec27449e", + "url": "https://raw.githubusercontent.com/ansible/schemas/main/f/ansible-meta.json" + }, + "meta-runtime": { + "etag": "21c8e4c37930a1c9b135101fcac6c4ef52cfbfe5a724d27612e7ec067cfc5a6a", + "url": "https://raw.githubusercontent.com/ansible/schemas/main/f/ansible-meta-runtime.json" + }, + "playbook": { + "etag": "3d3d803a7bba95bb159ad65c2b22c8961264308ef32c7e379d9d30ba3efeecae", + "url": "https://raw.githubusercontent.com/ansible/schemas/main/f/ansible-playbook.json" + }, + "requirements": { + "etag": "9805cd5cc2eb54de699fb9bc7a81db6321ab916d068bdd04e98ea58c8a7855e5", + "url": "https://raw.githubusercontent.com/ansible/schemas/main/f/ansible-requirements.json" + }, + "tasks": { + "etag": "68f5b5e1a568199617f777438c434006d9d6cfcd468a0f8b6bf8d1ce8d74af70", + "url": "https://raw.githubusercontent.com/ansible/schemas/main/f/ansible-tasks.json" + }, + "vars": { + "etag": "91faa0cc8adc0adf365a095efa948f8df21fcfc86ac742013b3429d5ea9a6092", + "url": "https://raw.githubusercontent.com/ansible/schemas/main/f/ansible-vars.json" + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/src/ansiblelint/schemas/ansible-lint-config.json new/ansible-lint-6.9.0/src/ansiblelint/schemas/ansible-lint-config.json --- old/ansible-lint-6.8.7/src/ansiblelint/schemas/ansible-lint-config.json 2022-11-21 01:17:27.000000000 +0100 +++ new/ansible-lint-6.9.0/src/ansiblelint/schemas/ansible-lint-config.json 2022-11-24 02:08:43.000000000 +0100 @@ -19,6 +19,11 @@ "additionalProperties": false, "examples": [".ansible-lint", ".config/ansible-lint.yml"], "properties": { + "profile": { + "title": "Profile", + "type": ["null", "string"], + "enum": ["min", "basic", "moderate", "safety", "shared", "production", null] + }, "enable_list": { "items": { "type": "string" @@ -51,6 +56,13 @@ "title": "Loop Var Prefix", "type": "string" }, + "only_builtins_allow_collections": { + "items": { + "type": "string" + }, + "title": "Only Builtins Allow Collections", + "type": "array" + }, "mock_modules": { "items": { "type": "string" @@ -70,6 +82,11 @@ "title": "Offline", "type": "boolean" }, + "progressive": { + "default": false, + "title": "Progressive", + "type": "boolean" + }, "parseable": { "default": true, "title": "Parseable", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/src/ansiblelint/schemas/main.py new/ansible-lint-6.9.0/src/ansiblelint/schemas/main.py --- old/ansible-lint-6.8.7/src/ansiblelint/schemas/main.py 1970-01-01 01:00:00.000000000 +0100 +++ new/ansible-lint-6.9.0/src/ansiblelint/schemas/main.py 2022-11-24 02:08:43.000000000 +0100 @@ -0,0 +1,99 @@ +"""Module containing cached JSON schemas.""" +import json +import logging +import os +import sys +import time +import urllib.request +from pathlib import Path +from urllib.request import Request + +_logger = logging.getLogger(__package__) + + +# Maps kinds to JSON schemas +# See https://www.schemastore.org/json/ +store_file = Path(f"{__file__}/../__store__.json").resolve() +with open(store_file, encoding="utf-8") as json_file: + JSON_SCHEMAS = json.load(json_file) + + +# pylint: disable=too-many-branches +def refresh_schemas(min_age_seconds: int = 3600 * 24) -> int: + """Refresh JSON schemas by downloading latest versions. + + Returns number of changed schemas. + """ + age = int(time.time() - store_file.stat().st_mtime) + + # never check for updated schemas more than once a day + if min_age_seconds < age: + return 0 + if not os.access(store_file, os.W_OK): + _logger.debug( + "Skipping schema update due to lack of writing rights on %s", store_file + ) + return 0 + _logger.debug("Checking for updated schemas...") + + changed = 0 + for kind, data in JSON_SCHEMAS.items(): + url = data["url"] + if "#" in url: + raise RuntimeError( + f"Schema URLs cannot contain # due to python-jsonschema limitation: {url}" + ) + if url.startswith("https://raw.githubusercontent.com/ansible/ansible-lint"): + _logger.debug( + "Skipped updating schema that is part of the ansible-lint repository: %s", + url, + ) + continue + path = Path(f"{os.path.relpath(os.path.dirname(__file__))}/{kind}.json") + _logger.debug("Refreshing %s schema ...", kind) + request = Request(url) + etag = data.get("etag", "") + if etag: + request.add_header("If-None-Match", f'"{data.get("etag")}"') + try: + with urllib.request.urlopen(request) as response: + if response.status == 200: + content = response.read().decode("utf-8") + etag = response.headers["etag"].strip('"') + if etag != data.get("etag", ""): + data["etag"] = etag + changed += 1 + print(etag) + with open(f"{path}", "r+", encoding="utf-8") as f_out: + _logger.info("Schema %s was updated", kind) + if f_out.read() != content: + f_out.seek(0) + f_out.write(content) + f_out.truncate() + else: + path.touch() + changed += 1 + except urllib.error.HTTPError as exc: + if exc.code == 304: + _logger.debug("Schema %s is not modified", url) + continue + _logger.warning( + "Skipped schema refresh due to unexpected exception: %s", exc + ) + return 0 + if changed: + with open(store_file, "w", encoding="utf-8") as f_out: + json.dump(JSON_SCHEMAS, f_out, indent=4, sort_keys=True) + else: + store_file.touch() + changed = 1 + return changed + + +if __name__ == "__main__": + + if refresh_schemas(): + print("Schemas were updated.") + sys.exit(1) + else: + print("Schemas not updated", 0) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/src/ansiblelint/testing/__init__.py new/ansible-lint-6.9.0/src/ansiblelint/testing/__init__.py --- old/ansible-lint-6.8.7/src/ansiblelint/testing/__init__.py 2022-11-21 01:17:27.000000000 +0100 +++ new/ansible-lint-6.9.0/src/ansiblelint/testing/__init__.py 2022-11-24 02:08:43.000000000 +0100 @@ -39,7 +39,6 @@ def _call_runner(self, path: str) -> list[MatchError]: runner = Runner(path, rules=self.collection) - # breakpoint() return runner.run() def run(self, filename: str) -> list[MatchError]: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/src/ansiblelint/version.py new/ansible-lint-6.9.0/src/ansiblelint/version.py --- old/ansible-lint-6.8.7/src/ansiblelint/version.py 2022-11-21 01:17:27.000000000 +0100 +++ new/ansible-lint-6.9.0/src/ansiblelint/version.py 2022-11-24 02:08:43.000000000 +0100 @@ -8,6 +8,8 @@ __version__ = pkg_resources.get_distribution("ansible-lint").version except Exception: # pylint: disable=broad-except - __version__ = "unknown" + # this is the fallback SemVer version picked by setuptools_scm when tag + # information is not available. + __version__ = "0.1.dev1" __all__ = ("__version__",) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/test/test_cli_role_paths.py new/ansible-lint-6.9.0/test/test_cli_role_paths.py --- old/ansible-lint-6.8.7/test/test_cli_role_paths.py 2022-11-21 01:17:27.000000000 +0100 +++ new/ansible-lint-6.9.0/test/test_cli_role_paths.py 2022-11-24 02:08:43.000000000 +0100 @@ -94,15 +94,26 @@ assert "Use shell only when shell functionality is required" in result.stdout -def test_run_role_name_invalid(local_test_dir: str) -> None: +@pytest.mark.parametrize( + ("args", "expected_msg"), + ( + pytest.param( + [], "role-name: Role name invalid-name does not match", id="normal" + ), + pytest.param(["--skip-list", "role-name"], "", id="skipped"), + ), +) +def test_run_role_name_invalid( + local_test_dir: str, args: list[str], expected_msg: str +) -> None: """Test run with a role with invalid name.""" cwd = local_test_dir role_path = "roles/invalid-name" - result = run_ansible_lint(role_path, cwd=cwd) - assert "role-name: Role name invalid-name does not match" in strip_ansi_escape( - result.stdout - ) + result = run_ansible_lint(*args, role_path, cwd=cwd) + assert result.returncode == (2 if expected_msg else 0), result + if expected_msg: + assert expected_msg in strip_ansi_escape(result.stdout) def test_run_role_name_with_prefix(local_test_dir: str) -> None: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.8.7/test/test_schemas.py new/ansible-lint-6.9.0/test/test_schemas.py --- old/ansible-lint-6.8.7/test/test_schemas.py 1970-01-01 01:00:00.000000000 +0100 +++ new/ansible-lint-6.9.0/test/test_schemas.py 2022-11-24 02:08:43.000000000 +0100 @@ -0,0 +1,12 @@ +"""Test schemas modules.""" +from ansiblelint.schemas import refresh_schemas + + +def test_refresh_schemas_skip() -> None: + """Test for schema update skip.""" + assert refresh_schemas(min_age_seconds=0) == 0 + + +def test_refresh_schemas_forced() -> None: + """Test for forced refresh.""" + assert refresh_schemas(min_age_seconds=3600 * 24 * 365 * 10) == 1