From e7327ef75b5a2b1a95dc551e02ff9b28a9fe4ed5 Mon Sep 17 00:00:00 2001 From: Jonathan Keane Date: Thu, 23 Oct 2025 22:44:01 -0400 Subject: [PATCH 1/9] a failing unit test --- tests/testthat/test-restore.R | 75 +++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/tests/testthat/test-restore.R b/tests/testthat/test-restore.R index d8c49dd3..c17cbb74 100644 --- a/tests/testthat/test-restore.R +++ b/tests/testthat/test-restore.R @@ -150,3 +150,78 @@ test_that("appendRemoteInfoToDescription uses RemoteSubdir", { desc <- readLines(file.path(dest_dir, "toast", "DESCRIPTION")) expect_true("RemoteSubdir: toast" %in% desc) }) + +test_that("isFromCranlikeRepo returns TRUE for CRAN source", { + pkgRecord <- list( + name = "ggplot2", + source = "CRAN", + version = "3.4.0" + ) + + repos <- c(CRAN = "https://cran.r-project.org") + + expect_true(isFromCranlikeRepo(pkgRecord, repos)) +}) + +test_that("isFromCranlikeRepo returns TRUE for CustomCRANLikeRepository class", { + pkgRecord <- structure( + list( + name = "ggplot2", + source = "CRAN", + version = "3.4.0" + ), + class = c("packageRecord", "CustomCRANLikeRepository") + ) + + repos <- c(CRAN = "https://cran.r-project.org") + + expect_true(isFromCranlikeRepo(pkgRecord, repos)) +}) + +test_that("isFromCranlikeRepo returns FALSE for source package", { + pkgRecord <- list( + name = "mypackage", + source = "source", + version = "1.0.0" + ) + + repos <- c(CRAN = "https://cran.r-project.org") + + expect_false(isFromCranlikeRepo(pkgRecord, repos)) +}) + +test_that("isFromCranlikeRepo returns TRUE for BioConductor source", { + pkgRecord <- list( + name = "GenomicRanges", + source = "Bioconductor", + version = "1.50.0" + ) + + repos <- c(BioCsoft = "https://bioconductor.org/packages/3.16/bioc") + + expect_true(isFromCranlikeRepo(pkgRecord, repos)) +}) + +test_that("isFromCranlikeRepo returns TRUE for custom repository source", { + pkgRecord <- list( + name = "mypackage", + source = "MyRepo", + version = "1.0.0" + ) + + repos <- c(MyRepo = "https://example.com/repo") + + expect_true(isFromCranlikeRepo(pkgRecord, repos)) +}) + +test_that("isFromCranlikeRepo returns TRUE for a CRAN-like source named Github", { + pkgRecord <- list( + name = "mypackage", + source = "GitHub", + version = "1.0.0" + ) + + repos <- c(GitHub = "https://example.com/repo") + + expect_true(isFromCranlikeRepo(pkgRecord, repos)) +}) \ No newline at end of file From bb90eefe33cf150409ec5ad4a46eefe153d0eafa Mon Sep 17 00:00:00 2001 From: Jonathan Keane Date: Thu, 23 Oct 2025 22:48:38 -0400 Subject: [PATCH 2/9] Use repo URL, not repo name to detect git-like repos. --- R/bitbucket.R | 2 +- R/github.R | 2 +- R/gitlab.R | 2 +- R/restore.R | 12 ++++++++++-- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/R/bitbucket.R b/R/bitbucket.R index 41a505b9..94c01e5b 100644 --- a/R/bitbucket.R +++ b/R/bitbucket.R @@ -96,7 +96,7 @@ bitbucketArchiveUrl <- function(pkgRecord) { isBitbucketURL <- function(url) { is.string(url) && - grepl("^http(?:s)?://(?:www|api).bitbucket.(org|com)", url, perl = TRUE) + grepl("^(http(?:s)?://)?(www|api)?.?bitbucket.(org|com)", url, perl = TRUE) } bitbucketAuthenticated <- function() { diff --git a/R/github.R b/R/github.R index 1f926de3..10117453 100644 --- a/R/github.R +++ b/R/github.R @@ -103,7 +103,7 @@ githubArchiveUrl <- function(pkgRecord) { isGitHubURL <- function(url) { is.string(url) && - grepl("^http(?:s)?://(?:www|api).github.com", url, perl = TRUE) + grepl("^(http(?:s)?://)?(www|api)?.?github.com", url, perl = TRUE) } githubAuthenticated <- function() { diff --git a/R/gitlab.R b/R/gitlab.R index f0be29a2..5b61d7d7 100644 --- a/R/gitlab.R +++ b/R/gitlab.R @@ -96,7 +96,7 @@ gitlabArchiveUrl <- function(pkgRecord) { isGitlabURL <- function(url) { is.string(url) && - grepl("^http(?:s)?://(?:www|api).gitlab.(org|com)", url, perl = TRUE) + grepl("^(http(?:s)?://)?(www|api)?.?gitlab.(org|com)", url, perl = TRUE) } gitlabAuthenticated <- function() { diff --git a/R/restore.R b/R/restore.R index e4b27ab1..20b68f35 100644 --- a/R/restore.R +++ b/R/restore.R @@ -25,12 +25,20 @@ isFromCranlikeRepo <- function(pkgRecord, repos) { return(TRUE) } - # for records that do declare a source, ensure it's not 'source', 'github', 'bitbucket', or 'gitlab'. + # check if there's a remote host for github, bitbucket, or gitlab + git_remote <- isBitbucketURL(pkgRecord$remote_host) || + isGitHubURL(pkgRecord$remote_host) || + isGitlabURL(pkgRecord$remote_host) + if (git_remote) { + return(FALSE) + } + + # for records that do declare a source, ensure it's not 'source'. # in previous releases of packrat, we attempted to match the repository name # with one of the existing repositories; however, this caused issues in # certain environments (the names declared repositories in the lockfile, and # the the names of the active repositories in the R session, may not match) - !tolower(source) %in% c("source", "github", "bitbucket", "gitlab") + !tolower(source) %in% c("source") } # Given a package record and a database of packages, check to see if From 7b90f4468b0f6ebccfa6e06bf55a7e9afca40b80 Mon Sep 17 00:00:00 2001 From: Jonathan Keane Date: Thu, 23 Oct 2025 22:54:34 -0400 Subject: [PATCH 3/9] Update R/restore.R Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- R/restore.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/restore.R b/R/restore.R index 20b68f35..fd65b564 100644 --- a/R/restore.R +++ b/R/restore.R @@ -27,8 +27,8 @@ isFromCranlikeRepo <- function(pkgRecord, repos) { # check if there's a remote host for github, bitbucket, or gitlab git_remote <- isBitbucketURL(pkgRecord$remote_host) || - isGitHubURL(pkgRecord$remote_host) || - isGitlabURL(pkgRecord$remote_host) + isGitHubURL(pkgRecord$remote_host) || + isGitlabURL(pkgRecord$remote_host) if (git_remote) { return(FALSE) } From ff9638172297b4bca3aaf8fd38bb76348f8d2bbf Mon Sep 17 00:00:00 2001 From: Jonathan Keane Date: Thu, 23 Oct 2025 22:54:41 -0400 Subject: [PATCH 4/9] Update R/restore.R Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- R/restore.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/restore.R b/R/restore.R index fd65b564..d92b1cf2 100644 --- a/R/restore.R +++ b/R/restore.R @@ -30,7 +30,7 @@ isFromCranlikeRepo <- function(pkgRecord, repos) { isGitHubURL(pkgRecord$remote_host) || isGitlabURL(pkgRecord$remote_host) if (git_remote) { - return(FALSE) + return(FALSE) } # for records that do declare a source, ensure it's not 'source'. From 0f60f7ee57caa7dee76f0e7319fd1f86b2010f62 Mon Sep 17 00:00:00 2001 From: Jonathan Keane Date: Thu, 23 Oct 2025 22:54:47 -0400 Subject: [PATCH 5/9] Update tests/testthat/test-restore.R Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- tests/testthat/test-restore.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testthat/test-restore.R b/tests/testthat/test-restore.R index c17cbb74..2d57cfd8 100644 --- a/tests/testthat/test-restore.R +++ b/tests/testthat/test-restore.R @@ -224,4 +224,4 @@ test_that("isFromCranlikeRepo returns TRUE for a CRAN-like source named Github", repos <- c(GitHub = "https://example.com/repo") expect_true(isFromCranlikeRepo(pkgRecord, repos)) -}) \ No newline at end of file +}) From d8984c0dab5adba8d39173238d9b3062cc3e1180 Mon Sep 17 00:00:00 2001 From: Jonathan Keane Date: Fri, 24 Oct 2025 17:41:01 -0400 Subject: [PATCH 6/9] Slightly nicer URL sniffers --- R/bitbucket.R | 2 +- R/github.R | 2 +- R/gitlab.R | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/R/bitbucket.R b/R/bitbucket.R index 94c01e5b..828b47c7 100644 --- a/R/bitbucket.R +++ b/R/bitbucket.R @@ -96,7 +96,7 @@ bitbucketArchiveUrl <- function(pkgRecord) { isBitbucketURL <- function(url) { is.string(url) && - grepl("^(http(?:s)?://)?(www|api)?.?bitbucket.(org|com)", url, perl = TRUE) + grepl("^(http(?:s)?://)?((www|api)\\.)?bitbucket.(org|com)", url, perl = TRUE) } bitbucketAuthenticated <- function() { diff --git a/R/github.R b/R/github.R index 10117453..873943a2 100644 --- a/R/github.R +++ b/R/github.R @@ -103,7 +103,7 @@ githubArchiveUrl <- function(pkgRecord) { isGitHubURL <- function(url) { is.string(url) && - grepl("^(http(?:s)?://)?(www|api)?.?github.com", url, perl = TRUE) + grepl("^(http(?:s)?://)?((www|api)\\.)?github.com", url, perl = TRUE) } githubAuthenticated <- function() { diff --git a/R/gitlab.R b/R/gitlab.R index 5b61d7d7..0176fc09 100644 --- a/R/gitlab.R +++ b/R/gitlab.R @@ -96,7 +96,7 @@ gitlabArchiveUrl <- function(pkgRecord) { isGitlabURL <- function(url) { is.string(url) && - grepl("^(http(?:s)?://)?(www|api)?.?gitlab.(org|com)", url, perl = TRUE) + grepl("^(http(?:s)?://)?((www|api)\\.)?gitlab.(org|com)", url, perl = TRUE) } gitlabAuthenticated <- function() { From ca801cd1fdb1789d3271344177e7eff240e816af Mon Sep 17 00:00:00 2001 From: Jonathan Keane Date: Tue, 28 Oct 2025 07:25:49 -0500 Subject: [PATCH 7/9] Use the presence of remote host and repo for determining that a repo is git-like --- R/bitbucket.R | 2 +- R/github.R | 2 +- R/gitlab.R | 2 +- R/restore.R | 7 ++----- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/R/bitbucket.R b/R/bitbucket.R index 828b47c7..41a505b9 100644 --- a/R/bitbucket.R +++ b/R/bitbucket.R @@ -96,7 +96,7 @@ bitbucketArchiveUrl <- function(pkgRecord) { isBitbucketURL <- function(url) { is.string(url) && - grepl("^(http(?:s)?://)?((www|api)\\.)?bitbucket.(org|com)", url, perl = TRUE) + grepl("^http(?:s)?://(?:www|api).bitbucket.(org|com)", url, perl = TRUE) } bitbucketAuthenticated <- function() { diff --git a/R/github.R b/R/github.R index 873943a2..1f926de3 100644 --- a/R/github.R +++ b/R/github.R @@ -103,7 +103,7 @@ githubArchiveUrl <- function(pkgRecord) { isGitHubURL <- function(url) { is.string(url) && - grepl("^(http(?:s)?://)?((www|api)\\.)?github.com", url, perl = TRUE) + grepl("^http(?:s)?://(?:www|api).github.com", url, perl = TRUE) } githubAuthenticated <- function() { diff --git a/R/gitlab.R b/R/gitlab.R index 0176fc09..f0be29a2 100644 --- a/R/gitlab.R +++ b/R/gitlab.R @@ -96,7 +96,7 @@ gitlabArchiveUrl <- function(pkgRecord) { isGitlabURL <- function(url) { is.string(url) && - grepl("^(http(?:s)?://)?((www|api)\\.)?gitlab.(org|com)", url, perl = TRUE) + grepl("^http(?:s)?://(?:www|api).gitlab.(org|com)", url, perl = TRUE) } gitlabAuthenticated <- function() { diff --git a/R/restore.R b/R/restore.R index d92b1cf2..5be4caab 100644 --- a/R/restore.R +++ b/R/restore.R @@ -25,11 +25,8 @@ isFromCranlikeRepo <- function(pkgRecord, repos) { return(TRUE) } - # check if there's a remote host for github, bitbucket, or gitlab - git_remote <- isBitbucketURL(pkgRecord$remote_host) || - isGitHubURL(pkgRecord$remote_host) || - isGitlabURL(pkgRecord$remote_host) - if (git_remote) { + # check if there's a remote host and repo for github, bitbucket, or gitlab + if (!is.null(pkgRecord$remote_host) && !is.null(pkgRecord$remote_repo)) { return(FALSE) } From 5066b391e6516e035aef46919649b77b9c133b2e Mon Sep 17 00:00:00 2001 From: Jonathan Keane Date: Tue, 28 Oct 2025 14:21:58 -0500 Subject: [PATCH 8/9] Update tests/testthat/test-restore.R Co-authored-by: Kara Woo --- tests/testthat/test-restore.R | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/testthat/test-restore.R b/tests/testthat/test-restore.R index 2d57cfd8..656c8ebb 100644 --- a/tests/testthat/test-restore.R +++ b/tests/testthat/test-restore.R @@ -190,6 +190,20 @@ test_that("isFromCranlikeRepo returns FALSE for source package", { expect_false(isFromCranlikeRepo(pkgRecord, repos)) }) +test_that("isFromCranlikeRepo returns FALSE if remote_repo/remote_host are present", { + pkgRecord <- list( + name = "mypackage", + source = "GitHub", + version = "1.0.0", + remote_host = "github.com", + remote_repo = "mypackage" + ) + + repos <- c(GitHub = "https://github.com/me/mypackage") + + expect_false(isFromCranlikeRepo(pkgRecord, repos)) +}) + test_that("isFromCranlikeRepo returns TRUE for BioConductor source", { pkgRecord <- list( name = "GenomicRanges", From ce187321d7de326ae458d0a244e8e156e8a11f16 Mon Sep 17 00:00:00 2001 From: Jonathan Keane Date: Tue, 28 Oct 2025 14:30:51 -0500 Subject: [PATCH 9/9] add news --- NEWS.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/NEWS.md b/NEWS.md index b05ca039..8536d9ef 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,6 +3,10 @@ - When restoring GitHub-hosted packages, packrat will now look for both `Github*` and `Remote*` fields to determine where to install from. (#740) +- When restoring packages from CRAN-like repositories, names are no + longer used to detect if these are actually git-like. This prevents + issues if you name a CRAN-like repository something like "GitHub". (#747) + # packrat 0.9.3 - Update vendored `renv` with support for additional Linux distributions when