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

org.technologybrewery.habushu.AbstractHabushuMojo Maven / Gradle / Ivy

Go to download

Leverages Poetry and Pyenv to provide an automated, predictable order of execution of build commands that apply DevOps and configuration management best practices

There is a newer version: 2.17.0
Show newest version
package org.technologybrewery.habushu;

import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;

import org.apache.commons.lang3.StringUtils;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.maven.settings.Settings;
import org.technologybrewery.habushu.exec.PoetryCommandHelper;
import org.technologybrewery.habushu.exec.PyenvCommandHelper;

/**
 * Contains logic common across the various Habushu mojos.
 */
public abstract class AbstractHabushuMojo extends AbstractMojo {

    protected static final String SNAPSHOT = "-SNAPSHOT";

    /**
     * The current Maven user's settings, pulled dynamically from their settings.xml
     * file.
     */
    @Parameter(defaultValue = "${settings}", readonly = true, required = true)
    protected Settings settings;

    /**
     * Folder in which Python source files are located - should align with Poetry's
     * project structure conventions.
     */
    @Parameter(property = "habushu.sourceDirectory", required = true, defaultValue = "${project.basedir}/src")
    protected File sourceDirectory;

    /**
     * Folder in which Python test files are located - should align with Poetry's
     * project structure conventions.
     */
    @Parameter(property = "habushu.testDirectory", required = true, defaultValue = "${project.basedir}/tests")
    protected File testDirectory;

    /**
     * Specifies the {@code } of the {@code } element declared within
     * the utilized settings.xml configuration that represents the desired
     * credentials to use when publishing the package to the official public PyPI
     * repository.
     */
    protected static final String PUBLIC_PYPI_REPO_ID = "pypi";

    /**
     * Specifies the {@code } of the {@code } element declared within
     * the utilized settings.xml configuration that represents the PyPI repository
     * to which this project's archives will be published and/or used as a secondary
     * repository from which dependencies may be installed. This property is
     * REQUIRED if publishing to or consuming dependencies from a private
     * PyPI repository that requires authentication - it is expected that the
     * relevant {@code } element provides the needed authentication details.
     * If this property is *not* specified, this property will default to
     * {@link #PUBLIC_PYPI_REPO_ID} and the execution of the {@code deploy}
     * lifecycle phase will publish this package to the official public PyPI
     * repository. Downstream package publishing functionality (i.e.
     * {@link PublishToPyPiRepoMojo}) will use the relevant settings.xml
     * {@code } declaration with a matching {@code } as credentials for
     * publishing the package to the official public PyPI repository.
     */
    @Parameter(property = "habushu.pypiRepoId", defaultValue = PUBLIC_PYPI_REPO_ID)
    protected String pypiRepoId;

    /**
     * Specifies the URL of the private PyPI repository to which this project's
     * archives will be published and/or used as a secondary repository from which
     * dependencies may be installed. This property is REQUIRED if publishing
     * to or consuming dependencies from a private PyPI repository.
     */
    @Parameter(property = "habushu.pypiRepoUrl")
    protected String pypiRepoUrl;

    /**
     * Specifies whether the version of the encapsulated Poetry package should be
     * automatically managed and overridden where necessary by Habushu. If this
     * property is true, Habushu may override the pyproject.toml defined version in
     * the following build phases/mojos:
     * 
    *
  • validate ({@link ValidatePyenvAndPoetryMojo}): Automatically sets the * Poetry package version to the version specified in the POM. If the POM is a * SNAPSHOT, the Poetry package version will be set to the corresponding * developmental release version without a numeric component (i.e. POM version * of {@code 1.2.3-SNAPSHOT} will result in the Poetry package version being set * to {@code 1.2.3.dev}).
  • *
  • deploy ({@link PublishToPyPiRepoMojo}): Automatically sets the version of * published Poetry packages that are SNAPSHOT modules to timestamped * developmental release versions (i.e. POM version of {@code 1.2.3-SNAPSHOT} * will result in the published Poetry package version to to * {@code 1.2.3.dev1658238063}). After the package is published, the version of * the SNAPSHOT module is reverted to its previous value (i.e. * {@code 1.2.3.dev}).
  • *
* If {@link #overridePackageVersion} is set to false, none of the above * automated version management operations will be performed. */ @Parameter(defaultValue = "true", property = "habushu.overridePackageVersion") protected boolean overridePackageVersion; /** * Enables access to the runtime properties associated with the project's POM * configuration against which Habushu is being executed. */ @Parameter(defaultValue = "${project}", readonly = true, required = true) protected MavenProject project; /** * Indicates whether Habushu should leverage the * {@code poetry-monorepo-dependency-plugin} to rewrite any local path * dependencies (to other Poetry projects) as versioned packaged dependencies in * generated wheel/sdist archives. If {@code true}, Habushu will replace * invocations of Poetry's {@code build} and {@code publish} commands in the * {@link BuildDeploymentArtifactsMojo} and {@link PublishToPyPiRepoMojo} with * the extensions of those commands exposed by the * {@code poetry monorepo-dependency-plugin}, which are * {@code build-rewrite-path-deps} and {@code publish-rewrite-path-deps} * respectively. *

* Typically, this flag will only be {@code true} when deploying/releasing * Habushu modules within a CI environment that are part of a monorepo project * structure which multiple Poetry projects depend on one another. */ @Parameter(defaultValue = "false", property = "habushu.rewriteLocalPathDepsInArchives") protected boolean rewriteLocalPathDepsInArchives; /** * Gets the canonical path for a file without having to deal w/ checked * exceptions. * * @param file file for which to get the canonical format * @return canonical format */ protected String getCanonicalPathForFile(File file) { try { return file.getCanonicalPath(); } catch (IOException ioe) { throw new HabushuException("Could not access file: " + file.getName(), ioe); } } /** * Creates a {@link PyenvCommandHelper} that may be used to invoke Pyenv * commands from the project's working directory. * * @return */ protected PyenvCommandHelper createPyenvCommandHelper() { return new PyenvCommandHelper(getPoetryProjectBaseDir()); } /** * Creates a {@link PoetryCommandHelper} that may be used to invoke Poetry * commands from the project's working directory. * * @return */ protected PoetryCommandHelper createPoetryCommandHelper() { return new PoetryCommandHelper(getPoetryProjectBaseDir()); } /** * Base directory in which Poetry projects will be located - should always be * the basedir of the encapsulating Maven project. */ protected File getPoetryProjectBaseDir() { return this.project.getBasedir(); } /** * Returns a {@link File} representing this project's Poetry pyproject.toml * configuration. * * @return */ protected File getPoetryPyProjectTomlFile() { return new File(getPoetryProjectBaseDir(), "pyproject.toml"); } /** * Gets the PEP-440 compliant Python package version associated with the given * POM version. *

* If the provided POM version is a SNAPSHOT, the version is converted into its * corresponding developmental release version, with its numeric component * optionally included based on the given {@code addSnapshotNumber} and * {@code snapshotNumberDateFormatPattern} parameters. For example, given the * POM version of {@code 1.2.3-SNAPSHOT}, a Python package version of * {@code 1.2.3.dev} will be returned if {@code addSnapshotNumber} is false. If * {@code addSnapshotNumber} is true, the numeric component will be added and * defaults to the number of seconds from the epoch (i.e. * {@code 1.2.3.dev1658238063}). The format of the snapshot number may be * modified by providing a date format pattern (i.e. "YYYYMMddHHmm" would yield * {@code 1.2.3.dev202207191002}) *

* If the provided POM version is a release version, it is expected to align * with a valid PEP-440 final release version and is returned unmodified. * * @param pomVersion POM version of the encapsulating module in which Habushu is * being executed. * @return version number of the encapsulated Python package, appropriately * formatted by the given parameters. */ protected String getPythonPackageVersion(String pomVersion, boolean addSnapshotNumber, String snapshotNumberDateFormatPattern) { String pythonPackageVersion = pomVersion; if (isPomVersionSnapshot(pomVersion)) { pythonPackageVersion = replaceSnapshotWithDev(pomVersion); if (addSnapshotNumber) { String snapshotNumber; LocalDateTime currentTime = LocalDateTime.now(); if (StringUtils.isNotEmpty(snapshotNumberDateFormatPattern)) { snapshotNumber = currentTime.format(DateTimeFormatter.ofPattern(snapshotNumberDateFormatPattern)); } else { snapshotNumber = String.valueOf(currentTime.toEpochSecond(ZoneOffset.UTC)); } pythonPackageVersion += snapshotNumber; } } return pythonPackageVersion; } protected static String replaceSnapshotWithDev(String pomVersion) { return pomVersion.substring(0, pomVersion.indexOf(SNAPSHOT)) + ".dev"; } /** * Returns whether the given POM version is a SNAPSHOT version. * * @param pomVersion * @return */ protected boolean isPomVersionSnapshot(String pomVersion) { return pomVersion.endsWith(SNAPSHOT); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy