git - add single_branch option (#28465)
In some usecases, we want to be able to clone a single branch of a repository, without using --depth (which implies --single-branch). * Use branch name when available - update description of parameter - consolidate branch or tag checking for easy reuse * Add changelog * Use static task imports rather than dynamic includes * Add integration tests for single_branch * Account for older versions of git * Minor tweak to warnings Co-authored-by: Laurent Coustet <laurent.coustet@clarisys.fr> Co-authored-by: Sam Doran <sdoran@redhat.com>
This commit is contained in:
parent
5a28b2b86c
commit
e396715d7b
5 changed files with 146 additions and 28 deletions
2
changelogs/fragments/git-add-single_branch.yml
Normal file
2
changelogs/fragments/git-add-single_branch.yml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
minor_changes:
|
||||||
|
- git - add ``single_branch`` parameter (https://github.com/ansible/ansible/pull/28465)
|
|
@ -69,7 +69,7 @@ options:
|
||||||
If version is set to a I(SHA-1) not reachable from any branch
|
If version is set to a I(SHA-1) not reachable from any branch
|
||||||
or tag, this option may be necessary to specify the ref containing
|
or tag, this option may be necessary to specify the ref containing
|
||||||
the I(SHA-1).
|
the I(SHA-1).
|
||||||
Uses the same syntax as the 'git fetch' command.
|
Uses the same syntax as the C(git fetch) command.
|
||||||
An example value could be "refs/meta/config".
|
An example value could be "refs/meta/config".
|
||||||
version_added: "1.9"
|
version_added: "1.9"
|
||||||
force:
|
force:
|
||||||
|
@ -127,6 +127,13 @@ options:
|
||||||
default: 'yes'
|
default: 'yes'
|
||||||
version_added: "1.6"
|
version_added: "1.6"
|
||||||
|
|
||||||
|
single_branch:
|
||||||
|
description:
|
||||||
|
- Clone only the history leading to the tip of the specified C(branch)
|
||||||
|
type: bool
|
||||||
|
default: 'no'
|
||||||
|
version_added: '2.11'
|
||||||
|
|
||||||
track_submodules:
|
track_submodules:
|
||||||
description:
|
description:
|
||||||
- if C(yes), submodules will track the latest commit on their
|
- if C(yes), submodules will track the latest commit on their
|
||||||
|
@ -232,6 +239,11 @@ EXAMPLES = '''
|
||||||
repo: https://github.com/ansible/ansible-examples.git
|
repo: https://github.com/ansible/ansible-examples.git
|
||||||
dest: /src/ansible-examples
|
dest: /src/ansible-examples
|
||||||
separate_git_dir: /src/ansible-examples.git
|
separate_git_dir: /src/ansible-examples.git
|
||||||
|
|
||||||
|
# Example clone of a single branch
|
||||||
|
- git:
|
||||||
|
single_branch: yes
|
||||||
|
branch: master
|
||||||
'''
|
'''
|
||||||
|
|
||||||
RETURN = '''
|
RETURN = '''
|
||||||
|
@ -254,7 +266,7 @@ warnings:
|
||||||
description: List of warnings if requested features were not available due to a too old git version.
|
description: List of warnings if requested features were not available due to a too old git version.
|
||||||
returned: error
|
returned: error
|
||||||
type: str
|
type: str
|
||||||
sample: Your git version is too old to fully support the depth argument. Falling back to full checkouts.
|
sample: git version is too old to fully support the depth argument. Falling back to full checkouts.
|
||||||
git_dir_now:
|
git_dir_now:
|
||||||
description: Contains the new path of .git directory if it's changed
|
description: Contains the new path of .git directory if it's changed
|
||||||
returned: success
|
returned: success
|
||||||
|
@ -453,7 +465,7 @@ def get_submodule_versions(git_path, module, dest, version='HEAD'):
|
||||||
|
|
||||||
|
|
||||||
def clone(git_path, module, repo, dest, remote, depth, version, bare,
|
def clone(git_path, module, repo, dest, remote, depth, version, bare,
|
||||||
reference, refspec, verify_commit, separate_git_dir, result, gpg_whitelist):
|
reference, refspec, git_version_used, verify_commit, separate_git_dir, result, gpg_whitelist, single_branch):
|
||||||
''' makes a new git repo if it does not already exist '''
|
''' makes a new git repo if it does not already exist '''
|
||||||
dest_dirname = os.path.dirname(dest)
|
dest_dirname = os.path.dirname(dest)
|
||||||
try:
|
try:
|
||||||
|
@ -466,11 +478,12 @@ def clone(git_path, module, repo, dest, remote, depth, version, bare,
|
||||||
cmd.append('--bare')
|
cmd.append('--bare')
|
||||||
else:
|
else:
|
||||||
cmd.extend(['--origin', remote])
|
cmd.extend(['--origin', remote])
|
||||||
|
|
||||||
|
is_branch_or_tag = is_remote_branch(git_path, module, dest, repo, version) or is_remote_tag(git_path, module, dest, repo, version)
|
||||||
if depth:
|
if depth:
|
||||||
if version == 'HEAD' or refspec:
|
if version == 'HEAD' or refspec:
|
||||||
cmd.extend(['--depth', str(depth)])
|
cmd.extend(['--depth', str(depth)])
|
||||||
elif is_remote_branch(git_path, module, dest, repo, version) \
|
elif is_branch_or_tag:
|
||||||
or is_remote_tag(git_path, module, dest, repo, version):
|
|
||||||
cmd.extend(['--depth', str(depth)])
|
cmd.extend(['--depth', str(depth)])
|
||||||
cmd.extend(['--branch', version])
|
cmd.extend(['--branch', version])
|
||||||
else:
|
else:
|
||||||
|
@ -480,10 +493,21 @@ def clone(git_path, module, repo, dest, remote, depth, version, bare,
|
||||||
"HEAD, branches, tags or in combination with refspec.")
|
"HEAD, branches, tags or in combination with refspec.")
|
||||||
if reference:
|
if reference:
|
||||||
cmd.extend(['--reference', str(reference)])
|
cmd.extend(['--reference', str(reference)])
|
||||||
needs_separate_git_dir_fallback = False
|
|
||||||
|
|
||||||
|
if single_branch:
|
||||||
|
if git_version_used is None:
|
||||||
|
module.fail_json(msg='Cannot find git executable at %s' % git_path)
|
||||||
|
|
||||||
|
if git_version_used < LooseVersion('1.7.10'):
|
||||||
|
module.warn("git version '%s' is too old to use 'single-branch'. Ignoring." % git_version_used)
|
||||||
|
else:
|
||||||
|
cmd.append("--single-branch")
|
||||||
|
|
||||||
|
if is_branch_or_tag:
|
||||||
|
cmd.extend(['--branch', version])
|
||||||
|
|
||||||
|
needs_separate_git_dir_fallback = False
|
||||||
if separate_git_dir:
|
if separate_git_dir:
|
||||||
git_version_used = git_version(git_path, module)
|
|
||||||
if git_version_used is None:
|
if git_version_used is None:
|
||||||
module.fail_json(msg='Cannot find git executable at %s' % git_path)
|
module.fail_json(msg='Cannot find git executable at %s' % git_path)
|
||||||
if git_version_used < LooseVersion('1.7.5'):
|
if git_version_used < LooseVersion('1.7.5'):
|
||||||
|
@ -1061,6 +1085,7 @@ def main():
|
||||||
executable=dict(default=None, type='path'),
|
executable=dict(default=None, type='path'),
|
||||||
bare=dict(default='no', type='bool'),
|
bare=dict(default='no', type='bool'),
|
||||||
recursive=dict(default='yes', type='bool'),
|
recursive=dict(default='yes', type='bool'),
|
||||||
|
single_branch=dict(default=False, type='bool'),
|
||||||
track_submodules=dict(default='no', type='bool'),
|
track_submodules=dict(default='no', type='bool'),
|
||||||
umask=dict(default=None, type='raw'),
|
umask=dict(default=None, type='raw'),
|
||||||
archive=dict(type='path'),
|
archive=dict(type='path'),
|
||||||
|
@ -1085,6 +1110,7 @@ def main():
|
||||||
verify_commit = module.params['verify_commit']
|
verify_commit = module.params['verify_commit']
|
||||||
gpg_whitelist = module.params['gpg_whitelist']
|
gpg_whitelist = module.params['gpg_whitelist']
|
||||||
reference = module.params['reference']
|
reference = module.params['reference']
|
||||||
|
single_branch = module.params['single_branch']
|
||||||
git_path = module.params['executable'] or module.get_bin_path('git', True)
|
git_path = module.params['executable'] or module.get_bin_path('git', True)
|
||||||
key_file = module.params['key_file']
|
key_file = module.params['key_file']
|
||||||
ssh_opts = module.params['ssh_opts']
|
ssh_opts = module.params['ssh_opts']
|
||||||
|
@ -1157,7 +1183,7 @@ def main():
|
||||||
git_version_used = git_version(git_path, module)
|
git_version_used = git_version(git_path, module)
|
||||||
|
|
||||||
if depth is not None and git_version_used < LooseVersion('1.9.1'):
|
if depth is not None and git_version_used < LooseVersion('1.9.1'):
|
||||||
result['warnings'].append("Your git version is too old to fully support the depth argument. Falling back to full checkouts.")
|
module.warn("git version is too old to fully support the depth argument. Falling back to full checkouts.")
|
||||||
depth = None
|
depth = None
|
||||||
|
|
||||||
recursive = module.params['recursive']
|
recursive = module.params['recursive']
|
||||||
|
@ -1180,7 +1206,8 @@ def main():
|
||||||
result['diff'] = diff
|
result['diff'] = diff
|
||||||
module.exit_json(**result)
|
module.exit_json(**result)
|
||||||
# there's no git config, so clone
|
# there's no git config, so clone
|
||||||
clone(git_path, module, repo, dest, remote, depth, version, bare, reference, refspec, verify_commit, separate_git_dir, result, gpg_whitelist)
|
clone(git_path, module, repo, dest, remote, depth, version, bare, reference,
|
||||||
|
refspec, git_version_used, verify_commit, separate_git_dir, result, gpg_whitelist, single_branch)
|
||||||
elif not update:
|
elif not update:
|
||||||
# Just return having found a repo already in the dest path
|
# Just return having found a repo already in the dest path
|
||||||
# this does no checking that the repo is the actual repo
|
# this does no checking that the repo is the actual repo
|
||||||
|
|
|
@ -16,25 +16,26 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
- include_tasks: setup.yml
|
- import_tasks: setup.yml
|
||||||
- include_tasks: setup-local-repos.yml
|
- import_tasks: setup-local-repos.yml
|
||||||
|
|
||||||
- include_tasks: formats.yml
|
- import_tasks: formats.yml
|
||||||
- include_tasks: missing_hostkey.yml
|
- import_tasks: missing_hostkey.yml
|
||||||
- include_tasks: no-destination.yml
|
- import_tasks: no-destination.yml
|
||||||
- include_tasks: specific-revision.yml
|
- import_tasks: specific-revision.yml
|
||||||
- include_tasks: submodules.yml
|
- import_tasks: submodules.yml
|
||||||
- include_tasks: change-repo-url.yml
|
- import_tasks: change-repo-url.yml
|
||||||
- include_tasks: depth.yml
|
- import_tasks: depth.yml
|
||||||
- include_tasks: checkout-new-tag.yml
|
- import_tasks: single-branch.yml
|
||||||
|
- import_tasks: checkout-new-tag.yml
|
||||||
- include_tasks: gpg-verification.yml
|
- include_tasks: gpg-verification.yml
|
||||||
when:
|
when:
|
||||||
- not gpg_version.stderr
|
- not gpg_version.stderr
|
||||||
- gpg_version.stdout
|
- gpg_version.stdout
|
||||||
- git_version.stdout is version("2.1.0", '>=')
|
- git_version.stdout is version("2.1.0", '>=')
|
||||||
- include_tasks: localmods.yml
|
- import_tasks: localmods.yml
|
||||||
- include_tasks: reset-origin.yml
|
- import_tasks: reset-origin.yml
|
||||||
- include_tasks: ambiguous-ref.yml
|
- import_tasks: ambiguous-ref.yml
|
||||||
- include_tasks: archive.yml
|
- import_tasks: archive.yml
|
||||||
- include_tasks: separate-git-dir.yml
|
- import_tasks: separate-git-dir.yml
|
||||||
- include_tasks: forcefully-fetch-tag.yml
|
- import_tasks: forcefully-fetch-tag.yml
|
||||||
|
|
87
test/integration/targets/git/tasks/single-branch.yml
Normal file
87
test/integration/targets/git/tasks/single-branch.yml
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
# Test single_branch parameter
|
||||||
|
|
||||||
|
- name: SINGLE_BRANCH | clear checkout_dir
|
||||||
|
file:
|
||||||
|
state: absent
|
||||||
|
path: "{{ checkout_dir }}"
|
||||||
|
|
||||||
|
- name: SINGLE_BRANCH | Clone example git repo using single_branch
|
||||||
|
git:
|
||||||
|
repo: 'file://{{ repo_dir|expanduser }}/shallow_branches'
|
||||||
|
dest: '{{ checkout_dir }}'
|
||||||
|
single_branch: yes
|
||||||
|
register: single_branch_1
|
||||||
|
|
||||||
|
- name: SINGLE_BRANCH | Clone example git repo using single_branch again
|
||||||
|
git:
|
||||||
|
repo: 'file://{{ repo_dir|expanduser }}/shallow_branches'
|
||||||
|
dest: '{{ checkout_dir }}'
|
||||||
|
single_branch: yes
|
||||||
|
register: single_branch_2
|
||||||
|
|
||||||
|
- name: SINGLE_BRANCH | List revisions
|
||||||
|
command: git rev-list --all --count
|
||||||
|
args:
|
||||||
|
chdir: '{{ checkout_dir }}'
|
||||||
|
register: rev_list1
|
||||||
|
when: git_version.stdout is version(git_version_supporting_single_branch, '>=')
|
||||||
|
|
||||||
|
- name: SINGLE_BRANCH | Ensure single_branch did the right thing with git >= {{ git_version_supporting_single_branch }}
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- single_branch_1 is changed
|
||||||
|
- single_branch_2 is not changed
|
||||||
|
when: git_version.stdout is version(git_version_supporting_single_branch, '>=')
|
||||||
|
|
||||||
|
- name: SINGLE_BRANCH | Ensure single_branch did the right thing with git < {{ git_version_supporting_single_branch }}
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- single_branch_1 is changed
|
||||||
|
- single_branch_1.warnings | length == 1
|
||||||
|
- single_branch_2 is not changed
|
||||||
|
when: git_version.stdout is version(git_version_supporting_single_branch, '<')
|
||||||
|
|
||||||
|
|
||||||
|
- name: SINGLE_BRANCH | clear checkout_dir
|
||||||
|
file:
|
||||||
|
state: absent
|
||||||
|
path: "{{ checkout_dir }}"
|
||||||
|
|
||||||
|
- name: SINGLE_BRANCH | Clone example git repo using single_branch with version
|
||||||
|
git:
|
||||||
|
repo: 'file://{{ repo_dir|expanduser }}/shallow_branches'
|
||||||
|
dest: '{{ checkout_dir }}'
|
||||||
|
single_branch: yes
|
||||||
|
version: master
|
||||||
|
register: single_branch_3
|
||||||
|
|
||||||
|
- name: SINGLE_BRANCH | Clone example git repo using single_branch with version again
|
||||||
|
git:
|
||||||
|
repo: 'file://{{ repo_dir|expanduser }}/shallow_branches'
|
||||||
|
dest: '{{ checkout_dir }}'
|
||||||
|
single_branch: yes
|
||||||
|
version: master
|
||||||
|
register: single_branch_4
|
||||||
|
|
||||||
|
- name: SINGLE_BRANCH | List revisions
|
||||||
|
command: git rev-list --all --count
|
||||||
|
args:
|
||||||
|
chdir: '{{ checkout_dir }}'
|
||||||
|
register: rev_list2
|
||||||
|
when: git_version.stdout is version(git_version_supporting_single_branch, '>=')
|
||||||
|
|
||||||
|
- name: SINGLE_BRANCH | Ensure single_branch did the right thing with git >= {{ git_version_supporting_single_branch }}
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- single_branch_3 is changed
|
||||||
|
- single_branch_4 is not changed
|
||||||
|
- rev_list2.stdout == '1'
|
||||||
|
when: git_version.stdout is version(git_version_supporting_single_branch, '>=')
|
||||||
|
|
||||||
|
- name: SINGLE_BRANCH | Ensure single_branch did the right thing with git < {{ git_version_supporting_single_branch }}
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- single_branch_3 is changed
|
||||||
|
- single_branch_3.warnings | length == 1
|
||||||
|
- single_branch_4 is not changed
|
||||||
|
when: git_version.stdout is version(git_version_supporting_single_branch, '<')
|
|
@ -43,6 +43,7 @@ known_host_files:
|
||||||
- '/etc/ssh/ssh_known_hosts'
|
- '/etc/ssh/ssh_known_hosts'
|
||||||
git_version_supporting_depth: 1.9.1
|
git_version_supporting_depth: 1.9.1
|
||||||
git_version_supporting_ls_remote: 1.7.5
|
git_version_supporting_ls_remote: 1.7.5
|
||||||
|
git_version_supporting_single_branch: 1.7.10
|
||||||
# path to a SSH private key for use with github.com (tests skipped if undefined)
|
# 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"
|
# github_ssh_private_key: "{{ lookup('env', 'HOME') }}/.ssh/id_rsa"
|
||||||
git_gpg_testkey: |
|
git_gpg_testkey: |
|
||||||
|
|
Loading…
Reference in a new issue