Skip to content

Commit

Permalink
[MNG-8052] New lifecycle for Maven 4 (#1448)
Browse files Browse the repository at this point in the history
  • Loading branch information
gnodet authored Aug 29, 2024
1 parent 9bc5cc8 commit acec540
Show file tree
Hide file tree
Showing 24 changed files with 1,001 additions and 110 deletions.
124 changes: 121 additions & 3 deletions api/maven-api-core/src/main/java/org/apache/maven/api/Lifecycle.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.annotations.Immutable;
import org.apache.maven.api.annotations.Nonnull;
import org.apache.maven.api.model.Plugin;

/**
Expand All @@ -41,14 +43,20 @@
@Immutable
public interface Lifecycle extends ExtensibleEnum {

// =========================
// Maven defined lifecycles
// =========================
String CLEAN = "clean";

String DEFAULT = "default";

String SITE = "site";

String WRAPPER = "wrapper";

// ======================
// Phase qualifiers
// ======================
String BEFORE = "before:";
String AFTER = "after:";

/**
* Name or identifier of this lifecycle.
*
Expand All @@ -62,6 +70,18 @@ public interface Lifecycle extends ExtensibleEnum {
*/
Collection<Phase> phases();

/**
* Stream of phases containing all child phases recursively.
*/
default Stream<Phase> allPhases() {
return phases().stream().flatMap(Phase::allPhases);
}

/**
* Collection of aliases.
*/
Collection<Alias> aliases();

/**
* Pre-ordered list of phases.
* If not provided, a default order will be computed.
Expand All @@ -72,10 +92,108 @@ default Optional<List<String>> orderedPhases() {

/**
* A phase in the lifecycle.
*
* A phase is identified by its name. It also contains a list of plugins bound to that phase,
* a list of {@link Link links}, and a list of sub-phases. This forms a tree of phases.
*/
interface Phase {

// ======================
// Maven defined phases
// ======================
String BUILD = "build";
String INITIALIZE = "initialize";
String VALIDATE = "validate";
String SOURCES = "sources";
String RESOURCES = "resources";
String COMPILE = "compile";
String READY = "ready";
String PACKAGE = "package";
String VERIFY = "verify";
String UNIT_TEST = "unit-test";
String TEST_SOURCES = "test-sources";
String TEST_RESOURCES = "test-resources";
String TEST_COMPILE = "test-compile";
String TEST = "test";
String INTEGRATION_TEST = "integration-test";
String INSTALL = "install";
String DEPLOY = "deploy";
String CLEAN = "clean";

@Nonnull
String name();

@Nonnull
List<Plugin> plugins();

@Nonnull
Collection<Link> links();

/**
* {@return the list of sub-phases}
*/
@Nonnull
List<Phase> phases();

@Nonnull
Stream<Phase> allPhases();
}

/**
* A phase alias, mostly used to support the Maven 3 phases which are mapped
* to dynamic phases in Maven 4.
*/
interface Alias {
String v3Phase();

String v4Phase();
}

/**
* A link from a phase to another phase, consisting of a type which can be
* {@link Kind#BEFORE} or {@link Kind#AFTER}, and a {@link Pointer} to
* another phase.
*/
interface Link {
enum Kind {
BEFORE,
AFTER
}

Kind kind();

Pointer pointer();
}

interface Pointer {
enum Type {
PROJECT,
DEPENDENCIES,
CHILDREN
}

String phase();

Type type();
}

interface PhasePointer extends Pointer {
default Type type() {
return Type.PROJECT;
}
}

interface DependenciesPointer extends Pointer {
String scope(); // default: all

default Type type() {
return Type.DEPENDENCIES;
}
}

interface ChildrenPointer extends Pointer {
default Type type() {
return Type.CHILDREN;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* 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.api.plugin.annotations;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.apache.maven.api.annotations.Experimental;

/**
* Specifies that the mojo should be run after the specific phase.
*
* @since 4.0.0
*/
@Experimental
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
public @interface After {

/**
* Type of pointer.
* @see org.apache.maven.api.Lifecycle.Pointer.Type
*/
enum Type {
PROJECT,
DEPENDENCIES,
CHILDREN
}

/**
* The phase name.
*/
String phase();

/**
* The type of this pointer.
*/
Type type();

/**
* The scope for dependencies, only if {@code type() == Type.Dependencies}.
*/
String scope() default "";
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/
package org.apache.maven.api.services;

import java.util.List;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

Expand All @@ -28,4 +29,6 @@ public interface LifecycleRegistry extends ExtensibleEnumRegistry<Lifecycle>, It
default Stream<Lifecycle> stream() {
return StreamSupport.stream(spliterator(), false);
}

List<String> computePhases(Lifecycle lifecycle);
}
2 changes: 1 addition & 1 deletion api/maven-api-plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ under the License.
<phase>generate-sources</phase>
<configuration>
<velocityBasedir>${project.basedir}/../../src/mdo</velocityBasedir>
<version>1.0.0</version>
<version>2.0.0</version>
<models>
<model>src/main/mdo/lifecycle.mdo</model>
</models>
Expand Down
67 changes: 54 additions & 13 deletions api/maven-api-plugin/src/main/mdo/lifecycle.mdo
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ under the License.
<classes>
<class rootElement="true" xml.tagName="lifecycles" xsd.compositor="sequence">
<name>LifecycleConfiguration</name>
<version>1.0.0</version>
<version>1.0.0+</version>
<description>Root element of the {@code lifecycle.xml} file.</description>
<fields>
<field>
<name>lifecycles</name>
<version>1.0.0</version>
<version>1.0.0+</version>
<association xml.itemsStyle="flat">
<type>Lifecycle</type>
<multiplicity>*</multiplicity>
Expand All @@ -45,19 +45,19 @@ under the License.
</class>
<class>
<name>Lifecycle</name>
<version>1.0.0</version>
<version>1.0.0+</version>
<description>A custom lifecycle mapping definition.</description>
<fields>
<field>
<name>id</name>
<required>true</required>
<version>1.0.0</version>
<version>1.0.0+</version>
<type>String</type>
<description>The ID of this lifecycle, for identification in the mojo descriptor.</description>
</field>
<field>
<name>phases</name>
<version>1.0.0</version>
<version>1.0.0+</version>
<description>The phase mappings for this lifecycle.</description>
<association>
<type>Phase</type>
Expand All @@ -68,19 +68,35 @@ under the License.
</class>
<class>
<name>Phase</name>
<version>1.0.0</version>
<version>1.0.0+</version>
<description>A phase mapping definition.</description>
<fields>
<field>
<name>id</name>
<required>true</required>
<version>1.0.0</version>
<version>1.0.0+</version>
<type>String</type>
<description>The ID of this phase, e.g., &lt;code&gt;generate-sources&lt;/code&gt;.</description>
<description>The ID of this phase, e.g., {@code generate-sources}.</description>
</field>
<field xml.attribute="true">
<name>executionPoint</name>
<required>false</required>
<version>2.0.0+</version>
<type>String</type>
<defaultValue><![CDATA[]]></defaultValue>
<description><![CDATA[If specified, identifies this phase as a dynamic phase to decorate the specified phase id, e.g. {@code after} or {@code before}.]]></description>
</field>
<field xml.attribute="true">
<name>priority</name>
<required>false</required>
<version>2.0.0+</version>
<type>int</type>
<defaultValue>0</defaultValue>
<description>If specified, identifies a within phase prioritization of executions.</description>
</field>
<field>
<name>executions</name>
<version>1.0.0</version>
<version>1.0.0+</version>
<description>The goals to execute within the phase.</description>
<association>
<type>Execution</type>
Expand All @@ -89,26 +105,51 @@ under the License.
</field>
<field>
<name>configuration</name>
<version>1.0.0</version>
<version>1.0.0+</version>
<type>DOM</type>
<description>Configuration to pass to all goals run in this phase.</description>
</field>
</fields>
<codeSegments>
<codeSegment>
<version>2.0.0+</version>
<code><![CDATA[
/**
* Get the effective ID of this phase, e.g.,
* {@code generate-sources} or {@code after:integration-test[1000]}.
*
* @return String
*/
public String getEffectiveId() {
if (executionPoint == null) {
if (priority == 0) {
return id;
}
return id + '[' + priority + ']';
}
if (priority == 0) {
return executionPoint + ':' + id;
}
return executionPoint + ':' + id + '[' + priority + ']';
}
]]></code>
</codeSegment>
</codeSegments>
</class>
<class>
<name>Execution</name>
<version>1.0.0</version>
<version>1.0.0+</version>
<description>A set of goals to execute.</description>
<fields>
<field>
<name>configuration</name>
<version>1.0.0</version>
<version>1.0.0+</version>
<type>DOM</type>
<description>Configuration to pass to the goals.</description>
</field>
<field>
<name>goals</name>
<version>1.0.0</version>
<version>1.0.0+</version>
<description>The goals to execute.</description>
<association>
<type>String</type>
Expand Down
Loading

0 comments on commit acec540

Please sign in to comment.