You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by gn...@apache.org on 2026/09/15 09:53:40 UTC

(maven) branch master updated: Externalize default lifecycle plugin versions to POM properties (#13080)

This is an automated email from the ASF dual-hosted git repository.

gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven.git


The following commit(s) were added to refs/heads/master by this push:
     new a58de000b9 Externalize default lifecycle plugin versions to POM properties (#13080)
a58de000b9 is described below

commit a58de000b9ac556d6cfac368ed8014df24852b81
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Tue Sep 15 11:53:33 2026 +0200

    Externalize default lifecycle plugin versions to POM properties (#13080)
    
    Move the 13 hardcoded plugin version constants from Java source into
    POM properties in impl/maven-core/pom.xml. The values are filtered at
    build time into plugin-versions.properties and loaded at runtime by a
    new PluginVersions utility class.
    
    This makes the default lifecycle plugin versions visible to
    dependency-update bots (Dependabot, Renovate) that scan POM files for
    version properties, enabling automated version bump PRs.
    
    No behavioral change: all version values are identical to the previous
    hardcoded constants.
---
 impl/maven-core/pom.xml                            | 88 ++++++++++++++++++++++
 .../internal/impl/DefaultLifecycleRegistry.java    |  5 +-
 .../org/apache/maven/lifecycle/PluginVersions.java | 81 ++++++++++++++++++++
 .../AbstractLifecycleMappingProvider.java          | 45 ++++++++---
 .../maven/lifecycle/plugin-versions.properties     | 35 +++++++++
 .../apache/maven/lifecycle/PluginVersionsTest.java | 54 +++++++++++++
 6 files changed, 295 insertions(+), 13 deletions(-)

diff --git a/impl/maven-core/pom.xml b/impl/maven-core/pom.xml
index 07ffa6662b..fe8f6d10de 100644
--- a/impl/maven-core/pom.xml
+++ b/impl/maven-core/pom.xml
@@ -31,6 +31,26 @@ under the License.
   <name>Maven 4 Core</name>
   <description>Maven Core classes.</description>
 
+  <properties>
+    <!-- Default lifecycle plugin versions.
+         Maintained here so that dependency-update bots (Dependabot, Renovate)
+         can propose version bumps automatically.  Values are filtered into
+         plugin-versions.properties at build time and loaded at runtime. -->
+    <version.maven-clean-plugin>3.4.0</version.maven-clean-plugin>
+    <version.maven-compiler-plugin>3.13.0</version.maven-compiler-plugin>
+    <version.maven-deploy-plugin>3.1.3</version.maven-deploy-plugin>
+    <version.maven-ear-plugin>3.3.0</version.maven-ear-plugin>
+    <version.maven-ejb-plugin>3.2.1</version.maven-ejb-plugin>
+    <version.maven-install-plugin>3.1.3</version.maven-install-plugin>
+    <version.maven-jar-plugin>3.4.2</version.maven-jar-plugin>
+    <version.maven-plugin-plugin>3.15.1</version.maven-plugin-plugin>
+    <version.maven-rar-plugin>3.0.0</version.maven-rar-plugin>
+    <version.maven-resources-plugin>3.3.1</version.maven-resources-plugin>
+    <version.maven-site-plugin>3.21.0</version.maven-site-plugin>
+    <version.maven-surefire-plugin>3.5.2</version.maven-surefire-plugin>
+    <version.maven-war-plugin>3.4.0</version.maven-war-plugin>
+  </properties>
+
   <dependencies>
     <!--  Maven4 API -->
     <dependency>
@@ -260,6 +280,74 @@ under the License.
     </resources>
     <pluginManagement>
       <plugins>
+        <!-- Default lifecycle plugins declared here so that dependency-update bots
+             (Dependabot, Renovate) see the version.maven-*-plugin properties as
+             actual plugin version references and can propose automated bumps. -->
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-clean-plugin</artifactId>
+          <version>${version.maven-clean-plugin}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-compiler-plugin</artifactId>
+          <version>${version.maven-compiler-plugin}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-deploy-plugin</artifactId>
+          <version>${version.maven-deploy-plugin}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-ear-plugin</artifactId>
+          <version>${version.maven-ear-plugin}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-ejb-plugin</artifactId>
+          <version>${version.maven-ejb-plugin}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-install-plugin</artifactId>
+          <version>${version.maven-install-plugin}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-jar-plugin</artifactId>
+          <version>${version.maven-jar-plugin}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-plugin-plugin</artifactId>
+          <version>${version.maven-plugin-plugin}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-rar-plugin</artifactId>
+          <version>${version.maven-rar-plugin}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-resources-plugin</artifactId>
+          <version>${version.maven-resources-plugin}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-site-plugin</artifactId>
+          <version>${version.maven-site-plugin}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-surefire-plugin</artifactId>
+          <version>${version.maven-surefire-plugin}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-war-plugin</artifactId>
+          <version>${version.maven-war-plugin}</version>
+        </plugin>
         <plugin>
           <groupId>org.apache.rat</groupId>
           <artifactId>apache-rat-plugin</artifactId>
diff --git a/impl/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLifecycleRegistry.java b/impl/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLifecycleRegistry.java
index c2006cb732..39e0c77d12 100644
--- a/impl/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLifecycleRegistry.java
+++ b/impl/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLifecycleRegistry.java
@@ -46,6 +46,7 @@
 import org.apache.maven.api.services.LookupException;
 import org.apache.maven.api.spi.ExtensibleEnumProvider;
 import org.apache.maven.api.spi.LifecycleProvider;
+import org.apache.maven.lifecycle.PluginVersions;
 import org.apache.maven.lifecycle.mapping.LifecyclePhase;
 import org.codehaus.plexus.PlexusContainer;
 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
@@ -416,7 +417,7 @@ static class SiteLifecycleProvider extends BaseLifecycleProvider {
 
     static class CleanLifecycle implements Lifecycle {
 
-        private static final String MAVEN_CLEAN_PLUGIN_VERSION = "3.4.0";
+        private static final String MAVEN_CLEAN_PLUGIN_VERSION = PluginVersions.CLEAN;
 
         @Override
         public String id() {
@@ -529,7 +530,7 @@ public Collection<Alias> aliases() {
 
     static class SiteLifecycle implements Lifecycle {
 
-        private static final String MAVEN_SITE_PLUGIN_VERSION = "3.21.0";
+        private static final String MAVEN_SITE_PLUGIN_VERSION = PluginVersions.SITE;
         private static final String MAVEN_SITE_PLUGIN =
                 MAVEN_PLUGINS + "maven-site-plugin:" + MAVEN_SITE_PLUGIN_VERSION + ":";
         private static final String PHASE_SITE = "site";
diff --git a/impl/maven-core/src/main/java/org/apache/maven/lifecycle/PluginVersions.java b/impl/maven-core/src/main/java/org/apache/maven/lifecycle/PluginVersions.java
new file mode 100644
index 0000000000..0a1e4a7ee9
--- /dev/null
+++ b/impl/maven-core/src/main/java/org/apache/maven/lifecycle/PluginVersions.java
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+package org.apache.maven.lifecycle;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+/**
+ * Provides default plugin versions for the built-in lifecycle bindings.
+ * <p>
+ * Versions are read from {@code plugin-versions.properties}, which is filtered
+ * at build time from POM properties ({@code version.maven-<name>-plugin}).
+ * Centralising them in the POM makes them visible to dependency-update bots
+ * such as Dependabot and Renovate.
+ *
+ * @since 4.1.0
+ */
+public final class PluginVersions {
+
+    private static final Properties VERSIONS = new Properties();
+
+    static {
+        try (InputStream in = PluginVersions.class.getResourceAsStream("plugin-versions.properties")) {
+            if (in == null) {
+                throw new ExceptionInInitializerError("plugin-versions.properties not found on classpath");
+            }
+            VERSIONS.load(in);
+        } catch (IOException e) {
+            throw new ExceptionInInitializerError(e);
+        }
+    }
+
+    private PluginVersions() {}
+
+    private static String version(String pluginArtifactId) {
+        String key = "version." + pluginArtifactId;
+        String version = VERSIONS.getProperty(key);
+        if (version == null) {
+            throw new IllegalArgumentException("No default version defined for " + pluginArtifactId + "; add " + key
+                    + " to plugin-versions.properties");
+        }
+        if (version.startsWith("${")) {
+            throw new ExceptionInInitializerError("plugin-versions.properties was not filtered at build time; " + key
+                    + " still contains placeholder: " + version);
+        }
+        return version;
+    }
+
+    // --- convenience constants used by lifecycle mapping providers ---
+
+    public static final String CLEAN = version("maven-clean-plugin");
+    public static final String COMPILER = version("maven-compiler-plugin");
+    public static final String DEPLOY = version("maven-deploy-plugin");
+    public static final String EAR = version("maven-ear-plugin");
+    public static final String EJB = version("maven-ejb-plugin");
+    public static final String INSTALL = version("maven-install-plugin");
+    public static final String JAR = version("maven-jar-plugin");
+    public static final String PLUGIN = version("maven-plugin-plugin");
+    public static final String RAR = version("maven-rar-plugin");
+    public static final String RESOURCES = version("maven-resources-plugin");
+    public static final String SITE = version("maven-site-plugin");
+    public static final String SUREFIRE = version("maven-surefire-plugin");
+    public static final String WAR = version("maven-war-plugin");
+}
diff --git a/impl/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/AbstractLifecycleMappingProvider.java b/impl/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/AbstractLifecycleMappingProvider.java
index ed841bcccd..3802905b43 100644
--- a/impl/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/AbstractLifecycleMappingProvider.java
+++ b/impl/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/AbstractLifecycleMappingProvider.java
@@ -23,6 +23,7 @@
 import java.util.Collections;
 import java.util.HashMap;
 
+import org.apache.maven.lifecycle.PluginVersions;
 import org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping;
 import org.apache.maven.lifecycle.mapping.Lifecycle;
 import org.apache.maven.lifecycle.mapping.LifecycleMapping;
@@ -35,29 +36,51 @@
  */
 public abstract class AbstractLifecycleMappingProvider implements Provider<LifecycleMapping> {
     // START SNIPPET: versions
-    protected static final String RESOURCES_PLUGIN_VERSION = "3.3.1";
+    /** @deprecated Use {@link PluginVersions#RESOURCES} instead. */
+    @Deprecated(since = "4.1.0", forRemoval = true)
+    protected static final String RESOURCES_PLUGIN_VERSION = PluginVersions.RESOURCES;
 
-    protected static final String COMPILER_PLUGIN_VERSION = "3.13.0";
+    /** @deprecated Use {@link PluginVersions#COMPILER} instead. */
+    @Deprecated(since = "4.1.0", forRemoval = true)
+    protected static final String COMPILER_PLUGIN_VERSION = PluginVersions.COMPILER;
 
-    protected static final String SUREFIRE_PLUGIN_VERSION = "3.5.2";
+    /** @deprecated Use {@link PluginVersions#SUREFIRE} instead. */
+    @Deprecated(since = "4.1.0", forRemoval = true)
+    protected static final String SUREFIRE_PLUGIN_VERSION = PluginVersions.SUREFIRE;
 
-    protected static final String INSTALL_PLUGIN_VERSION = "3.1.3";
+    /** @deprecated Use {@link PluginVersions#INSTALL} instead. */
+    @Deprecated(since = "4.1.0", forRemoval = true)
+    protected static final String INSTALL_PLUGIN_VERSION = PluginVersions.INSTALL;
 
-    protected static final String DEPLOY_PLUGIN_VERSION = "3.1.3";
+    /** @deprecated Use {@link PluginVersions#DEPLOY} instead. */
+    @Deprecated(since = "4.1.0", forRemoval = true)
+    protected static final String DEPLOY_PLUGIN_VERSION = PluginVersions.DEPLOY;
 
     // packaging
 
-    protected static final String JAR_PLUGIN_VERSION = "3.4.2";
+    /** @deprecated Use {@link PluginVersions#JAR} instead. */
+    @Deprecated(since = "4.1.0", forRemoval = true)
+    protected static final String JAR_PLUGIN_VERSION = PluginVersions.JAR;
 
-    protected static final String EAR_PLUGIN_VERSION = "3.3.0";
+    /** @deprecated Use {@link PluginVersions#EAR} instead. */
+    @Deprecated(since = "4.1.0", forRemoval = true)
+    protected static final String EAR_PLUGIN_VERSION = PluginVersions.EAR;
 
-    protected static final String EJB_PLUGIN_VERSION = "3.2.1";
+    /** @deprecated Use {@link PluginVersions#EJB} instead. */
+    @Deprecated(since = "4.1.0", forRemoval = true)
+    protected static final String EJB_PLUGIN_VERSION = PluginVersions.EJB;
 
-    protected static final String PLUGIN_PLUGIN_VERSION = "3.15.1";
+    /** @deprecated Use {@link PluginVersions#PLUGIN} instead. */
+    @Deprecated(since = "4.1.0", forRemoval = true)
+    protected static final String PLUGIN_PLUGIN_VERSION = PluginVersions.PLUGIN;
 
-    protected static final String RAR_PLUGIN_VERSION = "3.0.0";
+    /** @deprecated Use {@link PluginVersions#RAR} instead. */
+    @Deprecated(since = "4.1.0", forRemoval = true)
+    protected static final String RAR_PLUGIN_VERSION = PluginVersions.RAR;
 
-    protected static final String WAR_PLUGIN_VERSION = "3.4.0";
+    /** @deprecated Use {@link PluginVersions#WAR} instead. */
+    @Deprecated(since = "4.1.0", forRemoval = true)
+    protected static final String WAR_PLUGIN_VERSION = PluginVersions.WAR;
     // END SNIPPET: versions
 
     private final LifecycleMapping lifecycleMapping;
diff --git a/impl/maven-core/src/main/resources/org/apache/maven/lifecycle/plugin-versions.properties b/impl/maven-core/src/main/resources/org/apache/maven/lifecycle/plugin-versions.properties
new file mode 100644
index 0000000000..701d8a30fc
--- /dev/null
+++ b/impl/maven-core/src/main/resources/org/apache/maven/lifecycle/plugin-versions.properties
@@ -0,0 +1,35 @@
+# 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.
+
+# Default lifecycle plugin versions.
+# Values are substituted by Maven resource filtering at build time from
+# POM properties (version.maven-<name>-plugin), making them visible to
+# dependency-update bots such as Dependabot and Renovate.
+
+version.maven-clean-plugin=${version.maven-clean-plugin}
+version.maven-compiler-plugin=${version.maven-compiler-plugin}
+version.maven-deploy-plugin=${version.maven-deploy-plugin}
+version.maven-ear-plugin=${version.maven-ear-plugin}
+version.maven-ejb-plugin=${version.maven-ejb-plugin}
+version.maven-install-plugin=${version.maven-install-plugin}
+version.maven-jar-plugin=${version.maven-jar-plugin}
+version.maven-plugin-plugin=${version.maven-plugin-plugin}
+version.maven-rar-plugin=${version.maven-rar-plugin}
+version.maven-resources-plugin=${version.maven-resources-plugin}
+version.maven-site-plugin=${version.maven-site-plugin}
+version.maven-surefire-plugin=${version.maven-surefire-plugin}
+version.maven-war-plugin=${version.maven-war-plugin}
diff --git a/impl/maven-core/src/test/java/org/apache/maven/lifecycle/PluginVersionsTest.java b/impl/maven-core/src/test/java/org/apache/maven/lifecycle/PluginVersionsTest.java
new file mode 100644
index 0000000000..0f28b90297
--- /dev/null
+++ b/impl/maven-core/src/test/java/org/apache/maven/lifecycle/PluginVersionsTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+package org.apache.maven.lifecycle;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Verifies that {@link PluginVersions} constants are properly loaded
+ * from the filtered {@code plugin-versions.properties} resource.
+ */
+class PluginVersionsTest {
+
+    @Test
+    void allConstantsAreResolvedAndNotPlaceholders() throws Exception {
+        int count = 0;
+        for (Field field : PluginVersions.class.getFields()) {
+            if (field.getType() == String.class
+                    && Modifier.isStatic(field.getModifiers())
+                    && Modifier.isFinal(field.getModifiers())) {
+                String value = (String) field.get(null);
+                assertNotNull(value, field.getName() + " is null");
+                assertFalse(value.startsWith("${"), field.getName() + " contains unfiltered placeholder: " + value);
+                assertFalse(value.isEmpty(), field.getName() + " is empty");
+                count++;
+            }
+        }
+        // Ensure we actually tested something — catches the case where
+        // all constants are accidentally removed or made non-public.
+        assertTrue(count >= 13, "Expected at least 13 plugin version constants, found " + count);
+    }
+}