Skip to content

memoise_bioc_available(): query all Bioconductor repositories, not just BioCsoft - #402

Draft
aclark02-arcus wants to merge 2 commits into
pharmaR:masterfrom
aclark02-arcus:bioc-all-repositories
Draft

aclark02-arcus wants to merge 2 commits into
pharmaR:masterfrom
aclark02-arcus:bioc-all-repositories

Conversation

@aclark02-arcus

@aclark02-arcus aclark02-arcus commented Jul 29, 2026 •

Copy link
Copy Markdown

Motivation

Two related bugs bite pkg_ref() / pkg_bioc() / pkg_assess() for Bioconductor packages, both surfaced by field-testing on internal Posit Package Manager (PPM) mirrors but with knock-on effects on the public-network path too.

1. memoise_bioc_available() only sees the software repo

The current implementation hard-codes:

url("https://bioconductor.org/packages/release/bioc/src/contrib/PACKAGES")

That gives it only the BioCsoft snapshot, so annotation, experiment, workflow and books packages (~1,400 additional in Bioc 3.22) are invisible to pkg_bioc() / pkg_ref(). On air-gapped hosts the URL is unreachable entirely, and every BioC assessment fails with:

cannot open the connection to 'https://bioconductor.org/packages/release/bioc/src/contrib/PACKAGES'

2. pkg_bioc() throws away the resolved repository

Even after memoise_bioc_available() starts returning the correct Repository column, pkg_bioc() builds the pkg_bioc_remote reference with:

repo = "https://bioconductor.org/packages/release/bioc"

hard-coded. So x$repo_base_url is always bioconductor.org, and every downstream metric that scrapes x$web_html (has_news, remote_checks, news_current, has_vignettes, has_maintainer, bugs_status, has_source_control, has_bug_reports_url, license, ...) hits bioconductor.org too:

Failed to connect to bioconductor.org port 443: Connection refused

Changes

  • memoise_bioc_available() rewritten to query every Bioconductor repository from bioc_repositories() via utils::available.packages(), dedup by Package (software repo wins), preserve the Repository column, and stay memoised. Public-network callers still get https://bioconductor.org/... in Repository; air-gapped callers get the internal mirror URL — automatically.
  • pkg_bioc() now uses the Repository column, stripping the trailing /src/contrib. x$repo_base_url therefore points at the actual mirror, not bioconductor.org.
  • bioc_repositories() (new helper) resolves the repo set in order of specificity:
    1. options("riskmetric.bioc_repos") — explicit override.
    2. Sys.getenv("RISKMETRIC_BIOC_REPOS") — comma-separated URLs.
    3. BiocManager::repositories() entries whose names begin BioC (existing behaviour; public network unchanged).
    4. options("repos") entries whose name begins BioC or whose URL contains bioconductor / /bioc/. This covers PPM setups where the BioC snapshot is only surfaced via options("repos") (e.g. c(CRAN = "<ppm>/cran/latest", BioC = "<ppm>/bioconductor-3.22/latest")), not through BiocManager::repositories().
  • is_available_cran() now short-circuits FALSE when the package is also present in memoise_bioc_available(). verify_pkg_source() dispatches CRAN-before-BioC, so before this change any BioC package advertised through options("repos") alongside a CRAN repo was classified as pkg_cran_remote — which then broke pkg_ref_cache.examples (no pkg_cran_remote method) and routed remote_checks / web_url through the CRAN scrape paths against a Bioconductor package. This affects on-network sessions as much as air-gapped ones whenever options(repos) contains both a CRAN and a BioC entry.
  • assess_dependencies.pkg_bioc_remote() now queries all Bioconductor repos (previously only the first entry of BiocManager::repositories()), with a fallback to preserve current behaviour if bioc_repositories() is empty.

Compatibility

  • No new dependencies.
  • Public-network callers who don't set the new option/env var get the same behaviour as before for the BiocManager::repositories() path (BioCsoft, BioCann, BioCexp, BioCworkflows, BioCbooks). The two new fall-throughs (options(repos) and explicit override) only apply when the earlier tiers return nothing.
  • No signature changes on any exported function.

Tests

New / expanded tests in tests/testthat/test_memoise_bioc_available.R:

  1. Existing tests for memoise_bioc_available() querying all five BioC repos and pkg_bioc() picking up the Repository column.
  2. bioc_repositories() honours options("riskmetric.bioc_repos").
  3. bioc_repositories() honours Sys.getenv("RISKMETRIC_BIOC_REPOS").
  4. bioc_repositories() falls through to options("repos") and matches on URL pattern when BiocManager::repositories() errors.
  5. is_available_cran() vetoes packages known to memoise_bioc_available() even when memoise_available_packages() still reports them.

Related

Companion draft PR: #401 replaces devtools::revdep(bioconductor = TRUE) inside assess_reverse_dependencies.default() (same air-gapped failure class, hits .../VIEWS instead of .../PACKAGES).

Opened as a draft for maintainer discussion.

Previously memoise_bioc_available() hard-coded a single URL:

  https://bioconductor.org/packages/release/bioc/src/contrib/PACKAGES

which corresponds to BioCsoft (the software repository) only. That meant
packages hosted in BioCann, BioCexp, BioCworkflows and BioCbooks - ~1,400
additional packages in Bioconductor 3.22 - were invisible to pkg_bioc()
and pkg_ref(), so risk assessments couldn't be produced for them.

Query every BioC* repository advertised by BiocManager::repositories()
via utils::available.packages(), combine the results, and record the
actual repository each package resolves from. pkg_bioc() now uses that
repository URL instead of hard-coding release/bioc, and
assess_dependencies.pkg_bioc_remote() likewise queries all BioC repos
instead of only the first entry of BiocManager::repositories().

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR expands Bioconductor package discovery so riskmetric can recognize and assess packages hosted outside the BioCsoft (“software”) repo (e.g., annotation/experiment/workflows/books), by querying all BioC* repositories advertised by BiocManager::repositories().

Changes:

  • Update memoise_bioc_available() to query multiple Bioconductor repositories via utils::available.packages() and add a new bioc_repositories() helper.
  • Update pkg_bioc() to derive its repository URL from the matched package’s repository entry (instead of hard-coding BioCsoft).
  • Update assess_dependencies.pkg_bioc_remote() to query dependencies across all BioC repositories and add targeted tests + NEWS entry.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
R/utils_memoised.R Reworks Bioconductor availability lookup and introduces bioc_repositories() helper.
R/pkg_ref_class.R Adjusts pkg_bioc() to record the repository a package resolves from.
R/assess_dependencies.R Expands dependency lookup to search across all Bioconductor repositories.
tests/testthat/test_memoise_bioc_available.R Adds unit tests for repo filtering and multi-repo availability behavior.
NEWS.md Documents the expanded Bioconductor repository coverage.
Comments suppressed due to low confidence (1)

tests/testthat/test_memoise_bioc_available.R:81

  • Same as above: .local will be non-NULL under the test harness, so this call will try to read a local Bioc fixture (and currently errors because the fixture file is missing) rather than exercising the intended no-network path. Pass .local = NULL to force the code path under test.
    repositories = function(...) character(0),
    .package = "BiocManager",
    {
      out <- memoise_bioc_available()
      expect_s3_class(out, "data.frame")
      expect_equal(nrow(out), 0L)
      expect_true(all(c("Package", "Version", "Repository") %in% names(out)))
    }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

available.packages = function(repos = NULL, ...) fake_ap,
.package = "utils",
{
out <- memoise_bioc_available()
Comment thread R/utils_memoised.R
Comment on lines +64 to +73
if (!is.null(.local)) {
db <- read.csv(
file.path(.local, "test_webmocks", "data", "bioc_packages.csv"),
stringsAsFactors = FALSE)
if (!"Repository" %in% names(db)) {
db[["Repository"]] <- paste0(
"https://bioconductor.org/packages/release/bioc", "/src/contrib")
}
return(db)
}
Comment thread R/assess_dependencies.R
Comment on lines +65 to +67
bioc_repos <- bioc_repositories()
if (length(bioc_repos) == 0L) bioc_repos <- BiocManager::repositories()[1]
get_package_dependencies(x$name, repo = bioc_repos)
Comment thread R/pkg_ref_class.R
Comment on lines +213 to +217
repo <- if ("Repository" %in% colnames(info) && nrow(info) > 0L) {
sub("/src/contrib$", "", info[, "Repository"][1])
} else {
"https://bioconductor.org/packages/release/bioc"
}
aclark02-arcus added a commit to pharmaR/val.pipeline that referenced this pull request Jul 30, 2026
Released riskmetric::pkg_bioc() builds pkg_bioc_remote with a
hard-coded

  repo = "https://bioconductor.org/packages/release/bioc"

discarding the Repository column returned by memoise_bioc_available().
Every downstream metric that follows x$repo_base_url --
pkg_ref_cache.web_url.pkg_bioc_remote() among others -- then scrapes
bioconductor.org via httr::GET and fails on air-gapped hosts with

  <pkg_metric_error in curl::curl_fetch_memory(...):
     Failed to connect to bioconductor.org port 443: Connection refused>

for has_news, remote_checks, news_current, has_vignettes,
has_maintainer, bugs_status, has_source_control, has_bug_reports_url,
license, and friends.

Extend configure_riskmetric_offline() with Shim 4: replace pkg_bioc()
with a version that pulls the Repository column from the shimmed
memoise_bioc_available() (the internal PPM BioC URL) so x$repo_base_url
points at the mirror and all derived scrapes hit the mirror too. Falls
back to bioc_repos_from_config()[[1]] when the package is unknown.
Mirrors the upstream fix at pharmaR/riskmetric#402.

Standalone snippet dev/riskmetric-bioc-available-shim.txt updated to
install Shim 4 as well.

(#81)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ix is_available_cran() ordering

Two related follow-ups to the memoise_bioc_available / pkg_bioc fix,
surfaced when field-testing on air-gapped Posit Package Manager mirrors.

## bioc_repositories() falls through to options('repos') / accepts override

The previous implementation only recognized BiocManager::repositories()
entries whose names start with 'BioC'. On a fresh session against an
internal PPM, BiocManager::repositories() often returns nothing usable
because the mirror URLs are supplied through options('repos') instead --
so bioc_repositories() returned character(0) and memoise_bioc_available()
still fell back to whatever was in the public BiocManager default,
defeating the whole point of the fix.

Widen the resolver, in order of specificity:
  1. options('riskmetric.bioc_repos') -- explicit override, named char
     or single URL.
  2. Sys.getenv('RISKMETRIC_BIOC_REPOS') -- comma-separated URLs.
  3. BiocManager::repositories() entries whose names begin 'BioC'
     (existing behaviour).
  4. options('repos') entries whose name begins 'BioC' *or* whose URL
     contains 'bioconductor' / '/bioc/' (case-insensitive).

Public-network users are unaffected: BiocManager::repositories() still
returns the five BioC* entries and step 3 short-circuits before step 4.

## is_available_cran() no longer wins on BioC-known packages

verify_pkg_source() checks is_available_cran() *before*
is_available_bioc(). When options('repos') advertises both a CRAN and a
BioC entry (standard PPM setup, and equally common on-network with
options(repos = BiocManager::repositories()) sessions),
available.packages() over the full repo list finds a BioC package like
BiocGenerics and returns TRUE from is_available_cran() first --
classification stops at pkg_cran_remote and never reaches
is_available_bioc(). Downstream BioC-specific cache methods
(pkg_ref_cache.examples, pkg_ref_cache.remote_checks.pkg_bioc_remote,
pkg_ref_cache.web_url.pkg_bioc_remote, ...) then either error with 'no
applicable method' or scrape the wrong HTML endpoint.

Teach is_available_cran() to short-circuit FALSE when the package is
also present in memoise_bioc_available(). Dispatch then falls through
to is_available_bioc() as intended, and the ref is built as
pkg_bioc_remote with the correct repo_base_url from the pkg_bioc()
fix already in this branch.

## Tests

Four new tests in tests/testthat/test_memoise_bioc_available.R cover:
  - the options('riskmetric.bioc_repos') override,
  - the RISKMETRIC_BIOC_REPOS env var override,
  - options('repos') URL-pattern fallthrough when BiocManager errors,
  - is_available_cran() vetoing a BioC-known package while
    memoise_available_packages() still contains it.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants