我目前正在为我们公司开发的R软件包进行持续集成设置。每个R包都有一个Jenkins项目,每个项目都有一个对应的库。
我已经定义了将包的所有依赖项安装到项目库中的逻辑。现在我想定义一个基本上运行的检查阶段
devtools::check("${PROJECT_DIR}/pkg")
但仅将项目库用于依赖项。我尝试通过以下方式使用callr
包。
callr::r(
function(...) {
devtools::check(...)
),
args = list("${PROJECT_DIR}/pkg"),
libpath = "${PROJECT_DIR}/lib"
)
但是,检查过程仍然可以找到libpath
中未安装的软件包。有没有办法确保在构建阶段仅使用"${PROJECT_DIR}/lib"
?
到目前为止,我已经尝试了以下方法
callr()
和libpath
参数withr::with_libpaths
和new
参数devtools::check
和R CMD BUILD
中的文档以了解
合适的参数.libPaths("${JOB_DIR}/lib")
这是一个说明callr
意外行为的repex。我预计第3行会出现错误。
find.package("ggplot2", .libPaths()[1])
#> Error in find.package("ggplot2", .libPaths()[1]): there is no package called 'ggplot2'
callr::r(function() { ggplot2::vars() }, libpath = .libPaths()[1])
#> named list()
find.package("ggplot2", .libPaths()[2])
#> [1] "/data/R/3.5.3/lib/R/library/ggplot2"
callr::r(function() { ggplot2::vars() }, libpath = .libPaths()[2])
#> named list()
答案 0 :(得分:1)
根据this question编码,可以使用base::assign
对此进行归档。如果有更合适的解决方案,我很想听听。
callr::r(function() {
assign(".lib.loc", .libPaths()[1], envir = environment(.libPaths))
ggplot2::vars()
})
#> Error in loadNamespace(name): there is no package called ‘ggplot2’
我在这里遇到的问题是双重的
.libPaths()
的内部结构发生变化,它可以随时中断.Library
和.Library.site
(.libPaths()
的内部),以确保devtools::check
受到适当的影响。答案 1 :(得分:1)
这可能与主题无关,但是您是否考虑过在本用例中使用docker?
您可以定义Dockerfile
中引用的Jenkinsfile
,这将为运行的每个CI作业定义一个自定义图像。您可以使用Jenkins中的devtools::install()
将软件包安装到docker容器上。 CI完成后,此容器将被扔掉。
使用这种方法,您不必担心在运行CI时自己手动安装软件包,也不必担心不同软件包之间的命名空间冲突。
这肯定会有更高的启动成本,但是我认为从长远来看,测试R软件包是值得的。资料来源:我也在工作中测试了内部R包。
样本Dockerfile
FROM docker.io/rocker/r-base
USER root
# Install packages needed for package development
RUN R -e 'install.packages(c("devtools", "rmarkdown", "testthat", "roxygen2"))'
然后您在Dockerfile
中引用此Jenkinsfile
,以便安装,测试和检查软件包(下面的管道示例)
agent {
dockerfile {
args '-u root'
}
}
stages {
stage('Install') {
steps {
sh 'r -e "devtools::install()"'
}
}
stage('Test') {
steps {
sh '''
r -e "options(testthat.output_file = 'test-out.xml'); devtools::test(reporter = 'junit')"
'''
junit 'test-out.xml'
}
}
stage('Check') {
// Might need to modify expected ouput, depends on devtools version
steps {
sh '''
testOutput=$(R -e "devtools::check(args='--no-tests')" 2>&1)
echo "${testOutput}" | grep -q "0 errors ✔ | 0 warnings ✔ | 0 notes ✔"
'''
}
}
}
}