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

com.marvelution.bamboo.plugins.sonar.tasks.AbstractSonarMavenBuildTask Maven / Gradle / Ivy

/*
 * Licensed to Marvelution under one or more contributor license 
 * agreements.  See the NOTICE file distributed with this work 
 * for additional information regarding copyright ownership.
 * Marvelution licenses this file to you 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.
 */

package com.marvelution.bamboo.plugins.sonar.tasks;

import static com.atlassian.bamboo.task.TaskConfigConstants.CFG_PROJECT_FILENAME;

import java.io.File;
import java.io.FileReader;

import com.atlassian.bamboo.build.logger.BuildLogger;
import com.atlassian.bamboo.build.logger.interceptors.ErrorMemorisingInterceptor;
import com.atlassian.bamboo.build.logger.interceptors.LogMemorisingInterceptor;
import com.atlassian.bamboo.build.logger.interceptors.StringMatchingInterceptor;
import com.atlassian.bamboo.builder.MavenLogHelper;
import com.atlassian.bamboo.process.EnvironmentVariableAccessor;
import com.atlassian.bamboo.process.ExternalProcessBuilder;
import com.atlassian.bamboo.process.ProcessService;
import com.atlassian.bamboo.task.TaskContext;
import com.atlassian.bamboo.task.TaskException;
import com.atlassian.bamboo.task.TaskResult;
import com.atlassian.bamboo.task.TaskResultBuilder;
import com.atlassian.bamboo.task.TaskType;
import com.atlassian.bamboo.utils.SystemProperty;
import com.atlassian.bamboo.v2.build.CurrentBuildResult;
import com.atlassian.bamboo.v2.build.agent.capability.CapabilityContext;
import com.atlassian.utils.process.ExternalProcess;
import com.marvelution.bamboo.plugins.sonar.tasks.configuration.SonarConfigConstants;
import com.marvelution.bamboo.plugins.sonar.tasks.processors.SonarBuildPasswordProcessor;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.maven.model.Model;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.jetbrains.annotations.NotNull;

/**
 * Abstract Sonar {@link TaskType} implementation for use with Maven 2 or 3
 * This reuses the Maven 2 and Maven 3 implementations provided by Atlassian
 * 
 * @param  the Type extending {@link AbstractSonarMavenConfig}
 * 
 * @author Mark Rekveld
 */
public abstract class AbstractSonarMavenBuildTask implements TaskType {

	private static final String BUILD_SUCCESSFUL_MARKER = SystemProperty.BUILD_SUCCESSFUL_MARKER
		.getValue("BUILD SUCCESS");
	private static final boolean SEARCH_BUILD_SUCCESS_FAIL_MESSAGE_EVERYWHERE =
		SystemProperty.SEARCH_BUILD_SUCCESS_FAIL_MESSAGE_EVERYWHERE.getValue(false);
	private static final int LINES_TO_PARSE_FOR_ERRORS = 200;
	private static final int FIND_SUCCESS_MESSAGE_IN_LAST = SystemProperty.FIND_SUCCESS_MESSAGE_IN_LAST.getValue(250);

	protected final CapabilityContext capabilityContext;
	protected final EnvironmentVariableAccessor environmentVariableAccessor;
	protected final ProcessService processService;

	/**
	 * Default Constructor
	 * 
	 * @param capabilityContext the {@link CapabilityContext} implementation
	 * @param environmentVariableAccessor the {@link EnvironmentVariableAccessor} implementation
	 * @param processService the {@link ProcessService} implementation
	 */
	public AbstractSonarMavenBuildTask(CapabilityContext capabilityContext,
		EnvironmentVariableAccessor environmentVariableAccessor, ProcessService processService) {
		this.capabilityContext = capabilityContext;
		this.environmentVariableAccessor = environmentVariableAccessor;
		this.processService = processService;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	@NotNull
	public TaskResult execute(@NotNull TaskContext taskContext) throws TaskException {
		final BuildLogger buildLogger = taskContext.getBuildLogger();
		final CurrentBuildResult currentBuildResult = taskContext.getBuildContext().getBuildResult();

		CONFIG config = getMavenConfiguration(taskContext);

		StringMatchingInterceptor buildSuccessMatcher =
			new StringMatchingInterceptor(BUILD_SUCCESSFUL_MARKER, SEARCH_BUILD_SUCCESS_FAIL_MESSAGE_EVERYWHERE);
		LogMemorisingInterceptor recentLogLines = new LogMemorisingInterceptor(LINES_TO_PARSE_FOR_ERRORS);
		ErrorMemorisingInterceptor errorLines = new ErrorMemorisingInterceptor();

		buildLogger.getInterceptorStack().add(buildSuccessMatcher);
		buildLogger.getInterceptorStack().add(recentLogLines);
		buildLogger.getInterceptorStack().add(errorLines);
		buildLogger.getInterceptorStack().add(new SonarBuildPasswordProcessor());

		try {
			ExternalProcess externalProcess = processService.executeProcess(taskContext,
					new ExternalProcessBuilder().workingDirectory(config.getWorkingDirectory())
						.env(config.getExtraEnvironment()).command(config.getCommandline()));
			if (externalProcess.getHandler().isComplete()) {
				TaskResultBuilder taskResultBuilder =
					TaskResultBuilder.create(taskContext).checkReturnCode(externalProcess)
						.checkInterceptorMatches(buildSuccessMatcher, FIND_SUCCESS_MESSAGE_IN_LAST);
				TaskResult result = taskResultBuilder.build();
				Model pom = getProjectObjectModel(getProjectFile(taskContext));
				if (pom != null) {
					final String projectKey = getResourceKeyFromProjectModel(pom);
					getLogger().info("Setting the projectKey '" + projectKey + "' in the Build Results");
					currentBuildResult.getCustomBuildData().put(SonarConfigConstants.TRD_SONAR_PROJECT_KEY,
						projectKey);
					String resourceName = pom.getArtifactId();
					if (StringUtils.isNotBlank(pom.getName())) {
						resourceName = pom.getName();
					}
					getLogger().info("Setting the projectName '" + resourceName + "' in the Build Results");
					currentBuildResult.getCustomBuildData().put(SonarConfigConstants.TRD_SONAR_PROJECT_NAME,
						resourceName);
				} else{
					getLogger().warn("Failed to get the Project Key from the Maven Project Object Model");
				}
				return result;
			}
			throw new TaskException("Failed to execute sonar command, external process not completed?");
		} catch (Exception e) {
			throw new TaskException("Failed to execute sonar task", e);
		} finally {
			currentBuildResult.addBuildErrors(errorLines.getErrorStringList());
			currentBuildResult.addBuildErrors(MavenLogHelper.parseErrorOutput(recentLogLines.getLogEntries()));
		}
	}

	/**
	 * Get the Maven project file for the given {@link TaskContext}
	 * 
	 * @param taskContext the {@link TaskContext} to use to get the project file
	 * @return the project {@link File}
	 */
	private File getProjectFile(TaskContext taskContext) {
		if (StringUtils.isNotBlank(taskContext.getConfigurationMap().get(CFG_PROJECT_FILENAME))) {
			return new File(taskContext.getWorkingDirectory(),
				taskContext.getConfigurationMap().get(CFG_PROJECT_FILENAME));
		} else {
			return new File(taskContext.getWorkingDirectory(), SonarConfigConstants.MAVEN_PROJECT_FILE);
		}
	}

	/**
	 * Get the Apache Maven {@link Model} for a given project {@link File}
	 * 
	 * @param projectFile the project {@link File} to get the {@link Model} from
	 * @return the {@link Model} read from the project {@link File}, can be null if exceptions occur
	 */
	private Model getProjectObjectModel(File projectFile) {
		MavenXpp3Reader reader = new MavenXpp3Reader();
		try {
			return reader.read(new FileReader(projectFile));
		} catch (Exception e) {
			getLogger().warn("Failed to read the Maven Model from file: " + projectFile.getAbsolutePath(), e);
			return null;
		}
	}

	/**
	 * Internal method to get a Sonar Resource Key from the Maven {@link Model} given
	 * 
	 * @param model the Maven {@link Model}
	 * @return the SoanrResource Key
	 */
	private String getResourceKeyFromProjectModel(Model model) {
		String groupId = model.getGroupId();
		if (StringUtils.isBlank(groupId)) {
			groupId = model.getParent().getGroupId();
		}
		return String.format("%s:%s", groupId, model.getArtifactId());
	}

	/**
	 * Getter for the Maven Configuration used to execute the Sonar Analysis
	 * 
	 * @return the Maven Configuration
	 */
	protected abstract CONFIG getMavenConfiguration(TaskContext taskContext);

	/**
	 * Get the {@link Logger} from the sub class
	 * 
	 * @return the {@link Logger}
	 */
	protected abstract Logger getLogger();

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy