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#305 aleksandr-m#314
  • Loading branch information
mmusenbr committed Oct 15, 2021
1 parent 54d31d9 commit 015e902
Show file tree
Hide file tree
Showing 11 changed files with 309 additions and 29 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,13 @@ public abstract class AbstractGitFlowMojo extends AbstractMojo {
@Parameter(property = "argLine")
private String argLine;

/**
* Stores the original argLine.
* If branch based properties are needed, this will be used as reference
* for the argLine manipulation.
*/
private String argLineOrig;

/**
* Whether to make a GPG-signed commit.
*
Expand All @@ -149,6 +158,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 +244,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 +265,7 @@ public abstract class AbstractGitFlowMojo extends AbstractMojo {

@Component
protected ProjectBuilder projectBuilder;

/** Default prompter. */
@Component
protected Prompter prompter;
Expand Down Expand Up @@ -611,7 +685,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 +702,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 @@ -1288,5 +1362,167 @@ public String getError() {

public void setArgLine(String argLine) {
this.argLine = argLine;
this.argLineOrig = 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 re-configuring the <code>argLine</code> which is passed to the maven commands in
* <code>executeMvnCommand</code> and manipulates the user properties inside of the <code>MavenSession</code>,
* to guarantee that internal mvn commands via eg <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());
argLine = replacePropertyInArgline(changelistProperty, changelistValue, argLineOrig);
}

/**
* Sets a property in the given <code>Properties</code>.
* Updates the <code>Properties</code> and manipulates the <code>argLine</code> inside
* of the <code>Properties</code> as well.
*
* @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;
}

final String argLineFromProperty = properties.getProperty("argLine");
final String replaced = replacePropertyInArgline(key, value, argLineFromProperty);

if (replaced == null) {
properties.remove("argLine");
} else {
properties.put("argLine", replaced);
}

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

/**
* Replaces/sets a property in a argLine-String.
*
* @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 argLine
* A argLine-representation used to replace the key.
* @return a new argLine where the property is replaced/set.
*/
private String replacePropertyInArgline(final String key, final String value, final String argLine) {
final String javaProperty = "-D" + key + "=";
final String argLinePropertyRegex = javaProperty + "\\S*";
final String argLinePropertyReplacement = (value == null) ? "" : javaProperty + value;

if (StringUtils.isBlank(argLine) || !argLine.contains(javaProperty)) {
// noop: old argLine is empty or does not contain the property and no property to set
if (StringUtils.isBlank(argLinePropertyReplacement)) {
return argLine;
// append: old argLine is empty or does not contain the property and property to set
} else {
final String argLineReadyToAppend = StringUtils.isBlank(argLine) ? "" : argLine + " ";
return argLineReadyToAppend + argLinePropertyReplacement;
}
// replace or remove: old argLine contains property, replacement: new or empty
} else {
return argLine.replaceAll(argLinePropertyRegex, argLinePropertyReplacement);
}
}
}
23 changes: 23 additions & 0 deletions src/main/java/com/amashchenko/maven/plugin/gitflow/BranchType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright 2014-2021 Aleksandr Mashchenko.
*
* Licensed 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 com.amashchenko.maven.plugin.gitflow;

/**
* The possible types of the different used branches.
*/
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 015e902

Please sign in to comment.