Repository: pycontribs/jenkinsapi

Issue:
support getting environment variables
##### ISSUE TYPE
- Feature Idea
##### Jenkinsapi VERSION
##### Jenkins VERSION

2.9
##### SUMMARY

The REST API to get env variables from the build is present.
I think it would be great if jenkinsapi supported getting these variables.
https://wiki.jenkins-ci.org/display/JENKINS/EnvInject+Plugin


Discussion:
lechat: Why not adding systest? It is much easier to work with Jenkins compared to working with mocks. Plus this approach guarantees that the change works, while unit test guaranteed that unittest works and nothing more.
ripcurld0: @lechat thanks for that. I will add tests to the systest. 🥇 

Patch:
diff --git a/jenkinsapi/build.py b/jenkinsapi/build.py
index 9a85060..d1f1696 100644
--- a/jenkinsapi/build.py
+++ b/jenkinsapi/build.py
@@ -24,6 +24,7 @@ from jenkinsapi.custom_exceptions import NoResults
 from jenkinsapi.custom_exceptions import JenkinsAPIException
 
 from six.moves.urllib.parse import quote
+from requests import HTTPError
 
 
 log = logging.getLogger(__name__)
@@ -480,3 +481,19 @@ class Build(JenkinsBase):
                 url, data='', valid=[302, 200, 500, ])
             return True
         return False
+
+    def get_env_vars(self):
+        """
+        Return the environment variables.
+
+        This method is using the Environment Injector plugin:
+        https://wiki.jenkins-ci.org/display/JENKINS/EnvInject+Plugin
+        """
+        url = self.python_api_url('%s/injectedEnvVars' % self.baseurl)
+        try:
+            data = self.get_data(url, params={'depth': self.depth})
+        except HTTPError as ex:
+            warnings.warn('Make sure the Environment Injector plugin '
+                          'is installed.')
+            raise ex
+        return data['envMap']


Test patch:
diff --git a/jenkinsapi_tests/systests/conftest.py b/jenkinsapi_tests/systests/conftest.py
index 89fefe6..3f3c461 100644
--- a/jenkinsapi_tests/systests/conftest.py
+++ b/jenkinsapi_tests/systests/conftest.py
@@ -25,7 +25,8 @@ PLUGIN_DEPENDENCIES = [
     "https://updates.jenkins-ci.org/latest/nested-view.hpi",
     "https://updates.jenkins-ci.org/latest/ssh-slaves.hpi",
     "https://updates.jenkins-ci.org/latest/structs.hpi",
-    "http://updates.jenkins-ci.org/latest/plain-credentials.hpi"
+    "http://updates.jenkins-ci.org/latest/plain-credentials.hpi",
+    "http://updates.jenkins-ci.org/latest/envinject.hpi"
 ]
 
 
diff --git a/jenkinsapi_tests/systests/job_configs.py b/jenkinsapi_tests/systests/job_configs.py
index ce6341e..c5c3387 100644
--- a/jenkinsapi_tests/systests/job_configs.py
+++ b/jenkinsapi_tests/systests/job_configs.py
@@ -311,3 +311,31 @@ JOB_WITH_FILE_AND_PARAMS = """
   </publishers>
   <buildWrappers/>
 </project>""".strip()
+
+JOB_WITH_ENV_VARS = '''\
+<?xml version="1.0" encoding="UTF-8"?><project>
+  <actions/>
+  <description/>
+  <keepDependencies>false</keepDependencies>
+  <properties/>
+  <scm class="hudson.scm.NullSCM"/>
+  <canRoam>true</canRoam>
+  <disabled>false</disabled>
+  <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
+  <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
+  <triggers class="vector"/>
+  <concurrentBuild>false</concurrentBuild>
+  <builders/>
+  <publishers/>
+  <buildWrappers>
+    <EnvInjectBuildWrapper plugin="envinject@1.93.1">
+      <info>
+        <groovyScriptContent>
+          return [\'key1\': \'value1\', \'key2\': \'value2\']
+        </groovyScriptContent>
+        <loadFilesFromMaster>false</loadFilesFromMaster>
+      </info>
+    </EnvInjectBuildWrapper>
+  </buildWrappers>
+</project>
+'''.strip()
diff --git a/jenkinsapi_tests/systests/test_env_vars.py b/jenkinsapi_tests/systests/test_env_vars.py
new file mode 100644
index 0000000..05dd831
--- /dev/null
+++ b/jenkinsapi_tests/systests/test_env_vars.py
@@ -0,0 +1,17 @@
+"""
+System tests for `jenkinsapi.jenkins` module.
+"""
+from jenkinsapi_tests.systests.job_configs import JOB_WITH_ENV_VARS
+from jenkinsapi_tests.test_utils.random_strings import random_string
+
+
+def test_get_env_vars(jenkins):
+    job_name = 'get_env_vars_create1_%s' % random_string()
+    job = jenkins.create_job(job_name, JOB_WITH_ENV_VARS)
+    job.invoke(block=True)
+    build = job.get_last_build()
+    while build.is_running():
+        time.sleep(0.25)
+    data = build.get_env_vars()
+    assert data['key1'] == 'value1'
+    assert data['key2'] == 'value2'
diff --git a/jenkinsapi_tests/unittests/configs.py b/jenkinsapi_tests/unittests/configs.py
index cdcfd14..981a858 100644
--- a/jenkinsapi_tests/unittests/configs.py
+++ b/jenkinsapi_tests/unittests/configs.py
@@ -205,3 +205,8 @@ BUILD_SCM_DATA = {
     'timestamp': 1372553675652,
     'url': 'http://localhost:8080/job/git_yssrtigfds/3/'
 }
+
+BUILD_ENV_VARS = {
+    '_class': 'org.jenkinsci.plugins.envinject.EnvInjectVarList',
+    'envMap': {'KEY': 'VALUE'}
+}
diff --git a/jenkinsapi_tests/unittests/test_build.py b/jenkinsapi_tests/unittests/test_build.py
index 1af1bd9..a72fc91 100644
--- a/jenkinsapi_tests/unittests/test_build.py
+++ b/jenkinsapi_tests/unittests/test_build.py
@@ -1,3 +1,5 @@
+import requests
+import warnings
 import pytest
 import pytz
 from . import configs
@@ -154,3 +156,34 @@ def test_only_ParametersAction_parameters_considered(build):
     params = build.get_params()
     assert params == expected
 
+def test_build_env_vars(monkeypatch, build):
+    def fake_get_data(cls, tree=None, params=None):
+        return configs.BUILD_ENV_VARS
+    monkeypatch.setattr(Build, 'get_data', fake_get_data)
+    assert build.get_env_vars() == configs.BUILD_ENV_VARS['envMap']
+
+def test_build_env_vars_wo_injected_env_vars_plugin(monkeypatch, build):
+    def fake_get_data(cls, tree=None, params=None):
+        raise requests.HTTPError('404')
+    monkeypatch.setattr(Build, 'get_data', fake_get_data)
+
+    with pytest.raises(requests.HTTPError) as excinfo:
+        with pytest.warns(None) as record:
+            build.get_env_vars()
+    assert '404' == str(excinfo.value)
+    assert len(record) == 1
+    expected = UserWarning('Make sure the Environment Injector '
+                           'plugin is installed.')
+    assert str(record[0].message) == str(expected)
+
+def test_build_env_vars_other_exception(monkeypatch, build):
+    def fake_get_data(cls, tree=None, params=None):
+        raise ValueError()
+    monkeypatch.setattr(Build, 'get_data', fake_get_data)
+
+    with pytest.raises(Exception) as excinfo:
+        with pytest.warns(None) as record:
+            build.get_env_vars()
+    assert '' == str(excinfo.value)
+    assert len(record) == 0
+