Griotte: Code Review for Pharo

Developer Documentation

1. Overview

Griotte is an experiment in Modern Code Review with two goals:

  1. Improving the code review process in the Pharo programming language and environment.
  2. Improving code review in general.

In general, we aim to improve code review by exploiting information provided by 2.2 fine-grained IDE events. Most notably this comes in the form of groups of changes. Read the extended abstract and presentation slides given on the homepage for more information on this topic. The documentation pages will discuss them briefly too.

Within Pharo specifically, one of the goals was to leverage existing services for doing code review, and creating a frontend within Pharo to use them. This means that one uses for example GitHub as their backend, and doing the code review process within Pharo. The Pharo frontend then enables the use of groups and other special features by storing metadata in the backend service. One can imagine using git-notes to do this in the case of Git repositories.

There is currently one backend implementation which is for GitHub. It uses the GitHub API Bindings internally. It also serves as a reference implementation for possible future backends.

Currently, both the UI and the model don't actually allow for full code review yet. The aforementioned concept of groups is yet to be implemented, and it is the main component which will enable the process of code review.

1.1. Further Documentation

The documentation is split into three parts:

  1. 2 The Model: Explains briefly the model of Griotte, and Epicea's fine-grained IDE events.
  2. 3 Backends: How Griotte integrates with backends and versioning tools.
  3. 4 The UI: Some words about the UI, and approaches for extending it.

1.2. Installation

To install and try Griotte, run the following Metacello script (taken from the homepage) in a Pharo 5 image:

Metacello new
	baseline: 'Griotte';
	repository: 'github://Balletie/Griotte:master';
	load.

This will also load a tool to do basic versioning in GitHub repositories. Griotte integrates with this tool to create new reviews.

2. The Model

This part describes the abstractions, or model, relevant to Griotte. It discusses Griotte's own model, as well as Epicea's model for fine-grained IDE events.

2.1. Griotte's Model

Griotte's model consists of several abstract classes which require to be implemented by a backend. In other words, the classes of the model define a set of operations and accessors which a backend should be able to perform and provide for. The model is defined as follows:

GrUser
A user represents someone that performs operations in a review. They can be asked for the repositories that they own.
By design, this is an immutable class. This is useful because in this way, one can for example compare a user of a comment with the logged in user of the current context (see the 2.1 explanation on GrContext).
One can then display for example in a comment or a review, that the person who made that comment is the one that is logged in (i.e. you).
GrRepository
A repository is in principle a collection of reviews, as far as we are concerned. It can return the local reviews, those active in Griotte, and non-local reviews.
It allows for the creation of new reviews, through GrRepository>>newReviewWithTitle:description:.
GrReview
A review is a request for a change to be integrated into the system. It supports two basic operations: GrReview>>approve or GrReview>>reject.
It allows for a conversation of the review on a global level. These are called top-level comments. They can be accessed with the GrReview>>comments accessor. New top-level comments can be created using GrReview>>newCommentWithBody:.
Basic accessors are its title, its creator (which returns a GrUser) and its description.
In the future, the reviews contain the groups of changes.
GrGroup
A group is a collection of related changes with a description. Comments can be added to groups too, allowing for a more detailed conversation. Groups can be generated by using the information provided by fine-grained IDE events (see 2.2 for more information).
How groups are stored is defined by the backend which implements it.
As groups are not yet implemented, the only operation that is known so far is GrGroup>>newCommentWithBody:.
GrComment
A comment can be made on either a review (the aforementioned top-level comments) or on a group of changes. The model makes no distinction between comments added to groups or to reviews — both are just comments.
A backend can of course distinguish between these two if it is necessary for the implementation.
A comment can be edited through GrComment>>edit:, and it can be accessed for its body, creator, and both the time it was created and the time it was last updated.
GrContext
A relatively late addition to the model, this class represents the connection between the repositories that are locally active (those with locally active reviews), and the user that is logged in.
The interface of Griotte should allow for multiple contexts to be present at the same time, for using different backends transparently, and for context switching between logins.

Local and Non-Local

In the above descriptions of the model classes, there are some references to local and non-local repositories or reviews. Local reviews are the reviews which are considered active — that is to say, the reviews that are relevant and being operated on. Local repositories are similar: they contain local reviews.

It might be desirable to support operations to remove local repositories or reviews, after you are done with reviewing for example.

2.2. Epicea Fine-Grained IDE Events

Epicea is a Pharo project for recording the actions of a developer within the IDE. It was originally created for the PhD thesis of Martín Dias. The information recorded by Epicea is much more than what is recorded in the Version Control System (e.g. Git) at the point of commit; for example, Epicea records the following:

  • Each save of a code change (e.g. Class addition, method modification).
  • Test runs and their respective outcomes.
  • Versioning operations (commits, checkouts).
  • Refactorings.

In this sense we say that the events Epicea records are fine-grained, in contrast with the coarse-grained information stored by Version Control Systems.

The information provided by Epicea allows one to group changes together when committing them. These groups can then in turn be used for code review. The grouping can be done with the Epicea Untangler.

Epicea Untangler

Epicea Untangler is a tool which presents the developer with automatically grouped (or untangled) changes derived using machine learning algorithms. See the relevant paper (Dias et al.) for more details.

The untangler can work together with Griotte when submitting a review. When the groups are correct, Griotte can store the groups in the backend service. How the storing is done is the responsibility of the backend implementations.

3. Backends

Without a backend implementation, Griotte by itself cannot do anything. This documentation shows how backends are implemented, and what the connection is with versioning tools. The connection with versioning tools is explained because most code review services are tied to some versioning system.

Griotte comes shipped with a reference implementation for using it with GitHub. Thus, examples from this implementation are given where appropriate.

In the case of the GitHub backend, everything is delegated to the GitHub API Bindings.

3.1. Creating a Backend

A backend is implemented by realizing and implementing the model classes discussed in the 2 model section. Here a summary is given of what needs to be implemented to conform to the model.

Storing groups

The backend needs to store the groups of information in some way, such that they can be found again when another reviewer opens the review in Griotte's UI.

In the case of Git-based repositories, this can be done using git-notes in some ref namespace (such as refs/griotte).

Creation of reviews and comments

The backend needs to be able to create reviews on repositories. Further, it needs to be able to create comments on reviews (top-level comments) and on groups. The creation of these two are done in their class-side creation methods:

GrReview class>>createOnRepository:withTitle:description:
As the name suggests, it creates a review with that title and description on the repository given in the first parameter.
You might notice that there is no mention of a branch which has to be merged into another. As these are specific to some backends, it is left as a responsibility of the backend to determine which set of changed is to be integrated, and where it is to be integrated.
In the case of Git-based repositories, one can take the currently checked out branch and integrate it in the default branch.
The GitHub backend analyzes the 2.2 Epicea log and finds the latest commit. Then the branch this commit was done on will be merged with the repository's default branch. View GrGitHubReview class>>createOnRepository:withTitle:description: for the implementation.
GrComment class>>createOnReview:withBody:
GrComment class>>createOnGroup:withBody:
Two creation methods are provided for creating comments, to distinguish between creating a comment on a review and on a group.

Accessing information

The implementation should be able to provide a list of repositories for a given user, and for each repository a list of reviews. These functionalities are implemented by the GitHub backend with GrGitHubUser>>allRepositories and GrGitHubRepository>>allReviews.

For reviews and groups, the comments of both should be able to be provided as Collections containing GrComments.

Further things that should be able to be accessed are obvious:

  • The creator, description, title of a review.
  • The creator, body, creation time and update time of a comment.
  • For a user, not much. It allows for anonymous users, meaning anyone can change any comment or review as one likes. If such operations are not possible, then it means that there is some concept of a user being logged in. Thus one might want to implement GrUser>>avatar and GrUser>>username
  • For a repository, its name.

3.2. The Connection with Version Control Systems

Griotte's model is agnostic about its connection to Version Control Systems (VCS). Thus, which branch has to be merged into which has to be determined by the backend implementation.

Porting over responsibilities

Griotte relies on external tool support for the backends. However, it might be necessary to port some of the responsibility over to Griotte's model. For example, if specifying which branches should be merged into which is desirable to be done from Griotte's UI, the model needs to be adapted for this.

Using a Visitor for backend-specific UI

Another approach might be to allow for flexible creation of backend-specific UI. This however does pose a challenge on integrating it within Griotte's main UI. One approach might be to extend the model with a Visitor Pattern, which can visit specific backend implementations. This way, the UI stays more separated from the model, while still allowing for creating backend-specific UI.

As Pharo supports extension methods, the Visitor implementation can easily be adapted for additional future backends.

4. The UI

Griotte's UI is created by means of loosely coupled UI widgets wrapped around a 2 model object. The widgets are implemented with Spec.

4.1. The widgets

The widgets are prefixed with GrUI to distinguished between the two. For example, there are GrUIReview and GrUIComment, which allow to perform the operations on the model objects they wrap through a graphical interface. Thus if one has a GrComment object, one can do something like this to open a comment window allowing to edit the comment's body:

| comment |
" comment is an instance of GrComment. "
GrUIComment new
	withComment: comment;
	openWithSpec

Similarly, to open a window for a GrReview instance:

| review |
" review is an instance of GrReview. "
GrUIReview new
	withReview: review;
	openWithSpec

Creating new widgets

With these loose widgets, one can easily recompose the UI. Thus it is desirable that when creating new widgets (e.g. for GrGroups, which are not implemented) a similar pattern is followed.

The widget should support the operations through its UI in one way or another. This can be done with buttons, but also with textfields and the Control + S (Windows/Linux) or Command + S (OSX) shortcuts. The latter has been done for editing the body of a comment.

4.2. Dialogs

Some utility classes for dialogs were created, which ease the creation of new dialogs. These are subclasses of GrUIDialog, which contains a class comment with information to implement a new dialog class.

4.3. The Main Window

The main user interface, GriotteUI, uses AbstractLoginModel as its boilerplate for displaying a username and password textfield for logging in. It is defined in the Widget-Extensions-Balletie package. It is separate from Griotte's repository as it is used by the GitHub tool as well.

The class comment for AbstractLoginModel should provide enough information to use it.