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 2023-02-18 17:12:19 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/ansible-lint (Old) and /work/SRC/openSUSE:Factory/.ansible-lint.new.22824 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ansible-lint" Sat Feb 18 17:12:19 2023 rev:20 rq:1066523 version:6.13.1 Changes: -------- --- /work/SRC/openSUSE:Factory/ansible-lint/ansible-lint.changes 2023-02-16 16:56:40.186896769 +0100 +++ /work/SRC/openSUSE:Factory/.ansible-lint.new.22824/ansible-lint.changes 2023-02-18 17:12:34.071562678 +0100 @@ -1,0 +2,8 @@ +Fri Feb 17 12:09:56 UTC 2023 - Johannes Kastl <ka...@b1-systems.de> + +- update to 6.13.1: + * Bugfixes + - Improve no-changed-when rule (#3050) @ssbarnea + - Fix ignore file generation (#3046) @jcgruenhag + +------------------------------------------------------------------- Old: ---- ansible-lint-6.13.0.tar.gz New: ---- ansible-lint-6.13.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ ansible-lint.spec ++++++ --- /var/tmp/diff_new_pack.vsCmLO/_old 2023-02-18 17:12:35.643572603 +0100 +++ /var/tmp/diff_new_pack.vsCmLO/_new 2023-02-18 17:12:35.647572629 +0100 @@ -31,7 +31,7 @@ %global lib_name ansiblelint %{?python_enable_dependency_generator} Name: ansible-lint -Version: 6.13.0 +Version: 6.13.1 Release: 0%{?dist} Summary: Best practices checker for Ansible License: MIT ++++++ ansible-lint-6.13.0.tar.gz -> ansible-lint-6.13.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.13.0/.git_archival.txt new/ansible-lint-6.13.1/.git_archival.txt --- old/ansible-lint-6.13.0/.git_archival.txt 2023-02-15 18:19:36.000000000 +0100 +++ new/ansible-lint-6.13.1/.git_archival.txt 2023-02-17 12:51:00.000000000 +0100 @@ -1,4 +1,4 @@ -node: 3d07f99775f543f9cf8440110446913a5ca39a21 -node-date: 2023-02-15T17:19:36+00:00 -describe-name: v6.13.0 -ref-names: HEAD -> main, tag: v6.13.0 +node: 8805eab95ba1a4e7103507cb90e80877921dbeb3 +node-date: 2023-02-17T11:51:00+00:00 +describe-name: v6.13.1 +ref-names: HEAD -> main, tag: v6.13.1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.13.0/.github/workflows/tox.yml new/ansible-lint-6.13.1/.github/workflows/tox.yml --- old/ansible-lint-6.13.0/.github/workflows/tox.yml 2023-02-15 18:19:36.000000000 +0100 +++ new/ansible-lint-6.13.1/.github/workflows/tox.yml 2023-02-17 12:51:00.000000000 +0100 @@ -70,7 +70,7 @@ WSLENV: FORCE_COLOR:PYTEST_REQPASS:TOXENV:GITHUB_STEP_SUMMARY # Number of expected test passes, safety measure for accidental skip of # tests. Update value if you add/remove tests. - PYTEST_REQPASS: 796 + PYTEST_REQPASS: 791 steps: - name: Activate WSL1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.13.0/examples/playbooks/rule-no-changed-when-fail.yml new/ansible-lint-6.13.1/examples/playbooks/rule-no-changed-when-fail.yml --- old/ansible-lint-6.13.0/examples/playbooks/rule-no-changed-when-fail.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/ansible-lint-6.13.1/examples/playbooks/rule-no-changed-when-fail.yml 2023-02-17 12:51:00.000000000 +0100 @@ -0,0 +1,15 @@ +--- +- name: Fixture for no-changed-when (fail with 3 occurrences) + hosts: all + tasks: + - name: Register command output, but cat still does not change anything + ansible.builtin.command: cat {{ my_file | quote }} + register: my_output + - name: Block level 1 + block: + - name: Block level 2 + block: + - name: Basic command task, should fail + ansible.builtin.command: cat my_file + - name: Basic shell task, should fail + shell: cat my_file # noqa: fqcn command-instead-of-shell diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.13.0/examples/playbooks/rule-no-changed-when-pass.yml new/ansible-lint-6.13.1/examples/playbooks/rule-no-changed-when-pass.yml --- old/ansible-lint-6.13.0/examples/playbooks/rule-no-changed-when-pass.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/ansible-lint-6.13.1/examples/playbooks/rule-no-changed-when-pass.yml 2023-02-17 12:51:00.000000000 +0100 @@ -0,0 +1,23 @@ +--- +- name: Fixture for no-changed-when (pass) + hosts: all + tasks: + - name: Handle command output with return code # noqa: command-instead-of-shell + ansible.builtin.command: cat {{ my_file | quote }} + register: my_output + changed_when: my_output.rc != 0 + + - name: Handle shell output with return code # noqa: command-instead-of-shell + ansible.builtin.shell: cat {{ my_file | quote }} + register: my_output + changed_when: my_output.rc != 0 + + - name: Handle shell output with false changed_when # noqa: command-instead-of-shell + ansible.builtin.shell: cat {{ my_file | quote }} + register: my_output + changed_when: false + + - name: Command with argument + command: createfile.sh # noqa: fqcn + args: + creates: /tmp/????unknown_files???? diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.13.0/examples/playbooks/rule-no-free-form-pass.yml new/ansible-lint-6.13.1/examples/playbooks/rule-no-free-form-pass.yml --- old/ansible-lint-6.13.0/examples/playbooks/rule-no-free-form-pass.yml 2023-02-15 18:19:36.000000000 +0100 +++ new/ansible-lint-6.13.1/examples/playbooks/rule-no-free-form-pass.yml 2023-02-17 12:51:00.000000000 +0100 @@ -16,3 +16,4 @@ # https://github.com/ansible/ansible-lint/issues/2573 ansible.builtin.command: localectl set-locale LANG=en_GB.UTF-8 when: not ansible_check_mode + changed_when: false diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.13.0/src/ansiblelint/app.py new/ansible-lint-6.13.1/src/ansiblelint/app.py --- old/ansible-lint-6.13.0/src/ansiblelint/app.py 2023-02-15 18:19:36.000000000 +0100 +++ new/ansible-lint-6.13.1/src/ansiblelint/app.py 2023-02-17 12:51:00.000000000 +0100 @@ -171,13 +171,12 @@ console_stderr.print(f"Writing ignore file to {IGNORE_TXT}") lines = set() for rule in result.matches: - lines.add(f"{rule.filename} {rule.tag}") + lines.add(f"{rule.filename} {rule.tag}\n") with open(IGNORE_TXT, "w", encoding="utf-8") as ignore_file: ignore_file.write( "# This file contains ignores rule violations for ansible-lint\n" ) ignore_file.writelines(sorted(list(lines))) - ignore_file.write("\n") elif matched_rules and not self.options.quiet: console_stderr.print( "Read [link=https://ansible-lint.readthedocs.io/configuring/#ignoring-rules-for-entire-files]documentation[/link] for instructions on how to ignore specific rule violations." diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.13.0/src/ansiblelint/rules/no_changed_when.md new/ansible-lint-6.13.1/src/ansiblelint/rules/no_changed_when.md --- old/ansible-lint-6.13.0/src/ansiblelint/rules/no_changed_when.md 2023-02-15 18:19:36.000000000 +0100 +++ new/ansible-lint-6.13.1/src/ansiblelint/rules/no_changed_when.md 2023-02-17 12:51:00.000000000 +0100 @@ -1,12 +1,20 @@ # no-changed-when -This rule checks that tasks return changes to results or conditions. -Unless tasks only read information, you should ensure that they return changes in the following ways: +This rule checks that tasks return changes to results or conditions. Unless +tasks only read information, you should ensure that they return changes in the +following ways: - Register results or conditions and use the `changed_when` clause. - Use the `creates` or `removes` argument. -You should use the `when` clause to run tasks only if a check returns a particular result. +You should always use the `changed_when` clause on tasks that do not naturally +detect if a change has occurred or not. Some of the most common examples are +[shell] and [command] modules, which run arbitrary commands. + +One very common workaround is to use a boolean value like `changed_when: false` +if the task never changes anything or `changed_when: true` if it always +changes something, but you can also use any expressions, including ones that +use the registered result of a task, like in our example below. ## Problematic Code @@ -31,3 +39,8 @@ register: my_output # <- Registers the command output. changed_when: my_output.rc != 0 # <- Uses the return code to define when the task has changed. ``` + +[shell]: + https://docs.ansible.com/ansible/latest/collections/ansible/builtin/shell_module.html +[command]: + https://docs.ansible.com/ansible/latest/collections/ansible/builtin/command_module.html diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible-lint-6.13.0/src/ansiblelint/rules/no_changed_when.py new/ansible-lint-6.13.1/src/ansiblelint/rules/no_changed_when.py --- old/ansible-lint-6.13.0/src/ansiblelint/rules/no_changed_when.py 2023-02-15 18:19:36.000000000 +0100 +++ new/ansible-lint-6.13.1/src/ansiblelint/rules/no_changed_when.py 2023-02-17 12:51:00.000000000 +0100 @@ -24,6 +24,7 @@ import sys from typing import TYPE_CHECKING, Any +from ansiblelint.errors import MatchError from ansiblelint.rules import AnsibleLintRule if TYPE_CHECKING: @@ -34,168 +35,60 @@ """Commands should not change things if nothing needs doing.""" id = "no-changed-when" - description = """ -Tasks should tell Ansible when to return ``changed``, unless the task only reads -information. To do this, set ``changed_when``, use the ``creates`` or -``removes`` argument, or use ``when`` to run the task only if another check has -a particular result. - -For example, this task registers the ``shell`` output and uses the return code -to define when the task has changed. - -```yaml - - name: Handle shell output with return code - ansible.builtin.shell: cat {{ my_file|quote }} - register: my_output - changed_when: my_output.rc != 0 -``` - -The following example will trigger the rule since the task does not -handle the output of the ``command``. - -```yaml - - name: Does not handle any output or return codes - ansible.builtin.command: cat {{ my_file|quote }} -``` - """ severity = "HIGH" tags = ["command-shell", "idempotency"] version_added = "historic" - _commands = ["command", "shell", "raw"] + _commands = [ + "ansible.builtin.command", + "ansible.builtin.shell", + "ansible.builtin.raw", + "ansible.legacy.command", + "ansible.legacy.shell", + "ansible.legacy.raw", + "command", + "shell", + "raw", + ] def matchtask( self, task: dict[str, Any], file: Lintable | None = None - ) -> bool | str: + ) -> list[MatchError]: + result = [] # tasks in a block are "meta" type if task["__ansible_action_type__"] in ["task", "meta"]: - if task["action"]["__ansible_module__"] in self._commands: - return ( - "changed_when" not in task - and "when" not in task - and "creates" not in task["action"] - and "removes" not in task["action"] - ) - return False + if task["action"]["__ansible_module__"] in self._commands and ( + "changed_when" not in task + and "creates" not in task["action"] + and "removes" not in task["action"] + ): + result.append(self.create_matcherror(filename=file)) + return result if "pytest" in sys.modules: import pytest - NO_CHANGE_COMMAND_RC = """ -- hosts: all - tasks: - - name: Handle command output with return code - ansible.builtin.command: cat {{ my_file|quote }} - register: my_output - changed_when: my_output.rc != 0 -""" - - NO_CHANGE_SHELL_RC = """ -- hosts: all - tasks: - - name: Handle shell output with return code - ansible.builtin.shell: cat {{ my_file|quote }} - register: my_output - changed_when: my_output.rc != 0 -""" - - NO_CHANGE_SHELL_FALSE = """ -- hosts: all - tasks: - - name: Handle shell output with false changed_when - ansible.builtin.shell: cat {{ my_file|quote }} - register: my_output - changed_when: false -""" - - NO_CHANGE_ARGS = """ -- hosts: all - tasks: - - name: Command with argument - command: createfile.sh - args: - creates: /tmp/????unknown_files???? -""" - - NO_CHANGE_REGISTER_FAIL = """ -- hosts: all - tasks: - - name: Register command output, but cat still does not change anything - ansible.builtin.command: cat {{ my_file|quote }} - register: my_output -""" - - # also test to ensure it catches tasks in nested blocks. - NO_CHANGE_COMMAND_FAIL = """ -- hosts: all - tasks: - - block: - - block: - - name: Basic command task, should fail - ansible.builtin.command: cat my_file -""" - - NO_CHANGE_SHELL_FAIL = """ -- hosts: all - tasks: - - name: Basic shell task, should fail - shell: cat my_file -""" + from ansiblelint.rules import RulesCollection # pylint: disable=ungrouped-imports + from ansiblelint.runner import Runner # pylint: disable=ungrouped-imports @pytest.mark.parametrize( - "rule_runner", (CommandHasChangesCheckRule,), indirect=["rule_runner"] - ) - def test_no_change_command_rc(rule_runner: Any) -> None: - """This should pass since ``*_when`` is used.""" - results = rule_runner.run_playbook(NO_CHANGE_COMMAND_RC) - assert len(results) == 0 - - @pytest.mark.parametrize( - "rule_runner", (CommandHasChangesCheckRule,), indirect=["rule_runner"] - ) - def test_no_change_shell_rc(rule_runner: Any) -> None: - """This should pass since ``*_when`` is used.""" - results = rule_runner.run_playbook(NO_CHANGE_SHELL_RC) - assert len(results) == 0 - - @pytest.mark.parametrize( - "rule_runner", (CommandHasChangesCheckRule,), indirect=["rule_runner"] - ) - def test_no_change_shell_false(rule_runner: Any) -> None: - """This should pass since ``*_when`` is used.""" - results = rule_runner.run_playbook(NO_CHANGE_SHELL_FALSE) - assert len(results) == 0 - - @pytest.mark.parametrize( - "rule_runner", (CommandHasChangesCheckRule,), indirect=["rule_runner"] - ) - def test_no_change_args(rule_runner: Any) -> None: - """This test should not pass since the command doesn't do anything.""" - results = rule_runner.run_playbook(NO_CHANGE_ARGS) - assert len(results) == 0 - - @pytest.mark.parametrize( - "rule_runner", (CommandHasChangesCheckRule,), indirect=["rule_runner"] - ) - def test_no_change_register_fail(rule_runner: Any) -> None: - """This test should not pass since cat still doesn't do anything.""" - results = rule_runner.run_playbook(NO_CHANGE_REGISTER_FAIL) - assert len(results) == 1 - - @pytest.mark.parametrize( - "rule_runner", (CommandHasChangesCheckRule,), indirect=["rule_runner"] - ) - def test_no_change_command_fail(rule_runner: Any) -> None: - """This test should fail because command isn't handled.""" - # this also ensures that this catches tasks in nested blocks - results = rule_runner.run_playbook(NO_CHANGE_COMMAND_FAIL) - assert len(results) == 1 - - @pytest.mark.parametrize( - "rule_runner", (CommandHasChangesCheckRule,), indirect=["rule_runner"] - ) - def test_no_change_shell_fail(rule_runner: Any) -> None: - """This test should fail because shell isn't handled..""" - results = rule_runner.run_playbook(NO_CHANGE_SHELL_FAIL) - assert len(results) == 1 + ("file", "expected"), + ( + pytest.param( + "examples/playbooks/rule-no-changed-when-pass.yml", 0, id="pass" + ), + pytest.param( + "examples/playbooks/rule-no-changed-when-fail.yml", 3, id="fail" + ), + ), + ) + def test_rule_no_changed_when( + default_rules_collection: RulesCollection, file: str, expected: int + ) -> None: + """Validate no-changed-when rule.""" + results = Runner(file, rules=default_rules_collection).run() + + for result in results: + assert result.rule.id == CommandHasChangesCheckRule.id, result + assert len(results) == expected