diff --git a/changelogs/fragments/85834-fix-copy-in-single-file-directory.yml b/changelogs/fragments/85834-fix-copy-in-single-file-directory.yml new file mode 100644 index 00000000000..e19a3f4c273 --- /dev/null +++ b/changelogs/fragments/85834-fix-copy-in-single-file-directory.yml @@ -0,0 +1,2 @@ +bugfixes: + - "copy - when a single-file local directory was specified as the source, ``changed`` used to be ``false`` even when the source was actually copied. It now makes sure ``changed`` is ``true`` in this case. (https://github.com/ansible/ansible/issues/85833)" diff --git a/lib/ansible/plugins/action/copy.py b/lib/ansible/plugins/action/copy.py index 89a6a8f1f95..d3c1f0b2fc4 100644 --- a/lib/ansible/plugins/action/copy.py +++ b/lib/ansible/plugins/action/copy.py @@ -529,11 +529,9 @@ class ActionModule(ActionBase): result.update(module_return) return self._ensure_invocation(result) - paths = os.path.split(source_rel) - dir_path = '' - for dir_component in paths: - os.path.join(dir_path, dir_component) - implicit_directories.add(dir_path) + while (source_rel := os.path.dirname(source_rel)) != '': + implicit_directories.add(source_rel) + if 'diff' in result and not result['diff']: del result['diff'] module_executed = True diff --git a/test/integration/targets/copy/files/subdir_with_deep_single_file/dir/file.txt b/test/integration/targets/copy/files/subdir_with_deep_single_file/dir/file.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/integration/targets/copy/tasks/src_directory_contaning_one_single_file.yml b/test/integration/targets/copy/tasks/src_directory_contaning_one_single_file.yml new file mode 100644 index 00000000000..e5ce4c6b20e --- /dev/null +++ b/test/integration/targets/copy/tasks/src_directory_contaning_one_single_file.yml @@ -0,0 +1,29 @@ +# Test copying to a source directory that contains only a single file in a deeper structure + +- name: Ensure that dest top directory doesn't exist + file: + path: '{{ remote_dir }}/subdir_with_deep_single_file' + state: absent + +- name: Copy subdir_with_deep_single_file directory which contains a single file + copy: + src: subdir_with_deep_single_file + dest: '{{ remote_dir }}' + register: copy_result + +- name: Debug copy result + debug: + var: copy_result + verbosity: 1 + +- name: Check the transferred file + stat: + path: '{{ remote_dir }}/subdir_with_deep_single_file/dir/file.txt' + register: stat_file + +- name: Assert that transferred file exists and copy_result is as expected for deeper structure + assert: + that: + - 'stat_file.stat.exists' + - 'copy_result.changed' + - 'copy_result.dest == remote_dir + "/subdir_with_deep_single_file/dir/file.txt"' diff --git a/test/integration/targets/copy/tasks/tests.yml b/test/integration/targets/copy/tasks/tests.yml index 06643b97a03..c4a0cce357d 100644 --- a/test/integration/targets/copy/tasks/tests.yml +++ b/test/integration/targets/copy/tasks/tests.yml @@ -2535,3 +2535,5 @@ state: absent loop: - '{{ remote_file }}' + +- include_tasks: src_directory_contaning_one_single_file.yml