2016-11-28 106 views
11

我想设置一个项目,使用闪亮的新Jenkins管道,更具体地说是一个多分支项目。Jenkinsfile和Python virtualenv

我有一个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' 
} 

值得一提的是,preinstall.txt将更新PIP

我得到如下错误:

OSError: [Errno 13] Permission denied: '/usr/local/lib/python2.7/dist-packages/pip' 

看起来它试图更新全局env而不是virtualenv中的pip,并且看起来像每个sh步骤都在它自己的上下文中,我如何让它们执行wit欣赏相同的情境?

+0

'activate'只适用于运行它的shell例程,在你的情况下是单行。尝试在完整路径下使用venv运行'pip',使用(完整路径)'python'运行'manage.py'。 –

回答

5

你正在尝试做什么将无法正常工作。每当你打电话给sh命令时,jenkins都会创建一个新shell。

这意味着如果您在sh中使用.env/bin/activate,它将只在该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 
    """ 
} 

或运行在同一个外壳

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 
""" 
+4

令人遗憾的是,这种解决方法使得管道维护成为一场噩梦,我们显然需要扩展Pipeline DSL来启用此用例,并避免以此结束。此解决方法适用于简单的管道,但一旦使用激活成长为复杂的变成恶梦。考虑在virtualenv创建失败时运行的异常甚至块。 – sorin

+0

不幸的是我必须同意@sorin。它越来越好,但通常需要休息或解决方法。另一方面,凌晨可能会给每个人留下一点时间花在他们身上的时间。关于这个问题,tou总是可以用逻辑在你的repo中放一个脚本,然后调用它 – Rik

1

沥e Rik表示,virtualenvs在Jenkins管道环境中不能很好地工作,因为每个命令都会创建一个新的shell。

我创建了一个插件,使这个过程有点痛苦,可以在这里找到:https://wiki.jenkins.io/display/JENKINS/Pyenv+Pipeline+Plugin。它基本上只是以一种在运行命令之前激活virtualenv的方式来封装每个调用。这本身就很棘手,因为一些内联运行多个命令的方法被Jenkins分成两个单独的命令,导致激活的virtualenv不再适用。

0

我是新来的詹金斯文件。以下是我一直在解决虚拟环境问题的方法。 (我正在运行Python3,Jenkins 2.73.1)

警告:要说清楚,我并不是说这是解决问题的好方法,也不是我测试过这个方法足以支持这种方法,但在这里什么是我今天的工作:

我一直在绕过venv'activate'直接调用虚拟环境的python解释器。因此,而不是:

source ~/venv/bin/activate  

可以使用:

~/venv/bin/python3 my_script.py 

我通过外壳的RC文件传递的路径,我的虚拟环境的Python解释器从理论上讲,每个壳(在我的情况,~/.bashrc。) Jenkins调用应该读取这个资源文件。在实践中,我必须在更改shell资源文件后重新启动Jenkins。

HOME_DIR=~ 
export VENV_PATH="$HOME_DIR/venvs/my_venv" 
export PYTHON_INTERPRETER="${VENV_PATH}/bin/python3" 

我Jenkinsfile类似于此:

pipeline { 
    agent { 
     label 'my_slave' 
    } 

    stages { 
     stage('Stage1') { 
      steps { 
       // sh 'echo $PYTHON_INTERPRETER' 
       // sh 'env | sort' 
       sh "$PYTHON_INTERPRETER my_script.py " 
      } 
     } 
    } 
} 

所以在运行时管道的SH有$ PYTHON_INTERPRETER环境值设定。

注意这种方法的一个缺点是,现在Jenkins文件没有包含正确运行脚本的所有必要信息。希望这会让你离开地面。