GERRIT_PROJECT = os.getenv('GERRIT_PROJECT', 'fs/lustre-release')
GERRIT_BRANCH = os.getenv('GERRIT_BRANCH', 'master')
GERRIT_AUTH_PATH = os.getenv('GERRIT_AUTH_PATH', 'GERRIT_AUTH')
+GERRIT_CHANGE_NUMBER = os.getenv('GERRIT_CHANGE_NUMBER', None)
# GERRIT_AUTH should contain a single JSON dictionary of the form:
# {
# }
CHECKPATCH_PATHS = _getenv_list('CHECKPATCH_PATHS', ['checkpatch.pl'])
+CHECKPATCH_ARGS = os.getenv('CHECKPATCH_ARGS','--show-types -').split(' ')
CHECKPATCH_IGNORED_FILES = _getenv_list('CHECKPATCH_IGNORED_FILES', [
- 'lustre/contrib/wireshark/packet-lustre.c',
'lustre/ptlrpc/wiretest.c',
'lustre/utils/wiretest.c',
'*.patch'])
CHECKPATCH_IGNORED_KINDS = _getenv_list('CHECKPATCH_IGNORED_KINDS', [
+ 'LASSERT',
+ 'LCONSOLE',
'LEADING_SPACE'])
REVIEW_HISTORY_PATH = os.getenv('REVIEW_HISTORY_PATH', 'REVIEW_HISTORY')
STYLE_LINK = os.getenv('STYLE_LINK',
- 'https://wiki.hpdd.intel.com/display/PUB/Coding+Guidelines')
+ 'http://wiki.lustre.org/Lustre_Coding_Style_Guidelines')
USE_CODE_REVIEW_SCORE = False
path_comments = path_line_comments.setdefault(path, {})
line_comments = path_comments.setdefault(line, [])
- line_comments.append('(style) ' + message)
+ line_comments.append('(style) %s\n' % message)
warning_count[0] += 1
level = None # 'ERROR', 'WARNING'
'labels': {
'Code-Review': code_review_score
},
- 'comments': review_comments
+ 'comments': review_comments,
+ 'notify': 'OWNER',
}, score
else:
return {
'message': 'Looks good to me.',
'labels': {
'Code-Review': code_review_score
- }
+ },
+ 'notify': 'NONE',
}, score
self.post_enabled = True
self.post_interval = 10
self.update_interval = 300
+ self.request_timeout = 60
def _debug(self, msg, *args):
"""_"""
"""
url = self._url(path)
try:
- res = requests.get(url, auth=self.auth)
- except requests.exceptions.RequestException as exc:
+ res = requests.get(url, auth=self.auth,
+ timeout=self.request_timeout)
+ except Exception as exc:
self._error("cannot GET '%s': exception = %s", url, str(exc))
return None
try:
res = requests.post(url, data=data,
headers={'Content-Type': 'application/json'},
- auth=self.auth)
- except requests.exceptions.RequestException as exc:
+ auth=self.auth, timeout=self.request_timeout)
+ except Exception as exc:
self._error("cannot POST '%s': exception = %s", url, str(exc))
return False
"""
return change_id + ' ' + revision in self.history
+ def get_change_by_id(self, change_id):
+ """
+ GET one change by id.
+ """
+ path = ('/changes/' + urllib.quote(self.project, safe='') + '~' +
+ urllib.quote(self.branch, safe='') + '~' + change_id +
+ '?o=CURRENT_REVISION')
+ res = self._get(path)
+ if not res:
+ return None
+
+ # Gerrit uses " )]}'" to guard against XSSI.
+ return json.loads(res.content[5:])
+
def get_changes(self, query):
"""
GET a list of ChangeInfo()s for all changes matching query.
'&o=CURRENT_REVISION')
res = self._get(path)
if not res:
- return None
+ return []
# Gerrit uses " )]}'" to guard against XSSI.
return json.loads(res.content[5:])
return self.decode_patch(res.content)
- def set_review(self, change, revision, review_input):
+ def post_review(self, change, revision, review_input):
"""
POST review_input for the given revision of change.
"""
path = '/changes/' + change['id'] + '/revisions/' + revision + '/review'
- self._debug("set_review: path = '%s'", path)
+ self._debug("post_review: path = '%s'", path)
return self._post(path, review_input)
def check_patch(self, patch):
warning_count = [0]
for path in CHECKPATCH_PATHS:
- pipe = subprocess.Popen([path, '--show-types', '-'],
+ pipe = subprocess.Popen([path] + CHECKPATCH_ARGS,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
return review_input_and_score(path_line_comments, warning_count)
- def review_change(self, change, force=False):
+ def change_needs_review(self, change):
"""
- Review the current revision of change.
* Bail if the change isn't open (status is not 'NEW').
- * GET the current revision from gerrit.
- * Bail if we've already reviewed it (unless force is True).
- * Pipe the patch through checkpatch(es).
- * Save results to review history.
- * POST review to gerrit.
+ * Bail if we've already reviewed the current revision.
"""
- self._debug("review_change: change = %s, subject = '%s'",
- change['id'], change.get('subject', ''))
-
status = change.get('status')
if status != 'NEW':
- self._debug("review_change: status = %s", status)
+ self._debug("change_needs_review: status = %s", status)
return False
current_revision = change.get('current_revision')
- self._debug("review_change: current_revision = '%s'", current_revision)
+ self._debug("change_needs_review: current_revision = '%s'",
+ current_revision)
if not current_revision:
return False
# Have we already checked this revision?
- if self.in_history(change['id'], current_revision) and not force:
- self._debug("review_change: already reviewed")
+ if self.in_history(change['id'], current_revision):
+ self._debug("change_needs_review: already reviewed")
return False
+ return True
+
+ def review_change(self, change):
+ """
+ Review the current revision of change.
+ * Pipe the patch through checkpatch(es).
+ * Save results to review history.
+ * POST review to gerrit.
+ """
+ self._debug("review_change: change = %s, subject = '%s'",
+ change['id'], change.get('subject', ''))
+
+ current_revision = change.get('current_revision')
+ self._debug("change_needs_review: current_revision = '%s'",
+ current_revision)
+ if not current_revision:
+ return
+
patch = self.get_patch(change, current_revision)
if not patch:
self._debug("review_change: no patch")
- return False
+ return
review_input, score = self.check_patch(patch)
self._debug("review_change: score = %d", score)
self.write_history(change['id'], current_revision, score)
- self.set_review(change, current_revision, review_input)
- # Don't POST more than every post_interval seconds.
- time.sleep(self.post_interval)
+ self.post_review(change, current_revision, review_input)
def update(self):
"""
self._debug("update: got %d open_changes", len(open_changes))
for change in open_changes:
- self.review_change(change)
+ if self.change_needs_review(change):
+ self.review_change(change)
+ # Don't POST more than every post_interval seconds.
+ time.sleep(self.post_interval)
self.timestamp = new_timestamp
self.write_history('-', '-', 0)
+ def update_single_change(self, change):
+
+ self.load_history()
+
+ open_changes = self.get_changes({'status':'open',
+ 'change':change})
+ self._debug("update: got %d open_changes", len(open_changes))
+
+ for change in open_changes:
+ if self.change_needs_review(change):
+ self.review_change(change)
+
def run(self):
"""
* Load review history.
def main():
"""_"""
- logging.basicConfig(level=logging.DEBUG)
+ logging.basicConfig(format='%(asctime)s %(message)s', level=logging.DEBUG)
with open(GERRIT_AUTH_PATH) as auth_file:
auth = json.load(auth_file)
reviewer = Reviewer(GERRIT_HOST, GERRIT_PROJECT, GERRIT_BRANCH,
username, password, REVIEW_HISTORY_PATH)
- reviewer.run()
+
+ if GERRIT_CHANGE_NUMBER:
+ reviewer.update_single_change(GERRIT_CHANGE_NUMBER)
+ else:
+ reviewer.run()
if __name__ == "__main__":