A Jenkins plugin that provides a way to execute `sh` and `bat` Pipeline
DSL commands within a specified Python virtualenv.

## Setup

1.  Install [Pyenv
    Pipeline](https://github.com/jenkinsci/pyenv-pipeline-plugin)
2.  (Optional)
    Install [ShiningPanda](https://wiki.jenkins.io/display/JENKINS/ShiningPanda+Plugin)

## Why did you make this?

The `sh` and `bat` steps in the Jenkinsfile Pipeline DSL reset
environmental information after every execution. For simple
environmental variable needs, one can simply utilize the `withEnv` step,
and execute the commands as needed within the block. The Python
virtualenv, however, requires a fairly complicated set of environmental
steps, and it is much easier and more reliable to fallback on the
behavior of the virtualenv project. However, for this to work, a `sh` or
`bat` command to be executed within the virtualenv must be prefiex with
a command that first activates the virtualenv; for every single command
to be ran within the virtualenv. This is verbose, repetitive and
error-prone.

## Usage

This plugin provides 1 new Pipeline DSL method:

-   `withPythonEnv`: Specifies a Python virtualenv to execute
    any `sh` and `bat` DSL commands contained within its block.

    `withPythonEnv` takes a single String argument, which specifies the
    Python executable to use for the virtualenv. pyenv-pipeline will use
    the executable to generate a corresponding virtualenv. At runtime,
    it will take a snapshot of environmental variables with and without
    the virtualenv active. From this it generates a diff, and applies
    the environmental variable changes within the `withPythonEnv` block
    (reverting them after the block completes)

    The argument provided to `withPythonEnv` will first attempt to match
    it against the name of a `ToolInstallation` that is described by
    a `ToolDescriptor` with an ID that is contained within a pre-defined
    list of known Jenkins Python Tool plugin IDs. Currently, this plugin
    only looks to see
    if [ShiningPanda](https://wiki.jenkins.io/display/JENKINS/ShiningPanda+Plugin) is
    installed. If a `ToolInstallation` is matched, the location of that
    tool is used as the Python executable to generate the virtualenv.

    **Example: ShiningPanda Installation**

    ``` syntaxhighlighter-pre
    withPythonEnv('CPython-2.7'){
        // Uses the ShiningPanda registered Python installation named 'CPython-2.7'
        ...
    }
    ```

    If no `ToolInstallation` is matched, then the argument is treated as
    the literal location of the Python executable to be used. This can
    be used to specify a specific Python installation (if the location
    is known beforehand), or to fallback and use the systems default
    Python installation.

    **Example: Default Python Installation**

    ``` syntaxhighlighter-pre
    withPythonEnv('python') {
        // Uses the default system installation of Python
        // Equivalent to withPythonEnv('/usr/bin/python') 
        ...
    }
    ```

    **Example: Specific Python executable**

    ``` syntaxhighlighter-pre
    withPythonEnv('/usr/bin/python3.5') {
        // Uses the specific python3.5 executable located in /usr/bin
        ...
    }
    ```

    When `withPythonEnv` is called with an argument for the first time,
    it creates the virtualenv needed. Whenever `withPythonEnv` is called
    with the same argument, the previously created virtualenv is used
    again.

    **Example: Differentiating between virtualenvs**

    ``` syntaxhighlighter-pre
    withPythonEnv('some-python-installation') {
        // Creates the virtualenv before proceeding
        sh 'pip install nose'
    }
    withPythonEnv('some-other-python-installation') {
        // Creates a new virtualenv here. The following line will fail, since nose has not been installed in this env
        sh 'nosetests'
    }
    withPythonEnv('some-python-installation') {
        // Using the same virtualenv we created with the first block. The following line here will work
        sh 'nosetests'
    }
    ```