We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
False positive: async jobs
<!--- Verify first that your issue is not already reported on GitHub -->
<!--- Also test if the latest release and master branch are affected too -->

##### Summary
<!--- Explain the problem briefly below -->
A `command` module task that is run as an async job is incorrectly treated as a normal sync task.

For async tasks the options like `changed_when` (and `failed_when` and so on) are not given to the async `command` task itself, they are given to the `async_status` module task that is run after the async task.

Ansible-lint does not understand this and complains for rule `no-changed-when` for the `command` task.

Example:
```yaml
---
- name: Asynchronous long task
  command: alongtask.sh
  async: 1000
  poll: 0
  register: job_sleeper

- name: Wait for asynchronous job to end
  async_status:
    jid: '{{ job_sleeper.ansible_job_id }}'
  register: job_result
  until: job_result.finished
  retries: 100
  delay: 10
  changed_when: [....]
```

Note how the `changed_when` is given in the `async_status` task and not in the `command` task.

##### Issue Type

- Bug Report

##### Ansible and Ansible Lint details
<!--- Paste verbatim output between triple backticks -->
```console (paste below)
ansible --version
2.9.21

ansible-lint --version
5.0.8

```

- ansible installation method: pip
- ansible-lint installation method: pip

##### OS / ENVIRONMENT
<!--- Provide all relevant information below, e.g. target OS versions, network device firmware, etc. -->
EL7.9 all updated

##### STEPS TO REPRODUCE
<!--- Describe exactly how to reproduce the problem, using a minimal test-case -->
```yaml
---
- name: Asynchronous yum task
  command: alongtask.sh
  async: 1000
  poll: 0
  register: job_sleeper

- name: Wait for asynchronous job to end
  async_status:
    jid: '{{ job_sleeper.ansible_job_id }}'
  register: job_result
  until: job_result.finished
  retries: 100
  delay: 10
  changed_when: [....]
```

<!--- Paste example playbooks or commands between triple backticks below -->
```console (paste below)

```

<!--- HINT: You can paste gist.github.com links for larger files -->

##### Desired Behaviour
<!--- Describe what you expected to happen when running the steps above -->
Ansible-lint should not detect `no-changed-when` for `command` module task run as async job since the `changed_when` cannot be given to the `command` module task itself.

It should detect that there is a `changed_when` in the following `async_status` task.

##### Actual Behaviour
<!--- Describe what actually happened. If possible run with extra verbosity (-vvvv) -->
Ansible-lint detects false positive `no-changed-when` for `command` module task run as async job even though `changed_when` cannot be correctly given for an async task - the `changed_when` is given for the subsequent `async_status` module task.

<!--- Paste verbatim command output between triple backticks -->
```paste below

```


[minimum complete verifiable example]: http://stackoverflow.com/help/mcve


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/ansiblelint/rules/CommandHasChangesCheckRule.py`
Content:
```
1 # Copyright (c) 2016 Will Thames <will@thames.id.au>
2 #
3 # Permission is hereby granted, free of charge, to any person obtaining a copy
4 # of this software and associated documentation files (the "Software"), to deal
5 # in the Software without restriction, including without limitation the rights
6 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 # copies of the Software, and to permit persons to whom the Software is
8 # furnished to do so, subject to the following conditions:
9 #
10 # The above copyright notice and this permission notice shall be included in
11 # all copies or substantial portions of the Software.
12 #
13 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 # THE SOFTWARE.
20 
21 from typing import TYPE_CHECKING, Any, Dict, Union
22 
23 from ansiblelint.rules import AnsibleLintRule
24 
25 if TYPE_CHECKING:
26     from typing import Optional
27 
28     from ansiblelint.file_utils import Lintable
29 
30 
31 class CommandHasChangesCheckRule(AnsibleLintRule):
32     id = 'no-changed-when'
33     shortdesc = 'Commands should not change things if nothing needs doing'
34     description = (
35         'Commands should either read information (and thus set '
36         '``changed_when``) or not do something if it has already been '
37         'done (using creates/removes) or only do it if another '
38         'check has a particular result (``when``)'
39     )
40     severity = 'HIGH'
41     tags = ['command-shell', 'idempotency']
42     version_added = 'historic'
43 
44     _commands = ['command', 'shell', 'raw']
45 
46     def matchtask(
47         self, task: Dict[str, Any], file: 'Optional[Lintable]' = None
48     ) -> Union[bool, str]:
49         if task["__ansible_action_type__"] == 'task':
50             if task["action"]["__ansible_module__"] in self._commands:
51                 return (
52                     'changed_when' not in task
53                     and 'when' not in task
54                     and 'creates' not in task['action']
55                     and 'removes' not in task['action']
56                 )
57         return False
58
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/ansiblelint/rules/CommandHasChangesCheckRule.py b/src/ansiblelint/rules/CommandHasChangesCheckRule.py
--- a/src/ansiblelint/rules/CommandHasChangesCheckRule.py
+++ b/src/ansiblelint/rules/CommandHasChangesCheckRule.py
@@ -53,5 +53,6 @@
                     and 'when' not in task
                     and 'creates' not in task['action']
                     and 'removes' not in task['action']
+                    and not ('async' in task and task.get('poll') == 0)
                 )
         return False

{"golden_diff": "diff --git a/src/ansiblelint/rules/CommandHasChangesCheckRule.py b/src/ansiblelint/rules/CommandHasChangesCheckRule.py\n--- a/src/ansiblelint/rules/CommandHasChangesCheckRule.py\n+++ b/src/ansiblelint/rules/CommandHasChangesCheckRule.py\n@@ -53,5 +53,6 @@\n                     and 'when' not in task\n                     and 'creates' not in task['action']\n                     and 'removes' not in task['action']\n+                    and not ('async' in task and task.get('poll') == 0)\n                 )\n         return False\n", "issue": "False positive: async jobs\n<!--- Verify first that your issue is not already reported on GitHub -->\r\n<!--- Also test if the latest release and master branch are affected too -->\r\n\r\n##### Summary\r\n<!--- Explain the problem briefly below -->\r\nA `command` module task that is run as an async job is incorrectly treated as a normal sync task.\r\n\r\nFor async tasks the options like `changed_when` (and `failed_when` and so on) are not given to the async `command` task itself, they are given to the `async_status` module task that is run after the async task.\r\n\r\nAnsible-lint does not understand this and complains for rule `no-changed-when` for the `command` task.\r\n\r\nExample:\r\n```yaml\r\n---\r\n- name: Asynchronous long task\r\n  command: alongtask.sh\r\n  async: 1000\r\n  poll: 0\r\n  register: job_sleeper\r\n\r\n- name: Wait for asynchronous job to end\r\n  async_status:\r\n    jid: '{{ job_sleeper.ansible_job_id }}'\r\n  register: job_result\r\n  until: job_result.finished\r\n  retries: 100\r\n  delay: 10\r\n  changed_when: [....]\r\n```\r\n\r\nNote how the `changed_when` is given in the `async_status` task and not in the `command` task.\r\n\r\n##### Issue Type\r\n\r\n- Bug Report\r\n\r\n##### Ansible and Ansible Lint details\r\n<!--- Paste verbatim output between triple backticks -->\r\n```console (paste below)\r\nansible --version\r\n2.9.21\r\n\r\nansible-lint --version\r\n5.0.8\r\n\r\n```\r\n\r\n- ansible installation method: pip\r\n- ansible-lint installation method: pip\r\n\r\n##### OS / ENVIRONMENT\r\n<!--- Provide all relevant information below, e.g. target OS versions, network device firmware, etc. -->\r\nEL7.9 all updated\r\n\r\n##### STEPS TO REPRODUCE\r\n<!--- Describe exactly how to reproduce the problem, using a minimal test-case -->\r\n```yaml\r\n---\r\n- name: Asynchronous yum task\r\n  command: alongtask.sh\r\n  async: 1000\r\n  poll: 0\r\n  register: job_sleeper\r\n\r\n- name: Wait for asynchronous job to end\r\n  async_status:\r\n    jid: '{{ job_sleeper.ansible_job_id }}'\r\n  register: job_result\r\n  until: job_result.finished\r\n  retries: 100\r\n  delay: 10\r\n  changed_when: [....]\r\n```\r\n\r\n<!--- Paste example playbooks or commands between triple backticks below -->\r\n```console (paste below)\r\n\r\n```\r\n\r\n<!--- HINT: You can paste gist.github.com links for larger files -->\r\n\r\n##### Desired Behaviour\r\n<!--- Describe what you expected to happen when running the steps above -->\r\nAnsible-lint should not detect `no-changed-when` for `command` module task run as async job since the `changed_when` cannot be given to the `command` module task itself.\r\n\r\nIt should detect that there is a `changed_when` in the following `async_status` task.\r\n\r\n##### Actual Behaviour\r\n<!--- Describe what actually happened. If possible run with extra verbosity (-vvvv) -->\r\nAnsible-lint detects false positive `no-changed-when` for `command` module task run as async job even though `changed_when` cannot be correctly given for an async task - the `changed_when` is given for the subsequent `async_status` module task.\r\n\r\n<!--- Paste verbatim command output between triple backticks -->\r\n```paste below\r\n\r\n```\r\n\r\n\r\n[minimum complete verifiable example]: http://stackoverflow.com/help/mcve\r\n\n", "before_files": [{"content": "# Copyright (c) 2016 Will Thames <will@thames.id.au>\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n\nfrom typing import TYPE_CHECKING, Any, Dict, Union\n\nfrom ansiblelint.rules import AnsibleLintRule\n\nif TYPE_CHECKING:\n    from typing import Optional\n\n    from ansiblelint.file_utils import Lintable\n\n\nclass CommandHasChangesCheckRule(AnsibleLintRule):\n    id = 'no-changed-when'\n    shortdesc = 'Commands should not change things if nothing needs doing'\n    description = (\n        'Commands should either read information (and thus set '\n        '``changed_when``) or not do something if it has already been '\n        'done (using creates/removes) or only do it if another '\n        'check has a particular result (``when``)'\n    )\n    severity = 'HIGH'\n    tags = ['command-shell', 'idempotency']\n    version_added = 'historic'\n\n    _commands = ['command', 'shell', 'raw']\n\n    def matchtask(\n        self, task: Dict[str, Any], file: 'Optional[Lintable]' = None\n    ) -> Union[bool, str]:\n        if task[\"__ansible_action_type__\"] == 'task':\n            if task[\"action\"][\"__ansible_module__\"] in self._commands:\n                return (\n                    'changed_when' not in task\n                    and 'when' not in task\n                    and 'creates' not in task['action']\n                    and 'removes' not in task['action']\n                )\n        return False\n", "path": "src/ansiblelint/rules/CommandHasChangesCheckRule.py"}], "after_files": [{"content": "# Copyright (c) 2016 Will Thames <will@thames.id.au>\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n\nfrom typing import TYPE_CHECKING, Any, Dict, Union\n\nfrom ansiblelint.rules import AnsibleLintRule\n\nif TYPE_CHECKING:\n    from typing import Optional\n\n    from ansiblelint.file_utils import Lintable\n\n\nclass CommandHasChangesCheckRule(AnsibleLintRule):\n    id = 'no-changed-when'\n    shortdesc = 'Commands should not change things if nothing needs doing'\n    description = (\n        'Commands should either read information (and thus set '\n        '``changed_when``) or not do something if it has already been '\n        'done (using creates/removes) or only do it if another '\n        'check has a particular result (``when``)'\n    )\n    severity = 'HIGH'\n    tags = ['command-shell', 'idempotency']\n    version_added = 'historic'\n\n    _commands = ['command', 'shell', 'raw']\n\n    def matchtask(\n        self, task: Dict[str, Any], file: 'Optional[Lintable]' = None\n    ) -> Union[bool, str]:\n        if task[\"__ansible_action_type__\"] == 'task':\n            if task[\"action\"][\"__ansible_module__\"] in self._commands:\n                return (\n                    'changed_when' not in task\n                    and 'when' not in task\n                    and 'creates' not in task['action']\n                    and 'removes' not in task['action']\n                    and not ('async' in task and task.get('poll') == 0)\n                )\n        return False\n", "path": "src/ansiblelint/rules/CommandHasChangesCheckRule.py"}]}