findmissing: Created endpoint for bugfix CL creation

Implemented logic surrounding creating a bugfix CL in gerrit, finding
and attaching relevant reviewers, and assigning the CL a hashtag
'autogenerated' to indicate the patch robot created the CL.

BUG=None
TEST=None

Change-Id: I08d03b3c8cbd5707c73026c4682064ad7d7d7ac3
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/dev-util/+/2100291
Commit-Queue: Hirthanan Subenderan <hirthanan@google.com>
Tested-by: Hirthanan Subenderan <hirthanan@google.com>
Reviewed-by: Curtis Malainey <cujomalainey@chromium.org>
Reviewed-by: Guenter Roeck <groeck@chromium.org>
diff --git a/contrib/findmissing/gerrit_interface.py b/contrib/findmissing/gerrit_interface.py
index e491541..7d0aec8 100755
--- a/contrib/findmissing/gerrit_interface.py
+++ b/contrib/findmissing/gerrit_interface.py
@@ -22,16 +22,16 @@
 from __future__ import print_function
 import json
 import http
-import requests
 import os
+import requests
 
-from common import CHROMIUM_REVIEW_BASEURL, GIT_COOKIE_PATH
+import common
 
 
 def get_auth_cookie():
     """Load cookies in order to authenticate requests with gerrit/googlesource."""
     # This cookie should exist on GCE in order to perform GAIA authenticated requests
-    gerrit_credentials_cookies = http.cookiejar.MozillaCookieJar(GIT_COOKIE_PATH, None, None)
+    gerrit_credentials_cookies = http.cookiejar.MozillaCookieJar(common.GIT_COOKIE_PATH, None, None)
     gerrit_credentials_cookies.load()
     return gerrit_credentials_cookies
 
@@ -61,20 +61,26 @@
 
     return resp_json
 
+
 def get_commit(changeid):
     """Retrieves current commit message for a change.
 
     May add some additional information to the fix patch for tracking purposes.
     i.e attaching a tag
     """
-    get_commit_endpoint = os.path.join(CHROMIUM_REVIEW_BASEURL, 'changes',
+    get_commit_endpoint = os.path.join(common.CHROMIUM_REVIEW_BASEURL, 'changes',
                                         changeid, 'revisions/current/commit')
-    return retrieve_and_parse_endpoint(get_commit_endpoint)
+    resp = retrieve_and_parse_endpoint(get_commit_endpoint)
+
+    try:
+        return resp['message']
+    except KeyError as e:
+        raise type(e)('Gerrit API endpoint to get commit should contain message key') from e
 
 
 def get_changeid_reviewers(changeid):
     """Retrieves list of reviewer emails from gerrit given a chromeos changeid."""
-    list_reviewers_endpoint = os.path.join(CHROMIUM_REVIEW_BASEURL, 'changes',
+    list_reviewers_endpoint = os.path.join(common.CHROMIUM_REVIEW_BASEURL, 'changes',
                                         changeid, 'reviewers')
 
     resp = retrieve_and_parse_endpoint(list_reviewers_endpoint)
@@ -84,23 +90,31 @@
     except KeyError as e:
         raise type(e)('Gerrit API endpoint to list reviewers should contain key email') from e
 
-def set_changeid_reviewers(changeid, reviewer_emails):
+def set_reviewers(changeid, reviewer_emails):
     """Adds reviewers to a Gerrit CL."""
-    add_reviewer_endpoint = os.path.join(CHROMIUM_REVIEW_BASEURL, 'changes',
+    add_reviewer_endpoint = os.path.join(common.CHROMIUM_REVIEW_BASEURL, 'changes',
                                         changeid, 'reviewers')
 
     for email in reviewer_emails:
         payload = {'reviewer': email}
         set_and_parse_endpoint(add_reviewer_endpoint, payload)
 
-
 def get_change(changeid):
     """Retrieves ChangeInfo from gerrit using its changeid"""
-    get_change_endpoint = os.path.join(CHROMIUM_REVIEW_BASEURL, 'changes', changeid)
+    get_change_endpoint = os.path.join(common.CHROMIUM_REVIEW_BASEURL, 'changes',
+                                        changeid)
     return retrieve_and_parse_endpoint(get_change_endpoint)
 
+def set_hashtag(changeid):
+    """Set hashtag to be autogenerated indicating a robot generated CL."""
+    set_hashtag_endpoint = os.path.join(common.CHROMIUM_REVIEW_BASEURL, 'changes',
+                                        changeid, 'hashtags')
+    hashtag_input_payload = {'add' : ['autogenerated']}
+    set_and_parse_endpoint(set_hashtag_endpoint, hashtag_input_payload)
 
-def generate_fix_commit_message(old_changeid):
+
+# TODO(hirthanan) implement in seperate CL
+def generate_fix_message(fixer_upstream_message):
     """Generates new commit message for a fix change.
 
     Use script ./contrib/from_upstream.py to generate new commit msg
@@ -112,8 +126,41 @@
         TEST=...
         tag for Fixes: <upstream-sha>
     """
-    old_commit_msg = get_commit(old_changeid)
-    print(old_commit_msg)
+    print(fixer_upstream_message)
+    commit_message = ''
+    return commit_message
+
+
+# Note: Stable patches won't have a fixee_change_id since they come into chromeos as merges
+def create_change(fixer_upstream_commit_message, branch, fixee_changeid=None):
+    """Creates a Patch in gerrit given a ChangeInput object."""
+    create_change_endpoint = os.path.join(common.CHROMIUM_REVIEW_BASEURL, 'changes')
+
+    change_input_payload = {'project': common.CHROMEOS_KERNEL_DIR,
+                            'subject': generate_fix_message(fixer_upstream_commit_message),
+                            'branch': common.chromeos_branch(branch)}
+
+    resp = set_and_parse_endpoint(create_change_endpoint, change_input_payload)
+
+    fixer_changeid = None
+    try:
+        fixer_changeid = resp['_number']
+    except KeyError as e:
+        raise type(e)('Gerrit API endpoint to create CL should contain key: _number') from e
+
+    reviewers = None
+    if fixee_changeid:
+        # retrieve reviewers from gerrit for the relevant change
+        reviewers = get_changeid_reviewers(fixee_changeid)
+    else:
+        # TODO(hirthanan): find relevant mailing list/reviewers
+        # For now we will assign it to a default user like Guenter?
+        # This is for stable bug fix patches that don't have a direct fixee changeid
+        #  since groups of stable commits get merged as one changeid
+        reviewers = ['groeck@chromium.org']
+
+    set_reviewers(fixer_changeid, reviewers)
+    set_hashtag(fixer_changeid)
 
 
 def create_gerrit_change(reviewers, commit_msg):