Jenkinsfile和Python virtualenv

Jam*_*Lin 23 python jenkins

我正在尝试设置一个使用闪亮的新Jenkins管道的项目,更具体地说是一个多分支项目.

我在测试分支中创建了一个Jenkinsfile,如下所示:

node {
    stage 'Preparing VirtualEnv'
    if (!fileExists('.env')){
        echo 'Creating virtualenv ...'
        sh 'virtualenv --no-site-packages .env'
    }
    sh '. .env/bin/activate'
    sh 'ls -all'
    if (fileExists('requirements/preinstall.txt')){
        sh 'pip install -r requirements/preinstall.txt'
    }
    sh 'pip install -r requirements/test.txt'
    stage 'Unittests'
    sh './manage.py test --noinput'
}
Run Code Online (Sandbox Code Playgroud)

值得注意的是,preinstall.txt将更新pip

我收到如下错误:

OSError: [Errno 13] Permission denied: '/usr/local/lib/python2.7/dist-packages/pip'
Run Code Online (Sandbox Code Playgroud)

看起来它试图更新全局env中的pip而不是virtualenv内部,看起来每个sh步骤都在它自己的上下文中,我如何让它们在同一个上下文中执行?

Rik*_*Rik 17

你想做什么是行不通的.每次调用sh命令时,jenkins都会创建一个新shell.

这意味着如果您.env/bin/activate在其中使用sh它将只是该shell会话中的源.结果是在新sh命令中你必须再次获取文件(如果仔细查看控制台输出,你会看到Jenkins实际上每次运行comman时都会创建临时shell文件.

所以你应该.env/bin/activate在每个shell命令的开头找到文件(你可以使用三重qoutes来表示多行字符串),就像这样

if (fileExists('requirements/preinstall.txt')) {
    sh """
    . .env/bin/activate
    pip install -r requirements/preinstall.txt
    """
}
...
sh """
. .env/bin/activate
pip install -r requirements/test.txt
"""
}
stage("Unittests") {
    sh """
    . .env/bin/activate
    ./manage.py test --noinput
    """
}
Run Code Online (Sandbox Code Playgroud)

或者在一个shell中运行它

sh """
. .env/bin/activate
if [[ -f requirements/preinstall.txt ]]; then
    pip install -r requirements/preinstall.txt
fi
pip install -r requirements/test.txt
./manage.py test --noinput
"""
Run Code Online (Sandbox Code Playgroud)

  • 遗憾的是,这种解决方法使管道维护成为一场噩梦,我们显然需要扩展Pipeline DSL以启用此用例并避免以此为目的.这种解决方法适用于简单的管道,但是一旦你使用激活成为复杂的管道就变成了一场噩梦.想想如果virtualenv创建失败则会运行的异常甚至块. (7认同)

小智 6

就像Rik所说的那样,由于在每个命令中都会创建一个新的shell,因此virtualenvs在Jenkins Pipeline Environment中不能很好地工作。

我创建了一个插件,该插件可以使此过程更轻松一些,可以在以下位置找到:https : //wiki.jenkins.io/display/JENKINS/Pyenv+Pipeline+Plugin。本质上,它只是以在运行命令之前激活virtualenv的方式包装每个调用。这本身就很棘手,因为Jenkins将一些内联运行多个命令的方法分成两个单独的命令,导致激活的virtualenv不再适用。