All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.kuali.maven.plugins.jenkins.helper.JenkinsHelper Maven / Gradle / Ivy

Go to download

Automated management of Jenkins jobs via Maven. Much of the information needed by Jenkins when creating a job is already in the Maven pom. The SCM information and CI url are present there. Jenkins jobs also typically have names that reflect the groupId, artifactId, and version in some manner. This plugin automates the process of creating Jenkins jobs by harvesting information from the POM to create XML config files in the format Jenkins needs. The Jenkins CLI wrapper is then used to create, update, read, and delete Jenkins jobs on the CI server.

There is a newer version: 1.2.8
Show newest version
/**
 * Copyright 2011-2013 The Kuali Foundation
 *
 * Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php
 *
 * 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.
 */
package org.kuali.maven.plugins.jenkins.helper;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.util.StringUtils;
import org.kuali.maven.common.Extractor;
import org.kuali.maven.common.PropertiesUtils;
import org.kuali.maven.common.ResourceUtils;
import org.kuali.maven.plugins.jenkins.BaseMojo;
import org.kuali.maven.plugins.jenkins.CliMojo;
import org.kuali.maven.plugins.jenkins.Command;
import org.kuali.maven.plugins.jenkins.DeleteJobMojo;
import org.kuali.maven.plugins.jenkins.DeleteJobsMojo;
import org.kuali.maven.plugins.jenkins.GenJobMojo;
import org.kuali.maven.plugins.jenkins.GenJobsMojo;
import org.kuali.maven.plugins.jenkins.GetJobMojo;
import org.kuali.maven.plugins.jenkins.GetJobsMojo;
import org.kuali.maven.plugins.jenkins.PushJobsMojo;
import org.kuali.maven.plugins.jenkins.RunJobCommand;
import org.kuali.maven.plugins.jenkins.RunJobMojo;
import org.kuali.maven.plugins.jenkins.RunJobsMojo;
import org.kuali.maven.plugins.jenkins.SimpleJobCommand;
import org.kuali.maven.plugins.jenkins.Style;
import org.kuali.maven.plugins.jenkins.context.GAV;
import org.kuali.maven.plugins.jenkins.context.JenkinsException;
import org.kuali.maven.plugins.jenkins.context.ProcessContext;
import org.kuali.maven.plugins.jenkins.context.ProcessResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class JenkinsHelper {

	private final Logger logger = LoggerFactory.getLogger(JenkinsHelper.class);

	public static final String XML_EXTENSION = ".xml";
	public static final int SUCCESS_CODE = 0;
	public static final int NO_SUCH_COMMAND = 255;
	public static final String SERVER_ARG = "-s";
	public static final String NONE = "NONE";
	public static final String DASH = "-";
	public static final String FS = System.getProperty("file.separator", "/");

	Extractor extractor = new Extractor();
	PropertiesUtils propertiesUtils = new PropertiesUtils();
	ResourceUtils resourceUtils = new ResourceUtils();
	JavaHelper javaHelper = new JavaHelper();
	SshHelper sshHelper = new SshHelper();
	CommandHelper cmdHelper = new CommandHelper();

	protected List getNamesList(String csvNames, List names) {
		if (!Helper.isEmpty(names)) {
			return names;
		} else {
			return Helper.splitAndTrimCSVToList(csvNames);
		}
	}

	protected List getJobNames(BaseMojo mojo, String csvNames, List names) {
		List namesList = getNamesList(csvNames, names);
		List newNames = new ArrayList();
		for (String name : namesList) {
			String newName = getJobName(mojo, name);
			newNames.add(newName);
		}
		return newNames;
	}

	public void execute(GetJobMojo mojo) {
		List jobNames = getJobNames(mojo, mojo.getName(), null);
		List commands = createGetJobCommands(mojo, mojo.getCmd(), jobNames);
		executeCli(mojo, commands);
	}

	public void execute(GetJobsMojo mojo) {
		List jobNames = getJobNames(mojo, mojo.getNames(), mojo.getNameList());
		List commands = createGetJobCommands(mojo, mojo.getCmd(), jobNames);
		executeCli(mojo, commands);
	}

	protected List createGetJobCommands(BaseMojo mojo, String cmd, List jobNames) {
		List commands = new ArrayList();
		for (String jobName : jobNames) {
			Command command = createGetJobCommand(mojo, cmd, jobName);
			commands.add(command);
		}
		return commands;
	}

	protected Command createGetJobCommand(BaseMojo mojo, String cmd, String jobName) {
		String filename = mojo.getWorkingDir() + FS + jobName + XML_EXTENSION;
		String[] args = { cmd, jobName };
		Command command = new Command();
		command.setArgs(Arrays.asList(args));
		command.setStdout(new File(filename));
		return command;
	}

	protected GAV getGav(Properties properties) {
		String groupId = properties.getProperty("jenkins.cli.groupId");
		String artifactId = properties.getProperty("jenkins.cli.artifactId");
		String version = properties.getProperty("jenkins.cli.version");
		if (Helper.anyAreBlank(groupId, artifactId, version)) {
			return null;
		}
		GAV gav = new GAV();
		gav.setVersion(version);
		gav.setArtifactId(artifactId);
		gav.setGroupId(groupId);
		return gav;
	}

	protected GAV getGav(Artifact artifact) {
		GAV gav = new GAV();
		gav.setGroupId(artifact.getGroupId());
		gav.setArtifactId(artifact.getArtifactId());
		gav.setVersion(artifact.getVersion());
		return gav;
	}

	protected GAV getGav(MavenProject project) {
		try {
			String location = "classpath:org/kuali/maven/plugins/jenkins/jenkins-cli.properties";
			Properties internal = propertiesUtils.getProperties(location);
			GAV internalGAV = getGav(internal);
			GAV overrideGAV = getGav(project.getProperties());

			GAV gav = internalGAV;
			if (overrideGAV != null && !internalGAV.equals(overrideGAV)) {
				logger.info("Jenkins CLI override: [internal=" + internalGAV + ", override=" + overrideGAV + "]");
				gav = overrideGAV;
			}
			return gav;
		} catch (IOException e) {
			throw new JenkinsException(e);
		}

	}

	protected File getJenkinsJar(MavenProject project, List pluginArtifacts) {
		GAV gav = getGav(project);
		File jar = getJar(gav, pluginArtifacts);
		if (jar == null) {
			throw new JenkinsException("Unable to locate jenkins-cli.jar");
		} else {
			return jar;
		}
	}

	protected File getJar(GAV gav, List artifacts) {
		for (Artifact artifact : artifacts) {
			if (equals(artifact, gav)) {
				return artifact.getFile();
			}
		}
		return null;
	}

	protected boolean equals(Artifact artifact, GAV gav) {
		GAV artifactGav = getGav(artifact);
		return artifactGav.equals(gav);
	}

	protected List getFiles(File workingDir) {
		if (!workingDir.exists()) {
			return new ArrayList();
		}
		FileFilter filter = new XmlFileFilter();
		File[] files = workingDir.listFiles(filter);
		return Arrays.asList(files);
	}

	protected void pushJobs(BaseMojo mojo, String cmd) {
		try {
			List commands = getCommands(mojo.getWorkingDir(), cmd);
			executeCli(mojo, commands);
		} catch (IOException e) {
			throw new JenkinsException(e);
		}

	}

	protected List getCommands(File workingDir, String cmd) throws IOException {
		List files = getFiles(workingDir);
		List commands = new ArrayList();
		for (File file : files) {
			Command command = getCommand(file, cmd);
			commands.add(command);
		}
		return commands;
	}

	protected String getJobName(File file) {
		String name = file.getName();
		int pos = name.lastIndexOf(XML_EXTENSION);
		return name.substring(0, pos);
	}

	protected Command getCommand(File file, String cmd) throws IOException {
		String stdin = resourceUtils.read(file.getAbsolutePath());
		String jobName = getJobName(file);
		String[] args = { cmd, jobName };
		Command command = new Command();
		command.setStdin(stdin);
		command.setArgs(Arrays.asList(args));
		return command;
	}

	protected String getInput(Command cmd) {
		if (!StringUtils.isBlank(cmd.getStdinUrl())) {
			try {
				return resourceUtils.read(cmd.getStdinUrl());
			} catch (IOException e) {
				throw new JenkinsException(e);
			}
		} else {
			return cmd.getStdin();
		}
	}

	protected Map getSshOptions(int port, boolean verbose) {
		Map options = new HashMap();
		if (verbose) {
			options.put("v", "");
		}
		options.put("p", port + "");
		return options;
	}

	protected String[] getCliArgs(String url, List args) {
		List list = new ArrayList();
		list.add(SERVER_ARG);
		list.add(url);
		list.addAll(args);
		return Helper.toArray(list);
	}

	protected int[] getSuccessCodes(BaseMojo mojo) {
		String csv = mojo.getSuccessCodes();
		return Helper.toIntArray(csv);
	}

	protected void handleResult(Command command, ProcessResult result, BaseMojo mojo) {
		int[] successCodes = getSuccessCodes(mojo);
		int exitValue = result.getExitValue();
		if (Helper.isMatch(exitValue, successCodes)) {
			handleSuccess(mojo, command, result);
		} else {
			handleFailure(mojo, result);
		}
	}

	protected void logInfo(List lines) {
		if (lines.size() == 0) {
			return;
		}
		for (String line : lines) {
			logger.info(line);
		}
	}

	protected void logError(List lines) {
		String top = getTop(lines);
		if (top != null) {
			logger.error(top);
		}
	}

	protected void logWarning(List lines) {
		String top = getTop(lines);
		if (top != null) {
			logger.warn(top);
		}
	}

	protected String getTop(List lines) {
		for (String line : lines) {
			if (!StringUtils.isBlank(line)) {
				return line;
			}
		}
		return null;
	}

	protected void handleFailure(BaseMojo mojo, ProcessResult result) {
		if (mojo.isStopOnError()) {
			logger.error("Jenkins CLI Exception:" + getErrorMessage(mojo, result));
			throw new JenkinsException("Jenkins CLI Exception");
		} else {
			if (mojo.isFailOnError()) {
				logError(result.getOutputLines());
			} else {
				logWarning(result.getOutputLines());
			}
		}
	}

	protected void handleSuccess(BaseMojo mojo, Command command, ProcessResult result) {
		File stdout = command.getStdout();
		if (stdout != null) {
			write(stdout.getAbsolutePath(), result.getOutput());
		} else {
			List lines = result.getOutputLines();
			if (result.getExitValue() == SUCCESS_CODE) {
				logInfo(lines);
			} else {
				String top = getTop(lines);
				if (top != null) {
					logger.info(top);
				}
			}
		}
	}

	protected void write(String filename, String content) {
		try {
			resourceUtils.write(new File(filename), content);
		} catch (IOException e) {
			throw new JenkinsException(e);
		}
	}

	protected Map getBuildParameters(Map map, String csv) {
		Map buildParameters = new HashMap();
		if (!Helper.isEmpty(map)) {
			buildParameters.putAll(map);
		}
		if (!StringUtils.isBlank(csv)) {
			String[] keyValuePairs = Helper.splitAndTrimCSV(csv);
			Map csvMap = Helper.toMap(keyValuePairs);
			buildParameters.putAll(csvMap);
		}
		return buildParameters;
	}

	protected RunJobCommand getRunJobCommand(RunJobMojo mojo, String jobName, Map params) {
		RunJobCommand rjc = new RunJobCommand();
		rjc.setName(jobName);
		rjc.setParams(params);
		rjc.setCommand(mojo.getCmd());
		rjc.setWait(mojo.isWait());
		rjc.setSkipIfNoChanges(mojo.isSkipIfNoChanges());
		return rjc;
	}

	public void updateMojo(BaseMojo mojo) {
		MavenProject project = mojo.getProject();
		String scmType = extractor.getScmType(project.getScm());
		String scmUrl = extractor.getScmUrl(project.getScm());
		String majorVersion = extractor.getMajorVersion(project.getVersion());

		if (StringUtils.isBlank(mojo.getScmType())) {
			mojo.setScmType(scmType);
		}
		if (StringUtils.isBlank(mojo.getScmUrl())) {
			mojo.setScmUrl(scmUrl);
		}
		if (StringUtils.isBlank(mojo.getMajorVersion())) {
			mojo.setMajorVersion(majorVersion);
		}
	}

	public void execute(DeleteJobMojo mojo) {
		String ignoreCodes = mojo.getIgnoreCodes();
		String successCodes = mojo.getSuccessCodes();
		String newSuccessCodes = successCodes + "," + ignoreCodes;
		mojo.setSuccessCodes(newSuccessCodes);
		String jobName = getJobName(mojo, mojo.getName());
		SimpleJobCommand sjc = getSimpleJobCommand(jobName, mojo.getCmd());
		Command command = new Command();
		command.setArgs(cmdHelper.toArgs(sjc));
		executeCli(mojo, command);
	}

	protected List getSimpleJobCommands(List names, String cmd) {
		List commands = new ArrayList();
		for (String name : names) {
			SimpleJobCommand sjc = getSimpleJobCommand(name, cmd);
			commands.add(sjc);
		}
		return commands;
	}

	protected SimpleJobCommand getSimpleJobCommand(String name, String cmd) {
		SimpleJobCommand sjc = new SimpleJobCommand();
		sjc.setName(name);
		sjc.setCommand(cmd);
		return sjc;
	}

	public void execute(DeleteJobsMojo mojo) {
		String ignoreCodes = mojo.getIgnoreCodes();
		String successCodes = mojo.getSuccessCodes();
		String newSuccessCodes = successCodes + "," + ignoreCodes;
		mojo.setSuccessCodes(newSuccessCodes);
		List jobNames = getJobNames(mojo, mojo.getNames(), mojo.getNameList());
		List sjcs = getSimpleJobCommands(jobNames, mojo.getCmd());
		List commands = getCommandsFromSimple(sjcs);
		executeCli(mojo, commands);
	}

	public void execute(RunJobMojo mojo) {
		String jobName = getJobName(mojo, mojo.getName());
		Map params = getBuildParameters(mojo.getParamMap(), mojo.getParams());
		RunJobCommand rjc = getRunJobCommand(mojo, jobName, params);
		Command command = new Command();
		command.setArgs(cmdHelper.toArgs(rjc));
		executeCli(mojo, command);
	}

	protected void updateCommands(List commands, String cmd, BaseMojo mojo) {
		for (RunJobCommand command : commands) {
			String name = getJobName(mojo, command.getName());
			command.setName(name);
			command.setCommand(cmd);
		}
	}

	protected List getCommandsFromSimple(List sjcs) {
		List commands = new ArrayList();
		for (SimpleJobCommand sjc : sjcs) {
			Command command = new Command();
			command.setArgs(cmdHelper.toArgs(sjc));
			commands.add(command);
		}
		return commands;
	}

	protected List getCommands(List rjcs) {
		List commands = new ArrayList();
		for (RunJobCommand rjc : rjcs) {
			Command command = new Command();
			command.setArgs(cmdHelper.toArgs(rjc));
			commands.add(command);
		}
		return commands;
	}

	public void execute(RunJobsMojo mojo) {
		// nothing to do
		if (Helper.isEmpty(mojo.getCommands())) {
			return;
		}
		updateCommands(mojo.getCommands(), mojo.getCmd(), mojo);
		List commands = getCommands(mojo.getCommands());
		executeCli(mojo, commands);
	}

	public void execute(PushJobsMojo mojo) {
		pushJobs(mojo, mojo.getCmd());
	}

	public void execute(CliMojo mojo) {
		List cmds = cmdHelper.getCommands(mojo);
		executeCli(mojo, cmds);
	}

	protected void executeCli(BaseMojo mojo, Command command) {
		executeCli(mojo, Helper.toList(command));
	}

	protected String getActualUrl(BaseMojo mojo) {
		if (mojo.isSshEnabled()) {
			return mojo.getUsername() + "@" + mojo.getHostname();
		} else {
			return mojo.getUrl();
		}
	}

	protected void executeCli(BaseMojo mojo, List commands) {
		String url = getActualUrl(mojo);
		logger.info("Jenkins URL - " + url);

		File jar = null;
		if (!mojo.isSshEnabled()) {
			jar = getJenkinsJar(mojo.getProject(), mojo.getPluginArtifacts());
			logger.info("Jenkins CLI: " + jar.getPath());
		}
		List results = new ArrayList();
		for (Command command : commands) {
			logger.info(Helper.toString(command.getArgs()));
			ProcessResult result = executeCli(mojo, jar, url, command);
			handleResult(command, result, mojo);
			results.add(result);
		}
		handleResults(results, mojo);
	}

	protected ProcessResult executeCli(BaseMojo mojo, File jar, String url, Command cmd) {
		String input = getInput(cmd);
		return executeCli(mojo, jar, url, cmd.getArgs(), input);
	}

	protected ProcessResult executeCli(BaseMojo mojo, File jar, String url, List args, String input) {
		if (mojo.isSshEnabled()) {
			List cliArgs = new ArrayList();
			cliArgs.add(url);
			cliArgs.addAll(args);
			Map options = getSshOptions(mojo.getSshPort(), mojo.isSshVerbose());
			return sshHelper.execute(options, cliArgs, input);
		} else {
			String[] cliArgs = getCliArgs(url, args);
			return javaHelper.executeJar(jar, cliArgs, input);
		}
	}

	protected void handleResults(List results, BaseMojo mojo) {
		int[] successCodes = getSuccessCodes(mojo);
		List errors = new ArrayList();
		for (ProcessResult result : results) {
			int exitValue = result.getExitValue();
			if (!Helper.isMatch(exitValue, successCodes)) {
				errors.add(result);
			}
		}
		if (errors.size() == 0) {
			return;
		}
		if (mojo.isFailOnError()) {
			logger.error(getErrorMessage(mojo, errors));
			throw new JenkinsException("Jenkins CLI error");
		} else {
			logger.warn(getWarnMessage(errors));
		}
	}

	protected String getWarnMessage(List errors) {
		StringBuilder sb = new StringBuilder();
		if (errors.size() == 1) {
			sb.append("There was 1 error.");
		} else {
			sb.append("There were " + errors.size() + " errors.");
		}
		return sb.toString();
	}

	protected String getErrorMessage(BaseMojo mojo, List errors) {
		StringBuilder sb = new StringBuilder();
		if (errors.size() == 1) {
			sb.append("There was 1 error.");
		} else {
			sb.append("There were " + errors.size() + " errors.");
		}
		for (ProcessResult result : errors) {
			sb.append(getErrorMessage(mojo, result));
		}
		return sb.toString();
	}

	protected String getErrorMessage(BaseMojo mojo, ProcessResult result) {
		ProcessContext context = result.getContext();
		int exitValue = result.getExitValue();
		String top = getTop(result.getOutputLines());
		String[] args = result.getContext().getArgs();
		String cmd = Helper.toString(args, " ");
		StringBuilder sb = new StringBuilder();
		sb.append("\n");
		sb.append("msg: " + top + "\n");
		sb.append("executable: " + context.getExecutable() + "\n");
		sb.append("cmd: " + cmd + "\n");
		sb.append("result: " + exitValue + "\n");
		sb.append("input: " + getInputErrorMessage(mojo, context.getInput()) + "\n");
		// if (exitValue != NO_SUCH_COMMAND) {
		sb.append("details: " + result.getOutput());
		// }
		return sb.toString();
	}

	protected String getInputErrorMessage(BaseMojo mojo, String input) {
		String s = Helper.toEmpty(input);
		if (StringUtils.isBlank(s)) {
			return s;
		}
		int length = input.length();
		if (length > 50) {
			long count = Counter.increment() + 1;
			File dir = mojo.getWorkingDir();
			String filename = dir + FS + "error" + FS + "input-" + count + ".log";
			File file = new File(filename);
			write(filename, input);
			return Helper.getRelativePath(mojo.getProject().getBasedir(), file);
		} else {
			return input;
		}
	}

	public void execute(GenJobsMojo mojo) {
		List types = Helper.splitAndTrimCSVToList(mojo.getTypes());
		generateJobs(mojo, types);
	}

	public void execute(GenJobMojo mojo) {
		generateJob(mojo, mojo.getType());
	}

	protected void generateJobs(BaseMojo mojo, List types) {
		for (String type : types) {
			generateJob(mojo, type);
		}
	}

	protected String getRelativePath(BaseMojo mojo, String filename) {
		File dir = mojo.getProject().getBasedir();
		File file = new File(filename);
		String relativePath = Helper.getRelativePath(dir, file);
		if (relativePath == null) {
			return filename;
		} else {
			return relativePath;
		}
	}

	protected List