Во второй части этой серии вы увидели, как собирать информацию о коммитах из журналов git и отправлять запросы на просмотр случайным разработчикам, выбранным из списка участников проекта.
В этой части вы узнаете, как сохранять информацию о проверке кода для отслеживания при каждом запуске планировщика кода. Вы также узнаете, как читать электронные письма, чтобы проверить, ответил ли рецензент на запрос о рецензировании.
Начиная
Начните с клонирования исходного кода из второй части серии руководств.
1
|
git clone https://github.com/royagasthyan/CodeReviewer-Part2 CodeReviewer
|
Измените файл config.json
включив в него некоторые соответствующие адреса электронной почты, оставив [email protected]
электронной почты [email protected]
. Это потому, что у git есть коммиты, связанные с конкретным адресом электронной почты, который требуется для того, чтобы код выполнялся как ожидалось Измените учетные данные SMTP
в файле schedule.py
:
1
2
|
FROM_EMAIL = «[email protected]»
FROM_PWD = «your_password»
|
Перейдите в каталог проекта CodeReviewer
и попробуйте выполнить следующую команду в терминале.
1
|
python scheduler.py -n 20 -p «project_x»
|
Он должен отправить запрос на проверку кода случайным разработчикам для проверки.
Хранение информации о запросе на проверку
Чтобы получить информацию о запросе на проверку, вам нужно хранить его где-нибудь для справки. Вы можете выбрать, где вы хотите хранить информацию о проверке кода. Это может быть любая база данных или файл. Для этого руководства мы будем хранить информацию о запросе на просмотр в файле reviewer.json
. Каждый раз, когда запускается планировщик, он проверяет информационный файл, чтобы отслеживать запросы на рецензирование, на которые не были получены ответы.
Создайте метод с именем save_review_info
который будет сохранять информацию запроса на просмотр в файле. Внутри метода save_review_info
создайте info
объект с рецензентом, субъектом и уникальным идентификатором.
1
2
|
def save_review_info(reviewer, subject):
info = {‘reviewer’:reviewer,’subject’:subject,’id’:str(uuid.uuid4()),’sendDate’:str(datetime.date.today())}
|
Для уникального идентификатора импортируйте модуль Python uuid
.
1
|
import uuid
|
Вам также понадобится Python-модуль datetime
чтобы получить текущую дату. Импортируйте модуль datetime
Python.
1
|
import datetime
|
Вам нужно инициализировать файл reviewer.json
при запуске программы, если он еще не существует.
1
2
3
|
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
. Вот как будет выглядеть код:
01
02
03
04
05
06
07
08
09
10
|
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
на save_review_info
метод save_review_info
для сохранения информации о проверке.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
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
в каталоге проекта с информацией о запросе на проверку кода. Вот как это будет выглядеть:
01
02
03
04
05
06
07
08
09
10
11
|
[{
«reviewer»: «[email protected]»,
«id»: «8ca7da84-9da7-4a17-9843-be293ea8202c»,
«sendDate»: «2017-02-24»,
«subject»: «2017-02-24 Code Review [commit:16393106c944981f57b2b48a9180a33e217faacc]»
}, {
«reviewer»: «[email protected]»,
«id»: «68765291-1891-4b50-886e-e30ab41a8810»,
«sendDate»: «2017-02-24»,
«subject»: «2017-02-24 Code Review [commit:04d11e21fb625215c5e672a93d955f4a176e16e4]»
}]
|
Чтение данных электронной почты
Вы собрали всю информацию о запросе проверки кода и сохранили ее в файле reviewer.json
. Теперь каждый раз, когда запускается планировщик, вам нужно проверять почтовый ящик, чтобы увидеть, ответил ли рецензент на запрос проверки кода. Итак, сначала вам нужно определить метод для чтения вашего почтового ящика Gmail.
Создайте метод read_email
который принимает количество дней, чтобы проверить входящие в качестве параметра. Вы будете использовать Python-модуль imaplib
для чтения почтового ящика. Импортируйте imaplib
Python imaplib
:
1
|
import imaplib
|
Чтобы прочитать письмо с imaplib
модуля imaplib
, вам сначала нужно создать сервер.
1
|
email_server = imaplib.IMAP4_SSL(SERVER)
|
Войдите на сервер, используя адрес электронной почты и пароль:
1
|
email_server.login(FROM_EMAIL,FROM_PWD)
|
После входа в систему выберите папку «Входящие», чтобы прочитать сообщения электронной почты:
1
|
email_server.select(‘inbox’)
|
Вы будете читать электронные письма в течение последних n дней с момента отправки запроса на проверку кода. Импортируйте timedelta
Python timedelta
.
1
|
import timedelta
|
Создайте дату электронной почты как показано:
1
2
|
email_date = datetime.date.today() — timedelta(days=num_days)
formatted_date = email_date.strftime(‘%d-%b-%Y’)
|
Используя formatted_date
, formatted_date
поиск сообщений на почтовом сервере.
1
|
typ, data = email_server.search(None, ‘(SINCE «‘ + formatted_date + ‘»)’)
|
Он будет возвращать уникальные идентификаторы для каждого электронного письма, и, используя уникальные идентификаторы, вы можете получить данные электронной почты.
1
2
3
4
5
6
|
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
чтобы перебирать электронные письма и извлекать тему и адрес «от» писем.
1
2
|
for i in range(last_email_id,first_email_id, -1):
typ, data = email_server.fetch(i, ‘(RFC822)’ )
|
data
будут содержать содержимое электронной почты, поэтому выполните итерацию части данных и проверьте наличие кортежа. Вы будете использовать почтовый модуль Python для извлечения деталей. Поэтому импортируйте email
модуль Python.
1
|
import email
|
Вы можете извлечь тему письма и адрес «от», как показано ниже:
1
2
3
4
5
6
7
8
|
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
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
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
:
1
|
read_email(1)
|
Он должен напечатать тему электронного письма и адрес «от» на терминале.
Теперь давайте соберем адрес «от» и тему в список email_info
и вернем данные.
1
|
email_info = []
|
Вместо того, чтобы печатать тему и адрес «от», добавьте данные в список email_info
и email_info
список email_info
.
1
|
email_info.append({‘From’:msg[‘from’],’Subject’:msg[‘subject’].replace(«\r\n»,»»)})
|
Вот модифицированный метод read_email
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
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
|
Добавление регистрации для обработки ошибок
Обработка ошибок является важным аспектом разработки программного обеспечения. Это действительно полезно на этапе отладки для отслеживания ошибок. Если у вас нет обработки ошибок, то становится очень сложно отследить ошибку. Поскольку вы используете несколько новых методов, я думаю, что сейчас самое время добавить обработку ошибок в код планировщика.
Чтобы начать работать с ошибками, вам понадобится модуль Python для logging
и класс RotatingFileHandler
. Импортируйте их, как показано:
1
2
|
import logging
from logging.handlers import RotatingFileHandler
|
Как только у вас будет необходимый импорт, инициализируйте регистратор, как показано:
1
2
|
logger = logging.getLogger(«Code Review Log»)
logger.setLevel(logging.INFO)
|
В приведенном выше коде вы инициализировали регистратор и установите уровень журнала на INFO.
Создайте вращающийся обработчик журнала файлов, который будет создавать новый файл каждый раз, когда размер файла журнала достигает максимального размера.
1
|
logHandler = RotatingFileHandler(‘app.log’,maxBytes=3000,backupCount=2)
|
Присоедините logHandler
к объекту logger
.
1
|
logger.addHandler(logHandler)
|
Давайте добавим регистратор ошибок, чтобы регистрировать ошибки при обнаружении исключения. В части read_email
метода read_email
добавьте следующий код:
1
2
|
logger.error(str(datetime.datetime.now()) + » — Error while reading mail : » + str(e) + «\n»)
logger.exception(str(e))
|
Первая строка записывает сообщение об ошибке с текущей датой и временем в файл журнала. Во второй строке записывается трассировка стека до ошибки.
Точно так же вы можете добавить обработку ошибок в основную часть кода. Вот как будет выглядеть код с обработкой ошибок:
01
02
03
04
05
06
07
08
09
10
11
|
try:
commits = process_commits()
if len(commits) == 0:
print ‘No commits found ‘
else:
schedule_review_request(commits)
except Exception,e:
print ‘Error occurred.
logger.error(str(datetime.datetime.now()) + » — Error while reading mail : » + str(e) + «\n»)
logger.exception(str(e))
|
Завершение
В этой части серии вы отложили информацию о запросе на проверку в файле reviewer.json
. Вы также создали метод для чтения электронных писем. Вы будете использовать обе эти функции для выполнения запросов на проверку кода в заключительной части этой серии.
Кроме того, не стесняйтесь посмотреть, что у нас есть в наличии для продажи и для изучения на рынке , и не стесняйтесь задавать любые вопросы и предоставлять ценные отзывы, используя канал ниже.
Исходный код из этого урока доступен на GitHub .
Дайте нам знать ваши мысли и предложения в комментариях ниже.