diff --git a/README.md b/README.md index 420c3e8..9e675e9 100644 --- a/README.md +++ b/README.md @@ -7,21 +7,60 @@ with Java 1.8+ using Git for version control. ### Usage -This plugin works together with the [Maven Release Plugin] to create +This plugin works together with the [Maven Release Plugin] to create conventional commit compliant releases for your Maven projects #### Install the Plugin - + In your main `pom.xml` file add the plugin: +```xml com.smartling.cc4j conventional-commits-maven-plugin ${version} + + + org.apache.maven.plugins + maven-release-plugin + 3.0.0-M5 + + build(release): + ci(release): open next snapshot version + build(release): publish + + +``` + +In your CI code: + +- Execute only for master|main branch +- skip builds for build(release) and ci(release) commits + +GitHub workflow: + +```yaml +jobs: + main: + ... + if: | + "!contains(github.event.head_commit.message, 'build(release)')" && + "!contains(github.event.head_commit.message, 'ci(release)')" +``` + +Gitlab: + +```yaml + only: + variables: + - '$CI_COMMIT_MESSAGE !~ /^(build|ci)\(release\):.+/' + - '$CI_COMMIT_BRANCH =~ /^(master|main)/' +``` + #### Release a Version mvn conventional-commits:version release:prepare diff --git a/conventional-commits-common/src/main/java/com/smartling/cc4j/semantic/release/common/Commit.java b/conventional-commits-common/src/main/java/com/smartling/cc4j/semantic/release/common/Commit.java index 427d2bb..b233c24 100644 --- a/conventional-commits-common/src/main/java/com/smartling/cc4j/semantic/release/common/Commit.java +++ b/conventional-commits-common/src/main/java/com/smartling/cc4j/semantic/release/common/Commit.java @@ -6,8 +6,13 @@ public class Commit { - private static final Pattern BREAKING_REGEX = Pattern.compile("^(fix|feat)!.+", Pattern.CASE_INSENSITIVE); + private static final Pattern BREAKING_REGEX = Pattern.compile( + "^((build|chore|ci|docs|fix|feat|refactor|style|test)[a-z0-9\\(\\)]*)((\\!([\\s]*:(.|\\n)*))|" + + "([\\s]*:(.|\\n)*(BREAKING(\\s|-)CHANGE)(.|\\n)*))", Pattern.CASE_INSENSITIVE); + private static final Pattern CONVENTIONAL_COMMIT_REGEX = Pattern.compile( + "^((build|chore|ci|docs|fix|feat|refactor|style|test)[a-z0-9\\(\\)]*)((\\!([\\s]*:" + + "(.|\\n)*))|([\\s]*:(.|\\n)*))", Pattern.CASE_INSENSITIVE); private final CommitAdapter commit; public Commit(CommitAdapter commit) @@ -40,30 +45,23 @@ public Optional getCommitType() return Optional.of(ConventionalCommitType.BREAKING_CHANGE); } - for (ConventionalCommitType cc : ConventionalCommitType.values()) + if (CONVENTIONAL_COMMIT_REGEX.matcher(msg).matches()) { - for (String t : cc.getCommitTypes()) - { - if (msg.startsWith(t)) + for (ConventionalCommitType cc : ConventionalCommitType.values()) { + if (ConventionalCommitType.BREAKING_CHANGE.equals(cc)) { - type = cc; - break; + continue; } - } - } - // FIXME: check for breaking change in footer -/* - for (FooterLine footerLine : commit.getFooterLines()) - { - if (footerLine.getKey().equalsIgnoreCase(ConventionalCommitType.BREAKING_CHANGE.getCommitTypes().get(0))) { - type = ConventionalCommitType.BREAKING_CHANGE; - break; + for (String t : cc.getCommitTypes()) { + if (msg.startsWith(t)) { + type = cc; + break; + } + } } } - */ - return Optional.ofNullable(type); } diff --git a/conventional-commits-common/src/main/java/com/smartling/cc4j/semantic/release/common/ConventionalCommitType.java b/conventional-commits-common/src/main/java/com/smartling/cc4j/semantic/release/common/ConventionalCommitType.java index 3c381ff..0fde99a 100644 --- a/conventional-commits-common/src/main/java/com/smartling/cc4j/semantic/release/common/ConventionalCommitType.java +++ b/conventional-commits-common/src/main/java/com/smartling/cc4j/semantic/release/common/ConventionalCommitType.java @@ -5,7 +5,7 @@ public enum ConventionalCommitType implements Comparable { - BREAKING_CHANGE(SemanticVersionChange.MAJOR, "breaking change", "!"), + BREAKING_CHANGE(SemanticVersionChange.MAJOR, "", "!"), BUILD(SemanticVersionChange.NONE, "build"), CHORE(SemanticVersionChange.MINOR, "chore"), CI(SemanticVersionChange.NONE, "ci"), @@ -13,12 +13,13 @@ public enum ConventionalCommitType implements Comparable FIX(SemanticVersionChange.PATCH, "fix"), FEAT(SemanticVersionChange.MINOR, "feat"), REFACTOR(SemanticVersionChange.MINOR, "refactor"), + STYLE(SemanticVersionChange.NONE, "style"), TEST(SemanticVersionChange.NONE, "test"); private final List commitTypes; private final SemanticVersionChange changeType; - ConventionalCommitType(SemanticVersionChange change, String... commitTypes) + ConventionalCommitType(final SemanticVersionChange change, final String... commitTypes) { this.commitTypes = Arrays.asList(commitTypes); this.changeType = change; diff --git a/conventional-commits-common/src/main/java/com/smartling/cc4j/semantic/release/common/GitCommitAdapter.java b/conventional-commits-common/src/main/java/com/smartling/cc4j/semantic/release/common/GitCommitAdapter.java index 3a5edec..75876d5 100644 --- a/conventional-commits-common/src/main/java/com/smartling/cc4j/semantic/release/common/GitCommitAdapter.java +++ b/conventional-commits-common/src/main/java/com/smartling/cc4j/semantic/release/common/GitCommitAdapter.java @@ -8,7 +8,7 @@ public class GitCommitAdapter implements CommitAdapter { private final RevCommit commit; - GitCommitAdapter(RevCommit commit) + GitCommitAdapter(final RevCommit commit) { Objects.requireNonNull(commit, "commit cannot be null"); this.commit = commit; diff --git a/conventional-commits-common/src/main/java/com/smartling/cc4j/semantic/release/common/GitConventionalVersioning.java b/conventional-commits-common/src/main/java/com/smartling/cc4j/semantic/release/common/GitConventionalVersioning.java index 441daa6..a491c75 100644 --- a/conventional-commits-common/src/main/java/com/smartling/cc4j/semantic/release/common/GitConventionalVersioning.java +++ b/conventional-commits-common/src/main/java/com/smartling/cc4j/semantic/release/common/GitConventionalVersioning.java @@ -34,12 +34,12 @@ public SemanticVersionChange getNextVersionChangeType() throws ScmApiException, { try { - Iterable commits = logHandler().getCommitsSinceLastTag(); - SemanticVersionChangeResolver resolver = semanticVersionChangeResolver(); + final Iterable commits = logHandler().getCommitsSinceLastTag(); + final SemanticVersionChangeResolver resolver = semanticVersionChangeResolver(); return resolver.resolveChange(commits); } - catch (GitAPIException e) + catch (final GitAPIException e) { throw new ScmApiException("Git operation failed", e); } @@ -48,7 +48,7 @@ public SemanticVersionChange getNextVersionChangeType() throws ScmApiException, @Override public SemanticVersion getNextVersion(SemanticVersion currentVersion) throws IOException, ScmApiException { - SemanticVersionChange change = this.getNextVersionChangeType(); + final SemanticVersionChange change = this.getNextVersionChangeType(); return currentVersion.nextVersion(change); } } diff --git a/conventional-commits-common/src/main/java/com/smartling/cc4j/semantic/release/common/LogHandler.java b/conventional-commits-common/src/main/java/com/smartling/cc4j/semantic/release/common/LogHandler.java index 3dcee96..a5be0a3 100644 --- a/conventional-commits-common/src/main/java/com/smartling/cc4j/semantic/release/common/LogHandler.java +++ b/conventional-commits-common/src/main/java/com/smartling/cc4j/semantic/release/common/LogHandler.java @@ -22,7 +22,7 @@ public class LogHandler private final Repository repository; private final Git git; - public LogHandler(Repository repository) + public LogHandler(final Repository repository) { Objects.requireNonNull(repository, "repository cannot be null"); this.repository = repository; @@ -31,10 +31,10 @@ public LogHandler(Repository repository) RevCommit getLastTaggedCommit() throws IOException, GitAPIException { - List tags = git.tagList().call(); - List peeledTags = tags.stream().map(t -> repository.peel(t).getPeeledObjectId()).collect(Collectors.toList()); - PlotWalk walk = new PlotWalk(repository); - RevCommit start = walk.parseCommit(repository.resolve("HEAD")); + final List tags = git.tagList().call(); + final List peeledTags = tags.stream().map(t -> repository.peel(t).getPeeledObjectId()).collect(Collectors.toList()); + final PlotWalk walk = new PlotWalk(repository); + final RevCommit start = walk.parseCommit(repository.resolve("HEAD")); walk.markStart(start); @@ -55,8 +55,8 @@ RevCommit getLastTaggedCommit() throws IOException, GitAPIException public Iterable getCommitsSinceLastTag() throws IOException, GitAPIException { - ObjectId start = repository.resolve("HEAD"); - RevCommit lastCommit = this.getLastTaggedCommit(); + final ObjectId start = repository.resolve("HEAD"); + final RevCommit lastCommit = this.getLastTaggedCommit(); if (lastCommit == null) { diff --git a/conventional-commits-common/src/main/java/com/smartling/cc4j/semantic/release/common/SemanticVersion.java b/conventional-commits-common/src/main/java/com/smartling/cc4j/semantic/release/common/SemanticVersion.java index bbf5546..5aed1d2 100644 --- a/conventional-commits-common/src/main/java/com/smartling/cc4j/semantic/release/common/SemanticVersion.java +++ b/conventional-commits-common/src/main/java/com/smartling/cc4j/semantic/release/common/SemanticVersion.java @@ -5,11 +5,13 @@ public final class SemanticVersion { + public static final String VERSION_SUFFIX_SNAPSHOT = "-SNAPSHOT"; + private final Integer major; private final Integer minor; private final Integer patch; - public SemanticVersion(int major, int minor, int patch) + public SemanticVersion(final int major, final int minor, final int patch) { if (major < 0 || minor < 0 || patch < 0) throw new IllegalArgumentException("versions can only contain positive integers"); @@ -20,7 +22,7 @@ public SemanticVersion(int major, int minor, int patch) } @Override - public boolean equals(Object o) + public boolean equals(final Object o) { if (this == o) { @@ -55,9 +57,9 @@ public int getPatch() return patch; } - public SemanticVersion nextVersion(SemanticVersionChange change) + public SemanticVersion nextVersion(final SemanticVersionChange change) { - SemanticVersion nextVersion; + final SemanticVersion nextVersion; switch (change) { @@ -68,8 +70,6 @@ public SemanticVersion nextVersion(SemanticVersionChange change) nextVersion = new SemanticVersion(major, minor + 1, 0); break; case PATCH: - nextVersion = new SemanticVersion(major, minor, patch + 1); - break; case NONE: nextVersion = new SemanticVersion(major, minor, patch); break; @@ -85,10 +85,10 @@ public String toString() return toString(major, minor, patch); } - public static SemanticVersion parse(String version) + public static SemanticVersion parse(final String version) { Objects.requireNonNull(version, "version required"); - String[] parts = version.split("\\."); + final String[] parts = version.replace(VERSION_SUFFIX_SNAPSHOT, "").split("\\."); if (parts.length != 3) throw new IllegalArgumentException("Invalid semantic version: " + version); @@ -100,8 +100,13 @@ public static SemanticVersion parse(String version) ); } - private static String toString(int major, int minor, int patch) + private static String toString(final int major, final int minor, final int patch) { return String.format(Locale.US, "%d.%d.%d", major, minor, patch); } + + public String getDevelopmentVersionString() + { + return this.toString() + VERSION_SUFFIX_SNAPSHOT; + } } diff --git a/conventional-commits-common/src/main/java/com/smartling/cc4j/semantic/release/common/SimpleSemanticVersionChangeResolver.java b/conventional-commits-common/src/main/java/com/smartling/cc4j/semantic/release/common/SimpleSemanticVersionChangeResolver.java index 382a6a4..3c76705 100644 --- a/conventional-commits-common/src/main/java/com/smartling/cc4j/semantic/release/common/SimpleSemanticVersionChangeResolver.java +++ b/conventional-commits-common/src/main/java/com/smartling/cc4j/semantic/release/common/SimpleSemanticVersionChangeResolver.java @@ -10,16 +10,16 @@ public class SimpleSemanticVersionChangeResolver implements SemanticVersionChangeResolver { @Override - public SemanticVersionChange resolveChange(Iterable commits) + public SemanticVersionChange resolveChange(final Iterable commits) { Objects.requireNonNull(commits, "commits may not be null"); - List commitList = new ArrayList<>(); + final List commitList = new ArrayList<>(); commits.iterator().forEachRemaining(c -> commitList.add(new Commit(new GitCommitAdapter(c)))); SemanticVersionChange change = SemanticVersionChange.NONE; - for (Commit c : commitList) + for (final Commit c : commitList) { - Optional commitType = c.getCommitType(); + final Optional commitType = c.getCommitType(); if (commitType.isPresent()) { if (SemanticVersionChange.MAJOR.equals(commitType.get().getChangeType())) diff --git a/conventional-commits-common/src/main/java/com/smartling/cc4j/semantic/release/common/scm/ScmApiException.java b/conventional-commits-common/src/main/java/com/smartling/cc4j/semantic/release/common/scm/ScmApiException.java index 510f0ef..d00b7bb 100644 --- a/conventional-commits-common/src/main/java/com/smartling/cc4j/semantic/release/common/scm/ScmApiException.java +++ b/conventional-commits-common/src/main/java/com/smartling/cc4j/semantic/release/common/scm/ScmApiException.java @@ -2,7 +2,7 @@ public class ScmApiException extends Exception { - public ScmApiException(String message, Throwable cause) + public ScmApiException(final String message, final Throwable cause) { super(message, cause); } diff --git a/conventional-commits-common/src/test/java/com/smartling/cc4j/semantic/release/common/CommitTest.java b/conventional-commits-common/src/test/java/com/smartling/cc4j/semantic/release/common/CommitTest.java index a5f3b6f..9884199 100644 --- a/conventional-commits-common/src/test/java/com/smartling/cc4j/semantic/release/common/CommitTest.java +++ b/conventional-commits-common/src/test/java/com/smartling/cc4j/semantic/release/common/CommitTest.java @@ -2,6 +2,8 @@ import org.junit.Test; +import java.util.Optional; + import static org.junit.Assert.*; public class CommitTest @@ -20,36 +22,60 @@ public void isConventional() @Test public void getCommitTypeBreakingChange() { - assertEquals(ConventionalCommitType.BREAKING_CHANGE, create("breaking change: new version").getCommitType().get()); - assertEquals(ConventionalCommitType.BREAKING_CHANGE, create("Breaking Change: add foo").getCommitType().get()); - assertEquals(ConventionalCommitType.BREAKING_CHANGE, create("BREAKING CHANGE(scope): add foo").getCommitType().get()); + assertFalse(create("breaking change: new version").getCommitType().isPresent()); + assertFalse(create("Breaking Change: add foo").getCommitType().isPresent()); + assertFalse(create("BREAKING CHANGE(scope): add foo").getCommitType().isPresent()); } @Test public void getCommitTypeBreakingChangeExclamation() { - assertEquals(ConventionalCommitType.BREAKING_CHANGE, create("fix!: new version").getCommitType().get()); - assertEquals(ConventionalCommitType.BREAKING_CHANGE, create("feat!: new version").getCommitType().get()); - assertEquals(ConventionalCommitType.TEST, create("test!: new version").getCommitType().get()); + final Optional ctFix = create("fix!: new version").getCommitType(); + assertTrue(ctFix.isPresent()); + assertEquals(ConventionalCommitType.BREAKING_CHANGE, ctFix.get()); + + final Optional ctFeatBreaking = create("feat!: new version").getCommitType(); + assertTrue(ctFeatBreaking.isPresent()); + assertEquals(ConventionalCommitType.BREAKING_CHANGE, ctFeatBreaking.get()); + + final Optional ctTestBreaking = create("test!: new version").getCommitType(); + assertTrue(ctTestBreaking.isPresent()); + assertEquals(ConventionalCommitType.BREAKING_CHANGE, ctTestBreaking.get()); } @Test public void getCommitTypeFeat() { - assertEquals(ConventionalCommitType.FEAT, create("feat: add foo").getCommitType().get()); - assertEquals(ConventionalCommitType.FEAT, create("Feat: add foo").getCommitType().get()); - assertEquals(ConventionalCommitType.FEAT, create("feat(scope): add foo").getCommitType().get()); + final Optional ctFeat = create("feat: add foo").getCommitType(); + assertTrue(ctFeat.isPresent()); + assertEquals(ConventionalCommitType.FEAT, ctFeat.get()); + + final Optional ctFeat2 = create("Feat: add foo").getCommitType(); + assertTrue(ctFeat2.isPresent()); + assertEquals(ConventionalCommitType.FEAT, ctFeat2.get()); + + final Optional ctFeat3 = create("feat(scope): add foo").getCommitType(); + assertTrue(ctFeat3.isPresent()); + assertEquals(ConventionalCommitType.FEAT, ctFeat3.get()); } @Test public void getCommitTypeFix() { - assertEquals(ConventionalCommitType.FIX, create("fix: foo").getCommitType().get()); - assertEquals(ConventionalCommitType.FIX, create("Fix: foo").getCommitType().get()); - assertEquals(ConventionalCommitType.FIX, create("fix(scope): foo").getCommitType().get()); + final Optional ctFix = create("fix: foo").getCommitType(); + assertTrue(ctFix.isPresent()); + assertEquals(ConventionalCommitType.FIX, ctFix.get()); + + final Optional ctFix2 = create("Fix: foo").getCommitType(); + assertTrue(ctFix2.isPresent()); + assertEquals(ConventionalCommitType.FIX, ctFix2.get()); + + final Optional ctFix3 = create("fix(scope): foo").getCommitType(); + assertTrue(ctFix3.isPresent()); + assertEquals(ConventionalCommitType.FIX, ctFix3.get()); } - static Commit create(String shortMessage) + static Commit create(final String shortMessage) { return new Commit(new DummyCommitAdapter(shortMessage)); } diff --git a/conventional-commits-common/src/test/java/com/smartling/cc4j/semantic/release/common/LogHandlerTest.java b/conventional-commits-common/src/test/java/com/smartling/cc4j/semantic/release/common/LogHandlerTest.java index d4dcf3e..7359897 100644 --- a/conventional-commits-common/src/test/java/com/smartling/cc4j/semantic/release/common/LogHandlerTest.java +++ b/conventional-commits-common/src/test/java/com/smartling/cc4j/semantic/release/common/LogHandlerTest.java @@ -47,7 +47,7 @@ public void setUp() throws Exception { } @After - public void tearDown() throws Exception + public void tearDown() { //Files.delete(tempDir); } diff --git a/conventional-commits-common/src/test/java/com/smartling/cc4j/semantic/release/common/SemanticVersionTest.java b/conventional-commits-common/src/test/java/com/smartling/cc4j/semantic/release/common/SemanticVersionTest.java index 0c44ee4..40a8bf6 100644 --- a/conventional-commits-common/src/test/java/com/smartling/cc4j/semantic/release/common/SemanticVersionTest.java +++ b/conventional-commits-common/src/test/java/com/smartling/cc4j/semantic/release/common/SemanticVersionTest.java @@ -23,8 +23,8 @@ public void nextVersionMinor() @Test public void nextVersionPatch() { - SemanticVersion next = SemanticVersion.parse("9.10.11").nextVersion(SemanticVersionChange.PATCH); - assertEquals(new SemanticVersion(9, 10, 12), next); + SemanticVersion next = SemanticVersion.parse("9.10.11-SNAPSHOT").nextVersion(SemanticVersionChange.PATCH); + assertEquals(new SemanticVersion(9, 10, 11), next); } @Test diff --git a/conventional-commits-maven-plugin/pom.xml b/conventional-commits-maven-plugin/pom.xml index f9dd8f4..2e7f191 100644 --- a/conventional-commits-maven-plugin/pom.xml +++ b/conventional-commits-maven-plugin/pom.xml @@ -54,13 +54,13 @@ org.apache.maven.plugin-tools maven-plugin-annotations - 3.6.0 + 3.6.4 provided junit junit - 4.12 + 4.13.2 test @@ -148,7 +148,7 @@ org.apache.maven.plugins maven-invoker-plugin - 3.1.0 + 3.2.2 true ${project.build.directory}/it diff --git a/conventional-commits-maven-plugin/src/main/java/com/smartling/cc4j/semantic/plugin/maven/AbstractVersioningMojo.java b/conventional-commits-maven-plugin/src/main/java/com/smartling/cc4j/semantic/plugin/maven/AbstractVersioningMojo.java index 084c3fc..526945c 100644 --- a/conventional-commits-maven-plugin/src/main/java/com/smartling/cc4j/semantic/plugin/maven/AbstractVersioningMojo.java +++ b/conventional-commits-maven-plugin/src/main/java/com/smartling/cc4j/semantic/plugin/maven/AbstractVersioningMojo.java @@ -34,29 +34,48 @@ abstract class AbstractVersioningMojo extends AbstractMojo @Parameter(defaultValue = "${reactorProjects}", readonly = true, required = true) private List reactorProjects; + private SemanticVersion nextVersion; + + private SemanticVersion nextDevelopmentVersion; + + public String getOriginalVersion() + { + return this.versionString; + } + + public SemanticVersion getNextVersion() throws IOException, ScmApiException + { + if (this.nextVersion == null) { + createReleaseProperties(); + } + + return this.nextVersion; + } + ConventionalVersioning getConventionalVersioning() throws IOException { - Repository repository = new RepositoryBuilder().setWorkTree(baseDir).build(); + final Repository repository = new RepositoryBuilder().setWorkTree(baseDir).build(); //Repository repository = new RepositoryBuilder().findGitDir().build(); - MavenConventionalVersioning mvnConventionalVersioning = new MavenConventionalVersioning(repository); + final MavenConventionalVersioning mvnConventionalVersioning = new MavenConventionalVersioning(repository); + return mvnConventionalVersioning.getConventionalVersioning(); } Properties createReleaseProperties() throws IOException, ScmApiException { - ConventionalVersioning versioning = this.getConventionalVersioning(); - Properties props = new Properties(); + final ConventionalVersioning versioning = this.getConventionalVersioning(); + final Properties props = new Properties(); - SemanticVersion nextVersion = versioning.getNextVersion(SemanticVersion.parse(versionString.replace("-SNAPSHOT", ""))); - SemanticVersion nextDevelopmentVersion = nextVersion.nextVersion(SemanticVersionChange.PATCH); + this.nextVersion = versioning.getNextVersion(SemanticVersion.parse(versionString)); + this.nextDevelopmentVersion = nextVersion.nextVersion(SemanticVersionChange.PATCH); // set properties for release plugin - props.setProperty(MVN_RELEASE_VERSION_PROPERTY, nextVersion.toString()); - props.setProperty(MVN_DEVELOPMENT_VERSION_PROPERTY, nextDevelopmentVersion.toString() + "-SNAPSHOT"); + props.setProperty(MVN_RELEASE_VERSION_PROPERTY, this.nextVersion.toString()); + props.setProperty(MVN_DEVELOPMENT_VERSION_PROPERTY, this.nextDevelopmentVersion.getDevelopmentVersionString()); - for (MavenProject project : reactorProjects) + for (final MavenProject project : reactorProjects) { - String projectKey = project.getGroupId() + ":" + project.getArtifactId(); + final String projectKey = project.getGroupId() + ":" + project.getArtifactId(); props.setProperty("project.rel." + projectKey, nextVersion.toString()); props.setProperty("project.dev." + projectKey, nextDevelopmentVersion.toString()); } diff --git a/conventional-commits-maven-plugin/src/main/java/com/smartling/cc4j/semantic/plugin/maven/ConventionalVersionChangeValidatorMojo.java b/conventional-commits-maven-plugin/src/main/java/com/smartling/cc4j/semantic/plugin/maven/ConventionalVersionChangeValidatorMojo.java index df01231..2a731d2 100644 --- a/conventional-commits-maven-plugin/src/main/java/com/smartling/cc4j/semantic/plugin/maven/ConventionalVersionChangeValidatorMojo.java +++ b/conventional-commits-maven-plugin/src/main/java/com/smartling/cc4j/semantic/plugin/maven/ConventionalVersionChangeValidatorMojo.java @@ -19,15 +19,15 @@ public void execute() throws MojoExecutionException, MojoFailureException { try { - ConventionalVersioning versioning = this.getConventionalVersioning(); - SemanticVersionChange change = versioning.getNextVersionChangeType(); + final ConventionalVersioning versioning = this.getConventionalVersioning(); + final SemanticVersionChange change = versioning.getNextVersionChangeType(); if (SemanticVersionChange.NONE.equals(change)) { throw new NoVersionChangeException("No conventional commit version change to release"); } } - catch (IOException | ScmApiException e) + catch (final IOException | ScmApiException e) { throw new MojoExecutionException("Unable to access repository", e); } diff --git a/conventional-commits-maven-plugin/src/main/java/com/smartling/cc4j/semantic/plugin/maven/ConventionalVersioningMojo.java b/conventional-commits-maven-plugin/src/main/java/com/smartling/cc4j/semantic/plugin/maven/ConventionalVersioningMojo.java index 3779416..247d3ff 100644 --- a/conventional-commits-maven-plugin/src/main/java/com/smartling/cc4j/semantic/plugin/maven/ConventionalVersioningMojo.java +++ b/conventional-commits-maven-plugin/src/main/java/com/smartling/cc4j/semantic/plugin/maven/ConventionalVersioningMojo.java @@ -8,9 +8,9 @@ import org.apache.maven.plugins.annotations.Parameter; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; +import java.nio.file.Files; import java.util.Locale; import java.util.Properties; @@ -24,21 +24,22 @@ public void execute() throws MojoExecutionException { try { - Properties props = this.createReleaseProperties(); + final Properties props = this.createReleaseProperties(); - session.getExecutionProperties().putAll(props); + session.getUserProperties().putAll(props); writeVersionFile(props); - getLog().warn(String.format(Locale.US, "Set release properties: %s", props)); + + getLog().info(String.format(Locale.US, "Set release properties: %s", props)); } - catch (IOException | ScmApiException e) + catch (final IOException | ScmApiException e) { throw new MojoExecutionException("SCM error: " + e.getMessage(), e); } } - private void writeVersionFile(Properties props) throws MojoExecutionException + private void writeVersionFile(final Properties props) throws MojoExecutionException { - File f = outputDirectory; + final File f = outputDirectory; if (!f.exists()) { @@ -47,11 +48,11 @@ private void writeVersionFile(Properties props) throws MojoExecutionException File touch = new File(f, "version.props"); - try (OutputStream out = new FileOutputStream(touch)) + try (OutputStream out = Files.newOutputStream(touch.toPath())) { props.store(out, ""); } - catch (IOException e) + catch (final IOException e) { throw new MojoExecutionException("Error creating file " + touch, e); } diff --git a/conventional-commits-maven-plugin/src/main/java/com/smartling/cc4j/semantic/plugin/maven/context/MavenConventionalVersioning.java b/conventional-commits-maven-plugin/src/main/java/com/smartling/cc4j/semantic/plugin/maven/context/MavenConventionalVersioning.java index 674f269..3f3b6e7 100644 --- a/conventional-commits-maven-plugin/src/main/java/com/smartling/cc4j/semantic/plugin/maven/context/MavenConventionalVersioning.java +++ b/conventional-commits-maven-plugin/src/main/java/com/smartling/cc4j/semantic/plugin/maven/context/MavenConventionalVersioning.java @@ -10,7 +10,7 @@ public class MavenConventionalVersioning { private final Repository repository; - public MavenConventionalVersioning(Repository repository) + public MavenConventionalVersioning(final Repository repository) { Objects.requireNonNull(repository, "repository required"); this.repository = repository; diff --git a/conventional-commits-maven-plugin/src/main/java/com/smartling/cc4j/semantic/plugin/maven/context/NoVersionChangeException.java b/conventional-commits-maven-plugin/src/main/java/com/smartling/cc4j/semantic/plugin/maven/context/NoVersionChangeException.java index 6d4878b..2ed6866 100644 --- a/conventional-commits-maven-plugin/src/main/java/com/smartling/cc4j/semantic/plugin/maven/context/NoVersionChangeException.java +++ b/conventional-commits-maven-plugin/src/main/java/com/smartling/cc4j/semantic/plugin/maven/context/NoVersionChangeException.java @@ -4,7 +4,7 @@ public class NoVersionChangeException extends MojoFailureException { - public NoVersionChangeException(String message) + public NoVersionChangeException(final String message) { super(message); } diff --git a/conventional-commits-maven-plugin/src/test/java/com/smartling/cc4j/semantic/plugin/maven/AbstractScmMojoTest.java b/conventional-commits-maven-plugin/src/test/java/com/smartling/cc4j/semantic/plugin/maven/AbstractScmMojoTest.java index a7b642c..cdd6849 100644 --- a/conventional-commits-maven-plugin/src/test/java/com/smartling/cc4j/semantic/plugin/maven/AbstractScmMojoTest.java +++ b/conventional-commits-maven-plugin/src/test/java/com/smartling/cc4j/semantic/plugin/maven/AbstractScmMojoTest.java @@ -24,8 +24,8 @@ public class AbstractScmMojoTest @Before public void setUp() throws Exception { - Path tempDir = Files.createTempDirectory("convention-commits-version-change-mojo-test"); - Path sourceProjectPath = Paths.get("target/test-classes/project-to-test/pom.xml"); + final Path tempDir = Files.createTempDirectory("convention-commits-version-change-mojo-test"); + final Path sourceProjectPath = Paths.get("target/test-classes/project-to-test/pom.xml"); Files.copy(sourceProjectPath, tempDir.resolve("pom.xml")); this.repository = new RepositoryBuilder().setWorkTree(tempDir.toFile()).build(); @@ -42,8 +42,8 @@ public void setUp() throws Exception void createCommit(String commitMessage) throws IOException, GitAPIException { - String filename = String.format(Locale.US, "%s.txt", UUID.randomUUID().toString()); - BufferedWriter writer = new BufferedWriter(new FileWriter(projectPath.resolve(filename).toFile())); + final String filename = String.format(Locale.US, "%s.txt", UUID.randomUUID()); + final BufferedWriter writer = new BufferedWriter(new FileWriter(projectPath.resolve(filename).toFile())); writer.write("Hello world"); writer.newLine(); writer.close(); diff --git a/conventional-commits-maven-plugin/src/test/java/com/smartling/cc4j/semantic/plugin/maven/ConventionalVersionChangeValidatorMojoTest.java b/conventional-commits-maven-plugin/src/test/java/com/smartling/cc4j/semantic/plugin/maven/ConventionalVersionChangeValidatorMojoTest.java index 9fc099d..cb14d15 100644 --- a/conventional-commits-maven-plugin/src/test/java/com/smartling/cc4j/semantic/plugin/maven/ConventionalVersionChangeValidatorMojoTest.java +++ b/conventional-commits-maven-plugin/src/test/java/com/smartling/cc4j/semantic/plugin/maven/ConventionalVersionChangeValidatorMojoTest.java @@ -1,12 +1,14 @@ package com.smartling.cc4j.semantic.plugin.maven; import com.smartling.cc4j.semantic.plugin.maven.context.NoVersionChangeException; +import com.smartling.cc4j.semantic.release.common.SemanticVersion; import org.apache.maven.plugin.testing.MojoRule; import org.junit.Rule; import org.junit.Test; import java.io.File; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -16,7 +18,7 @@ public class ConventionalVersionChangeValidatorMojoTest extends AbstractScmMojoT public MojoRule rule = new MojoRule() { @Override - protected void before() throws Throwable + protected void before() { } @@ -28,7 +30,7 @@ protected void after() ConventionalVersionChangeValidatorMojo getMojo() throws Exception { - File pom = projectPath.toFile(); + final File pom = projectPath.toFile(); assertNotNull(pom); assertTrue(pom.exists()); @@ -41,14 +43,14 @@ ConventionalVersionChangeValidatorMojo getMojo() throws Exception @Test(expected = NoVersionChangeException.class) public void executeNoConventionalCommits() throws Exception { - ConventionalVersionChangeValidatorMojo myMojo = getMojo(); + final ConventionalVersionChangeValidatorMojo myMojo = getMojo(); myMojo.execute(); } @Test(expected = NoVersionChangeException.class) public void executeNoConventionalVersionChangeCommits() throws Exception { - ConventionalVersionChangeValidatorMojo myMojo = getMojo(); + final ConventionalVersionChangeValidatorMojo myMojo = getMojo(); createCommit("ci: release x.y.z"); myMojo.execute(); } @@ -56,7 +58,7 @@ public void executeNoConventionalVersionChangeCommits() throws Exception @Test public void executeChoreCommit() throws Exception { - ConventionalVersionChangeValidatorMojo myMojo = getMojo(); + final ConventionalVersionChangeValidatorMojo myMojo = getMojo(); createCommit("chore: add something"); myMojo.execute(); } @@ -64,7 +66,7 @@ public void executeChoreCommit() throws Exception @Test public void executeFeatCommit() throws Exception { - ConventionalVersionChangeValidatorMojo myMojo = getMojo(); + final ConventionalVersionChangeValidatorMojo myMojo = getMojo(); createCommit("feat: add foo"); myMojo.execute(); } @@ -72,7 +74,7 @@ public void executeFeatCommit() throws Exception @Test public void executeFixCommit() throws Exception { - ConventionalVersionChangeValidatorMojo myMojo = getMojo(); + final ConventionalVersionChangeValidatorMojo myMojo = getMojo(); createCommit("fix: add something"); myMojo.execute(); } @@ -80,8 +82,119 @@ public void executeFixCommit() throws Exception @Test public void executeBreakingChangeCommit() throws Exception { - ConventionalVersionChangeValidatorMojo myMojo = getMojo(); + final ConventionalVersionChangeValidatorMojo myMojo = getMojo(); createCommit("fix: add something"); myMojo.execute(); } + + @Test + public void executeMultipleChangesOnlyPatch() throws Exception + { + final ConventionalVersionChangeValidatorMojo myMojo = getMojo(); + createCommit("fix: add something"); + createCommit("fix: add something"); + createCommit("docs: shiny docs added"); + myMojo.execute(); + + final SemanticVersion originalVersion = SemanticVersion.parse(myMojo.getOriginalVersion()); + + assertNotNull(myMojo.getOriginalVersion()); + assertTrue(myMojo.getOriginalVersion().endsWith(SemanticVersion.VERSION_SUFFIX_SNAPSHOT)); + + assertEquals(originalVersion.getMajor(), myMojo.getNextVersion().getMajor()); + assertEquals(originalVersion.getMinor(), myMojo.getNextVersion().getMinor()); + assertEquals(originalVersion.getPatch(), myMojo.getNextVersion().getPatch()); + } + + @Test + public void executeMultipleChangesMinorAndPatch() throws Exception + { + final ConventionalVersionChangeValidatorMojo myMojo = getMojo(); + createCommit("fix: add something"); + createCommit("chore: add something"); + createCommit("docs: shiny docs added"); + myMojo.execute(); + + final SemanticVersion originalVersion = SemanticVersion.parse(myMojo.getOriginalVersion()); + + assertEquals(originalVersion.getMajor(), myMojo.getNextVersion().getMajor()); + assertEquals(originalVersion.getMinor() + 1, myMojo.getNextVersion().getMinor()); + assertEquals(0, myMojo.getNextVersion().getPatch()); + } + + @Test + public void executeMultipleChangesMinorAndPatchWithBreakingChange() throws Exception + { + final ConventionalVersionChangeValidatorMojo myMojo = getMojo(); + createCommit("fix: add something"); + createCommit("chore: add something"); + createCommit("fix!: add some breaking thing"); + createCommit("docs: shiny docs added"); + myMojo.execute(); + + final SemanticVersion originalVersion = SemanticVersion.parse(myMojo.getOriginalVersion()); + + assertEquals(originalVersion.getMajor() + 1, myMojo.getNextVersion().getMajor()); + assertEquals(0 , myMojo.getNextVersion().getMinor()); + assertEquals(0, myMojo.getNextVersion().getPatch()); + } + + @Test + public void executeMultipleChangesMinorAndPatchWithBreakingChangeInFooter() throws Exception + { + final ConventionalVersionChangeValidatorMojo myMojo = getMojo(); + createCommit("fix: add something"); + createCommit("chore: add something"); + createCommit("fix: add some breaking thing." + + "With a long, long, long description." + + "BREAKING CHANGE: this rocks."); + createCommit("docs: shiny docs added"); + myMojo.execute(); + + final SemanticVersion originalVersion = SemanticVersion.parse(myMojo.getOriginalVersion()); + + assertEquals(originalVersion.getMajor() + 1, myMojo.getNextVersion().getMajor()); + assertEquals(0 , myMojo.getNextVersion().getMinor()); + assertEquals(0, myMojo.getNextVersion().getPatch()); + } + + @Test + public void executeMultipleChangesMinorAndPatchWithNonCompliantCommit() throws Exception + { + final ConventionalVersionChangeValidatorMojo myMojo = getMojo(); + createCommit("fix: add something"); + createCommit("chore: add something"); + createCommit("fix: add some breaking thing." + + "With a long, long, long description." + + "BREAKING CHANGE: this rocks."); + createCommit("choke add something"); + createCommit("docs: shiny docs added"); + myMojo.execute(); + + final SemanticVersion originalVersion = SemanticVersion.parse(myMojo.getOriginalVersion()); + + assertEquals(originalVersion.getMajor() + 1, myMojo.getNextVersion().getMajor()); + assertEquals(0 , myMojo.getNextVersion().getMinor()); + assertEquals(0, myMojo.getNextVersion().getPatch()); + } + + @Test(expected = NoVersionChangeException.class) + public void executeMultipleChangesWithOnlyNonCompliantCommit() throws Exception + { + final ConventionalVersionChangeValidatorMojo myMojo = getMojo(); + createCommit("fixx add something"); + createCommit("chores add something"); + createCommit("fiks add some breaking thing." + + "With a long, long, long description." + + "BREAKING CHANGE: this rocks."); + createCommit("choke add something"); + createCommit("docs shiny docs added"); + myMojo.execute(); + + final SemanticVersion originalVersion = SemanticVersion.parse(myMojo.getOriginalVersion()); + + assertEquals(originalVersion.getMajor(), myMojo.getNextVersion().getMajor()); + assertEquals(0, myMojo.getNextVersion().getMinor()); + assertEquals(0, myMojo.getNextVersion().getPatch()); + } } diff --git a/conventional-commits-maven-plugin/src/test/java/com/smartling/cc4j/semantic/plugin/maven/ConventionalVersioningMojoTest.java b/conventional-commits-maven-plugin/src/test/java/com/smartling/cc4j/semantic/plugin/maven/ConventionalVersioningMojoTest.java index 34a4278..2832fb7 100644 --- a/conventional-commits-maven-plugin/src/test/java/com/smartling/cc4j/semantic/plugin/maven/ConventionalVersioningMojoTest.java +++ b/conventional-commits-maven-plugin/src/test/java/com/smartling/cc4j/semantic/plugin/maven/ConventionalVersioningMojoTest.java @@ -15,7 +15,7 @@ public class ConventionalVersioningMojoTest extends AbstractScmMojoTest @Rule public MojoRule rule = new MojoRule() { @Override - protected void before() throws Throwable + protected void before() { } @@ -31,19 +31,19 @@ protected void after() @Test public void testExecute() throws Exception { - File pom = projectPath.toFile(); + final File pom = projectPath.toFile(); assertNotNull(pom); assertTrue(pom.exists()); - ConventionalVersioningMojo myMojo = (ConventionalVersioningMojo) rule.lookupConfiguredMojo(pom, "version"); + final ConventionalVersioningMojo myMojo = (ConventionalVersioningMojo) rule.lookupConfiguredMojo(pom, "version"); assertNotNull(myMojo); myMojo.execute(); - File outputDirectory = (File) rule.getVariableValueFromObject(myMojo, "outputDirectory"); + final File outputDirectory = (File) rule.getVariableValueFromObject(myMojo, "outputDirectory"); assertNotNull(outputDirectory); assertTrue(outputDirectory.exists()); - File touch = new File(outputDirectory, "version.props"); + final File touch = new File(outputDirectory, "version.props"); assertTrue(touch.exists()); } diff --git a/pom.xml b/pom.xml index a0c4250..f45bd54 100644 --- a/pom.xml +++ b/pom.xml @@ -33,29 +33,29 @@ org.eclipse.jgit org.eclipse.jgit - 5.5.0.201909110433-r + 6.1.0.202203080745-r org.slf4j slf4j-api - 1.7.28 + 1.7.36 org.slf4j slf4j-simple - 1.7.28 + 1.7.36 compile junit junit - 4.12 + 4.13.2 test org.mockito mockito-core - 2.28.2 + 4.5.1 test @@ -94,7 +94,7 @@ org.apache.maven.plugins maven-release-plugin - 2.5.3 + 3.0.0-M5 true false @@ -131,7 +131,7 @@ com.smartling.cc4j conventional-commits-maven-plugin - 0.1.0 + 0.2.0 false