Spanish (Español) translation by Elías Nicolás (you can also view the original English article)
En la segunda parte de esta serie, se vio cómo recopilar la información de los registros git de los commit y enviar solicitudes de revisión a los desarrolladores aleatorios seleccionados de la lista de miembros del proyecto.
En esta parte, verá cómo guardar la información de revisión de código para realizar el seguimiento cada vez que se ejecuta el programador de código. También verá cómo leer mensajes de correo electrónico para comprobar si el revisor ha respondido a la solicitud de revisión.
Introducción
Comience clonando el código fuente de la segunda parte de la serie.
1 |
git clone https://github.com/royagasthyan/CodeReviewer-Part2 CodeReviewer |
Modifique
el archivo config.json
para incluir algunas direcciones de correo
electrónico relevantes, manteniendo la dirección de correo electrónico
royagasthyan@gmail.com
. Es
porque el git tiene commits relacionadas con esa dirección de correo
electrónico particular y se requiere para que el código se ejecute correctamente. Modifique las credenciales SMTP
en el archivo schedule.py
:
1 |
FROM_EMAIL = "your_email_address@gmail.com" |
2 |
FROM_PWD = "your_password" |
Navegue hasta el directorio de proyecto CodeReviewer
e intente ejecutar el siguiente comando en el terminal.
1 |
python scheduler.py -n 20 -p "project_x" |
Debe enviar la solicitud de revisión de código a desarrolladores aleatorios para su revisión.
Mantener la información de solicitud de revisión
Para dar seguimiento a la información de la solicitud de revisión, debe guardarla en algún lugar para referencia. Puede seleccionar dónde desea conservar la información de solicitud de revisión de código. Puede ser cualquier base de datos o puede ser un archivo. Para el bien de este tutorial, mantendremos la información de la solicitud de revisión dentro de un archivo reviewer.json
. Cada
vez que se ejecute el planificador, comprobará el archivo de
información para dar seguimiento a las solicitudes de revisión que no se
han respondido.
Cree un método llamado save_review_info
que guarde la información de la solicitud de revisión dentro de un archivo. Dentro del método save_review_info
, cree un objeto info
con el revisor, el asunto y una Id única.
1 |
def save_review_info(reviewer, subject): |
2 |
info = {'reviewer':reviewer,'subject':subject,'id':str(uuid.uuid4()),'sendDate':str(datetime.date.today())} |
Para una Id única, importe el módulo Python uuid
.
1 |
import uuid |
También necesita el módulo de Python datetime
para obtener la fecha actual. Importe el módulo de datetime
de Python.
1 |
import datetime |
Necesita inicializar el archivo reviewer.json
cuando se inicie el programa si aún no existe.
1 |
if not os.path.exists('reviewer.json'): |
2 |
with open('reviewer.json','w+') as outfile: |
3 |
json.dump([],outfile) |
Si
el archivo no existe, debe crear un archivo llamado reviewer.json
y
rellenarlo con una array JSON vacía como se ve en el código anterior.
Este método se llamará cada vez que se envíe una solicitud de revisión. Por lo tanto, dentro del método save_review_info
, abra el archivo reviewer.json
en modo de lectura y lea el contenido. Añada la nueva información de contenido al contenido existente y vuelva a escribirla en el archivo reviewer.json
. Así es como se vería el código:
1 |
def save_review_info(reviewer, subject): |
2 |
info = {'reviewer':reviewer,'subject':subject,'id':str(uuid.uuid4()),'sendDate':str(datetime.date.today())} |
3 |
|
4 |
with open('reviewer.json','r') as infile: |
5 |
review_data = json.load(infile) |
6 |
|
7 |
review_data.append(info) |
8 |
|
9 |
with open('reviewer.json','w') as outfile: |
10 |
json.dump(review_data,outfile) |
Dentro
del método schedule_review_request
, antes de enviar el correo de
solicitud de revisión de código, llame al método save_review_info
para
guardar la información de revisión.
1 |
def schedule_review_request(commits): |
2 |
date = time.strftime("%Y-%m-%d") |
3 |
|
4 |
for commit in commits: |
5 |
reviewer = select_reviewer(commit.Author, project_members) |
6 |
subject = date + " Code Review [commit:" + commit.Id + "]" |
7 |
body = "Hello '" + reviewer + "', you have been selected to review the code for commit\n" |
8 |
body += "done by '" + commit.Author + "'.\n" |
9 |
body += "\n" |
10 |
|
11 |
body += format_review_commit(commit) |
12 |
|
13 |
save_review_info(reviewer,subject); |
14 |
|
15 |
send_email(reviewer,subject,body) |
Guarde los cambios anteriores y ejecute el programa planificador. Una
vez que se ha ejecutado el planificador, debería poder ver el archivo
reviewer.json
dentro del directorio del proyecto con la información de
solicitud de revisión de código. Así es como se vería:
1 |
[{
|
2 |
"reviewer": "samson1987@gmail.com", |
3 |
"id": "8ca7da84-9da7-4a17-9843-be293ea8202c", |
4 |
"sendDate": "2017-02-24", |
5 |
"subject": "2017-02-24 Code Review [commit:16393106c944981f57b2b48a9180a33e217faacc]" |
6 |
}, { |
7 |
"reviewer": "roshanjames@gmail.com", |
8 |
"id": "68765291-1891-4b50-886e-e30ab41a8810", |
9 |
"sendDate": "2017-02-24", |
10 |
"subject": "2017-02-24 Code Review [commit:04d11e21fb625215c5e672a93d955f4a176e16e4]" |
11 |
}]
|
Lectura de los datos de correo electrónico
Ha recogido toda la información de solicitud de revisión de código y la ha guardado en el archivo reviewer.json
. Ahora,
cada vez que se ejecuta el planificador, debe comprobar su bandeja de
entrada de correo para ver si el revisor ha respondido a la solicitud de
revisión de código. Así que primero debes definir un método para leer tu bandeja de entrada de Gmail.
Cree un método llamado read_email
que toma el número de días para comprobar la bandeja de entrada como un parámetro. Utilizarás el módulo imaplib
de Python para leer la bandeja de entrada de correo electrónico. Importe el módulo imaplib
de Python:
1 |
import imaplib |
Para leer el correo electrónico con el módulo imaplib
, primero debe crear el servidor.
1 |
email_server = imaplib.IMAP4_SSL(SERVER) |
Inicie sesión en el servidor utilizando la dirección de correo electrónico y la contraseña:
1 |
email_server.login(FROM_EMAIL,FROM_PWD) |
Una vez conectado, seleccione la bandeja de entrada para leer los correos electrónicos:
1 |
email_server.select('inbox') |
Estará leyendo los mensajes de correo electrónico durante el último número n de días desde que se envió la solicitud de revisión de código. Importe el módulo timedelta
de Python.
1 |
import timedelta |
Crear la fecha del correo electrónico como se muestra:
1 |
email_date = datetime.date.today() - timedelta(days=num_days) |
2 |
formatted_date = email_date.strftime('%d-%b-%Y') |
Utilizando formatted_date
, busque en el servidor de correo electrónico los mensajes de correo electrónico.
1 |
typ, data = email_server.search(None, '(SINCE "' + formatted_date + '")') |
Devolverá los identificadores únicos para cada correo electrónico y, utilizando los ID únicos, podrá obtener los detalles del correo electrónico.
1 |
ids = data[0] |
2 |
|
3 |
id_list = ids.split() |
4 |
|
5 |
first_email_id = int(id_list[0]) |
6 |
last_email_id = int(id_list[-1]) |
Ahora
usará el first_email_id
y el last_email_id
para iterar a través de los
correos electrónicos y buscar el asunto y la dirección "from" de los
correos electrónicos.
1 |
for i in range(last_email_id,first_email_id, -1): |
2 |
typ, data = email_server.fetch(i, '(RFC822)' ) |
data
contendrá el contenido del correo electrónico, por lo que iterar la parte de datos y comprobar una tupla. Estará haciendo uso del módulo de correo electrónico Python para extraer los detalles. Así que importa el módulo email
de Python.
1 |
import email |
Puede extraer el asunto del correo electrónico y la dirección "from" como se muestra:
1 |
for response_part in data: |
2 |
if isinstance(response_part, tuple): |
3 |
msg = email.message_from_string(response_part[1]) |
4 |
print 'From: ' + msg['from'] |
5 |
print '\n' |
6 |
print 'Subject: ' + msg['subject'] |
7 |
print '\n' |
8 |
print '------------------------------------------------' |
Aquí está el método completo read_email
:
1 |
def read_email(num_days): |
2 |
try: |
3 |
email_server = imaplib.IMAP4_SSL(SERVER) |
4 |
email_server.login(FROM_EMAIL,FROM_PWD) |
5 |
email_server.select('inbox') |
6 |
|
7 |
email_date = datetime.date.today() - timedelta(days=num_days) |
8 |
formatted_date = email_date.strftime('%d-%b-%Y') |
9 |
|
10 |
typ, data = email_server.search(None, '(SINCE "' + formatted_date + '")') |
11 |
ids = data[0] |
12 |
|
13 |
id_list = ids.split() |
14 |
|
15 |
first_email_id = int(id_list[0]) |
16 |
last_email_id = int(id_list[-1]) |
17 |
|
18 |
for i in range(last_email_id,first_email_id, -1): |
19 |
typ, data = email_server.fetch(i, '(RFC822)' ) |
20 |
|
21 |
for response_part in data: |
22 |
if isinstance(response_part, tuple): |
23 |
msg = email.message_from_string(response_part[1]) |
24 |
print 'From: ' + msg['from'] |
25 |
print '\n' |
26 |
print 'Subject: ' + msg['subject'] |
27 |
print '\n' |
28 |
print '------------------------------------------------' |
29 |
|
30 |
except Exception, e: |
31 |
print str(e) |
Guarde los cambios anteriores e intente ejecutar el método read_email
anterior:
1 |
read_email(1) |
Debe imprimir el asunto del correo electrónico y la dirección "from" en el terminal.



Ahora vamos a recopilar la dirección "from" y el asunto en una lista de email_info
y devolver los datos.
1 |
email_info = [] |
En lugar de imprimir el asunto y la dirección "from", agregue los datos a la lista email_info
y devuelva la lista email_info
.
1 |
email_info.append({'From':msg['from'],'Subject':msg['subject'].replace("\r\n","")}) |
Aquí está el método read_email
modificado:
1 |
def read_email(num_days): |
2 |
try: |
3 |
email_info = [] |
4 |
email_server = imaplib.IMAP4_SSL(SERVER) |
5 |
email_server.login(FROM_EMAIL,FROM_PWD) |
6 |
email_server.select('inbox') |
7 |
|
8 |
email_date = datetime.date.today() - timedelta(days=num_days) |
9 |
formatted_date = email_date.strftime('%d-%b-%Y') |
10 |
|
11 |
typ, data = email_server.search(None, '(SINCE "' + formatted_date + '")') |
12 |
ids = data[0] |
13 |
|
14 |
id_list = ids.split() |
15 |
|
16 |
first_email_id = int(id_list[0]) |
17 |
last_email_id = int(id_list[-1]) |
18 |
|
19 |
for i in range(last_email_id,first_email_id, -1): |
20 |
typ, data = email_server.fetch(i, '(RFC822)' ) |
21 |
|
22 |
for response_part in data: |
23 |
if isinstance(response_part, tuple): |
24 |
msg = email.message_from_string(response_part[1]) |
25 |
email_info.append({'From':msg['from'],'Subject':msg['subject'].replace("\r\n","")}) |
26 |
|
27 |
except Exception, e: |
28 |
print str(e) |
29 |
|
30 |
return email_info |
Añadir registro para la gestión de errores
El manejo de errores es un aspecto importante del desarrollo de software. Es muy útil durante la fase de depuración para rastrear errores. Si no tiene ningún manejo de errores, entonces se hace realmente difícil de rastrear el error. Puesto que tiene un par de nuevos métodos, creo que es el momento adecuado para agregar el manejo de errores al código del planificador.
Para comenzar con el manejo de errores, necesitará el módulo logging
de Python y la clase RotatingFileHandler
. Importarlos como se muestra:
1 |
import logging |
2 |
from logging.handlers import RotatingFileHandler |
Una vez que tenga las importaciones necesarias, inicialice el logger como se muestra:
1 |
logger = logging.getLogger("Code Review Log") |
2 |
logger.setLevel(logging.INFO) |
En el código anterior, inicializó el logger y estableció el nivel de registro en INFO.
Cree un manejador de registro de archivos rotatorio que creará un nuevo archivo cada vez que el archivo de registro haya alcanzado un tamaño máximo.
1 |
logHandler = RotatingFileHandler('app.log',maxBytes=3000,backupCount=2) |
Adjuntar el logHandler
al objeto logger
.
1 |
logger.addHandler(logHandler) |
Añadamos el registrador de errores para registrar errores cuando se captura una excepción. En la parte de excepción del método read_email
, agregue el código siguiente:
1 |
logger.error(str(datetime.datetime.now()) + " - Error while reading mail : " + str(e) + "\n") |
2 |
logger.exception(str(e)) |
La primera línea registra el mensaje de error con la fecha y hora actuales en el archivo de registro. La segunda línea registra el seguimiento stack trace en el error.
Del mismo modo, puede agregar el tratamiento de errores a la parte principal del código. Así es como se vería el código con el manejo de errores:
1 |
try: |
2 |
commits = process_commits() |
3 |
|
4 |
if len(commits) == 0: |
5 |
print 'No commits found ' |
6 |
else: |
7 |
schedule_review_request(commits) |
8 |
except Exception,e: |
9 |
print 'Error occurred. Check log for details.' |
10 |
logger.error(str(datetime.datetime.now()) + " - Error while reading mail : " + str(e) + "\n") |
11 |
logger.exception(str(e)) |
Conclusion
En esta parte de la serie, archivó la información de solicitud de revisión en el archivo reviewer.json
. También creó un método para leer los correos electrónicos. Utilizará ambas funciones para dar seguimiento a las solicitudes de revisión de código en la parte final de esta serie.
Además,
no dude en ver lo que tenemos disponible para la venta y para estudiar
en el marketplace, y no dude en hacer cualquier pregunta y proporcionar su
valiosos comentarios usando el feed a continuación.
El código fuente de este tutorial está disponible en GitHub.
Háganos saber sus pensamientos y sugerencias en los comentarios a continuación.