Chore: customize github workflows to correctly install system dependencies #172
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Source: https://github.com/pharmaverse/admiralci | |
# Stripped down version of admiralci checks. Good for | |
# the developement process. When package is ready to | |
# be published, revisit and add release-related | |
# workflows. | |
# Instead of using reusable actions provided by admiralci, | |
# the actions are inlined in the workflow file. This is | |
# because some of the R dependencies required system packages | |
# not available/installable using reusable actions. | |
# If any updates are available, the workflow should be | |
# updated manually. | |
# Last update: 2025-01-07 | |
name: Modified Admiral CI/CD Wortkflows | |
on: | |
workflow_dispatch: | |
push: | |
branches: | |
- main | |
pull_request: | |
branches: | |
- main | |
concurrency: | |
group: admiral-${{ github.event.pull_request.number || github.ref }} | |
cancel-in-progress: true | |
env: | |
R_VERSION: "release" | |
jobs: | |
get_r_version: | |
name: Get R version | |
runs-on: ubuntu-latest | |
outputs: | |
r-version: ${{ steps.get_r_version.outputs.R_VERSION }} | |
steps: | |
- name: Get R Version for Downstream Container Jobs | |
id: get_r_version | |
run: echo "R_VERSION=$R_VERSION" >> $GITHUB_OUTPUT | |
shell: bash | |
spellcheck: | |
name: Spelling | |
runs-on: ubuntu-latest | |
needs: get_r_version | |
container: | |
image: "ghcr.io/pharmaverse/admiralci-${{ needs.get_r_version.outputs.r-version }}:latest" | |
steps: | |
- name: Get branch names | |
id: branch-name | |
uses: tj-actions/branch-names@v8 | |
- name: Checkout repo | |
uses: actions/[email protected] | |
if: github.event_name == 'pull_request' | |
with: | |
ref: ${{ steps.branch-name.outputs.head_ref_branch }} | |
repository: ${{ github.event.pull_request.head.repo.full_name }} | |
- name: Restore cache | |
uses: actions/cache@v4 | |
with: | |
path: | | |
~/.staged.dependencies | |
key: staged-deps | |
- name: Run Staged dependencies | |
uses: insightsengineering/staged-dependencies-action@v1 | |
with: | |
run-system-dependencies: true | |
renv-restore: false | |
enable-check: false | |
direction: upstream | |
git-ref: ${{ steps.branch-name.outputs.current_branch }} | |
- name: Run Spellcheck | |
uses: insightsengineering/r-spellcheck-action@v3 | |
lint: | |
name: Lint | |
runs-on: ubuntu-latest | |
needs: get_r_version | |
container: | |
image: "ghcr.io/pharmaverse/admiralci-${{ needs.get_r_version.outputs.r-version }}:latest" | |
steps: | |
- name: Get branch names | |
id: branch-name | |
uses: tj-actions/branch-names@v8 | |
- name: Checkout repo | |
uses: actions/[email protected] | |
if: github.event_name == 'pull_request' | |
with: | |
ref: ${{ steps.branch-name.outputs.head_ref_branch }} | |
repository: ${{ github.event.pull_request.head.repo.full_name }} | |
- name: Restore cache | |
uses: actions/cache@v4 | |
with: | |
path: | | |
~/.staged.dependencies | |
key: staged-deps | |
- name: Run Staged dependencies | |
uses: insightsengineering/staged-dependencies-action@v1 | |
with: | |
run-system-dependencies: true | |
renv-restore: false | |
enable-check: false | |
direction: upstream | |
git-ref: ${{ steps.branch-name.outputs.current_branch }} | |
- name: Install latest release of lintr | |
shell: Rscript {0} | |
run: | | |
install.packages("lintr", repos = "https://packagemanager.posit.co/cran/latest/") | |
- name: Lint | |
shell: Rscript {0} | |
run: | | |
lints <- lintr::lint_package() | |
if (length(lints) > 0L) { | |
print(lints) | |
stop("Lints detected. Please review and adjust code according to the comments provided.", call. = FALSE) | |
} | |
man-pages: | |
name: Man Pages | |
runs-on: ubuntu-latest | |
needs: get_r_version | |
container: | |
image: "ghcr.io/pharmaverse/admiralci-${{ needs.get_r_version.outputs.r-version }}:latest" | |
steps: | |
- name: Get branch names | |
id: branch-name | |
uses: tj-actions/branch-names@v8 | |
- name: Checkout repo | |
uses: actions/[email protected] | |
if: github.event_name == 'pull_request' | |
with: | |
ref: ${{ steps.branch-name.outputs.head_ref_branch }} | |
- name: Restore cache | |
uses: actions/cache@v4 | |
with: | |
path: | | |
~/.staged.dependencies | |
key: staged-deps | |
- name: Run Staged dependencies | |
uses: insightsengineering/staged-dependencies-action@v1 | |
with: | |
run-system-dependencies: false | |
renv-restore: false | |
enable-check: false | |
direction: upstream | |
git-ref: ${{ steps.branch-name.outputs.current_branch }} | |
- name: Install dependencies | |
run: | | |
Rscript -e 'pak::local_install_deps(dependencies = TRUE)' | |
- name: Generate man pages | |
run: roxygen2::roxygenize('.', roclets = c('rd', 'collate', 'namespace')) | |
shell: Rscript {0} | |
- name: Set-up safe dir | |
run: git config --global --add safe.directory "${GITHUB_WORKSPACE}" | |
shell: bash | |
- name: Roxygen check | |
run: | | |
git status -s | |
if [[ -n `git status -s | grep -E "man|DESCRIPTION"` ]] | |
then { | |
ROXYGEN_VERSION="$(Rscript -e 'packageVersion("roxygen2")' | awk '{print $NF}')" | |
echo "🙈 Manuals are not up-to-date with roxygen comments!" | |
echo "🔀 The following differences were noted:" | |
git diff man/* DESCRIPTION | |
echo -e "\n💻 Please rerun the following command on your workstation and push your changes" | |
echo "--------------------------------------------------------------------" | |
echo "roxygen2::roxygenize('.', roclets = c('rd', 'collate', 'namespace'))" | |
echo "--------------------------------------------------------------------" | |
echo "ℹ roxygen2 version that was used in this workflow: $ROXYGEN_VERSION" | |
echo "🙏 Please ensure that the 'RoxygenNote' field in the DESCRIPTION file matches this version" | |
exit 1 | |
} else { | |
echo "💚 Manuals are up-to-date with roxygen comments" | |
} | |
fi | |
shell: bash | |
tests: | |
name: Tests | |
runs-on: ubuntu-latest | |
needs: get_r_version | |
container: | |
image: "ghcr.io/pharmaverse/admiralci-${{ needs.get_r_version.outputs.r-version }}:latest" | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v2 | |
- name: Install dependencies | |
run: | | |
Rscript -e 'pak::local_install_deps(dependencies = TRUE)' | |
- name: Run tests | |
shell: Rscript {0} | |
run: | | |
devtools::load_all(".") | |
devtools::test() | |
check: | |
runs-on: ubuntu-latest | |
needs: | |
- spellcheck | |
- tests | |
- lint | |
- man-pages | |
container: | |
image: "ghcr.io/pharmaverse/admiralci-${{ matrix.r_version }}:latest" | |
name: Check (${{ matrix.r_version }}) | |
strategy: | |
fail-fast: false | |
matrix: | |
r_version: ["release", "devel", "oldrel"] | |
env: | |
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} | |
R_KEEP_PKG_SOURCE: true | |
R_REMOTES_NO_ERRORS_FROM_WARNINGS: true | |
R_REPOS: "https://cran.r-project.org" | |
DEPS_IGNORE: >- | |
pharmaversesdtm, | |
pharmaverseadam, | |
admiral, | |
admiraldev, | |
admiralophtha, | |
admiralonco, | |
admiralvaccine, | |
staged.dependencies | |
steps: | |
- name: Get branch names | |
id: branch-name | |
uses: tj-actions/branch-names@v8 | |
- name: Checkout repo | |
uses: actions/[email protected] | |
if: | | |
github.event_name == 'pull_request' | |
with: | |
ref: ${{ steps.branch-name.outputs.head_ref_branch }} | |
repository: ${{ github.event.pull_request.head.repo.full_name }} | |
- name: Restore cache | |
uses: actions/cache@v4 | |
with: | |
path: | | |
~/.staged.dependencies | |
key: staged-deps | |
- name: Run Staged dependencies | |
uses: insightsengineering/staged-dependencies-action@v1 | |
if: | | |
(github.event_name == 'workflow_dispatch' && matrix.r_version == 'devel') || | |
matrix.r_version != 'devel' | |
with: | |
git-ref: ${{ steps.branch-name.outputs.current_branch }} | |
run-system-dependencies: false | |
renv-restore: false | |
enable-check: false | |
cran-repos: "https://cloud.r-project.org" | |
direction: upstream | |
- name: Install dependencies from DESCRIPTION | |
if: | | |
(github.event_name == 'workflow_dispatch' && matrix.r_version == 'devel') || | |
matrix.r_version != 'devel' | |
run: | | |
Rscript -e 'pak::local_install_deps(dependencies = TRUE)' | |
- name: Upload dependencies artifact | |
if: | | |
(github.event_name == 'workflow_dispatch' && matrix.r_version == 'devel') || | |
matrix.r_version != 'devel' | |
run: | | |
dir.create("/workspace/tmp") | |
library(dplyr) | |
installed_packages <- as.data.frame(installed.packages()) | |
packages_to_remove <- Sys.getenv("DEPS_IGNORE", "") | |
packages_to_remove <- unlist(strsplit(packages_to_remove, ",")) | |
installed_packages <- installed_packages %>% filter(LibPath != "/usr/local/lib/R/library") %>% # remove pre-built deps | |
filter(!Package %in% packages_to_remove) | |
# save deps as csv file | |
write.csv(installed_packages, "/workspace/tmp/deps-${{ matrix.r_version }}.csv", row.names = FALSE) | |
# create also renv.lock file | |
setwd("/workspace/tmp") | |
renv_lock <- list( | |
"R" = list( | |
"Version" = paste(R.version$major, R.version$minor, sep=".") | |
), | |
"Repositories" = list( | |
list(Name = "CRAN", URL = Sys.getenv("R_REPOS")) | |
), | |
"Packages" = list() | |
) | |
# Populate with information about each package | |
for (package in installed_packages$Package) { | |
dep_name <- package | |
dep_version <- installed_packages[installed_packages$Package == package, "Version"] | |
version_parts <- strsplit(dep_version, "\\.")[[1]] | |
if (length(version_parts) == 4) { | |
print(sprintf("skipping installation of dep %s", dep_name)) | |
} else { | |
print(sprintf("append dependency %s - version %s", dep_name, dep_version)) | |
requirements <- tools::package_dependencies(dep_name, recursive = TRUE) | |
have_requirements <- length(requirements[[1]]) > 0 | |
if (have_requirements) { | |
renv_lock[["Packages"]][[dep_name]] <- list( | |
"Package" = dep_name, | |
"Version" = dep_version, | |
"Source" = "Repository", | |
"Repository" = "CRAN", | |
"Requirements" = requirements[[dep_name]] | |
) | |
} else { | |
renv_lock[["Packages"]][[dep_name]] <- list( | |
"Package" = dep_name, | |
"Version" = dep_version, | |
"Source" = "Repository", | |
"Repository" = "CRAN" | |
) | |
} | |
} | |
} | |
# Write the list to a JSON file (renv.lock) | |
writeLines(jsonlite::toJSON(renv_lock, pretty = TRUE, auto_unbox = TRUE), "renv-${{ matrix.r_version }}.lock") | |
print("generated renv.lock content") | |
system("cat renv-${{ matrix.r_version }}.lock") | |
shell: Rscript {0} | |
- name: Upload deps.csv and renv.lock artifacts | |
uses: actions/upload-artifact@v4 | |
if: | | |
(github.event_name == 'workflow_dispatch' && matrix.r_version == 'devel') || | |
matrix.r_version != 'devel' | |
with: | |
name: deps-${{ matrix.r_version }} | |
path: | | |
/workspace/tmp/ | |
- name: Check Version | |
id: check_version | |
if: | | |
(github.event_name == 'workflow_dispatch' && matrix.r_version == 'devel') || | |
matrix.r_version != 'devel' | |
run: | | |
maintenance_version="F" | |
description_dat <- readLines("DESCRIPTION") | |
for (i in seq_along(description_dat)) { | |
if (grepl("^Version:", description_dat[i])) { | |
current_version <- sub("^Version: ", "", description_dat[i]) | |
version_parts <- strsplit(current_version, "\\.")[[1]] | |
# check if maintenance version | |
if (length(version_parts) == 4) { | |
print("Maintenance version detected (format X.Y.Z.M with M >= 9000)") | |
maintenance_version="T" | |
} | |
} | |
} | |
cat(sprintf("maintenance_version=%s", maintenance_version), file = Sys.getenv("GITHUB_OUTPUT"), append = TRUE) | |
shell: Rscript {0} | |
- name: Check | |
if: | | |
(github.event_name == 'workflow_dispatch' && matrix.r_version == 'devel') || | |
matrix.r_version != 'devel' | |
env: | |
_R_CHECK_CRAN_INCOMING_REMOTE_: false | |
_R_CHECK_FORCE_SUGGESTS_: false | |
run: | | |
unlink("tmp",recursive=TRUE) | |
if ("${{ steps.check_version.outputs.maintenance_version }}" == "T"){ | |
Sys.setenv("_R_CHECK_CRAN_INCOMING_SKIP_LARGE_VERSION_" = TRUE) | |
} | |
if (!requireNamespace("rcmdcheck", quietly = TRUE)) install.packages("rcmdcheck") | |
options(crayon.enabled = TRUE) | |
check_error_on <- "error" | |
if (check_error_on == "") { | |
check_error_on <- "note" | |
} | |
rcmdcheck::rcmdcheck( | |
args = c("--no-manual", "--as-cran"), | |
error_on = check_error_on, | |
check_dir = "check" | |
) | |
shell: Rscript {0} | |
- name: Upload check results | |
if: failure() | |
uses: actions/upload-artifact@v4 | |
with: | |
name: r${{ matrix.r_version }}-results | |
path: check | |