Merge "Add http(s) protocol support to fetch_review and list_reviews"
This commit is contained in:
commit
3cd81cc4d6
@ -137,9 +137,9 @@ def run_command(*argv, **env):
|
||||
|
||||
|
||||
def run_command_exc(klazz, *argv, **env):
|
||||
"""Run command *argv, on failure raise 'klazz
|
||||
"""Run command *argv, on failure raise klazz
|
||||
|
||||
klass should be derived from CommandFailed
|
||||
klazz should be derived from CommandFailed
|
||||
"""
|
||||
(rc, output) = run_command_status(*argv, **env)
|
||||
if rc != 0:
|
||||
@ -147,6 +147,28 @@ def run_command_exc(klazz, *argv, **env):
|
||||
return output
|
||||
|
||||
|
||||
def run_http_exc(klazz, url, **env):
|
||||
"""Run http GET request url, on failure raise klazz
|
||||
|
||||
klazz should be derived from CommandFailed
|
||||
"""
|
||||
if url.startswith("https://") and "verify" not in env:
|
||||
if "GIT_SSL_NO_VERIFY" in os.environ:
|
||||
env["verify"] = False
|
||||
else:
|
||||
verify = git_config_get_value("http", "sslVerify", as_bool=True)
|
||||
env["verify"] = verify != 'false'
|
||||
|
||||
try:
|
||||
res = requests.get(url, **env)
|
||||
if not 200 <= res.status_code < 300:
|
||||
code = (res.status_code - 301) % 255 + 1
|
||||
raise klazz(code, res.text, ('GET', url), env)
|
||||
return res
|
||||
except Exception as err:
|
||||
raise klazz(255, str(err), ('GET', url), env)
|
||||
|
||||
|
||||
def get_version():
|
||||
requirement = pkg_resources.Requirement.parse('git-review')
|
||||
provider = pkg_resources.get_provider(requirement)
|
||||
@ -195,12 +217,13 @@ def run_custom_script(action):
|
||||
print(output)
|
||||
|
||||
|
||||
def git_config_get_value(section, option, default=None):
|
||||
def git_config_get_value(section, option, default=None, as_bool=False):
|
||||
"""Get config value for section/option."""
|
||||
cmd = ["git", "config", "--get", "%s.%s" % (section, option)]
|
||||
if as_bool:
|
||||
cmd.insert(2, "--bool")
|
||||
try:
|
||||
return run_command_exc(GitConfigException,
|
||||
"git", "config",
|
||||
"--get",
|
||||
"%s.%s" % (section, option)).strip()
|
||||
return run_command_exc(GitConfigException, *cmd).strip()
|
||||
except GitConfigException as exc:
|
||||
if exc.rc == 1:
|
||||
return default
|
||||
@ -232,13 +255,10 @@ def set_hooks_commit_msg(remote, target_file):
|
||||
hook_url = urljoin(remote_url, '/tools/hooks/commit-msg')
|
||||
if VERBOSE:
|
||||
print("Fetching commit hook from: %s" % hook_url)
|
||||
res = requests.get(hook_url, stream=True)
|
||||
if res.status_code == 200:
|
||||
with open(target_file, 'wb') as f:
|
||||
for x in res.iter_content(1024):
|
||||
f.write(x)
|
||||
else:
|
||||
raise CannotInstallHook
|
||||
res = run_http_exc(CannotInstallHook, hook_url, stream=True)
|
||||
with open(target_file, 'wb') as f:
|
||||
for x in res.iter_content(1024):
|
||||
f.write(x)
|
||||
else:
|
||||
(hostname, username, port, project_name) = \
|
||||
parse_gerrit_ssh_params_from_git_url(remote_url)
|
||||
@ -376,6 +396,100 @@ def parse_gerrit_ssh_params_from_git_url(git_url):
|
||||
return (hostname, username, port, project_name)
|
||||
|
||||
|
||||
def query_reviews(remote_url, change=None, current_patch_set=True,
|
||||
exception=CommandFailed, parse_exc=Exception):
|
||||
if remote_url.startswith('http://') or remote_url.startswith('https://'):
|
||||
query = query_reviews_over_http
|
||||
else:
|
||||
query = query_reviews_over_ssh
|
||||
return query(remote_url,
|
||||
change=change,
|
||||
current_patch_set=current_patch_set,
|
||||
exception=exception,
|
||||
parse_exc=parse_exc)
|
||||
|
||||
|
||||
def query_reviews_over_http(remote_url, change=None, current_patch_set=True,
|
||||
exception=CommandFailed, parse_exc=Exception):
|
||||
url = urljoin(remote_url, '/changes/')
|
||||
if change:
|
||||
if current_patch_set:
|
||||
url += '?q=%s&o=CURRENT_REVISION' % change
|
||||
else:
|
||||
url += '?q=%s&o=ALL_REVISIONS' % change
|
||||
|
||||
if VERBOSE:
|
||||
print("Query gerrit %s" % url)
|
||||
request = run_http_exc(exception, url)
|
||||
if VERBOSE:
|
||||
print(request.text)
|
||||
reviews = json.loads(request.text[4:])
|
||||
|
||||
# Reformat output to match ssh output
|
||||
try:
|
||||
for review in reviews:
|
||||
review["number"] = str(review.pop("_number"))
|
||||
if "revisions" not in review:
|
||||
continue
|
||||
patchsets = {}
|
||||
for key, revision in review["revisions"].items():
|
||||
fetch_value = list(revision["fetch"].values())[0]
|
||||
patchset = {"number": str(revision["_number"]),
|
||||
"ref": fetch_value["ref"]}
|
||||
patchsets[key] = patchset
|
||||
review["patchSets"] = patchsets.values()
|
||||
review["currentPatchSet"] = patchsets[review["current_revision"]]
|
||||
except Exception as err:
|
||||
raise parse_exc(err)
|
||||
|
||||
return reviews
|
||||
|
||||
|
||||
def query_reviews_over_ssh(remote_url, change=None, current_patch_set=True,
|
||||
exception=CommandFailed, parse_exc=Exception):
|
||||
(hostname, username, port, project_name) = \
|
||||
parse_gerrit_ssh_params_from_git_url(remote_url)
|
||||
|
||||
if change:
|
||||
if current_patch_set:
|
||||
query = "--current-patch-set change:%s" % change
|
||||
else:
|
||||
query = "--patch-sets change:%s" % change
|
||||
else:
|
||||
query = "project:%s status:open" % project_name
|
||||
|
||||
port = "-p%s" % port if port is not None else ""
|
||||
if username is None:
|
||||
userhost = hostname
|
||||
else:
|
||||
userhost = "%s@%s" % (username, hostname)
|
||||
|
||||
if VERBOSE:
|
||||
print("Query gerrit %s %s" % (remote_url, query))
|
||||
output = run_command_exc(
|
||||
exception,
|
||||
"ssh", "-x", port, userhost,
|
||||
"gerrit", "query",
|
||||
"--format=JSON %s" % query)
|
||||
if VERBOSE:
|
||||
print(output)
|
||||
|
||||
changes = []
|
||||
try:
|
||||
for line in output.split("\n"):
|
||||
if line[0] == "{":
|
||||
try:
|
||||
data = json.loads(line)
|
||||
if "type" not in data:
|
||||
changes.append(data)
|
||||
except Exception:
|
||||
if VERBOSE:
|
||||
print(output)
|
||||
except Exception as err:
|
||||
raise parse_exc(err)
|
||||
return changes
|
||||
|
||||
|
||||
def check_color_support():
|
||||
global _has_color
|
||||
if _has_color is None:
|
||||
@ -638,60 +752,25 @@ class CannotParseOpenChangesets(ChangeSetException):
|
||||
|
||||
def list_reviews(remote):
|
||||
remote_url = get_remote_url(remote)
|
||||
(hostname, username, port, project_name) = \
|
||||
parse_gerrit_ssh_params_from_git_url(remote_url)
|
||||
reviews = query_reviews(remote_url,
|
||||
exception=CannotQueryOpenChangesets,
|
||||
parse_exc=CannotParseOpenChangesets)
|
||||
|
||||
if port is not None:
|
||||
port = "-p %s" % port
|
||||
else:
|
||||
port = ""
|
||||
if username is None:
|
||||
userhost = hostname
|
||||
else:
|
||||
userhost = "%s@%s" % (username, hostname)
|
||||
|
||||
review_info = None
|
||||
output = run_command_exc(
|
||||
CannotQueryOpenChangesets,
|
||||
"ssh", "-x", port, userhost,
|
||||
"gerrit", "query",
|
||||
"--format=JSON project:%s status:open" % project_name)
|
||||
|
||||
review_list = []
|
||||
review_field_width = {}
|
||||
REVIEW_FIELDS = ('number', 'branch', 'subject')
|
||||
FIELDS = range(0, len(REVIEW_FIELDS))
|
||||
FIELDS = range(len(REVIEW_FIELDS))
|
||||
if check_color_support():
|
||||
review_field_color = (colors.yellow, colors.green, "")
|
||||
color_reset = colors.reset
|
||||
else:
|
||||
review_field_color = ("", "", "")
|
||||
color_reset = ""
|
||||
review_field_width = [0, 0, 0]
|
||||
review_field_format = ["%*s", "%*s", "%*s"]
|
||||
review_field_justify = [+1, +1, -1] # -1 is justify to right
|
||||
|
||||
for line in output.split("\n"):
|
||||
# Warnings from ssh wind up in this output
|
||||
if line[0] != "{":
|
||||
print(line)
|
||||
continue
|
||||
try:
|
||||
review_info = json.loads(line)
|
||||
except Exception:
|
||||
if VERBOSE:
|
||||
print(output)
|
||||
raise(CannotParseOpenChangesets, sys.exc_info()[1])
|
||||
|
||||
if 'type' in review_info:
|
||||
break
|
||||
|
||||
review_list.append([review_info[f] for f in REVIEW_FIELDS])
|
||||
for i in FIELDS:
|
||||
review_field_width[i] = max(
|
||||
review_field_width[i],
|
||||
len(review_info[REVIEW_FIELDS[i]])
|
||||
)
|
||||
review_list = [[r[f] for f in REVIEW_FIELDS] for r in reviews]
|
||||
review_field_width = dict()
|
||||
for i in FIELDS:
|
||||
review_field_width[i] = max(len(r[i]) for r in review_list)
|
||||
|
||||
review_field_format = " ".join([
|
||||
review_field_color[i] +
|
||||
@ -713,7 +792,7 @@ def list_reviews(remote):
|
||||
for (width, value) in zip(review_field_width, review_value):
|
||||
formatted_fields.extend([width, value])
|
||||
print(review_field_format % tuple(formatted_fields))
|
||||
print("Found %d items for review" % review_info['rowCount'])
|
||||
print("Found %d items for review" % len(reviews))
|
||||
|
||||
return 0
|
||||
|
||||
@ -763,53 +842,26 @@ class ResetHardFailed(CommandFailed):
|
||||
|
||||
def fetch_review(review, masterbranch, remote):
|
||||
remote_url = get_remote_url(remote)
|
||||
(hostname, username, port, project_name) = \
|
||||
parse_gerrit_ssh_params_from_git_url(remote_url)
|
||||
|
||||
if port is not None:
|
||||
port = "-p %s" % port
|
||||
else:
|
||||
port = ""
|
||||
if username is None:
|
||||
userhost = hostname
|
||||
else:
|
||||
userhost = "%s@%s" % (username, hostname)
|
||||
|
||||
review_arg = review
|
||||
patchset_opt = '--current-patch-set'
|
||||
|
||||
review, patchset_number = parse_review_number(review)
|
||||
if patchset_number is not None:
|
||||
patchset_opt = '--patch-sets'
|
||||
current_patch_set = patchset_number is None
|
||||
|
||||
review_info = None
|
||||
output = run_command_exc(
|
||||
CannotQueryPatchSet,
|
||||
"ssh", "-x", port, userhost,
|
||||
"gerrit", "query",
|
||||
"--format=JSON %s change:%s" % (patchset_opt, review))
|
||||
review_infos = query_reviews(remote_url,
|
||||
change=review,
|
||||
current_patch_set=current_patch_set,
|
||||
exception=CannotQueryPatchSet,
|
||||
parse_exc=ReviewInformationNotFound)
|
||||
|
||||
review_jsons = output.split("\n")
|
||||
found_review = False
|
||||
for review_json in review_jsons:
|
||||
try:
|
||||
review_info = json.loads(review_json)
|
||||
found_review = True
|
||||
except Exception:
|
||||
pass
|
||||
if found_review:
|
||||
break
|
||||
if not found_review:
|
||||
if VERBOSE:
|
||||
print(output)
|
||||
if not len(review_infos):
|
||||
raise ReviewInformationNotFound(review)
|
||||
review_info = review_infos[0]
|
||||
|
||||
try:
|
||||
if patchset_number is None:
|
||||
refspec = review_info['currentPatchSet']['ref']
|
||||
else:
|
||||
refspec = [ps for ps
|
||||
in review_info['patchSets']
|
||||
refspec = [ps for ps in review_info['patchSets']
|
||||
if ps['number'] == patchset_number][0]['ref']
|
||||
except IndexError:
|
||||
raise PatchSetNotFound(review_arg)
|
||||
|
@ -148,7 +148,3 @@ class GitReviewTestCase(tests.BaseGitReviewTestCase):
|
||||
|
||||
class HttpGitReviewTestCase(tests.HttpMixin, GitReviewTestCase):
|
||||
"""Class for the git-review tests over HTTP(S)."""
|
||||
|
||||
def test_git_review_d(self):
|
||||
self.skipTest("git review -d uses fetch_review "
|
||||
"which does not support http remote")
|
||||
|
Loading…
x
Reference in New Issue
Block a user