From e3921427658266d41b5279b110b42264fdbadb2e Mon Sep 17 00:00:00 2001
From: Doug Hellmann <doug@doughellmann.com>
Date: Mon, 30 Apr 2018 13:14:01 -0400
Subject: [PATCH] add 'changes query' command

Change-Id: I305220c459a3c88d23b425df7fbdd700eddae786
Signed-off-by: Doug Hellmann <doug@doughellmann.com>
---
 goal_tools/gerrit.py             | 23 +++++++-
 goal_tools/who_helped/changes.py | 99 ++++++++++++++++++++++++++++++++
 setup.cfg                        |  2 +
 3 files changed, 121 insertions(+), 3 deletions(-)
 create mode 100644 goal_tools/who_helped/changes.py

diff --git a/goal_tools/gerrit.py b/goal_tools/gerrit.py
index 6f3aed4..9b3922c 100644
--- a/goal_tools/gerrit.py
+++ b/goal_tools/gerrit.py
@@ -145,6 +145,24 @@ class Review:
             )
 
 
+def cache_review(review_id, data, cache):
+    """Add a review to the cache.
+
+    Review data is only cached if the review is MERGED because
+    otherwise it is more likely to change.
+
+    :param review_id: Review ID of the review to look for.
+    :type review_id: str
+    :param data: Data structure returned by query_gerrit
+    :type data: dict
+    :param cache: Storage for repeated lookups.
+    :type cache: goal_tools.cache.Cache
+
+    """
+    if data['status'] == 'MERGED':
+        cache[('review', str(review_id))] = data
+
+
 def fetch_review(review_id, cache):
     """Find the review in the cache or look it up in the API.
 
@@ -157,7 +175,7 @@ def fetch_review(review_id, cache):
     :type cache: goal_tools.cache.Cache
 
     """
-    key = ('review', review_id)
+    key = ('review', str(review_id))
     if key in cache:
         LOG.debug('found %s cached', review_id)
         return Review(review_id, cache[key])
@@ -168,6 +186,5 @@ def fetch_review(review_id, cache):
         },
     )
     response = Review(review_id, data)
-    if response.is_merged:
-        cache[key] = data
+    cache_review(review_id, data, cache)
     return response
diff --git a/goal_tools/who_helped/changes.py b/goal_tools/who_helped/changes.py
new file mode 100644
index 0000000..8865bdf
--- /dev/null
+++ b/goal_tools/who_helped/changes.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python3
+
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import logging
+
+from cliff import command
+
+from goal_tools import gerrit
+from goal_tools import governance
+
+LOG = logging.getLogger(__name__)
+
+
+class QueryChanges(command.Command):
+    "Query gerrit for a set of changes and build a review ID file."
+
+    def get_parser(self, prog_name):
+        parser = super().get_parser(prog_name)
+        parser.add_argument(
+            '--governance-project-list',
+            default=governance.PROJECTS_LIST,
+            help='location of governance project list',
+        )
+        parser.add_argument(
+            '--include-unofficial',
+            default=False,
+            action='store_true',
+            help='include projects not under governance in the output',
+        )
+        parser.add_argument(
+            'query_string',
+            help='gerrit query string',
+        )
+        parser.add_argument(
+            'review_list',
+            help='name output file to create',
+        )
+        return parser
+
+    def take_action(self, parsed_args):
+        team_data = governance.get_team_data(
+            parsed_args.governance_project_list)
+
+        review_ids = []
+
+        offset = 0
+        while True:
+            changes = gerrit.query_gerrit(
+                'changes/',
+                params={
+                    'n': '100',
+                    'start': offset,
+                    'q': parsed_args.query_string,
+                    'o': gerrit.QUERY_OPTIONS,
+                },
+            )
+            LOG.debug('%d changes', len(changes))
+
+            for change in changes:
+                review = gerrit.Review(
+                    change['_number'],
+                    change,
+                )
+                team_name = governance.get_repo_owner(
+                    team_data, review.project)
+                if not parsed_args.include_unofficial and not team_name:
+                    LOG.debug(
+                        'filtered out %s based on repo governance status',
+                        change['project'],
+                    )
+                    continue
+
+                gerrit.cache_review(
+                    change['_number'],
+                    change,
+                    self.app.cache,
+                )
+                review_ids.append(change['_number'])
+
+            if changes and changes[-1].get('_more_changes', False):
+                offset += 100
+            else:
+                break
+
+        with open(parsed_args.review_list, 'w', encoding='utf-8') as f:
+            f.write('# QUERY: {}\n'.format(parsed_args.query_string))
+            for rid in review_ids:
+                f.write('{}\n'.format(rid))
diff --git a/setup.cfg b/setup.cfg
index 9b8c3f2..226915f 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -31,6 +31,8 @@ console_scripts =
 who_helped =
     contributions list = goal_tools.who_helped.contributions:ListContributions
     member show = goal_tools.who_helped.members:ShowMember
+	changes query = goal_tools.who_helped.changes:QueryChanges
+
 
 [wheel]
 universal = 1