Skip to content

Commit

Permalink
support git version starting with heads/ or tags/ (#171)
Browse files Browse the repository at this point in the history
* support git version starting with heads/ or tags/

* use tags/ in tests

* use heads/ in tests

* avoid heads/ ending up in detached state

* use file:// url
  • Loading branch information
dirk-thomas authored Apr 22, 2021
1 parent f6cc45c commit 89bbf61
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 45 deletions.
2 changes: 1 addition & 1 deletion test/import.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Downloaded tarball from 'https://github.com/dirk-thomas/vcstool/archive/377d5b3d
Downloaded zipfile from 'https://github.com/dirk-thomas/vcstool/archive/377d5b3d03c212f015cc832fdb368f4534d0d583.zip' and unpacked it
=== ./immutable/tag (git) ===
Cloning into '.'...
Note: switching to '0.1.27'.
Note: switching to 'tags/0.1.27'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
Expand Down
2 changes: 1 addition & 1 deletion test/import_shallow.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Initialized empty Git repository in ./immutable/tag/.git/

From https://github.com/dirk-thomas/vcstool
* [new tag] 0.1.27 -> 0.1.27
Note: switching to '0.1.27'.
Note: switching to 'tags/0.1.27'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
Expand Down
4 changes: 2 additions & 2 deletions test/list.repos
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ repositories:
immutable/tag:
type: git
url: https://github.com/dirk-thomas/vcstool.git
version: 0.1.27
version: tags/0.1.27
vcstool:
type: git
url: https://github.com/dirk-thomas/vcstool.git
version: master
version: heads/master
without_version:
type: git
url: https://github.com/dirk-thomas/vcstool.git
3 changes: 1 addition & 2 deletions test/test_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@
from vcstool.util import rmtree # noqa: E402

REPOS_FILE = os.path.join(os.path.dirname(__file__), 'list.repos')
REPOS_FILE_URL = \
'https://raw.githubusercontent.com/dirk-thomas/vcstool/master/test/list.repos' # noqa: E501
REPOS_FILE_URL = 'file://' + REPOS_FILE
REPOS2_FILE = os.path.join(os.path.dirname(__file__), 'list2.repos')
TEST_WORKSPACE = os.path.join(
os.path.dirname(os.path.dirname(__file__)), 'test_workspace')
Expand Down
4 changes: 2 additions & 2 deletions test/validate.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ Tarball url 'https://github.com/dirk-thomas/vcstool/archive/377d5b3d03c212f015cc
=== immutable/hash_zip (zip) ===
Zip url 'https://github.com/dirk-thomas/vcstool/archive/377d5b3d03c212f015cc832fdb368f4534d0d583.zip' exists
=== immutable/tag (git) ===
Found git repository 'https://github.com/dirk-thomas/vcstool.git' with ref '0.1.27'
Found git repository 'https://github.com/dirk-thomas/vcstool.git' with tag '0.1.27'
=== vcstool (git) ===
Found git repository 'https://github.com/dirk-thomas/vcstool.git' with ref 'master'
Found git repository 'https://github.com/dirk-thomas/vcstool.git' with branch 'master'
=== without_version (git) ===
Found git repository 'https://github.com/dirk-thomas/vcstool.git' with default branch
131 changes: 94 additions & 37 deletions vcstool/clients/git.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,54 +314,71 @@ def import_(self, command):
# fetch updates for existing repo
cmd_fetch = [GitClient._executable, 'fetch', remote]
if command.shallow:
result_version_type = self._check_version_type(
result_version_type, version_name = self._check_version_type(
command.url, checkout_version)
if result_version_type['returncode']:
return result_version_type
version_type = result_version_type['version_type']
if version_type == 'branch':
cmd_fetch.append(
'refs/heads/%s:refs/remotes/%s/%s' %
(checkout_version, remote, checkout_version))
(version_name, remote, version_name))
elif version_type == 'hash':
cmd_fetch.append(checkout_version)
elif version_type == 'tag':
cmd_fetch.append(
'+refs/tags/%s:refs/tags/%s' %
(checkout_version, checkout_version))
(version_name, version_name))
else:
assert False
cmd_fetch += ['--depth', '1']
else:
version_type = None
result_fetch = self._run_command(cmd_fetch, retry=command.retry)
if result_fetch['returncode']:
return result_fetch
cmd = result_fetch['cmd']
output = result_fetch['output']

if not command.shallow and checkout_version is not None:
if checkout_version.startswith('heads/'):
version_name = checkout_version[6:]
version_type = 'branch'
elif checkout_version.startswith('tags/'):
version_name = checkout_version[5:]
version_type = 'tag'
else:
version_type = None
# ensure that a tracking branch exists which can be checked out
if command.shallow and version_type == 'branch':
if version_type == 'branch':
cmd_show_ref = [
GitClient._executable, 'show-ref',
'refs/heads/%s' % checkout_version]
'refs/heads/%s' % version_name]
result_show_ref = self._run_command(cmd_show_ref)
if result_show_ref['returncode']:
if not command.shallow:
result_show_ref['output'] = \
"Could not find branch '%s': %s" % \
(version_name, result_show_ref['output'])
return result_show_ref
# creating tracking branch
cmd_branch = [
GitClient._executable, 'branch', checkout_version,
'%s/%s' % (remote, checkout_version)]
GitClient._executable, 'branch', version_name,
'%s/%s' % (remote, version_name)]
result_branch = self._run_command(cmd_branch)
if result_branch['returncode']:
result_branch['output'] = \
"Could not create branch '%s': %s" % \
(checkout_version, result_branch['output'])
(version_name, result_branch['output'])
return result_branch
cmd += ' && ' + ' '.join(cmd_branch)
output = '\n'.join([output, result_branch['output']])
checkout_version = version_name

else:
version_type = None
if command.version:
result_version_type = self._check_version_type(
result_version_type, version_name = self._check_version_type(
command.url, command.version)
if result_version_type['returncode']:
return result_version_type
Expand All @@ -370,7 +387,7 @@ def import_(self, command):
if not command.shallow or version_type in (None, 'branch'):
cmd_clone = [GitClient._executable, 'clone', command.url, '.']
if version_type == 'branch':
cmd_clone += ['-b', command.version]
cmd_clone += ['-b', version_name]
checkout_version = None
else:
checkout_version = command.version
Expand Down Expand Up @@ -409,7 +426,7 @@ def import_(self, command):
elif version_type == 'tag':
cmd_fetch.append(
'refs/tags/%s:refs/tags/%s' %
(command.version, command.version))
(version_name, version_name))
else:
assert False
cmd_fetch += ['--depth', '1']
Expand Down Expand Up @@ -481,15 +498,30 @@ def _get_remote_urls(self):
}

def _check_version_type(self, url, version):
# check if version starts with heads/ or tags/
prefixes = {
'heads/': 'branch',
'tags/': 'tag',
}
for prefix, version_type in prefixes.items():
if version.startswith(prefix):
return {
'cmd': None,
'cwd': None,
'output': None,
'returncode': 0,
'version_type': version_type,
}, version[len(prefix):]

cmd = [GitClient._executable, 'ls-remote', url, version]
result = self._run_command(cmd)
if result['returncode']:
result['output'] = 'Could not determine ref type of version: ' + \
result['output']
return result
return result, None
if not result['output']:
result['version_type'] = 'hash'
return result
return result, None

refs = {}
for hash_, ref in self._get_hash_ref_tuples(result['output']):
Expand All @@ -502,14 +534,15 @@ def _check_version_type(self, url, version):
result['returncode'] = 1
result['output'] = 'The version ref is a branch as well as ' \
'tag but with different hashes'
return result
return result, None
if tag_ref in refs:
result['version_type'] = 'tag'
elif branch_ref in refs:
result['version_type'] = 'branch'
else:
result['version_type'] = 'hash'
return result
return result, \
version if result['version_type'] in ('tag', 'branch') else None

def log(self, command):
self._check_executable()
Expand Down Expand Up @@ -645,6 +678,8 @@ def validate(self, command):
if command.version:
hashes = []
refs = []
tags = []
branches = []

for hash_and_ref in self._get_hash_ref_tuples(
result_ls_remote['output']
Expand All @@ -654,37 +689,59 @@ def validate(self, command):
# ignore pull request refs
if not hash_and_ref[1].startswith('refs/pull/'):
if hash_and_ref[1].startswith('refs/tags/'):
refs.append(hash_and_ref[1][10:])
tags.append(hash_and_ref[1][10:])
elif hash_and_ref[1].startswith('refs/heads/'):
refs.append(hash_and_ref[1][11:])
branches.append(hash_and_ref[1][11:])
else:
refs.append(hash_and_ref[1])

# test for refs first
ref_found = command.version in refs

if not ref_found:
if command.version in refs:
version_type = 'ref'
version_name = command.version
elif (
command.version.startswith('heads/') and
command.version[6:] in branches
):
version_type = 'branch'
version_name = command.version[6:]
elif (
command.version.startswith('tags/') and
command.version[5:] in tags
):
version_type = 'tag'
version_name = command.version[5:]
elif (
command.version in branches and
command.version not in tags
):
version_type = 'branch'
version_name = command.version
elif (
command.version in tags and
command.version not in branches
):
version_type = 'tag'
version_name = command.version
else:
for _hash in hashes:
if _hash.startswith(command.version):
ref_found = True
break
else:
cmd = result_ls_remote['cmd']
output = "Found git repository '%s' but " % command.url + \
'unable to verify non-branch / non-tag ref ' + \
"'%s' without cloning the repo" % command.version

if not ref_found:
cmd = result_ls_remote['cmd']
output = "Found git repository '%s' but " % command.url + \
'unable to verify non-branch / non-tag ref ' + \
"'%s' without cloning the repo" % command.version
return {
'cmd': cmd,
'cwd': self.path,
'output': output,
'returncode': 0
}

return {
'cmd': cmd,
'cwd': self.path,
'output': output,
'returncode': 0
}
else:
cmd = result_ls_remote['cmd']
output = "Found git repository '%s' with ref '%s'" % \
(command.url, command.version)
cmd = result_ls_remote['cmd']
output = "Found git repository '%s' with %s '%s'" % \
(command.url, version_type, version_name)
else:
cmd = result_ls_remote['cmd']
output = "Found git repository '%s' with default branch" % \
Expand Down

0 comments on commit 89bbf61

Please sign in to comment.