Fix for issue #280
authorAleksey Maksimov <ctpeko3a@gmail.com>
Sat, 24 May 2014 15:08:03 +0000 (23:08 +0800)
committerAleksey Maksimov <ctpeko3a@gmail.com>
Sat, 24 May 2014 15:14:18 +0000 (23:14 +0800)
Properly pass job parameters via json
When files parameter present select correct job invokation url

jenkinsapi/job.py
jenkinsapi_tests/systests/job_configs.py
jenkinsapi_tests/systests/test_parameterized_builds.py

index e46899581fceeaa7e9f0c78377999594da384138..fb379d73adefb8567fe5333226e16ac265ba6afe 100644 (file)
@@ -138,27 +138,29 @@ class Job(JenkinsBase, MutableJenkinsThing):
         return "%s/buildWithParameters" % self.baseurl
 
     @staticmethod
-    def _mk_json_from_build_parameters(build_params):
+    def _mk_json_from_build_parameters(build_params, file_params=None):
         """
-        Build parameters must be submitted in a particular format - Key-Value pairs would be
-        far too simple, no no! Watch and read on and behold!
+        Build parameters must be submitted in a particular format
+        Key-Value pairs would be far too simple, no no!
+        Watch and read on and behold!
         """
         assert isinstance(
             build_params, dict), 'Build parameters must be a dict'
 
-        try:
-            it = build_params.iteritems()
-        except AttributeError:
-            # Python3
-            it = build_params.items()
+        build_p = [{'name': k, 'value': v}
+                   for k, v in build_params.iteritems()]
+        out = {'parameter': build_p}
+        if file_params:
+            file_p = [{'name': k, 'file': k}
+                      for k in file_params.iterkeys()]
+            out['parameter'].extend(file_p)
 
-        return {'parameter': [
-            {'name': k, 'value': v} for k, v in it
-        ]}
+        return out
 
     @staticmethod
-    def mk_json_from_build_parameters(build_params):
-        to_json_structure = Job._mk_json_from_build_parameters(build_params)
+    def mk_json_from_build_parameters(build_params, file_params=None):
+        to_json_structure = Job._mk_json_from_build_parameters(build_params,
+                                                               file_params)
         return json.dumps(to_json_structure)
 
     def invoke(self, securitytoken=None, block=False, skip_if_running=False, invoke_pre_check_delay=3,
@@ -196,6 +198,11 @@ class Job(JenkinsBase, MutableJenkinsThing):
                 self.get_jenkins_obj()))
 
             url = self.get_build_triggerurl()
+            # If job has file parameters - it must be triggered
+            # using "/build", not by "/buildWithParameters"
+            # "/buildWithParameters" will ignore non-file parameters
+            if files:
+                url = "%s/build" % self.baseurl
 
             if cause:
                 build_params['cause'] = cause
@@ -203,6 +210,7 @@ class Job(JenkinsBase, MutableJenkinsThing):
             if securitytoken:
                 params['token'] = securitytoken
 
+            build_params['json'] = self.mk_json_from_build_parameters(build_params, files)
             data = build_params
 
             response = self.jenkins.requester.post_and_confirm_status(
index 1cf58a6e32b972f29fc206abfcd6b6c16bb11d34..2f127a4983406a6834ffbec44065e81e47a4efdc 100644 (file)
@@ -270,3 +270,45 @@ echo $B &gt; b.txt</command>
   </publishers>
   <buildWrappers/>
 </project>""".strip()
+
+JOB_WITH_FILE_AND_PARAMS = """
+<?xml version='1.0' encoding='UTF-8'?>
+<project>
+  <actions/>
+  <description></description>
+  <keepDependencies>false</keepDependencies>
+  <properties>
+    <hudson.model.ParametersDefinitionProperty>
+      <parameterDefinitions>
+        <hudson.model.FileParameterDefinition>
+          <name>file.txt</name>
+          <description></description>
+        </hudson.model.FileParameterDefinition>
+        <hudson.model.StringParameterDefinition>
+          <name>B</name>
+          <description>B, like buzzing B.</description>
+          <defaultValue></defaultValue>
+        </hudson.model.StringParameterDefinition>
+      </parameterDefinitions>
+    </hudson.model.ParametersDefinitionProperty>
+  </properties>
+  <scm class="hudson.scm.NullSCM"/>
+  <canRoam>true</canRoam>
+  <disabled>false</disabled>
+  <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
+  <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
+  <triggers/>
+  <concurrentBuild>false</concurrentBuild>
+  <builders>
+    <hudson.tasks.Shell>
+      <command>cat file.txt;echo $B &gt; file1.txt</command>
+    </hudson.tasks.Shell>
+  </builders>
+  <publishers>
+    <hudson.tasks.ArtifactArchiver>
+      <artifacts>*</artifacts>
+      <latestOnly>false</latestOnly>
+    </hudson.tasks.ArtifactArchiver>
+  </publishers>
+  <buildWrappers/>
+</project>""".strip()
index 2c69cfde92cd67194099113790174ae4273fb65b..678ea33ed80c3ad653c21e210216e8ae02fb5799 100644 (file)
@@ -14,6 +14,7 @@ except ImportError:
 from jenkinsapi_tests.systests.base import BaseSystemTest
 from jenkinsapi_tests.test_utils.random_strings import random_string
 from jenkinsapi_tests.systests.job_configs import JOB_WITH_FILE
+from jenkinsapi_tests.systests.job_configs import JOB_WITH_FILE_AND_PARAMS
 from jenkinsapi_tests.systests.job_configs import JOB_WITH_PARAMETERS
 from jenkinsapi.custom_exceptions import WillNotBuild
 
@@ -98,6 +99,27 @@ class TestParameterizedBuilds(BaseSystemTest):
         expected_msg = 'A build with these parameters is already queued.'
         self.assertEqual(str(na.exception), expected_msg)
 
+    def test_invoke_job_with_file_and_params(self):
+        file_data = random_string()
+        param_data = random_string()
+        param_file = StringIO(file_data)
+
+        job_name = 'create_%s' % random_string()
+        job = self.jenkins.create_job(job_name, JOB_WITH_FILE_AND_PARAMS)
+        job.invoke(block=True, files={'file.txt': param_file},
+                   build_params={'B': param_data})
+
+        build = job.get_last_build()
+        while build.is_running():
+            time.sleep(0.25)
+
+        artifacts = build.get_artifact_dict()
+        self.assertIsInstance(artifacts, dict)
+        art_file = artifacts['file.txt']
+        self.assertTrue(art_file.get_data().strip(), file_data)
+        art_param = artifacts['file1.txt']
+        self.assertTrue(art_param.get_data().strip(), param_data)
+
 
 if __name__ == '__main__':
     unittest.main()