Package Initiation

Steps to create an empty package

R
Author

Trent McDonald

Published

March 11, 2023

R Packages are awesome. Here, I show you how to initiate a clean new package. Why I initiate things this way is beyond the scope of this post. A more complete description of package initiation, including the why’s and various options, is in Chapter 2 of ‘R Packages’, an excellent online book by Hadley Wickham and Jennifer Bryan. The code I show here overlaps with the recommendations in R Packages, but also extends those recommendations a bit.

I make heavy use of the usethis package (another amazing packages from the folks at Rstudio), which is a compilation of routines in devtools, so make sure usethis is installed. I also use git2r to initiate the git repository.

Set the directory

First, I use setwd() to specify the working directory, i.e., the directory where I want the package. In this post, I want to initiate a package in directory ./initPackage, i.e., in the initPackage directory under the current directory. I set a variable with this directory name, check whether it exists, create it if not, and finally set the working directory. Setting the working directory simplifies matters because by default most of the routines in usethis operate on the working directory.

packageDir <- "./initPackage"
if( !dir.exists(packageDir) ){
  dir.create(packageDir)
}
setwd(packageDir)

Construct the empty package

I use usethis::create_package to create the critical DESCRIPTION and NAMESPACE files, the R directory, and several other critical files. I then add a license and readme. This is the basic empty package. A person can stop here and go forward if they do not use git and will never submit this package to CRAN. In fact, a person could stop after the create_package routine if the package is truly local and will never be seen by anyone else, although I argue that keeping good notes in a readme is essential.

usethis::create_package(getwd()) # Creates empty package
usethis::use_readme_rmd()  # Creates the readme. Edit the RMD, then knit to get MD
usethis::use_mit_license() # Creates LICENSE file

Initiate the local GIT repository

It is always a good idea to keep track of versions using git. This code creates a local git repository, updates the .gitignore file, and makes the initial commit.

git2r::init()
writeLines(".Rproj.user", file=".gitignore")
git2r::add(path="*")  # or different file glob
git2r::commit(message="Initial commit")

Initiate remote repository and push

If you will not be sharing this package, there is no real need to create a remote repository and you can skip this step. But, if you want to share this package via a git server, such as GitLab or GitHub, you need to create a place for the repository on the remote server. Navigate to whichever website you want, sign in, and create an empty project prior to running the following code. I create remotes for almost all packages, even if I only have one collaborator or user.

If you know how to do this, move on. Here are some additional details on how to complete this step. After creating a remote git project, GitLab or GitHub will give you the remote repository’s ‘glob’. ‘glob’ is jargon for a URL address of the project’s repository. It looks something like this:

https:://gitlab.com/user/project.git

Copy the ‘glob’ and assign it to variable remoteGlob, as in the code below.

Code in the next block adds the address of the newly created remote repository to the local repository. I generally name the remote repository origin, but that is not necessary. The remote field of the local repository is simply the address of (a pointer to) the GitLab or GitHub project. With this defined, the local repository knows where to push commits.

remoteGlob <- "https://gitlab.com/<userIdOrGroup>/<gitProjectName>.git"
git2r::remote_add(name="origin",url=remoteGlob)

Before you can push the initial commit to the remote, you need remote credentials. Remote credentials are your GitLab or GitHub username and password or token.

push’ means upload changes in the local repository to the remote repository.

For convenience, I store remote credentials in Windows environmental variables. Environment variables exist “in the background” of a machine. They are not obvious and are only accessible by users of a particular Windows account; hence, the Windows account password is a master password when credentials are stored as environment variables. Environmental variables are also convenient because git2r::cred_env will automatically pull values.

To define an environmental variable use the Windows ‘System Properties’ dialog. To do this, click on start and search for ‘edit environmental’ and click the ‘edit system environmental variables’ app. In the app, click the ‘Environmental Variables’ button in the bottom right and define the environmental variables in the next dialog box. I have one variable named GITLAB_USER that stores my GitLab username. I have a second variable named GITLAB_TOKEN that contains my GitLab token (or password). Discussion of the differences between passwords and tokens is beyond the scope of this post.

This code sets user credentials by reading environmental variables and then pushes the initial commit to the remote repository.

creds <- git2r::cred_env("GITLAB_USER", "GITLAB_TOKEN")
git2r::push(name="origin", refspec="refs/heads/master", credentials = creds)

Assuming all of the above code worked, this is usually the end of package initiation. All that is left is to edit the DESCRIPTION file, edit readme.Rmd, create package functions in separate files inside the R directory with roxygen comments at the top, document(), and install(). And, git2r::add() and git2r::commit() early and often. Easy.

P.S.: If Your Package is Destined for CRAN

If my package is destined for CRAN, I include the following code in the package creation step.

usethis::use_cran_comments()
usethis::use_news()
usethis::use_testthat()
usethis::use_coverage()
# add some badges if you want
usethis::use_cran_badge() 
usethis::use_lifecycle_badge("Experimental")
# for testing prior to submission
usethis::use_travis() # or use_gitlab_ci() 

P.P.S.: All together

The code in this post is split up by explanations. That is appropriate, but it is also not convenient. Here is all the lines in my package initiation workflow, in one convenient place.

packageDir <- "./initPackage"
remoteGlob <- "https://gitlab.com/<userIdOrGroup>/<gitProjectName>.git"
if( !dir.exists(packageDir) ){ dir.create(packageDir) }
setwd(packageDir)
usethis::create_package(getwd()) 
usethis::use_readme_rmd()  
usethis::use_mit_license() 
git2r::init()
git2r::add(path="*")  # or different file glob
git2r::commit(message="Initial commit")
git2r::remote_add(name="origin",url=remoteGlob)
creds <- git2r::cred_env("GITLAB_USER", "GITLAB_TOKEN")
git2r::push(name="origin", refspec="refs/heads/master", credentials = creds)