<- "./initPackage"
packageDir if( !dir.exists(packageDir) ){
dir.create(packageDir)
}setwd(packageDir)
Package Initiation
Steps to create an empty package
In this post, I show code to initiate a new packages. Why I run these routines is beyond the scope of this post. A much more complete description of package initiation, include why 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 routines in the usethis
package (amazing packages from the folks at Rstudio), which is a compilation of routines in other packages such as devtools
, so make sure usethis
is installed. I also use git2r
to initiate the git repository.
Set the directory
First, I use setwd()
and set the working directory to a 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, whatever that is. 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 is important because most of the routines that follow operate on the working directory by default.
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.
::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 usethis
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.
::init()
git2rwriteLines(".Rproj.user", file=".gitignore")
::add(path="*") # or different file glob
git2r::commit(message="Initial commit") git2r
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 to the project. 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, which I generally name origin
, to the local repository. 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.
<- "https://gitlab.com/<userIdOrGroup>/<gitProjectName>.git"
remoteGlob ::remote_add(name="origin",url=remoteGlob) git2r
Before you can push the initial commit to the remote, you need remote credentials. These are our GitLab or GitHub username and password or token.
For convenience, I store my user credentials in Windows environmental variables. These are variables that always exist on your machine in the background. They are handy for user credentials because they are not obvious and they can only be seen by users with the correct Windows account credentials. Environmental variables are particularly convenient because git2r::cred_env
will automatically pull values of input environmental variable names.
Aside: To define an environmental variable, I use the ‘System Properties’ dialog in Windows. Start menu search for ‘edit environmental’ and open the ‘edit system environmental variables’ app (it’s not really an app). Click ‘Environmental Variables’ and define the environmental variables. 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.
<- git2r::cred_env("GITLAB_USER", "GITLAB_TOKEN")
creds ::push(name="origin", refspec="refs/heads/master", credentials = creds) git2r
You are done. This is usually the end of my package initiation. All that is left is to edit the DESCRIPTION
file, edit readme.Rmd
, create some functions in separate files inside the R
directory with roxygen
comments at the top, document()
, and install()
. And, do not forget to git2r::add()
and git2r::commit()
early and often. Easy.
Postscript: Package destined for CRAN
If my package is destined for CRAN, I include the following code in the package creation step.
::use_cran_comments()
usethis::use_news()
usethis::use_testthat()
usethis::use_coverage()
usethis# add some badges if you want
::use_cran_badge()
usethis::use_lifecycle_badge("Experimental")
usethis# for testing prior to submission
::use_travis() # or use_gitlab_ci() usethis
Post-postscript: All together
The code in this post is split up by explanations. That is appropriate, but it is also not convenient. I generally source the following lines to initiate a package.
<- "./initPackage"
packageDir <- "https://gitlab.com/<userIdOrGroup>/<gitProjectName>.git"
remoteGlob if( !dir.exists(packageDir) ){ dir.create(packageDir) }
setwd(packageDir)
::create_package(getwd())
usethis::use_readme_rmd()
usethis::use_mit_license()
usethis::init()
git2rwriteLines(".Rproj.user", file=".gitignore")
::add(path="*") # or different file glob
git2r::commit(message="Initial commit")
git2r::remote_add(name="origin",url=remoteGlob) git2r