在本系列的第二部分中 ,您了解了如何从git日志中收集提交信息,以及如何向从项目成员列表中选择的随机开发者发送审阅请求。
在这一部分中,您将看到如何保存代码检查信息以在每次运行代码调度程序时进行后续操作。 您还将看到如何阅读电子邮件以检查审阅者是否已回复审阅请求。
入门
首先从教程系列的第二部分克隆源代码。
git clone https://github.com/royagasthyan/CodeReviewer-Part2 CodeReviewer
修改config.json
文件,使其包含一些相关的电子邮件地址,并保留royagasthyan@gmail.com
电子邮件地址。 这是因为git具有与特定电子邮件地址相关的提交,该代码是代码按预期执行所必需的。 修改schedule.py
文件中的SMTP
凭据:
FROM_EMAIL = "your_email_address@gmail.com"
FROM_PWD = "your_password"
导航到项目目录CodeReviewer
并尝试在终端中执行以下命令。
python scheduler.py -n 20 -p "project_x"
它应该将代码审查请求发送给随机开发人员进行审查。
保留审查请求信息
要跟踪审阅请求信息,您需要将其保留在某处以供参考。 您可以选择将代码检查请求信息保留在何处。 它可以是任何数据库,也可以是文件。 为了本教程的缘故,我们将审阅请求信息保留在reviewer.json
文件中。 每次运行调度程序时,它将检查信息文件以跟进尚未响应的审阅请求。
创建一个名为save_review_info
的方法,该方法会将审阅请求信息保存在文件中。 在save_review_info
方法内,创建一个带有审阅者,主题和唯一ID的info
对象。
def save_review_info(reviewer, subject):
info = {'reviewer':reviewer,'subject':subject,'id':str(uuid.uuid4()),'sendDate':str(datetime.date.today())}
对于唯一ID,请导入uuid
Python模块。
import uuid
您还需要datetime
Python模块来获取当前日期。 导入datetime
Python模块。
import datetime
如果程序不存在,则需要在程序启动时初始化reviewer.json
文件。
if not os.path.exists('reviewer.json'):
with open('reviewer.json','w+') as outfile:
json.dump([],outfile)
如果该文件不存在,则需要创建一个名为reviewer.json
的文件,并用一个空的JSON数组填充该文件,如上面的代码所示。
每次发送审阅请求时,都会调用此方法。 因此,在save_review_info
方法内部,以读取模式打开reviewer.json
文件并读取内容。 将新的内容信息附加到现有内容中,然后将其写回到reviewer.json
文件。 代码如下所示:
def save_review_info(reviewer, subject):
info = {'reviewer':reviewer,'subject':subject,'id':str(uuid.uuid4()),'sendDate':str(datetime.date.today())}
with open('reviewer.json','r') as infile:
review_data = json.load(infile)
review_data.append(info)
with open('reviewer.json','w') as outfile:
json.dump(review_data,outfile)
在schedule_review_request
方法内部,在发送代码审阅请求邮件之前,调用save_review_info
方法以保存审阅信息。
def schedule_review_request(commits):
date = time.strftime("%Y-%m-%d")
for commit in commits:
reviewer = select_reviewer(commit.Author, project_members)
subject = date + " Code Review [commit:" + commit.Id + "]"
body = "Hello '" + reviewer + "', you have been selected to review the code for commit\n"
body += "done by '" + commit.Author + "'.\n"
body += "\n"
body += format_review_commit(commit)
save_review_info(reviewer,subject);
send_email(reviewer,subject,body)
保存以上更改并执行调度程序。 调度程序运行后,您应该能够在项目目录中查看带有代码审阅请求信息的reviewer.json
文件。 外观如下:
[{
"reviewer": "samson1987@gmail.com",
"id": "8ca7da84-9da7-4a17-9843-be293ea8202c",
"sendDate": "2017-02-24",
"subject": "2017-02-24 Code Review [commit:16393106c944981f57b2b48a9180a33e217faacc]"
}, {
"reviewer": "roshanjames@gmail.com",
"id": "68765291-1891-4b50-886e-e30ab41a8810",
"sendDate": "2017-02-24",
"subject": "2017-02-24 Code Review [commit:04d11e21fb625215c5e672a93d955f4a176e16e4]"
}]
读取电子邮件数据
您已经收集了所有代码审查请求信息,并将其保存在reviewer.json
文件中。 现在,每次运行调度程序时,您都需要检查您的邮件收件箱,以查看审阅者是否已响应代码审阅请求。 因此,首先您需要定义一种读取Gmail收件箱的方法。
创建一个名为read_email
的方法,该方法需要将天数作为参数来检查收件箱。 您将利用imaplib
Python模块读取电子邮件收件箱。 导入imaplib
Python模块:
import imaplib
要使用imaplib
模块阅读电子邮件,首先需要创建服务器。
email_server = imaplib.IMAP4_SSL(SERVER)
使用电子邮件地址和密码登录到服务器:
email_server.login(FROM_EMAIL,FROM_PWD)
登录后,选择收件箱以阅读电子邮件:
email_server.select('inbox')
自从发送代码审查请求以来,您将阅读过去n天的电子邮件。 导入timedelta
Python模块。
import timedelta
创建电子邮件日期,如下所示:
email_date = datetime.date.today() - timedelta(days=num_days)
formatted_date = email_date.strftime('%d-%b-%Y')
使用formatted_date
,在电子邮件服务器中搜索电子邮件。
typ, data = email_server.search(None, '(SINCE "' + formatted_date + '")')
它将返回每封电子邮件的唯一ID,并使用唯一ID可以获取电子邮件详细信息。
ids = data[0]
id_list = ids.split()
first_email_id = int(id_list[0])
last_email_id = int(id_list[-1])
现在,您将使用first_email_id
和last_email_id
遍历电子邮件,并获取主题和电子邮件的“ last_email_id
”地址。
for i in range(last_email_id,first_email_id, -1):
typ, data = email_server.fetch(i, '(RFC822)' )
data
将包含电子邮件内容,因此请迭代数据部分并检查元组。 您将利用电子邮件Python模块提取详细信息。 因此,导入email
Python模块。
import email
您可以提取电子邮件主题和“发件人”地址,如下所示:
for response_part in data:
if isinstance(response_part, tuple):
msg = email.message_from_string(response_part[1])
print 'From: ' + msg['from']
print '\n'
print 'Subject: ' + msg['subject']
print '\n'
print '------------------------------------------------'
这是完整的read_email
方法:
def read_email(num_days):
try:
email_server = imaplib.IMAP4_SSL(SERVER)
email_server.login(FROM_EMAIL,FROM_PWD)
email_server.select('inbox')
email_date = datetime.date.today() - timedelta(days=num_days)
formatted_date = email_date.strftime('%d-%b-%Y')
typ, data = email_server.search(None, '(SINCE "' + formatted_date + '")')
ids = data[0]
id_list = ids.split()
first_email_id = int(id_list[0])
last_email_id = int(id_list[-1])
for i in range(last_email_id,first_email_id, -1):
typ, data = email_server.fetch(i, '(RFC822)' )
for response_part in data:
if isinstance(response_part, tuple):
msg = email.message_from_string(response_part[1])
print 'From: ' + msg['from']
print '\n'
print 'Subject: ' + msg['subject']
print '\n'
print '------------------------------------------------'
except Exception, e:
print str(e)
保存以上更改,然后尝试运行以上的read_email
方法:
read_email(1)
它应该在终端上打印电子邮件主题和“发件人”地址。

现在,让我们将“ email_info
”地址和主题收集到email_info
列表中并返回数据。
email_info = []
而不是打印主题和“ email_info
”地址,而是将数据附加到email_info
列表并返回email_info
列表。
email_info.append({'From':msg['from'],'Subject':msg['subject'].replace("\r\n","")})
这是修改后的read_email
方法:
def read_email(num_days):
try:
email_info = []
email_server = imaplib.IMAP4_SSL(SERVER)
email_server.login(FROM_EMAIL,FROM_PWD)
email_server.select('inbox')
email_date = datetime.date.today() - timedelta(days=num_days)
formatted_date = email_date.strftime('%d-%b-%Y')
typ, data = email_server.search(None, '(SINCE "' + formatted_date + '")')
ids = data[0]
id_list = ids.split()
first_email_id = int(id_list[0])
last_email_id = int(id_list[-1])
for i in range(last_email_id,first_email_id, -1):
typ, data = email_server.fetch(i, '(RFC822)' )
for response_part in data:
if isinstance(response_part, tuple):
msg = email.message_from_string(response_part[1])
email_info.append({'From':msg['from'],'Subject':msg['subject'].replace("\r\n","")})
except Exception, e:
print str(e)
return email_info
添加日志记录以进行错误处理
错误处理是软件开发的重要方面。 在调试阶段跟踪错误非常有用。 如果您没有错误处理,那么很难跟踪错误。 由于您正在使用两种新方法,因此我认为现在是向调度程序代码添加错误处理的正确时机。
要开始进行错误处理,您将需要logging
Python模块和RotatingFileHandler
类。 如图所示导入它们:
import logging
from logging.handlers import RotatingFileHandler
获得所需的导入后,请如下所示初始化记录器:
logger = logging.getLogger("Code Review Log")
logger.setLevel(logging.INFO)
在上面的代码中,您初始化了记录器并将日志级别设置为INFO。
创建一个旋转文件日志处理程序,该日志处理程序将在每次日志文件达到最大大小时创建一个新文件。
logHandler = RotatingFileHandler('app.log',maxBytes=3000,backupCount=2)
将logHandler
附加到logger
对象。
logger.addHandler(logHandler)
让我们添加错误记录器以在捕获异常时记录错误。 在read_email
方法的异常部分中,添加以下代码:
logger.error(str(datetime.datetime.now()) + " - Error while reading mail : " + str(e) + "\n")
logger.exception(str(e))
第一行将错误消息以及当前日期和时间记录到日志文件中。 第二行将堆栈跟踪记录到错误中。
同样,您可以将错误处理添加到代码的主要部分。 这是带有错误处理的代码的外观:
try:
commits = process_commits()
if len(commits) == 0:
print 'No commits found '
else:
schedule_review_request(commits)
except Exception,e:
print 'Error occurred. Check log for details.'
logger.error(str(datetime.datetime.now()) + " - Error while reading mail : " + str(e) + "\n")
logger.exception(str(e))
包起来
在本系列的这一部分中,您将审阅请求信息搁置在reviewer.json
文件中。 您还创建了一种读取电子邮件的方法。 您将使用这两个功能来跟踪本系列最后一部分中的代码审查请求。
此外,不要犹豫,看看我们在市场上有哪些可供出售和研究的东西 ,也不要犹豫,使用下面的提要来问任何问题并提供宝贵的反馈。
该教程的源代码可在GitHub上获得 。
请在下面的评论中告诉我们您的想法和建议。