Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Save a warmed R package cache for faster installs in failing Actions #695

Merged
merged 16 commits into from
May 8, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion setup-r-dependencies/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ This action install dependencies for the current R environment based on the DESC
Inputs available

- `cache` - default `true`. Whether packages should be cached across runs or
gaborcsardi marked this conversation as resolved.
Show resolved Hide resolved
not.
not. If `"always"` is provided, the package cache will be saved even if the Action fails.
- `cache-version` - default `1`. If you need to invalidate the existing
cache pass any other number and a new cache will be used. Ignored if
`cache: false`. Note that you can also [delete caches
Expand All @@ -40,6 +40,8 @@ Inputs available
you need quoting. Defaults to `FALSE`.
- `working-directory` - default `'.'`. If the DESCRIPTION file is not in the
root directory of your repository.
- `prune` - default `true`. Used when `cache="always"`. Whether to prune the R
library of packages not found within the lock file used for installation.
schloerke marked this conversation as resolved.
Show resolved Hide resolved

Basic:
```yaml
Expand Down
91 changes: 82 additions & 9 deletions setup-r-dependencies/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description: 'Action to setup installation tools and install R dependencies'
author: 'Jim Hester'
inputs:
cache:
description: 'A boolean value indicating whether packages should be cached from one to the other'
description: 'Whether packages should be cached across runs or not. If `"always"` is provided, the package cache will be saved even if the Action fails.'
required: true
default: true
cache-version:
Expand All @@ -29,6 +29,9 @@ inputs:
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'
prune:
description: 'Whether to prune the R library of packages not found within the lock file used for installation.'
schloerke marked this conversation as resolved.
Show resolved Hide resolved
default: true
runs:
using: "composite"
steps:
Expand Down Expand Up @@ -111,29 +114,99 @@ runs:
shell: Rscript {0}
working-directory: ${{ inputs.working-directory }}

- name: Restore R package cache
- name: Restore R package cache keys
id: cache-args
if: inputs.cache != 'false'
shell: bash
run: |
# Make cache args
RESTORE_KEY="${{ format('{0}-{1}-{2}', steps.install.outputs.os-version, steps.install.outputs.r-version, inputs.cache-version) }}"
PRIMARY_KEY="$RESTORE_KEY-${{ hashFiles(format('{0}/.github/pkg.lock', inputs.working-directory )) }}"
echo "key=$PRIMARY_KEY" >> $GITHUB_OUTPUT
echo "restore-keys=$RESTORE_KEY" >> $GITHUB_OUTPUT

# Make cache path
echo "path<<EOF" >> $GITHUB_OUTPUT
echo '${{ env.R_LIBS_USER }}/*' >> $GITHUB_OUTPUT
echo '!${{ env.R_LIBS_USER }}/pak' >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT

- name: Restore R package cache (and save cache on successful Action)
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, hashFiles(format('{0}/.github/pkg.lock', inputs.working-directory ))) }}
restore-keys: ${{ steps.install.outputs.os-version }}-${{ steps.install.outputs.r-version }}-${{inputs.cache-version }}-
path: ${{ steps.cache-args.outputs.path }}
key: ${{ steps.cache-args.outputs.key }}
restore-keys: ${{ steps.cache-args.outputs.restore-keys }}

- name: Restore R package cache
if: inputs.cache == 'always'
id: r-pkg-cache
uses: actions/cache/restore@v3
with:
path: ${{ steps.cache-args.outputs.path }}
key: ${{ steps.cache-args.outputs.key }}
restore-keys: ${{ steps.cache-args.outputs.restore-keys }}

- name: Install dependencies
id: install-pkgs
run: |
# 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
pkgs <- pak::lockfile_install(".github/pkg.lock")
# Store the installed packages
packages <- paste0(pkgs$package, collapse = "|")
cat("packages=", packages, "\n", file = Sys.getenv("GITHUB_OUTPUT"), sep = "", append = TRUE)
cat("::endgroup::\n")
shell: Rscript {0}
working-directory: ${{ inputs.working-directory }}

- name: Prune unused R packages
if: inputs.cache == 'always' && inputs.prune == 'true'
gaborcsardi marked this conversation as resolved.
Show resolved Hide resolved
run: |
# Prune packages
cat("::group::Prune unnecessary packages\n")
installed_df <- as.data.frame(installed.packages(), stringsAsFactors = FALSE)
installed_packages <- installed_df$Package
core_pkgs <- c(
"translations", # Core package on windows
installed_packages[!is.na(installed_df$Priority)]
)
pak_pkgs <- c(
"pak", # Never remove pak
strsplit("${{ steps.install-pkgs.outputs.packages }}", "|", fixed = TRUE)[[1]]
)
to_remove_pkgs <- setdiff(installed_packages, c(core_pkgs, pak_pkgs))
if (length(to_remove_pkgs) > 0) {
cat("Removing unnecessary packages: ", paste0(to_remove_pkgs, collapse = ", "), "\n")
remove.packages(to_remove_pkgs)
} else {
cat("No unnecessary packages to remove\n")
}
cat("::endgroup::\n")
shell: Rscript {0}
working-directory: ${{ inputs.working-directory }}

- name: Clean up lock file
run: |
# Clean up lock file
cat("::group::Clean up lock file\n")
unlink(".github/pkg.lock")
cat("::endgroup::\n")
shell: Rscript {0}
working-directory: ${{ inputs.working-directory }}

# Step used to help speed up package installation on troublesome Actions
- name: Save R package cache
# If `actions/cache/restore@v3` restored from `cache-primary-key`, then `cache-hit == 'true'`; If so, do not save cache
if: inputs.cache == 'always' && steps.r-pkg-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v3
with:
path: ${{ steps.cache-args.outputs.path }}
key: ${{ steps.r-pkg-cache.outputs.cache-primary-key }}

- name: Session info
run: |
# Session info
Expand Down
Loading