org.eclipse.aether
aether-api
diff --git a/maven-release-api/src/main/java/org/apache/maven/shared/release/config/ReleaseDescriptor.java b/maven-release-api/src/main/java/org/apache/maven/shared/release/config/ReleaseDescriptor.java
index 6ca7c0f01..26a078d80 100644
--- a/maven-release-api/src/main/java/org/apache/maven/shared/release/config/ReleaseDescriptor.java
+++ b/maven-release-api/src/main/java/org/apache/maven/shared/release/config/ReleaseDescriptor.java
@@ -426,6 +426,13 @@ public interface ReleaseDescriptor
*/
String getProjectVersionPolicyId();
+ /**
+ * Get the (optional) config for the VersionPolicy implementation used to calculate the project versions.
+ *
+ * @return The parsed XML of the provided config (an instance of XmlPlexusConfiguration) or null.
+ */
+ Object getProjectVersionPolicyConfig();
+
/**
* Get the role-hint for the release Strategy implementation.
*
diff --git a/maven-release-api/src/main/java/org/apache/maven/shared/release/policy/version/VersionPolicyRequest.java b/maven-release-api/src/main/java/org/apache/maven/shared/release/policy/version/VersionPolicyRequest.java
index 4001b8714..9c771089f 100644
--- a/maven-release-api/src/main/java/org/apache/maven/shared/release/policy/version/VersionPolicyRequest.java
+++ b/maven-release-api/src/main/java/org/apache/maven/shared/release/policy/version/VersionPolicyRequest.java
@@ -20,6 +20,8 @@
*/
import org.apache.maven.artifact.repository.metadata.Metadata;
+import org.apache.maven.scm.provider.ScmProvider;
+import org.apache.maven.scm.repository.ScmRepository;
/**
* VersionPolicyRequest class.
@@ -33,6 +35,12 @@ public class VersionPolicyRequest
private Metadata metaData;
+ private ScmRepository scmRepository;
+ private ScmProvider scmProvider;
+ private String workingDirectory;
+
+ private String config;
+
/**
* Getter for the field version
.
*
@@ -76,5 +84,93 @@ public VersionPolicyRequest setMetaData( Metadata metaData )
this.metaData = metaData;
return this;
}
-
+
+ /**
+ * Getter for the field scmRepository
.
+ *
+ * @return a {@link ScmRepository} object
+ */
+ public ScmRepository getScmRepository()
+ {
+ return scmRepository;
+ }
+
+ /**
+ * Setter for the field scmRepository
.
+ *
+ * @param scmRepository The {@link ScmRepository} where the history can be retrieved.
+ * @return a {@link org.apache.maven.shared.release.policy.version.VersionPolicyRequest} object
+ */
+ public VersionPolicyRequest setScmRepository( ScmRepository scmRepository )
+ {
+ this.scmRepository = scmRepository;
+ return this;
+ }
+
+ /**
+ * Getter for the field scmProvider
.
+ *
+ * @return a {@link ScmProvider} object
+ */
+ public ScmProvider getScmProvider()
+ {
+ return scmProvider;
+ }
+
+ /**
+ * Setter for the field scmProvider
.
+ *
+ * @param scmProvider The {@link ScmProvider} where the history can be retrieved.
+ * @return a {@link org.apache.maven.shared.release.policy.version.VersionPolicyRequest} object
+ */
+ public VersionPolicyRequest setScmProvider( ScmProvider scmProvider )
+ {
+ this.scmProvider = scmProvider;
+ return this;
+ }
+
+ /**
+ * Getter for the field workingDirectory
.
+ *
+ * @return the {@link String} that contains the workingDirectory (can be null or empty).
+ */
+ public String getWorkingDirectory()
+ {
+ return workingDirectory;
+ }
+
+ /**
+ * Setter for the field workingDirectory
.
+ *
+ * @param workingDirectory The {@link String} that contains the workingDirectory (can be null or empty).
+ * @return a {@link org.apache.maven.shared.release.policy.version.VersionPolicyRequest} object
+ */
+ public VersionPolicyRequest setWorkingDirectory( String workingDirectory )
+ {
+ this.workingDirectory = workingDirectory;
+ return this;
+ }
+
+ /**
+ * Getter for the field config
.
+ *
+ * @return the {@link String} that contains the config (can be null or empty).
+ */
+ public String getConfig()
+ {
+ return config;
+ }
+
+ /**
+ * Setter for the field config
.
+ *
+ * @param config The {@link String} that contains the config (can be null or empty).
+ * @return a {@link org.apache.maven.shared.release.policy.version.VersionPolicyRequest} object
+ */
+ public VersionPolicyRequest setConfig( String config )
+ {
+ this.config = config;
+ return this;
+ }
+
}
diff --git a/maven-release-api/src/main/java/org/apache/maven/shared/release/versions/VersionParseException.java b/maven-release-api/src/main/java/org/apache/maven/shared/release/versions/VersionParseException.java
index 8d24cb112..010c8c4b3 100644
--- a/maven-release-api/src/main/java/org/apache/maven/shared/release/versions/VersionParseException.java
+++ b/maven-release-api/src/main/java/org/apache/maven/shared/release/versions/VersionParseException.java
@@ -34,4 +34,14 @@ public VersionParseException( String message )
{
super( message );
}
+
+ /**
+ * Constructor for VersionParseException.
+ *
+ * @param message a {@link java.lang.String} object
+ */
+ public VersionParseException( String message, Exception e )
+ {
+ super( message, e );
+ }
}
diff --git a/maven-release-manager/pom.xml b/maven-release-manager/pom.xml
index 98345bc11..7488a60dc 100644
--- a/maven-release-manager/pom.xml
+++ b/maven-release-manager/pom.xml
@@ -191,7 +191,6 @@
org.eclipse.sisu
org.eclipse.sisu.plexus
- test
diff --git a/maven-release-manager/src/main/java/org/apache/maven/shared/release/config/PropertiesReleaseDescriptorStore.java b/maven-release-manager/src/main/java/org/apache/maven/shared/release/config/PropertiesReleaseDescriptorStore.java
index fdacb6d2d..9d3246c00 100644
--- a/maven-release-manager/src/main/java/org/apache/maven/shared/release/config/PropertiesReleaseDescriptorStore.java
+++ b/maven-release-manager/src/main/java/org/apache/maven/shared/release/config/PropertiesReleaseDescriptorStore.java
@@ -269,6 +269,10 @@ public void write( BuilderReleaseDescriptor config, File file )
{
properties.setProperty( "projectVersionPolicyId", config.getProjectVersionPolicyId() );
}
+ if ( config.getProjectVersionPolicyConfig() != null )
+ {
+ properties.setProperty( "projectVersionPolicyConfig", config.getProjectVersionPolicyConfig().toString() );
+ }
if ( config.getProjectNamingPolicyId() != null )
{
properties.setProperty( "projectNamingPolicyId", config.getProjectNamingPolicyId() );
diff --git a/maven-release-manager/src/main/java/org/apache/maven/shared/release/config/ReleaseDescriptorBuilder.java b/maven-release-manager/src/main/java/org/apache/maven/shared/release/config/ReleaseDescriptorBuilder.java
index 6940d31da..5b81f7032 100644
--- a/maven-release-manager/src/main/java/org/apache/maven/shared/release/config/ReleaseDescriptorBuilder.java
+++ b/maven-release-manager/src/main/java/org/apache/maven/shared/release/config/ReleaseDescriptorBuilder.java
@@ -401,6 +401,18 @@ public ReleaseDescriptorBuilder setProjectVersionPolicyId( String projectVersion
return this;
}
+ /**
+ * setProjectVersionPolicyConfig.
+ *
+ * @param setProjectVersionPolicyConfig a {@link java.lang.String} object
+ * @return a {@link org.apache.maven.shared.release.config.ReleaseDescriptorBuilder} object
+ */
+ public ReleaseDescriptorBuilder setProjectVersionPolicyConfig( String setProjectVersionPolicyConfig )
+ {
+ releaseDescriptor.setProjectVersionPolicyConfig( setProjectVersionPolicyConfig );
+ return this;
+ }
+
/**
* setPushChanges.
*
diff --git a/maven-release-manager/src/main/java/org/apache/maven/shared/release/config/ReleaseUtils.java b/maven-release-manager/src/main/java/org/apache/maven/shared/release/config/ReleaseUtils.java
index 3847b52d0..2d24e35c2 100644
--- a/maven-release-manager/src/main/java/org/apache/maven/shared/release/config/ReleaseUtils.java
+++ b/maven-release-manager/src/main/java/org/apache/maven/shared/release/config/ReleaseUtils.java
@@ -156,6 +156,10 @@ public static void copyPropertiesToReleaseDescriptor( Properties properties, Rel
{
builder.setProjectVersionPolicyId( properties.getProperty( "projectVersionPolicyId" ) );
}
+ if ( properties.containsKey( "projectVersionPolicyConfig" ) )
+ {
+ builder.setProjectVersionPolicyConfig( properties.getProperty( "projectVersionPolicyConfig" ) );
+ }
if ( properties.containsKey( "projectNamingPolicyId" ) )
{
builder.setProjectNamingPolicyId( properties.getProperty( "projectNamingPolicyId" ) );
diff --git a/maven-release-manager/src/main/java/org/apache/maven/shared/release/phase/AbstractMapVersionsPhase.java b/maven-release-manager/src/main/java/org/apache/maven/shared/release/phase/AbstractMapVersionsPhase.java
index 97617f35a..6f7b4d2ad 100644
--- a/maven-release-manager/src/main/java/org/apache/maven/shared/release/phase/AbstractMapVersionsPhase.java
+++ b/maven-release-manager/src/main/java/org/apache/maven/shared/release/phase/AbstractMapVersionsPhase.java
@@ -24,6 +24,11 @@
import org.apache.maven.artifact.ArtifactUtils;
import org.apache.maven.project.MavenProject;
+import org.apache.maven.scm.manager.NoSuchScmProviderException;
+import org.apache.maven.scm.provider.ScmProvider;
+import org.apache.maven.scm.repository.ScmRepository;
+import org.apache.maven.scm.repository.ScmRepositoryException;
+import org.apache.maven.settings.Settings;
import org.apache.maven.shared.release.ReleaseExecutionException;
import org.apache.maven.shared.release.ReleaseResult;
import org.apache.maven.shared.release.config.ReleaseDescriptor;
@@ -31,8 +36,11 @@
import org.apache.maven.shared.release.policy.PolicyException;
import org.apache.maven.shared.release.policy.version.VersionPolicy;
import org.apache.maven.shared.release.policy.version.VersionPolicyRequest;
+import org.apache.maven.shared.release.scm.ScmRepositoryConfigurator;
import org.apache.maven.shared.release.util.ReleaseUtil;
import org.apache.maven.shared.release.versions.VersionParseException;
+import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.components.interactivity.Prompter;
import org.codehaus.plexus.components.interactivity.PrompterException;
import org.codehaus.plexus.util.StringUtils;
@@ -67,9 +75,16 @@
* @author Brett Porter
* @author Robert Scholte
*/
+@Component( role = ReleasePhase.class, hint = "map-release-versions" )
public abstract class AbstractMapVersionsPhase
extends AbstractReleasePhase
{
+ /**
+ * Tool that gets a configured SCM repository from release configuration.
+ */
+ @Requirement
+ private ScmRepositoryConfigurator scmRepositoryConfigurator;
+
/**
* Component used to prompt for input.
*/
@@ -275,14 +290,14 @@ else if ( releaseDescriptor.isBranchCreation() )
{
suggestedVersion =
resolveSuggestedVersion( baseVersion,
- releaseDescriptor.getProjectVersionPolicyId() );
+ releaseDescriptor );
}
catch ( VersionParseException e )
{
if ( releaseDescriptor.isInteractive() )
{
suggestedVersion =
- resolveSuggestedVersion( "1.0", releaseDescriptor.getProjectVersionPolicyId() );
+ resolveSuggestedVersion( "1.0", releaseDescriptor );
}
else
{
@@ -347,9 +362,10 @@ private String getContextString( ReleaseDescriptor releaseDescriptor )
return "new development";
}
- private String resolveSuggestedVersion( String baseVersion, String policyId )
+ private String resolveSuggestedVersion( String baseVersion, ReleaseDescriptor releaseDescriptor )
throws PolicyException, VersionParseException
{
+ String policyId = releaseDescriptor.getProjectVersionPolicyId();
VersionPolicy policy = versionPolicies.get( policyId );
if ( policy == null )
{
@@ -357,6 +373,31 @@ private String resolveSuggestedVersion( String baseVersion, String policyId )
}
VersionPolicyRequest request = new VersionPolicyRequest().setVersion( baseVersion );
+
+ if ( releaseDescriptor.getProjectVersionPolicyConfig() != null )
+ {
+ request.setConfig( releaseDescriptor.getProjectVersionPolicyConfig().toString() );
+ }
+ request.setWorkingDirectory( releaseDescriptor.getWorkingDirectory() );
+
+ if ( scmRepositoryConfigurator != null && releaseDescriptor.getScmSourceUrl() != null )
+ {
+ try
+ {
+ ScmRepository repository = scmRepositoryConfigurator
+ .getConfiguredRepository( releaseDescriptor, new Settings() );
+
+ ScmProvider provider = scmRepositoryConfigurator
+ .getRepositoryProvider( repository );
+
+ request.setScmRepository( repository );
+ request.setScmProvider( provider );
+ }
+ catch ( ScmRepositoryException | NoSuchScmProviderException e )
+ {
+ getLogger().warn( "Next Version will NOT be based on the version control: {}", e.getMessage() );
+ }
+ }
return convertToSnapshot ? policy.getDevelopmentVersion( request ).getVersion()
: policy.getReleaseVersion( request ).getVersion();
}
diff --git a/maven-release-manager/src/main/mdo/release-descriptor.mdo b/maven-release-manager/src/main/mdo/release-descriptor.mdo
index 0a1d8cd55..a752ff695 100644
--- a/maven-release-manager/src/main/mdo/release-descriptor.mdo
+++ b/maven-release-manager/src/main/mdo/release-descriptor.mdo
@@ -488,6 +488,15 @@
The role-hint for the VersionPolicy implementation used to calculate the project versions.
+
+ projectVersionPolicyConfig
+ 3.0.0+
+ DOM
+
+ The optional config string for the VersionPolicy implementation used to calculate the project versions.
+ The format of this depends on the specific VersionPolicy that is used.
+
+
projectNamingPolicyId
3.0.0+
diff --git a/maven-release-manager/src/test/java/org/apache/maven/shared/release/config/PropertiesReleaseDescriptorStoreTest.java b/maven-release-manager/src/test/java/org/apache/maven/shared/release/config/PropertiesReleaseDescriptorStoreTest.java
index 27e03d982..a45861c72 100644
--- a/maven-release-manager/src/test/java/org/apache/maven/shared/release/config/PropertiesReleaseDescriptorStoreTest.java
+++ b/maven-release-manager/src/test/java/org/apache/maven/shared/release/config/PropertiesReleaseDescriptorStoreTest.java
@@ -367,6 +367,9 @@ private ReleaseDescriptorBuilder createReleaseConfigurationForWriting()
builder.addReleaseVersion( "groupId:artifactId", "1.0" );
builder.addDevelopmentVersion( "groupId:artifactId", "1.1-SNAPSHOT" );
+ // The actual kind of string you will get when setting the projectVersionPolicyConfig
+ builder.setProjectVersionPolicyConfig("bar");
+
IdentifiedScm scm = new IdentifiedScm();
scm.setId( "id-write" );
scm.setConnection( "connection-write" );
diff --git a/maven-release-plugin/pom.xml b/maven-release-plugin/pom.xml
index aa20fa24f..74e0a7239 100644
--- a/maven-release-plugin/pom.xml
+++ b/maven-release-plugin/pom.xml
@@ -95,6 +95,12 @@
${project.version}
true
+
+ org.apache.maven.release
+ maven-release-ccsemver-policy
+ ${project.version}
+ true
+
junit
diff --git a/maven-release-plugin/src/it/projects/prepare/ccsemver-policy/pom.xml b/maven-release-plugin/src/it/projects/prepare/ccsemver-policy/pom.xml
new file mode 100644
index 000000000..5c809f1eb
--- /dev/null
+++ b/maven-release-plugin/src/it/projects/prepare/ccsemver-policy/pom.xml
@@ -0,0 +1,83 @@
+
+
+
+ 4.0.0
+ org.apache.maven.plugin.release.it
+ ccsemver-policy
+ 1.0-SNAPSHOT
+
+ scm:dummytags|nul
+ scm:dummytags|nul
+
+
+
+
+ org.apache.maven.plugins
+ maven-release-plugin
+ @project.version@
+
+ true
+ true
+ false
+ false
+
+ ci(Release):
+ ci(Release): Version @{releaseLabel}
+ v@{project.version}
+
+ CCSemVerVersionPolicy
+
+
+
+
+
+
+
+
+
+
+ ^v([0-9]+(?:\.[0-9]+(?:\.[0-9]+)?)?)$
+
+ ^[a-zA-Z]+!(?:\([a-zA-Z0-9_-]+\))?: .*$
+ ^BREAKING CHANGE:.*$
+
+
+ ^feat(?:\([a-zA-Z0-9_-]+\))?: .*$
+
+
+
+
+
+
+ org.apache.maven.its.release
+ maven-scm-provider-dummy
+ 1.0
+
+
+ org.apache.maven.release
+ maven-release-ccsemver-policy
+ @project.version@
+
+
+
+
+
+
diff --git a/maven-release-plugin/src/it/projects/prepare/ccsemver-policy/verify.groovy b/maven-release-plugin/src/it/projects/prepare/ccsemver-policy/verify.groovy
new file mode 100644
index 000000000..476b00fec
--- /dev/null
+++ b/maven-release-plugin/src/it/projects/prepare/ccsemver-policy/verify.groovy
@@ -0,0 +1,39 @@
+
+/*
+ * 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.
+ */
+
+File buildLog = new File( basedir, 'build.log' )
+assert buildLog.exists()
+assert 1 == buildLog.getText().count("[INFO] From SCM tag with version 1.2.3 doing a MINOR version increase based on commit messages to version 1.3.0")
+assert 1 == buildLog.getText().count("[INFO] Full run would be commit 1 files with message: 'ci(Release): Version v1.3.0'")
+
+// The pom based version is NOT related to what the actual version will be.
+File pomXml = new File( basedir, 'pom.xml' )
+assert pomXml.exists()
+assert new XmlSlurper().parse( pomXml ).version.text() == "1.0-SNAPSHOT"
+
+// The actual version is based upon the tags and commit messages.
+File pomXmlTag = new File( basedir, 'pom.xml.tag' )
+assert pomXmlTag.exists()
+assert new XmlSlurper().parse( pomXmlTag ).version.text() == "1.3.0"
+
+// The next development version should be standard
+File pomXmlNext = new File( basedir, 'pom.xml.next' )
+assert pomXmlNext.exists()
+assert new XmlSlurper().parse( pomXmlNext ).version.text() == "1.3.1-SNAPSHOT"
diff --git a/maven-release-plugin/src/it/setup/maven-scm-provider-dummy/src/main/java/org/apache/maven/scm/provider/dummy/DummyTagsScmProvider.java b/maven-release-plugin/src/it/setup/maven-scm-provider-dummy/src/main/java/org/apache/maven/scm/provider/dummy/DummyTagsScmProvider.java
new file mode 100644
index 000000000..dfa218106
--- /dev/null
+++ b/maven-release-plugin/src/it/setup/maven-scm-provider-dummy/src/main/java/org/apache/maven/scm/provider/dummy/DummyTagsScmProvider.java
@@ -0,0 +1,115 @@
+package org.apache.maven.scm.provider.dummy;
+
+/*
+ * 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.
+ */
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.apache.maven.scm.ChangeSet;
+import org.apache.maven.scm.CommandParameters;
+import org.apache.maven.scm.ScmFileSet;
+import org.apache.maven.scm.ScmResult;
+import org.apache.maven.scm.command.changelog.ChangeLogScmRequest;
+import org.apache.maven.scm.command.changelog.ChangeLogScmResult;
+import org.apache.maven.scm.command.changelog.ChangeLogSet;
+import org.apache.maven.scm.command.status.StatusScmResult;
+import org.apache.maven.scm.provider.AbstractScmProvider;
+import org.apache.maven.scm.provider.ScmProviderRepository;
+
+import java.util.Arrays;
+import java.util.Date;
+
+/**
+ * A dummy SCM provider used to provide commit messages and tags for testing the Conventional Commits Version Policy.
+ *
+ * @plexus.component role="org.apache.maven.scm.provider.ScmProvider" role-hint="dummytags"
+ * @author Niels Basjes
+ */
+@Singleton
+@Named( "dummytags" )
+public class DummyTagsScmProvider
+ extends AbstractScmProvider
+{
+
+ public String getScmType()
+ {
+ return "dummytags";
+ }
+
+ public ScmProviderRepository makeProviderScmRepository( String scmSpecificUrl, char delimiter )
+ {
+ return new DummyScmProviderRepository();
+ }
+
+ @Override
+ protected StatusScmResult status( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
+ {
+ return new StatusScmResult( "", "", "", true );
+ }
+
+ private ChangeSet changeSet(String comment, String... tags)
+ {
+ ChangeSet changeSet = new ChangeSet();
+ changeSet.setComment( comment );
+ changeSet.setAuthor( "Someone " );
+ changeSet.setTags( Arrays.asList( tags ) );
+ return changeSet;
+ }
+
+ @Override
+ public ChangeLogScmResult changeLog(ChangeLogScmRequest request)
+ {
+ Date from = new Date( 39817800000L );
+ Date to = new Date( 1644768534785L );
+ ChangeLogSet changeLogSet = new ChangeLogSet(
+ Arrays.asList(
+ changeSet( "Commit 19" ),
+ changeSet( "Commit 18" ),
+ changeSet( "Commit 17" ),
+ changeSet( "Commit 16" ),
+ changeSet( "Commit 15", "tag 1", "tag 2" ),
+ changeSet( "feat(it): This is a new feature." ), // For Conventional Commits.
+ changeSet( "Commit 13" ),
+ changeSet( "Commit 12", "tag 3" ),
+ changeSet( "Commit 11" ),
+ changeSet( "Commit 10" ),
+ changeSet( "Commit 9" ),
+ changeSet( "Commit 8" ),
+ changeSet( "Commit 7" ),
+ changeSet( "Commit 6", "tag 4" ),
+ changeSet( "Commit 5" ),
+ changeSet( "Commit 4" ),
+ changeSet( "Commit 3" ),
+ changeSet( "Commit 2", "v1.2.3" ), // For Conventional Commits.
+ changeSet( "Commit 1" ),
+ changeSet( "Commit 0" )
+ ), from, to
+ );
+
+ ScmResult scmResult = new ScmResult(
+ "No command",
+ "Special for CCSemVer testing",
+ "No command output",
+ true
+ );
+ return new ChangeLogScmResult( changeLogSet, scmResult );
+ }
+
+}
diff --git a/maven-release-plugin/src/main/java/org/apache/maven/plugins/release/BranchReleaseMojo.java b/maven-release-plugin/src/main/java/org/apache/maven/plugins/release/BranchReleaseMojo.java
index 7e67b80eb..cca4bcbf8 100644
--- a/maven-release-plugin/src/main/java/org/apache/maven/plugins/release/BranchReleaseMojo.java
+++ b/maven-release-plugin/src/main/java/org/apache/maven/plugins/release/BranchReleaseMojo.java
@@ -30,6 +30,7 @@
import org.apache.maven.shared.release.ReleaseExecutionException;
import org.apache.maven.shared.release.ReleaseFailureException;
import org.apache.maven.shared.release.config.ReleaseDescriptorBuilder;
+import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
/**
* Branch a project in SCM, using the same steps as the release:prepare
goal, creating a branch instead of
@@ -200,6 +201,14 @@ public class BranchReleaseMojo
@Parameter( defaultValue = "default", property = "projectVersionPolicyId" )
private String projectVersionPolicyId;
+ /**
+ * Optional config for the VersionPolicy implementation used to calculate the project versions.
+ *
+ * @since 3.0.0-M7
+ */
+ @Parameter( property = "projectVersionPolicyConfig" )
+ private XmlPlexusConfiguration projectVersionPolicyConfig;
+
/**
* The role-hint for the {@link org.apache.maven.shared.release.policy.naming.NamingPolicy}
* implementation used to calculate the project names.
@@ -260,6 +269,10 @@ public void execute()
config.setDefaultDevelopmentVersion( developmentVersion );
config.setSuppressCommitBeforeTagOrBranch( suppressCommitBeforeBranch );
config.setProjectVersionPolicyId( projectVersionPolicyId );
+ if ( projectVersionPolicyConfig != null )
+ {
+ config.setProjectVersionPolicyConfig( projectVersionPolicyConfig.toString() );
+ }
config.setProjectNamingPolicyId( projectBranchNamingPolicyId );
config.setScmBranchCommitComment( scmBranchCommitComment );
config.setPinExternals( pinExternals );
diff --git a/maven-release-plugin/src/main/java/org/apache/maven/plugins/release/PrepareReleaseMojo.java b/maven-release-plugin/src/main/java/org/apache/maven/plugins/release/PrepareReleaseMojo.java
index a7bc0f126..b00282631 100644
--- a/maven-release-plugin/src/main/java/org/apache/maven/plugins/release/PrepareReleaseMojo.java
+++ b/maven-release-plugin/src/main/java/org/apache/maven/plugins/release/PrepareReleaseMojo.java
@@ -34,6 +34,7 @@
import org.apache.maven.shared.release.ReleaseFailureException;
import org.apache.maven.shared.release.ReleasePrepareRequest;
import org.apache.maven.shared.release.config.ReleaseDescriptorBuilder;
+import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
/**
* Prepare for a release in SCM. Steps through several phases to ensure the POM is ready to be released and then
@@ -240,6 +241,14 @@ public class PrepareReleaseMojo
@Parameter( defaultValue = "default", property = "projectVersionPolicyId" )
private String projectVersionPolicyId;
+ /**
+ * Optional config for the VersionPolicy implementation used to calculate the project versions.
+ *
+ * @since 3.0.0-M7
+ */
+ @Parameter( property = "projectVersionPolicyConfig" )
+ private XmlPlexusConfiguration projectVersionPolicyConfig;
+
/**
* The role-hint for the {@link org.apache.maven.shared.release.policy.naming.NamingPolicy}
* implementation used to calculate the project branch and tag names.
@@ -382,6 +391,10 @@ protected void prepareRelease( boolean generateReleasePoms )
config.setSuppressCommitBeforeTagOrBranch( suppressCommitBeforeTag );
config.setWaitBeforeTagging( waitBeforeTagging );
config.setProjectVersionPolicyId( projectVersionPolicyId );
+ if ( projectVersionPolicyConfig != null )
+ {
+ config.setProjectVersionPolicyConfig( projectVersionPolicyConfig.toString() );
+ }
config.setProjectNamingPolicyId( projectTagNamingPolicyId );
config.setScmDevelopmentCommitComment( scmDevelopmentCommitComment );
config.setScmReleaseCommitComment( scmReleaseCommitComment );
diff --git a/maven-release-plugin/src/main/java/org/apache/maven/plugins/release/UpdateVersionsMojo.java b/maven-release-plugin/src/main/java/org/apache/maven/plugins/release/UpdateVersionsMojo.java
index 60f657dfd..c72590040 100644
--- a/maven-release-plugin/src/main/java/org/apache/maven/plugins/release/UpdateVersionsMojo.java
+++ b/maven-release-plugin/src/main/java/org/apache/maven/plugins/release/UpdateVersionsMojo.java
@@ -29,6 +29,7 @@
import org.apache.maven.shared.release.ReleaseFailureException;
import org.apache.maven.shared.release.ReleaseUpdateVersionsRequest;
import org.apache.maven.shared.release.config.ReleaseDescriptorBuilder;
+import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
/**
* Update the POM versions for a project. This performs the normal version updates of the release:prepare
@@ -93,6 +94,14 @@ public class UpdateVersionsMojo
@Parameter( defaultValue = "default", property = "projectVersionPolicyId" )
private String projectVersionPolicyId;
+ /**
+ * Optional config for the VersionPolicy implementation used to calculate the project versions.
+ *
+ * @since 3.0.0-M7
+ */
+ @Parameter( property = "projectVersionPolicyConfig" )
+ private XmlPlexusConfiguration projectVersionPolicyConfig;
+
@Override
public void execute()
throws MojoExecutionException, MojoFailureException
@@ -104,7 +113,10 @@ public void execute()
config.setScmUseEditMode( useEditMode );
config.setUpdateDependencies( updateDependencies );
config.setProjectVersionPolicyId( projectVersionPolicyId );
-
+ if ( projectVersionPolicyConfig != null )
+ {
+ config.setProjectVersionPolicyConfig( projectVersionPolicyConfig.toString() );
+ }
config.addOriginalScmInfo( ArtifactUtils.versionlessKey( project.getGroupId(), project.getArtifactId() ),
project.getScm() );
diff --git a/maven-release-plugin/src/site/apt/usage.apt.vm b/maven-release-plugin/src/site/apt/usage.apt.vm
index 8353bc6ce..0068e9847 100644
--- a/maven-release-plugin/src/site/apt/usage.apt.vm
+++ b/maven-release-plugin/src/site/apt/usage.apt.vm
@@ -5,6 +5,7 @@
Brett Porter
John Tolentino
Robert Scholte
+ Niels Basjes
------
2011-11-10
------
@@ -151,3 +152,131 @@ mvn -Dusername=your_scm_username release:prepare
...
+-------------------
+
+* Automatically calculating the released version
+
+ The Release Plugin automatically calculates the version that is released and the next development version
+ (i.e. the next SNAPSHOT). If nothing is configured this is done by the default VersionPolicy which compares
+ and increments versions for a common java versioning scheme.
+
+ It is possible to select a different VersionPolicy by specifying its id.
+
++-------------------
+
+ ...
+
+
+
+ org.apache.maven.plugins
+ maven-release-plugin
+ ${project.version}
+
+ CCSemVerVersionPolicy
+
+
+
+ ...
+
+ ...
+
++-------------------
+
+ There are 4 VersionPolicies bundled with the Release Plugin:
+
+ * default: \
+ This compares and increments versions for a common java versioning scheme.
+
+ * OddEvenVersionPolicy: \
+ A version policy that proposes even version numbers only for releases and odd numbers for development.
+
+ * SemVerVersionPolicy: \
+ A version policy that enforce SemVer format and upgrades minor element for next development version.
+
+ * CCSemVerVersionPolicy (since 3.0.0-M7): \
+ A version policy that enforces the SemVer format and uses Conventional Commits to determine the next version.
+
+* CCSemVerVersionPolicy
+
+ The CCSemVerVersionPolicy is different in the sense that it goes beyond the project version specified in the pom.xml
+ and tries to analyze the SCM history and from the tags and commit messages it calculates the next version.
+ For this a few additional configuration options are available.
+
+ The calculation works as follows:
+
+ * It tries to find the previously released version by searching for the previous release tag.
+ Here the configured <<>> regex is used to locate and extract (the regex MUST have exactly
+ 1 capture group) the correct value.
+ If no matching tags are found the project version from the pom.xml is used as the fallback reference point.
+
+ * By default it assumes that only a patch release (i.e. <<.?.+1>>> ) is needed.
+
+ * If any of the commit messages since the previous release tag match any of the of <<>> regexes then
+ it assumes the next release is a minor release (i.e. <<.+1.0>>> ).
+
+ * If any of the commit messages since the previous release tag match any of the of <<>> regexes then
+ it assumes the next release is a major release (i.e. <<<+1.0.0>>> ).
+
+ The next development version is always calculated as the release version and then <<.?.+1-SNAPSHOT>>>.
+
+ When doing <<>> the details about the found tags, commit messages and the used patterns
+ are output to the console.
+
+ The default configuration assumes a version tag that is just the version (i.e. something like <<<1.2.3>>>) and
+ the rules from the {{{https://www.conventionalcommits.org/en/v1.0.0/}Conventional Commits v1.0.0}} are followed.
+
+ If you want a different tag format this will usually result in setting it both when creating the tag and
+ for finding it again:
+
++-------------------
+
+ v@{project.version}
+ CCSemVerVersionPolicy
+
+ ^v([0-9]+\.[0-9]+\.[0-9]+)$
+
+
++-------------------
+
+ If either the minor or major rules are specified then all default rules (both minor and major) are dropped
+ in favour of the configuration.
+
++-------+
+
+ ...
+
+
+
+ org.apache.maven.plugins
+ maven-release-plugin
+ ${project.version}
+
+ v@{project.version}
+
+ CCSemVerVersionPolicy
+
+
+
+
+
+
+
+
+
+
+ ^v([0-9]+\.[0-9]+\.[0-9]+)$
+
+ ^[a-zA-Z]+!(?:\([a-zA-Z0-9_-]+\))?: .*$
+ ^BREAKING CHANGE:.*$
+
+
+ ^feat(?:\([a-zA-Z0-9_-]+\))?: .*$
+
+
+
+
+
+ ...
+
+ ...
+
++-------+
diff --git a/maven-release-policies/maven-release-ccsemver-policy/pom.xml b/maven-release-policies/maven-release-ccsemver-policy/pom.xml
new file mode 100644
index 000000000..29b4831c5
--- /dev/null
+++ b/maven-release-policies/maven-release-ccsemver-policy/pom.xml
@@ -0,0 +1,120 @@
+
+
+
+
+ 4.0.0
+
+
+ org.apache.maven.release
+ maven-release
+ 3.0.0-M7-SNAPSHOT
+ ../../pom.xml
+
+
+ maven-release-ccsemver-policy
+
+ Maven Release Conventional Commits SemVer Policy
+
+ A version policy that enforces the SemVer format and uses Conventional Commits to determine the next version.
+
+
+
+
+
+ ${project.parent.groupId}
+ maven-release-api
+ ${project.parent.version}
+
+
+
+ org.semver
+ api
+ 0.9.33
+
+
+
+ org.apache.maven.scm
+ maven-scm-api
+ ${scmVersion}
+
+
+
+ org.slf4j
+ slf4j-api
+
+
+
+ javax.inject
+ javax.inject
+ provided
+
+
+
+ org.eclipse.sisu
+ org.eclipse.sisu.inject
+ provided
+
+
+
+ org.codehaus.plexus
+ plexus-component-annotations
+ true
+
+
+
+ junit
+ junit
+ test
+
+
+
+ org.slf4j
+ slf4j-simple
+ test
+
+
+
+
+
+
+
+ org.codehaus.modello
+ modello-maven-plugin
+
+
+
+ xpp3-reader
+ java
+
+
+
+
+ 3.0.0
+ false
+
+ src/main/mdo/ccsemver-config.mdo
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/maven-release-policies/maven-release-ccsemver-policy/src/main/java/org/apache/maven/shared/release/policy/ccsemver/CCSemVerVersionPolicy.java b/maven-release-policies/maven-release-ccsemver-policy/src/main/java/org/apache/maven/shared/release/policy/ccsemver/CCSemVerVersionPolicy.java
new file mode 100644
index 000000000..60f1722c4
--- /dev/null
+++ b/maven-release-policies/maven-release-ccsemver-policy/src/main/java/org/apache/maven/shared/release/policy/ccsemver/CCSemVerVersionPolicy.java
@@ -0,0 +1,175 @@
+package org.apache.maven.shared.release.policy.ccsemver;
+
+/*
+ * 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.
+ */
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.apache.maven.scm.ScmException;
+import org.apache.maven.shared.release.policy.version.VersionPolicy;
+import org.apache.maven.shared.release.policy.version.VersionPolicyRequest;
+import org.apache.maven.shared.release.policy.version.VersionPolicyResult;
+import org.apache.maven.shared.release.versions.VersionParseException;
+import org.eclipse.sisu.Description;
+import org.semver.Version;
+import org.semver.Version.Element;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+/**
+ * Uses SemVer combined with the tags and commit messages to increase the version.
+ */
+@Singleton
+@Named( "CCSemVerVersionPolicy" )
+@Description( "A VersionPolicy following the SemVer rules and looks at "
+ + "the commit messages following the Conventional Commits convention." )
+public class CCSemVerVersionPolicy implements VersionPolicy
+{
+ protected Logger logger = LoggerFactory.getLogger( CCSemVerVersionPolicy.class );
+
+ public VersionPolicyResult getReleaseVersion( VersionPolicyRequest request )
+ throws VersionParseException
+ {
+ VersionRules versionRules = new VersionRules( request.getConfig() );
+ try
+ {
+ return getReleaseVersion(
+ request,
+ versionRules,
+ new CommitHistory( request, versionRules ) );
+ }
+ catch ( ScmException e )
+ {
+ throw new VersionParseException( "Unable to obtain the information from the SCM history", e );
+ }
+ }
+
+ public VersionPolicyResult getReleaseVersion( VersionPolicyRequest request,
+ VersionRules versionRules,
+ CommitHistory commitHistory )
+ throws VersionParseException
+ {
+ boolean usingTag = false;
+
+ String versionString = request.getVersion(); // The current version in the pom
+ Version version;
+
+ logger.debug( "--------------------------------------------------------" );
+ logger.debug( "Determining next ReleaseVersion" );
+ logger.debug( "VersionRules: \n{}", versionRules );
+ logger.debug( "Pom version : {}", versionString );
+
+ logger.debug( "Commit History : \n{}", commitHistory );
+
+ Element maxElementSinceLastVersionTag = versionRules.getMaxElementSinceLastVersionTag( commitHistory );
+
+ List commitHistoryTags = commitHistory.getTags();
+ if ( commitHistoryTags.size() == 1 )
+ {
+ // Use the latest tag we have
+ versionString = commitHistoryTags.get( 0 );
+ usingTag = true;
+ logger.debug( "Version from tags : {}", versionString );
+ }
+ else
+ {
+ logger.debug( "Version from tags : NOT FOUND" );
+ }
+
+ if ( maxElementSinceLastVersionTag == null )
+ {
+ logger.debug( "Step from commits : No SCM version tags found" );
+ }
+ else
+ {
+ logger.debug( "Step from commits : {}", maxElementSinceLastVersionTag.name() );
+ }
+
+ try
+ {
+ version = Version.parse( versionString );
+ }
+ catch ( IllegalArgumentException e )
+ {
+ throw new VersionParseException( e.getMessage() );
+ }
+
+ logger.debug( "Current version : {}", version );
+
+
+ // If we have a version from the tag we use that + the calculated update.
+ // If only have the version from the current pom version with -SNAPSHOT removed.
+ if ( maxElementSinceLastVersionTag != null )
+ {
+ version = version.next( maxElementSinceLastVersionTag );
+ }
+
+ Version releaseVersion = version.toReleaseVersion();
+ logger.debug( "Next version : {}", releaseVersion );
+ logger.debug( "--------------------------------------------------------" );
+
+ if ( usingTag )
+ {
+ logger.info( "From SCM tag with version {} "
+ + "doing a {} version increase based on commit messages to version {}",
+ versionString, maxElementSinceLastVersionTag, releaseVersion );
+ }
+ else
+ {
+ if ( maxElementSinceLastVersionTag == null )
+ {
+ logger.info( "From project.version {} (because we did not find any valid SCM tags) "
+ + "going to version {} (because we did not find any minor/major commit messages).",
+ versionString, releaseVersion );
+ }
+ else
+ {
+ logger.info( "From project.version {} (because we did not find any valid SCM tags) "
+ + "doing a {} version increase based on commit messages to version {}",
+ versionString, maxElementSinceLastVersionTag, releaseVersion );
+ }
+ }
+
+ VersionPolicyResult result = new VersionPolicyResult();
+ result.setVersion( releaseVersion.toString() );
+ return result;
+ }
+
+ public VersionPolicyResult getDevelopmentVersion( VersionPolicyRequest request )
+ throws VersionParseException
+ {
+ Version version;
+ try
+ {
+ version = Version.parse( request.getVersion() );
+ }
+ catch ( IllegalArgumentException e )
+ {
+ throw new VersionParseException( e.getMessage() );
+ }
+
+ version = version.next( Element.PATCH );
+ VersionPolicyResult result = new VersionPolicyResult();
+ result.setVersion( version + "-SNAPSHOT" );
+ return result;
+ }
+}
diff --git a/maven-release-policies/maven-release-ccsemver-policy/src/main/java/org/apache/maven/shared/release/policy/ccsemver/CommitHistory.java b/maven-release-policies/maven-release-ccsemver-policy/src/main/java/org/apache/maven/shared/release/policy/ccsemver/CommitHistory.java
new file mode 100644
index 000000000..4ae661f93
--- /dev/null
+++ b/maven-release-policies/maven-release-ccsemver-policy/src/main/java/org/apache/maven/shared/release/policy/ccsemver/CommitHistory.java
@@ -0,0 +1,187 @@
+package org.apache.maven.shared.release.policy.ccsemver;
+
+/*
+ * 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.
+ */
+
+import org.apache.maven.scm.ChangeSet;
+import org.apache.maven.scm.ScmException;
+import org.apache.maven.scm.ScmFileSet;
+import org.apache.maven.scm.command.changelog.ChangeLogScmRequest;
+import org.apache.maven.scm.command.changelog.ChangeLogScmResult;
+import org.apache.maven.scm.provider.ScmProvider;
+import org.apache.maven.scm.repository.ScmRepository;
+import org.apache.maven.shared.release.policy.version.VersionPolicyRequest;
+import org.apache.maven.shared.release.versions.VersionParseException;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.stream.Collectors;
+
+/**
+ * Helper class to manage the commit history of the SCM repository.
+ */
+public class CommitHistory
+{
+ private final List changes = new ArrayList<>();
+ private final List tags = new ArrayList<>();
+ private String string;
+
+ public List getChanges()
+ {
+ return changes;
+ }
+
+ public void addChanges( String change )
+ {
+ this.changes.add( change );
+ }
+
+ public void addChanges( List changes )
+ {
+ this.changes.addAll( changes );
+ }
+
+ public List getTags()
+ {
+ return tags;
+ }
+
+ public void addTags( List tags )
+ {
+ if ( tags != null )
+ {
+ tags.forEach( this::addTags );
+ }
+ }
+
+ public void addTags( String tag )
+ {
+ if ( tag != null && !tag.isEmpty() )
+ {
+ this.tags.add( tag );
+ }
+ }
+
+ public String getLastVersionTag()
+ {
+ if ( tags.size() != 1 )
+ {
+ return null;
+ }
+ return tags.get( 0 );
+ }
+
+ public CommitHistory()
+ {
+ // Default constructor which results in an empty history.
+ }
+
+ public CommitHistory( VersionPolicyRequest request, VersionRules versionRules )
+ throws ScmException, VersionParseException
+ {
+ ScmRepository scmRepository = request.getScmRepository();
+ ScmProvider scmProvider = request.getScmProvider();
+ String workingDirectory = request.getWorkingDirectory();
+
+ if ( scmRepository == null || scmProvider == null || workingDirectory == null )
+ {
+ // We do not have a commit history so the changes and tags will remain empty
+ return;
+ }
+
+ ChangeLogScmRequest changeLogRequest = new ChangeLogScmRequest(
+ scmRepository,
+ new ScmFileSet( new File( workingDirectory ) )
+ );
+
+ List logLines = new ArrayList<>();
+
+ int limit = 0;
+ while ( getTags().isEmpty() )
+ {
+ limit += 100; // Read the repository in incremental steps of 100
+ changeLogRequest.setLimit( null );
+ changeLogRequest.setLimit( limit );
+ changes.clear();
+
+ ChangeLogScmResult changeLog = scmProvider.changeLog( changeLogRequest );
+
+ logLines.clear();
+ logLines.add( "Commit history:" );
+ for ( ChangeSet changeSet : changeLog.getChangeLog().getChangeSets() )
+ {
+ List changeSetTags = changeSet.getTags();
+ logLines.add( "-- Comment: \"" + changeSet.getComment() + "\"" );
+ logLines.add( " Tags : " + changeSetTags );
+ List versionTags = changeSetTags
+ .stream()
+ .map( tag ->
+ {
+ Matcher matcher = versionRules.getTagPattern().matcher( tag );
+ if ( matcher.find() )
+ {
+ return matcher.group( 1 );
+ }
+ return null;
+ }
+ )
+ .filter( Objects::nonNull )
+ .collect( Collectors.toList() );
+
+ if ( !versionTags.isEmpty() )
+ {
+ // Found the previous release tag
+ if ( versionTags.size() > 1 )
+ {
+ throw new VersionParseException( "Most recent commit with tags has multiple version tags: "
+ + versionTags );
+ }
+ logLines.add( "-- Version tags: " + versionTags );
+ addTags( versionTags );
+ break; // We have the last version tag
+ }
+ else
+ {
+ addChanges( changeSet.getComment() );
+ }
+ }
+ if ( changeLog.getChangeLog().getChangeSets().size() < limit )
+ {
+ // Apparently there are simply no more commits.
+ break;
+ }
+ }
+
+ StringBuilder sb = new StringBuilder();
+ for ( String logLine: logLines )
+ {
+ sb.append( logLine ).append( '\n' );
+ }
+ string = sb.toString();
+ }
+
+ @Override
+ public String toString()
+ {
+ return string;
+ }
+}
diff --git a/maven-release-policies/maven-release-ccsemver-policy/src/main/java/org/apache/maven/shared/release/policy/ccsemver/VersionRules.java b/maven-release-policies/maven-release-ccsemver-policy/src/main/java/org/apache/maven/shared/release/policy/ccsemver/VersionRules.java
new file mode 100644
index 000000000..0c005a581
--- /dev/null
+++ b/maven-release-policies/maven-release-ccsemver-policy/src/main/java/org/apache/maven/shared/release/policy/ccsemver/VersionRules.java
@@ -0,0 +1,175 @@
+package org.apache.maven.shared.release.policy.ccsemver;
+
+/*
+ * 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.
+ */
+
+import org.apache.maven.shared.release.policy.ccsemver.config.ProjectVersionPolicyConfig;
+import org.apache.maven.shared.release.policy.ccsemver.config.io.xpp3.CCSemverVersionPolicyConfigXpp3Reader;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+import org.semver.Version;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+/**
+ * The set of rules that determine from the commit history what the next version should be.
+ */
+public class VersionRules
+{
+ private static final Logger LOGGER = LoggerFactory.getLogger( VersionRules.class );
+
+ private final Pattern tagPattern;
+
+ private final List majorUpdatePatterns = new ArrayList<>();
+ private final List minorUpdatePatterns = new ArrayList<>();
+
+ public VersionRules( String config )
+ {
+ int patternFlags = Pattern.MULTILINE | Pattern.DOTALL | Pattern.UNIX_LINES;
+
+ // The default assumes then entire tag is what we need
+ String tagRegex = "^(\\d+\\.\\d+\\.\\d+)$";
+
+ // https://www.conventionalcommits.org/en/v1.0.0/
+ majorUpdatePatterns.add( Pattern.compile( "^[a-zA-Z]+!(?:\\([a-zA-Z\\d_-]+\\))?: .*$", patternFlags ) );
+ majorUpdatePatterns.add( Pattern.compile( "^BREAKING CHANGE:.*$", patternFlags ) );
+ minorUpdatePatterns.add( Pattern.compile( "^feat(?:\\([a-zA-Z\\d_-]+\\))?: .*$", patternFlags ) );
+
+ if ( config != null && !config.trim().isEmpty() )
+ {
+ ByteArrayInputStream inputStream = new ByteArrayInputStream( config.getBytes( UTF_8 ) );
+ CCSemverVersionPolicyConfigXpp3Reader configReader = new CCSemverVersionPolicyConfigXpp3Reader();
+ try
+ {
+ ProjectVersionPolicyConfig semverConfig = configReader.read( inputStream );
+
+ String semverConfigVersionTag = semverConfig.getVersionTag();
+ if ( semverConfigVersionTag != null && !semverConfigVersionTag.trim().isEmpty() )
+ {
+ tagRegex = semverConfigVersionTag;
+ }
+
+ if ( !semverConfig.getMajorRules().isEmpty() || !semverConfig.getMinorRules().isEmpty() )
+ {
+ majorUpdatePatterns.clear();
+ for ( String majorRule : semverConfig.getMajorRules() )
+ {
+ majorUpdatePatterns.add( Pattern.compile( majorRule, patternFlags ) );
+ }
+ minorUpdatePatterns.clear();
+ for ( String minorRule : semverConfig.getMinorRules() )
+ {
+ minorUpdatePatterns.add( Pattern.compile( minorRule, patternFlags ) );
+ }
+ }
+ }
+ catch ( IOException | XmlPullParserException e )
+ {
+ throw new IllegalArgumentException( "Unable to load the CCSemverVersionPolicyConfig: ", e );
+ }
+ }
+ tagPattern = Pattern.compile( tagRegex, Pattern.MULTILINE );
+ }
+
+ public Version.Element getMaxElementSinceLastVersionTag( CommitHistory commitHistory )
+ {
+ boolean needMinorUpdate = false;
+ for ( String change : commitHistory.getChanges() )
+ {
+ if ( isMajorUpdate( change ) )
+ {
+ LOGGER.debug( "MAJOR: \"{}\"", change );
+ return Version.Element.MAJOR;
+ }
+ else
+ if ( isMinorUpdate( change ) )
+ {
+ LOGGER.debug( "MINOR: \"{}\"", change );
+ needMinorUpdate = true;
+ }
+ }
+
+ if ( needMinorUpdate )
+ {
+ return Version.Element.MINOR;
+ }
+ if ( commitHistory.getLastVersionTag() != null )
+ {
+ LOGGER.debug( "PATCH: Tag {}", commitHistory.getLastVersionTag() );
+ return Version.Element.PATCH;
+ }
+ return null;
+ }
+
+ public boolean isMajorUpdate( String input )
+ {
+ return matchesAny( majorUpdatePatterns, input );
+ }
+
+ public boolean isMinorUpdate( String input )
+ {
+ return matchesAny( minorUpdatePatterns, input );
+ }
+
+ private boolean matchesAny( List patterns, String input )
+ {
+ for ( Pattern pattern : patterns )
+ {
+ Matcher matcher = pattern.matcher( input );
+ if ( matcher.find() )
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public Pattern getTagPattern()
+ {
+ return tagPattern;
+ }
+
+ @Override
+ public String toString()
+ {
+ StringBuilder result = new StringBuilder();
+ result.append( "Conventional Commits config:\n" );
+ result.append( " VersionTag:\n" );
+ result.append( " >>>" ).append( tagPattern ).append( "<<<\n" );
+ result.append( " MajorRules:\n" );
+ for ( Pattern majorUpdatePattern : majorUpdatePatterns )
+ {
+ result.append( " >>>" ).append( majorUpdatePattern ).append( "<<<\n" );
+ }
+ result.append( " Minor Rules:\n" );
+ for ( Pattern minorUpdatePattern : minorUpdatePatterns )
+ {
+ result.append( " >>>" ).append( minorUpdatePattern ).append( "<<<\n" );
+ }
+ return result.toString();
+ }
+}
diff --git a/maven-release-policies/maven-release-ccsemver-policy/src/main/mdo/ccsemver-config.mdo b/maven-release-policies/maven-release-ccsemver-policy/src/main/mdo/ccsemver-config.mdo
new file mode 100644
index 000000000..578604b80
--- /dev/null
+++ b/maven-release-policies/maven-release-ccsemver-policy/src/main/mdo/ccsemver-config.mdo
@@ -0,0 +1,77 @@
+
+
+
+
+ ccsemver-config
+ CCSemverVersionPolicyConfig
+
+ The config for the CCSemverVersionPolicy.
+
+
+
+ package
+ org.apache.maven.shared.release.policy.ccsemver.config
+
+
+
+
+
+ ProjectVersionPolicyConfig
+ 1.0.0+
+
+
+
+ versionTag
+ 1.1.0+
+ String
+
+ The regex with exactly 1 capture group that extracts the version from the SCM tag.
+
+
+
+ minorRules
+ 1.1.0+
+ List
+
+ String
+ *
+
+
+ The list of regexes that must be classified as "minor" version changes.
+
+
+
+ majorRules
+ 1.1.0+
+ List
+
+ String
+ *
+
+
+ The list of regexes that must be classified as "major" version changes.
+
+
+
+
+
+
+
diff --git a/maven-release-policies/maven-release-ccsemver-policy/src/site/site.xml b/maven-release-policies/maven-release-ccsemver-policy/src/site/site.xml
new file mode 100644
index 000000000..220ecbb57
--- /dev/null
+++ b/maven-release-policies/maven-release-ccsemver-policy/src/site/site.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/maven-release-policies/maven-release-ccsemver-policy/src/test/java/org/apache/maven/shared/release/policy/ccsemver/CCSemVerVersionPolicyTest.java b/maven-release-policies/maven-release-ccsemver-policy/src/test/java/org/apache/maven/shared/release/policy/ccsemver/CCSemVerVersionPolicyTest.java
new file mode 100644
index 000000000..4c90f5c27
--- /dev/null
+++ b/maven-release-policies/maven-release-ccsemver-policy/src/test/java/org/apache/maven/shared/release/policy/ccsemver/CCSemVerVersionPolicyTest.java
@@ -0,0 +1,160 @@
+package org.apache.maven.shared.release.policy.ccsemver;
+
+/*
+ * 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.
+ */
+
+import org.apache.maven.shared.release.policy.version.VersionPolicyRequest;
+import org.apache.maven.shared.release.versions.VersionParseException;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+public class CCSemVerVersionPolicyTest
+{
+
+ private void verifyNextVersion(
+ String versionRulesConfig,
+ String pomVersion,
+ String expectedReleaseVersion,
+ String expectedDevelopmentVersion,
+ String comment,
+ String... tags
+ ) throws VersionParseException
+ {
+ VersionPolicyRequest request = new VersionPolicyRequest();
+ MockScmProvider provider = new MockScmProvider(comment, tags);
+ request.setScmProvider( provider );
+ request.setScmRepository( new MockScmRepository( provider ) );
+ request.setWorkingDirectory( "/tmp" );
+ request.setConfig( versionRulesConfig );
+ request.setVersion( pomVersion );
+
+ String suggestedVersion = new CCSemVerVersionPolicy().getReleaseVersion( request ).getVersion();
+ assertEquals( expectedReleaseVersion, suggestedVersion );
+
+ request.setVersion( suggestedVersion );
+ String suggestedDevelopmentVersion = new CCSemVerVersionPolicy().getDevelopmentVersion( request ).getVersion();
+ assertEquals( expectedDevelopmentVersion, suggestedDevelopmentVersion );
+ }
+
+ private void verifyNextVersionMustFail(
+ String versionRulesConfig,
+ String pomVersion,
+ String comment,
+ String... tags
+ )
+ {
+ try
+ {
+ verifyNextVersion( versionRulesConfig, pomVersion, "ignore", "ignore", comment, tags );
+ }
+ catch ( VersionParseException vpe )
+ {
+ // Success !
+ return;
+ }
+ fail( "Should have failed" );
+ }
+
+ @Test
+ public void testDefaultVersionRules() throws VersionParseException
+ {
+ String normal = "Did something";
+ String patch = "fix(core): Another fix.";
+ String minor = "feat(core): New thingy.";
+ String major = "fix!(core): Breaking improvement";
+
+ String versionRulesConfig = "";
+ verifyNextVersion( versionRulesConfig, "1.1.1-SNAPSHOT", "1.1.1", "1.1.2-SNAPSHOT", normal ); // No Tag - No CC Comments
+ verifyNextVersion( versionRulesConfig, "1.1.1-SNAPSHOT", "1.1.1", "1.1.2-SNAPSHOT", patch ); // No Tag - Patch Comments
+ verifyNextVersion( versionRulesConfig, "1.1.1-SNAPSHOT", "1.2.0", "1.2.1-SNAPSHOT", minor ); // No Tag - Minor Comments
+ verifyNextVersion( versionRulesConfig, "1.1.1-SNAPSHOT", "2.0.0", "2.0.1-SNAPSHOT", major ); // No Tag - Major Comments
+
+ // The default tag pattern will look at the "2.3.4" tag
+ verifyNextVersion( versionRulesConfig, "1.1.1-SNAPSHOT", "2.3.5", "2.3.6-SNAPSHOT", normal, "2.3.4", "v3.4.5" ); // Tag - No CC Comments
+ verifyNextVersion( versionRulesConfig, "1.1.1-SNAPSHOT", "2.3.5", "2.3.6-SNAPSHOT", patch, "2.3.4", "v3.4.5" ); // Tag - Patch Comments
+ verifyNextVersion( versionRulesConfig, "1.1.1-SNAPSHOT", "2.4.0", "2.4.1-SNAPSHOT", minor, "2.3.4", "v3.4.5" ); // Tag - Minor Comments
+ verifyNextVersion( versionRulesConfig, "1.1.1-SNAPSHOT", "3.0.0", "3.0.1-SNAPSHOT", major, "2.3.4", "v3.4.5" ); // Tag - Major Comments
+
+ // Too many valid version tags on one commit
+ verifyNextVersionMustFail( versionRulesConfig, "1.1.1-SNAPSHOT", major, "1.1.1", "2.2.2" );
+ }
+
+ @Test
+ public void testCustomTagPattern() throws VersionParseException {
+ String normal = "Did something";
+ String patch = "fix(core): Another fix.";
+ String minor = "feat(core): New thingy.";
+ String major = "fix!(core): Breaking improvement";
+
+ String versionRulesConfig = ""
+ + ""
+ + "^v([0-9]+\\.[0-9]+\\.[0-9]+)$"
+ + "" +
+ "";
+
+ verifyNextVersion( versionRulesConfig, "1.1.1-SNAPSHOT", "1.1.1", "1.1.2-SNAPSHOT", normal ); // No Tag - No CC Comments
+ verifyNextVersion( versionRulesConfig, "1.1.1-SNAPSHOT", "1.1.1", "1.1.2-SNAPSHOT", patch ); // No Tag - Patch Comments
+ verifyNextVersion( versionRulesConfig, "1.1.1-SNAPSHOT", "1.2.0", "1.2.1-SNAPSHOT", minor ); // No Tag - Minor Comments
+ verifyNextVersion( versionRulesConfig, "1.1.1-SNAPSHOT", "2.0.0", "2.0.1-SNAPSHOT", major ); // No Tag - Major Comments
+
+ // The custom tag pattern will look at the "v3.4.5" tag
+ verifyNextVersion( versionRulesConfig, "1.1.1-SNAPSHOT", "3.4.6", "3.4.7-SNAPSHOT", normal, "2.3.4", "v3.4.5" ); // Tag - No CC Comments
+ verifyNextVersion( versionRulesConfig, "1.1.1-SNAPSHOT", "3.4.6", "3.4.7-SNAPSHOT", patch, "2.3.4", "v3.4.5" ); // Tag - Patch Comments
+ verifyNextVersion( versionRulesConfig, "1.1.1-SNAPSHOT", "3.5.0", "3.5.1-SNAPSHOT", minor, "2.3.4", "v3.4.5" ); // Tag - Minor Comments
+ verifyNextVersion( versionRulesConfig, "1.1.1-SNAPSHOT", "4.0.0", "4.0.1-SNAPSHOT", major, "2.3.4", "v3.4.5" ); // Tag - Major Comments
+
+ // Too many valid version tags on one commit
+ verifyNextVersionMustFail( versionRulesConfig, "1.1.1-SNAPSHOT", minor, "v1.1.1", "v2.2.2" );
+ }
+
+ @Test
+ public void testCustomVersionRules() throws VersionParseException {
+ String normal = "This is a different commit.";
+ String patch = "This is a No Change commit.";
+ String minor = "This is a Nice Change commit.";
+ String major = "This is a Big Change commit.";
+
+ String versionRulesConfig = ""
+ + ""
+ + "^The awesome ([0-9]+\\.[0-9]+\\.[0-9]+) release$"
+ + ""
+ + "^.*Big Change.*$"
+ + ""
+ + ""
+ + "^.*Nice Change.*$"
+ + ""
+ + "" +
+ "";
+
+ verifyNextVersion( versionRulesConfig, "1.1.1-SNAPSHOT", "1.1.1", "1.1.2-SNAPSHOT", normal ); // No Tag - No CC Comments
+ verifyNextVersion( versionRulesConfig, "1.1.1-SNAPSHOT", "1.1.1", "1.1.2-SNAPSHOT", patch ); // No Tag - Patch Comments
+ verifyNextVersion( versionRulesConfig, "1.1.1-SNAPSHOT", "1.2.0", "1.2.1-SNAPSHOT", minor ); // No Tag - Minor Comments
+ verifyNextVersion( versionRulesConfig, "1.1.1-SNAPSHOT", "2.0.0", "2.0.1-SNAPSHOT", major ); // No Tag - Major Comments
+ verifyNextVersion( versionRulesConfig, "1.1.1-SNAPSHOT", "3.4.6", "3.4.7-SNAPSHOT", normal, "2.3.4", "The awesome 3.4.5 release" ); // Tag - No CC Comments
+ verifyNextVersion( versionRulesConfig, "1.1.1-SNAPSHOT", "3.4.6", "3.4.7-SNAPSHOT", patch, "2.3.4", "The awesome 3.4.5 release" ); // Tag - Patch Comments
+ verifyNextVersion( versionRulesConfig, "1.1.1-SNAPSHOT", "3.5.0", "3.5.1-SNAPSHOT", minor, "2.3.4", "The awesome 3.4.5 release" ); // Tag - Minor Comments
+ verifyNextVersion( versionRulesConfig, "1.1.1-SNAPSHOT", "4.0.0", "4.0.1-SNAPSHOT", major, "2.3.4", "The awesome 3.4.5 release" ); // Tag - Major Comments
+
+ // Too many valid version tags on one commit
+ verifyNextVersionMustFail( versionRulesConfig, "1.1.1-SNAPSHOT", minor, "The awesome 1.1.1 release", "The awesome 2.2.2 release" );
+ }
+
+}
diff --git a/maven-release-policies/maven-release-ccsemver-policy/src/test/java/org/apache/maven/shared/release/policy/ccsemver/MockScmProvider.java b/maven-release-policies/maven-release-ccsemver-policy/src/test/java/org/apache/maven/shared/release/policy/ccsemver/MockScmProvider.java
new file mode 100644
index 000000000..6b18e1872
--- /dev/null
+++ b/maven-release-policies/maven-release-ccsemver-policy/src/test/java/org/apache/maven/shared/release/policy/ccsemver/MockScmProvider.java
@@ -0,0 +1,105 @@
+package org.apache.maven.shared.release.policy.ccsemver;
+/*
+ * 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.
+ */
+
+import org.apache.maven.scm.ChangeSet;
+import org.apache.maven.scm.ScmResult;
+import org.apache.maven.scm.command.changelog.ChangeLogScmRequest;
+import org.apache.maven.scm.command.changelog.ChangeLogScmResult;
+import org.apache.maven.scm.command.changelog.ChangeLogSet;
+import org.apache.maven.scm.provider.AbstractScmProvider;
+import org.apache.maven.scm.provider.ScmProviderRepository;
+
+import java.util.Arrays;
+import java.util.Date;
+
+public class MockScmProvider
+ extends AbstractScmProvider
+{
+ String comment;
+ String[] tags;
+
+ public MockScmProvider( String comment, String... tags )
+ {
+ this.comment = comment;
+ this.tags = tags;
+ }
+
+ @Override
+ public String getScmType()
+ {
+ return "dummy";
+ }
+
+ @Override
+ public ScmProviderRepository makeProviderScmRepository( String scmSpecificUrl, char delimiter )
+ {
+ ScmProviderRepository repository = new ScmProviderRepository(){};
+ repository.setUser( "someone" );
+ repository.setPassword( "secret" );
+ repository.setPushChanges( false );
+ return repository;
+ }
+
+ private ChangeSet changeSet(String comment, String... tags) {
+ ChangeSet changeSet = new ChangeSet();
+ changeSet.setComment( comment );
+ changeSet.setAuthor( "Someone " );
+ changeSet.setTags( Arrays.asList( tags ) );
+ return changeSet;
+ }
+
+ @Override
+ public ChangeLogScmResult changeLog(ChangeLogScmRequest request) {
+ Date from = new Date( 39817800000L );
+ Date to = new Date( 1644768534785L );
+ ChangeLogSet changeLogSet = new ChangeLogSet(
+ Arrays.asList(
+ changeSet( "Commit 19" ),
+ changeSet( "Commit 18" ),
+ changeSet( "Commit 17" ),
+ changeSet( "Commit 16" ),
+ changeSet( "Commit 15", "tag 1", "tag 2" ),
+ changeSet( comment ), // The comment that should make the difference
+ changeSet( "Commit 13" ),
+ changeSet( "Commit 12", "tag 3" ),
+ changeSet( "Commit 11" ),
+ changeSet( "Commit 10" ),
+ changeSet( "Commit 9" ),
+ changeSet( "Commit 8" ),
+ changeSet( "Commit 7" ),
+ changeSet( "Commit 6", "tag 4" ),
+ changeSet( "Commit 5" ),
+ changeSet( "Commit 4" ),
+ changeSet( "Commit 3" ),
+ changeSet( "Commit 2", tags ), // The first tag that looks like a version
+ changeSet( "Commit 1" ),
+ changeSet( "Commit 0" )
+ ), from, to
+ );
+
+ ScmResult scmResult = new ScmResult(
+ "No command",
+ "Special for CCSemVer testing",
+ "No command output",
+ true
+ );
+ return new ChangeLogScmResult( changeLogSet, scmResult );
+ }
+}
diff --git a/maven-release-policies/maven-release-ccsemver-policy/src/test/java/org/apache/maven/shared/release/policy/ccsemver/MockScmRepository.java b/maven-release-policies/maven-release-ccsemver-policy/src/test/java/org/apache/maven/shared/release/policy/ccsemver/MockScmRepository.java
new file mode 100644
index 000000000..5a6179afa
--- /dev/null
+++ b/maven-release-policies/maven-release-ccsemver-policy/src/test/java/org/apache/maven/shared/release/policy/ccsemver/MockScmRepository.java
@@ -0,0 +1,30 @@
+package org.apache.maven.shared.release.policy.ccsemver;
+
+/*
+ * 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.
+ */
+
+import org.apache.maven.scm.repository.ScmRepository;
+
+public class MockScmRepository extends ScmRepository
+{
+ public MockScmRepository( MockScmProvider provider )
+ {
+ super( "dummy", provider.makeProviderScmRepository( "dummy", ':' ) );
+ }
+}
diff --git a/maven-release-policies/maven-release-ccsemver-policy/src/test/java/org/apache/maven/shared/release/policy/ccsemver/NextVersionCalculationTest.java b/maven-release-policies/maven-release-ccsemver-policy/src/test/java/org/apache/maven/shared/release/policy/ccsemver/NextVersionCalculationTest.java
new file mode 100644
index 000000000..0a2f80c7f
--- /dev/null
+++ b/maven-release-policies/maven-release-ccsemver-policy/src/test/java/org/apache/maven/shared/release/policy/ccsemver/NextVersionCalculationTest.java
@@ -0,0 +1,143 @@
+package org.apache.maven.shared.release.policy.ccsemver;
+
+/*
+ * 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.
+ */
+
+import org.apache.maven.shared.release.policy.version.VersionPolicyRequest;
+import org.apache.maven.shared.release.versions.VersionParseException;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.semver.Version;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.semver.Version.Element.MAJOR;
+import static org.semver.Version.Element.MINOR;
+import static org.semver.Version.Element.PATCH;
+
+public class NextVersionCalculationTest
+{
+
+ private CCSemVerVersionPolicy versionPolicy;
+ private static final VersionRules DEFAULT_VERSION_RULES = new VersionRules( null );
+
+ @Before
+ public void setUp()
+ {
+ versionPolicy = new CCSemVerVersionPolicy();
+ }
+
+ @After
+ public void tearDown()
+ {
+ versionPolicy = null;
+ }
+
+ private void assertNextVersion( VersionRules versionRules, String input, Version.Element element )
+ {
+ switch (element) {
+ case MAJOR:
+ assertTrue( versionRules.isMajorUpdate( input ) );
+ // We do not care about minor and patch
+ break;
+ case MINOR:
+ assertFalse( versionRules.isMajorUpdate( input ) );
+ assertTrue( versionRules.isMinorUpdate( input ) );
+ // We do not care about patch
+ break;
+ case PATCH:
+ assertFalse( versionRules.isMajorUpdate( input ) );
+ assertFalse( versionRules.isMinorUpdate( input ) );
+ break;
+ }
+ }
+
+ @Test
+ public void testMajorMinorPatchDetection()
+ {
+ VersionRules rules = DEFAULT_VERSION_RULES;
+ assertNextVersion( rules, "feat!(core): New feature.", MAJOR );
+ assertNextVersion( rules, "feat!: New feature.", MAJOR );
+ assertNextVersion( rules, "feat(core): Foo.\n\nBREAKING CHANGE: New feature.\n", MAJOR );
+ assertNextVersion( rules, "feat: Foo.\n\nBREAKING CHANGE: New feature.\n", MAJOR );
+
+ assertNextVersion( rules, "feat(core): New feature.", MINOR );
+ assertNextVersion( rules, "feat: New feature.", MINOR );
+
+ assertNextVersion( rules, "Does not match any pattern.", PATCH );
+ }
+
+ @Test
+ public void testConvertToSnapshot()
+ throws Exception
+ {
+ String suggestedVersion = versionPolicy.getDevelopmentVersion( new VersionPolicyRequest().setVersion( "1.0.0" ) )
+ .getVersion();
+
+ assertEquals( "1.0.1-SNAPSHOT", suggestedVersion );
+ }
+
+ public void verifyNextVersion(VersionRules versionRules,
+ String currentPomVersion,
+ String tag,
+ List comments,
+ String expectedNextVersion) throws VersionParseException {
+ CommitHistory commitHistory = new CommitHistory();
+ commitHistory.addTags( tag );
+ commitHistory.addChanges( comments );
+
+ assertEquals( expectedNextVersion, versionPolicy
+ .getReleaseVersion(
+ new VersionPolicyRequest().setVersion( currentPomVersion ),
+ versionRules,
+ commitHistory
+ ).getVersion() );
+ }
+
+ String patch1 = "Quick patch";
+ String patch2 = "fix(core): Another fix.";
+ String minor1 = "feat(core): New thingy.";
+ String major1 = "fix!(core): Breaking improvement" ;
+
+ List EMPTY = Collections.emptyList();
+ List MAJOR_MESSAGES = Arrays.asList( patch1, patch2, minor1, major1 );
+ List MINOR_MESSAGES = Arrays.asList( patch1, patch2, minor1 );
+ List PATCH_MESSAGES = Arrays.asList( patch1, patch2 );
+
+ @Test
+ public void testDefaultVersionRules() throws VersionParseException
+ {
+ VersionRules rules = DEFAULT_VERSION_RULES;
+ verifyNextVersion( rules, "1.2.3-SNAPSHOT", "", EMPTY, "1.2.3"); // No Tag - No CC Comments
+ verifyNextVersion( rules, "1.2.3-SNAPSHOT", "", PATCH_MESSAGES, "1.2.3"); // No Tag - Patch Comments
+ verifyNextVersion( rules, "1.2.3-SNAPSHOT", "", MINOR_MESSAGES, "1.3.0"); // No Tag - Minor Comments
+ verifyNextVersion( rules, "1.2.3-SNAPSHOT", "", MAJOR_MESSAGES, "2.0.0"); // No Tag - Major Comments
+ verifyNextVersion( rules, "1.2.3-SNAPSHOT", "2.3.4", EMPTY, "2.3.5"); // Tag - No CC Comments
+ verifyNextVersion( rules, "1.2.3-SNAPSHOT", "2.3.4", PATCH_MESSAGES, "2.3.5"); // Tag - Patch Comments
+ verifyNextVersion( rules, "1.2.3-SNAPSHOT", "2.3.4", MINOR_MESSAGES, "2.4.0"); // Tag - Minor Comments
+ verifyNextVersion( rules, "1.2.3-SNAPSHOT", "2.3.4", MAJOR_MESSAGES, "3.0.0"); // Tag - Major Comments
+ }
+
+}
diff --git a/pom.xml b/pom.xml
index 1429ac0a7..95e817e6e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -41,6 +41,7 @@
maven-release-manager
maven-release-policies/maven-release-oddeven-policy
maven-release-policies/maven-release-semver-policy
+ maven-release-policies/maven-release-ccsemver-policy
maven-release-plugin
diff --git a/src/site/apt/index.apt b/src/site/apt/index.apt
index cbdaf26c5..47e46d943 100644
--- a/src/site/apt/index.apt
+++ b/src/site/apt/index.apt
@@ -42,3 +42,5 @@ Maven Release
*----------------------------------------------------------+----------------+
| {{{./maven-release-policies/maven-release-semver-policy/}maven-release-semver-policy}} | a version policy that enforce SemVer format and upgrades minor element for next development version
*----------------------------------------------------------+----------------+
+| {{{./maven-release-policies/maven-release-ccsemver-policy/}maven-release-ccsemver-policy}} | a version policy that enforce SemVer format and upgrades major/minor/patch element for next development version depending on the commit messages since the previous release (actually tag in the SCM).
+*----------------------------------------------------------+----------------+