One of the useful features for Gerrit users is to receive notifications about events related to their changes. Gerrit contains built-in support for email notifications. You can just configure SMTP settings and voilà, bunch categories of emails will be sent. So far so good, but the reality is often quite different.
It turns out that amount of emails is quite large. Especially if Gerrit is a part of CI infrastructure and various actions are bound to changes uploading. For example if each published change is verified by build bot and reviewed by another developer, users (change owner and reviewers since they are added) may receive the following emails:
- Build of patchset #1 started (comment posted by bot)
- Build of patchset #1 finished (verified label set by bot)
- Code review done (code review label set by reviewer
- Build of patchset #2 started
- Build of patchset #2 finished
- Code review done (code review label set by reviewer
- … (subsequent updates of verified and code label review)
- Change merged (or abandoned)
Moreover emails are also sent for events like Change abandoned, which are often not interesting for many users.
Finally email is not a perfect solution for notifications. Messages sent by Gerrit may get into spam or be overlooked in the jungle of other emails. Of course it is possible to set filters, whitelists, categories, visual feedback and so on in email client but there are tools which are better suited to that.
In our company we have already used HipChat for communication between team members for some time. It supports group chat rooms as well as one-on-one chats. It also has some extra features like desktop notifications and message coloring. The latter is used by HipChat plugin for Jenkins to indicate build results. Each software project has dedicated chat room for alerts. Messages generated by various robots (like HockeyApp, JIRA, etc.) go here. The following picture shows example of messages generated by Jenkins plugin:
OK, so why not use HipChat also for Gerrit related notifications? Great idea but unfortunately (at the time of writing) there was no ready-to-use Gerrit-HipChat integration. Happily we are software development company, so we can develop missing functionality ourselves.
Let’s start with some theory. One of the extension points of Gerrit are hooks which corresponds to events like
change-merged, not to be confused with git hooks like
commit-msg. We are exactly interested in 2 of the hooks:
While the first one is self-explanatory, the second refers among other things, to code review score setting. Precisely, comment on Gerrit can optionally contain a score and a message. Thus, using one-click Code-Review+2 button causes adding a comment with score but without a text typed by user.
Hook itself is a file (usually a script) with name equal to hook name (without any extension) placed in
$site_path/hooks directory, where
site_path is a path to root directory of Gerrit installation. If hook is present and executable (on Unix-like OSes) it will be executed when particular event occurs in any of the projects. There is no need to additionally enable it or restart/reload Gerrit daemon. Parameters are passed using commandline.
Now we know which hooks have to be implemented, so let’s determine what exactly should they do. 2 functionalities are needed:
- newly added reviewer should be notified via private message
- code review score should be posted on alerts room, with appropriate background color
Since there is no special hook for code review score change, so we need to use
comment-added analyze input and filter out useless events. Firstly we exclude draft comments since only author (and administrators) can see them so it does not make sense to inform other people about them. Then we exclude comments without code review score. In practice it means comments made by Jenkins (it uses
Verified label in our configuration) and those written by teammates without changing a code review score given by particular user. As a result all code review score changes should be published to alerts chat room.
reviewer-added logic is almost straightforward. In our CI configuration build on Jenkins is started just after patchset is published. That means Jenkins bot (as a non-interactive Gerrit user) also becomes a reviewer. There is no need to post message about adding such reviewer because Jenkins (via aforementioned HipChat plugin) posts message with information that job has started. So the only additional action is to check if the reviewer is a Jenkins bot.
HipChat provides a REST API. We will use version 2 of the API which is current at the time of writing. Note that admin account on HipChat is needed to perform all described steps.
API Authorization is based on tokens and there are several ways to obtain them. We need write-only access to all rooms and ability to send private messages. To achieve that we can create a HipChat user with admin rights. Note that despite that user is an admin, token created by him does not need to have admin rights (and should not have them for security reasons). Such user can post messages to all rooms even if he is not their member. Additionally that user acts as a sender of private messages. Instead of a user, an integration can be created. The latter way is not covered by this article.
After creating a user (you can call him for example Gerrit bot), we can login in as him, go to API access settings (on HipChat on demand it is located under
https://<your domain>.hipchat.com/account/api and create an API token with scopes: Send Message and Send Notification.
In terms of Gerrit hooks users’ login is display name (usually first and last name but may be edited by user) and email address. HipChat API on the other hand accepts both email address and mention name (called also @mention). In our company email addresses have standardized format:
<first name>.<last name>@droidsonroids.pl. Similarly mention names are written as
@<first name><last name> (dot is not allowed by HipChat). All that simplifies our hooks implementation since there is no need to maintain any name-to-name mapping (growing on each project addition) but names can be simply converted using constant rules.
reviewer-added can be bound to Private message user HipChat API request. Its description is pretty simple. We need to provide:
id_or_email– user mention name or email, the latter is provided by hook so it is easier to use
message– the message body (10000 characters max.), eg. Visit <change url> to review change in <project name>,both values for placeholders are provided by hook
notify– flag whether user should be notified (by change of the tab color, play a sound, badge, etc.), we want it to be set to
trueso users will be notified (their individual notification settings are also taken into account)
text, we will use the latter since message contains only plain text and URL (which will appear clickable to user, without wrapping with tags)
comment-added can correspond to Send room notification request. Not to be confused with Send message! Many more parameters are supported but we will use only few of them.
notify have exactly the same meaning as already mentioned. Message can be eg. Hello <change owner>, change <change url> reviewed, score: <score>. We can additionally specify a
color so messages about successfully passed code review can have green background while those about fails – red similarly to messages generated by Jenkins.
Error handling and logging
API requests mail fail due to network issues or logical errors, especially caused by non-matching user or room names. Hook script itself can also contain bugs causing its process to terminate abnormally. It will be useful to collect such occurrences. We can achieve it simply by printing to
stdout. Hook output is collected by Gerrit and saved to
$site_path/logs/error_log, each line is prefixed by
hook[<hook name>] output:. Error may also occur if API rate limit is exceeded. Keep in mind that most of the Gerrit hooks (including 2 mentioned in this article) are executed in background after activity, so Gerrit server may shut down in the time between event and hook completion.
Source code is available on GitHub. Hooks are implemented in Python (compatible with Python 3.5.1), using standard Python library. API token is read from external configuration file
$site_path/etc/hipchat.config which should have secure permissions, eg.
0600 (definitely it should not be world readable). It is not article about Python programming, so only key code fragments will be mentioned here:
- Use ArgumentParser.parse_known_args when parsing commandline arguments since not all of them are needed and new ones may be added in future versions of Gerrit.
- Environment variable
GERRIT_SITEcontaining path to the root directory of Gerrit installation is available, so it can be used to determine location of configuration file. It is better to use it instead of hardcoding path or using relative one.
- All variables used to form an URL must be URL-encoded