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

io.sealights.onpremise.agents.plugin.SeaLightsMojo Maven / Gradle / Ivy

package io.sealights.onpremise.agents.plugin;

import io.sealights.onpremise.agents.infra.logging.DefaultLogManager;
import io.sealights.onpremise.agents.infra.logging.Level;
import io.sealights.onpremise.agents.infra.logging.LogFactory;
import io.sealights.onpremise.agents.infra.utils.StringUtils;
import io.sealights.onpremise.agents.plugin.logging.MavenLogWrapper;
import io.sealights.onpremise.agents.plugin.surefire.PluginsHandler;
import io.sealights.plugins.engine.api.*;
import io.sealights.plugins.engine.lifecycle.BuildEndInfo;
import io.sealights.plugins.engine.lifecycle.BuildEndListener;
import io.sealights.plugins.engine.lifecycle.BuildLifeCycle;
import io.sealights.plugins.engine.procsexecutor.PluginEngineHandler;
import io.sealights.plugins.engine.utils.FilesStorageGoalHelper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Plugin;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.project.MavenProject;
import org.slf4j.Logger;

import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import static io.sealights.onpremise.agents.plugin.surefire.PluginsHandler.SEALIGHTS_DISABLED;

/**
 * An abstract Mojo for sealights mojos
 */
@Data
@EqualsAndHashCode(callSuper = false)
public abstract class SeaLightsMojo extends AbstractMojo implements PluginGoal, BuildEndListener {
	public static final String SEALIGHTS_MAVEN_PLUGIN = "sealights-mvn-plugin";
	public static final String POM_PACKAGING_VALUE = "pom";

	private PluginEngine pluginEngine;

	private Logger logger;

	private PluginsHandler pluginsHandler;

	/**
	 * Maven project.
	 *
	 * @parameter property="project" default_value="${project}"
	 * @required
	 * @readOnly
	 */
	@Getter
	private MavenProject project;

	/**
	 * The token provided by SeaLights.
	 *
	 * @parameter property="token"
	 */
	private String token;

	/**
	 * The token provided by SeaLights in file.
	 *
	 * @parameter property="tokenFile"
	 */
	private String tokenFile;

	/**
	 * Customer id.
	 *
	 * @parameter property="customerid"
	 */
	private String customerid;

	/**
	 * The url to sealights server.
	 *
	 * @parameter property="server"
	 */
	private String server;

	/**
	 * Url to proxy.
	 *
	 * @parameter property="proxy"
	 */
	private String proxy;

	/**
	 * Path to the source code root folder.
	 *
	 * @parameter property="workspacepath" default-value="${basedir}"
	 */
	private String workspacepath;

	/**
	 * Use buildSessionId feature for this build.
	 *
	 * @parameter property="createBuildSessionId" default-value="false"
	 */
	private boolean createBuildSessionId;

	/**
	 * Use buildSessionId for build session data.
	 *
	 * @parameter property="buildSessionId"
	 */
	private String buildSessionId;

	/**
	 * Build session id from file.
	 *
	 * @parameter property="buildSessionIdFile"
	 */
	private String buildSessionIdFile;

	/**
	 * The application name.
	 *
	 * @parameter property="appName"
	 */
	private String appName;

	/**
	 * The flag for module name build method.
	 * If not provided, project,name is used
	 * If true - project.artifactId is used
	 *
	 * @parameter property="moduleNameArtifactId" default-value="false"
	 */
	private boolean moduleNameArtifactId;


	/**
	 * The development environment.
	 *
	 * @parameter property="environment"
	 */
	private String environment;

	/**
	 * The branch name.
	 *
	 * @parameter property="branch"
	 */
	private String branch;

	/**
	 * The build version.
	 *
	 * @parameter property="build" default-value="${version}"
	 */
	private String build;

	/**
	 * Comma-separated list of packages to scan.
	 * Supports wildcards (* = any string, ? = any character).
	 * For example:'com.example.* ,io.*.demo, com.?ello.world'.
	 *
	 * @parameter property="packagesincluded"
	 */
	private String packagesincluded;

	/**
	 * Comma-separated list of packages to exclude from scan.
	 * Supports wildcards (* = any string, ? = any character).
	 * For example: 'com.example.* ,io.*.demo, com.?ello.world'.
	 *
	 * @parameter property="packagesexcluded"
	 */
	private String packagesexcluded;

	/**
	 * Use buildPullRequestSessionId feature for this build.
	 *
	 * @parameter property="createPRBuildSessionId" default-value="false"
	 */
	private boolean createPRBuildSessionId;

	/**
	 * The repository URL of the target branch.
	 *
	 * @parameter property="repositoryUrl"
	 */
	private String repositoryUrl;

	/**
	 * The number of the pull request.
	 *
	 * @parameter property="pullRequestNumber"
	 */
	private int pullRequestNumber;

	/**
	 * The head SHA of the pull request source.
	 *
	 * @parameter property="latestCommit"
	 */
	private String latestCommit;

	/**
	 * The target branch of the pull request.
	 *
	 * @parameter property="targetBranch"
	 */
	private String targetBranch;

	/**
	 * Comma-separated list of files to scan.
	 * Supports wildcards (* = any string, ? = any character).
	 * For example: 'original-*.jar ,demo?.jar'.
	 *
	 * @parameter property="filesincluded" default-value="*.class"
	 */
	private String filesincluded;

	/**
	 * Comma-separated list of files to exclude from scan.
	 * Supports wildcards (* = any string, ? = any character).
	 * For example: '*-with-dependencies.jar , bad-bad?.war, *-source.jar'.
	 *
	 * @parameter property="filesexcluded" default-value="*test-classes*"
	 */
	private String filesexcluded;

	/**
	 * Flag to start a recursive search for files to scan in the folder specified by the 'workspacepath' option.
	 *
	 * @parameter property="recursive" default-value="true"
	 */
	private boolean recursive;

	/**
	 * Flag to enable logs.
	 *
	 * @parameter property="logEnabled" default-value="true"
	 */
	private boolean logEnabled;

	/**
	 * If true, the logging from the SeaLights plugin will be restricted to minimum.
	 *
	 * @parameter property="logPluginMinimal" default-value=false
	 */
	private boolean logPluginMinimal;

	/**
	 * Log level (e.g info, debug..)
	 *
	 * @parameter property="logLevel" default-value="info"
	 */
	private String logLevel;

	/**
	 * Flag to write logs to file.
	 *
	 * @parameter property="logToFile" default-value="false"
	 */
	private boolean logToFile;

	/**
	 * Flag to write logs to file.
	 *
	 * @parameter property="logToConsole" default-value="false"
	 */
	private boolean logToConsole;

	/**
	 * Path to folder where log file will be written.
	 *
	 * @parameter property="logFolder"
	 */
	private String logFolder;

	/**
	 * Path to specific java version.
	 *
	 * @parameter property="javaPath" default-value="java"
	 */
	private String javaPath;

	/**
	 * Path to a folder where Sealights can save files.
	 *
	 * @parameter property="filesStorage"
	 */
	private String filesStorage;

	/**
	 * Meta data of the build currently executed.
	 *
	 * @parameter property="metadata"
	 */
	private Map metadata;

	/**
	 * Jvm params for testListener.
	 *
	 * @parameter property="sealightsJvmParams"
	 *
	 * */
	private Map sealightsJvmParams;

	/**
	 * Force this plugin to create the test listener in this path.
	 *
	 * @parameter property="overrideMetaJsonPath"
	 */
	private String overrideMetaJsonPath;

	/**
	 * Include token and buildSessionId files in jar.
	 *
	 * @parameter property="includeResources" default-value="false"
	 */
	private boolean includeResources;

	/**
	 * Include token file in jar.
	 *
	 * @parameter property="includeTokenResource" default-value="true"
	 */
	private boolean includeTokenResource;

    /**
     * Path to the sealights Build Scanner.
     *
     * @parameter property="buildScannerJar"
     */
	private String buildScannerJar;

    /**
     * Path to the sealights Test Listener.
     *
     * @parameter property="testListenerJar"
     */
	private String testListenerJar;

    /**
     * The testStage.
     *
     * @parameter property="testStage" default-value="Unit Tests"
     */
	private String testStage;

    /**
     * The labId.
     *
     * @parameter property="labId"
     */
	private String labId;

	/**
	 * Sets creation of a global executionId
	 * @parameter property="createExecutionId" default-value="true"
	 */
	private boolean createExecutionId;

	/**
	 * A flag to skip build-scanner
	 * @parameter property="runTestOnly" default-value="false"
	 */
	private boolean runTestOnly;

	/**
	 * A flag to skip test-listener
	 * @parameter property="runScanOnly" default-value="false"
	 */
	private boolean runScanOnly;

	/**
	 * A flag to skip build-scanner and build-session data reduced validation
	 * @parameter property="runFunctionalTests" default-value="false"
	 */
	private boolean runFunctionalTests;

	/**
	 * The Maven Session Object
	 *
	 * @parameter property="session"
	 * @required
	 * @readOnly
	 */
	private MavenSession session;

	private String sealightsPluginVersion;

	private PluginParameters params;

	public SeaLightsMojo() {
		super();
		pluginEngine = new PluginEngineHandler();
	}

	@Override
	public PluginType getPluginType() {
		return PluginType.maven;
	}

	@Override
	public String getBuildToolVersion() {
		return project.getProjectBuildingRequest().getSystemProperties().getProperty("maven.version");
	}

	@Override
	public void execute() {
		boolean goalExecutedOk = false;
		try {
			if (getExecData().getExecStage() != ExecutionStage.initFailed) {
				goalExecutedOk = executePluginGoal();
			}
		}
		catch(Exception e) {
			logger.info("Unexpected exception, failed execute {}; proceed build without Sealights", getInternalName());
		}
		finally {
			if (!goalExecutedOk) {
				logger.info("{} due to '{}' goal failure", PluginExecData.SKIP_SEALIGHTS_MSG, getMojoName());
			}
		}
	}

 	@Override
 	public String getName() {
		return getMojoName();
 	}

 	public String getInternalName() {
		return String.format("%s - project:%s, mojo:%s, session:%s", getModuleName(), getMojoName(), toStringInstanceShort(this), toStringInstanceShort(session));
 	}

	protected String toStringInstanceShort(Object instance) {
		if (instance != null) {
			String instStr = instance.toString();
			int lastDotIndex = instStr.lastIndexOf(".");
			if (lastDotIndex != -1 && lastDotIndex < instStr.length()-1) {
				String subst = instStr.substring(lastDotIndex+1);
				return subst;
			}
			else {
				return instStr;
			}
		}
		return null;
	}

	@Override
	public void initGoalInternals() {
		pluginsHandler.detectConfigurations();
		normalizeInput();
		MavenEventsListener.INSTANCE.initialize(session, this);
	}

 	@Override
 	public boolean postExecute() {
 		return true;
 	}

 	@Override
 	public void onFailure() {
        // In the jenkins plugin,
        // if the 'configuration.argLine' element inside surefire plugin is present,
        // we will add the ${argLine} variable.
        // In case sealights is disabled, we need to make sure this variable is not null so maven won't fail.
 		pluginsHandler.updateProperties(SEALIGHTS_DISABLED, getExecData().getToken(), false);
	}

	@Override
	public String getModuleName() {
		if (moduleNameArtifactId) {
			return project.getArtifactId();
		}
		else {
			return project.getName();
		}
	}

	@Override
	public ProjectDescriptor getProjectDescriptor() {
		List pluginsDeps = buildProjectPluginsData();
		List projectDeps = buildProjectDependencyData();
		return new ProjectDescriptor(
				SEALIGHTS_MAVEN_PLUGIN,
				sealightsPluginVersion,
				getModuleName(),
				project.getVersion(),
				project.getProperties(),
				project.getBuild().getSourceDirectory(),
				project.getBasedir() != null ? project.getBasedir().getAbsolutePath() : null,
				project.getBuild().getOutputDirectory(),
				projectDeps,
				pluginsDeps);
	}

	/*
	 * Implementation of BuildEndListener interface
	 */
	@Override
	public void notifyBuildEndInfo(BuildEndInfo buildEndInfo) {
		pluginEngine.notifyBuildEnd(this, buildEndInfo);
	}

	@Override
	public Logger getPluginLogger() {
		return getLogger();
	}

	public String getProjectProperty(String propKey) {
		if (project != null ) {
			return project.getProperties().getProperty(propKey);
		}

		return null;
	}

	public void setProject(MavenProject project) {
		setupLogging();

		this.pluginsHandler = MavenSessionExtension.INSTANCE.getOrCreateTestPluginsHandler(project, logger);
		this.project = project;
	}

	public void setProjectProperty(String propKey, String propValue) {
		if (project != null ) {
			project.getProperties().setProperty(propKey, propValue);
		}
	}

	public void normalizeInput() {
		normalizeLogSettings();
	}

	// A shortcut
	protected PluginExecData getExecData() {
		return BuildLifeCycle.getExecData();
	}

	protected Properties getProjectProperties() {
		return project.getProperties();
	}

	protected List buildProjectDependencyData(){
		List dependenciesData = new ArrayList<>();
		for (Dependency d: project.getDependencies()){
			dependenciesData.add(new DependencyInfo(d.getGroupId(),  d.getArtifactId(), d.getVersion()));
		}
		return dependenciesData;
	}

	protected List buildProjectPluginsData() {
		List pluginsData = new ArrayList<>();
		for (Plugin p: project.getBuildPlugins()) {
			pluginsData.add(new DependencyInfo(p.getGroupId(), p.getArtifactId(), p.getVersion()));
			if (p.getArtifactId().contains("sealights")) {
				sealightsPluginVersion = p.getVersion();
			}
		}
		return pluginsData;
	}

	public synchronized PluginParameters getParams() {
		if (params == null) {
			params = new PluginParameters();
			initParams();
		}
		return params;
	}

	protected void initParams() {
		params.getGeneralParams().setToken(token);
		params.getGeneralParams().setTokenFile(tokenFile);
		params.getGeneralParams().setCustomerId(customerid);
		params.getGeneralParams().setServer(server);
		params.getGeneralParams().setProxy(proxy);
		params.getGeneralParams().setWorkspacepath(workspacepath);
		params.getGeneralParams().setCreateBuildSessionId(createBuildSessionId);
		params.getGeneralParams().setBuildSessionId(buildSessionId);
		params.getGeneralParams().setBuildSessionIdFile(buildSessionIdFile);
		params.getGeneralParams().setAppName(appName);
		params.getGeneralParams().setEnvironment(environment);
		params.getGeneralParams().setBranch(branch);
		params.getGeneralParams().setBuild(build);
		params.getGeneralParams().setPackagesIncluded(packagesincluded);
		params.getGeneralParams().setPackagesExcluded(packagesexcluded);
		params.getGeneralParams().setCreatePRBuildSessionId(createPRBuildSessionId);
		params.getGeneralParams().setRepositoryUrl(repositoryUrl);
		params.getGeneralParams().setPullRequestNumber(pullRequestNumber);
		params.getGeneralParams().setLatestCommit(latestCommit);
		params.getGeneralParams().setTargetBranch(targetBranch);
		params.getGeneralParams().setFilesincluded(filesincluded);
		params.getGeneralParams().setFilesexcluded(filesexcluded);
		params.getGeneralParams().setRecursive(recursive);
		params.getGeneralParams().setLogEnabled(logEnabled);
		params.getGeneralParams().setLogPluginMinimal(logPluginMinimal);
		params.getGeneralParams().setLogLevel(logLevel);
		params.getGeneralParams().setLogToFile(logToFile);
		params.getGeneralParams().setLogToConsole(logToConsole);
		params.getGeneralParams().setLogFolder(logFolder);
		params.getGeneralParams().setJavaPath(javaPath);
		params.getGeneralParams().setFilesStorage(FilesStorageGoalHelper.normalizeFilesStorage(this, filesStorage));
		params.getGeneralParams().setMetadata(metadata);
		params.getGeneralParams().setSealightsJvmParams(sealightsJvmParams);
		params.getGeneralParams().setOverrideMetaJsonPath(overrideMetaJsonPath);
		params.getGeneralParams().setIncludeResources(includeResources);
		params.getGeneralParams().setIncludeTokenResource(includeTokenResource);
		params.getGeneralParams().setBuildScannerJar(buildScannerJar);
		params.getGeneralParams().setTestListenerJar(testListenerJar);
		params.getGeneralParams().setTestStage(testStage);
		params.getGeneralParams().setLabId(labId);
		params.getGeneralParams().setCreateExecutionId(createExecutionId);
		params.getGeneralParams().setRunScanOnly(runScanOnly);
		params.getGeneralParams().setRunTestOnly(runTestOnly);
		params.getGeneralParams().setRunFunctionalTests(runFunctionalTests);
	}

	private void normalizeLogSettings() {
		// Normalizing is needed due to bug in jenkins plugin:
		// 1. It does not put logEnabled into the pom, if log level is off
		// 2. it does not put Console log destination into the pom
		if (Level.OFF.equals(Level.get(logLevel))) {
			logger.info("missing 'logEnabled' parameter was set to '{}' due to logLevel '{}'", false, logLevel);
			logEnabled = false;
		}

		if (!logEnabled) {
			// Dont't care, since logs are disable
			return;
		}

		if (logToFile) {
			// Dont't care, since log destination is set to file
			return;
		}
		if (!logToConsole) {
			// Fix missed destination
			logToConsole = true;
			logger.info("missing 'logToConsole' parameter was set to '{}'", true);
		}
	}

	public void setupLogging() {
		Level level = logPluginMinimal ? Level.OFF : Level.INFO;
		LogFactory.setConsoleLogLevel(level);

		if (logger != null) {
			return;
		}

		logger = new MavenLogWrapper(getLog(), !logPluginMinimal);
		LogFactory.bindLogManager(new DefaultLogManager() {
			@Override
			public Logger getFrameworkLogger(Class clazz) {
				return logger;
			}

			@Override
			public Logger getFrameworkLogger(String name) {
				return logger;
			}
		});
	}

	@Override
	public String locateFile(String agentPathInput) {
		if (agentPathInput == null) {
			return null;
		}

		Path path = Paths.get(agentPathInput);
		if (path.isAbsolute()) {
			return agentPathInput;
		}

		MavenProject currentProject = getProject();
		while (currentProject != null) {
			String baseDirPath = currentProject.getBasedir().getPath();
			String filePathRelativizedToBaseDir = Paths.get(baseDirPath, agentPathInput).normalize().toString();
			if (new File(filePathRelativizedToBaseDir).exists()) {
				getLogger().info("agent jar found in parent dir " + filePathRelativizedToBaseDir);
				return filePathRelativizedToBaseDir;
			} 
			else {
				currentProject = currentProject.getParent();
			}
		}

		getLogger().warn("failed to resolve agent path for the input relative path " + agentPathInput);
		return null;
	}

	protected abstract boolean executePluginGoal();
	protected abstract String getMojoName();
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy