blob: 7d0aec856a9581a6d4486aed8afe582b0b7f5519 [file] [log] [blame]
Hirthanan Subenderanb8402a12020-02-05 14:11:00 -08001#!/usr/bin/env python3
2# -*- coding: utf-8 -*-"
3#
4# Copyright 2020 The Chromium OS Authors. All rights reserved.
5# Use of this source code is governed by a BSD-style license that can be
6# found in the LICENSE file.
7
8"""Module containing methods interfacing with gerrit.
9
10i.e Create new bugfix change tickets, and reading metadata about a specific change.
Hirthanan Subenderan40368002020-03-10 15:36:48 -070011
12Example CURL command that creates CL:
13curl -b /home/chromeos_patches/.git-credential-cache/cookie \
14 --header "Content-Type: application/json" \
15 --data \
16 '{"project":"chromiumos/third_party/kernel",\
17 "subject":"test",\
18 "branch":"chromeos-4.19",\
19 "topic":"test_topic"}' https://chromium-review.googlesource.com/a/changes/
Hirthanan Subenderanb8402a12020-02-05 14:11:00 -080020"""
21
22from __future__ import print_function
Hirthanan Subenderanb8402a12020-02-05 14:11:00 -080023import json
Hirthanan Subenderan40368002020-03-10 15:36:48 -070024import http
Hirthanan Subenderan3f029112020-03-11 12:33:05 -070025import os
Hirthanan Subenderanc44a0b32020-03-11 22:34:39 -070026import requests
Hirthanan Subenderanb8402a12020-02-05 14:11:00 -080027
Hirthanan Subenderanc44a0b32020-03-11 22:34:39 -070028import common
Hirthanan Subenderan40368002020-03-10 15:36:48 -070029
30
31def get_auth_cookie():
32 """Load cookies in order to authenticate requests with gerrit/googlesource."""
33 # This cookie should exist on GCE in order to perform GAIA authenticated requests
Hirthanan Subenderanc44a0b32020-03-11 22:34:39 -070034 gerrit_credentials_cookies = http.cookiejar.MozillaCookieJar(common.GIT_COOKIE_PATH, None, None)
Hirthanan Subenderan40368002020-03-10 15:36:48 -070035 gerrit_credentials_cookies.load()
36 return gerrit_credentials_cookies
37
38def retrieve_and_parse_endpoint(endpoint_url):
39 """Retrieves Gerrit endpoint response and removes XSSI prefix )]}'"""
Hirthanan Subenderan40368002020-03-10 15:36:48 -070040 try:
Hirthanan Subenderan3f029112020-03-11 12:33:05 -070041 resp = requests.get(endpoint_url, cookies=get_auth_cookie())
42 resp.raise_for_status()
Hirthanan Subenderan40368002020-03-10 15:36:48 -070043 resp_json = json.loads(resp.text[5:])
Hirthanan Subenderan3f029112020-03-11 12:33:05 -070044 except requests.exceptions.HTTPError as e:
45 raise type(e)('Endpoint %s should have HTTP response 200' % endpoint_url) from e
Hirthanan Subenderan40368002020-03-10 15:36:48 -070046 except json.decoder.JSONDecodeError as e:
Hirthanan Subenderan3f029112020-03-11 12:33:05 -070047 raise ValueError('Response should contain json )]} prefix to prevent XSSI attacks') from e
Hirthanan Subenderan40368002020-03-10 15:36:48 -070048
49 return resp_json
Hirthanan Subenderanb8402a12020-02-05 14:11:00 -080050
Hirthanan Subenderan3f029112020-03-11 12:33:05 -070051def set_and_parse_endpoint(endpoint_url, payload):
52 """POST request to gerrit endpoint with specified payload."""
53 try:
54 resp = requests.post(endpoint_url, json=payload, cookies=get_auth_cookie())
55 resp.raise_for_status()
56 resp_json = json.loads(resp.text[5:])
57 except requests.exceptions.HTTPError as e:
58 raise type(e)('Endpoint %s should have HTTP response 200' % endpoint_url) from e
59 except json.decoder.JSONDecodeError as e:
60 raise ValueError('Response should contain json )]} prefix to prevent XSSI attacks') from e
61
62 return resp_json
Hirthanan Subenderanb8402a12020-02-05 14:11:00 -080063
Hirthanan Subenderanc44a0b32020-03-11 22:34:39 -070064
Hirthanan Subenderanb8402a12020-02-05 14:11:00 -080065def get_commit(changeid):
66 """Retrieves current commit message for a change.
67
68 May add some additional information to the fix patch for tracking purposes.
69 i.e attaching a tag
70 """
Hirthanan Subenderanc44a0b32020-03-11 22:34:39 -070071 get_commit_endpoint = os.path.join(common.CHROMIUM_REVIEW_BASEURL, 'changes',
Hirthanan Subenderan3f029112020-03-11 12:33:05 -070072 changeid, 'revisions/current/commit')
Hirthanan Subenderanc44a0b32020-03-11 22:34:39 -070073 resp = retrieve_and_parse_endpoint(get_commit_endpoint)
74
75 try:
76 return resp['message']
77 except KeyError as e:
78 raise type(e)('Gerrit API endpoint to get commit should contain message key') from e
Hirthanan Subenderanb8402a12020-02-05 14:11:00 -080079
80
Hirthanan Subenderan3f029112020-03-11 12:33:05 -070081def get_changeid_reviewers(changeid):
82 """Retrieves list of reviewer emails from gerrit given a chromeos changeid."""
Hirthanan Subenderanc44a0b32020-03-11 22:34:39 -070083 list_reviewers_endpoint = os.path.join(common.CHROMIUM_REVIEW_BASEURL, 'changes',
Hirthanan Subenderan3f029112020-03-11 12:33:05 -070084 changeid, 'reviewers')
85
86 resp = retrieve_and_parse_endpoint(list_reviewers_endpoint)
87
88 try:
89 return [reviewer_resp['email'] for reviewer_resp in resp]
90 except KeyError as e:
91 raise type(e)('Gerrit API endpoint to list reviewers should contain key email') from e
92
Hirthanan Subenderanc44a0b32020-03-11 22:34:39 -070093def set_reviewers(changeid, reviewer_emails):
Hirthanan Subenderan3f029112020-03-11 12:33:05 -070094 """Adds reviewers to a Gerrit CL."""
Hirthanan Subenderanc44a0b32020-03-11 22:34:39 -070095 add_reviewer_endpoint = os.path.join(common.CHROMIUM_REVIEW_BASEURL, 'changes',
Hirthanan Subenderan3f029112020-03-11 12:33:05 -070096 changeid, 'reviewers')
97
98 for email in reviewer_emails:
99 payload = {'reviewer': email}
100 set_and_parse_endpoint(add_reviewer_endpoint, payload)
Hirthanan Subenderanb8402a12020-02-05 14:11:00 -0800101
Hirthanan Subenderanb8402a12020-02-05 14:11:00 -0800102def get_change(changeid):
103 """Retrieves ChangeInfo from gerrit using its changeid"""
Hirthanan Subenderanc44a0b32020-03-11 22:34:39 -0700104 get_change_endpoint = os.path.join(common.CHROMIUM_REVIEW_BASEURL, 'changes',
105 changeid)
Hirthanan Subenderan40368002020-03-10 15:36:48 -0700106 return retrieve_and_parse_endpoint(get_change_endpoint)
Hirthanan Subenderanb8402a12020-02-05 14:11:00 -0800107
Hirthanan Subenderanc44a0b32020-03-11 22:34:39 -0700108def set_hashtag(changeid):
109 """Set hashtag to be autogenerated indicating a robot generated CL."""
110 set_hashtag_endpoint = os.path.join(common.CHROMIUM_REVIEW_BASEURL, 'changes',
111 changeid, 'hashtags')
112 hashtag_input_payload = {'add' : ['autogenerated']}
113 set_and_parse_endpoint(set_hashtag_endpoint, hashtag_input_payload)
Hirthanan Subenderanb8402a12020-02-05 14:11:00 -0800114
Hirthanan Subenderanc44a0b32020-03-11 22:34:39 -0700115
116# TODO(hirthanan) implement in seperate CL
117def generate_fix_message(fixer_upstream_message):
Hirthanan Subenderanb8402a12020-02-05 14:11:00 -0800118 """Generates new commit message for a fix change.
119
120 Use script ./contrib/from_upstream.py to generate new commit msg
121 Commit message should include essential information:
122 i.e:
123 FROMGIT, FROMLIST, ANDROID, CHROMIUM, etc.
124 commit message indiciating what is happening
125 BUG=...
126 TEST=...
127 tag for Fixes: <upstream-sha>
128 """
Hirthanan Subenderanc44a0b32020-03-11 22:34:39 -0700129 print(fixer_upstream_message)
130 commit_message = ''
131 return commit_message
132
133
134# Note: Stable patches won't have a fixee_change_id since they come into chromeos as merges
135def create_change(fixer_upstream_commit_message, branch, fixee_changeid=None):
136 """Creates a Patch in gerrit given a ChangeInput object."""
137 create_change_endpoint = os.path.join(common.CHROMIUM_REVIEW_BASEURL, 'changes')
138
139 change_input_payload = {'project': common.CHROMEOS_KERNEL_DIR,
140 'subject': generate_fix_message(fixer_upstream_commit_message),
141 'branch': common.chromeos_branch(branch)}
142
143 resp = set_and_parse_endpoint(create_change_endpoint, change_input_payload)
144
145 fixer_changeid = None
146 try:
147 fixer_changeid = resp['_number']
148 except KeyError as e:
149 raise type(e)('Gerrit API endpoint to create CL should contain key: _number') from e
150
151 reviewers = None
152 if fixee_changeid:
153 # retrieve reviewers from gerrit for the relevant change
154 reviewers = get_changeid_reviewers(fixee_changeid)
155 else:
156 # TODO(hirthanan): find relevant mailing list/reviewers
157 # For now we will assign it to a default user like Guenter?
158 # This is for stable bug fix patches that don't have a direct fixee changeid
159 # since groups of stable commits get merged as one changeid
160 reviewers = ['groeck@chromium.org']
161
162 set_reviewers(fixer_changeid, reviewers)
163 set_hashtag(fixer_changeid)
Hirthanan Subenderanb8402a12020-02-05 14:11:00 -0800164
165
166def create_gerrit_change(reviewers, commit_msg):
167 """Uses gerrit api to handle creating gerrit change.
168
169 Determines whether a change for a fix has already been created,
170 and avoids duplicate creations.
171
172 May add some additional information to the fix patch for tracking purposes.
173 i.e attaching a tag,
174 """
175
176 # Call gerrit api to create new change if neccessary
177 print('Calling gerrit api', reviewers, commit_msg)