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

org.openrewrite.maven.ConfigurableRewriteMojo Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2021 the original author or authors.
 *
 * 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
 *
 * https://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 org.openrewrite.maven;

import com.puppycrawl.tools.checkstyle.Checker;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Plugin;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.codehaus.plexus.util.xml.pull.MXSerializer;
import org.intellij.lang.annotations.Language;
import org.jspecify.annotations.Nullable;
import org.openrewrite.config.Environment;
import org.openrewrite.style.NamedStyles;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;

import static java.util.Collections.emptyMap;
import static java.util.Collections.unmodifiableSet;
import static java.util.stream.Collectors.toCollection;
import static org.openrewrite.java.style.CheckstyleConfigLoader.loadCheckstyleConfig;

@SuppressWarnings("FieldMayBeFinal")
public abstract class ConfigurableRewriteMojo extends AbstractMojo {

    private static final String CHECKSTYLE_DOCTYPE = "module PUBLIC " +
                                                     "\"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN\" " +
                                                     "\"https://checkstyle.org/dtds/configuration_1_3.dtd\"";

    @Parameter(property = "rewrite.configLocation", alias = "configLocation", defaultValue = "${maven.multiModuleProjectDirectory}/rewrite.yml")
    protected String configLocation;

    @Nullable
    @Parameter(property = "rewrite.activeRecipes")
    protected LinkedHashSet activeRecipes;

    @Nullable
    @Parameter(property = "rewrite.activeStyles")
    protected LinkedHashSet activeStyles;

    @Nullable
    @Parameter(property = "rewrite.metricsUri", alias = "metricsUri")
    protected String metricsUri;

    @Nullable
    @Parameter(property = "rewrite.metricsUsername", alias = "metricsUsername")
    protected String metricsUsername;

    @Nullable
    @Parameter(property = "rewrite.metricsPassword", alias = "metricsPassword")
    protected String metricsPassword;

    @Parameter(property = "rewrite.pomCacheEnabled", alias = "pomCacheEnabled", defaultValue = "true")
    protected boolean pomCacheEnabled;

    @Nullable
    @Parameter(property = "rewrite.pomCacheDirectory", alias = "pomCacheDirectory")
    protected String pomCacheDirectory;

    @Parameter(property = "rewrite.skip", defaultValue = "false")
    protected boolean rewriteSkip;

    /**
     * When enabled, skip parsing Maven `pom.xml`s, and any transitive poms, as source files.
     * This can be an efficiency improvement in certain situations.
     */
    @Parameter(property = "skipMavenParsing", defaultValue = "false")
    protected boolean skipMavenParsing;

    @Nullable
    @Parameter(property = "rewrite.checkstyleConfigFile", alias = "checkstyleConfigFile")
    protected String checkstyleConfigFile;

    @Nullable
    @Parameter(property = "rewrite.checkstyleDetectionEnabled", alias = "checkstyleDetectionEnabled", defaultValue = "true")
    protected boolean checkstyleDetectionEnabled;

    @Nullable
    @Parameter(property = "rewrite.exclusions")
    private LinkedHashSet exclusions;

    protected Set getExclusions() {
        return getCleanedSet(exclusions);
    }

    /**
     * Override default plain text masks. If this is specified,
     * {@code rewrite.additionalPlainTextMasks} will have no effect.
     */
    @Nullable
    @Parameter(property = "rewrite.plainTextMasks")
    private LinkedHashSet plainTextMasks;

    /**
     * Allows to add additional plain text masks without overriding
     * the defaults.
     */
    @Nullable
    @Parameter(property = "rewrite.additionalPlainTextMasks")
    private LinkedHashSet additionalPlainTextMasks;

    protected Set getPlainTextMasks() {
        Set masks = getCleanedSet(plainTextMasks);
        if (!masks.isEmpty()) {
            return masks;
        }
        //If not defined, use a default set of masks
        masks = new HashSet<>(Arrays.asList(
                "**/*.adoc",
                "**/*.aj",
                "**/*.bash",
                "**/*.bat",
                "**/CODEOWNERS",
                "**/*.css",
                "**/*.config",
                "**/Dockerfile*",
                "**/*.env",
                "**/.gitattributes",
                "**/.gitignore",
                "**/*.htm*",
                "**/gradlew",
                "**/.java-version",
                "**/*.jsp",
                "**/*.ksh",
                "**/lombok.config",
                "**/*.md",
                "**/*.mf",
                "**/META-INF/services/**",
                "**/META-INF/spring/**",
                "**/META-INF/spring.factories",
                "**/mvnw",
                "**/mvnw.cmd",
                "**/*.qute.java",
                "**/.sdkmanrc",
                "**/*.sh",
                "**/*.sql",
                "**/*.svg",
                "**/*.tsx",
                "**/*.txt",
                "**/*.py"
        ));
        masks.addAll(getCleanedSet(additionalPlainTextMasks));
        return unmodifiableSet(masks);
    }

    @Nullable
    @Parameter(property = "sizeThresholdMb", defaultValue = "10")
    protected int sizeThresholdMb;

    /**
     * Whether to throw an exception if an activeRecipe fails configuration validation.
     * This may happen if the activeRecipe is improperly configured, or any downstream recipes are improperly configured.
     * 

* For the time, this default is "false" to prevent one improperly recipe from failing the build. * In the future, this default may be changed to "true" to be more restrictive. */ @Parameter(property = "rewrite.failOnInvalidActiveRecipes", alias = "failOnInvalidActiveRecipes", defaultValue = "false") protected boolean failOnInvalidActiveRecipes; @Parameter(property = "rewrite.runPerSubmodule", alias = "runPerSubmodule", defaultValue = "false") protected boolean runPerSubmodule; @Parameter(defaultValue = "${session}", readonly = true) protected MavenSession mavenSession; @Parameter(defaultValue = "${plugin}", required = true, readonly = true) protected PluginDescriptor pluginDescriptor; protected enum State { SKIPPED, PROCESSED, TO_BE_PROCESSED } private static final String OPENREWRITE_PROCESSED_MARKER = "openrewrite.processed"; protected void putState(State state) { getPluginContext().put(OPENREWRITE_PROCESSED_MARKER, state.name()); } private boolean hasState(MavenProject project) { Map pluginContext = mavenSession.getPluginContext(pluginDescriptor, project); return pluginContext.containsKey(OPENREWRITE_PROCESSED_MARKER); } protected boolean allProjectsMarked() { return mavenSession.getProjects().stream().allMatch(this::hasState); } @Nullable @Parameter(property = "rewrite.recipeArtifactCoordinates") private LinkedHashSet recipeArtifactCoordinates; @Nullable private volatile Set computedRecipes; @Nullable private volatile Set computedStyles; @Nullable private volatile Set computedRecipeArtifactCoordinates; protected Set getActiveRecipes() { if (computedRecipes == null) { synchronized (this) { if (computedRecipes == null) { computedRecipes = getCleanedSet(activeRecipes); } } } //noinspection ConstantConditions return computedRecipes; } protected Set getActiveStyles() { if (computedStyles == null) { synchronized (this) { if (computedStyles == null) { computedStyles = getCleanedSet(activeStyles); } } } //noinspection ConstantConditions return computedStyles; } protected List loadStyles(MavenProject project, Environment env) { List styles = env.activateStyles(getActiveStyles()); try { Plugin checkstylePlugin = project.getPlugin("org.apache.maven.plugins:maven-checkstyle-plugin"); if (checkstyleConfigFile != null && !checkstyleConfigFile.isEmpty()) { styles.add(loadCheckstyleConfig(Paths.get(checkstyleConfigFile), emptyMap())); } else if (checkstyleDetectionEnabled && checkstylePlugin != null) { Object checkstyleConfRaw = checkstylePlugin.getConfiguration(); if (checkstyleConfRaw instanceof Xpp3Dom) { Xpp3Dom xmlCheckstyleConf = (Xpp3Dom) checkstyleConfRaw; Xpp3Dom xmlConfigLocation = xmlCheckstyleConf.getChild("configLocation"); Xpp3Dom xmlCheckstyleRules = xmlCheckstyleConf.getChild("checkstyleRules"); if (xmlConfigLocation != null) { // resolve location against plugin location (could be in parent pom) Path configPath = Paths.get(checkstylePlugin.getLocation("").getSource().getLocation()) .resolveSibling(xmlConfigLocation.getValue()); if (configPath.toFile().exists()) { styles.add(loadCheckstyleConfig(configPath, emptyMap())); } } else if (xmlCheckstyleRules != null && xmlCheckstyleRules.getChildCount() > 0) { styles.add(loadCheckstyleConfig(toCheckStyleDocument(xmlCheckstyleRules.getChild(0)), emptyMap())); } else { // When no config location is specified, the maven-checkstyle-plugin falls back on sun_checks.xml try (InputStream is = Checker.class.getResourceAsStream("/sun_checks.xml")) { if (is != null) { styles.add(loadCheckstyleConfig(is, emptyMap())); } } } } } } catch (Exception e) { getLog().warn("Unable to parse checkstyle configuration. Checkstyle will not inform rewrite execution.", e); } return styles; } private @Language("XML") String toCheckStyleDocument(final Xpp3Dom dom) throws IOException { StringWriter stringWriter = new StringWriter(); MXSerializer serializer = new MXSerializer(); serializer.setOutput(stringWriter); serializer.docdecl(CHECKSTYLE_DOCTYPE); dom.writeToSerializer("", serializer); return stringWriter.toString(); } protected Set getRecipeArtifactCoordinates() { if (computedRecipeArtifactCoordinates == null) { synchronized (this) { if (computedRecipeArtifactCoordinates == null) { computedRecipeArtifactCoordinates = getCleanedSet(recipeArtifactCoordinates); } } } //noinspection ConstantConditions return computedRecipeArtifactCoordinates; } private static Set getCleanedSet(@Nullable Set<@Nullable String> set) { if (set == null) { return Collections.emptySet(); } Set cleaned = set.stream() .filter(Objects::nonNull) .map(String::trim) .filter(s -> !s.isEmpty()) .collect(toCollection(LinkedHashSet::new)); return unmodifiableSet(cleaned); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy