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

org.codehaus.mojo.versions.AbstractVersionsUpdaterMojo Maven / Gradle / Ivy

Go to download

Versions Plugin for Maven. The Versions Plugin updates the versions of components in the POM.

The newest version!
package org.codehaus.mojo.versions;

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF 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.
 */

import javax.inject.Inject;
import javax.xml.stream.XMLStreamException;
import javax.xml.transform.TransformerException;

import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.artifact.versioning.ArtifactVersion;
import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
import org.apache.maven.artifact.versioning.VersionRange;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecution;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.maven.wagon.Wagon;
import org.codehaus.mojo.versions.api.ArtifactVersions;
import org.codehaus.mojo.versions.api.DefaultVersionsHelper;
import org.codehaus.mojo.versions.api.PomHelper;
import org.codehaus.mojo.versions.api.Property;
import org.codehaus.mojo.versions.api.PropertyVersions;
import org.codehaus.mojo.versions.api.Segment;
import org.codehaus.mojo.versions.api.VersionRetrievalException;
import org.codehaus.mojo.versions.api.VersionsHelper;
import org.codehaus.mojo.versions.api.recording.ChangeRecorder;
import org.codehaus.mojo.versions.model.RuleSet;
import org.codehaus.mojo.versions.ordering.InvalidSegmentException;
import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader;
import org.eclipse.aether.RepositorySystem;

import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
import static java.util.Optional.ofNullable;

/**
 * Abstract base class for Versions Mojos.
 *
 * @author Stephen Connolly
 */
public abstract class AbstractVersionsUpdaterMojo extends AbstractMojo {

    // ------------------------------ FIELDS ------------------------------

    /**
     * The Maven Project.
     *
     * @since 1.0-alpha-1
     */
    @Parameter(defaultValue = "${project}", required = true, readonly = true)
    protected MavenProject project;

    /**
     * The (injected) {@link ArtifactHandlerManager} instance.
     */
    protected final ArtifactHandlerManager artifactHandlerManager;

    /**
     * The (injected) {@link org.eclipse.aether.RepositorySystem} instance.
     */
    protected RepositorySystem repositorySystem;

    /**
     * @since 1.0-alpha-1
     */
    @Parameter(defaultValue = "${reactorProjects}", required = true, readonly = true)
    protected List reactorProjects;

    /**
     * settings.xml's server id for the URL. This is used when wagon needs extra authentication information.
     *
     * @since 1.0-alpha-3
     */
    @Parameter(property = "maven.version.rules.serverId", defaultValue = "serverId")
    private String serverId;

    /**
     * URI of a ruleSet file containing the rules that control how to compare
     * version numbers. The URI could be either a Wagon URI or a classpath URI
     * (e.g. classpath:///package/sub/package/rules.xml).
     *
     * @since 1.0-alpha-3
     */
    @Parameter(property = "maven.version.rules")
    private String rulesUri;

    /**
     * Controls whether a backup pom should be created.
     *
     * @since 1.0-alpha-3
     */
    @Parameter(property = "generateBackupPoms", defaultValue = "true")
    protected boolean generateBackupPoms;

    /**
     * Whether to allow snapshots when searching for the latest version of an artifact.
     *
     * @since 1.0-alpha-1
     */
    @Parameter(property = "allowSnapshots", defaultValue = "false")
    protected boolean allowSnapshots;

    /**
     * Our versions helper.
     */
    private VersionsHelper helper;

    /**
     * The Maven Session.
     *
     * @since 1.0-alpha-1
     */
    @Parameter(defaultValue = "${session}", required = true, readonly = true)
    protected MavenSession session;

    @Parameter(defaultValue = "${mojoExecution}", required = true, readonly = true)
    private MojoExecution mojoExecution;

    /**
     * The format used to record changes. If "none" is specified, no changes are recorded.
     *
     * @since 2.11
     */
    @Parameter(property = "changeRecorderFormat", defaultValue = "none")
    private String changeRecorderFormat = "none";
    /**
     * The output file used to record changes.
     *
     * @since 2.11
     */
    @Parameter(property = "changeRecorderOutputFile", defaultValue = "${project.build.directory}/versions-changes.xml")
    private File changeRecorderOutputFile;

    /**
     * The change recorders implementation.
     */
    private Map changeRecorders;

    /**
     * 

Allows specifying the {@linkplain RuleSet} object describing rules * on artifact versions to ignore when considering updates.

* * @see * Using the ruleSet element in the POM * * @since 2.13.0 */ @Parameter protected RuleSet ruleSet; /** *

Allows specifying ignored versions directly as an alternative * to providing the {@linkplain #ruleSet} parameter; mainly created * for {@code -D} property usage.

* *

* Example: {@code "1\.0\.1,.+-M.,.*-SNAPSHOT"} *

* *

Currently, this parameter will override the defined {@link #ruleSet}

* @since 2.13.0 */ @Parameter(property = "maven.version.ignore") protected Set ignoredVersions; /** * (injected) map of {@link Wagon} instances * * @since 2.14.0 */ protected final Map wagonMap; // --------------------- GETTER / SETTER METHODS --------------------- @Inject protected AbstractVersionsUpdaterMojo( ArtifactHandlerManager artifactHandlerManager, RepositorySystem repositorySystem, Map wagonMap, Map changeRecorders) { this.artifactHandlerManager = artifactHandlerManager; this.repositorySystem = repositorySystem; this.wagonMap = wagonMap; this.changeRecorders = changeRecorders; } public VersionsHelper getHelper() throws MojoExecutionException { if (helper == null) { helper = new DefaultVersionsHelper.Builder() .withArtifactHandlerManager(artifactHandlerManager) .withRepositorySystem(repositorySystem) .withWagonMap(wagonMap) .withServerId(serverId) .withRulesUri(rulesUri) .withRuleSet(ruleSet) .withIgnoredVersions(ignoredVersions) .withLog(getLog()) .withMavenSession(session) .withMojoExecution(mojoExecution) .build(); } return helper; } /** * Getter for property 'project'. * * @return Value for property 'project'. * @since 1.0-alpha-1 */ public MavenProject getProject() { return project; } /** * Setter for property 'project'. * * @param project Value to set for property 'project'. * @since 1.0-alpha-1 */ public void setProject(MavenProject project) { this.project = project; } public String getVersion() { return getProject() == null ? null : getProject().getVersion(); } // ------------------------ INTERFACE METHODS ------------------------ // --------------------- Interface Mojo --------------------- /** * {@inheritDoc} * * @since 1.0-alpha-1 */ public void execute() throws MojoExecutionException, MojoFailureException { validateInput(); File outFile = project.getFile(); process(outFile); } // -------------------------- OTHER METHODS -------------------------- /** * Validates input parameters * * @throws MojoExecutionException thrown if any of input parameters is invalid */ protected void validateInput() throws MojoExecutionException {} /** * Finds the latest version of the specified artifact that matches the version range. * * @param artifact The artifact. * @param versionRange The version range. * @param allowingSnapshots null for no override, otherwise the local override to apply. * @param usePluginRepositories Use plugin repositories * @return The latest version of the specified artifact that matches the specified version range or * null if no matching version could be found. * @throws VersionRetrievalException If the artifact metadata could not be found. * @throws MojoExecutionException if something goes wrong. * @since 1.0-alpha-1 */ protected ArtifactVersion findLatestVersion( Artifact artifact, VersionRange versionRange, Boolean allowingSnapshots, boolean usePluginRepositories) throws MojoExecutionException, VersionRetrievalException { boolean includeSnapshots = allowingSnapshots != null ? allowingSnapshots : this.allowSnapshots; final ArtifactVersions artifactVersions = getHelper().lookupArtifactVersions(artifact, versionRange, usePluginRepositories); return artifactVersions.getNewestVersion(versionRange, null, includeSnapshots, false); } /** * Processes the specified file. This is an extension point to allow updating a file external to the reactor. * * @param outFile The file to process. * @throws MojoExecutionException If things go wrong. * @throws MojoFailureException If things go wrong. * @since 1.0-alpha-1 */ protected void process(File outFile) throws MojoExecutionException, MojoFailureException { try { MutableXMLStreamReader newPom = new MutableXMLStreamReader(outFile.toPath()); update(newPom); if (newPom.isModified()) { if (generateBackupPoms) { File backupFile = new File(outFile.getParentFile(), outFile.getName() + ".versionsBackup"); if (!backupFile.exists()) { getLog().debug("Backing up " + outFile + " to " + backupFile); Files.copy(outFile.toPath(), backupFile.toPath(), REPLACE_EXISTING); } else { getLog().debug("Leaving existing backup " + backupFile + " unmodified"); } } else { getLog().debug("Skipping generation of backup file"); } try (Writer writer = Files.newBufferedWriter( outFile.toPath(), ofNullable(newPom.getEncoding()).map(Charset::forName).orElse(Charset.defaultCharset()))) { writer.write(newPom.getSource()); } } saveChangeRecorderResults(); } catch (IOException e) { getLog().error(e); } catch (VersionRetrievalException | XMLStreamException | TransformerException e) { throw new MojoExecutionException(e.getMessage(), e); } } /** * Updates the pom. * * @param pom The pom to update. * @throws MojoExecutionException If things go wrong. * @throws MojoFailureException If things go wrong. * @throws javax.xml.stream.XMLStreamException If things go wrong. * @throws VersionRetrievalException if version retrieval goes wrong * @since 1.0-alpha-1 */ protected abstract void update(MutableXMLStreamReader pom) throws MojoExecutionException, MojoFailureException, XMLStreamException, VersionRetrievalException; /** * @param artifact The artifact. * @param currentVersion The current version of the artifact. * @param updateVersion The proposed new version of the artifact. * @return true if the update should be applied. * @since 1.0-alpha-1 * @deprecated This method no longer supported. * use shouldApplyUpdate( Artifact artifact, String currentVersion, ArtifactVersion updateVersion, Boolean * forceUpdate ) *

* Returns true if the update should be applied. */ @Deprecated protected boolean shouldApplyUpdate(Artifact artifact, String currentVersion, ArtifactVersion updateVersion) { return shouldApplyUpdate(artifact, currentVersion, updateVersion, false); } /** * Returns true if the update should be applied. * * @param artifact The artifact. * @param currentVersion The current version of the artifact. * @param updateVersion The proposed new version of the artifact. * @param forceUpdate if true, LATEST and RELEASE versions will be overwritten with the real version * @return true if the update should be applied to the pom. * @since 2.9 */ protected boolean shouldApplyUpdate( Artifact artifact, String currentVersion, ArtifactVersion updateVersion, boolean forceUpdate) { getLog().debug("Proposal is to update from " + currentVersion + " to " + updateVersion); if (updateVersion == null) { getLog().warn("Not updating version: could not resolve any versions"); return false; } if (forceUpdate) { getLog().info("Force update enabled. LATEST or RELEASE versions will be overwritten with real version"); return true; } artifact.setVersion(updateVersion.toString()); try { getHelper().resolveArtifact(artifact, false); } catch (ArtifactResolutionException | MojoExecutionException e) { getLog().warn("Not updating version: could not resolve " + artifact, e); return false; } if (currentVersion.equals(updateVersion.toString())) { getLog().info("Current version of " + artifact + " is the latest."); return false; } return true; } /** * Attempts to update the property to a newer version, if that exists * @param pom pom to update * @param property property to update * @param version {@link PropertyVersions} object * @param currentVersion current version * @param allowDowngrade if downgrades should be allowed if snapshots are not allowed * @param unchangedSegment most major segment not to be changed * @return new version of the artifact, if the property was updated; {@code null} if there was no update * @throws XMLStreamException thrown from {@link MutableXMLStreamReader} if the update doesn't succeed * @throws InvalidVersionSpecificationException thrown if {@code unchangedSegment} doesn't match the version * @throws InvalidSegmentException thrown if {@code unchangedSegment} is invalid * @throws MojoExecutionException thrown if any other error occurs */ protected ArtifactVersion updatePropertyToNewestVersion( MutableXMLStreamReader pom, Property property, PropertyVersions version, String currentVersion, boolean allowDowngrade, Optional unchangedSegment) throws XMLStreamException, InvalidVersionSpecificationException, InvalidSegmentException, MojoExecutionException { ArtifactVersion winner = version.getNewestVersion( currentVersion, property, this.allowSnapshots, this.reactorProjects, this.getHelper(), allowDowngrade, unchangedSegment); if (winner == null || currentVersion.equals(winner.toString())) { getLog().info("Property ${" + property.getName() + "}: Leaving unchanged as " + currentVersion); } else if (PomHelper.setPropertyVersion(pom, version.getProfileId(), property.getName(), winner.toString())) { getLog().info("Updated ${" + property.getName() + "} from " + currentVersion + " to " + winner); return winner; } return null; } /** * Configure and return the change recorder. * * @return The change recorder * @throws MojoExecutionException if something goes wrong. */ protected ChangeRecorder getChangeRecorder() throws MojoExecutionException { ChangeRecorder changeRecorder = changeRecorders.get(changeRecorderFormat); if (changeRecorder == null) { throw new MojoExecutionException( "Only " + changeRecorders.keySet() + " formats are supported for change recordings"); } return changeRecorder; } /** * Save all of the changes recorded by the change recorder. * * @throws IOException On I/O errors * @throws MojoExecutionException if something goes wrong. */ protected void saveChangeRecorderResults() throws IOException, MojoExecutionException { this.getLog().debug("writing change record to " + this.changeRecorderOutputFile); getChangeRecorder() .writeReport( ofNullable(changeRecorderOutputFile).map(File::toPath).orElse(null)); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy