|
2 | 2 |
|
3 | 3 | import com.e_gineering.maven.gitflowhelper.properties.PropertyResolver;
|
4 | 4 | import org.apache.maven.AbstractMavenLifecycleParticipant;
|
| 5 | +import org.apache.maven.Maven; |
5 | 6 | import org.apache.maven.MavenExecutionException;
|
6 | 7 | import org.apache.maven.artifact.Artifact;
|
7 | 8 | import org.apache.maven.artifact.versioning.VersionRange;
|
| 9 | +import org.apache.maven.execution.DefaultMavenExecutionRequest; |
| 10 | +import org.apache.maven.execution.MavenExecutionRequest; |
| 11 | +import org.apache.maven.execution.MavenExecutionResult; |
8 | 12 | import org.apache.maven.execution.MavenSession;
|
9 | 13 | import org.apache.maven.model.Dependency;
|
10 | 14 | import org.apache.maven.model.Model;
|
11 | 15 | import org.apache.maven.model.Parent;
|
12 | 16 | import org.apache.maven.model.Plugin;
|
13 | 17 | import org.apache.maven.model.ReportPlugin;
|
14 | 18 | import org.apache.maven.model.io.ModelWriter;
|
| 19 | +import org.apache.maven.plugin.LegacySupport; |
15 | 20 | import org.apache.maven.project.MavenProject;
|
16 | 21 | import org.codehaus.plexus.component.annotations.Component;
|
17 | 22 | import org.codehaus.plexus.component.annotations.Requirement;
|
18 | 23 |
|
19 | 24 | import java.io.File;
|
20 | 25 | import java.io.IOException;
|
21 | 26 | import java.util.HashMap;
|
| 27 | +import java.util.List; |
22 | 28 | import java.util.Map;
|
23 | 29 |
|
24 | 30 | @Component(role = AbstractMavenLifecycleParticipant.class, hint = "other-branch-version")
|
25 | 31 | public class OtherBranchVersionExtension extends AbstractBranchDetectingExtension {
|
26 | 32 |
|
27 | 33 | @Requirement(role = ModelWriter.class)
|
28 | 34 | ModelWriter modelWriter;
|
| 35 | + |
| 36 | + @Requirement(role = Maven.class) |
| 37 | + Maven maven; |
| 38 | + |
| 39 | + @Requirement(role = LegacySupport.class) |
| 40 | + LegacySupport legacySupport; |
29 | 41 |
|
30 | 42 | private static final int ORIGINAL_VERSION_IDX = 0;
|
31 | 43 | private static final int ADJUSTED_VERSION_IDX = 1;
|
32 | 44 |
|
33 | 45 | @Override
|
34 | 46 | public void afterProjectsRead(final MavenSession session) throws MavenExecutionException {
|
35 | 47 | super.afterProjectsRead(session);
|
36 |
| - |
| 48 | + |
| 49 | + if (session.getUserProperties().containsKey("gitflow.skip.extension")) { |
| 50 | + return; |
| 51 | + } |
| 52 | + |
37 | 53 | if (pluginFound) {
|
38 | 54 | logger.debug("other-branch-version extension active.");
|
39 | 55 | if (branchInfo != null) {
|
@@ -62,7 +78,60 @@ public void afterProjectsRead(final MavenSession session) throws MavenExecutionE
|
62 | 78 | project.getArtifact().setVersionRange(VersionRange.createFromVersion(newVersion));
|
63 | 79 | }
|
64 | 80 | }
|
65 |
| - |
| 81 | + |
| 82 | + final MavenProject topLevelProjectInsideReactor = session.getTopLevelProject(); |
| 83 | + final MavenProject topLevelProject = findTopLevelProject(topLevelProjectInsideReactor); |
| 84 | + logger.info("Top level project: " + topLevelProjectInsideReactor.getGroupId() + ":" + topLevelProjectInsideReactor.getArtifactId()); |
| 85 | + if (!topLevelProjectInsideReactor.equals(topLevelProject)) { |
| 86 | + // When only the partial tree of modules is being built, not all modules could be indexed |
| 87 | + // into the cross-walk map. In order to deal with dependencies to modules outside the reactor, |
| 88 | + // Another Maven execution is performed on the 'actual' top level project. This allows the |
| 89 | + // cross-walk map to be completed with the modules that *are* part of the multi-module project, |
| 90 | + // but are currently not part of the reactor. |
| 91 | + |
| 92 | + logger.info("Found top level project, but outside reactor: " + topLevelProject.getGroupId() + ":" + topLevelProject.getArtifactId() + " (" + topLevelProject.getFile() + ")"); |
| 93 | + |
| 94 | + // Initialization of the nested Maven execution, based on the current session's request |
| 95 | + final MavenExecutionRequest request = DefaultMavenExecutionRequest.copy(session.getRequest()) |
| 96 | + .setExecutionListener(null) /* Disable the observer of the outer maven session */ |
| 97 | + .setTransferListener(null) /* Disable the observer of the outer maven session */ |
| 98 | + .setGoals(null) /* Disable the goals used to execute the outer maven session */ |
| 99 | + .setReactorFailureBehavior(MavenExecutionRequest.REACTOR_FAIL_NEVER) |
| 100 | + .setPom(topLevelProject.getFile()) /* Use the pom file of the top-level project */ |
| 101 | + .setBaseDirectory(topLevelProject.getBasedir()) /* Use the basedir of the top-level project */ |
| 102 | + ; |
| 103 | + // The following user property on the nested execution prevents this extension to activate |
| 104 | + // in the nested execution. This is needed, as the extension is not reentrant. |
| 105 | + request.getUserProperties().put("gitflow.skip.extension", true); |
| 106 | + |
| 107 | + // Perform the nested Maven execution, and grab the list of *all* projects (ie modules of the |
| 108 | + // multi-module build). |
| 109 | + final MavenExecutionResult mavenExecutionResult; |
| 110 | + try { |
| 111 | + mavenExecutionResult = maven.execute(request); |
| 112 | + } finally { |
| 113 | + // The additional Maven execution uses a new session, and at the end of the execution |
| 114 | + // clears the Session object in LegacySupport. This may break other plugins/uses of |
| 115 | + // LegacySupport; therefore always restore the session *after* the additional Maven |
| 116 | + // execution. |
| 117 | + legacySupport.setSession(session); |
| 118 | + } |
| 119 | + final List<MavenProject> topologicallySortedProjects = mavenExecutionResult.getTopologicallySortedProjects(); |
| 120 | + |
| 121 | + // Iterate over these modules and process the 'new' ones just as the modules that are part |
| 122 | + // of the reactor. |
| 123 | + for (MavenProject parsedProject : topologicallySortedProjects) { |
| 124 | + if (adjustedVersions.containsKey(parsedProject)) { |
| 125 | + logger.info("Skipping " + parsedProject.getGroupId() + ":" + parsedProject.getArtifactId() + ": already part of reactor"); |
| 126 | + } else { |
| 127 | + String originalVersion = PropertyResolver.resolveValue(parsedProject.getVersion(), parsedProject.getProperties(), systemEnvVars); |
| 128 | + String newVersion = getAsBranchSnapshotVersion(originalVersion, branchInfo.getName()); |
| 129 | + adjustedVersions.put(parsedProject, new String[]{originalVersion, newVersion}); |
| 130 | + logger.info("Updating outside-reactor project " + parsedProject.getGroupId() + ":" + parsedProject.getArtifactId() + ":" + originalVersion + " to: " + newVersion); |
| 131 | + } |
| 132 | + } |
| 133 | + } |
| 134 | + |
66 | 135 | // Once we have that populated, refilter the adjusted projects models
|
67 | 136 | // updating dependencies on both the in-memory effective model, and the original pom.xml model.
|
68 | 137 | for (Map.Entry<MavenProject, String[]> adjustedProject : adjustedVersions.entrySet()) {
|
@@ -96,6 +165,16 @@ public void afterProjectsRead(final MavenSession session) throws MavenExecutionE
|
96 | 165 | logger.info("Continuing execution....");
|
97 | 166 | }
|
98 | 167 |
|
| 168 | + private MavenProject findTopLevelProject(MavenProject mavenProject) { |
| 169 | + MavenProject parent = mavenProject; |
| 170 | + |
| 171 | + while (parent.getParentFile() != null) { |
| 172 | + parent = parent.getParent(); |
| 173 | + } |
| 174 | + |
| 175 | + return parent; |
| 176 | + } |
| 177 | + |
99 | 178 | private void updateProjectModel(final MavenProject projectContext, final Model model, final String[] versions, final Map<MavenProject, String[]> adjustedVersions) {
|
100 | 179 | model.setVersion(versions[ADJUSTED_VERSION_IDX]);
|
101 | 180 |
|
|
0 commit comments