"""
import datetime
import json
+import logging
import os
import re
import shlex
import traceback
import sys
-
# TODO: Haven't tested python 3
if sys.version < '3':
import urllib
import urlparse
+
urlencode = urllib.urlencode
urljoin = urlparse.urljoin
urlparse = urlparse.urlparse
else:
import urllib.parse
import urllib.request
+
urlencode = urllib.parse.urlencode
urljoin = urllib.parse.urljoin
urlparse = urllib.parse.urlparse
do_input = input
+logger = logging.getLogger("changes.gerritquery")
+
+
class GitReviewException(Exception):
EXIT_CODE = 127
class CommandFailed(GitReviewException):
+ """Command Failure Analysis"""
def __init__(self, *args):
Exception.__init__(self, *args)
remote_url = REMOTE_URL
branch = BRANCH
query_limit = QUERY_LIMIT
- verbose = 0
def __init__(self, remote_url, branch, query_limit, verbose):
self.remote_url = remote_url
self.query_limit = query_limit
self.verbose = verbose
- def set_verbose(self, verbose):
- self.verbose = verbose
-
@staticmethod
def print_safe_encoding(string):
- if sys.stdout.encoding is None:
- print(string)
- else:
- print(string.encode(sys.stdout.encoding, 'replace'))
+ try:
+ if type(string) == unicode:
+ encoding = 'utf-8'
+ if hasattr(sys.stdout, 'encoding') and sys.stdout.encoding:
+ encoding = sys.stdout.encoding
+ return string.encode(encoding or 'utf-8', 'replace')
+ else:
+ return str(string)
+ except:
+ return str(string)
def run_command_status(self, *argv, **kwargs):
-
- if self.verbose >= 2:
- print(datetime.datetime.now(), "Running:", " ".join(argv))
+ logger.debug("%s Running: %s", datetime.datetime.now(), " ".join(argv))
if len(argv) == 1:
# for python2 compatibility with shlex
if sys.version_info < (3,) and isinstance(argv[0], unicode):
env=newenv)
(out, nothing) = p.communicate(stdin)
out = out.decode('utf-8', 'replace')
- return (p.returncode, out.strip())
+ return p.returncode, out.strip()
def run_command(self, *argv, **kwargs):
(rc, output) = self.run_command_status(*argv, **kwargs)
else:
username = None
port = None
- (hostname, path) = self.remote_url_url.split(":", 1)
+ (hostname, path) = self.remote_url.split(":", 1)
if "@" in hostname:
(username, hostname) = hostname.split("@", 1)
# name.
project_name = re.sub(r"^/|(\.git$)", "", path)
- return (hostname, username, port, project_name)
+ return hostname, username, port, project_name
def gerrit_request(self, request):
"""
else:
userhost = "%s@%s" % (username, hostname)
- if self.verbose >= 2:
- print("gerrit request %s %s" % (self.remote_url, request))
- output = self.run_command_exc(
- CommandFailed,
- "ssh", "-x" + port_data, userhost,
- request)
- if self.verbose >= 3:
- self.print_safe_encoding(output)
+ logger.debug("gerrit request %s %s" % (self.remote_url, request))
+ output = self.run_command_exc(CommandFailed, "ssh", "-x" + port_data, userhost, request)
+ if logger.isEnabledFor(logging.DEBUG):
+ logger.debug("%s", self.print_safe_encoding(output))
return output
- def make_gerrit_query(self, project, changeid=None, limit=1, msg=None):
+ def make_gerrit_query(self, project, changeid=None, limit=1, msg=None, status=None, comments=False, commitid=None):
"""
Make a gerrit query by combining the given options.
:param str project: The project to search
:param str changeid: A Change-Id to search
:param int limit: The number of items to return
- :param str msg: A commit-msg to search
+ :param str msg or None: A commit-msg to search
+ :param str status or None: The gerrit status, i.e. merged
+ :param bool comments: If true include comments
+ :param commitid: A commit hash to search
:return str: A gerrit query
"""
- query = "gerrit query --format=json limit:%d status:merged --all-approvals " \
- "project:%s branch:%s" \
- % (limit, project, self.branch)
+
+ if project == "odlparent" or project == "yangtools":
+ query = "gerrit query --format=json limit:%d " \
+ "project:%s" \
+ % (limit, project)
+ else:
+ query = "gerrit query --format=json limit:%d " \
+ "project:%s branch:%s" \
+ % (limit, project, self.branch)
if changeid:
query += " change:%s" % changeid
if msg:
- query += " message:%s" % msg
+ query += " message:{%s}" % msg
+ if commitid:
+ query += " commit:%s" % commitid
+ if status:
+ query += " status:%s --all-approvals" % status
+ if comments:
+ query += " --comments"
return query
def parse_gerrit(self, line, parse_exc=Exception):
parsed['subject'] = data['subject']
parsed['url'] = data['url']
parsed['lastUpdated'] = data['lastUpdated']
+ parsed['grantedOn'] = 0
if "patchSets" in data:
patch_sets = data['patchSets']
for patch_set in reversed(patch_sets):
if 'type' in approval and approval['type'] == 'SUBM':
parsed['grantedOn'] = approval['grantedOn']
break
- if parsed['grantedOn']:
+ if parsed['grantedOn'] != 0:
+ break
+ if "comments" in data:
+ comments = data['comments']
+ for comment in reversed(comments):
+ if "message" in comment and "timestamp" in comment:
+ message = comment['message']
+ timestamp = comment['timestamp']
+ if "Build Started" in message and "patch-test" in message:
+ parsed['grantedOn'] = timestamp
break
except Exception:
- if self.verbose:
- print("Failed to decode JSON: %s" % traceback.format_exc())
- self.print_safe_encoding(line)
+ logger.warn("Failed to decode JSON: %s", traceback.format_exc())
+ if logger.isEnabledFor(logging.DEBUG):
+ logger.warn(self.print_safe_encoding(line))
except Exception as err:
- print("Exception: %s" % traceback.format_exc())
+ logger.warn("Exception: %s", traceback.format_exc())
raise parse_exc(err)
return parsed
:return list: Lines of the JSON
"""
lines = []
- for line in changes.split("\n"):
- if line.find('stats') == -1:
+ skipped = 0
+ for i, line in enumerate(changes.split("\n")):
+ if line.find('"grantedOn":') != -1:
lines.append(line)
- if self.verbose >= 2:
- print("get_gerrit_lines: found %d lines" % len(lines))
+ else:
+ logger.debug("skipping: {}".format(line))
+ skipped += 1
+ logger.debug("get_gerrit_lines: found {} lines, skipped: {}".format(len(lines), skipped))
return lines
- def get_gerrits(self, project, changeid=None, limit=1, msg=None):
+ def get_gerrits(self, project, changeid=None, limit=1, msg=None, status=None, comments=False, commitid=None):
"""
Get a list of gerrits from gerrit query request.
:param str project: The project to search
:param str or None changeid: A Change-Id to search
:param int limit: The number of items to return
- :param str msg: A commit-msg to search
- :return str: A gerrit query
+ :param str or None msg: A commit-msg to search
+ :param str or None status: The gerrit status, i.e. merged
+ :param bool comments: If true include comments
+ :param commitid: A commit hash to search
+ :return str: List of gerrits sorted by merge time
"""
- query = self.make_gerrit_query(project, changeid, limit, msg)
+ logger.debug("get_gerrits: project: %s, changeid: %s, limit: %d, msg: %s, status: %s, comments: %s, " +
+ "commitid: %s",
+ project, changeid, limit, msg, status, comments, commitid)
+ query = self.make_gerrit_query(project, changeid, limit, msg, status, comments, commitid)
changes = self.gerrit_request(query)
lines = self.extract_lines_from_json(changes)
gerrits = []
+ sorted_gerrits = []
for line in lines:
gerrits.append(self.parse_gerrit(line))
from operator import itemgetter
- sorted_gerrits = sorted(gerrits, key=itemgetter('grantedOn'), reverse=True)
+ if gerrits is None:
+ logger.warn("No gerrits were found for %s", project)
+ return gerrits
+ try:
+ sorted_gerrits = sorted(gerrits, key=itemgetter('grantedOn'), reverse=True)
+ except KeyError as e:
+ logger.warn("KeyError exception in %s, %s", project, str(e))
return sorted_gerrits