Remove libraries and cleanup tsdr
[integration/test.git] / tools / distchanges / gerritquery.py
index aa0ae59c2d9c0a070665dc1577713be5ebbef439..215f3b5e0b2d855437db49a9add6ead468440ed7 100644 (file)
@@ -3,6 +3,7 @@ This module contains functions to manipulate gerrit queries.
 """
 import datetime
 import json
+import logging
 import os
 import re
 import shlex
@@ -11,7 +12,7 @@ import traceback
 import sys
 
 # TODO: Haven't tested python 3
-if sys.version < '3':
+if sys.version < "3":
     import urllib
     import urlparse
 
@@ -29,6 +30,9 @@ else:
     do_input = input
 
 
+logger = logging.getLogger("changes.gerritquery")
+
+
 class GitReviewException(Exception):
     EXIT_CODE = 127
 
@@ -39,29 +43,31 @@ class CommandFailed(GitReviewException):
     def __init__(self, *args):
         Exception.__init__(self, *args)
         (self.rc, self.output, self.argv, self.envp) = args
-        self.quickmsg = dict([
-            ("argv", " ".join(self.argv)),
-            ("rc", self.rc),
-            ("output", self.output)])
+        self.quickmsg = dict(
+            [("argv", " ".join(self.argv)), ("rc", self.rc), ("output", self.output)]
+        )
 
     def __str__(self):
-        return self.__doc__ + """
+        return (
+            self.__doc__
+            + """
 The following command failed with exit code %(rc)d
     "%(argv)s"
 -----------------------
 %(output)s
------------------------""" % self.quickmsg
+-----------------------"""
+            % self.quickmsg
+        )
 
 
 class GerritQuery:
-    REMOTE_URL = 'ssh://git.opendaylight.org:29418'
-    BRANCH = 'master'
+    REMOTE_URL = "ssh://git.opendaylight.org:29418"
+    BRANCH = "master"
     QUERY_LIMIT = 50
 
     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
@@ -69,39 +75,42 @@ class GerritQuery:
         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:
-            # just print(string) could still throw a UnicodeEncodeError sometimes so casting string to unicode
-            print(unicode(string))
-        else:
-            print(string.encode(sys.stdout.encoding, 'replace'))
+        try:
+            # FIXME: Python3 does not have 'unicode'
+            if isinstance(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 Exception:
+            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):
-                argv = shlex.split(argv[0].encode('utf-8'))
+                argv = shlex.split(argv[0].encode("utf-8"))
             else:
                 argv = shlex.split(str(argv[0]))
-        stdin = kwargs.pop('stdin', None)
+        stdin = kwargs.pop("stdin", None)
         newenv = os.environ.copy()
-        newenv['LANG'] = 'C'
-        newenv['LANGUAGE'] = 'C'
+        newenv["LANG"] = "C"
+        newenv["LANGUAGE"] = "C"
         newenv.update(kwargs)
-        p = subprocess.Popen(argv,
-                             stdin=subprocess.PIPE if stdin else None,
-                             stdout=subprocess.PIPE,
-                             stderr=subprocess.STDOUT,
-                             env=newenv)
+        p = subprocess.Popen(
+            argv,
+            stdin=subprocess.PIPE if stdin else None,
+            stdout=subprocess.PIPE,
+            stderr=subprocess.STDOUT,
+            env=newenv,
+        )
         (out, nothing) = p.communicate(stdin)
-        out = out.decode('utf-8', 'replace')
+        out = out.decode("utf-8", "replace")
         return p.returncode, out.strip()
 
     def run_command(self, *argv, **kwargs):
@@ -171,8 +180,12 @@ class GerritQuery:
         :param str request: A gerrit query
         :return unicode: The JSON response
         """
-        (hostname, username, port, project_name) = \
-            self.parse_gerrit_ssh_params_from_git_url()
+        (
+            hostname,
+            username,
+            port,
+            project_name,
+        ) = self.parse_gerrit_ssh_params_from_git_url()
 
         port_data = "p%s" % port if port is not None else ""
         if username is None:
@@ -180,17 +193,24 @@ class GerritQuery:
         else:
             userhost = "%s@%s" % (username, hostname)
 
-        if self.verbose >= 2:
-            print("gerrit request %s %s" % (self.remote_url, request))
+        logger.debug("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)
+            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, status=None, comments=False):
+    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.
 
@@ -200,15 +220,27 @@ class GerritQuery:
         :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 " \
-                "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:
@@ -231,38 +263,44 @@ class GerritQuery:
             if line and line[0] == "{":
                 try:
                     data = json.loads(line)
-                    parsed['id'] = data['id']
-                    parsed['number'] = data['number']
-                    parsed['subject'] = data['subject']
-                    parsed['url'] = data['url']
-                    parsed['lastUpdated'] = data['lastUpdated']
-                    parsed['grantedOn'] = 0
+                    parsed["id"] = data["id"]
+                    parsed["number"] = data["number"]
+                    parsed["subject"] = data["subject"]
+                    parsed["url"] = data["url"]
+                    parsed["lastUpdated"] = data["lastUpdated"]
+                    parsed["grantedOn"] = 0
                     if "patchSets" in data:
-                        patch_sets = data['patchSets']
+                        patch_sets = data["patchSets"]
                         for patch_set in reversed(patch_sets):
                             if "approvals" in patch_set:
-                                approvals = patch_set['approvals']
+                                approvals = patch_set["approvals"]
                                 for approval in approvals:
-                                    if 'type' in approval and approval['type'] == 'SUBM':
-                                        parsed['grantedOn'] = approval['grantedOn']
+                                    if (
+                                        "type" in approval
+                                        and approval["type"] == "SUBM"
+                                    ):
+                                        parsed["grantedOn"] = approval["grantedOn"]
                                         break
-                                if parsed['grantedOn'] != 0:
+                                if parsed["grantedOn"] != 0:
                                     break
                     if "comments" in data:
-                        comments = data['comments']
+                        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
+                                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
 
@@ -276,17 +314,28 @@ class GerritQuery:
         :return list: Lines of the JSON
         """
         lines = []
-        for line in changes.split("\n"):
-            if line.find('"type":"error","message"') != -1:
-                print("there was a query error")
-                continue
-            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, status=None, comments=False):
+    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.
 
@@ -302,15 +351,37 @@ class GerritQuery:
         :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, status, comments)
+        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