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)
|
|
@ -31,7 +31,7 @@ options:
|
|||
required: true
|
||||
version:
|
||||
description:
|
||||
- What version of the repository to check out. This can be
|
||||
- What version of the repository to check out. This can be
|
||||
the literal string C(HEAD), a branch name, a tag name.
|
||||
It can also be a I(SHA-1) hash, in which case C(refspec) needs
|
||||
to be specified if the given revision is not already available.
|
||||
|
@ -69,7 +69,7 @@ options:
|
|||
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
|
||||
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".
|
||||
version_added: "1.9"
|
||||
force:
|
||||
|
@ -127,6 +127,13 @@ options:
|
|||
default: 'yes'
|
||||
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:
|
||||
description:
|
||||
- if C(yes), submodules will track the latest commit on their
|
||||
|
@ -232,6 +239,11 @@ EXAMPLES = '''
|
|||
repo: https://github.com/ansible/ansible-examples.git
|
||||
dest: /src/ansible-examples
|
||||
separate_git_dir: /src/ansible-examples.git
|
||||
|
||||
# Example clone of a single branch
|
||||
- git:
|
||||
single_branch: yes
|
||||
branch: master
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
|
@ -254,7 +266,7 @@ warnings:
|
|||
description: List of warnings if requested features were not available due to a too old git version.
|
||||
returned: error
|
||||
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:
|
||||
description: Contains the new path of .git directory if it's changed
|
||||
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,
|
||||
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 '''
|
||||
dest_dirname = os.path.dirname(dest)
|
||||
try:
|
||||
|
@ -466,11 +478,12 @@ def clone(git_path, module, repo, dest, remote, depth, version, bare,
|
|||
cmd.append('--bare')
|
||||
else:
|
||||
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 version == 'HEAD' or refspec:
|
||||
cmd.extend(['--depth', str(depth)])
|
||||
elif is_remote_branch(git_path, module, dest, repo, version) \
|
||||
or is_remote_tag(git_path, module, dest, repo, version):
|
||||
elif is_branch_or_tag:
|
||||
cmd.extend(['--depth', str(depth)])
|
||||
cmd.extend(['--branch', version])
|
||||
else:
|
||||
|
@ -480,12 +493,23 @@ def clone(git_path, module, repo, dest, remote, depth, version, bare,
|
|||
"HEAD, branches, tags or in combination with refspec.")
|
||||
if reference:
|
||||
cmd.extend(['--reference', str(reference)])
|
||||
needs_separate_git_dir_fallback = False
|
||||
|
||||
if separate_git_dir:
|
||||
git_version_used = git_version(git_path, module)
|
||||
if single_branch:
|
||||
if git_version_used is None:
|
||||
module.fail_json(msg='Can not 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.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 git_version_used is None:
|
||||
module.fail_json(msg='Cannot find git executable at %s' % git_path)
|
||||
if git_version_used < LooseVersion('1.7.5'):
|
||||
# git before 1.7.5 doesn't have separate-git-dir argument, do fallback
|
||||
needs_separate_git_dir_fallback = True
|
||||
|
@ -1061,6 +1085,7 @@ def main():
|
|||
executable=dict(default=None, type='path'),
|
||||
bare=dict(default='no', type='bool'),
|
||||
recursive=dict(default='yes', type='bool'),
|
||||
single_branch=dict(default=False, type='bool'),
|
||||
track_submodules=dict(default='no', type='bool'),
|
||||
umask=dict(default=None, type='raw'),
|
||||
archive=dict(type='path'),
|
||||
|
@ -1085,6 +1110,7 @@ def main():
|
|||
verify_commit = module.params['verify_commit']
|
||||
gpg_whitelist = module.params['gpg_whitelist']
|
||||
reference = module.params['reference']
|
||||
single_branch = module.params['single_branch']
|
||||
git_path = module.params['executable'] or module.get_bin_path('git', True)
|
||||
key_file = module.params['key_file']
|
||||
ssh_opts = module.params['ssh_opts']
|
||||
|
@ -1157,7 +1183,7 @@ def main():
|
|||
git_version_used = git_version(git_path, module)
|
||||
|
||||
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
|
||||
|
||||
recursive = module.params['recursive']
|
||||
|
@ -1180,7 +1206,8 @@ def main():
|
|||
result['diff'] = diff
|
||||
module.exit_json(**result)
|
||||
# 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:
|
||||
# Just return having found a repo already in the dest path
|
||||
# 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
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
- include_tasks: setup.yml
|
||||
- include_tasks: setup-local-repos.yml
|
||||
- import_tasks: setup.yml
|
||||
- import_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
|
||||
- import_tasks: formats.yml
|
||||
- import_tasks: missing_hostkey.yml
|
||||
- import_tasks: no-destination.yml
|
||||
- import_tasks: specific-revision.yml
|
||||
- import_tasks: submodules.yml
|
||||
- import_tasks: change-repo-url.yml
|
||||
- import_tasks: depth.yml
|
||||
- import_tasks: single-branch.yml
|
||||
- import_tasks: checkout-new-tag.yml
|
||||
- include_tasks: gpg-verification.yml
|
||||
when:
|
||||
- not gpg_version.stderr
|
||||
- gpg_version.stdout
|
||||
- git_version.stdout is version("2.1.0", '>=')
|
||||
- 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
|
||||
- import_tasks: localmods.yml
|
||||
- import_tasks: reset-origin.yml
|
||||
- import_tasks: ambiguous-ref.yml
|
||||
- import_tasks: archive.yml
|
||||
- import_tasks: separate-git-dir.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'
|
||||
git_version_supporting_depth: 1.9.1
|
||||
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)
|
||||
# github_ssh_private_key: "{{ lookup('env', 'HOME') }}/.ssh/id_rsa"
|
||||
git_gpg_testkey: |
|
||||
|
|
Loading…
Reference in a new issue