Heavily based on Noam Ross's instructions, here is how we obtain and encrypt the OAuth2.0 token used for testing, including on Travis-CI. Go here for the generic instructions on how to encrypt files on Travis.
In theory, you do this once. In reality, you do it more often because something goes wrong with your token. For example, with Google, you can only have 25 active tokens per account. In the course of googlesheets
development, if one of us does something that results in several new token requests, we inevitably use up some of those 25. Over time, the token on Travis eventually falls off the end and we need to request and encrypt a new one. Here's how we do it.
The support provided by httr
for OAuth token management is a beautiful thing. Specifically, the automagic usage of .httr-oauth
for token caching. It is a great kindness to preserve the user's blissful ignorance about the OAuth2 flow for as long as possible.
However, I've decided it's pretty important to anticipate token workflows where the user asserts more control. You will want this for development purposes, e.g., in automated testing against the API, and for non-interactive use of the package, e.g. in scripts run in batch mode or in a Shiny app. Our initial OAuth flow relied solely on .httr-oauth
but we eventually extended gs_auth()
to make it easy to retrieve the current token and to put a pre-existing token into force, whether stored in an R object or in an .rds
file.
Either do this from a working directory where the existing .httr-oauth
contains the token you'd like to use or where there is NO existing .httr-oauth
(or use gs_auth(new_user = TRUE)
). In the latter case, when you are kicked to the browser, make sure you log in (or already logged in) to Google as the desired user. Pro tip: start with a fresh token or one near the beginning of the current 25-token sequence.
library(googlesheets)
token <- gs_auth()
saveRDS(token, file = "tests/testthat/googlesheets_token.rds")
This token is now in an obvious location for use in (local) testing via testthat
.
Prior to tests that require authorization, put this token into force.
gs_auth(token = "googlesheets_token.rds")
or, more realistically,
suppressMessages(gs_auth(token = "googlesheets_token.rds", verbose = FALSE))
A line like this will be at the top of your testing files, but presumably outside of actual tests or expectations. Here's an example. I also like to explicitly suspend authenticated access at the end of every testing file.
This is the work necessary to use our existing token on Travis CI, securely.
First you need to install the Travis command line client:
gem install travis
Note: I had to do this as sudo.
Then log into your Travis account using your GitHub username and password.
travis login
Encrypt the token and send to Travis:
travis encrypt-file tests/testthat/googlesheets_token.rds --add
The --add
option should add a decrypt command to your pre-existing .travis.yml
file, along these lines:
before_install:
- openssl aes-256-cbc -K $encrypted_84f43c85142c_key -iv $encrypted_84f43c85142c_iv -in tests/testthat/googlesheets_token.rds.enc -out tests/testthat/googlesheets_token.rds -d
Double check that the token and encrypted token live in tests/testthat/
and that .travis.yml
reflects the correct path. You will probably need to move the encrypted token into the correct directory and edit the path(s) in .travis.yml
!
List the token tests/testthat/googlesheets_token.rds
in .gitignore
.
List the encrypted token tests/testthat/googlesheets_token.rds.enc
in .Rbuildignore
.
Do not mix these up.
token_file.rds
in .Rbuildignore
, it will not be copied over into the my_package.Rcheck
directory when Travis runs R CMD check
, and your tests will fail. Over and over. As you bang your desk trying to figure out what's wrong.Commit tests/testthat/googlesheets_token.rds.enc
and your updated .travis.yml
and push to Github. God willing, your tests that require authorization will now pass on Travis.
I use the token in tests/testthat/googlesheets_token.rds
to authorize googlesheets
in the vignette and was sort of horrified when I noticed that the vignette compiled just fine on http://win-builder.r-project.org. Since we do NOT (and cannot) Rbuildignore the unencrypted token, it was indeed being bundled up and sent along to win-builder. This got me concerned that, unless I took deliberate steps to omit the token in my eventual CRAN submission, it would be distributed with my package source.
I decided to make a "CRAN submission" branch and add tests/testthat/googlesheets_token.rds
to .Rbuildignore
. Of course, this breaks the build on Travis, so this little exercise will have to be done just prior to each CRAN submission and I'll need to take care to submit from the branch, not from master.
When I first submitted the "CRAN submission" branch to win-builder, I got an education on all the ways in which CRAN checks vignettes. In the absence of the token, googlesheets
cannot do anything that requires authorization, which broke many chunks of the original vignette. How I worked around that is a separate story (TO DO: write that down).
Temporary summary of vignette analogue of testthat::skip_on_CRAN()
: there are two issues. First, CRAN will attempt to build the vignette. Second, CRAN will attempt to run the R code extracted from the vignette. To solve the first problem, conditionally suppress chunk execution on CRAN. To solve the second problem, prevent the extraction of source code from some or all chunks with purl = FALSE
. The vignette CRAN actually uses is the one you build and submit, so these measures aren't as harmful as you might fear.
For CRAN updates, I still plan to vet them with win-builder and it's pretty clear that, if I allow the token to go, it's not kept private in any shape or form. So either I'll just tolerate the small chance this could come back to haunt me or I'll handle like a CRAN submission and submit from a branch in which I've Rbuildignored the unencrypted token.
2015-06-29 The token we had been using finally fell off the end of the 25-token stack. But the basic instructions did not work for me when attempting to encrypt the new token file. I got this:
Jennifers-2015-MacBook-Pro:googlesheets jenny$ travis encrypt-file tests/testthat/googlesheets_token.rds
repository not known to https://api.travis-ci.com/: jennybc/gspreadr
The old name of this repo was somehow blocking me. The repo hasn't been called gspreadr
for months! From this issue thread I learned to inspect and correct the Travis slug in .git/config
. It now reads like so:
[travis]
slug = jennybc/googlesheets
That allowed me to encrypt a new token file.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.