Advertisement
  1. Code
  2. Python

Building a Python Code Review Scheduler: Sending Review Requests

Scroll to top
Read Time: 8 min
This post is part of a series called Building a Python Code Review Scheduler.
Building a Python Code Review Scheduler: Processing Log
Building a Python Code Review Scheduler: Keeping the Review Information

In the first part of the tutorial series, you saw how to set up the project and its required configurations. You processed the project git logs and printed them in the terminal. In this part, we'll take it to the next level and send out the code review requests.

Getting Started

Start by cloning the source code from the first part of the tutorial series.

1
git clone https://github.com/royagasthyan/CodeReviewer CodeReviewer

Once you have cloned the repository, navigate to the project directory CodeReviewer and try to execute the following command in the terminal.

1
python scheduler.py -n 20 -p "project_x"

It should print the commit IDs, commit date and the commit author in the terminal.

Collecting All Commits With Details

You'll get the commit details while iterating the commit logs. Now you need to collect the commit details and store them in a list, so that you can iterate them later to send out the code review request. In order to collect the commit details, start by creating a Commit class with the required members as shown:

1
# -------------------------------------------

2
#

3
# Commit class to contain commit related info

4
#

5
# -------------------------------------------

6
class Commit:
7
    def __init__(self, Id, Author, Date):
8
        self.Id = Id;
9
        self.Author = Author;
10
        self.Date = Date;

While iterating the commit logs in the process_commits method, create a Commit instance to keep the commit detail.

In the process_commits method, define a few variables as shown:

1
commitId = ''
2
author = ''
3
date = ''
4
commits = []

You'll be collecting each commit detail into a Python list called commits. While reading the commit logs, the first time when the commit ID is encountered, keep the commit Id and flush the date and author variables since it's a new commit. Modify the process_commits method's code after the commit keyword checking as shown: 

1
if line.startswith('commit '):
2
    author = ''
3
    date = ''
4
    commitId = line[7:]

When the commit Id is not null, that's when the commit details have been collected and it's time to add the commit to the commits list. Add the following line of code to the above code:

1
if line.startswith('commit '):
2
    if commitId <> "":
3
        commits.append(Commit(commitId, author, date))
4
    author = ''
5
    date = ''
6
    commitId = line[7:]

Modify the Author keyword check and the Date keyword check to keep the respective commit details in the author and date variables.

1
if line.startswith('Author:'):
2
    if(re.search('\<(.*?)\>',line)):
3
        author = re.search('\<(.*?)\>',line).group(1)
4
if line.startswith('Date:'):
5
    date = line[5:]

Now, if there is only one commit in the source code, the details will be saved inside the commit list. So add the following code to the end of the loop to handle that scenario.

1
if commitId <> "":
2
    commits.append(Commit(commitId, author, date))

Here is the complete process_commits method which collects the commit details and returns a list of commits.

1
# ----------------------------------

2
#

3
# Process the git log 

4
#

5
# ----------------------------------

6
7
def process_commits():
8
    cmd = "cd " + project + "; git log --all --since=" + str(no_days) + ".day --name-status"
9
    response = execute_cmd(cmd)
10
    commitId = ''
11
    author = ''
12
    date = ''
13
    commits = []
14
15
    for line in response.splitlines():
16
        if line.startswith('commit '):
17
            if commitId <> "":
18
                commits.append(Commit(commitId, author, date))
19
            author = ''
20
            date = ''
21
            commitId = line[7:]
22
        if line.startswith('Author:'):
23
            if(re.search('\<(.*?)\>',line)):
24
                author = re.search('\<(.*?)\>',line).group(1)
25
        if line.startswith('Date:'):
26
            date = line[5:]
27
28
    if commitId <> "":
29
        commits.append(Commit(commitId, author, date))
30
31
    return commits

Scheduling a Code Review Request

You have the commit details collected from the project log. You need to select random developers to send the code review request. Inside the config.json file, let's add the developers associated with the project who can review the code. Here is the modified config.json file:

1
[{
2
    "name": "project_x",
3
    "git_url": "https://github.com/royagasthyan/project_x",
4
    "members": [
5
        "royagasthyan",
6
        "hari",
7
        "sam",
8
        "shaun"
9
    ]
10
}, {
11
    "name": "project_y",
12
    "git_url": "https://github.com/royagasthyan/project_y",
13
    "members": [
14
        "royagasthyan",
15
        "hari",
16
        "sam",
17
        "shaun"
18
    ]
19
}]

Let's read the developer's info related to a particular project. Define a public variable called project_members.

1
project_members = ''

While reading the project configurations, fill in the project member details in the project_members list variable.

1
#

2
# Read the scheduler config file

3
#

4
with open('config.json') as cfg_file:
5
    main_config = json.load(cfg_file)
6
7
for p in main_config:
8
    if p['name'] == project:
9
        project_url = p['git_url']
10
        project_members = p['members']
11
    break

Now you have the developer list related to a particular project in the project_members variable.

Define a method called schedule_review_request which you'll call to schedule the review request corresponding to each project commit. The review request will be sent to a random developer from the project_members list, excluding the commit author. 

Create a method called select_reviewer to select the random developer from the project_members list. To select random developers from the list, you'll be making use of the random Python module. Import the random Python module.

1
import random

Here is how the code would look:

1
# -----------------------------------------

2
#

3
# Method to select random reviewer

4
#

5
# -----------------------------------------

6
7
def select_reviewer(author, group):
8
    if author in group:
9
        group.remove(author)
10
    reviewer = random.choice(group)
11
    return reviewer

As seen in the above code, the commit author has been removed from the developer list before selecting random developers to review the code. To select random developers from the list, you have made use of the random.choice method from the random module.

Inside the schedule_review_request method, iterate through each commit from the commits list. For each commit, select a random developer other than the author of the commit to send out the review request. Here is how the code would look:

1
def schedule_review_request(commits):
2
    for commit in commits:
3
        reviewer = select_reviewer(commit.Author, project_members)

Format the Code Review Request

You selected random developers to send out the code review request. Before sending the review request, you need to format it with details about the review request. Define a method called format_review_commit which will format the code review request. Here is how the code would look:

1
def format_review_commit(commit):
2
    review_req = ""
3
    review_req += "URL:     " + project_url + '/commit/' +  commit.Id + "\n"
4
    review_req += "Commit:  " + commit.Id + "\n"
5
    review_req += "Author:  " + commit.Author + "\n"
6
    review_req += "Date:    " + commit.Date + "\n"
7
    return review_req

In the schedule_review_request method, build up the review request email content which will be sent to the reviewer. The email content will contain the required information for the reviewer to review the code commit. Modify the schedule_review_request as shown:

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
        print body

Save the above changes and run the Python scheduler program.

1
python scheduler.py -n 25 -p "project_x"

You should be able to see an output similar to the one shown below:

Code Review Scheduler OutputCode Review Scheduler OutputCode Review Scheduler Output

Emailing the Code Review Request

Create a method called send_email which will email the review request with the required subject and content. You'll be making use of the smtplib module to send out the emails. Import smptlib in the scheduler.py file:

1
import smtplib

Define the mail server details along with the public variables:

1
FROM_EMAIL      = "youemail@gmail.com"
2
FROM_PWD        = "your password"
3
SERVER     = "smtp.gmail.com"
4
PORT       = 587

Create a method called send_email which will send out the email to the address specified. Here is how the send_email code would look:

1
def send_email(to, subject, body):
2
    header  = "From: " + FROM_EMAIL + "\n"
3
    header += "To: " + to + "\n"
4
    header += "Subject: " + subject + "\n"
5
    header += "\n"
6
    header += body
7
8
    print "** Sending email to '" + to + "'"
9
    
10
    
11
    mail_server = smtplib.SMTP(SERVER, PORT)
12
    mail_server.starttls()
13
    mail_server.login(FROM_EMAIL, FROM_PWD)
14
    mail_server.sendmail(FROM_EMAIL, to, header)
15
    mail_server.quit()

As seen in the above code, you created the smtp server using the gmail server and port number. Using the defined username and password, you logged into the email account and sent the email to the recipient.

Modify the schedule_review_request method to send the email instead of printing the email content to the terminal.

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
        send_email(reviewer,subject,body)

Save the above changes. Modify the config.json file to include a valid email address which you can check. Run the scheduler using the following command:

1
python scheduler.py -n 30 -p "project_x"

You should be able to see the following output on the terminal:

Code Review Request Sending OutputCode Review Request Sending OutputCode Review Request Sending Output

Verify the email address to see the code review request mailed from the Code Review scheduler.

Wrapping It Up

In this part of the Python Code Review Scheduler series, you collected the commit information into a list. The commit list was further iterated to format the review request. Random developers were selected to send out the code review request.

In the next part of this series, you'll see how to follow up the code review request.

Source code from this tutorial is available on GitHub.

I hope you enjoyed this part. Do let us know your thoughts in the comments below.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.