这个问题涉及在 Jenkins 管道中使用 Python + Poetry 项目以及如何保留.venv/
设想:
我有一个 Jenkins Pipeline 作业,它触发了一个 Python 项目。该项目使用 poetry 在工作区内以 .venv 创建虚拟环境。每次后续作业运行,它都会按预期重新使用 .venv,因此每个 pip 包不需要在每次运行时重新下载(除非 poetry.lock 文件中存在差异)。一切都按预期进行。
我想使用 Jenkins 工作区清理插件对流水线进行更改,我想删除工作区文件但保留一些文件,包括 pip/poetry/venv 环境文件。这是为了允许它重新使用仍存储在 .venv 中的上次运行的 pip 包——就像它在今天工作的管道上所做的那样。
完整的管道文件示例位于本文的底部,但这里是我添加到现有管道的 cleanWs() 部分的片段:
post {
always {
cleanWs(
deleteDirs: true,
notFailBuild: true,
patterns: [
[pattern: '.venv', type: 'EXCLUDE'],
[pattern: '.venv/**', type: 'EXCLUDE']
]
)
}
}
问题如下:
作业首次运行时,运行良好,工作区清理工作如预期进行。目录
.venv/
按预期保留。(问题)在后续的作业运行中,诗歌将重新安装所有软件包,并且不会重新使用 .venv 目录:
Creating virtualenv test in /data/jenkins_home/workspace/test-cleanup/.venv
-- 这会强制重新下载所有软件包,即使它们.venv
已经存在。已确认/data/jenkins_home/workspace/test-cleanup/.venv
在作业运行前它们已经存在。奇怪的是:如果我在 Jenkins 服务器上手动进入工作区目录并运行完全相同的命令
poetry install
它按预期工作,.venv
被重用,并且所有包都未重新安装。因此,它在作业中处理运行的方式存在一些特殊之处,这使得它想要重新创建 .venv 目录。
注意,这in-project = true
已为 Poetry 设置。因此它将始终尝试在当前工作目录中使用 .venv。
例子:
这是一个按预期工作的简单示例管道。当poetry install
step 运行时,它不会在作业每次运行时重新下载所有包,只有在第一次或存在差异时才会重新下载:
pipeline {
agent any
stages {
stage("Prep Build Environment") {
steps {
script {
scmVars = git branch: "main", poll: false, url: "[email protected]:my-org/private-repo.git"
}
sh "poetry install"
}
}
}
}
这里是新的添加了Jenkinsfile 管道文件cleanWs()
。添加后,项目将不再在每次运行时重复使用 .venv,即使它仍然存在:
pipeline {
agent any
stages {
stage("Prep Build Environment") {
steps {
script {
scmVars = git branch: "main", poll: false, url: "[email protected]:my-org/private-repo.git"
}
sh "poetry install"
}
}
}
post {
always {
cleanWs(
deleteDirs: true,
notFailBuild: true,
patterns: [
[pattern: '.venv', type: 'EXCLUDE'],
[pattern: '.venv/**', type: 'EXCLUDE']
]
)
}
}
}
答案1
通常,Jenkins Pipeline 会在构建开始时清理工作区,这就是为什么 .venv 文件夹在构建运行后存在但在下一次构建期间运行 virtualenv 步骤时不存在的原因。
如果您想在构建之间缓存或保留某些文件,最可靠的方法是将这些文件存储在工作区之外。但是,您需要非常小心,因为同时运行访问相同文件的构建可能会导致资源争用和竞争条件以及文件损坏。
答案2
快速回答:
添加[pattern: '.git/**', type: 'EXCLUDE']
到您的模式列表cleanWs()
。
工作区文件(包括).venv/
将在作业运行之间保留。
长答案:
因此问题似乎是当.git/
目录丢失时(当需要进行完整克隆时),git 插件会破坏工作区。据我所知,我没有看到任何关于此行为的记录。
由于该cleanWs()
操作删除了.git
,它将触发 git 插件的这一“功能”。
将目录添加.git/
到排除列表似乎解决了原始问题,并允许其他文件在构建之间保留。
这种行为可以通过以下方式证明:
将文件写入工作区并检出 repo 的管道步骤。
steps { sh "ls -l" sh "touch foo.txt" git branch: "master", poll: false, url: "[email protected]:golang/example.git" }
作业运行一次后,
foo.txt
将会持续下去在工作区中:.git
克隆后删除数据:steps { sh "ls -l" sh "touch foo.txt" git branch: "master", poll: false, url: "[email protected]:golang/example.git" sh "rm -rf .git" }
作业运行一次后,
foo.txt
将会消失在每次作业运行开始时:
最后的帖子/总是阻止片段。诗歌安装并且虚拟环境现在按预期工作:
post {
always {
cleanWs(
deleteDirs: true,
notFailBuild: true,
patterns: [
[pattern: '.git/**', type: 'EXCLUDE'],
[pattern: '.venv/**', type: 'EXCLUDE']
]
)
}
}