Skip to content

Commit

Permalink
Only fetch when branch/tag/commit not on local repo
Browse files Browse the repository at this point in the history
The fetch operation is a slow operation, if a commit/tag/branch
has been on local repo, we can skip the fetch operation.
For branch, if it's a known branch, the following pull will also
fetch from remote.
For tag/commit, if it's a know local commit/tag, the fetch is
not required as it has been downloaded to local.
  • Loading branch information
tiewei committed Mar 30, 2017
1 parent fc13594 commit 5a55f67
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 29 deletions.
55 changes: 46 additions & 9 deletions gilt/git.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def extract(repository, destination, version, debug=False):
"""
with util.saved_cwd():
os.chdir(repository)
_get_branch(version, debug)
_get_version(version, debug)
cmd = sh.git.bake(
'checkout-index', force=True, all=True, prefix=destination)
util.run_command(cmd, debug=debug)
Expand All @@ -85,7 +85,7 @@ def overlay(repository, files, version, debug=False):
"""
with util.saved_cwd():
os.chdir(repository)
_get_branch(version, debug)
_get_version(version, debug)

for fc in files:
if '*' in fc.src:
Expand All @@ -103,7 +103,7 @@ def overlay(repository, files, version, debug=False):
util.print_info(msg)


def _get_branch(version, debug=False):
def _get_version(version, debug=False):
"""
Handle switching to the specified version and return None.
Expand All @@ -116,22 +116,59 @@ def _get_branch(version, debug=False):
:param debug: An optional bool to toggle debug output.
:return: None
"""
cmd = sh.git.bake('fetch')
util.run_command(cmd, debug=debug)
if not any((_has_branch(version, debug), _has_tag(version, debug),
_has_commit(version, debug))):
cmd = sh.git.bake('fetch')
util.run_command(cmd, debug=debug)
cmd = sh.git.bake('checkout', version)
util.run_command(cmd, debug=debug)
cmd = sh.git.bake('clean', '-d', '-x', '-f')
util.run_command(cmd, debug=debug)
if _is_branch(version, debug):
if _has_branch(version, debug):
cmd = sh.git.bake('pull', rebase=True, ff_only=True)
util.run_command(cmd, debug=debug)


def _is_branch(version, debug=False):
def _has_commit(version, debug=False):
"""
Determine a version is a git branch name or not.
Determine a version is a local git commit sha or not.
:param version: A string containing the branch/tag/sha to be exported.
:param version: A string containing the branch/tag/sha to be determined.
:param debug: An optional bool to toggle debug output.
:return: bool
"""
if _has_tag(version, debug) or _has_branch(version, debug):
return False
cmd = sh.git.bake('cat-file', '-e', version)
try:
util.run_command(cmd, debug=debug)
return True
except sh.ErrorReturnCode:
return False


def _has_tag(version, debug=False):
"""
Determine a version is a local git tag name or not.
:param version: A string containing the branch/tag/sha to be determined.
:param debug: An optional bool to toggle debug output.
:return: bool
"""
cmd = sh.git.bake('show-ref', '--verify', '--quiet',
"refs/tags/{}".format(version))
try:
util.run_command(cmd, debug=debug)
return True
except sh.ErrorReturnCode:
return False


def _has_branch(version, debug=False):
"""
Determine a version is a local git branch name or not.
:param version: A string containing the branch/tag/sha to be determined.
:param debug: An optional bool to toggle debug output.
:return: bool
"""
Expand Down
100 changes: 80 additions & 20 deletions test/test_git.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,16 +127,15 @@ def patched_run_command(mocker):
return mocker.patch('gilt.util.run_command')


def test_get_branch(mocker, patched_run_command):
git._get_branch('branch')
def test_get_version_has_branch(mocker, patched_run_command):
mocker.patch('gilt.git._has_branch').return_value = True
mocker.patch('gilt.git._has_tag').return_value = False
mocker.patch('gilt.git._has_commit').return_value = False
git._get_version('branch')
# yapf: disable
expected = [
mocker.call(sh.git.bake('fetch'), debug=False),
mocker.call(sh.git.bake('checkout', 'branch'), debug=False),
mocker.call(sh.git.bake('clean', '-d', '-x', '-f'), debug=False),
mocker.call(sh.git.bake(
'show-ref', '--verify', '--quiet', 'refs/heads/branch'),
debug=False),
mocker.call(sh.git.bake('pull', rebase=True, ff_only=True),
debug=False)
]
Expand All @@ -145,27 +144,88 @@ def test_get_branch(mocker, patched_run_command):
assert expected == patched_run_command.mock_calls


@slow
def test_is_branch(temp_dir):
name = 'retr0h.ansible-etcd'
repo = 'https://github.com/retr0h/ansible-etcd.git'
destination = os.path.join(temp_dir.strpath, name)
git.clone(name, repo, destination)
os.chdir(destination)
assert git._is_branch('master')
assert not git._is_branch('1.1')
assert not git._is_branch('888ef7b')
def test_get_version_has_tag(mocker, patched_run_command):
mocker.patch('gilt.git._has_branch').return_value = False
mocker.patch('gilt.git._has_tag').return_value = True
mocker.patch('gilt.git._has_commit').return_value = False
git._get_version('tag_name')
# yapf: disable
expected = [
mocker.call(sh.git.bake('checkout', 'tag_name'), debug=False),
mocker.call(sh.git.bake('clean', '-d', '-x', '-f'), debug=False)
]
# yapf: enable

assert expected == patched_run_command.mock_calls


def test_is_branch_nonbranch(mocker, patched_run_command):
mocker.patch('gilt.git._is_branch').return_value = False
git._get_branch('nonbranch')
def test_get_version_has_commit(mocker, patched_run_command):
mocker.patch('gilt.git._has_branch').return_value = False
mocker.patch('gilt.git._has_tag').return_value = False
mocker.patch('gilt.git._has_commit').return_value = True
git._get_version('commit_sha')
# yapf: disable
expected = [
mocker.call(sh.git.bake('checkout', 'commit_sha'), debug=False),
mocker.call(sh.git.bake('clean', '-d', '-x', '-f'), debug=False)
]
# yapf: enable

assert expected == patched_run_command.mock_calls


def test_get_version_needs_fetch(mocker, patched_run_command):
mocker.patch('gilt.git._has_branch').return_value = False
mocker.patch('gilt.git._has_tag').return_value = False
mocker.patch('gilt.git._has_commit').return_value = False
git._get_version('remote_tag')
# yapf: disable
expected = [
mocker.call(sh.git.bake('fetch'), debug=False),
mocker.call(sh.git.bake('checkout', 'nonbranch'), debug=False),
mocker.call(sh.git.bake('checkout', 'remote_tag'), debug=False),
mocker.call(sh.git.bake('clean', '-d', '-x', '-f'), debug=False)
]
# yapf: enable

assert expected == patched_run_command.mock_calls


def test_get_version_needs_pull(mocker, patched_run_command):
mocker.patch('gilt.git._has_branch').side_effect = [False, True]
mocker.patch('gilt.git._has_tag').return_value = False
mocker.patch('gilt.git._has_commit').return_value = False
git._get_version('remote_branch')
# yapf: disable
expected = [
mocker.call(sh.git.bake('fetch'), debug=False),
mocker.call(sh.git.bake('checkout', 'remote_branch'), debug=False),
mocker.call(sh.git.bake('clean', '-d', '-x', '-f'), debug=False),
mocker.call(sh.git.bake('pull', rebase=True, ff_only=True),
debug=False)
]
# yapf: enable

assert expected == patched_run_command.mock_calls


@slow
def test_has_version(temp_dir):
name = 'retr0h.ansible-etcd'
repo = 'https://github.com/retr0h/ansible-etcd.git'
destination = os.path.join(temp_dir.strpath, name)
git.clone(name, repo, destination)
os.chdir(destination)
# _has_branch tests
assert git._has_branch('master')
assert not git._has_branch('1.1')
assert not git._has_branch('888ef7b')

# _has_tag tests
assert not git._has_tag('master')
assert git._has_tag('1.1')
assert not git._has_tag('888ef7b')

# _has_commit tests
assert not git._has_commit('master')
assert not git._has_commit('1.1')
assert git._has_commit('888ef7b')

0 comments on commit 5a55f67

Please sign in to comment.