Maintaining Packages Using fakemake
Our brand new package veryImportantPackage is checked into git already:
r <- git2r::repository(path)
summary(r)
## Local: master /tmp/Rtmp6JVfXG/veryImportantPackage
## Head: [4d830f9] 2020-03-13: Packager Changes
##
## Branches: 1
## Tags: 0
## Commits: 15
## Contributors: 1
## Stashes: 0
## Ignored files: 0
## Untracked files: 0
## Unstaged files: 0
## Staged files: 0
##
## Latest commits:
## [4d830f9] 2020-03-13: Packager Changes
## [f30cd44] 2020-03-13: Adding `make.R` from template `make.R` of package` packager`.
## [95688d3] 2020-03-13: Adding `inst/runit_tests/runit-throw.R` from template `runit-throw.R` of package` packager`.
## [ec54552] 2020-03-13: Adding `tests/runit.R` from template `runit.R` of package` packager`.
## [87fb2fe] 2020-03-13: Adding `tests/testthat/test-throw.R` from template `test-throw.R` of package` packager`.
git2r::status(r)
## working directory clean
but we have so far only built the documentation from the roxygen
comments:
list.files(file.path(path, "log"))
## [1] "roxygen2.Rout"
So we get a makelist
and look at its targets and aliases:
ml <- packager::get_package_makelist(is_cran = TRUE)
cbind(lapply(ml, function(x) x[["target"]]),
lapply(ml, function(x) x[["alias"]]))
## [,1] [,2]
## [1,] "log/roxygen2.Rout" "roxygen2"
## [2,] "log/spell.Rout" "spell"
## [3,] "log/cleanr.Rout" "cleanr"
## [4,] "log/lintr.Rout" "lint"
## [5,] "log/covr.Rout" "covr"
## [6,] "packager::get_pkg_archive_path(absolute = FALSE)" "build"
## [7,] "log/check.Rout" "check"
## [8,] ".log.Rout" ".log"
## [9,] "log/testthat.Rout" "testthat"
## [10,] "log/vignettes.Rout" "vignettes"
## [11,] "log/codetags.Rout" "codetags"
## [12,] "log/news.Rout" "news"
## [13,] "log/usage.Rout" "usage"
## [14,] "log/winbuilder.Rout" "winbuilder"
## [15,] "log/cran_comments.Rout" "cran_comments"
## [16,] "log/check_as_cran.Rout" "check_as_cran"
## [17,] "log/submit.Rout" "submit"
Building the Package
We choose to build the package:
suppressMessages(withr::with_dir(path,
print(fakemake::make("build", ml,
verbose = FALSE))))
## Warning:
## Spell check failed, see /tmp/Rtmp6JVfXG/veryImportantPackage/log/spell.Rout for details.
## [1] "log/cleanr.Rout" "log/codetags.Rout"
## [3] "log/covr.Rout" "log/lintr.Rout"
## [5] "log/news.Rout" "log/spell.Rout"
## [7] "log/testthat.Rout" "log/usage.Rout"
## [9] "log/vignettes.Rout" "veryImportantPackage_0.1.0.tar.gz"
We note the warning
cat(git2r::diff(r, as_char = TRUE, path = file.path(".Rbuildignore")))
## diff --git a/.Rbuildignore b/.Rbuildignore
## index 16b85bc..33b3299 100644
## --- a/.Rbuildignore
## +++ b/.Rbuildignore
## @@ -13,3 +13,5 @@
## ^make\.R$
## ^\.log\.Rout$
## ^log$
## +^doc$
## +^Meta$
and see that now there are untracked files in our package’s log directory and that some files changed.
git2r::status(r)
## Untracked files:
## Untracked: log/build.Rout
## Untracked: log/cleanr.Rout
## Untracked: log/codetags.Rout
## Untracked: log/covr.Rout
## Untracked: log/lintr.Rout
## Untracked: log/news.Rout
## Untracked: log/spell.Rout
## Untracked: log/testthat.Rout
## Untracked: log/usage.Rout
## Untracked: log/vignettes.Rout
##
## Unstaged changes:
## Modified: .Rbuildignore
## Modified: .gitignore
cat(diff(r, as_char = TRUE, path = ".Rbuildignore"))
## diff --git a/.Rbuildignore b/.Rbuildignore
## index 16b85bc..33b3299 100644
## --- a/.Rbuildignore
## +++ b/.Rbuildignore
## @@ -13,3 +13,5 @@
## ^make\.R$
## ^\.log\.Rout$
## ^log$
## +^doc$
## +^Meta$
After inspecting the change, we commit:
withr::with_dir(path, packager::git_add_commit(path = ".", untracked = TRUE,
message = "make build"))
## [dc9a10f] 2020-03-13: make build
git2r::status(r)
## working directory clean
Checking the Package
So now we want the check the package:
suppressMessages(withr::with_dir(path,
print(fakemake::make("check", ml,
verbose = FALSE))))
## Warning: 'check_archive' is deprecated.
## Use 'packager::check_archive' instead.
## See help("Deprecated")
## [1] "log/cleanr.Rout" "log/covr.Rout"
## [3] "log/lintr.Rout" "log/testthat.Rout"
## [5] "veryImportantPackage_0.1.0.tar.gz" "log/check.Rout"
We again see new files and changes to old files.
git2r::status(r)
## Untracked files:
## Untracked: log/check.Rout
Note that the RUnit
test files are run while checking the tarball, hence we see output from RUnit
in our log directory.
We assume that we passed the check:
cat(tail(readLines(file.path(path, "log", "check.Rout")), n = 7), sep = "\n")
## Status: 1 WARNING
##
## See
## ‘/tmp/Rtmp6JVfXG/veryImportantPackage/veryImportantPackage.Rcheck/00check.log’
## for details.
check_log <- file.path(path, "log", "check.Rout")
status <- packager::get_check_status(check_log)
RUnit::checkEqualsNumeric(status[["status"]][["errors"]], 0)
## [1] TRUE
and commit again
withr::with_dir(path, packager::git_add_commit(path = ".", untracked = TRUE,
message = "make check"))
## [a634bd2] 2020-03-13: make check
If we choose to rerun the check without touching any files “down the make chain” (i.e. no files that any of our make targets depend on), we see there’s nothing to be done:
system.time(withr::with_dir(path, print(fakemake::make("check", ml, verbose = FALSE))))
## NULL
## user system elapsed
## 1.164 0.164 1.336
This is the big difference between running the check via fakemake
with a set of dependencies (set up with packager
) and running the check (be it using R CMD check
or rcmdcheck::rcmdcheck
or its wrapper devtools::check
) unconditionally: the latter method rebuilds and checks the whole package every time. This is why I wrote packager
and fakemake
.
Submitting the Package
Now we would like to submit our package to CRAN (which we will not do here, but we want to!) We provide comments to CRAN:
withr::with_dir(path, print(fakemake::make("cran_comments", ml, verbose = FALSE)))
## R CMD check results
## 0 errors | 1 warning | 0 notes
## Warning in get_gitlab_info(path = path, private_token = private_token): You need
## a private token to access gitlab.
## [1] "log/cran_comments.Rout"
cat(readLines(file.path(path, "cran-comments.md")), sep = "\n")
## Dear CRAN Team,
## this is a resubmission of package 'veryImportantPackage'. I have added the following changes:
##
## * Added a `NEWS.md` file to track changes to the package.
##
##
## Please upload to CRAN.
## Best, Your
##
## # Package veryImportantPackage 0.1.0
##
## Reporting is done by packager version 1.1.0
##
## ## Test environments
## - R version 3.3.3 (2017-03-06)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Devuan GNU/Linux ascii
## NA
## - win-builder (devel)
##
## ## Local test results
## - Testthat:
## OK: 1, Failed: 0, Warnings: 1, Skipped: 0
## - Coverage by covr:
##
##
## ## Local meta results
## - lintr:
## found 2 lints in 34 lines of code (a ratio of 0.0588).
## - cleanr:
## found 0 dreadful things about your code.
## - codetools::checkUsagePackage:
## found 0 issues.
## - devtools::spell_check:
## found 2 unkown words.
After editing the contents we feel ready to submit:
try(packager::submit(path))
Oops: we need to commit git first:
packager::git_add_commit(path = path, untracked = TRUE,
message = "prepare for CRAN")
## [b59e077] 2020-03-13: prepare for CRAN
git2r::status(r)
## working directory clean
Now we try and fail again, because this vignette is built in batch mode and there’s a security query which then fails:
try(packager::submit(path))
## Warning in packager::submit(path): You have no upstream!
## Ready to submit?
Should you run this code interactively, you will be prompted for the security query (as you might be used from devtools::release()
). Best you know how to write R extensions and the CRAN policies.
Anyway, we might want to tag the current commit and commence developing our package:
packager::git_tag(path = path, message = "A Tag")
## [b59e07] 0.1.0
packager::use_dev_version(path = path)
## Package version bumped from '0.1.0' to '0.1.0.9000'
## [3089bdb] 2020-03-13: Using Developement Version
desc::desc_get("Version", file = path)
## Version
## "0.1.0.9000"
cat(readLines(file.path(path, "NEWS.md")), sep = "\n")
## # veryImportantPackage 0.1.0.9000
##
## * FIXME
##
## # veryImportantPackage 0.1.0
##
## * Added a `NEWS.md` file to track changes to the package.
This is close to the workflow I have been using for most of my packages, substituting fakemake
with GNU make whenever possible.