Skip to content

Commit

Permalink
Merge pull request e-gineering#129 from Thales-Netherlands/feature/re…
Browse files Browse the repository at this point in the history
…tain-specific-plugins-on-master

Allow explicit configured plugins to execute on master as well
  • Loading branch information
bvarner authored Apr 17, 2023
2 parents 7ac1213 + 735ec61 commit c839530
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 19 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -449,8 +449,8 @@ directly from master**. Rather, master is really only used for tracking releases
To accomplish this the `promote-master` goal and a Maven build extension work together.

With the build extension added to your project, any build where the `gitBranchExpression` matches the `masterBranchPattern` or `supportBranchPattern` will have it's
build lifecycle (plugins, goals, etc) altered. Any plugin other than the gitflow-helper-maven-plugin, the maven-deploy-plugin, or plugins with goals
explicitly referenced on the command line will be ignored (removed from the project reactor).
build lifecycle (plugins, goals, etc) altered. Any plugin other than the gitflow-helper-maven-plugin, the maven-deploy-plugin, plugins with goals
explicitly referenced on the command line or those configured explicitly in the `retainPlugins` list, will be ignored (removed from the project reactor).
This allows us to enforce the ideal that code should never be built in the master branch.

The `promote-master` goal executes when the `gitBranchExpression` resolves to a value matching the `masterBranchPattern` or `supportBranchPattern` regular expression.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import org.codehaus.plexus.util.xml.Xpp3Dom;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

public abstract class AbstractBranchDetectingExtension extends AbstractMavenLifecycleParticipant {
Expand All @@ -34,6 +36,7 @@ public abstract class AbstractBranchDetectingExtension extends AbstractMavenLife
String featureOrBugfixBranchPattern;
String otherDeployBranchPattern;
String otherBranchVersionDelimiter;
List<String> retainPlugins;
GitBranchInfo branchInfo;
Properties systemEnvVars;

Expand Down Expand Up @@ -93,6 +96,10 @@ public void afterProjectsRead(MavenSession session) throws MavenExecutionExcepti
if (gitBranchExpression == null) {
gitBranchExpression = extractPluginConfigValue("gitBranchExpression", plugin);
}

if (retainPlugins == null) {
retainPlugins = extractPluginConfigList("retainPlugins", plugin);
}
}
}
}
Expand Down Expand Up @@ -145,6 +152,10 @@ public void afterProjectsRead(MavenSession session) throws MavenExecutionExcepti
logger.debug("Using default otherBranchVersionDelimiter.");
otherBranchVersionDelimiter = "+";
}

if (retainPlugins == null) {
logger.debug("No additional plugin executions will be retained on master");
}

ScmUtils scmUtils = new ScmUtils(systemEnvVars, scmManager, session.getTopLevelProject(), new PlexusLoggerToMavenLog(logger), masterBranchPattern, supportBranchPattern, releaseBranchPattern, hotfixBranchPattern, developmentBranchPattern);
branchInfo = scmUtils.resolveBranchInfo(gitBranchExpression);
Expand All @@ -168,4 +179,25 @@ private String extractConfigValue(String parameter, Object configuration) {
}
return null;
}

private List<String> extractPluginConfigList(String parameter, Plugin plugin) {
List<String> value = extractConfigList(parameter, plugin.getConfiguration());
for (int i = 0; i < plugin.getExecutions().size() && value == null; i++) {
value = extractConfigList(parameter, plugin.getExecutions().get(i).getConfiguration());
}
return value;
}

private List<String> extractConfigList(String parameter, Object configuration) {
try {
List<String> result = new ArrayList<>();
Xpp3Dom parameterNode = ((Xpp3Dom) configuration).getChild(parameter);
for (int i = 0; i < parameterNode.getChildCount(); i++) {
result.add(parameterNode.getChild(i).getValue());
}
return result;
} catch (Exception ignored) {
}
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,14 @@
import org.codehaus.plexus.component.annotations.Component;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
* Maven extension which removes (skips) undesired plugins from the build reactor when running on a master branch.
Expand All @@ -19,6 +25,15 @@
*/
@Component(role = AbstractMavenLifecycleParticipant.class, hint = "promote-master")
public class MasterPromoteExtension extends AbstractBranchDetectingExtension {

private static final Set<String> PLUGIN_WHITELIST = Collections.unmodifiableSet(
new HashSet<>(
Arrays.asList(
"org.apache.maven.plugins:maven-deploy-plugin",
"com.e-gineering:gitflow-helper-maven-plugin"
)
)
);

@Override
public void afterProjectsRead(final MavenSession session) throws MavenExecutionException {
Expand All @@ -41,26 +56,25 @@ public void afterProjectsRead(final MavenSession session) throws MavenExecutionE
}

// Build up a map of plugins to remove from projects, if we're on the master branch.
HashMap<MavenProject, List<Plugin>> pluginsToDrop = new HashMap<>();
Map<MavenProject, List<Plugin>> pluginsToDrop = new HashMap<>();

final List<String> configuredPluginsToRetain;
if (this.retainPlugins != null) {
configuredPluginsToRetain = this.retainPlugins;
} else {
configuredPluginsToRetain = Collections.emptyList();
}

for (MavenProject project : session.getProjects()) {
List<Plugin> dropPlugins = new ArrayList<>();

for (Plugin plugin : project.getModel().getBuild().getPlugins()) {
// Don't drop our plugin.
if (plugin.getKey().equals("com.e-gineering:gitflow-helper-maven-plugin")) {
continue;
// Don't drop things we declare goals for.
} else if (pluginsToRetain.contains(plugin)) {
logger.debug("gitflow-helper-maven-plugin retaining plugin: " + plugin + " from project: " + project.getName());
// Don't drop the maven-deploy-plugin
} else if (plugin.getKey().equals("org.apache.maven.plugins:maven-deploy-plugin")) {
logger.debug("gitflow-helper-maven-plugin retaining plugin: " + plugin + " from project: " + project.getName());
} else {
logger.debug("gitflow-helper-maven-plugin removing plugin: " + plugin + " from project: " + project.getName());
dropPlugins.add(plugin);
}
}
// Create a list of all plugins that are not in the whitelist, not explicitly invoked from the commandline,
// and not configured to be allowed on master/support.
List<Plugin> dropPlugins = project.getModel().getBuild().getPlugins()
.stream()
.filter(plugin -> !PLUGIN_WHITELIST.contains(plugin.getKey()))
.filter(plugin -> !pluginsToRetain.contains(plugin))
.filter(plugin -> !configuredPluginsToRetain.contains(plugin.getKey()))
.collect(Collectors.toList());

pluginsToDrop.put(project, dropPlugins);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;

import java.util.List;

/**
* If the build is being executed from a DEVELOPMENT, HOTFIX or RELEASE branch, attach an artifact containing a list of
Expand All @@ -17,6 +20,15 @@
@Mojo(name = "promote-master", defaultPhase = LifecyclePhase.INSTALL)
public class PromoteMasterMojo extends AbstractGitflowBasedRepositoryMojo {

/**
* List of groupId:artifactId strings that refer to plugins that should be retained while building on master.
*
* Note that this property is listed here for documentation purposes, but it is handled within
* {@link MasterPromoteExtension}.
*/
@Parameter(property = "retainPlugins")
private List<String> retainPlugins;

@Override
protected void execute(final GitBranchInfo gitBranchInfo) throws MojoExecutionException, MojoFailureException {
switch (gitBranchInfo.getType()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,16 @@ public void promotionOfRelease() throws Exception {
// Otherwise, it's the VerificationException from looking for "Compiling", and that's expected to fail.
}

try {
// The flatten-maven-plugin should not activate, fail if it does.
verifier.verifyTextInLog("Generating flattened POM of project");
throw new VerificationException(PROMOTION_FAILED_MESSAGE);
} catch (VerificationException ve) {
if (ve.getMessage().equals(PROMOTION_FAILED_MESSAGE)) {
throw ve;
}
}

verifier.verifyTextInLog(
"gitflow-helper-maven-plugin: Enabling MasterPromoteExtension. GIT_BRANCH: [origin/master] matches masterBranchPattern");
verifier.verifyTextInLog("[INFO] Setting release artifact repository to: [releases]");
Expand Down Expand Up @@ -121,4 +131,46 @@ public void dontPruneExplicitlyInvokedPlugins() throws Exception {
verifier.resetStreams();
}
}

@Test
public void dontPruneExplicitlyConfiguredPlugins() throws Exception {
// Create a release version and get it deployed.
Verifier verifier = createVerifier("/project-stub", "origin/release/1.2.0", "1.2.0");

try {
verifier.executeGoal("deploy");

verifier.verifyErrorFreeLog();
} finally {
verifier.resetStreams();
}

// Promote (deploy) from /origin/master
verifier = createVerifier("/project-stub", "origin/master", "1.2.0");
// Activate a profile to enable the retainPlugins configuration
verifier.addCliOption("-Pretain-configuration");
try {
verifier.executeGoal("deploy");

try {
verifier.verifyTextInLog("Compiling");
throw new VerificationException(PROMOTION_FAILED_MESSAGE);
} catch (VerificationException ve) {
if (ve.getMessage().equals(PROMOTION_FAILED_MESSAGE)) {
throw ve;
}
// Otherwise, it's the VerificationException from looking for "Compiling", and that's expected to fail.
}

verifier.verifyTextInLog("Generating flattened POM of project"); // This should still be there.
verifier.verifyTextInLog(
"gitflow-helper-maven-plugin: Enabling MasterPromoteExtension. GIT_BRANCH: [origin/master] matches masterBranchPattern");
verifier.verifyTextInLog("[INFO] Setting release artifact repository to: [releases]");
verifier.verifyTextInLog(
"[INFO] Resolving & Reattaching existing artifacts from stageDeploymentRepository [test-releases");
verifier.verifyErrorFreeLog();
} finally {
verifier.resetStreams();
}
}
}
35 changes: 35 additions & 0 deletions src/test/resources/project-stub/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,42 @@
<version>4.2.0</version>
<extensions>true</extensions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>flatten-maven-plugin</artifactId>
<version>1.2.2</version>
<executions>
<execution>
<goals>
<goal>flatten</goal>
</goals>
<phase>process-resources</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>

<profiles>
<profile>
<id>retain-configuration</id>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>com.e-gineering</groupId>
<artifactId>gitflow-helper-maven-plugin</artifactId>
<version>${version.gitflow.plugin}</version>
<configuration>
<retainPlugins>
<retainPlugin>org.codehaus.mojo:flatten-maven-plugin</retainPlugin>
</retainPlugins>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</profile>
</profiles>

</project>

0 comments on commit c839530

Please sign in to comment.