diff --git a/.github/actions/setup-r-dependencies.yaml b/.github/actions/setup-r-dependencies.yaml new file mode 100644 index 0000000..312b140 --- /dev/null +++ b/.github/actions/setup-r-dependencies.yaml @@ -0,0 +1,220 @@ +name: 'setup-r-dependencies' +description: 'Action to setup installation tools and install R dependencies' +author: 'Jim Hester (modified by Henrik Spiegelhauer)' +inputs: + cache: + description: 'A boolean value indicating whether packages should be cached from one to the other' + required: true + default: true + cache-version: + description: 'The version of the cache, change this from the default (1) to start over with a fresh cache. Ignored if cache: false' + required: true + default: 1 + extra-packages: + description: 'Any extra packages to install outside of the packages listed in the dependencies' + needs: + description: 'Any extra Config/Needs fields which need to be included when installing dependencies' + packages: + description: 'Which package(s) to install.' + default: 'deps::., any::sessioninfo' + pak-version: + description: 'Which pak version to use. Possible values are "stable", "rc" and "devel".' + default: 'stable' + working-directory: + description: 'Using the working-directory keyword, you can specify the working directory of where "pkg_deps" command searches for dependencies in the "DESCRIPTION" file.' + default: '.' + dependencies: + description: 'Types of dependencies to install. Must be an R expression. Note that it often needs to be quoted in YAML, see the README for details.' + default: '"all"' + dependency_repo: + description: 'Overwrite the default CRAN-like reposity' + default: 'NULL' + upgrade: + description: 'Whether to install the latest available versions of the dependencies. Must be an R expression. See the README for details if you need quoting.' + default: 'FALSE' + lockfile-create-lib: + description: 'The package library to consider when creating the pak lockfile. This is passed to the `lib` argument of `pak::lockfile_create()`. Defaults to an empty library, for reproducibility. Must be an R expression. Note that it often needs to be quoted in YAML, see the README for details.' + default: 'NULL' + install-pandoc: + description: 'Whether to install pandoc. By default it is installed if it is not on the PATH and the local package suggests or depends on the rmarkdown package.' + pandoc-version: + description: 'Pandoc version to install.' + default: '3.1.11' +runs: + using: "composite" + steps: + - name: Set site library path + run: | + # Set site library path + cat("::group::Set site library path\n") + if (Sys.getenv("RENV_PROJECT") != "") { + message("renv project detected, no need to set R_LIBS_SITE") + cat(sprintf("R_LIB_FOR_PAK=%s\n", .libPaths()[1]), file = Sys.getenv("GITHUB_ENV"), append = TRUE) + q("no") + } + lib <- Sys.getenv("R_LIBS_SITE") + if (lib == "") { + lib <- file.path(dirname(.Library), "site-library") + cat(sprintf("R_LIBS_SITE=%s\n", lib), file = Sys.getenv("GITHUB_ENV"), append = TRUE) + cat(sprintf("R_LIB_FOR_PAK=%s\n", lib), file = Sys.getenv("GITHUB_ENV"), append = TRUE) + message("Setting R_LIBS_SITE to ", lib) + } else { + message("R_LIBS_SITE is already set to ", lib) + cat(sprintf("R_LIB_FOR_PAK=%s\n", strsplit(lib, .Platform$path.sep)[[1]][[1]]), file = Sys.getenv("GITHUB_ENV"), append = TRUE) + } + cat("::endgroup::\n") + shell: Rscript {0} + + - name: Install pak (Windows) + if: runner.os == 'Windows' + run: | + # Install pak + cat("::group::Install pak\n") + lib <- Sys.getenv("R_LIB_FOR_PAK") + dir.create(lib, showWarnings = FALSE, recursive = TRUE) + install.packages("pak", lib = lib, repos = sprintf( + "https://r-lib.github.io/p/pak/%s/%s/%s/%s", + "${{ inputs.pak-version }}", + .Platform$pkgType, + R.Version()$os, + R.Version()$arch + )) + cat("::endgroup::\n") + shell: Rscript {0} + + - name: Install pak (Unix) + if: runner.os != 'Windows' + run: | + # Install pak + echo "::group::Install pak" + if which sudo >/dev/null; then SUDO="sudo -E --preserve-env=PATH env"; else SUDO=""; fi + $SUDO R -q -e 'dir.create(Sys.getenv("R_LIB_FOR_PAK"), recursive = TRUE, showWarnings = FALSE)' + $SUDO R -q -e 'install.packages("pak", lib = Sys.getenv("R_LIB_FOR_PAK"), repos = sprintf("https://r-lib.github.io/p/pak/%s/%s/%s/%s", "${{ inputs.pak-version }}", .Platform$pkgType, R.Version()$os, R.Version()$arch))' + echo "::endgroup::" + shell: bash + + - name: Query dependencies + id: install + run: | + # Override the default CRAN-like repository + if ("${{ inputs.dependency_repo }}" != "NULL") { + options(repos = c(CRAN = "${{ inputs.dependency_repo }}")) + } + + # Dependency resolution + cat("::group::Dependency resolution\n") + cat("os-version=", sessionInfo()$running, "\n", file = Sys.getenv("GITHUB_OUTPUT"), sep = "", append = TRUE) + r_version <- + if (grepl("development", R.version.string)) { + pdf(tempfile()) + ge_ver <- attr(recordPlot(), "engineVersion") + dev.off() + paste0("R version ", getRversion(), " (ge:", ge_ver, "; iid:", .Internal(internalsID()), ")") + } else { + R.version.string + } + cat("r-version=", r_version, "\n", file = Sys.getenv("GITHUB_OUTPUT"), sep = "", append = TRUE) + needs <- sprintf("Config/Needs/%s", strsplit("${{ inputs.needs }}", "[[:space:],]+")[[1]]) + deps <- strsplit("${{ inputs.packages }}", "[[:space:],]+")[[1]] + extra_deps <- strsplit("${{ inputs.extra-packages }}", "[[:space:],]+")[[1]] + dir.create(".github", showWarnings=FALSE) + Sys.setenv("PKGCACHE_HTTP_VERSION" = "2") + library(pak, lib.loc = Sys.getenv("R_LIB_FOR_PAK")) + pak::lockfile_create( + c(deps, extra_deps), + lockfile = ".github/pkg.lock", + upgrade = (${{ inputs.upgrade }}), + dependencies = c(needs, (${{ inputs.dependencies }})), + lib = ${{ inputs.lockfile-create-lib }} + ) + cat("::endgroup::\n") + cat("::group::Show Lockfile\n") + writeLines(readLines(".github/pkg.lock")) + cat("::endgroup::\n") + shell: Rscript {0} + working-directory: ${{ inputs.working-directory }} + + - name: Restore R package cache + if: inputs.cache == 'true' + uses: actions/cache@v4 + with: + path: | + ${{ env.R_LIBS_USER }}/* + !${{ env.R_LIBS_USER }}/pak + key: ${{ format('{0}-{1}-{2}-{3}', steps.install.outputs.os-version, steps.install.outputs.r-version, inputs.cache-version, inputs.dependency_repo, hashFiles(format('{0}/.github/pkg.lock', inputs.working-directory ))) }} + restore-keys: ${{ steps.install.outputs.os-version }}-${{ steps.install.outputs.r-version }}-${{inputs.cache-version }}- + + - name: Install dependencies + run: | + # Override the default CRAN-like repository + if ("${{ inputs.dependency_repo }}" != "NULL") { + options(repos = c(CRAN = "${{ inputs.dependency_repo }}")) + } + + # Install/Update packages + cat("::group::Install/update packages\n") + Sys.setenv("PKGCACHE_HTTP_VERSION" = "2") + library(pak, lib.loc = Sys.getenv("R_LIB_FOR_PAK")) + pak::lockfile_install(".github/pkg.lock") + ## Clean up lock file + unlink(".github/pkg.lock") + cat("::endgroup::\n") + shell: Rscript {0} + working-directory: ${{ inputs.working-directory }} + + - name: Check whether pandoc needs to be installed + id: check-pandoc + run: | + cat("::group::Check if package needs pandoc\n") + o <- '${{ inputs.install-pandoc }}' + if (! o %in% c('true', 'false')) { + if (Sys.which("pandoc") != "") { + o <- 'false' + } else if (file.exists("DESCRIPTION")) { + deptypes <- list(direct = "all", indirect = character()) + deps <- pak::pkg_deps(".", dependencies = deptypes) + if ("rmarkdown" %in% deps$package) { + o <- 'true' + } else { + o <- 'false' + } + } else { + o <- 'false' + } + } + cat("install=", o, "\n", file = Sys.getenv("GITHUB_OUTPUT"), sep = "", append = TRUE) + cat("::endgroup::\n") + shell: Rscript {0} + working-directory: ${{ inputs.working-directory }} + + - name: Install pandoc if needed + if: ${{ steps.check-pandoc.outputs.install == 'true' }} + uses: r-lib/actions/setup-pandoc@v2 + with: + pandoc-version: ${{ inputs.pandoc-version }} + + - name: Session info + run: | + # Session info + cat("::group::Session info\n") + if (requireNamespace("sessioninfo", quietly = TRUE)) { + if (packageVersion("sessioninfo") >= "1.2.1") { + sessioninfo::session_info(pkgs = "installed", include_base = TRUE) + } else { + options(width = 200) + sessioninfo::session_info(rownames(installed.packages()), include_base=TRUE) + } + } else { + sessionInfo() + } + cat("::endgroup::\n") + shell: Rscript {0} + working-directory: ${{ inputs.working-directory }} + + - name: Don't use tar 1.30 from Rtools35 to store the cache + if: runner.os == 'Windows' + shell: bash + run: | + if command -v /c/Rtools/bin/tar && /c/Rtools/bin/tar --version | grep -q 'tar (GNU tar) 1.30' + then echo 'C:/Program Files/Git/usr/bin' >> $GITHUB_PATH + fi