Dependency floor checks #10
Workflow file for this run
This file contains hidden or 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
| name: Dependency floor checks | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| r_version: | |
| description: "R version to test. Use the latest patch release for the minimum supported R minor version." | |
| required: true | |
| default: "4.1.3" | |
| install_suggests: | |
| description: "Install Suggests too. Disable only for a faster import-only smoke check." | |
| required: false | |
| type: boolean | |
| default: true | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: dependency-floor-${{ github.ref }} | |
| cancel-in-progress: false | |
| env: | |
| GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} | |
| R_REMOTES_NO_ERRORS_FROM_WARNINGS: true | |
| _R_CHECK_FORCE_SUGGESTS_: ${{ inputs.install_suggests }} | |
| DEPENDENCY_FLOOR_CACHE_VERSION: v3 | |
| RSPM: https://packagemanager.posit.co/cran/__linux__/focal/latest | |
| R_LIBS: ${{ github.workspace }}/.cache/r-library | |
| R_LIBS_USER: ${{ github.workspace }}/.cache/r-library | |
| EUNOMIA_DATA_FOLDER: ${{ github.workspace }}/.cache/eunomia | |
| UV_CACHE_DIR: ${{ github.workspace }}/.cache/uv | |
| RETICULATE_PY_VERSION: 3.11 | |
| jobs: | |
| dependency-floor: | |
| runs-on: ubuntu-latest | |
| container: rocker/r-ver:${{ inputs.r_version }} | |
| steps: | |
| - name: Checkout repo | |
| uses: actions/checkout@v5 | |
| - name: Install system requirements | |
| run: | | |
| apt-get update | |
| apt-get install -y --no-install-recommends \ | |
| build-essential \ | |
| cmake \ | |
| curl \ | |
| default-jdk \ | |
| git \ | |
| libbz2-dev \ | |
| libcurl4-openssl-dev \ | |
| libfontconfig1-dev \ | |
| libfreetype6-dev \ | |
| libfribidi-dev \ | |
| libgit2-dev \ | |
| libharfbuzz-dev \ | |
| libicu-dev \ | |
| libjpeg-dev \ | |
| liblzma-dev \ | |
| libomp-dev \ | |
| libpng-dev \ | |
| libssh-dev \ | |
| libssl-dev \ | |
| libtiff5-dev \ | |
| libwebp-dev \ | |
| libxml2-dev \ | |
| make \ | |
| pandoc \ | |
| pkg-config \ | |
| python3 \ | |
| python3-pip \ | |
| python3-venv \ | |
| zlib1g-dev | |
| R CMD javareconf | |
| - name: Prepare caches | |
| run: | | |
| mkdir -p "${R_LIBS_USER}" "${EUNOMIA_DATA_FOLDER}" "${UV_CACHE_DIR}" | |
| - name: Restore R library cache | |
| id: cache-r-library-restore | |
| uses: actions/cache/restore@v5 | |
| with: | |
| path: ${{ env.R_LIBS_USER }} | |
| key: dependency-floor-${{ env.DEPENDENCY_FLOOR_CACHE_VERSION }}-focal-r${{ inputs.r_version }}-suggests-${{ inputs.install_suggests }}-${{ hashFiles('DESCRIPTION') }} | |
| restore-keys: | | |
| dependency-floor-${{ env.DEPENDENCY_FLOOR_CACHE_VERSION }}-focal-r${{ inputs.r_version }}-suggests-${{ inputs.install_suggests }}- | |
| - name: Cache Eunomia datasets | |
| uses: actions/cache@v5 | |
| with: | |
| path: ${{ env.EUNOMIA_DATA_FOLDER }} | |
| key: eunomia-v1-${{ runner.os }}-GiBleed_5.3 | |
| - name: Cache uv | |
| uses: actions/cache@v5 | |
| with: | |
| path: ${{ env.UV_CACHE_DIR }} | |
| key: uv-v1-${{ runner.os }}-py${{ env.RETICULATE_PY_VERSION }} | |
| - name: Install dependency floor | |
| shell: Rscript {0} | |
| env: | |
| INSTALL_SUGGESTS: ${{ inputs.install_suggests }} | |
| run: | | |
| .libPaths(c(Sys.getenv("R_LIBS_USER"), .libPaths())) | |
| message("R library paths: ", paste(.libPaths(), collapse = ", ")) | |
| repos <- Sys.getenv("RSPM", unset = "https://cloud.r-project.org") | |
| install.packages(c("remotes", "rcmdcheck"), repos = repos) | |
| options(Ncpus = max(1L, parallel::detectCores())) | |
| installSuggests <- tolower(Sys.getenv("INSTALL_SUGGESTS", unset = "false")) == "true" | |
| description <- read.dcf("DESCRIPTION")[1, ] | |
| hardDependencyFields <- intersect(c("Depends", "Imports", "LinkingTo"), names(description)) | |
| dependencyFields <- hardDependencyFields | |
| suggestedPackages <- character() | |
| dependencyFields <- intersect(dependencyFields, names(description)) | |
| message("Installing dependency fields: ", paste(dependencyFields, collapse = ", ")) | |
| parseDependencies <- function(fields) { | |
| dependencyText <- paste(description[fields], collapse = ",") | |
| dependencyText <- gsub("[\r\n]", " ", dependencyText) | |
| dependencies <- trimws(unlist(strsplit(dependencyText, ","))) | |
| dependencies <- dependencies[nzchar(dependencies)] | |
| parsed <- regexec("^([A-Za-z0-9.]+)\\s*(?:\\(([^ ]+)\\s*([^)]+)\\))?$", dependencies) | |
| parsed <- regmatches(dependencies, parsed) | |
| parsed <- do.call(rbind, lapply(parsed, function(x) { | |
| length(x) <- 4 | |
| data.frame( | |
| package = x[2], | |
| operator = x[3], | |
| version = x[4], | |
| stringsAsFactors = FALSE | |
| ) | |
| })) | |
| parsed[parsed$package != "R", ] | |
| } | |
| parsed <- parseDependencies(dependencyFields) | |
| if (installSuggests && "Suggests" %in% names(description)) { | |
| suggested <- parseDependencies("Suggests") | |
| suggestedPackages <- suggested$package | |
| parsed <- rbind(parsed, suggested) | |
| } | |
| floorDependencies <- parsed[parsed$operator == ">=", ] | |
| write.csv(floorDependencies, "dependency-floor-requested.csv", row.names = FALSE) | |
| if (installSuggests) { | |
| compatibilityPins <- data.frame( | |
| package = c("Matrix", "arrow", "pbkrtest", "xgboost"), | |
| version = c("1.6-5", "17.0.0", "0.5.2", "1.7.8.1"), | |
| stringsAsFactors = FALSE | |
| ) | |
| write.csv(compatibilityPins, "dependency-floor-compatibility-pins.csv", row.names = FALSE) | |
| for (i in seq_len(nrow(compatibilityPins))) { | |
| package <- compatibilityPins$package[[i]] | |
| version <- compatibilityPins$version[[i]] | |
| message("Installing old-R compatibility pin: ", package, " ", version) | |
| remotes::install_version( | |
| package = package, | |
| version = version, | |
| repos = repos, | |
| dependencies = FALSE, | |
| upgrade = "never" | |
| ) | |
| } | |
| } else { | |
| write.csv(data.frame(package = character(), version = character()), | |
| "dependency-floor-compatibility-pins.csv", | |
| row.names = FALSE | |
| ) | |
| } | |
| remotes::install_deps( | |
| dependencies = hardDependencyFields, | |
| repos = repos, | |
| upgrade = "never" | |
| ) | |
| if (length(suggestedPackages) > 0) { | |
| installedPackages <- rownames(installed.packages()) | |
| suggestedPackages <- setdiff(suggestedPackages, installedPackages) | |
| if (length(suggestedPackages) > 0) { | |
| message("Installing direct suggested packages: ", paste(suggestedPackages, collapse = ", ")) | |
| install.packages( | |
| suggestedPackages, | |
| repos = repos, | |
| dependencies = hardDependencyFields | |
| ) | |
| } | |
| missingSuggestedPackages <- setdiff(suggestedPackages, rownames(installed.packages())) | |
| if (length(missingSuggestedPackages) > 0) { | |
| stop( | |
| "Failed to install direct suggested packages: ", | |
| paste(missingSuggestedPackages, collapse = ", ") | |
| ) | |
| } | |
| } | |
| sourceFloorPackages <- c("Andromeda", "FeatureExtraction") | |
| sourceRepos <- "https://cloud.r-project.org" | |
| for (i in seq_len(nrow(floorDependencies))) { | |
| package <- floorDependencies$package[[i]] | |
| version <- floorDependencies$version[[i]] | |
| useSource <- package %in% sourceFloorPackages | |
| message( | |
| "Installing floor dependency: ", | |
| package, | |
| " ", | |
| version, | |
| if (useSource) " from source" else "" | |
| ) | |
| remotes::install_version( | |
| package = package, | |
| version = version, | |
| repos = if (useSource) sourceRepos else repos, | |
| dependencies = FALSE, | |
| upgrade = "never", | |
| type = if (useSource) "source" else getOption("pkgType") | |
| ) | |
| } | |
| installed <- as.data.frame(installed.packages()[, c("Package", "Version")]) | |
| declared <- parsed$package | |
| installed <- installed[installed$Package %in% declared, ] | |
| installed <- installed[order(tolower(installed$Package)), ] | |
| write.csv(installed, "dependency-floor-installed.csv", row.names = FALSE) | |
| - name: Save R library cache | |
| if: steps.cache-r-library-restore.outputs.cache-hit != 'true' | |
| uses: actions/cache/save@v5 | |
| with: | |
| path: ${{ env.R_LIBS_USER }} | |
| key: ${{ steps.cache-r-library-restore.outputs.cache-primary-key }} | |
| - name: Run R CMD check | |
| shell: Rscript {0} | |
| run: | | |
| .libPaths(c(Sys.getenv("R_LIBS_USER"), .libPaths())) | |
| message("R library paths: ", paste(.libPaths(), collapse = ", ")) | |
| result <- rcmdcheck::rcmdcheck( | |
| args = c("--no-manual", "--no-build-vignettes", "--ignore-vignettes"), | |
| build_args = c("--no-manual", "--no-build-vignettes"), | |
| error_on = "warning", | |
| check_dir = "check" | |
| ) | |
| print(result) | |
| - name: Upload results | |
| if: always() | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: dependency-floor-results | |
| path: | | |
| check | |
| dependency-floor-requested.csv | |
| dependency-floor-compatibility-pins.csv | |
| dependency-floor-installed.csv |