Skip to content

Commit

Permalink
Add support for changelist property per branch for maven ci friendly …
Browse files Browse the repository at this point in the history
…versioning - closes aleksandr-m#314
  • Loading branch information
mmusenbr committed Oct 7, 2021
1 parent 54d31d9 commit cf63898
Show file tree
Hide file tree
Showing 11 changed files with 289 additions and 30 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,18 @@ The `skipUpdateVersion` parameter can be used to skip updating `<version>` in th

To support [CI friendly versioning](https://maven.apache.org/maven-ci-friendly.html) in projects which use `<version>${revision}</version>` set `versionProperty` to `revision` and `skipUpdateVersion` to `true`.

### CI friendly in dependencies/multi module

Projects which additionally use the `changelist` property in the version (`<version>${revision}${changelist}</version>`) and refer to it via `<version>${project.version}</version>` in dependencies are supported as well.

As the different steps of the plugin running on different branches, different values for `changelist` may be needed to successfully resolve the dependencies.

To set different values to `changelist` per branch the properties `productionChangelistValue`, `hotfixChangelistValue`, `releaseChangelistValue`, `developmentChangelistValue`, `featureChangelistValue`, `supportChangelistValue` are used.

As example for the `gitflow:hotfix-finish` the following properties may be used (setting `developmentChangelistValue` done explicit for better understanding):

mvn gitflow:hotfix-finish -DhotfixVersion=x.y.z -DproductionChangelistValue='' -DhotfixChangelistValue='' -DdevelopmentChangelistValue='-SNAPSHOT'

## Additional goal parameters

The `gitflow:release-finish`, `gitflow:release` and `gitflow:hotfix-finish` goals have `skipTag` parameter. This parameter controls whether the release/hotfix will be tagged in Git.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.TimeZone;
import java.util.regex.Pattern;

Expand All @@ -30,6 +31,7 @@
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Dependency;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Parameter;
Expand Down Expand Up @@ -91,7 +93,7 @@ public abstract class AbstractGitFlowMojo extends AbstractMojo {
*/
@Parameter(defaultValue = "false")
protected boolean tychoBuild;

/**
* Whether to call Maven install goal during the mojo execution.
*
Expand Down Expand Up @@ -124,6 +126,12 @@ public abstract class AbstractGitFlowMojo extends AbstractMojo {
@Parameter(property = "argLine")
private String argLine;

/**
* Stores the branch specific maven arguments.
* Gets set if branch based properties are requested and appended to the maven commands.
*/
private String mvnArgsBranchSpecific = "";

/**
* Whether to make a GPG-signed commit.
*
Expand All @@ -149,6 +157,70 @@ public abstract class AbstractGitFlowMojo extends AbstractMojo {
@Parameter(property = "versionProperty")
private String versionProperty;

/**
* Property to treat as <code>changelist</code> property.
* Used for Maven CI friendly versioning handling. Only relevant in conjunction
* with the <code>xxxChangelistValue</code>'s.
*
* @since 1.17.0
*/
@Parameter(property = "changelistProperty", defaultValue = "changelist")
private String changelistProperty;

/**
* The value to pass as <code>changelist</code> value when running on the
* production branch.
*
* @since 1.17.0
*/
@Parameter(property = "productionChangelistValue")
private String productionChangelistValue;

/**
* The value to pass as <code>changelist</code> value when running on the
* hotfix branch.
*
* @since 1.17.0
*/
@Parameter(property = "hotfixChangelistValue")
private String hotfixChangelistValue;

/**
* The value to pass as <code>changelist</code> value when running on the
* release branch.
*
* @since 1.17.0
*/
@Parameter(property = "releaseChangelistValue")
private String releaseChangelistValue;

/**
* The value to pass as <code>changelist</code> value when running on the
* development branch.
*
* @since 1.17.0
*/
@Parameter(property = "developmentChangelistValue")
private String developmentChangelistValue;

/**
* The value to pass as <code>changelist</code> value when running on the
* feature branch.
*
* @since 1.17.0
*/
@Parameter(property = "featureChangelistValue")
private String featureChangelistValue;

/**
* The value to pass as <code>changelist</code> value when running on the
* support branch.
*
* @since 1.17.0
*/
@Parameter(property = "supportChangelistValue")
private String supportChangelistValue;

/**
* Whether to skip updating version. Useful with {@link #versionProperty} to be
* able to update <code>revision</code> property without modifying version tag.
Expand All @@ -171,6 +243,7 @@ public abstract class AbstractGitFlowMojo extends AbstractMojo {
*/
@Parameter(property = "mvnExecutable")
private String mvnExecutable;

/**
* The path to the Git executable. Defaults to "git".
*/
Expand All @@ -191,7 +264,7 @@ public abstract class AbstractGitFlowMojo extends AbstractMojo {

@Component
protected ProjectBuilder projectBuilder;

/** Default prompter. */
@Component
protected Prompter prompter;
Expand Down Expand Up @@ -611,7 +684,7 @@ protected boolean gitCheckTagExists(final String tagName) throws MojoFailureExce
* @throws MojoFailureException
* @throws CommandLineException
*/
protected void gitCheckout(final String branchName)
private void gitCheckout(final String branchName)
throws MojoFailureException, CommandLineException {
getLog().info("Checking out '" + branchName + "' branch.");

Expand All @@ -628,7 +701,7 @@ protected void gitCheckout(final String branchName)
* @throws MojoFailureException
* @throws CommandLineException
*/
protected void gitCreateAndCheckout(final String newBranchName,
private void gitCreateAndCheckout(final String newBranchName,
final String fromBranchName) throws MojoFailureException,
CommandLineException {
getLog().info(
Expand Down Expand Up @@ -1188,7 +1261,8 @@ private void executeGitCommand(final String... args)
*/
private void executeMvnCommand(final String... args)
throws CommandLineException, MojoFailureException {
executeCommand(cmdMvn, true, argLine, args);
final String argLineWithBranchSpecifics = joinStrings(argLine, mvnArgsBranchSpecific);
executeCommand(cmdMvn, true, argLineWithBranchSpecifics, args);
}

/**
Expand Down Expand Up @@ -1289,4 +1363,163 @@ public String getError() {
public void setArgLine(String argLine) {
this.argLine = argLine;
}

/**
* Executes git checkout and sets Maven CI friendly settings per branch.
*
* @param branchType
* Type of branch to set config for.
* @param branchName
* Branch name to checkout.
* @throws MojoExecutionException an internal error occurred
* @throws MojoFailureException an error with the underlying commands occurred
* @throws CommandLineException an error with the underlying commands occurred
*/
protected void checkoutAndSetConfigForBranch(final BranchType branchType, final String branchName)
throws MojoExecutionException, MojoFailureException, CommandLineException {
if (branchType == null) {
throw new MojoExecutionException("INTERNAL: given BranchType is null");
}

gitCheckout(branchName);
setConfigForBranchType(branchType);
}

/**
* Executes git checkout -b and sets Maven CI friendly settings per branch.
*
* @param branchType
* Type of branch to set config for.
* @param newBranchName
* Create branch with this name.
* @param fromBranchName
* Create branch from this branch.
* @throws MojoExecutionException an internal error occurred
* @throws MojoFailureException an error with the underlying commands occurred
* @throws CommandLineException an error with the underlying commands occurred
*/
protected void createAndCheckoutAndSetConfigForBranch(final BranchType branchType, final String newBranchName,
final String fromBranchName) throws MojoExecutionException, MojoFailureException, CommandLineException {
if (branchType == null) {
throw new MojoExecutionException("INTERNAL: given BranchType is null");
}

gitCreateAndCheckout(newBranchName, fromBranchName);
setConfigForBranchType(branchType);
}

/**
* Sets Maven CI friendly settings dependent of the type of branch.
* This includes settings passed to the maven commands in <code>executeMvnCommand</code> and manipulates
* the user properties inside the <code>MavenSession</code>, to guarantee that internal mvn commands
* via e.g. <code>ProjectBuilder.build</code> also uses the correct properties.
*
* @param branchType
* Type of branch to set config for.
* @throws MojoExecutionException an internal error occurred
*/
protected void setConfigForBranchType(final BranchType branchType) throws MojoExecutionException {
if (branchType == null) {
throw new MojoExecutionException("INTERNAL: given BranchType is null");
}

final boolean noChangelistValueToBeModified = productionChangelistValue == null
&& hotfixChangelistValue == null && releaseChangelistValue == null
&& developmentChangelistValue == null && featureChangelistValue == null
&& supportChangelistValue == null;

if (StringUtils.isBlank(changelistProperty) || noChangelistValueToBeModified) {
return;
}

final String changelistValue;

switch (branchType) {
case PRODUCTION:
changelistValue = productionChangelistValue;
break;
case HOTFIX:
changelistValue = hotfixChangelistValue;
break;
case RELEASE:
changelistValue = releaseChangelistValue;
break;
case DEVELOPMENT:
changelistValue = developmentChangelistValue;
break;
case FEATURE:
changelistValue = featureChangelistValue;
break;
case SUPPORT:
changelistValue = supportChangelistValue;
break;
default:
throw new MojoExecutionException("INTERNAL: unhandled case for branchType value: " + branchType);
}

setPropertyInProperties(changelistProperty, changelistValue, mavenSession.getProjectBuildingRequest().getUserProperties());
mvnArgsBranchSpecific = getJavaPropertyAsArgLineString(changelistProperty, changelistValue);
}

/**
* Sets a property in the given <code>Properties</code>.
*
* @param key
* The key of the property to set.
* @param value
* The value of the property to set, if null, the property gets removed.
* @param properties
* The properties where to replace the entry.
*/
private void setPropertyInProperties(final String key, final String value, final Properties properties) {
if (StringUtils.isBlank(key) || properties == null) {
return;
}

if (value == null) {
properties.remove(key);
} else {
properties.put(key, value);
}
}

/**
* Retrieve a string representation of a java property defined by key/value.
*
* @param key
* The key of the property to set.
* @param value
* The value of the property to set, if null, an empty string is returned.
* @return
* A string representation to be used as java argument.
* Empty if key is null or empty, or the value is null.
*/
private String getJavaPropertyAsArgLineString(final String key, final String value) {
if (StringUtils.isBlank(key) || value == null) {
return "";
} else {
return "-D" + key + "=" + value;
}
}

/**
* Join two <code>String</code>'s with a space.
* Both <code>String</code>'s can be null. And always a non-null value is returned.
*
* @param a
* The first string, where the second gets appended to. null is treated as empty.
* @param b
* The second string, which gets appended to the first one. null is treated as empty.
* @return
* The combined string, if both strings are null or empty, an empty String is returned.
*/
private String joinStrings(final String a, final String b) {
if (StringUtils.isBlank(a)) {
return StringUtils.clean(b);
} else if (StringUtils.isBlank(b)) {
return StringUtils.clean(a);
} else {
return a + " " + b;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.amashchenko.maven.plugin.gitflow;

public enum BranchType {
PRODUCTION, DEVELOPMENT, FEATURE, RELEASE, HOTFIX, SUPPORT;
}
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ public void execute() throws MojoExecutionException, MojoFailureException {

if (!skipTestProject) {
// git checkout feature/...
gitCheckout(featureBranchName);
checkoutAndSetConfigForBranch(BranchType.FEATURE, featureBranchName);

// mvn clean test
mvnCleanTest();
Expand Down Expand Up @@ -196,7 +196,7 @@ public void execute() throws MojoExecutionException, MojoFailureException {
}

// git checkout develop
gitCheckout(gitFlowConfig.getDevelopmentBranch());
checkoutAndSetConfigForBranch(BranchType.DEVELOPMENT, gitFlowConfig.getDevelopmentBranch());

if (featureSquash) {
// git merge --squash feature/...
Expand All @@ -222,7 +222,7 @@ public void execute() throws MojoExecutionException, MojoFailureException {
}

if (keepBranch) {
gitCheckout(featureBranchName);
checkoutAndSetConfigForBranch(BranchType.FEATURE, featureBranchName);

mvnSetVersions(keptFeatureVersion);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ public void execute() throws MojoExecutionException, MojoFailureException {
}

// git checkout -b ... develop
gitCreateAndCheckout(
createAndCheckoutAndSetConfigForBranch(
BranchType.FEATURE,
gitFlowConfig.getFeatureBranchPrefix() + featureBranchName,
gitFlowConfig.getDevelopmentBranch());

Expand Down
Loading

0 comments on commit cf63898

Please sign in to comment.