Developing an R package from scratch with Travis continuous integration

[This article was first published on R on Datentrang, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

This short tutorial provdes a quick guide on how to develop an R package from scratch and how use Travis CI for automatic builds on various R versions and automatic test coverage calculation. The resulting package can be found here: CIexamplePkg

A very nice general introduction can be found here: rOpenSci Packages: Development, Maintenance, and Peer Review

Some material is taken from the awesome UseR 2019 tutorial from Colin Gillespie: https://www.jumpingrivers.com/t/2019-user-git/#1

R package basics

First, create a new package, e.g. using the RStudio GUI. The usethis package facilitates all upcoming steps immensely:

library(usethis)

Feel free to delete the hello world example (R and Rd file in R and man folder). We’ll add new functionality via

use_r("add.R")

The code we add is as follows:

add <- function(a,b) {
  return(a+b)
}

To see the new function in action run “Install and Restart” from the “Build” tab:

add(7,2)

We’ll now add more functionality. Note that one should always refer to the package of a function using “::”. If you don’t do this, the check later gives an error. Thus we refer to all ggplot functions with ggplot2::fun().

add <- function(a,b,plot=FALSE) {
  val <- a+b
  if (plot==TRUE) {
    df <- data.frame(x=c(a,b,val))
    p <- ggplot2::ggplot(df) + ggplot2::geom_col(ggplot2::aes(x=x,y=x))
    print(p)
  }
  return(val)
}

Use “Source on save” to play around with the function. When done, install and restart again.

add(4,16,plot=TRUE)

The package now depends on ggplot2. We have to add this to the description file

use_package("ggplot2", "Imports")

Finally, we’ll ad a license to our package:

use_gpl3_license(name = "Oliver Pfaffel") # change to your name

If you are a pipe fan, you can easily make it available via

use_pipe() # Use %>%

We do not need it here.

Documentation

We’ll add a news and readme file.

use_news_md()
use_readme_md() # use_readme_rmd() IF you want to run R code in your readme

We change the readme file as follows.

# CIexamplePkg

<!-- badges: start -->
<!-- badges: end -->

The goal of CIexamplePkg is to provide a simple example on how to set up a package for continuous integration.

Be sure to keep the news file up to date. You can increment the version number via

use_version()

You can also add a vignette, but we’ll not do this here.

use_vignette("name_of_vignette")

Also very nice is the option to add a spell-checker (again omited for this package)

use_spell_check() # requires spelling package

Every R function should have a documentation. We’ll change the code of our function to

#' Sum up two variables
#'
#' What is the sum of a and b?
#'
#' @param a numeric
#' @param b numeric
#' @param plot Makes plot if TRUE
#'
#' @return Returns a numeric that is the sum of a and b.
#'
#' @examples
#' add(7,2)
#' add(4,16,plot=TRUE)
#'
#' @export
add <- function(a,b,plot=FALSE) {
  val <- a+b
  if (plot==TRUE) {
    df <- data.frame(x=c(a,b,val))
    p <- ggplot2::ggplot(df) + ggplot2::geom_col(ggplot2::aes(x=x,y=x))
    print(p)
  }
  return(val)
}

The function will now be exported to the namespace of our package, if we delete the existing NAMESPACE file first. After “Install and Restart” we build the documentation via

devtools::document()

Now the documentation is available via

?add

Checking the package

Now we should check the package (there also is a button for this in RStudio)

devtools::check(document = FALSE)

To remove the note about non-standard files on top level, we simply ignore those files when building R

use_build_ignore("name of file to ignore.filetype")

Tests

Every R package should have tests that automatically check core functionality

use_test("add")

We’ll simply change the code to

test_that("addition works", {
  expect_equal(add(7,2), 9)
})

and run the test. It should be successfull.

Continous integration

Using github

Run the following commands and allow git to comit all files. Then restart RStudio.

usethis::use_git()
usethis::use_git_config(user.name = "Oliver Pfaffel", user.email = "[email protected]") # change to your name and email

Now create a github PAT (personal access token) from the github page and add it to the environment

usethis::edit_r_environ()

Add the line GITHUB_PAT=YOUR-PAT, restart R and run

Sys.getenv("GITHUB_PAT")

to see if it works. Next we create a github repo via the github website. Then commit and push all files (copy and paste the code suggested at github to the terminal or use the RStudio GUI).

Travis CI

Make a travis account and log in. Add Travis to your package via

usethis::use_travis()

Turn on travis for your repo at https://travis-ci.org/profile/o1iv3r as usethis says (your link will include your repo name).

Add your github PAT to the Travis environment variables via options -> settings -> Environment variables

  • NAME: GITHUB_PAT
  • VALUE: token

Travis will now run each time we push to github. Try this out! Note that this might take some time. After a successfull build you might notice the nice badge on your github page.

Advanced Travis options

Building w.r.t. different R versions:

Add

r:
  - oldrel
  - release
  - devel

to your .travis.yml

This means we can test against three versions of R with no effort

Build only for certain branches via

branches:
  only:
  - master
  - stable

or exclude some (experimental) branches via

branches:
  except:
  - legacy
  - experimental

Test coverage

We want Travis not only to run the tests but also to report test coverage. We’ll do this via the covr package

use_coverage()

Make sure to copy

r_github_packages:
  - r-lib/covr

after_success:
  - Rscript -e 'covr::codecov()'

to your travis.yml

Then go to https://codecov.io/ and add your repo. You will get a token that you have to add as a Travis environment variable (similar to your github PAT)

  • NAME: CODECOV_TOKEN
  • VALUE: token

Now commit and push your changes to github and enjoy your new coverage badge.

By the way, the covr package has a nice Addin that graphically shows you test coverage:

library(covr)
# Addins -> Calculate text package coverage

To leave a comment for the author, please follow the link and comment on their blog: R on Datentrang.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)