.. _lfreleng-docs-gerrit:
############
Gerrit Guide
############
Gerrit is an opensource web-based collaborative code review tool that
integrates with Git. Gerrit provides a framework for reviewing code commits
before it merges into the code base.
The changes are not made a part of the project until a code review completes.
Gerrit is also a good collaboration tool for storing the conversations that
occur around the code commits.
.. note::
Here is more information on `Gerrit `_
Prerequisites
=============
Before you get started, you should have:
* an LFID account (sign up `here
`_)
* git installed (see: http://www.git-scm.com/downloads)
* git configured with your name, e-mail address and editor
.. code-block:: bash
git config --global user.name "Firstname Lastname"
git config --global user.email "email@address.com"
git config --global core.editor "text-editor-name"
.. note:: Your name and e-mail address (including capitalization) must match what you entered
when creating your LFID account.
* an ssh public/private key pair (see the good `GitHub docs on generating ssh keys
`_)
* register in the Gerrit server. See below for detailed instructions.
:ref:`register-key-gerrit`
* git-review installed (see: https://www.mediawiki.org/wiki/Gerrit/git-review#Installation)
Clone the code
==============
Cloning the code into a local workspace can happen via HTTP or SSH.
#. Make sure your Gerrit settings are up to date with correct SSH and GPG keys.
#. In the project's Gerrit instance, we can see the HTTP and SSH commands. From
the left side menu, select Projects->List->Select any project->General.
#. Copy the desired clone command and paste it in your terminal.
SSH Clone
---------
This option provides a more secure connection. We should always use SSH for
pushing code unless the user is under a network that prevents SSH usage.
In such case, use HTTPS.
.. note::
For more information on how to generate the public/private key pair see
`Generating SSH keys for your system`_ and
`Register your SSH key with Gerrit`_
.. note::
The SSH clone option will not appear if the settings are not updated with
the correct SSH keys.
#. Browse for the project's General information.
#. Click on the ssh tab.
#. Clone desired repo. For example:
.. code-block:: bash
git clone ssh://USERNAME@gerrit.linuxfoundation.org:29418/releng/docs
.. note::
Since we are constantly working on uploading new code into the
repositories, we recommend to use SSH clones since the remotes for
pushing code get configured appropriately.
Anonymous HTTP Clone
--------------------
Recommended if the intention is to view code and not make any contributions:
#. Browse the project and click ``General``
#. Click ``anonymous http`` tab.
#. Clone desired repo. For example:
.. code-block:: bash
git clone https://gerrit.linuxfoundation.org/releng/docs
Authenticated HTTP Clone
------------------------
This works everywhere, even behind a proxy or a firewall.
#. Get the password by clicking on the username on the top right->Settings->
HTTP Password->Generate Password
#. Browse for the project and click ``General``.
#. Click ``http`` tab.
#. Clone desired repo. For example:
.. code-block:: bash
git clone https://USERNAME@gerrit.linuxfoundation.org/infra/a/releng/docs
#. Follow the user/password prompts.
.. note::
For Gerrit < 2.14 the HTTP password is not the same as the Linux Foundation ID password.
.. note::
For Gerrit with HTTP configuration, the HTTP Password is in the User Name
(Top right corner) -> Settings -> HTTP Password -> Generate Password.
Clone with commit-msg hook
--------------------------
Both SSH and HTTP clone options have a clone with commit-msg hook which adds
a hook to handle the Change-Id_ field in the footer of the
commit message.
#. Browse for the project and click ``General``.
#. Click ``Clone with commit-msg hook``. For example:
.. literalinclude:: _static/commit-hook.example
:language: bash
OR
.. literalinclude:: _static/commit-hook-curl.example
:language: bash
.. note::
The hook implementation is intelligent at inserting the Change-Id_ line before
any Signed-off-by or Acked-by lines placed at the end of the commit message by
the author, but if no lines are present then it will insert a blank line, and
add the Change-Id_ at the bottom of the message.
If a Change-Id_ line is already present in the message footer, the script will do
nothing, leaving the existing Change-Id_ unmodified. This permits amending an existing
commit, or allows the user to insert the Change-Id_ manually after copying it from
an existing change viewed on the web.
#. (Optional). To prevent the Change-Id_ addition, set gerrit.createChangeId to false in the
git config.
Push patches to Gerrit
======================
#. Open a shell to the directory containing the project repo
#. Create a local working branch, based on the branch you would like to make
changes to.
.. code-block:: bash
git fetch origin
git checkout -b new_feature_branch origin/master
Replace *origin/master* with whichever remote/branch you need to contribute
to. Typically master is the latest development branch.
#. Make the modifications you would like to change in the project
#. Stage the modified files for commit. (Repeat for all files modified)
.. code-block:: bash
git add /path/to/file
#. Verify the staged files by running ``git status``
#. Commit the staged files by amending the patch
.. code-block:: bash
git commit -s
.. note::
The '-s' argument signs the commit message with your name and email and
is a statement that you agree to the :ref:`dco`.
#. Push the patch to Gerrit using one of the 2 methods documented:
#. :ref:`gerrit-push-git-review`
#. :ref:`gerrit-push-git-push`
.. _gerrit-push-git-review:
Push using git review
---------------------
We recommend using `git-review `_
if possible as it makes working with Gerrit much easier.
#. Install ``git-review`` via your local package management system
If your distro does not package git-review or you need a newer version.
Install it via PyPi in a virtualenv_ environment:
.. code-block:: bash
virtualenv ~/.virtualenvs/git-review
pip install git-review
#. Push the patch to Gerrit
.. code-block:: bash
git review
We can optionally pass the parameter ``-t my_topic`` to set a
:ref:`topic ` in
Gerrit. Useful when we have related patches to organize in one
:ref:`topic `.
Once pushed we should see some output in the terminal as described in
:ref:`Gerrit Push Output `.
.. _gerrit-push-git-push:
Push using git push
-------------------
This method is a useful fallback in situations where we cannot use
:ref:`git-review `.
#. Use the following command:
.. code-block:: bash
git push HEAD:refs/for/master
Where is the Gerrit location to push the patch to. Typically
'origin' but can also be 'gerrit' depending on how we have our local repo
setup.
.. note::
Notice the word "for" is explicitly intending to perform the push into Gerrit.
Using "heads" instead, will attempt to make the a push into the repository bypassing
Gerrit which can come in handy for some isolated cases (when having force push rights).
Another variable commonly used is "refs/changes/" which is an explicit
way of making an update to an existing gerrit. In such case, is best to let gerrit handle
this via Change-Id_ in the commit text.
More options for this command: `git-push `_.
Once pushed we should see some output in the terminal as described in
:ref:`Gerrit Push Output `.
.. _gerrit-push-output:
Push output
-----------
After pushing a commit to Gerrit we should see the following output:
.. literalinclude:: _static/push-success.example
:language: bash
This output includes a URL to the patch. The number at the end is the patch's
change number.
Update an existing patch
========================
In a healthy Open Source project code reviews will happen and we will need to
amend the patches until reviewers are happy with the change. This section will
walk through the process of updating a patch that is already in
Gerrit Code Review.
#. Open a shell to the directory containing the project repo
#. Pull the latest version of the patch from Gerrit
.. code-block:: bash
git review -d ${change_number}
The change number is in the URL of the Gerrit patch.
For example if the URL is https://git.opendaylight.org/gerrit/75307
then run ``git review -d 75307`` to pull the corresponding changes.
(Optional) View information on the latest changes made to that patch.
* To view the edited files, run ``git show``.
* To view a listing of the edited files and the number of lines in those
files, run ``git show --stat``.
#. Rebase the patch before you start working on it
.. code-block:: bash
git pull --rebase
This is to ensure that the patch incorporates the latest version of the
repo and is not out of date.
#. Make the necessary changes to the patch with your favorite editor
#. Check the state of the repo by running ``git status``
#. Stage the modified files for commit. (Repeat for all files modified)
.. code-block:: bash
git add /path/to/file
#. Verify the staged files by running ``git status``
#. Commit the staged files by amending the patch
.. code-block:: bash
git commit --amend
#. Update the current patch description and then save the commit request.
If you feel as though you added enough work on the patch, add your name
in the footer with a line ``Co-Authored-By: Firstname Lastname ``.
#. Rebase the patch one last time
.. code-block:: bash
git pull --rebase
This is to ensure that the patch incorporates the latest version of the
repo and is not out of date.
#. Submit your files for review:
.. code-block:: bash
git review
You will receive 2 emails from Gerrit Code Review: the first indicating that
a build to incorporate your changes has started; and the second indicating
the whether the build passed or failed. Refer to the console logs if the
build has failed and amend the patch as necessary.
Update a patch with dependent changes
=====================================
In the case where a patch depends on another in review Gerrit patch, we will
need to rebase the commit against the latest patchset of the dependent change
in Gerrit. The best way to do this is to retrieve the latest version of the
dependent change and then cherry-pick our patch on top of the change.
#. Fetch latest parent patch set
.. code-block:: bash
git review -d
#. Cherry-pick out patch on top
.. code-block:: bash
git review -x
#. Push patch back up to Gerrit
.. code-block:: bash
git review -R
Rebasing a change against master
================================
In the case that your patchset cannot be re-based via the U/I (merge conflict)
.. code-block:: bash
git pull origin master
git review -d 12345
git rebase master
"fix conflicts"
git add *
git rebase --continue
git review
Code Review
===========
All contributions to Git repositories use Gerrit for code review.
The code review process provides constructive feedback about a proposed change.
Committers and interested contributors will review the change, give their feedback,
propose revisions and work with the change author through iterations of the patch until
it’s ready for merging.
Managing and providing feedback for the change happens via Gerrit web UI.
.. figure:: _static/gerrit-wide-view.png
Gerrit wide view.
Pre-review
----------
Change authors will want to push changes to Gerrit before they are actually
ready for review. This is an encouraged good practice. It has been the
experience of experienced community members that pushing often tends to reduce
the amount of work and ensures speedy code reviews.
.. note::
This is not required and in some projects, not encouraged, but the general idea
of making sure patches are ready for review when submitted is a good one.
.. note::
While in draft state, Gerrit triggers, e.g., verify Jenkins jobs, won’t run
by default. You can trigger them despite it being a draft by adding
"Jenkins CI" (or the corresponding Jenkins automation account) as a
reviewer. You may need to do a recheck by replying with a comment
containing ``recheck`` to trigger the jobs after adding the reviewer.
To mark an uploaded change as not ready for attention by committers and interested
contributors (in order of preference), either mark the Gerrit a draft (by adding
a ``-D`` to your ``git review`` command), vote -1 on it yourself or edit the commit
message with "WIP" ("Work in Progress").
Do not add committers to the Reviewers list for a change while in the pre-review
state, as it adds noise to their review queue.
Review
------
Once an author wants a change reviewed, they need to take some actions to put it on
the radar of the committers.
If the change it's a draft, you'll need to publish it. Do this from the Gerrit web UI.
.. figure:: _static/gerrit-publish-button.png
Gerrit Web UI button to publish a draft change.
Remove your -1 vote if you've marked it with one. If you think the patch is ready for
merge, vote +1. If there is not an automated job to test your change and vote +1/-1
for Verified, you will need to do as much testing yourself as possible and then manually
vote +1 to Verified. Reviewers can dditionally vote +1 for Verified along with
automated jobs. Describing the testing you did or did not do is typically helpful.
.. figure:: _static/gerrit-voting-interface.png
Gerrit voting interface, exposed by the Reply button.
Once the change gets published and you have voted for merging, add the people who
need to review/merge the change to the Gerrit Reviewers list. The auto-complete for
this Gerrit UI field is somewhat flaky, but typing the full name from the start
typically works.
.. figure:: _static/gerrit-reviewers-interface.png
Gerrit Reviewers list with Int/Pack committers added
Reviewers will give feedback via Gerrit comments or inline against the diff.
.. figure:: _static/gerrit-inline-feedback.png
Gerrit inline feedback about a typo
Updated versions of the proposed change get pushed as new patchsets to the same
Gerrit, either by the original submitter or other contributors. Amending proposed changes
owned by others while reviewing may be more efficient than documenting the problem, -1ing,
waiting for the original submitter to make the changes, re-reviewing and merging.
Download changes for local manipulation and re-uploaded updates via git-review.
See `Update an existing patch`_ above. Once you have re-uploaded the patch the Gerrit web
UI for the proposed change will reflect the new patchset.
.. figure:: _static/gerrit-patch-update-history.png
Gerrit history showing a patch update
Reviewers will use the diff between the last time they gave review and the current patchset
to understand updates, speeding the code review process.
.. figure:: _static/gerrit-diff-menu.png
Gerrit diff menu
Iterative feedback continues until reaching consensus (typically: all active reviewers +1/+2
and no -1s nor -2s), at least one committer +2s and a committer merges the change.
.. figure:: _static/gerrit-code-review-votes.png
Gerrit code review votes
Merge
-----
Once a patch has gotten a +2 from a committer and they have clicked the submit button the
project's merge job should run and publish the project's artifacts to Nexus. Once completed,
other projects will be able to see the results of that patch.
This is important when merging dependent patches across projects. You will need to wait
for the merge job to run on one patch before any patches in other projects depending on
it will successful verify.
Set up Gerrit
=============
Generating SSH keys for your system
-----------------------------------
You must have SSH keys for your system to register with your Gerrit
account. The method for generating SSH keys is different for different
types of operating systems.
The key you register with Gerrit must be identical to the one you will
use later to pull or edit the code. For example, if you have a
development VM which has a different UID login and keygen than that of
your laptop, the SSH key you generate for the VM is different from the
laptop. If you register the SSH key generated on your VM with Gerrit and
do not reuse it on your laptop when using Git on the laptop, the pull
fails.
.. note::
Here is more information on `SSH keys for Ubuntu
`_
and more on `generating SSH keys
`_
For a system running Ubuntu operating system, follow the steps below:
#. Run the following command::
mkdir ~/.ssh
chmod 700 ~/.ssh
ssh-keygen -t rsa
#. Save the keys, and add a passphrase for the keys.
This passphrase protects your private key stored in the hard drive.
You must use the passphrase to use the keys every time you need
to login to a key-based system::
Generating public/private rsa key pair.
Enter file in which to save the key (/home/b/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your public key is now available as **.ssh/id\_rsa.pub** in your home
folder.
.. _register-key-gerrit:
Register your SSH key with Gerrit
---------------------------------
#. Using a Google Chrome or Mozilla Firefox browser, go to
gerrit..org
#. Click **Sign In** to access the repositories.
.. figure:: _static/gerrit-sign-in.png
:alt: Sign into Gerrit
Sign into Gerrit
#. Click your name in the top right corner of the window and then click
**Settings**.
The **Settings** page.
.. figure:: _static/gerrit-settings.png
:alt: Settings page for your Gerrit account
Settings page for your Gerrit account
#. Click **SSH Public Keys** under **Settings**.
#. Click **Add Key**.
#. In the **Add SSH Public Key** text box, paste the contents of your
**id\_rsa.pub** file and then click **Add**.
.. figure:: _static/gerrit-ssh-keys.png
:alt: Adding your SSH key
Adding your SSH key
To verify your SSH key, try using an SSH client to connect to Gerrit’s
SSHD port::
$ ssh -p 29418 @gerrit..org
Enter passphrase for key '/home/cisco/.ssh/id_rsa':
**** Welcome to Gerrit Code Review ****
Submit a patch over HTTPS
=========================
While we recommend you submit patchsets over SSH some users may need to
submit patchsets over HTTPS due to corporate network policies such as
the blocking of high range ports or outgoing SSH.
To submit code to Gerrit over HTTPS follow these steps.
.. note::
This guide uses the Linux Foundation Gerrit server and the
releng/docs project as an example. Differences may vary with other
Gerrit servers.
Configure your Machine
----------------------
#. Generate a HTTPS password
.. note::
Required when uploading patches to Gerrit servers via HTTPS.
Navigate to ``_
and click **Generate Password**. Write this to the file **.netrc** in your
home directory excluding the angle brackets::
machine gerrit.linuxfoundation.org user password
#. Clone the repository over HTTPS using your Linux Foundation ID
.. code-block:: shell
git clone https://bramwelt@gerrit.linuxfoundation.org/infra/releng/docs
#. Download the commit-msg git hook
.. code-block:: shell
curl -Lo .git/hooks/commit-msg \
https://gerrit.linuxfoundation.org/infra/tools/hooks/commit-msg && \
chmod +x .git/hooks/commit-msg
Due to a bug in git-review, you need to download the commit-msg hook
manually to the .git/hooks/ directory or ``git-review -s`` will fail.
Configure the Repository
------------------------
Because ``git-review`` attempts to use SSH by default, you need
configure the git-review scheme and port through git-config in the
repository.
.. note::
The Gerrit context path on the Linux Foundation Gerrit server is
``infra/``. Others Gerrit servers may use ``gerrit/`` or ``r/``.
#. Perform the following commands
.. code-block:: shell
cd docs/
git config gitreview.scheme https
git config gitreview.port 443
git config gitreview.project infra/releng/docs
#. Verify the configuration by running the following command::
git review -s
If successful, the command will not print anything to the console, and
you will be able to submit code with::
git review
Otherwise ``git-review`` will still request your Gerrit username,
indicating a configuration issue.
You can check the configuration using verbose output::
git review -v -s
Sign Gerrit Commits
===================
1. Generate your GPG key.
The following instructions work on a Mac, but the general approach
should be the same on other OSes.
.. literalinclude:: _static/gpg-setup.example
If you are collaborating in keysigning, then send the output of
``gpg2 --fingerprint $KEY_ID`` to your coworkers.
.. code-block:: bash
gpg2 --fingerprint $KEY_ID
# in the above example, the $KEY_ID would be F566C9B1
# in my case, the output was:
# pub 4096R/F566C9B1 2015-04-06 [expires: 2017-04-05]
# Key fingerprint = 7C37 02AC D651 1FA7 9209 48D3 5DD5 0C4B F566 C9B1
# uid [ultimate] Colin Dixon
# sub 4096R/DC1497E1 2015-04-06 [expires: 2017-04-05]
2. Install gpg, instead of or addition to gpg2.
.. note:: you can tell Git to use gpg by doing:
``git config --global gpg.program gpg2``
but that then will seem to struggle asking for your
passphrase unless you have your gpg-agent set up right.
3. Add your GPG to Gerrit
a. Run the following at the CLI:
.. code-block:: bash
gpg --export -a $FINGER_PRINT
# e.g., gpg --export -a F566C9B1
# in my case the output looked like:
# -----BEGIN PGP PUBLIC KEY BLOCK-----
# Version: GnuPG v2
#
# mQINBFUisGABEAC/DkcjNUhxQkRLdfbfdlq9NlfDusWri0cXLVz4YN1cTUTF5HiW
# ...
# gJT+FwDvCGgaE+JGlmXgjv0WSd4f9cNXkgYqfb6mpji0F3TF2HXXiVPqbwJ1V3I2
# NA+l+/koCW0aMReK
# =A/ql
# -----END PGP PUBLIC KEY BLOCK-----
b. Browse to https://git.opendaylight.org/gerrit/#/settings/gpg-keys
c. Click Add Key...
d. Copy the output from the above command, paste it into the box,
and click Add
4. Set up your Git to sign commits and push signatures
.. code-block:: bash
git config commit.gpgsign true
git config push.gpgsign true
git config user.signingkey $FINGER_PRINT
# e.g., git config user.signingkey F566C9B1
.. note::
We can create a signed commit with ``git commit -S`` and
a signed push with ``git push --signed`` on the CLI instead of
configuring it in config if we want to manually control which commits
use the signature.
5. Create a signed commit
a. Change a file
b. Create a signed commit with ``git commit -asm "test commit"``
This will result in Git asking you for your passphrase.
Enter it to proceed.
6. Push to Gerrit with a signed-push with ``git review``
This will result in Git asking you for your passphrase.
Enter it to proceed.
.. note::
The signing a commit or pushing again with a signed push is not
recognized as a "change" by Gerrit, so if you forget to do either, you
need to change something about the commit to get Gerrit to accept the
patch again. Slightly tweaking the commit message is a good way.
.. note::
This assumes you have git review set up and push.gpgsign
set to true. Otherwise:
``git push --signed gerrit HEAD:refs/for/master``
This assumes the gerrit remote is available, if not, configure
something like: ``ssh://ckd@git.opendaylight.org:29418/.git``
where repo is something like docs or controller
6. Verify the signature
To do this, navigate to Gerrit and check for a green check next to your name in the patch.
.. figure:: _static/gerrit-signed-push.png
Example signed push to Gerrit.
Appendix
========
Developer's Certificate of Origin (DCO)
---------------------------------------
Code contributions to Linux Foundation projects must have a sign-off by the
author of the code which indicates that they have read and agree to the DCO.
.. literalinclude:: _static/dco-1.1.txt
:language: none
:caption: Developer's Certificate of Origin
:name: dco
Refer to https://developercertificate.org/ for original text.
.. _gerrit-topics:
Gerrit Topics
-------------
Topics are useful as a search criteria in Gerrit. By entering ``topic:foo``
as a search criteria we can track related commits. Use one of the following
methods to configure topics:
1. Directly in the Gerrit UI via the Edit Topic button
2. Via ``git review`` using the ``-t topic`` parameter
.. note::
git-review defaults to the local branch name as the topic if it does not
match the upstream branch.
3. Via ``git push`` using one of the following methods:
.. code-block:: bash
git push origin HEAD:refs/for/master%topic=some-topic
git push origin HEAD:refs/for/master -o topic=some-topic
Both methods achieve the same result so is up to preference. Further
documentation available at `Gerrit Topics
`_.
.. _Change-Id: https://gerrit.linuxfoundation.org/infra/Documentation/user-changeid.html
.. _virtualenv: https://virtualenv.pypa.io/en/stable/