4 Basic workflow

Update the trunk branch to the latest sources with git pull --rebase. Create a new branch for your changes off of trunk and develop as you would normally with git commits.

4.1 Rebuilding R

Compiling R takes some time. Building it from scratch every time you’d like to test a change would slow down your workflow considerably. Fortunately, it is easy to rebuild only parts of it.

If you have changed a source file inside src/main run this from the build directory:

(cd src/main/ && make) && make install

If you have changed a package (say base), use:

(cd src/library/base/ && make && cd .. && make install)

4.2 Testing your changes

4.2.1 Running tests

Go to the tests folder inside your build directory. There are many make targets for running tests. See the README file in the tests folder. The three main targets to know about are:

  • make check: Runs the main unit test files. This includes running examples of the base packages and checking the outputs conform and no unexpected errors arise.

  • make check-devel: Runs all tests minus those of the recommended package. This includes running R CMD check on the base packages.

  • make check-all: Runs all tests including R CMD check on the recommended packages. You normally don’t need to run this until you’re ready to finalise a patch.

Other useful targets are test-Specific, test-Sloppy, and test-Reg as their running time is much faster. If you’re having trouble with a particular test domain and would like to find a smaller target to run these tests, check Makefile.common to find out which target invokes these tests.

Running the check-devel and check-all suites can take quite some time. Set this environment variable (maybe in your shell profile) to run the tests in parallel (in this case on 4 cores):

TEST_MC_CORES=4

4.2.2 Output comparison

Many test files have a .Rout.save file checked in the repository. These files are meant to monitor changes to the output of tested functions. There are two kinds of comparisons:

  • Strict, like method-dispatch.Rout.save. The saved and actual outputs must match exactly or the tests fail.

  • Sloppy, like print-tests.Rout.save. The diff of the changes are printed at the console, but they don’t make the tests fail.

In doubt, check tests/Makefile.common and search for RVAL_IF_DIFF. If set to 1, the comparison is strict, otherwise it is sloppy.

Some tests are compared sloppily because they are sensitive to benign changes, for instance:

  • The presence of srcref attributes might change how functions are printed. This could happen if you have set R_KEEP_PKG_SOURCE.

  • The memory addresses of environments or bytecode will change each time the file is run.

It is your responsibility to inspect all output changes in the test results and determine whether they actually are failures.

4.2.3 Debugging failures

When an unexpected error occurs, you will find a .Rout.fail file in the tests directory (the one inside your build directory). If the error was from a base package example, the failure file will be in tests/Example. From this file you should be able to find the source of the failure.

4.2.4 Adding new unit tests

The go-to file for new unit tests is currently tests/reg-tests-1d.R (choose the reg-tests-1 file with the highest letter suffix).

  • Insert your tests as a single block without whitespace. The tests should be navigable by contiguous paragraph. You can use ## to create empty lines inside your block.

  • If you are fixing a bug, insert comments describing the old behaviour.

  • If you have added code to a file that has a .Rout.save output file checked in, you need to update that file as well. To do this, run the tests as usual. You will find a .Rout file inside build/tests. Go to root/tests and copy paste the new contents in the corresponding .Rout.save file.

4.3 Making a patch

In a git-based workflow, you submit contributions via pull requests. Since R core doesn’t use git, we’re going to submit our changes the old fashioned way, by creating a patch file.

4.3.1 With github

Fortunately it is very easy to create patches from git branches and git commits. The simplest way is to send a pull request or branch to your github’s mirror repo and append .patch to a PR or commit URL. If you do that on a PR, all the commits are folded in a single patch. For instance, given this dummy PR that I made to my own clone of the R sources on github:

https://github.com/lionel-/r-source/pull/5

Get the corresponding patch via this URL:

https://github.com/lionel-/r-source/pull/5.patch

It also works with individual commits:

https://github.com/lionel-/r-source/commit/7b7ce5be72cab4c6ad41f0d8eb01591a4c01a882.patch

4.3.2 At the command line

To manually create a patch, use git format-patch. When given one argument (a revision), it creates patches for each commit from that revision to the current head:

git checkout mypatch
git format-patch trunk

Squash the commits together beforehand if you’d like to create a single patch.

4.4 Submitting

If the patch is trivial (e.g. it fixes a bug, implements a small feature that was already discussed), create a bugzilla report with a reprex if there isn’t one already. Attach the patch, click on “Show Advanced Fields” to reveal the “Content Type” checkbox and declare the attachment is a patch. This way the patch is properly formatted in the bug report.

If the patch introduces a new feature or change the API, it’s probably better to discuss it first on r-devel or with the relevant R core member.