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

de.smartics.maven.plugin.buildmetadata.BuildMetaDataMojo Maven / Gradle / Ivy

/*
 * Copyright 2006-2019 smartics, Kronseder & Reiner GmbH
 *
 * 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.
 */
package de.smartics.maven.plugin.buildmetadata;

import de.smartics.maven.plugin.buildmetadata.common.Constant;
import de.smartics.maven.plugin.buildmetadata.common.ScmControl;
import de.smartics.maven.plugin.buildmetadata.common.ScmCredentials;
import de.smartics.maven.plugin.buildmetadata.common.ScmInfo;
import de.smartics.maven.plugin.buildmetadata.data.HostMetaDataProvider;
import de.smartics.maven.plugin.buildmetadata.data.MavenMetaDataProvider;
import de.smartics.maven.plugin.buildmetadata.data.MavenMetaDataSelection;
import de.smartics.maven.plugin.buildmetadata.data.ScmMetaDataProvider;
import de.smartics.maven.plugin.buildmetadata.io.AdditionalLocationsSupport;
import de.smartics.maven.plugin.buildmetadata.io.BuildPropertiesFileHelper;
import de.smartics.maven.plugin.buildmetadata.io.BuildXmlFileHelper;
import de.smartics.maven.plugin.buildmetadata.maven.MavenPluginProperties;
import de.smartics.maven.plugin.buildmetadata.scm.ScmNoRevisionException;
import de.smartics.maven.plugin.buildmetadata.util.FilePathNormalizer;

import org.apache.maven.artifact.versioning.ArtifactVersion;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.scm.ScmBranch;
import org.apache.maven.scm.manager.ScmManager;
import org.apache.maven.settings.Settings;
import org.codehaus.plexus.util.StringUtils;

import java.io.File;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Properties;

/**
 * Provides the build properties. This information is also written to a
 * build.properties file.
 *
 * @goal provide-buildmetadata
 * @phase initialize
 * @requiresProject
 * @threadSafe
 * @since 1.0
 * @description Provides a build meta data to the build process.
 */
public final class BuildMetaDataMojo extends AbstractBuildMojo {
  // ********************************* Fields *********************************

  // --- constants ------------------------------------------------------------

  // --- members --------------------------------------------------------------

  // ... Mojo infrastructure ..................................................

  /**
   * The user's settings.
   *
   * @parameter expression="${settings}"
   * @required
   * @readonly
   * @since 1.0
   */
  private Settings settings;

  /**
   * If set to true, build properties will be generate even if they
   * already exist in the target folder.
   *
   * @parameter default-value="false"
   * @since 1.0
   */
  private boolean forceNewProperties;

  /**
   * In offline mode the plugin will not generate revision information.
   *
   * @parameter default-value="${settings.offline}"
   * @required
   * @readonly
   * @since 1.0
   */
  private boolean offline;

  /**
   * Add SCM information if set to true, skip it, if set to
   * false. If you are not interested in SCM information, set this
   * to false.
   * 

* For security reasons you may want to remove the properties file from the * META-INF folder. Please refer to propertiesOutputFile * property. *

* * @parameter expression="${buildMetaData.addScmInfo}" default-value="true" * @since 1.0 */ private boolean addScmInfo; /** * Fail if revision is requested to be retrieved, access to SCM is provided, * system is online, nothing should prevent the build from fetching the * information. *

* If set to true the build will fail, if revision cannot be * fetched under the conditions mentioned above. If set to false * the build will continue silently so that the meta data do not contain the * revision. *

* * @parameter expression="${buildMetaData.failOnMissingRevision}" * default-value="false" * @since 1.0 */ private boolean failOnMissingRevision; /** * Add host information if set to true, skip it, if set to * false. If you are not interested in host information (e.g. for * security reasons), set this to false. *

* For security reasons you may want to remove the properties file from the * META-INF folder. Please refer to propertiesOutputFile * property. *

* * @parameter expression="${buildMetaData.addHostInfo}" default-value="true" * @since 1.0 */ private boolean addHostInfo; /** * Add environment variables if set to true, skip it, if set to * false. If you are not interested in the environment variables * of the host (e.g. for security reasons), set this to false. *

* For security reasons you may want to remove the properties file from the * META-INF folder. Please refer to propertiesOutputFile * property. *

* * @parameter expression="${buildMetaData.addEnvInfo}" default-value="false" * @since 1.0 */ private boolean addEnvInfo; /** * Add information about the Java runtime running the build if set to * true, skip it, if set to false. * * @parameter expression="${buildMetaData.addJavaRuntimeInfo}" * default-value="true" * @since 1.0 */ private boolean addJavaRuntimeInfo; /** * Add information about the operating system the build is run in if set to * true, skip it, if set to false. * * @parameter expression="${buildMetaData.addOsInfo}" default-value="true" * @since 1.0 */ private boolean addOsInfo; /** * Add Maven execution information (all properties starting with * build.maven.execution, like command line, goals, profiles, * etc.) if set to true, skip it, if set to false. * If you are not interested in execution information, set this to * false. *

* For security reasons you may want to remove the properties file from the * META-INF folder. Please refer to propertiesOutputFile * property. *

* * @parameter expression="${buildMetaData.addMavenExecutionInfo}" * default-value="true" * @since 1.0 */ private boolean addMavenExecutionInfo; /** * Add project information (homepage URL, categories, tags, etc.) if set to * true, skip it, if set to false. If you are not * interested in execution information, set this to false. * * @parameter expression="${buildMetaData.addProjectInfo}" * default-value="false" * @since 1.1 */ private boolean addProjectInfo; /** * While the command line may be useful to refer to for a couple of reasons, * displaying it with the build properties is a security issue. Some plugins * allow to read passwords as properties from the command line and this * sensible data will be shown. *

* Therefore the command line is hidden by default (true). If you * want to include this information, use a value of false. *

* * @parameter expression="${buildMetaData.hideCommandLineInfo}" * default-value="true" * @since 1.0 */ private boolean hideCommandLineInfo; /** * While the MAVEN_OPTS may be useful to refer to for a couple of * reasons, displaying them with the build properties is a security issue. * Some plugins allow to read passwords as properties from the command line * and this sensible data will be shown. *

* Therefore the MAVEN_OPTS are hidden by default ( * true). If you want to include this information, use a value of * false. *

*

* This exclusion does not prevent the property from being written as part of * addEnvInfo! *

* * @parameter expression="${buildMetaData.hideMavenOptsInfo}" * default-value="true" * @since 1.0 */ private boolean hideMavenOptsInfo; /** * While the JAVA_OPTS may be useful to refer to for a couple of * reasons, displaying them with the build properties is a security issue. * Some plugins allow to read passwords as properties from the command line * and this sensible data will be shown. *

* Therefore the JAVA_OPTS are hidden by default ( * true). If you want to include this information, use a value of * false. *

*

* This exclusion does not prevent the property from being written as part of * addEnvInfo! *

* * @parameter expression="${buildMetaData.hideJavaOptsInfo}" * default-value="true" * @since 1.0 */ private boolean hideJavaOptsInfo; /** * If it should be checked if the local files are up-to-date with the remote * files in the SCM repository. If the value is true the result * of the check, including the list of changed files, is added to the build * meta data. * * @parameter expression="${buildMetaData.validateCheckout}" * default-value="true" * @since 1.0 */ private boolean validateCheckout; /** * The manager instance to access the SCM system. Provides access to the * repository and the provider information. * * @component * @since 1.0 */ private ScmManager scmManager; /** * Allows the user to choose which scm connection to use when connecting to * the scm. Can either be "connection" or "developerConnection". * * @parameter default-value="connection" * @required * @since 1.0 */ private String connectionType; // ... core information ..................................................... /** * The date pattern to use to format the build and revision dates. Please * refer to the * SimpleDateFormat class for valid patterns. * * @parameter expression="${buildMetaData.buildDate.pattern}" * default-value="dd.MM.yyyy" * @since 1.0 */ protected String buildDatePattern = Constant.DEFAULT_DATE_PATTERN; // NOPMD /** * The pattern to use to format the timestamp dates. Please refer to the * * SimpleDateFormat class for valid patterns. * * @parameter expression="${buildMetaData.timestamp.pattern}" * default-value="yyyyMMdd.HHmmss" * @since 1.7 */ protected String buildTimestampPattern = Constant.DEFAULT_TIMESTAMP_PATTERN; // NOPMD /** * The property to query for the build user. * * @parameter default-value="username" * @since 1.0 */ private String buildUserPropertyName; // ... build information related ............................................ /** * Flag to add the build date to the full version separated by a '-'. If * true the build date is added, if false it is not. * * @parameter expression="${buildMetaData.addBuildDateToFullVersion}" * default-value="true" * @since 1.0 */ private boolean addBuildDateToFullVersion; // ... svn related .......................................................... /** * Used to specify the date format of the log entries that are retrieved from * your SCM system. * * @parameter expression="${changelog.dateFormat}" default-value= * "yyyy-MM-dd HH:mm:ss" * @required * @since 1.0 */ private String scmDateFormat; /** * Input dir. Directory where the files under SCM control are located. * * @parameter expression="${basedir}" * @required * @since 1.0 */ private File basedir; /** * The user name (used by svn and starteam protocol). * * @parameter expression="${username}" * @since 1.0 */ private String userName; /** * The user password (used by svn and starteam protocol). * * @parameter expression="${password}" * @since 1.0 */ private String password; /** * The private key (used by java svn). * * @parameter expression="${privateKey}" * @since 1.0 */ private String privateKey; /** * The passphrase (used by java svn). * * @parameter expression="${passphrase}" * @since 1.0 */ private String passphrase; /** * The url of tags base directory (used by svn protocol). * * @parameter expression="${tagBase}" * @since 1.0 */ private String tagBase; /** * Flag to add the revision number to the full version separated by an 'r'. If * true the revision number is added, if false it is * not. * * @parameter expression="${buildMetaData.addReleaseNumberToFullVersion}" * default-value="true" * @since 1.0 */ private boolean addReleaseNumberToFullVersion; /** * Flag to add the tag -locally-modified to the full version * string to make visible that this artifact has been created with locally * modified sources. This is often the case while the artifact is built while * still working on an issue before it is committed to the SCM repository. * * @parameter expression="${buildMetaData.addLocallyModifiedTagToFullVersion}" * default-value="true" * @since 1.0 */ private boolean addLocallyModifiedTagToFullVersion; /** * The range of the query in days to fetch change log entries from the SCM. If * no change logs have been found, the range is incremented up to * {@value de.smartics.maven.plugin.buildmetadata.scm.maven.ScmAccessInfo#DEFAULT_RETRY_COUNT} * (5) times. If no change log has been found after these * {@value de.smartics.maven.plugin.buildmetadata.scm.maven.ScmAccessInfo#DEFAULT_RETRY_COUNT} * (5) additional queries, the revision number will not be set with a valid * value. * * @parameter expression="${buildMetaData.queryRangeInDays}" * default-value="30" * @since 1.0 */ private int queryRangeInDays; /** * Flag to fail if local modifications have been found. The value is * true if the build should fail if there are modifications (any * files not in-sync with the remote repository), false if the * fact is only to be noted in the build properties. * * @parameter default-value="false" * @since 1.0 */ private boolean failOnLocalModifications; /** * The flag to ignore files and directories starting with a dot for checking * modified files. This implicates that any files or directories, starting * with a dot, are ignored when the check on changed files is run. If the * value is true, dot files are ignored, if it is set to * false, dot files are respected. * * @parameter default-value="true" * @since 1.0 */ private boolean ignoreDotFilesInBaseDir; /** * Flag to copy build report files to the generated-sources * folder, if the Maven sources plugin is configured. * * @parameter default-value="true" * @since 1.5.0 */ private boolean addToGeneratedSources; /** * The list of locations the report files are to be copied to. If it is not * absolute, the subfolder META-INF is appended. * * @parameter * @since 1.5.0 */ private List addToLocations; // ****************************** Initializer ******************************* // ****************************** Constructors ****************************** // ****************************** Inner Classes ***************************** // ********************************* Methods ******************************** // --- init ----------------------------------------------------------------- // --- get&set -------------------------------------------------------------- // --- business ------------------------------------------------------------- @Override public void execute() throws MojoExecutionException, MojoFailureException { if (!doSkip()) { super.execute(); final String baseDir = project.getBasedir().getAbsolutePath(); final FilePathNormalizer filePathNormalizer = new FilePathNormalizer(baseDir); final BuildPropertiesFileHelper helper = new BuildPropertiesFileHelper( getLog(), propertiesOutputFile, filePathNormalizer); final Properties projectProperties = helper.getProjectProperties(project); if (!isBuildPropertiesAlreadySet(projectProperties)) { final Properties buildMetaDataProperties = new Properties(); if (isBuildPropertiesToBeRebuild()) { createBuildProperties(helper, projectProperties, buildMetaDataProperties); } else { getLog().info("Reusing previously built metadata file."); helper.readBuildPropertiesFile(buildMetaDataProperties); } updateMavenEnvironment(buildMetaDataProperties, helper); } } else { getLog().info("Skipping buildmetadata collection since skip=true."); } } private void createBuildProperties(final BuildPropertiesFileHelper helper, final Properties projectProperties, final Properties buildMetaDataProperties) throws MojoExecutionException, MojoFailureException { final Date buildDate = session.getStartTime(); provideBuildUser(projectProperties, buildMetaDataProperties); provideMavenMetaData(buildMetaDataProperties); provideHostMetaData(buildMetaDataProperties); final ScmInfo scmInfo = provideScmMetaData(buildMetaDataProperties); provideBuildDateMetaData(buildMetaDataProperties, buildDate); providePluginMetaData(buildMetaDataProperties); // The custom providers are required to be run at the end. // This allows these providers to access the information generated // by the built-in providers. provideBuildMetaData(buildMetaDataProperties, scmInfo, providers, false); writeBuildMetaData(helper, buildMetaDataProperties); } private void providePluginMetaData(Properties buildMetaDataProperties) { final MavenPluginProperties helper = new MavenPluginProperties(project); for (final PluginSelector selector : getPluginSelectors()) { final Properties pluginProperties = helper.fetchProperties(selector); buildMetaDataProperties.putAll(pluginProperties); } } private void writeBuildMetaData(final BuildPropertiesFileHelper helper, final Properties buildMetaDataProperties) throws MojoExecutionException { final File propertiesFile = helper.writePropertiesFile(buildMetaDataProperties); final AdditionalLocationsSupport.Config config = new AdditionalLocationsSupport.Config(); config.setAddToGeneratedSources(addToGeneratedSources) .setAddToLocations(addToLocations); final AdditionalLocationsSupport additionalLocations = new AdditionalLocationsSupport(project, config); additionalLocations.handle(propertiesFile); final boolean writable = !writeProtectFiles; propertiesFile.setWritable(writable); if (createXmlReport) { final String projectRootPath = project.getBasedir().getAbsolutePath(); final BuildXmlFileHelper xmlHelper = new BuildXmlFileHelper( projectRootPath, getLog(), xmlOutputFile, properties); final File xmlFile = xmlHelper.writeXmlFile(buildMetaDataProperties); additionalLocations.handle(xmlFile); xmlFile.setWritable(writable); } } private void provideMavenMetaData(final Properties buildMetaDataProperties) { final MavenMetaDataSelection selection = new MavenMetaDataSelection(); selection.setAddMavenExecutionInfo(addMavenExecutionInfo); selection.setAddEnvInfo(addEnvInfo); selection.setAddJavaRuntimeInfo(addJavaRuntimeInfo); selection.setAddOsInfo(addOsInfo); selection.setAddProjectInfo(addProjectInfo); selection.setHideCommandLineInfo(hideCommandLineInfo); selection.setHideJavaOptsInfo(hideJavaOptsInfo); selection.setHideMavenOptsInfo(hideMavenOptsInfo); selection.setSelectedSystemProperties(properties); final MavenMetaDataProvider mavenMetaDataProvider = new MavenMetaDataProvider(project, session, runtime, selection); mavenMetaDataProvider.provideBuildMetaData(buildMetaDataProperties); } private ScmInfo provideScmMetaData(final Properties buildMetaDataProperties) throws MojoFailureException { try { final ScmInfo scmInfo = createScmInfo(); final ScmMetaDataProvider scmMetaDataProvider = new ScmMetaDataProvider(project, scmInfo); scmMetaDataProvider.provideBuildMetaData(buildMetaDataProperties); return scmInfo; } catch (final ScmNoRevisionException e) { throw new MojoFailureException(e.getMessage()); // NOPMD } } private void provideHostMetaData(final Properties buildMetaDataProperties) throws MojoExecutionException { if (addHostInfo) { final HostMetaDataProvider hostMetaData = new HostMetaDataProvider(); hostMetaData.provideBuildMetaData(buildMetaDataProperties); } } private void provideBuildDateMetaData( final Properties buildMetaDataProperties, final Date buildDate) { final String buildDateString = createBuildDate(buildMetaDataProperties, buildDate); createYears(buildMetaDataProperties, buildDate); createBuildVersion(buildMetaDataProperties, buildDate, buildDateString); } private ScmInfo createScmInfo() { final ScmCredentials scmCredentials = new ScmCredentials(settingsDecrypter, settings, userName, password, privateKey, passphrase); final ScmControl scmControl = new ScmControl(failOnLocalModifications, ignoreDotFilesInBaseDir, offline, addScmInfo, validateCheckout, failOnMissingRevision); final ScmInfo scmInfo = new ScmInfo(scmManager, connectionType, scmDateFormat, basedir, scmCredentials, tagBase, queryRangeInDays, buildDatePattern, scmControl, StringUtils.isNotBlank(remoteVersion) ? new ScmBranch(remoteVersion) : null); return scmInfo; } private boolean isBuildPropertiesToBeRebuild() { return forceNewProperties || !propertiesOutputFile.exists(); } private boolean isBuildPropertiesAlreadySet( final Properties projectProperties) { return projectProperties .getProperty(Constant.PROP_NAME_FULL_VERSION) != null; } /** * Provides the name of the user running the build. The value is either * specified in the project properties or is taken from the Java system * properties (user.name). * * @param projectProperties the project properties. * @param buildMetaDataProperties the build meta data properties. */ private void provideBuildUser(final Properties projectProperties, final Properties buildMetaDataProperties) { String userNameValue = System.getProperty("user.name"); if ((buildUserPropertyName != null)) { final String value = projectProperties.getProperty(buildUserPropertyName); if (!StringUtils.isBlank(value)) { userNameValue = value; } } if (userNameValue != null) { buildMetaDataProperties.setProperty(Constant.PROP_NAME_BUILD_USER, userNameValue); } } /** * Creates and adds the build date information. * * @param buildMetaDataProperties the build meta data properties. * @param buildDate the date of the build. * @return the formatted build date. */ private String createBuildDate(final Properties buildMetaDataProperties, final Date buildDate) { final DateFormat format = new SimpleDateFormat(buildDatePattern, Locale.ENGLISH); final String buildDateString = format.format(buildDate); final String timestamp = String.valueOf(buildDate.getTime()); buildMetaDataProperties.setProperty(Constant.PROP_NAME_BUILD_DATE, buildDateString); buildMetaDataProperties.setProperty(Constant.PROP_NAME_BUILD_DATE_PATTERN, this.buildDatePattern); buildMetaDataProperties.setProperty(Constant.PROP_NAME_BUILD_TIMESTAMP, timestamp); final DateFormat formatTs = new SimpleDateFormat(buildTimestampPattern, Locale.ENGLISH); buildMetaDataProperties.setProperty( Constant.PROP_NAME_BUILD_TIMESTAMP_PATTERN, buildTimestampPattern); final String buildTimestampString = formatTs.format(buildDate); buildMetaDataProperties.setProperty( Constant.PROP_NAME_BUILD_TIMESTAMP_CUSTOM, buildTimestampString); return buildDateString; } /** * Adds the build and copyright year information. * * @param buildMetaDataProperties the build meta data properties. * @param buildDate the build date to create the build year information. */ private void createYears(final Properties buildMetaDataProperties, final Date buildDate) { final DateFormat yearFormat = new SimpleDateFormat("yyyy", Locale.ENGLISH); final String buildYearString = yearFormat.format(buildDate); buildMetaDataProperties.setProperty(Constant.PROP_NAME_BUILD_YEAR, buildYearString); final String inceptionYearString = project.getInceptionYear(); final String copyrightYearString = (inceptionYearString == null ? buildYearString : (buildYearString.equals(inceptionYearString) ? inceptionYearString : inceptionYearString + '-' + buildYearString)); buildMetaDataProperties.setProperty(Constant.PROP_NAME_COPYRIGHT_YEAR, copyrightYearString); } /** * Adds the version information of the artifact. * * @param buildMetaDataProperties the build meta data properties. * @param buildDate the date of the build. * @param buildDateString the formatted date string. */ private void createBuildVersion(final Properties buildMetaDataProperties, final Date buildDate, final String buildDateString) { final String version = project.getVersion(); buildMetaDataProperties.setProperty(Constant.PROP_NAME_VERSION, version); buildMetaDataProperties.setProperty(Constant.PROP_NAME_GROUP_ID, project.getGroupId()); buildMetaDataProperties.setProperty(Constant.PROP_NAME_ARTIFACT_ID, project.getArtifactId()); buildMetaDataProperties.setProperty(Constant.PROP_NAME_BUILD_DATE, buildDateString); final ArtifactVersion artifactVersion = new DefaultArtifactVersion(version); buildMetaDataProperties.setProperty(Constant.PROP_NAME_VERSION_MAJOR, String.valueOf(artifactVersion.getMajorVersion())); buildMetaDataProperties.setProperty(Constant.PROP_NAME_VERSION_MINOR, String.valueOf(artifactVersion.getMinorVersion())); buildMetaDataProperties.setProperty(Constant.PROP_NAME_VERSION_MICRO, String.valueOf(artifactVersion.getIncrementalVersion())); buildMetaDataProperties.setProperty(Constant.PROP_NAME_VERSION_BUILDNUMBER, String.valueOf(artifactVersion.getBuildNumber())); final String qualifier = artifactVersion.getQualifier(); if (qualifier != null) { buildMetaDataProperties.setProperty(Constant.PROP_NAME_VERSION_QUALIFIER, qualifier); } final String fullVersion = createFullVersion(buildMetaDataProperties, buildDate); buildMetaDataProperties.setProperty(Constant.PROP_NAME_FULL_VERSION, fullVersion); } /** * Creates the full version string which may include the date, the build, and * the revision. * * @param buildMetaDataProperties the generated build meta data properties. * @param buildDate the date of the current build. * @return the full version string. */ private String createFullVersion(final Properties buildMetaDataProperties, final Date buildDate) { final String version = project.getVersion(); final DateFormat format = new SimpleDateFormat("yyyyMMddHHmmss", Locale.ENGLISH); final String datePart = format.format(buildDate); final String revisionId = buildMetaDataProperties.getProperty(Constant.PROP_NAME_SCM_REVISION_ID); final String versionPrefix; final String versionSuffix; if (version.endsWith("-SNAPSHOT")) { versionPrefix = version.substring(0, version.lastIndexOf('-')); versionSuffix = "-SNAPSHOT"; } else { versionPrefix = version; versionSuffix = ""; } final String modified; if (addLocallyModifiedTagToFullVersion && "true".equals(buildMetaDataProperties .getProperty(Constant.PROP_NAME_SCM_LOCALLY_MODIFIED))) { modified = "-locally-modified"; } else { modified = ""; } final String fullVersion = versionPrefix + (addBuildDateToFullVersion ? '-' + datePart : "") + (addReleaseNumberToFullVersion && StringUtils.isNotBlank(revisionId) ? "r" + revisionId : "") + modified + versionSuffix; return fullVersion; } // --- object basics -------------------------------------------------------- }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy