From a453ac31f3428614cceb99027f8efbdb9258a40b Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Tue, 14 May 2024 22:03:01 +0200 Subject: Adding upstream version 2.10.7+merged+base+2.10.8+dfsg. Signed-off-by: Daniel Baumann --- test/integration/targets/git/aliases | 2 + .../targets/git/handlers/cleanup-default.yml | 6 + .../targets/git/handlers/cleanup-freebsd.yml | 5 + test/integration/targets/git/handlers/main.yml | 7 + test/integration/targets/git/meta/main.yml | 3 + .../targets/git/tasks/ambiguous-ref.yml | 37 ++++ test/integration/targets/git/tasks/archive.yml | 135 ++++++++++++ .../targets/git/tasks/change-repo-url.yml | 132 ++++++++++++ .../targets/git/tasks/checkout-new-tag.yml | 54 +++++ test/integration/targets/git/tasks/depth.yml | 229 ++++++++++++++++++++ .../targets/git/tasks/forcefully-fetch-tag.yml | 38 ++++ test/integration/targets/git/tasks/formats.yml | 40 ++++ .../targets/git/tasks/gpg-verification.yml | 212 ++++++++++++++++++ test/integration/targets/git/tasks/localmods.yml | 112 ++++++++++ test/integration/targets/git/tasks/main.yml | 40 ++++ .../targets/git/tasks/missing_hostkey.yml | 48 +++++ .../targets/git/tasks/no-destination.yml | 13 ++ .../integration/targets/git/tasks/reset-origin.yml | 25 +++ .../targets/git/tasks/separate-git-dir.yml | 132 ++++++++++++ .../targets/git/tasks/setup-local-repos.yml | 45 ++++ test/integration/targets/git/tasks/setup.yml | 43 ++++ .../targets/git/tasks/specific-revision.yml | 238 +++++++++++++++++++++ test/integration/targets/git/tasks/submodules.yml | 124 +++++++++++ test/integration/targets/git/vars/main.yml | 97 +++++++++ 24 files changed, 1817 insertions(+) create mode 100644 test/integration/targets/git/aliases create mode 100644 test/integration/targets/git/handlers/cleanup-default.yml create mode 100644 test/integration/targets/git/handlers/cleanup-freebsd.yml create mode 100644 test/integration/targets/git/handlers/main.yml create mode 100644 test/integration/targets/git/meta/main.yml create mode 100644 test/integration/targets/git/tasks/ambiguous-ref.yml create mode 100644 test/integration/targets/git/tasks/archive.yml create mode 100644 test/integration/targets/git/tasks/change-repo-url.yml create mode 100644 test/integration/targets/git/tasks/checkout-new-tag.yml create mode 100644 test/integration/targets/git/tasks/depth.yml create mode 100644 test/integration/targets/git/tasks/forcefully-fetch-tag.yml create mode 100644 test/integration/targets/git/tasks/formats.yml create mode 100644 test/integration/targets/git/tasks/gpg-verification.yml create mode 100644 test/integration/targets/git/tasks/localmods.yml create mode 100644 test/integration/targets/git/tasks/main.yml create mode 100644 test/integration/targets/git/tasks/missing_hostkey.yml create mode 100644 test/integration/targets/git/tasks/no-destination.yml create mode 100644 test/integration/targets/git/tasks/reset-origin.yml create mode 100644 test/integration/targets/git/tasks/separate-git-dir.yml create mode 100644 test/integration/targets/git/tasks/setup-local-repos.yml create mode 100644 test/integration/targets/git/tasks/setup.yml create mode 100644 test/integration/targets/git/tasks/specific-revision.yml create mode 100644 test/integration/targets/git/tasks/submodules.yml create mode 100644 test/integration/targets/git/vars/main.yml (limited to 'test/integration/targets/git') diff --git a/test/integration/targets/git/aliases b/test/integration/targets/git/aliases new file mode 100644 index 00000000..f71c8117 --- /dev/null +++ b/test/integration/targets/git/aliases @@ -0,0 +1,2 @@ +shippable/posix/group4 +skip/aix diff --git a/test/integration/targets/git/handlers/cleanup-default.yml b/test/integration/targets/git/handlers/cleanup-default.yml new file mode 100644 index 00000000..02a79882 --- /dev/null +++ b/test/integration/targets/git/handlers/cleanup-default.yml @@ -0,0 +1,6 @@ +# TODO remove everything we'd installed (see git_required_packages), not just git +# problem is that we should not remove what we hadn't installed +- name: remove git + package: + name: git + state: absent diff --git a/test/integration/targets/git/handlers/cleanup-freebsd.yml b/test/integration/targets/git/handlers/cleanup-freebsd.yml new file mode 100644 index 00000000..1ee35013 --- /dev/null +++ b/test/integration/targets/git/handlers/cleanup-freebsd.yml @@ -0,0 +1,5 @@ +- name: remove git fromn FreeBSD + pkgng: + name: git + state: absent + autoremove: yes diff --git a/test/integration/targets/git/handlers/main.yml b/test/integration/targets/git/handlers/main.yml new file mode 100644 index 00000000..875f513a --- /dev/null +++ b/test/integration/targets/git/handlers/main.yml @@ -0,0 +1,7 @@ +- name: cleanup + include_tasks: "{{ cleanup_filename }}" + with_first_found: + - "cleanup-{{ ansible_distribution | lower }}.yml" + - "cleanup-default.yml" + loop_control: + loop_var: cleanup_filename diff --git a/test/integration/targets/git/meta/main.yml b/test/integration/targets/git/meta/main.yml new file mode 100644 index 00000000..34a77cb7 --- /dev/null +++ b/test/integration/targets/git/meta/main.yml @@ -0,0 +1,3 @@ +dependencies: + - prepare_tests + - setup_gnutar diff --git a/test/integration/targets/git/tasks/ambiguous-ref.yml b/test/integration/targets/git/tasks/ambiguous-ref.yml new file mode 100644 index 00000000..f06112e5 --- /dev/null +++ b/test/integration/targets/git/tasks/ambiguous-ref.yml @@ -0,0 +1,37 @@ +# test for https://github.com/ansible/ansible-modules-core/pull/3386 + +- name: AMBIGUOUS-REF | clone repo + git: + repo: '{{ repo_format1 }}' + dest: '{{ checkout_dir }}' + +- name: AMBIGUOUS-REF | rename remote to be ambiguous + command: git remote rename origin v0.1 + args: + chdir: "{{ checkout_dir }}" + +- name: AMBIGUOUS-REF | switch to HEAD + git: + repo: '{{ repo_format1 }}' + dest: '{{ checkout_dir }}' + remote: v0.1 + +- name: AMBIGUOUS-REF | rev-parse remote HEAD + command: git rev-parse v0.1/HEAD + args: + chdir: "{{ checkout_dir }}" + register: git_remote_head + +- name: AMBIGUOUS-REF | rev-parse local HEAD + command: git rev-parse HEAD + args: + chdir: "{{ checkout_dir }}" + register: git_local_head + +- assert: + that: git_remote_head.stdout == git_local_head.stdout + +- name: AMBIGUOUS-REF | clear checkout_dir + file: + state: absent + path: "{{ checkout_dir }}" diff --git a/test/integration/targets/git/tasks/archive.yml b/test/integration/targets/git/tasks/archive.yml new file mode 100644 index 00000000..574559ef --- /dev/null +++ b/test/integration/targets/git/tasks/archive.yml @@ -0,0 +1,135 @@ +- name: ARCHIVE | Clear checkout_dir + file: + state: absent + path: "{{ checkout_dir }}" + +- name: ARCHIVE | Archive repo using various archival format + git: + repo: '{{ repo_format1 }}' + dest: '{{ checkout_dir }}' + archive: '{{ checkout_dir }}/test_role.{{ item }}' + register: git_archive + with_items: "{{ git_archive_extensions[ansible_os_family ~ ansible_distribution_major_version | default('default') ] | default(git_archive_extensions.default) }}" + +# The map filter was added in Jinja2 2.7, which is newer than the version on RHEL/CentOS 6, +# so we skip this validation on those hosts +- name: ARCHIVE | Assert that archives were downloaded + assert: + that: (git_archive.results | map(attribute='changed') | unique | list)[0] + when: + - "ansible_os_family == 'RedHat'" + - ansible_distribution_major_version is version('7', '>=') + +- name: ARCHIVE | Check if archive file is created or not + stat: + path: '{{ checkout_dir }}/test_role.{{ item }}' + register: archive_check + with_items: "{{ git_archive_extensions[ansible_os_family ~ ansible_distribution_major_version | default('default') ] | default(git_archive_extensions.default) }}" + +- name: ARCHIVE | Assert that archive files exist + assert: + that: (archive_check.results | map(attribute='stat.exists') | unique | list)[0] + when: + - "ansible_os_family == 'RedHat'" + - ansible_distribution_major_version is version('7', '>=') + +- name: ARCHIVE | Clear checkout_dir + file: + state: absent + path: "{{ checkout_dir }}" + +- name: ARCHIVE | Clone clean repo + git: + repo: '{{ repo_format1 }}' + dest: '{{ checkout_dir }}' + +# Check git archive functionality without update +- name: ARCHIVE | Archive repo using various archival format and without update + git: + repo: '{{ repo_format1 }}' + dest: '{{ checkout_dir }}' + update: no + archive: '{{ checkout_dir }}/test_role.{{ item }}' + register: git_archive + with_items: "{{ git_archive_extensions[ansible_os_family ~ ansible_distribution_major_version | default('default') ] | default(git_archive_extensions.default) }}" + +# The map filter was added in Jinja2 2.7, which is newer than the version on RHEL/CentOS 6, +# so we skip this validation on those hosts +- name: ARCHIVE | Assert that archives were downloaded + assert: + that: (git_archive.results | map(attribute='changed') | unique | list)[0] + when: + - "ansible_os_family == 'RedHat'" + - ansible_distribution_major_version is version('7', '>=') + +- name: ARCHIVE | Check if archive file is created or not + stat: + path: '{{ checkout_dir }}/test_role.{{ item }}' + register: archive_check + with_items: "{{ git_archive_extensions[ansible_os_family ~ ansible_distribution_major_version | default('default') ] | default(git_archive_extensions.default) }}" + +- name: ARCHIVE | Assert that archive files exist + assert: + that: (archive_check.results | map(attribute='stat.exists') | unique | list)[0] + when: + - "ansible_os_family == 'RedHat'" + - ansible_distribution_major_version is version('7', '>=') + +- name: ARCHIVE | Inspect archive file + command: + cmd: "{{ git_list_commands[item] }} {{ checkout_dir }}/test_role.{{ item }}" + warn: no + register: archive_content + with_items: "{{ git_archive_extensions[ansible_os_family ~ ansible_distribution_major_version | default('default') ] | default(git_archive_extensions.default) }}" + +# Does not work on RedHat6 (jinja2 too old?) +- name: ARCHIVE | Ensure archive content is correct + assert: + that: + - item.stdout_lines | sort | first == 'defaults/' + with_items: "{{ archive_content.results }}" + when: + - ansible_os_family ~ ansible_distribution_major_version != 'RedHat6' + +- name: ARCHIVE | Clear checkout_dir + file: + state: absent + path: "{{ checkout_dir }}" + +- name: ARCHIVE | Generate an archive prefix + set_fact: + git_archive_prefix: '{{ range(2 ** 31, 2 ** 32) | random }}' # Generate some random archive prefix + +- name: ARCHIVE | Archive repo using various archival format and with an archive prefix + git: + repo: '{{ repo_format1 }}' + dest: '{{ checkout_dir }}' + archive: '{{ checkout_dir }}/test_role.{{ item }}' + archive_prefix: '{{ git_archive_prefix }}/' + register: git_archive + with_items: "{{ git_archive_extensions[ansible_os_family ~ ansible_distribution_major_version | default('default') ] | default(git_archive_extensions.default) }}" + +- name: ARCHIVE | Prepare the target for archive(s) extraction + file: + state: directory + path: '{{ checkout_dir }}/{{ git_archive_prefix }}.{{ item }}' + with_items: "{{ git_archive_extensions[ansible_os_family ~ ansible_distribution_major_version | default('default') ] | default(git_archive_extensions.default) }}" + +- name: ARCHIVE | Extract the archive(s) into that target + unarchive: + src: '{{ checkout_dir }}/test_role.{{ item }}' + dest: '{{ checkout_dir }}/{{ git_archive_prefix }}.{{ item }}' + with_items: "{{ git_archive_extensions[ansible_os_family ~ ansible_distribution_major_version | default('default') ] | default(git_archive_extensions.default) }}" + +- name: ARCHIVE | Check if prefix directory exists in what's extracted + find: + path: '{{ checkout_dir }}/{{ git_archive_prefix }}.{{ item }}' + patterns: '{{ git_archive_prefix }}' + file_type: directory + register: archive_check + with_items: "{{ git_archive_extensions[ansible_os_family ~ ansible_distribution_major_version | default('default') ] | default(git_archive_extensions.default) }}" + +- name: ARCHIVE | Assert that prefix directory is found + assert: + that: '{{ item.matched == 1 }}' + with_items: "{{ archive_check.results }}" diff --git a/test/integration/targets/git/tasks/change-repo-url.yml b/test/integration/targets/git/tasks/change-repo-url.yml new file mode 100644 index 00000000..b12fca1f --- /dev/null +++ b/test/integration/targets/git/tasks/change-repo-url.yml @@ -0,0 +1,132 @@ +# test change of repo url +# see https://github.com/ansible/ansible-modules-core/pull/721 + +- name: CHANGE-REPO-URL | clear checkout_dir + file: + state: absent + path: "{{ checkout_dir }}" + +- name: CHANGE-REPO-URL | Clone example git repo + git: + repo: "{{ repo_update_url_1 }}" + dest: "{{ checkout_dir }}" + +- name: CHANGE-REPO-URL | Clone repo with changed url to the same place + git: + repo: "{{ repo_update_url_2 }}" + dest: "{{ checkout_dir }}" + register: clone2 + +- assert: + that: "clone2 is successful" + +- name: CHANGE-REPO-URL | check url updated + shell: git remote show origin | grep Fetch + register: remote_url + args: + chdir: "{{ checkout_dir }}" + environment: + LC_ALL: C + +- assert: + that: + - "'git-test-new' in remote_url.stdout" + - "'git-test-old' not in remote_url.stdout" + +- name: CHANGE-REPO-URL | check for new content in git-test-new + stat: path={{ checkout_dir }}/newfilename + register: repo_content + +- name: CHANGE-REPO-URL | assert presence of new file in repo (i.e. working copy updated) + assert: + that: "repo_content.stat.exists" + +# Make sure 'changed' result is accurate in check mode. +# See https://github.com/ansible/ansible-modules-core/pull/4243 + +- name: CHANGE-REPO-URL | clear checkout_dir + file: + state: absent + path: "{{ checkout_dir }}" + +- name: CHANGE-REPO-URL | clone repo + git: + repo: "{{ repo_update_url_1 }}" + dest: "{{ checkout_dir }}" + +- name: CHANGE-REPO-URL | clone repo with same url to same destination + git: + repo: "{{ repo_update_url_1 }}" + dest: "{{ checkout_dir }}" + register: checkout_same_url + +- name: CHANGE-REPO-URL | check repo not changed + assert: + that: + - checkout_same_url is not changed + + +- name: CHANGE-REPO-URL | clone repo with new url to same destination + git: + repo: "{{ repo_update_url_2 }}" + dest: "{{ checkout_dir }}" + register: checkout_new_url + +- name: CHANGE-REPO-URL | check repo changed + assert: + that: + - checkout_new_url is changed + + +- name: CHANGE-REPO-URL | clone repo with new url in check mode + git: + repo: "{{ repo_update_url_1 }}" + dest: "{{ checkout_dir }}" + register: checkout_new_url_check_mode + check_mode: True + +- name: CHANGE-REPO-URL | check repo reported changed in check mode + assert: + that: + - checkout_new_url_check_mode is changed + when: git_version.stdout is version(git_version_supporting_ls_remote, '>=') + +- name: CHANGE-REPO-URL | clone repo with new url after check mode + git: + repo: "{{ repo_update_url_1 }}" + dest: "{{ checkout_dir }}" + register: checkout_new_url_after_check_mode + +- name: CHANGE-REPO-URL | check repo still changed after check mode + assert: + that: + - checkout_new_url_after_check_mode is changed + + +# Test that checkout by branch works when the branch is not in our current repo but the sha is + +- name: CHANGE-REPO-URL | clear checkout_dir + file: + state: absent + path: "{{ checkout_dir }}" + +- name: CHANGE-REPO-URL | "Clone example git repo that we're going to modify" + git: + repo: "{{ repo_update_url_1 }}" + dest: "{{ checkout_dir }}/repo" + +- name: CHANGE-REPO-URL | Clone the repo again - this is what we test + git: + repo: "{{ checkout_dir }}/repo" + dest: "{{ checkout_dir }}/checkout" + +- name: CHANGE-REPO-URL | Add a branch to the repo + command: git branch new-branch + args: + chdir: "{{ checkout_dir }}/repo" + +- name: CHANGE-REPO-URL | Checkout the new branch in the checkout + git: + repo: "{{ checkout_dir}}/repo" + version: 'new-branch' + dest: "{{ checkout_dir }}/checkout" diff --git a/test/integration/targets/git/tasks/checkout-new-tag.yml b/test/integration/targets/git/tasks/checkout-new-tag.yml new file mode 100644 index 00000000..eac73f67 --- /dev/null +++ b/test/integration/targets/git/tasks/checkout-new-tag.yml @@ -0,0 +1,54 @@ +# test for https://github.com/ansible/ansible-modules-core/issues/527 +# clone a repo, add a tag to the same commit and try to checkout the new commit + + +- name: clear checkout_dir + file: + state: absent + path: "{{ checkout_dir }}" + +- name: checkout example repo + git: + repo: "{{ repo_dir }}/format1" + dest: "{{ checkout_dir }}" + +- name: get tags of head + command: git tag --contains + args: + chdir: "{{ checkout_dir }}" + register: listoftags + +- name: make sure the tag does not yet exist + assert: + that: + - "'newtag' not in listoftags.stdout_lines" + +- name: add tag in orig repo + command: git tag newtag + args: + chdir: "{{ repo_dir }}/format1" + +- name: update copy with new tag + git: + repo: "{{ repo_dir }}/format1" + dest: "{{checkout_dir}}" + version: newtag + register: update_new_tag + +- name: get tags of new head + command: git tag --contains + args: + chdir: "{{ checkout_dir }}" + register: listoftags + +- name: check new head + assert: + that: + - update_new_tag is not changed + - "'newtag' in listoftags.stdout_lines" + + +- name: clear checkout_dir + file: + state: absent + path: "{{ checkout_dir }}" diff --git a/test/integration/targets/git/tasks/depth.yml b/test/integration/targets/git/tasks/depth.yml new file mode 100644 index 00000000..547f84f7 --- /dev/null +++ b/test/integration/targets/git/tasks/depth.yml @@ -0,0 +1,229 @@ +# Test the depth option and fetching revisions that were ignored first + +- name: DEPTH | clear checkout_dir + file: + state: absent + path: "{{ checkout_dir }}" + +- name: DEPTH | Clone example git repo with depth 1 + git: + repo: 'file://{{ repo_dir|expanduser }}/shallow' + dest: '{{ checkout_dir }}' + depth: 1 + +- name: DEPTH | try to access earlier commit + command: "git checkout {{git_shallow_head_1.stdout}}" + register: checkout_early + failed_when: False + args: + chdir: '{{ checkout_dir }}' + +- name: DEPTH | make sure the old commit was not fetched + assert: + that: 'checkout_early.rc != 0' + when: git_version.stdout is version(git_version_supporting_depth, '>=') + +# tests https://github.com/ansible/ansible/issues/14954 +- name: DEPTH | fetch repo again with depth=1 + git: + repo: 'file://{{ repo_dir|expanduser }}/shallow' + dest: '{{ checkout_dir }}' + depth: 1 + register: checkout2 + +- assert: + that: "checkout2 is not changed" + when: git_version.stdout is version(git_version_supporting_depth, '>=') + +- name: DEPTH | again try to access earlier commit + shell: "git checkout {{git_shallow_head_1.stdout}}" + register: checkout_early + failed_when: False + args: + chdir: '{{ checkout_dir }}' + +- name: DEPTH | again make sure the old commit was not fetched + assert: + that: 'checkout_early.rc != 0' + when: git_version.stdout is version(git_version_supporting_depth, '>=') + +# make sure we are still able to fetch other versions +- name: DEPTH | Clone same repo with older version + git: + repo: 'file://{{ repo_dir|expanduser }}/shallow' + dest: '{{ checkout_dir }}' + depth: 1 + version: earlytag + register: cloneold + +- assert: + that: cloneold is successful + +- name: DEPTH | try to access earlier commit + shell: "git checkout {{git_shallow_head_1.stdout}}" + args: + chdir: '{{ checkout_dir }}' + +- name: DEPTH | clear checkout_dir + file: + state: absent + path: "{{ checkout_dir }}" + +# Test for https://github.com/ansible/ansible/issues/21316 +- name: DEPTH | Shallow clone with tag + git: + repo: 'file://{{ repo_dir|expanduser }}/shallow' + dest: '{{ checkout_dir }}' + depth: 1 + version: earlytag + register: cloneold + +- assert: + that: cloneold is successful + +- name: DEPTH | clear checkout_dir + file: + state: absent + path: "{{ checkout_dir }}" + + + # Test for https://github.com/ansible/ansible-modules-core/issues/3456 + # clone a repo with depth and version specified + +- name: DEPTH | clone repo with both version and depth specified + git: + repo: 'file://{{ repo_dir|expanduser }}/shallow' + dest: '{{ checkout_dir }}' + depth: 1 + version: master + +- name: DEPTH | run a second time (now fetch, not clone) + git: + repo: 'file://{{ repo_dir|expanduser }}/shallow' + dest: '{{ checkout_dir }}' + depth: 1 + version: master + register: git_fetch + +- name: DEPTH | ensure the fetch succeeded + assert: + that: git_fetch is successful + + +- name: DEPTH | clear checkout_dir + file: + state: absent + path: "{{ checkout_dir }}" + +- name: DEPTH | clone repo with both version and depth specified + git: + repo: 'file://{{ repo_dir|expanduser }}/shallow' + dest: '{{ checkout_dir }}' + depth: 1 + version: master + +- name: DEPTH | switch to older branch with depth=1 (uses fetch) + git: + repo: 'file://{{ repo_dir|expanduser }}/shallow' + dest: '{{ checkout_dir }}' + depth: 1 + version: earlybranch + register: git_fetch + +- name: DEPTH | ensure the fetch succeeded + assert: + that: git_fetch is successful + +- name: DEPTH | clear checkout_dir + file: + state: absent + path: "{{ checkout_dir }}" + +# test for https://github.com/ansible/ansible-modules-core/issues/3782 +# make sure shallow fetch works when no version is specified + +- name: DEPTH | checkout old repo + git: + repo: 'file://{{ repo_dir|expanduser }}/shallow' + dest: '{{ checkout_dir }}' + depth: 1 + +- name: DEPTH | "update repo" + shell: echo "3" > a; git commit -a -m "3" + args: + chdir: "{{ repo_dir }}/shallow" + +- name: DEPTH | fetch updated repo + git: + repo: 'file://{{ repo_dir|expanduser }}/shallow' + dest: '{{ checkout_dir }}' + depth: 1 + register: git_fetch + ignore_errors: yes + +- name: DEPTH | get "a" file + slurp: + src: '{{ checkout_dir }}/a' + register: a_file + +- name: DEPTH | check update arrived + assert: + that: + - "{{ a_file.content | b64decode | trim }} == 3" + - git_fetch is changed + +- name: DEPTH | clear checkout_dir + file: + state: absent + path: "{{ checkout_dir }}" + +# +# Make sure shallow fetch works when switching to (fetching) a new a branch +# + +- name: DEPTH | clone from branch with depth specified + git: + repo: 'file://{{ repo_dir|expanduser }}/shallow_branches' + dest: '{{ checkout_dir }}' + depth: 1 + version: test_branch + +- name: DEPTH | check if clone is shallow + stat: path={{ checkout_dir }}/.git/shallow + register: is_shallow + when: git_version.stdout is version(git_version_supporting_depth, '>=') + +- name: DEPTH | assert that clone is shallow + assert: + that: + - is_shallow.stat.exists + when: git_version.stdout is version(git_version_supporting_depth, '>=') + +- name: DEPTH | switch to new branch (fetch) with the shallow clone + git: + repo: 'file://{{ repo_dir|expanduser }}/shallow_branches' + dest: '{{ checkout_dir }}' + depth: 1 + version: new_branch + register: git_fetch + +- name: DEPTH | assert if switching a shallow clone to a new branch worked + assert: + that: + - git_fetch is changed + +- name: DEPTH | check if clone is still shallow + stat: path={{ checkout_dir }}/.git/shallow + register: is_shallow + when: git_version.stdout is version(git_version_supporting_depth, '>=') + +- name: DEPTH | assert that clone still is shallow + assert: + that: + - is_shallow.stat.exists + when: git_version.stdout is version(git_version_supporting_depth, '>=') + +- name: DEPTH | clear checkout_dir + file: + state: absent + path: "{{ checkout_dir }}" diff --git a/test/integration/targets/git/tasks/forcefully-fetch-tag.yml b/test/integration/targets/git/tasks/forcefully-fetch-tag.yml new file mode 100644 index 00000000..47c37478 --- /dev/null +++ b/test/integration/targets/git/tasks/forcefully-fetch-tag.yml @@ -0,0 +1,38 @@ +# Tests against https://github.com/ansible/ansible/issues/67972 + +# Do our first clone manually; there are no commits yet and Ansible doesn't like +# that. +- name: FORCEFULLY-FETCH-TAG | Clone the bare repo in a non-bare clone + shell: git clone {{ repo_dir }}/tag_force_push {{ repo_dir }}/tag_force_push_clone1 + +- name: FORCEFULLY-FETCH-TAG | Prepare repo with a tag + shell: | + echo 1337 > leet; + git add leet; + git commit -m uh-oh; + git tag -f herewego; + git push --tags origin master + args: + chdir: "{{ repo_dir }}/tag_force_push_clone1" + +- name: FORCEFULLY-FETCH-TAG | clone the repo for the second time + git: + repo: "{{ repo_dir }}/tag_force_push" + dest: "{{ repo_dir }}/tag_force_push_clone2" + +- name: FORCEFULLY-FETCH-TAG | Forcefully overwrite the tag in clone1 + shell: | + echo 1338 > leet; + git add leet; + git commit -m uh-oh; + git tag -f herewego; + git push -f --tags origin master + args: + chdir: "{{ repo_dir }}/tag_force_push_clone1" + +- name: FORCEFULLY-FETCH-TAG | Try to update the second clone + git: + repo: "{{ repo_dir }}/tag_force_push" + dest: "{{ repo_dir }}/tag_force_push_clone2" + force: yes + register: git_res diff --git a/test/integration/targets/git/tasks/formats.yml b/test/integration/targets/git/tasks/formats.yml new file mode 100644 index 00000000..e5fcda72 --- /dev/null +++ b/test/integration/targets/git/tasks/formats.yml @@ -0,0 +1,40 @@ +- name: FORMATS | initial checkout + git: + repo: "{{ repo_format1 }}" + dest: "{{ repo_dir }}/format1" + register: git_result + +- name: FORMATS | verify information about the initial clone + assert: + that: + - "'before' in git_result" + - "'after' in git_result" + - "not git_result.before" + - "git_result.changed" + +- name: FORMATS | repeated checkout + git: + repo: "{{ repo_format1 }}" + dest: "{{ repo_dir }}/format1" + register: git_result2 + +- name: FORMATS | check for tags + stat: + path: "{{ repo_dir }}/format1/.git/refs/tags" + register: tags + +- name: FORMATS | check for HEAD + stat: + path: "{{ repo_dir }}/format1/.git/HEAD" + register: head + +- name: FORMATS | assert presence of tags/trunk/branches + assert: + that: + - "tags.stat.isdir" + - "head.stat.isreg" + +- name: FORMATS | verify on a reclone things are marked unchanged + assert: + that: + - "not git_result2.changed" diff --git a/test/integration/targets/git/tasks/gpg-verification.yml b/test/integration/targets/git/tasks/gpg-verification.yml new file mode 100644 index 00000000..8c8834a9 --- /dev/null +++ b/test/integration/targets/git/tasks/gpg-verification.yml @@ -0,0 +1,212 @@ +# Test for verification of GnuPG signatures + +- name: GPG-VERIFICATION | Create GnuPG verification workdir + tempfile: + state: directory + register: git_gpg_workdir + +- name: GPG-VERIFICATION | Define variables based on workdir + set_fact: + git_gpg_keyfile: "{{ git_gpg_workdir.path }}/testkey.asc" + git_gpg_source: "{{ git_gpg_workdir.path }}/source" + git_gpg_dest: "{{ git_gpg_workdir.path }}/dest" + git_gpg_gpghome: "{{ git_gpg_workdir.path }}/gpg" + +- name: GPG-VERIFICATION | Temporary store GnuPG test key + copy: + content: "{{ git_gpg_testkey }}" + dest: "{{ git_gpg_keyfile }}" + +- name: GPG-VERIFICATION | Create temporary GNUPGHOME directory + file: + path: "{{ git_gpg_gpghome }}" + state: directory + mode: 0700 + +- name: GPG-VERIFICATION | Import GnuPG test key + environment: + - GNUPGHOME: "{{ git_gpg_gpghome }}" + command: gpg --import {{ git_gpg_keyfile }} + +- name: GPG-VERIFICATION | Create local GnuPG signed repository directory + file: + path: "{{ git_gpg_source }}" + state: directory + +- name: GPG-VERIFICATION | Generate local GnuPG signed repository + environment: + - GNUPGHOME: "{{ git_gpg_gpghome }}" + shell: | + set -e + git init + touch an_empty_file + git add an_empty_file + git commit --no-gpg-sign --message "Commit, and don't sign" + git tag lightweight_tag/unsigned_commit HEAD + git commit --allow-empty --gpg-sign --message "Commit, and sign" + git tag lightweight_tag/signed_commit HEAD + git tag --annotate --message "This is not a signed tag" unsigned_annotated_tag HEAD + git commit --allow-empty --gpg-sign --message "Commit, and sign" + git tag --sign --message "This is a signed tag" signed_annotated_tag HEAD + git checkout -b some_branch/signed_tip master + git commit --allow-empty --gpg-sign --message "Commit, and sign" + git checkout -b another_branch/unsigned_tip master + git commit --allow-empty --no-gpg-sign --message "Commit, and don't sign" + git checkout master + args: + chdir: "{{ git_gpg_source }}" + +- name: GPG-VERIFICATION | Get hash of an unsigned commit + command: git show-ref --hash --verify refs/tags/lightweight_tag/unsigned_commit + args: + chdir: "{{ git_gpg_source }}" + register: git_gpg_unsigned_commit + +- name: GPG-VERIFICATION | Get hash of a signed commit + command: git show-ref --hash --verify refs/tags/lightweight_tag/signed_commit + args: + chdir: "{{ git_gpg_source }}" + register: git_gpg_signed_commit + +- name: GPG-VERIFICATION | Clone repo and verify signed HEAD + environment: + - GNUPGHOME: "{{ git_gpg_gpghome }}" + git: + repo: "{{ git_gpg_source }}" + dest: "{{ git_gpg_dest }}" + verify_commit: yes + when: + - git_version.stdout is version("2.1.0", '>=') + +- name: GPG-VERIFICATION | Clone repo and verify a signed lightweight tag + environment: + - GNUPGHOME: "{{ git_gpg_gpghome }}" + git: + repo: "{{ git_gpg_source }}" + dest: "{{ git_gpg_dest }}" + version: lightweight_tag/signed_commit + verify_commit: yes + when: + - git_version.stdout is version("2.1.0", '>=') + +- name: GPG-VERIFICATION | Clone repo and verify an unsigned lightweight tag (should fail) + environment: + - GNUPGHOME: "{{ git_gpg_gpghome }}" + git: + repo: "{{ git_gpg_source }}" + dest: "{{ git_gpg_dest }}" + version: lightweight_tag/unsigned_commit + verify_commit: yes + register: git_verify + ignore_errors: yes + when: + - git_version.stdout is version("2.1.0", '>=') + +- name: GPG-VERIFICATION | Check that unsigned lightweight tag verification failed + assert: + that: + - git_verify is failed + - git_verify.msg is match("Failed to verify GPG signature of commit/tag.+") + when: + - git_version.stdout is version("2.1.0", '>=') + +- name: GPG-VERIFICATION | Clone repo and verify a signed commit + environment: + - GNUPGHOME: "{{ git_gpg_gpghome }}" + git: + repo: "{{ git_gpg_source }}" + dest: "{{ git_gpg_dest }}" + version: "{{ git_gpg_signed_commit.stdout }}" + verify_commit: yes + when: + - git_version.stdout is version("2.1.0", '>=') + +- name: GPG-VERIFICATION | Clone repo and verify an unsigned commit + environment: + - GNUPGHOME: "{{ git_gpg_gpghome }}" + git: + repo: "{{ git_gpg_source }}" + dest: "{{ git_gpg_dest }}" + version: "{{ git_gpg_unsigned_commit.stdout }}" + verify_commit: yes + register: git_verify + ignore_errors: yes + when: + - git_version.stdout is version("2.1.0", '>=') + +- name: GPG-VERIFICATION | Check that unsigned commit verification failed + assert: + that: + - git_verify is failed + - git_verify.msg is match("Failed to verify GPG signature of commit/tag.+") + when: + - git_version.stdout is version("2.1.0", '>=') + +- name: GPG-VERIFICATION | Clone repo and verify a signed annotated tag + environment: + - GNUPGHOME: "{{ git_gpg_gpghome }}" + git: + repo: "{{ git_gpg_source }}" + dest: "{{ git_gpg_dest }}" + version: signed_annotated_tag + verify_commit: yes + +- name: GPG-VERIFICATION | Clone repo and verify an unsigned annotated tag (should fail) + environment: + - GNUPGHOME: "{{ git_gpg_gpghome }}" + git: + repo: "{{ git_gpg_source }}" + dest: "{{ git_gpg_dest }}" + version: unsigned_annotated_tag + verify_commit: yes + register: git_verify + ignore_errors: yes + +- name: GPG-VERIFICATION | Check that unsigned annotated tag verification failed + assert: + that: + - git_verify is failed + - git_verify.msg is match("Failed to verify GPG signature of commit/tag.+") + +- name: GPG-VERIFICATION | Clone repo and verify a signed branch + environment: + - GNUPGHOME: "{{ git_gpg_gpghome }}" + git: + repo: "{{ git_gpg_source }}" + dest: "{{ git_gpg_dest }}" + version: some_branch/signed_tip + verify_commit: yes + when: + - git_version.stdout is version("2.1.0", '>=') + +- name: GPG-VERIFICATION | Clone repo and verify an unsigned branch (should fail) + environment: + - GNUPGHOME: "{{ git_gpg_gpghome }}" + git: + repo: "{{ git_gpg_source }}" + dest: "{{ git_gpg_dest }}" + version: another_branch/unsigned_tip + verify_commit: yes + register: git_verify + ignore_errors: yes + when: + - git_version.stdout is version("2.1.0", '>=') + +- name: GPG-VERIFICATION | Check that unsigned branch verification failed + assert: + that: + - git_verify is failed + - git_verify.msg is match("Failed to verify GPG signature of commit/tag.+") + when: + - git_version.stdout is version("2.1.0", '>=') + +- name: GPG-VERIFICATION | Stop gpg-agent so we can remove any locks on the GnuPG dir + command: gpgconf --kill gpg-agent + environment: + GNUPGHOME: "{{ git_gpg_gpghome }}" + ignore_errors: yes + +- name: GPG-VERIFICATION | Remove GnuPG verification workdir + file: + path: "{{ git_gpg_workdir.path }}" + state: absent diff --git a/test/integration/targets/git/tasks/localmods.yml b/test/integration/targets/git/tasks/localmods.yml new file mode 100644 index 00000000..09a1326d --- /dev/null +++ b/test/integration/targets/git/tasks/localmods.yml @@ -0,0 +1,112 @@ +# test for https://github.com/ansible/ansible-modules-core/pull/5505 +- name: LOCALMODS | prepare old git repo + shell: rm -rf localmods; mkdir localmods; cd localmods; git init; echo "1" > a; git add a; git commit -m "1" + args: + chdir: "{{repo_dir}}" + +- name: LOCALMODS | checkout old repo + git: + repo: '{{ repo_dir }}/localmods' + dest: '{{ checkout_dir }}' + +- name: LOCALMODS | "update repo" + shell: echo "2" > a; git commit -a -m "2" + args: + chdir: "{{repo_dir}}/localmods" + +- name: LOCALMODS | "add local mods" + shell: echo "3" > a + args: + chdir: "{{ checkout_dir }}" + +- name: LOCALMODS | fetch with local mods without force (should fail) + git: + repo: '{{ repo_dir }}/localmods' + dest: '{{ checkout_dir }}' + register: git_fetch + ignore_errors: yes + +- name: LOCALMODS | check fetch with localmods failed + assert: + that: + - git_fetch is failed + +- name: LOCALMODS | fetch with local mods with force + git: + repo: '{{ repo_dir }}/localmods' + dest: '{{ checkout_dir }}' + force: True + register: git_fetch_force + ignore_errors: yes + +- name: LOCALMODS | get "a" file + slurp: + src: '{{ checkout_dir }}/a' + register: a_file + +- name: LOCALMODS | check update arrived + assert: + that: + - "{{ a_file.content | b64decode | trim }} == 2" + - git_fetch_force is changed + +- name: LOCALMODS | clear checkout_dir + file: state=absent path={{ checkout_dir }} + +# localmods and shallow clone +- name: LOCALMODS | prepare old git repo + shell: rm -rf localmods; mkdir localmods; cd localmods; git init; echo "1" > a; git add a; git commit -m "1" + args: + chdir: "{{repo_dir}}" + +- name: LOCALMODS | checkout old repo + git: + repo: '{{ repo_dir }}/localmods' + dest: '{{ checkout_dir }}' + depth: 1 + +- name: LOCALMODS | "update repo" + shell: echo "2" > a; git commit -a -m "2" + args: + chdir: "{{repo_dir}}/localmods" + +- name: LOCALMODS | "add local mods" + shell: echo "3" > a + args: + chdir: "{{ checkout_dir }}" + +- name: LOCALMODS | fetch with local mods without force (should fail) + git: + repo: '{{ repo_dir }}/localmods' + dest: '{{ checkout_dir }}' + depth: 1 + register: git_fetch + ignore_errors: yes + +- name: LOCALMODS | check fetch with localmods failed + assert: + that: + - git_fetch is failed + +- name: LOCALMODS | fetch with local mods with force + git: + repo: '{{ repo_dir }}/localmods' + dest: '{{ checkout_dir }}' + depth: 1 + force: True + register: git_fetch_force + ignore_errors: yes + +- name: LOCALMODS | get "a" file + slurp: + src: '{{ checkout_dir }}/a' + register: a_file + +- name: LOCALMODS | check update arrived + assert: + that: + - "{{ a_file.content | b64decode | trim }} == 2" + - git_fetch_force is changed + +- name: LOCALMODS | clear checkout_dir + file: state=absent path={{ checkout_dir }} diff --git a/test/integration/targets/git/tasks/main.yml b/test/integration/targets/git/tasks/main.yml new file mode 100644 index 00000000..722713bf --- /dev/null +++ b/test/integration/targets/git/tasks/main.yml @@ -0,0 +1,40 @@ +# test code for the git module +# (c) 2014, James Tanner + +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +- include_tasks: setup.yml +- include_tasks: setup-local-repos.yml + +- include_tasks: formats.yml +- include_tasks: missing_hostkey.yml +- include_tasks: no-destination.yml +- include_tasks: specific-revision.yml +- include_tasks: submodules.yml +- include_tasks: change-repo-url.yml +- include_tasks: depth.yml +- include_tasks: checkout-new-tag.yml +- include_tasks: gpg-verification.yml + when: + - not gpg_version.stderr + - gpg_version.stdout + - not (ansible_os_family == 'RedHat' and ansible_distribution_major_version is version('7', '<')) +- include_tasks: localmods.yml +- include_tasks: reset-origin.yml +- include_tasks: ambiguous-ref.yml +- include_tasks: archive.yml +- include_tasks: separate-git-dir.yml +- include_tasks: forcefully-fetch-tag.yml diff --git a/test/integration/targets/git/tasks/missing_hostkey.yml b/test/integration/targets/git/tasks/missing_hostkey.yml new file mode 100644 index 00000000..02d5be35 --- /dev/null +++ b/test/integration/targets/git/tasks/missing_hostkey.yml @@ -0,0 +1,48 @@ +- name: MISSING-HOSTKEY | checkout ssh://git@github.com repo without accept_hostkey (expected fail) + git: + repo: '{{ repo_format2 }}' + dest: '{{ checkout_dir }}' + ssh_opts: '-o UserKnownHostsFile={{ output_dir }}/known_hosts' + register: git_result + ignore_errors: true + +- assert: + that: + - git_result is failed + +- name: MISSING-HOSTKEY | checkout git@github.com repo with accept_hostkey (expected pass) + git: + repo: '{{ repo_format2 }}' + dest: '{{ checkout_dir }}' + accept_hostkey: true + key_file: '{{ github_ssh_private_key }}' + ssh_opts: '-o UserKnownHostsFile={{ output_dir }}/known_hosts' + register: git_result + when: github_ssh_private_key is defined + +- assert: + that: + - git_result is changed + when: github_ssh_private_key is defined + +- name: MISSING-HOSTKEY | clear checkout_dir + file: + state: absent + path: '{{ checkout_dir }}' + when: github_ssh_private_key is defined + +- name: MISSING-HOSTKEY | checkout ssh://git@github.com repo with accept_hostkey (expected pass) + git: + repo: '{{ repo_format3 }}' + dest: '{{ checkout_dir }}' + version: 'master' + accept_hostkey: false # should already have been accepted + key_file: '{{ github_ssh_private_key }}' + ssh_opts: '-o UserKnownHostsFile={{ output_dir }}/known_hosts' + register: git_result + when: github_ssh_private_key is defined + +- assert: + that: + - git_result is changed + when: github_ssh_private_key is defined diff --git a/test/integration/targets/git/tasks/no-destination.yml b/test/integration/targets/git/tasks/no-destination.yml new file mode 100644 index 00000000..1ef7f2fd --- /dev/null +++ b/test/integration/targets/git/tasks/no-destination.yml @@ -0,0 +1,13 @@ +# Test a non-updating repo query with no destination specified + +- name: NO-DESTINATION | get info on a repo without updating and with no destination specified + git: + repo: '{{ repo_dir }}/minimal' + update: no + clone: no + accept_hostkey: yes + register: git_result + +- assert: + that: + - git_result is changed diff --git a/test/integration/targets/git/tasks/reset-origin.yml b/test/integration/targets/git/tasks/reset-origin.yml new file mode 100644 index 00000000..8fddd4b1 --- /dev/null +++ b/test/integration/targets/git/tasks/reset-origin.yml @@ -0,0 +1,25 @@ +- name: RESET-ORIGIN | Clean up the directories + file: + state: absent + path: "{{ item }}" + with_items: + - "{{ repo_dir }}/origin" + - "{{ checkout_dir }}" + +- name: RESET-ORIGIN | Create a directory + file: + name: "{{ repo_dir }}/origin" + state: directory + +- name: RESET-ORIGIN | Initialise the repo with a file named origin,see github.com/ansible/ansible/pull/22502 + shell: git init; echo "PR 22502" > origin; git add origin; git commit -m "PR 22502" + args: + chdir: "{{ repo_dir }}/origin" + +- name: RESET-ORIGIN | Clone a git repo with file named origin + git: + repo: "{{ repo_dir }}/origin" + dest: "{{ checkout_dir }}" + remote: origin + update: no + register: status diff --git a/test/integration/targets/git/tasks/separate-git-dir.yml b/test/integration/targets/git/tasks/separate-git-dir.yml new file mode 100644 index 00000000..5b874043 --- /dev/null +++ b/test/integration/targets/git/tasks/separate-git-dir.yml @@ -0,0 +1,132 @@ +# test code for repositories with separate git dir updating +# see https://github.com/ansible/ansible/pull/38016 +# see https://github.com/ansible/ansible/issues/30034 + +- name: SEPARATE-GIT-DIR | clear checkout_dir + file: + state: absent + path: '{{ checkout_dir }}' + +- name: SEPARATE-GIT-DIR | make a pre-exist repo dir + file: + state: directory + path: '{{ separate_git_dir }}' + +- name: SEPARATE-GIT-DIR | clone with a separate git dir + git: + repo: '{{ repo_format1 }}' + dest: '{{ checkout_dir }}' + separate_git_dir: '{{ separate_git_dir }}' + ignore_errors: yes + register: result + +- name: SEPARATE-GIT-DIR | the clone will fail due to pre-exist dir + assert: + that: 'result is failed' + +- name: SEPARATE-GIT-DIR | delete pre-exist dir + file: + state: absent + path: '{{ separate_git_dir }}' + +- name: SEPARATE-GIT-DIR | clone again with a separate git dir + git: + repo: '{{ repo_format1 }}' + dest: '{{ checkout_dir }}' + separate_git_dir: '{{ separate_git_dir }}' + +- name: SEPARATE-GIT-DIR | check the stat of git dir + stat: + path: '{{ separate_git_dir }}' + register: stat_result + +- name: SEPARATE-GIT-DIR | the git dir should exist + assert: + that: 'stat_result.stat.exists == True' + +- name: SEPARATE-GIT-DIR | update repo the usual way + git: + repo: '{{ repo_format1 }}' + dest: '{{ checkout_dir }}' + separate_git_dir: '{{ separate_git_dir }}' + register: result + +- name: SEPARATE-GIT-DIR | update should not fail + assert: + that: + - result is not failed + +- name: SEPARATE-GIT-DIR | move the git dir to new place + git: + repo: '{{ repo_format1 }}' + dest: '{{ checkout_dir }}' + separate_git_dir: '{{ separate_git_dir }}_new' + register: result + +- name: SEPARATE-GIT-DIR | the movement should not failed + assert: + that: 'result is not failed' + +- name: SEPARATE-GIT-DIR | check the stat of new git dir + stat: + path: '{{ separate_git_dir }}_new' + register: stat_result + +- name: SEPARATE-GIT-DIR | the new git dir should exist + assert: + that: 'stat_result.stat.exists == True' + +- name: SEPARATE-GIT-DIR | test the update + git: + repo: '{{ repo_format1 }}' + dest: '{{ checkout_dir }}' + register: result + +- name: SEPARATE-GIT-DIR | the update should not failed + assert: + that: + - result is not failed + +- name: SEPARATE-GIT-DIR | set git dir to non-existent dir + shell: "echo gitdir: /dev/null/non-existent-dir > .git" + args: + chdir: "{{ checkout_dir }}" + +- name: SEPARATE-GIT-DIR | update repo the usual way + git: + repo: "{{ repo_format1 }}" + dest: "{{ checkout_dir }}" + ignore_errors: yes + register: result + +- name: SEPARATE-GIT-DIR | check update has failed + assert: + that: + - result is failed + +- name: SEPARATE-GIT-DIR | set .git file to bad format + shell: "echo some text gitdir: {{ checkout_dir }} > .git" + args: + chdir: "{{ checkout_dir }}" + +- name: SEPARATE-GIT-DIR | update repo the usual way + git: + repo: "{{ repo_format1 }}" + dest: "{{ checkout_dir }}" + ignore_errors: yes + register: result + +- name: SEPARATE-GIT-DIR | check update has failed + assert: + that: + - result is failed + +- name: SEPARATE-GIT-DIR | clear separate git dir + file: + state: absent + path: "{{ separate_git_dir }}_new" + +- name: SEPARATE-GIT-DIR | clear checkout_dir + file: + state: absent + path: '{{ checkout_dir }}' diff --git a/test/integration/targets/git/tasks/setup-local-repos.yml b/test/integration/targets/git/tasks/setup-local-repos.yml new file mode 100644 index 00000000..584a1693 --- /dev/null +++ b/test/integration/targets/git/tasks/setup-local-repos.yml @@ -0,0 +1,45 @@ +- name: SETUP-LOCAL-REPOS | create dirs + file: + name: "{{ item }}" + state: directory + with_items: + - "{{ repo_dir }}/minimal" + - "{{ repo_dir }}/shallow" + - "{{ repo_dir }}/shallow_branches" + - "{{ repo_dir }}/tag_force_push" + +- name: SETUP-LOCAL-REPOS | prepare minimal git repo + shell: git init; echo "1" > a; git add a; git commit -m "1" + args: + chdir: "{{ repo_dir }}/minimal" + +- name: SETUP-LOCAL-REPOS | prepare git repo for shallow clone + shell: | + git init; + echo "1" > a; git add a; git commit -m "1"; git tag earlytag; git branch earlybranch; + echo "2" > a; git add a; git commit -m "2"; + args: + chdir: "{{ repo_dir }}/shallow" + +- name: SETUP-LOCAL-REPOS | set old hash var for shallow test + command: 'git rev-parse HEAD~1' + register: git_shallow_head_1 + args: + chdir: "{{ repo_dir }}/shallow" + +- name: SETUP-LOCAL-REPOS | prepare tmp git repo with two branches + shell: | + git init + echo "1" > a; git add a; git commit -m "1" + git checkout -b test_branch; echo "2" > a; git commit -m "2 on branch" a + git checkout -b new_branch; echo "3" > a; git commit -m "3 on new branch" a + args: + chdir: "{{ repo_dir }}/shallow_branches" + +# Make this a bare one, we need to be able to push to it from clones +# We make the repo here for consistency with the other repos, +# but we finish setting it up in forcefully-fetch-tag.yml. +- name: SETUP-LOCAL-REPOS | prepare tag_force_push git repo + shell: git init --bare + args: + chdir: "{{ repo_dir }}/tag_force_push" diff --git a/test/integration/targets/git/tasks/setup.yml b/test/integration/targets/git/tasks/setup.yml new file mode 100644 index 00000000..16c56904 --- /dev/null +++ b/test/integration/targets/git/tasks/setup.yml @@ -0,0 +1,43 @@ +- name: SETUP | clean out the output_dir + file: + path: "{{ output_dir }}" + state: absent + +- name: SETUP | create clean output_dir + file: + path: "{{ output_dir }}" + state: directory + +- name: SETUP | install git + package: + name: '{{ item }}' + when: ansible_distribution != "MacOSX" + notify: + - cleanup + with_items: "{{ git_required_packages[ansible_os_family | default('default') ] | default(git_required_packages.default) }}" + +- name: SETUP | verify that git is installed so this test can continue + shell: which git + +- name: SETUP | get git version, only newer than {{git_version_supporting_depth}} has fixed git depth + shell: git --version | grep 'git version' | sed 's/git version //' + register: git_version + +- name: SETUP | get gpg version + shell: gpg --version 2>1 | head -1 | sed -e 's/gpg (GnuPG) //' + register: gpg_version + +- name: SETUP | set git global user.email if not already set + shell: git config --global user.email || git config --global user.email "noreply@example.com" + +- name: SETUP | set git global user.name if not already set + shell: git config --global user.name || git config --global user.name "Ansible Test Runner" + +- name: SETUP | create repo_dir + file: + path: "{{ repo_dir }}" + state: directory + +- name: SETUP | show git version + debug: + msg: "Running test with git {{ git_version.stdout }}" diff --git a/test/integration/targets/git/tasks/specific-revision.yml b/test/integration/targets/git/tasks/specific-revision.yml new file mode 100644 index 00000000..26fa7cf3 --- /dev/null +++ b/test/integration/targets/git/tasks/specific-revision.yml @@ -0,0 +1,238 @@ +# Test that a specific revision can be checked out + +- name: SPECIFIC-REVISION | clear checkout_dir + file: + state: absent + path: '{{ checkout_dir }}' + +- name: SPECIFIC-REVISION | clone to specific revision + git: + repo: "{{ repo_dir }}/format1" + dest: "{{ checkout_dir }}" + version: df4612ba925fbc1b3c51cbb006f51a0443bd2ce9 + +- name: SPECIFIC-REVISION | check HEAD after clone to revision + command: git rev-parse HEAD + args: + chdir: "{{ checkout_dir }}" + register: git_result + +- assert: + that: + - 'git_result.stdout == "df4612ba925fbc1b3c51cbb006f51a0443bd2ce9"' + +- name: SPECIFIC-REVISION | update to specific revision + git: + repo: "{{ repo_dir }}/format1" + dest: "{{ checkout_dir }}" + version: 4e739a34719654db7b04896966e2354e1256ea5d + register: git_result + +- assert: + that: + - git_result is changed + +- name: SPECIFIC-REVISION | check HEAD after update to revision + command: git rev-parse HEAD + args: + chdir: "{{ checkout_dir }}" + register: git_result + +- assert: + that: + - 'git_result.stdout == "4e739a34719654db7b04896966e2354e1256ea5d"' + +- name: SPECIFIC-REVISION | update to HEAD from detached HEAD state + git: + repo: "{{ repo_dir }}/format1" + dest: "{{ checkout_dir }}" + version: HEAD + register: git_result + +- assert: + that: + - git_result is changed + +# Test a revision not available under refs/heads/ or refs/tags/ + +- name: SPECIFIC-REVISION | attempt to get unavailable revision + git: + repo: "{{ repo_dir }}/format1" + dest: "{{ checkout_dir }}" + version: 5473e343e33255f2da0b160f53135c56921d875c + ignore_errors: true + register: git_result + +- assert: + that: + - git_result is failed + +# Same as the previous test, but this time we specify which ref +# contains the SHA1 +- name: SPECIFIC-REVISION | update to revision by specifying the refspec + git: + repo: https://github.com/ansible/ansible-examples.git + dest: '{{ checkout_dir }}' + version: 5473e343e33255f2da0b160f53135c56921d875c + refspec: refs/pull/7/merge + +- name: SPECIFIC-REVISION | check HEAD after update with refspec + command: git rev-parse HEAD + args: + chdir: "{{ checkout_dir }}" + register: git_result + +- assert: + that: + - 'git_result.stdout == "5473e343e33255f2da0b160f53135c56921d875c"' + +# try out combination of refspec and depth +- name: SPECIFIC-REVISION | clear checkout_dir + file: + state: absent + path: "{{ checkout_dir }}" + +- name: SPECIFIC-REVISION | update to revision by specifying the refspec with depth=1 + git: + repo: https://github.com/ansible/ansible-examples.git + dest: '{{ checkout_dir }}' + version: 5473e343e33255f2da0b160f53135c56921d875c + refspec: refs/pull/7/merge + depth: 1 + +- name: SPECIFIC-REVISION | check HEAD after update with refspec + command: git rev-parse HEAD + args: + chdir: "{{ checkout_dir }}" + register: git_result + +- assert: + that: + - 'git_result.stdout == "5473e343e33255f2da0b160f53135c56921d875c"' + +- name: SPECIFIC-REVISION | try to access other commit + shell: git checkout 0ce1096 + register: checkout_shallow + failed_when: False + args: + chdir: "{{ checkout_dir }}" + +- name: SPECIFIC-REVISION | "make sure the old commit was not fetched, task is 'forced success'" + assert: + that: + - checkout_shallow.rc != 0 + - checkout_shallow is successful + when: git_version.stdout is version(git_version_supporting_depth, '>=') + +- name: SPECIFIC-REVISION | clear checkout_dir + file: + state: absent + path: "{{ checkout_dir }}" + +- name: SPECIFIC-REVISION | clone to revision by specifying the refspec + git: + repo: https://github.com/ansible/ansible-examples.git + dest: "{{ checkout_dir }}" + version: 5473e343e33255f2da0b160f53135c56921d875c + refspec: refs/pull/7/merge + +- name: SPECIFIC-REVISION | check HEAD after update with refspec + command: git rev-parse HEAD + args: + chdir: "{{ checkout_dir }}" + register: git_result + +- assert: + that: + - 'git_result.stdout == "5473e343e33255f2da0b160f53135c56921d875c"' + +# Test that a forced shallow checkout referincing branch only always fetches latest head + +- name: SPECIFIC-REVISION | clear checkout_dir + file: + state: absent + path: "{{ item }}" + with_items: + - "{{ checkout_dir }}" + - "{{ checkout_dir }}.copy" + +- name: SPECIFIC-REVISION | create original repo dir + file: + state: directory + path: "{{ checkout_dir }}" + +- name: SPECIFIC-REVISION | prepare origina repo + shell: git init; echo "1" > a; git add a; git commit -m "1" + args: + chdir: "{{ checkout_dir }}" + +- name: SPECIFIC-REVISION | clone example repo locally + git: + repo: "{{ checkout_dir }}" + dest: "{{ checkout_dir }}.copy" + +- name: SPECIFIC-REVISION | create branch in original + command: git checkout -b test/branch + args: + chdir: "{{ checkout_dir }}" + +- name: SPECIFIC-REVISION | get commit for HEAD on new branch + command: git rev-parse HEAD + args: + chdir: "{{ checkout_dir }}.copy" + register: originaltip0 + +- name: SPECIFIC-REVISION | shallow force checkout new branch in copy + git: + repo: "{{ checkout_dir }}" + dest: "{{ checkout_dir }}.copy" + version: test/branch + depth: 1 + force: yes + +- name: SPECIFIC-REVISION | create new commit in original + shell: git init; echo "2" > b; git add b; git commit -m "2" + args: + chdir: "{{ checkout_dir }}" + +- name: SPECIFIC-REVISION | get commit for new HEAD on original branch + command: git rev-parse HEAD + args: + chdir: "{{ checkout_dir }}" + register: originaltip1 + +- name: SPECIFIC-REVISION | get commit for HEAD on new branch + command: git rev-parse HEAD + args: + chdir: "{{ checkout_dir }}.copy" + register: newtip + +- name: SPECIFIC-REVISION | assert that copy is still pointing at previous tip + assert: + that: + - newtip.stdout == originaltip0.stdout + +- name: SPECIFIC-REVISION | create a local modification in the copy + shell: echo "3" > c + args: + chdir: "{{ checkout_dir }}.copy" + +- name: SPECIFIC-REVISION | shallow force checkout new branch in copy (again) + git: + repo: "{{ checkout_dir }}" + dest: "{{ checkout_dir }}.copy" + version: test/branch + depth: 1 + force: yes + +- name: SPECIFIC-REVISION | get commit for HEAD on new branch + command: git rev-parse HEAD + args: + chdir: "{{ checkout_dir }}.copy" + register: newtip + +- name: SPECIFIC-REVISION | make sure copy tip is not pointing at previous sha and that new tips match + assert: + that: + - newtip.stdout != originaltip0.stdout + - newtip.stdout == originaltip1.stdout diff --git a/test/integration/targets/git/tasks/submodules.yml b/test/integration/targets/git/tasks/submodules.yml new file mode 100644 index 00000000..647d1e23 --- /dev/null +++ b/test/integration/targets/git/tasks/submodules.yml @@ -0,0 +1,124 @@ +# +# Submodule tests +# + +# Repository A with submodules defined (repo_submodules) +# .gitmodules file points to Repository I +# Repository B forked from A that has newer commits (repo_submodules_newer) +# .gitmodules file points to Repository II instead of I +# .gitmodules file also points to Repository III +# Repository I for submodule1 (repo_submodule1) +# Has 1 file checked in +# Repository II forked from I that has newer commits (repo_submodule1_newer) +# Has 2 files checked in +# Repository III for a second submodule (repo_submodule2) +# Has 1 file checked in + +- name: SUBMODULES | clear checkout_dir + file: + state: absent + path: "{{ checkout_dir }}" + +- name: SUBMODULES | Test that clone without recursive does not retrieve submodules + git: + repo: "{{ repo_submodules }}" + version: 45c6c07ef10fd9e453d90207e63da1ce5bd3ae1e + dest: "{{ checkout_dir }}" + recursive: no + +- name: SUBMODULES | List submodule1 + command: 'ls -1a {{ checkout_dir }}/submodule1' + register: submodule1 + +- name: SUBMODULES | Ensure submodu1 is at the appropriate commit + assert: + that: '{{ submodule1.stdout_lines | length }} == 2' + +- name: SUBMODULES | clear checkout_dir + file: + state: absent + path: "{{ checkout_dir }}" + + +- name: SUBMODULES | Test that clone with recursive retrieves submodules + git: + repo: "{{ repo_submodules }}" + dest: "{{ checkout_dir }}" + version: 45c6c07ef10fd9e453d90207e63da1ce5bd3ae1e + recursive: yes + +- name: SUBMODULES | List submodule1 + command: 'ls -1a {{ checkout_dir }}/submodule1' + register: submodule1 + +- name: SUBMODULES | Ensure submodule1 is at the appropriate commit + assert: + that: '{{ submodule1.stdout_lines | length }} == 4' + +- name: SUBMODULES | Copy the checkout so we can run several different tests on it + command: 'cp -pr {{ checkout_dir }} {{ checkout_dir }}.bak' + + +- name: SUBMODULES | Test that update without recursive does not change submodules + git: + repo: "{{ repo_submodules }}" + version: d2974e4bbccdb59368f1d5eff2205f0fa863297e + dest: "{{ checkout_dir }}" + recursive: no + update: yes + track_submodules: yes + +- name: SUBMODULES | List submodule1 + command: 'ls -1a {{ checkout_dir }}/submodule1' + register: submodule1 + +- name: SUBMODULES | Stat submodule2 + stat: + path: "{{ checkout_dir }}/submodule2" + register: submodule2 + +- name: SUBMODULES | List submodule2 + command: ls -1a {{ checkout_dir }}/submodule2 + register: submodule2 + +- name: SUBMODULES | Ensure both submodules are at the appropriate commit + assert: + that: + - '{{ submodule1.stdout_lines|length }} == 4' + - '{{ submodule2.stdout_lines|length }} == 2' + + +- name: SUBMODULES | Remove checkout dir + file: + state: absent + path: "{{ checkout_dir }}" + +- name: SUBMODULES | Restore checkout to prior state + command: 'cp -pr {{ checkout_dir }}.bak {{ checkout_dir }}' + + +- name: SUBMODULES | Test that update with recursive updated existing submodules + git: + repo: "{{ repo_submodules }}" + version: d2974e4bbccdb59368f1d5eff2205f0fa863297e + dest: "{{ checkout_dir }}" + update: yes + recursive: yes + track_submodules: yes + +- name: SUBMODULES | List submodule 1 + command: 'ls -1a {{ checkout_dir }}/submodule1' + register: submodule1 + +- name: SUBMODULES | Ensure submodule1 is at the appropriate commit + assert: + that: '{{ submodule1.stdout_lines | length }} == 5' + + +- name: SUBMODULES | Test that update with recursive found new submodules + command: 'ls -1a {{ checkout_dir }}/submodule2' + register: submodule2 + +- name: SUBMODULES | Enusre submodule2 is at the appropriate commit + assert: + that: '{{ submodule2.stdout_lines | length }} == 4' diff --git a/test/integration/targets/git/vars/main.yml b/test/integration/targets/git/vars/main.yml new file mode 100644 index 00000000..a5bae5ba --- /dev/null +++ b/test/integration/targets/git/vars/main.yml @@ -0,0 +1,97 @@ +git_archive_extensions: + default: + - tar.gz + - tar + - tgz + - zip + RedHat6: + - tar + - zip + +git_required_packages: + default: + - git + - gzip + - tar + - unzip + - zip + FreeBSD: + - git + - gzip + - unzip + - zip + +git_list_commands: + tar.gz: tar -tf + tar: tar -tf + tgz: tar -tf + zip: unzip -Z1 + +checkout_dir: '{{ output_dir }}/git' +repo_dir: '{{ output_dir }}/local_repos' +separate_git_dir: '{{ output_dir }}/sep_git_dir' +repo_format1: 'https://github.com/jimi-c/test_role' +repo_format2: 'git@github.com:jimi-c/test_role.git' +repo_format3: 'ssh://git@github.com/jimi-c/test_role.git' +repo_submodules: 'https://github.com/abadger/test_submodules_newer.git' +repo_submodule1: 'https://github.com/abadger/test_submodules_subm1.git' +repo_submodule2: 'https://github.com/abadger/test_submodules_subm2.git' +repo_update_url_1: 'https://github.com/ansible-test-robinro/git-test-old' +repo_update_url_2: 'https://github.com/ansible-test-robinro/git-test-new' +known_host_files: + - "{{ lookup('env','HOME') }}/.ssh/known_hosts" + - '/etc/ssh/ssh_known_hosts' +git_version_supporting_depth: 1.9.1 +git_version_supporting_ls_remote: 1.7.5 +# path to a SSH private key for use with github.com (tests skipped if undefined) +# github_ssh_private_key: "{{ lookup('env', 'HOME') }}/.ssh/id_rsa" +git_gpg_testkey: | + -----BEGIN PGP PRIVATE KEY BLOCK----- + + lQOYBFlkmX0BCACtE81Xj/351nnvwnAWMf8ZUP9B1YOPe9ohqNsCQY1DxODVJc9y + ljCoh9fTdoHXuaUMUFistozxCMP81RuZxfbfsGePnl8OAOgWT5Sln6yEG45oClJ0 + RmJJZdDT1lF3VaVwK9NQ5E1oqmk1IOjISi7iFa9TmMn1h7ISP/p+/xtMxQhzUXt8 + APAEhRdc9FfwxaxCHKZBiM7ND+pAm6vpom07ZUgxSppsrXZAxDncTwAeCumDpeOL + LAcSBsw02swOIHFfqHNrkELLr4KJqws+zeAk6R2nq0k16AVdNX+Rb7T3OKmuLawx + HXe8rKpaw0RC+JCogZK4tz0KDNuZPLW2Y5JJABEBAAEAB/4zkKpFk79p35YNskLd + wgCMRN7/+MKNDavUCnBRsEELt0z7BBxVudx+YZaSSITvxj4fuJJqxqqgJ2no2n8y + JdJjG7YHCnqse+WpvAUAAV4PL/ySD704Kj4fOwfoDTrRUIGNNWlseNB9RgQ5UXg5 + MCzeq/JD+En3bnnFySzzCENUcAQfu2FVYgKEiKaKL5Djs6p5w/jTm+Let3EsIczb + ykJ8D4/G/tSrNdp/g10DDy+VclWMhMFqmFesedvytE8jzCVxPKOoRkFTGrX76gIK + eMVxHIYxdCfSTHLjBykMGO9gxfk9lf18roNYs0VV2suyi4fVFxEozSAxwWlwKrXn + 0arvBADPsm5NjlZ5uR06YKbpUUwPTYcwLbasic0qHuUWgNsTVv8dd2il/jbha77m + StU7qRJ1jwbFEFxx7HnTmeGfPbdyKe2qyLJUyD/rpQSC5YirisUchtG8nZsHlnzn + k10SIeB480tkgkdMQx1Eif40aiuQb09/TxaaXAEFKttZhEO4RwQA1VQ8a0IrMBI2 + i4WqaIDNDl3x61JvvFD74v43I0AHKmZUPwcgAd6q2IvCDaKH0hIuBKu6BGq6DPvx + Oc/4r3iRn/xccconxRop2A9ffa00B/eQXrBq+uLBQfyiFL9UfkU8eTAAgbDKRxjY + ScaevoBbbYxkpgJUCL6VnoSdXlbNOO8EAL2ypsVkDmXNgR8ZT8cKSUft47di5T+9 + mhT1qmD62B+D86892y2QAohmUDadYRK9m9WD91Y7gOMeNhYj9qbxyPprPYUL0aPt + L8KS1H73C5WQMOsl2RyIw81asss30LWghsFIJ1gz8gVEjXhV+YC6W9XQ42iabmRR + A67f5sqK1scuO0q0KUFuc2libGUgVGVzdCBSdW5uZXIgPG5vcmVwbHlAZXhhbXBs + ZS5jb20+iQE3BBMBCAAhBQJZZJl9AhsDBQsJCAcCBhUICQoLAgQWAgMBAh4BAheA + AAoJEK0vcLBcXpbYi/kH/R0xk42MFpGd4pndTAsVIjRk/VhmhFc1v6sBeR40GXlt + hyEeOQQnIeHKLhsVT6YnfFZa8b4JwgTD6NeIiibOAlLgaKOWNwZu8toixMPVAzfQ + cRei+/gFXNil0FmBwWreVBDppuIn6XiSEPik0C7eCcw4lD+A+BbL3WGkp+OSQPho + hodIU02hgkrgs/6YJPats8Rgzw9hICsa2j0MjnG6P2z9atMz6tw2SiE5iBl7mZ2Z + zG/HiplleMhf/G8OZOskrWkKiLbpSPfQSKdOFkw1C6yqOlQ+HmuCZ56oyxtpItET + R11uAKt+ABdi4DX3FQQ+A+bGJ1+aKrcorZ8Z8s0XhPo= + =tV71 + -----END PGP PRIVATE KEY BLOCK----- + -----BEGIN PGP PUBLIC KEY BLOCK----- + + mQENBFlkmX0BCACtE81Xj/351nnvwnAWMf8ZUP9B1YOPe9ohqNsCQY1DxODVJc9y + ljCoh9fTdoHXuaUMUFistozxCMP81RuZxfbfsGePnl8OAOgWT5Sln6yEG45oClJ0 + RmJJZdDT1lF3VaVwK9NQ5E1oqmk1IOjISi7iFa9TmMn1h7ISP/p+/xtMxQhzUXt8 + APAEhRdc9FfwxaxCHKZBiM7ND+pAm6vpom07ZUgxSppsrXZAxDncTwAeCumDpeOL + LAcSBsw02swOIHFfqHNrkELLr4KJqws+zeAk6R2nq0k16AVdNX+Rb7T3OKmuLawx + HXe8rKpaw0RC+JCogZK4tz0KDNuZPLW2Y5JJABEBAAG0KUFuc2libGUgVGVzdCBS + dW5uZXIgPG5vcmVwbHlAZXhhbXBsZS5jb20+iQE3BBMBCAAhBQJZZJl9AhsDBQsJ + CAcCBhUICQoLAgQWAgMBAh4BAheAAAoJEK0vcLBcXpbYi/kH/R0xk42MFpGd4pnd + TAsVIjRk/VhmhFc1v6sBeR40GXlthyEeOQQnIeHKLhsVT6YnfFZa8b4JwgTD6NeI + iibOAlLgaKOWNwZu8toixMPVAzfQcRei+/gFXNil0FmBwWreVBDppuIn6XiSEPik + 0C7eCcw4lD+A+BbL3WGkp+OSQPhohodIU02hgkrgs/6YJPats8Rgzw9hICsa2j0M + jnG6P2z9atMz6tw2SiE5iBl7mZ2ZzG/HiplleMhf/G8OZOskrWkKiLbpSPfQSKdO + Fkw1C6yqOlQ+HmuCZ56oyxtpItETR11uAKt+ABdi4DX3FQQ+A+bGJ1+aKrcorZ8Z + 8s0XhPo= + =mUYY + -----END PGP PUBLIC KEY BLOCK----- -- cgit v1.2.3