Java tutorial
import com.offbytwo.jenkins.JenkinsServer; import com.offbytwo.jenkins.client.JenkinsHttpClient; import com.offbytwo.jenkins.model.Build; import com.offbytwo.jenkins.model.BuildResult; import com.offbytwo.jenkins.model.BuildWithDetails; import com.offbytwo.jenkins.model.Job; import com.offbytwo.jenkins.model.JobWithDetails; import org.apache.http.client.HttpResponseException; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; import java.io.StringReader; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; /** Copyright 2016 Alianza Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ public class JenkinsHelper { JSONObject config; JenkinsHttpClient client; JenkinsServer jenkins; boolean crumbsFlag = false; public JenkinsHelper(String configFile) throws JSONException, URISyntaxException, IOException { // parse the config file config = ConfigParser.parseConfigFile(configFile); // crumbs flag will not work without "Prevent Cross Site Request Forgery Exploits" enabled in jenkins if (config.has("crumbsFlag")) crumbsFlag = config.getBoolean("crumbsFlag"); URI jenkinsURI = new URI(config.getString("jenkinsURI")); String username = config.getString("username"); String token = config.getString("token"); // setup our client client = new JenkinsHttpClient(jenkinsURI, username, token); jenkins = new JenkinsServer(client); } public void createJob(String test, JSONObject repository) throws Exception { String jobName = ConfigParser.parseConfigString(repository.getString("jobName"), test); String jobXML = generateJobXML(test, repository); Map<String, Job> jobs = jenkins.getJobs(); if (jobs.containsKey(jobName.toLowerCase())) { jenkins.updateJob(jobName.toLowerCase(), jobXML, crumbsFlag); } else { jenkins.createJob(jobName, jobXML, crumbsFlag); } if (repository.has("addToView")) { String addToView = repository.getString("addToView"); addJobToView(jobName, addToView); } } public void runJobIfFailing(String test, JSONObject repository) throws Exception { String jobName = ConfigParser.parseConfigString(repository.getString("jobName"), test); JobWithDetails job = jenkins.getJob(jobName); if (job == null) { System.out.println("Job not yet created, skipping: [" + jobName + "]"); return; } Build lastBuild = job.getLastBuild(); if (lastBuild == null) { runJob(test, repository); return; } BuildResult lastResult = lastBuild.details().getResult(); if (lastResult != null && lastResult.equals(BuildResult.FAILURE)) { runJob(test, repository); } } public void runJob(String test, JSONObject repository) throws Exception { String jobName = ConfigParser.parseConfigString(repository.getString("jobName"), test); Map<String, String> params = new HashMap<>(); if (repository.has("buildParams")) { JSONObject buildParams = repository.getJSONObject("buildParams"); Iterator keys = buildParams.keys(); while (keys.hasNext()) { String key = (String) keys.next(); params.put(key, buildParams.getString(key)); } System.out.println("Running job with parameters [" + jobName + "]"); runJob(test, repository, params); } else { System.out.println("Running job without parameters [" + jobName + "]"); try { jenkins.getJob(jobName).build(crumbsFlag); } catch (HttpResponseException e) { System.out.println("Running job [" + jobName + "] without parameters failed, were there supposed to be parameters?"); e.printStackTrace(); } } } public void runJob(String test, JSONObject repository, Map<String, String> params) throws Exception { String jobName = ConfigParser.parseConfigString(repository.getString("jobName"), test); try { jenkins.getJob(jobName).build(params, crumbsFlag); } catch (HttpResponseException e) { System.out.println("Running job [" + jobName + "] with parameters failed, params sent:"); System.out.println(params); e.printStackTrace(); } } private String generateJobXML(String test, JSONObject repository) throws Exception { String templateJob = repository.getString("templateJob").toLowerCase(); if (!jenkins.getJobs().containsKey(templateJob)) { throw new Exception("Template job not found in jenkins jobs, is the name right?"); } String jobXML = client.get("/job/" + templateJob.replace(" ", "%20") + "/config.xml"); SAXReader reader = new SAXReader(); Document doc = reader.read(new StringReader(jobXML)); Element root = doc.getRootElement(); if (repository.has("mvnOptions") || repository.has("mvnCommand")) { root = insertMvnGoals(root, repository, test); } else if (repository.has("executeShells") || repository.has("executeShell")) { root = insertShellCommand(root, repository, test); } else { System.out.println("WARNING - Did not provide an executeShell or mvnOptions/mvnCommand in repo: " + repository.getString("repository")); } if (repository.has("description")) { root = setDescription(root, repository.getString("description")); } else { root = setDescription(root, "Automatically generated test job"); } root = enableJob(root); return doc.asXML(); } private Element insertMvnGoals(Element root, JSONObject repository, String test) throws JSONException { String mvnOptions = ConfigParser.parseConfigString(repository.getString("mvnOptions"), test); String mvnCommand = ConfigParser.parseConfigString(repository.getString("mvnCommand"), test); root.element("goals").setText(mvnOptions + " " + mvnCommand); return root; } private Element setDescription(Element root, String description) { root.element("description").setText(description); return root; } private Element insertShellCommand(Element root, JSONObject repository, String test) throws Exception { // if we have multiple executeShells specified, make sure they're put in, in order if (repository.has("executeShells")) { JSONArray shells = repository.getJSONArray("executeShells"); List list = root.element("builders").elements("hudson.tasks.Shell"); // check how many execute shell's exist in the template job int count = 0; for (Iterator iter = list.iterator(); iter.hasNext();) { Element el = (Element) iter.next(); if (el.element("command") != null) { count++; } } // if the number of execute shell's in template job differ from the number in our config if (count != shells.length()) { throw new Exception("The number of ExecuteShells is different than the number in the template job"); } // insert the commands into the XML for (int i = 0; i < shells.length(); i++) { ((Element) root.element("builders").elements("hudson.tasks.Shell").get(i)).element("command") .setText(ConfigParser.parseConfigString(shells.getString(i), test)); } } else { root.element("builders").element("hudson.tasks.Shell").element("command") .setText(ConfigParser.parseConfigString(repository.getString("executeShell"), test)); } return root; } private Element enableJob(Element root) { root.element("disabled").setText("false"); return root; } //TODO: make addJobToView use dom4j instead of this nasty regex text parsing private void addJobToView(String jobName, String viewName) throws IOException { String viewXML = ""; try { viewXML = client.get("/view/" + viewName.replace(" ", "%20") + "/config.xml"); } catch (IOException e) { System.out.println("Failed to get view, please check spelling (case-sensitive) and try again"); e.printStackTrace(); } if (viewXML.isEmpty()) return; ArrayList<String> views = new ArrayList<>(); String regex = "<string>([a-zA-Z0-9\\-_\\. ]+)</string>"; Pattern p = Pattern.compile(regex); Matcher matcher = p.matcher(viewXML); while (matcher.find()) { views.add(matcher.group(1)); } // if our job is already in view, don't do anything else for (String view : views) { if (view.equals(jobName)) { return; } } views.add(jobName); Collections.sort(views, new Comparator<String>() { @Override public int compare(String s, String t1) { return s.toLowerCase().compareTo(t1.toLowerCase()); } }); viewXML = viewXML.replaceAll("\\s+?" + regex + "\\+?", ""); String v = ""; for (String view : views) { v += "<string>" + view + "</string>"; } viewXML = viewXML.replace("</jobNames>", v + "</jobNames>"); client.post_xml("/view/" + viewName.replace(" ", "%20") + "/config.xml", viewXML, crumbsFlag); } }