2016-11-28 2 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 обновит пип

я получаю сообщение об ошибке, как показано ниже:

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

Похоже, что он пытается обновить pip в глобальном env, а не внутри virtualenv, и выглядит как каждый шаг sh в своем собственном контексте, как заставить их выполнять wit в том же контексте?

+0

'активировать' применяется только к оболочке, в которой он запущен, в вашем случае это одна строка. Попробуйте запустить «pip» в venv с полным путем и 'manage.py' с (полным путем)' python'. –

ответ

5

То, что вы пытаетесь сделать, не будет работать. Каждый раз, когда вы вызываете команду sh, jenkins создаст новую оболочку.

Это означает, что если вы используете .env/bin/activate в sh, это будут только источники в этом сеансе оболочки. В результате в новой команде sh вам нужно снова запустить файл (если вы более подробно рассмотрите вывод консоли, вы увидите, что Дженкинс будет создавать временные файлы оболочки каждый раз, когда вы запустите запятую.

So вы должны либо источник файла .env/bin/activate в начале каждой команды оболочки (вы можете использовать тройные 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

К сожалению, это обходное решение делает техническое обслуживание трубопроводов кошмаром, нам явно нужно расширить DSL трубопровода, чтобы включить этот прецедент, и избежать этого. Это обходное решение работает для простых трубопроводов, но как только вы становитесь сложными, использование активизации становится кошмаром. Подумайте об исключениях и даже блоках, которые выполняются, если создание virtualenv не удалось. – sorin

+0

К сожалению, я должен согласиться с @sorin. Он продолжает улучшаться, но часто требуется перерыв или обходной путь. С другой стороны, мы могли бы дать всем возможность немного отдохнуть, потратив на это время. Относительно этой проблемы, tou всегда может просто поместить скрипт в ваше репо с логикой и просто называть это – Rik

1

Лик e Rik опубликовал, virtualenvs плохо работают в среде Jenkins Pipeline Environment, поскольку для каждой команды создается новая оболочка.

Я создал плагин, который делает этот процесс немного менее болезненным, который можно найти здесь: https://wiki.jenkins.io/display/JENKINS/Pyenv+Pipeline+Plugin. Он по сути просто обертывает каждый вызов таким образом, который активирует virtualenv до запуска команды. Это само по себе сложно, так как некоторые методы запуска нескольких команд inline разделены на две отдельные команды Jenkins, в результате чего активированный virtualenv больше не применяется.

0

Я новичок в файлах Jenkins. Вот как я работал над проблемой виртуальной среды. (Я бегу Python3, Jenkins 2.73.1)

Предостережение. Чтобы быть ясным, я не говорю, что это хороший способ решить проблему, и я не проверил это достаточно, чтобы стоять за этим подходом, но вот то, что работает для меня сегодня:

Я играю в обход «взвода» в Вене, напрямую позвонив интерпретатору python виртуальной среды. Таким образом, вместо:

source ~/venv/bin/activate  

можно использовать:

~/venv/bin/python3 my_script.py 

я прохожу путь к моему виртуальному интерпретатору среды питона с помощью файла гса командного интерпретатора Теоретически, каждый снаряд (В моем случае, ~/.bashrc.) Вызовы Дженкинса должны прочитать этот файл ресурсов. На практике я должен перезапустить Jenkins после внесения изменений в файл ресурсов оболочки.

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

My Jenkinsfile выглядит примерно так:

pipeline { 
    agent { 
     label 'my_slave' 
    } 

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

Итак, когда трубопровод запущен, ш имеет $ установить значение PYTHON_INTERPRETER среды.

Примечание: один недостаток этого подхода заключается в том, что теперь файл Jenkins не содержит всю необходимую информацию для правильного запуска скрипта. Надеюсь, это уберет вас от земли.