170 lines
6.4 KiB
Python
170 lines
6.4 KiB
Python
#!/usr/bin/env python
|
|
#
|
|
# 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.
|
|
|
|
# This is designed to be called by a gerrit hook. It searched new
|
|
# patchsets for those from a first time commiter, then posts a helpful
|
|
# message welcoming them to the community and explaining the review process
|
|
#
|
|
# For example, this might be called as follows
|
|
# python welcome_message.py --change Ia1fea1eab3976f1a9cb89ceb3ce1c6c6a7e79c42
|
|
# --change-url \ https://review-dev.openstack.org/81 --project gtest-org/test \
|
|
# --branch master --uploader User A. Example (user@example.com) --commit \
|
|
# 05508ae633852469d2fd7786a3d6f1d06f87055b --patchset 1 patchset-merged \
|
|
# --ssh-user=user --ssh-key=/home/user/.ssh/id_rsa
|
|
# and if this was the first commit from "user@example.com", a message
|
|
# would be posted on review 81.
|
|
|
|
|
|
import argparse
|
|
import logging
|
|
import paramiko
|
|
|
|
import jeepyb.gerritdb
|
|
import jeepyb.log as l
|
|
|
|
logger = logging.getLogger('welcome_reviews')
|
|
|
|
|
|
def is_newbie(uploader):
|
|
"""Determine if the owner of the patch is a first-timer."""
|
|
|
|
# Retrieve uploader email
|
|
try:
|
|
searchkey = uploader[uploader.rindex("(") + 1:-1]
|
|
except ValueError:
|
|
logger.info('Couldnt get email for %s', uploader)
|
|
return False
|
|
|
|
# this query looks for all distinct patchsets for the given
|
|
# user. If there's only 1, they're a first-timer.
|
|
query = """SELECT COUNT(DISTINCT p.change_id + p.patch_set_id)
|
|
FROM patch_sets p, account_external_ids a
|
|
WHERE a.email_address = %s
|
|
AND a.account_id = p.uploader_account_id;"""
|
|
|
|
cursor = jeepyb.gerritdb.connect().cursor()
|
|
cursor.execute(query, searchkey)
|
|
data = cursor.fetchone()
|
|
if data:
|
|
if data[0] == 1:
|
|
logger.info('We found a newbie: %s', uploader)
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
|
|
def post_message(commit, gerrit_user, gerrit_ssh_key, message_file):
|
|
"""Post a welcome message on the patch set specified by the commit."""
|
|
|
|
default_text = """\
|
|
Congratulations, you've proposed your first change in OpenDev.
|
|
|
|
Your submission will now be tested automatically by Zuul, our gatekeeper,
|
|
and reviewed by other friendly developers. They will give you feedback and
|
|
may require you to refine it.
|
|
|
|
People seldom get their patch approved on the first try, so don't be
|
|
concerned if requested to make corrections. Feel free to modify your patch
|
|
and resubmit a new change-set.
|
|
|
|
Patches often take days (and sometimes weeks) to get reviewed, so be
|
|
patient. Don't hesitate to ask for help, and answer questions about your
|
|
work promptly if you can. The more you get to know reviewers and get to be
|
|
known by them, the smoother the review and approval process will become. The
|
|
fastest way to accomplish this is by reviewing other proposed changes
|
|
yourself: anybody can do it, and it's a great way to learn the code base.
|
|
|
|
Thanks again for participating in OpenDev, we look forward to seeing you
|
|
around.
|
|
|
|
Workflow Guide: https://docs.openstack.org/infra/manual/developers.html
|
|
"""
|
|
|
|
if message_file:
|
|
try:
|
|
with open(message_file, 'r') as _file:
|
|
welcome_text = _file.read()
|
|
except (OSError, IOError):
|
|
logger.exception("Could not open message file")
|
|
welcome_text = default_text
|
|
else:
|
|
welcome_text = default_text
|
|
|
|
# post the above message, using ssh.
|
|
command = ('gerrit review '
|
|
'--message="{message}" {commit}').format(
|
|
message=welcome_text,
|
|
commit=commit)
|
|
logger.info('Welcoming: %s', commit)
|
|
ssh = paramiko.SSHClient()
|
|
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
|
ssh.connect('localhost', username=gerrit_user,
|
|
key_filename=gerrit_ssh_key, port=29418)
|
|
stdin, stdout, stderr = ssh.exec_command(command)
|
|
stdout_text = stdout.read()
|
|
stderr_text = stderr.read()
|
|
ssh.close()
|
|
if stdout_text:
|
|
logger.debug('stdout: %s' % stdout_text)
|
|
if stderr_text:
|
|
logger.error('stderr: %s' % stderr_text)
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument('hook')
|
|
# common
|
|
parser.add_argument('--change', default=None)
|
|
parser.add_argument('--change-url', default=None)
|
|
parser.add_argument('--project', default=None)
|
|
parser.add_argument('--branch', default=None)
|
|
parser.add_argument('--commit', default=None)
|
|
parser.add_argument('--topic', default=None)
|
|
parser.add_argument('--change-owner', default=None)
|
|
# patchset-abandoned
|
|
parser.add_argument('--abandoner', default=None)
|
|
parser.add_argument('--reason', default=None)
|
|
# change-merged
|
|
parser.add_argument('--submitter', default=None)
|
|
parser.add_argument('--newrev', default=None)
|
|
# patchset-created
|
|
parser.add_argument('--uploader', default=None)
|
|
parser.add_argument('--patchset', default=None)
|
|
parser.add_argument('--is-draft', default=None)
|
|
parser.add_argument('--kind', default=None)
|
|
# for Welcome Message
|
|
parser.add_argument('--ssh-user', dest='ssh_user',
|
|
help='The gerrit welcome message user')
|
|
parser.add_argument('--ssh-key', dest='ssh_key',
|
|
help='The gerrit welcome message SSH key file')
|
|
parser.add_argument('--message-file', dest='message_file', default=None,
|
|
help='The gerrit welcome message')
|
|
# Don't actually post the message
|
|
parser.add_argument('--dryrun', dest='dryrun', action='store_true')
|
|
parser.add_argument('--no-dryrun', dest='dryrun', action='store_false')
|
|
parser.set_defaults(dryrun=False)
|
|
l.setup_logging_arguments(parser)
|
|
|
|
args = parser.parse_args()
|
|
|
|
l.configure_logging(args)
|
|
|
|
# they're a first-timer, post the message on 1st patchset
|
|
if is_newbie(args.uploader) and args.patchset == '1' and not args.dryrun:
|
|
post_message(args.commit, args.ssh_user, args.ssh_key,
|
|
args.message_file)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|