Ignore any non gerrit lines
[integration/test.git] / tools / distchanges / gerritquery.py
index e46756f78121f9c41826862c72808e9d13ba0370..b6cddc5cdb22fd526cab938ec18994779f6609b8 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
@@ -10,11 +11,11 @@ import subprocess
 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
@@ -22,12 +23,16 @@ if sys.version < '3':
 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
 
@@ -60,7 +65,6 @@ class GerritQuery:
     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
@@ -68,21 +72,21 @@ 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:
+            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):
@@ -179,33 +183,44 @@ class GerritQuery:
         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):
@@ -229,6 +244,7 @@ class GerritQuery:
                     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):
@@ -238,14 +254,23 @@ class GerritQuery:
                                     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
 
@@ -259,17 +284,17 @@ 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):
+    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.
 
@@ -282,16 +307,29 @@ class GerritQuery:
         :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