By default when uploading a package to CRAN or testing a package on Travis, the code on the vignette will be run in order to make sure that it is reproducible. That is understandable and actually really helpful, as it minimises bugs.
What happens though when your code either takes too long to run (imagine running a complicated model which takes 20 hours) or requires using a password (imagine creating an API where you would need to use a username and password) ? In the first case you wouldn’t want to hammer CRAN’s or Travis’s servers whereas in the second case you wouldn’t want to show your credentials to everyone reading the vignette. However, when building the vignette locally you would definitely want to test that your code works. This leads us to the question:
How can we ignore vignette code testing on CRAN or Travis, but test it locally?
When I was preparing the RDota2 package (an API client for Valve’s Dota2) I needed to use a key to access the API. In order to do this I created an environment variable with the key value locally. Every time I wanted to test the package, I would load this environment variable
(with Sys.getenv('RDota_KEY')
) and use it to log in to the API. Obviously, the environment variable was saved on my local machine. When testing my package with devtools::check
the environment variable would be loaded and all of the code would run fine. However, this would cause an error on CRAN and Travis, as they wouldn’t be able to find the environment variable. (For information on how to set up an environment variable please check the Appendix at the end of this article).
Therefore, I needed to find a way to test my vignette code locally (making sure that the functions work correctly with my key) but not on CRAN and Travis. For CRAN I used the following (modified from httr
’s tutorial):
If we setup an environment variable on our local machines named LOCAL
and set that to true
, then we can use that in a setup chunk in the vignette:
LOCAL <- identical(Sys.getenv("LOCAL"), "true")
knitr::opts_chunk$set(purl = CRAN)
Then we can use eval = LOCAL
as a chunk option (in next chunks).
When building the package locally identical(Sys.getenv("LOCAL"), "true")
will return TRUE
. This will result in eval = TRUE
in all chunks and the code will be checked. On the other hand, identical(Sys.getenv("LOCAL"), "true")
will return FALSE
on CRAN, which will result in eval = FALSE
in individual chunks and the code will not run.
Although the Cran solution above would work for Travis too (since there is no LOCAL
environment variable on Travis), I also provide a secondary solution in case anyone needs it.
On Travis, by default, there is an environment variable called Travis
. Travis
is set to true
. Using the same technique as CRAN we specify in our setup chunk:
TRAVIS <- !identical(tolower(Sys.getenv("TRAVIS")), "true")
knitr::opts_chunk$set(purl = TRAVIS)
Then we can use eval = TRAVIS
as a chunk option (in next chunks).
When building the package locally !identical(tolower(Sys.getenv("TRAVIS")), "true")
will return TRUE
. This will result in eval = TRUE
in all chunks. On the other hand, !identical(tolower(Sys.getenv("TRAVIS")), "true")
will return FALSE
on TRAVIS, which will result in eval = FALSE
in individual chunks and the code will not run.
At this point I think it is worth mentioning that Travis-CI actually allows users to create their own environment variables and even encrypt them (which is perfect for credentials). You can find out more about the encryption process here.
We can actually just use LOCAL
in the same way defined in the Cran solution as this checks the LOCAL
environment variable we defined (which won’t exist on CRAN or Travis).
If you would like to see a real example you could check my vignette for RDota2 here.
Thanks for reading!
There are 5 easy steps in order to create an environment variable. I demonstrate the steps from the RDota2 package, but the methodology is exactly the same:
normalizePath("~/")
in the R console.RDota_KEY=xxxxxxxx
, where RDota_KEY will be the name of the R environment variable and xxxxxxxx will be your individual API Key. Make sure the last line in the file is empty (if it isn’t R will silently fail to load the file). If you’re using an editor that shows line numbers, there should be two lines, where the second one is empty.Sys.getenv
.