26 | * - %v : replace with the generated version 27 | *28 | */ 29 | @Parameter(name = "tagMessagePattern", defaultValue = "Release version %v", property = "tag.messagePattern") 30 | private String tagMessagePattern = "Release version %v"; 31 | 32 | /** 33 | * Pattern to create tag name. You may use following tokens - 34 | * 35 | *
36 | * - %v : replace with the generated version 37 | *38 | */ 39 | @Parameter(name = "tagNamePattern", defaultValue = "v%v", property = "tag.namePattern") 40 | private String tagNamePattern = "v%v"; 41 | 42 | public boolean isFailWhenTagExist() { 43 | return failWhenTagExist; 44 | } 45 | 46 | public String getTagMessagePattern() { 47 | return tagMessagePattern; 48 | } 49 | 50 | public String getTagNamePattern() { 51 | return tagNamePattern; 52 | } 53 | 54 | @Override 55 | public void execute() throws MojoExecutionException, MojoFailureException { 56 | var versionStrategy = getVersioner().version(); 57 | var tagName = replaceTokens(getTagNamePattern(), versionStrategy); 58 | var tagMessage = replaceTokens(getTagMessagePattern(), versionStrategy); 59 | getLog().info("Current Version: " + versionStrategy.toVersionString()); 60 | getLog().info(String.format("Tag Version '%s' with message '%s'", tagName, tagMessage)); 61 | if (GitTag.exists(mavenProject.getBasedir().getAbsoluteFile(), tagName)) { 62 | getLog().error(String.format("Tag already exist: %s", tagName)); 63 | if (isFailWhenTagExist()) 64 | throw new GitVersionerException("Tag already exist: " + tagName); 65 | } else { 66 | String tagId = GitTag.create(mavenProject.getBasedir().getAbsoluteFile(), tagName, tagMessage); 67 | getLog().info(String.format("Created tag: '%s'", tagId)); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: tag-and-release 2 | on: 3 | push: 4 | tags: 5 | - 'v*' 6 | 7 | env: 8 | JAVA_VERSION: '11' 9 | JAVA_DISTRO: 'zulu' 10 | 11 | jobs: 12 | release: 13 | runs-on: ubuntu-latest 14 | name: Release 15 | env: 16 | JRELEASER_TWITTER_CONSUMER_KEY: ${{ secrets.JRELEASER_TWITTER_CONSUMER_KEY }} 17 | JRELEASER_TWITTER_CONSUMER_SECRET: ${{ secrets.JRELEASER_TWITTER_CONSUMER_SECRET }} 18 | JRELEASER_TWITTER_ACCESS_TOKEN: ${{ secrets.JRELEASER_TWITTER_ACCESS_TOKEN }} 19 | JRELEASER_TWITTER_ACCESS_TOKEN_SECRET: ${{ secrets.JRELEASER_TWITTER_ACCESS_TOKEN_SECRET }} 20 | JRELEASER_MASTODON_ACCESS_TOKEN: ${{ secrets.JRELEASER_MASTODON_ACCESS_TOKEN }} 21 | JRELEASER_GITHUB_TOKEN: ${{ secrets.JRELEASER_GITHUB_TOKEN }} 22 | JRELEASER_GPG_PASSPHRASE: ${{ secrets.JRELEASER_GPG_PASSPHRASE }} 23 | JRELEASER_GPG_PUBLIC_KEY: ${{ secrets.JRELEASER_GPG_PUBLIC_KEY }} 24 | JRELEASER_GPG_SECRET_KEY: ${{ secrets.JRELEASER_GPG_SECRET_KEY }} 25 | JRELEASER_NEXUS2_MAVEN_CENTRAL_PASSWORD: ${{ secrets.JRELEASER_NEXUS2_MAVEN_CENTRAL_PASSWORD }} 26 | JRELEASER_NEXUS2_USERNAME: ${{ secrets.JRELEASER_NEXUS2_USERNAME }} 27 | JRELEASER_VERSION: early-access 28 | steps: 29 | - uses: actions/checkout@v3 30 | with: 31 | fetch-depth: '0' 32 | - name: Setup Java 33 | uses: actions/setup-java@v3 34 | with: 35 | java-version: ${{ env.JAVA_VERSION }} 36 | distribution: ${{ env.JAVA_DISTRO }} 37 | cache: maven 38 | - name: Install LATEST extension 39 | run: ./mvnw install -DskipTests 40 | - name: Configure git-versioner Extension 41 | run: | 42 | mv ./.mvn/extensions.xml.template ./.mvn/extensions.xml 43 | - name: Stage Deploy 44 | run: ./mvnw deploy -Pdeploy -DskipTests 45 | - name: Set Version 46 | id: set-version 47 | run: | 48 | echo "RELEASE_VERSION=$(./mvnw -q -Dexec.executable=echo -Dexec.args='${project.version}' --non-recursive exec:exec)" >> $GITHUB_OUTPUT 49 | - name: Print Version 50 | run: | 51 | echo "Releasing version: ${{steps.set-version.outputs.RELEASE_VERSION}}" 52 | - name: Run JReleaser 53 | uses: jreleaser/release-action@v2 54 | env: 55 | JRELEASER_PROJECT_VERSION: ${{steps.set-version.outputs.RELEASE_VERSION}} 56 | with: 57 | version: ${{ env.JRELEASER_VERSION }} 58 | arguments: full-release 59 | - name: JReleaser release output 60 | if: always() 61 | uses: actions/upload-artifact@v2 62 | with: 63 | name: jreleaser-release 64 | path: | 65 | out/jreleaser/trace.log 66 | out/jreleaser/output.properties 67 | -------------------------------------------------------------------------------- /git-versioner-maven-plugin/src/test/java/com/github/manikmagar/maven/versioner/plugin/mojo/AbstractVersionerMojoTest.java: -------------------------------------------------------------------------------- 1 | package com.github.manikmagar.maven.versioner.plugin.mojo; 2 | 3 | import com.github.manikmagar.maven.versioner.core.git.JGitVersioner; 4 | import com.github.manikmagar.maven.versioner.core.version.SemVerStrategy; 5 | import com.github.manikmagar.maven.versioner.core.version.Versioner; 6 | import com.github.manikmagar.maven.versioner.plugin.mojo.params.InitialVersionParam; 7 | import com.github.manikmagar.maven.versioner.plugin.mojo.params.VersionConfigParam; 8 | import org.apache.maven.plugin.MojoExecutionException; 9 | import org.apache.maven.plugin.MojoFailureException; 10 | import org.apache.maven.project.MavenProject; 11 | import org.junit.Test; 12 | 13 | import java.io.File; 14 | 15 | import static com.github.manikmagar.maven.versioner.core.params.VersionKeywords.*; 16 | import static org.assertj.core.api.Assertions.assertThat; 17 | 18 | public class AbstractVersionerMojoTest { 19 | 20 | private AbstractVersionerMojo testMojo = new AbstractVersionerMojo() { 21 | 22 | { 23 | mavenProject = new MavenProject(); 24 | mavenProject.setFile(new File("my/pom.xml")); 25 | } 26 | @Override 27 | public void execute() throws MojoExecutionException, MojoFailureException { 28 | 29 | } 30 | }; 31 | 32 | @Test 33 | public void getVersionConfig() { 34 | assertThat(testMojo.getVersionConfig()).isNotNull(); 35 | assertThat(testMojo.getVersionConfig().getInitial()).isNotNull().isEqualTo(new InitialVersionParam(0, 0, 0)); 36 | assertThat(testMojo.getVersionConfig().getKeywords()).isNotNull().extracting("majorKey", "minorKey", "patchKey") 37 | .containsExactly(KEY_MAJOR, KEY_MINOR, KEY_PATCH); 38 | } 39 | 40 | @Test 41 | public void setVersionConfig() { 42 | AbstractVersionerMojo mojo = new AbstractVersionerMojo() { 43 | @Override 44 | public void execute() throws MojoExecutionException, MojoFailureException { 45 | 46 | } 47 | }; 48 | InitialVersionParam one = new InitialVersionParam(1, 0, 0); 49 | VersionConfigParam versionConfig = new VersionConfigParam(); 50 | versionConfig.setInitial(one); 51 | mojo.setVersionConfig(versionConfig); 52 | assertThat(mojo.getVersionConfig().getInitial()).isNotNull().isEqualTo(one); 53 | assertThat(testMojo.getVersionConfig().getKeywords()).isNotNull().extracting("majorKey", "minorKey", "patchKey") 54 | .containsExactly(KEY_MAJOR, KEY_MINOR, KEY_PATCH); 55 | } 56 | 57 | @Test 58 | public void getVersioner() { 59 | Versioner versioner = testMojo.getVersioner(); 60 | assertThat(versioner).isNotNull().isInstanceOf(JGitVersioner.class); 61 | } 62 | 63 | @Test 64 | public void replaceVersionToken() { 65 | assertThat(testMojo.replaceTokens("v%v", new SemVerStrategy(1, 2, 3, "test", "testHash"))).isEqualTo("v1.2.3"); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /git-versioner-maven-core/src/main/java/com/github/manikmagar/maven/versioner/core/params/VersionKeywords.java: -------------------------------------------------------------------------------- 1 | /* (C)2022 */ 2 | package com.github.manikmagar.maven.versioner.core.params; 3 | 4 | import java.util.Objects; 5 | 6 | /** 7 | * Define the version keywords to use when parsing git commit messages. 8 | */ 9 | public final class VersionKeywords { 10 | public static final String KEY_MAJOR = "[major]"; 11 | public static final String KEY_MINOR = "[minor]"; 12 | public static final String KEY_PATCH = "[patch]"; 13 | public static final String GV_KEYWORDS_MAJOR_KEY = "gv.keywords.majorKey"; 14 | public static final String GV_KEYWORDS_MINOR_KEY = "gv.keywords.minorKey"; 15 | public static final String GV_KEYWORDS_PATCH_KEY = "gv.keywords.patchKey"; 16 | public static final String GV_KEYWORDS_KEY_USEREGEX = "gv.keywords.useRegex"; 17 | 18 | /** 19 | * The keyword for calculating major version of the SemVer. 20 | */ 21 | private String majorKey = KEY_MAJOR; 22 | /** 23 | * The keyword for calculating minor version of the SemVer. 24 | */ 25 | private String minorKey = KEY_MINOR; 26 | /** 27 | * The keyword for calculating patch version of the SemVer. 28 | */ 29 | private String patchKey = KEY_PATCH; 30 | /** 31 | * Whether to use regex for matching keywords. 32 | */ 33 | private boolean useRegex = false; 34 | 35 | public VersionKeywords(String majorKey, String minorKey, String patchKey, boolean useRegex) { 36 | setMajorKey(majorKey); 37 | setMinorKey(minorKey); 38 | setPatchKey(patchKey); 39 | setUseRegex(useRegex); 40 | } 41 | public VersionKeywords() { 42 | 43 | } 44 | 45 | public String getMajorKey() { 46 | return majorKey; 47 | } 48 | 49 | public void setMajorKey(String majorKey) { 50 | if (majorKey == null || majorKey.trim().isEmpty()) { 51 | this.majorKey = KEY_MAJOR; 52 | } else { 53 | this.majorKey = majorKey; 54 | } 55 | } 56 | 57 | public String getMinorKey() { 58 | return minorKey; 59 | } 60 | 61 | public void setMinorKey(String minorKey) { 62 | if (minorKey == null || minorKey.trim().isEmpty()) { 63 | this.minorKey = KEY_MINOR; 64 | } else { 65 | this.minorKey = minorKey; 66 | } 67 | } 68 | 69 | public String getPatchKey() { 70 | return patchKey; 71 | } 72 | 73 | public void setPatchKey(String patchKey) { 74 | if (patchKey == null || patchKey.trim().isEmpty()) { 75 | this.patchKey = KEY_PATCH; 76 | } else { 77 | this.patchKey = patchKey; 78 | } 79 | } 80 | 81 | public void setUseRegex(boolean useRegex) { 82 | this.useRegex = useRegex; 83 | } 84 | 85 | public boolean isUseRegex() { 86 | return useRegex; 87 | } 88 | 89 | @Override 90 | public boolean equals(Object o) { 91 | if (this == o) 92 | return true; 93 | if (!(o instanceof VersionKeywords)) 94 | return false; 95 | VersionKeywords that = (VersionKeywords) o; 96 | return majorKey.equals(that.majorKey) && minorKey.equals(that.minorKey) && patchKey.equals(that.patchKey); 97 | } 98 | 99 | @Override 100 | public int hashCode() { 101 | return Objects.hash(majorKey, minorKey, patchKey); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /git-versioner-maven-plugin/src/main/java/com/github/manikmagar/maven/versioner/plugin/mojo/VersionCommit.java: -------------------------------------------------------------------------------- 1 | package com.github.manikmagar.maven.versioner.plugin.mojo; 2 | 3 | import com.github.manikmagar.maven.versioner.core.git.JGit; 4 | import org.apache.maven.plugin.MojoExecutionException; 5 | import org.apache.maven.plugin.MojoFailureException; 6 | import org.apache.maven.plugins.annotations.Mojo; 7 | import org.apache.maven.plugins.annotations.Parameter; 8 | 9 | import java.io.IOException; 10 | import java.util.concurrent.TimeUnit; 11 | 12 | /** 13 | * Add a new commit to change version 14 | */ 15 | public abstract class VersionCommit extends AbstractVersionerMojo { 16 | 17 | public static final String KEYWORD_TOKEN = "[%k]"; 18 | 19 | public enum IncrementType { 20 | MAJOR("major"), MINOR("minor"), PATCH("patch"); 21 | private final String name; 22 | IncrementType(String name) { 23 | this.name = name; 24 | } 25 | public String getName() { 26 | return name; 27 | } 28 | } 29 | 30 | @Parameter(name = "message", property = "gv.commit.message", defaultValue = "chore(release): " + KEYWORD_TOKEN) 31 | private String message; 32 | 33 | public void setMessage(String message) { 34 | this.message = message; 35 | } 36 | 37 | abstract IncrementType getIncrementType(); 38 | 39 | @Override 40 | public void execute() throws MojoExecutionException, MojoFailureException { 41 | String typeName = getIncrementType().getName(); 42 | switch (getIncrementType()) { 43 | case MAJOR : 44 | typeName = getVersionConfig().getKeywords().getMajorKey(); 45 | break; 46 | case MINOR : 47 | typeName = getVersionConfig().getKeywords().getMinorKey(); 48 | break; 49 | case PATCH : 50 | typeName = getVersionConfig().getKeywords().getPatchKey(); 51 | break; 52 | } 53 | if (!message.contains(KEYWORD_TOKEN)) 54 | message = message.concat(" " + KEYWORD_TOKEN); 55 | String resolvedMessage = message.replace(KEYWORD_TOKEN, typeName); 56 | try { 57 | // Use local git configuration for any write operations to retain local user 58 | // settings such as sign 59 | String gitDir = JGit.findGitDir(mavenProject.getBasedir().getAbsoluteFile().toPath().toString()); 60 | boolean completed = new ProcessBuilder() 61 | .command("git", "--git-dir", gitDir, "commit", "--allow-empty", "-m", resolvedMessage).inheritIO() 62 | .start().waitFor(5, TimeUnit.SECONDS); 63 | if (!completed) { 64 | throw new MojoFailureException("Timed out for creating commit"); 65 | } 66 | } catch (IOException | InterruptedException e) { 67 | throw new MojoFailureException(e.getMessage(), e); 68 | } 69 | } 70 | 71 | /** 72 | * Add a new git commit to increment patch version. 73 | */ 74 | @Mojo(name = "commit-patch") 75 | public static class VersionCommitPatch extends VersionCommit { 76 | 77 | public IncrementType getIncrementType() { 78 | return IncrementType.PATCH; 79 | } 80 | } 81 | /** 82 | * Add a new git commit to increment minor version. 83 | */ 84 | @Mojo(name = "commit-minor") 85 | public static class VersionCommitMinor extends VersionCommit { 86 | 87 | public IncrementType getIncrementType() { 88 | return IncrementType.MINOR; 89 | } 90 | } 91 | 92 | /** 93 | * Add a new git commit to increment major version. 94 | */ 95 | @Mojo(name = "commit-major") 96 | public static class VersionCommitMajor extends VersionCommit { 97 | 98 | public IncrementType getIncrementType() { 99 | return IncrementType.MAJOR; 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /CONTRIBUTING.adoc: -------------------------------------------------------------------------------- 1 | = Contributing 2 | ifndef::env-github[:icons: font] 3 | ifdef::env-github[] 4 | :caution-caption: :fire: 5 | :important-caption: :exclamation: 6 | :note-caption: :paperclip: 7 | :tip-caption: :bulb: 8 | :warning-caption: :warning: 9 | endif::[] 10 | 11 | == Build 12 | 13 | === Java Support 14 | 15 | Source code uses *Java 11* for development, however the API compatibility is restricted to *Java 8*. 16 | This allows us to use the syntactical sugar advancements such as var, switch etc but still _support Java 8 projects_. 17 | This is achieved with the use of https://github.com/bsideup/jabel[Jabel - javac compiler plugin]. 18 | 19 | - Development dependency: Java 11 20 | - Runtime dependency: Java 8+ 21 | 22 | WARNING: Using Java 9+ APIs will result in compilation failure. See https://github.com/bsideup/jabel#how-jabel-works[how and why Jabel works] for more details. 23 | 24 | === Installation 25 | Install artifacts to local repository - 26 | 27 | [source,shell] 28 | ---- 29 | ./mvnw install 30 | ---- 31 | 32 | == Releasing 33 | GitHub Actions workflow is configured to use this same extension to version the project 34 | and then use https://jreleaser.org/[JReleaser] to release this to https://search.maven.org/search?q=a:git-versioner-maven-extension[Maven Central]. 35 | 36 | _To trigger the release:_ 37 | 38 | *Install* the latest extension to local repository - 39 | 40 | [source,shell] 41 | ---- 42 | ./mvnw install 43 | ---- 44 | 45 | *Commit* using one of the link:README.adoc#_how_do_i_increment_version[Version Commit goals] - 46 | 47 | .Example goal to increment patch 48 | [source,shell] 49 | ---- 50 | ./mvnw com.github.manikmagar:git-versioner-maven-plugin:V-LATEST-SNAPSHOT:commit-patch --non-recursive 51 | ---- 52 | 53 | .Example goal to increment minor 54 | [source,shell] 55 | ---- 56 | ./mvnw com.github.manikmagar:git-versioner-maven-plugin:V-LATEST-SNAPSHOT:commit-minor --non-recursive 57 | ---- 58 | 59 | *Verify* the new version by running plugin's `print` goal - 60 | 61 | [source,shell] 62 | ---- 63 | ./mvnw com.github.manikmagar:git-versioner-maven-plugin:V-LATEST-SNAPSHOT:print --non-recursive 64 | ---- 65 | 66 | In the output, you can look for version - 67 | 68 | .Example version 0.6.0 print 69 | [source,log] 70 | ---- 71 | ... 72 | [INFO] --- git-versioner-maven-plugin:V-LATEST-SNAPSHOT:print (default-cli) @ git-versioner-maven-parent --- 73 | [INFO] VersionPatternStrategy [branch: main, version: 0.6.0, hash: 238bedfdff4e84f7c3964a494b91a76c4998287f] 74 | .... 75 | ---- 76 | 77 | *Tag* the new version by running plugin's `tag` goal - 78 | 79 | [source,shell] 80 | ---- 81 | ./mvnw com.github.manikmagar:git-versioner-maven-plugin:V-LATEST-SNAPSHOT:tag --non-recursive 82 | ---- 83 | 84 | This should create a tag with current verison. 85 | 86 | .Example tag goal creating v0.6.0 tag 87 | [source,log] 88 | ---- 89 | [INFO] 90 | [INFO] --- git-versioner-maven-plugin:V-LATEST-SNAPSHOT:tag (default-cli) @ git-versioner-maven-parent --- 91 | [INFO] Current Version: 0.6.0 92 | [INFO] Tag Version 'v0.6.0' with message 'Release version 0.6.0' 93 | [INFO] Created tag: 'refs/tags/v0.6.0@c95da362ef54a682f45b0a723aea609b3e980247' 94 | [INFO] ------------------------------------------------------------------------ 95 | ---- 96 | 97 | **Push** the release commit and tag 98 | 99 | [source,shell] 100 | ---- 101 | # push branch commit 102 | git push 103 | 104 | tagName=$(./mvnw help:evaluate -Dexpression=project.version -q -DforceStdout) 105 | # push the new tag 106 | # example - git push origin v0.6.0 107 | git push origin v$tagName 108 | ---- 109 | 110 | *Monitor* GitHub Actions Workflows for https://github.com/manikmagar/git-versioner-maven-plugin/actions/workflows/release.yml[release]. 111 | 112 | Once the pipeline succeeds, the new release should soon be available on -------------------------------------------------------------------------------- /git-versioner-maven-plugin/src/test/java/com/github/manikmagar/maven/versioner/plugin/VersionCommitTest.java: -------------------------------------------------------------------------------- 1 | package com.github.manikmagar.maven.versioner.plugin; 2 | 3 | import com.github.manikmagar.maven.versioner.plugin.mojo.VersionCommit; 4 | import junitparams.JUnitParamsRunner; 5 | import junitparams.Parameters; 6 | import org.eclipse.jgit.api.Git; 7 | import org.eclipse.jgit.api.errors.GitAPIException; 8 | import org.eclipse.jgit.lib.StoredConfig; 9 | import org.eclipse.jgit.revwalk.RevCommit; 10 | import org.junit.Rule; 11 | import org.junit.Test; 12 | import org.junit.rules.TemporaryFolder; 13 | import org.junit.runner.RunWith; 14 | 15 | import java.io.File; 16 | import java.io.IOException; 17 | import java.nio.file.Files; 18 | import java.nio.file.Path; 19 | import java.nio.file.Paths; 20 | import java.nio.file.StandardCopyOption; 21 | import java.util.stream.Collectors; 22 | import java.util.stream.StreamSupport; 23 | 24 | import static org.assertj.core.api.Assertions.assertThat; 25 | 26 | @RunWith(JUnitParamsRunner.class) 27 | public class VersionCommitTest extends AbstractMojoTest { 28 | 29 | @Rule 30 | public TemporaryFolder temporaryFolder = new TemporaryFolder(); 31 | 32 | @Test 33 | @Parameters(value = {"commit-patch, patch", "commit-minor, minor", "commit-major, major"}) 34 | public void executeVersionCommit(String goal, String keyword) throws Exception { 35 | File tempProject = setupTestProject(); 36 | try (Git git = getMain(tempProject)) { 37 | addEmptyCommit(git); 38 | var commit = (VersionCommit) rule.lookupConfiguredMojo(tempProject, goal); 39 | assertThat(commit).isNotNull(); 40 | commit.execute(); 41 | var commits = git.log().call(); 42 | var revCommits = StreamSupport.stream(commits.spliterator(), false).collect(Collectors.toList()); 43 | assertThat(revCommits.get(0).getShortMessage()).isEqualTo(String.format("chore(release): [%s]", keyword)); 44 | } 45 | } 46 | 47 | @Test 48 | @Parameters(value = {"commit-patch, patch", "commit-minor, minor", "commit-major, major"}) 49 | public void executeVersionCommitCustomMessage(String goal, String keyword) throws Exception { 50 | File tempProject = setupTestProject(); 51 | try (Git git = getMain(tempProject)) { 52 | addEmptyCommit(git); 53 | var commit = (VersionCommit) rule.lookupConfiguredMojo(tempProject, goal); 54 | commit.setMessage("chore: releasing [%k]"); 55 | assertThat(commit).isNotNull(); 56 | commit.execute(); 57 | var commits = git.log().call(); 58 | var revCommits = StreamSupport.stream(commits.spliterator(), false).collect(Collectors.toList()); 59 | assertThat(revCommits.get(0).getShortMessage()).isEqualTo(String.format("chore: releasing [%s]", keyword)); 60 | } 61 | } 62 | 63 | private File setupTestProject() throws IOException { 64 | File tempProject = temporaryFolder.newFolder(); 65 | Path testProject = Paths.get("src/test/resources/project-to-test/"); 66 | Files.copy(testProject.resolve("pom.xml"), tempProject.toPath().resolve("pom.xml"), 67 | StandardCopyOption.REPLACE_EXISTING); 68 | assertThat(tempProject.list()).contains("pom.xml"); 69 | return tempProject; 70 | } 71 | private static Git getMain(File tempProject) throws GitAPIException, IOException { 72 | Git main = Git.init().setInitialBranch("main").setDirectory(tempProject).call(); 73 | StoredConfig config = main.getRepository().getConfig(); 74 | config.setString("user", null, "name", "GitHub Actions Test"); 75 | config.setString("user", null, "email", ""); 76 | config.save(); 77 | return main; 78 | } 79 | private static void addEmptyCommit(Git git) throws GitAPIException { 80 | git.commit().setSign(false).setMessage("Empty commit").setAllowEmpty(true).call(); 81 | } 82 | private static String addCommit(Git git, String message) throws GitAPIException { 83 | RevCommit commit = git.commit().setSign(false).setMessage(message).setAllowEmpty(true).call(); 84 | return commit.toObjectId().getName(); 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /git-versioner-maven-core/src/main/java/com/github/manikmagar/maven/versioner/core/version/VersionPatternStrategy.java: -------------------------------------------------------------------------------- 1 | package com.github.manikmagar.maven.versioner.core.version; 2 | 3 | import java.util.regex.Pattern; 4 | 5 | import static java.lang.String.valueOf; 6 | 7 | public class VersionPatternStrategy extends SemVerStrategy { 8 | 9 | public static final String DEFAULT_VERSION_PATTERN = "%M.%m.%p(-%c)"; 10 | private final String versionPattern; 11 | 12 | public VersionPatternStrategy(int major, int minor, int patch, String branchName, String hashRef, 13 | String versionPattern) { 14 | super(major, minor, patch, branchName, hashRef); 15 | if (versionPattern == null || versionPattern.trim().isEmpty()) { 16 | this.versionPattern = DEFAULT_VERSION_PATTERN; 17 | } else { 18 | this.versionPattern = versionPattern; 19 | } 20 | } 21 | 22 | public VersionPatternStrategy(String branchName, String hashRef, String versionPattern) { 23 | super(branchName, hashRef); 24 | this.versionPattern = versionPattern; 25 | } 26 | 27 | public VersionPatternStrategy(int major, int minor, int patch, String branchName, String hashRef) { 28 | this(major, minor, patch, branchName, hashRef, DEFAULT_VERSION_PATTERN); 29 | } 30 | 31 | public VersionPatternStrategy(String branchName, String hashRef) { 32 | this(branchName, hashRef, DEFAULT_VERSION_PATTERN); 33 | } 34 | 35 | public String getVersionPattern() { 36 | return versionPattern; 37 | } 38 | 39 | @Override 40 | public String toVersionString() { 41 | return new TokenReplacer(getVersionPattern()).replace(PatternToken.MAJOR, getVersion().getMajor()) 42 | .replace(PatternToken.MINOR, getVersion().getMinor()) 43 | .replace(PatternToken.PATCH, getVersion().getPatch()) 44 | .replace(PatternToken.COMMIT, getVersion().getCommit()) 45 | .replace(PatternToken.BRANCH, getVersion().getBranch()) 46 | .replace(PatternToken.HASH_SHORT, getVersion().getHashShort()) 47 | .replace(PatternToken.HASH, getVersion().getHash()).toString(); 48 | } 49 | 50 | public static class TokenReplacer { 51 | private String text; 52 | 53 | public TokenReplacer(String text) { 54 | this.text = text; 55 | } 56 | 57 | public TokenReplacer replace(PatternToken token, int value) { 58 | return replace(token, valueOf(value)); 59 | } 60 | 61 | public TokenReplacer replace(PatternToken token, String value) { 62 | if (!text.contains(token.getToken())) 63 | return this; 64 | if (!PatternToken.COMMIT.equals(token)) { 65 | if (text.contains(token.getToken())) { 66 | text = text.replace(token.getToken(), value); 67 | } 68 | } else { 69 | // Full regex to match the version string containing group regex 70 | var fullRegex = ".*" + token.getTokenGroupRegex() + ".*"; 71 | if (Pattern.matches(fullRegex, text)) { 72 | if (value != null && !value.trim().isEmpty() && !value.equals("0")) { 73 | text = text.replace(token.getToken(), value); 74 | } else { 75 | text = text.replaceAll(token.getTokenGroupRegex(), ""); 76 | } 77 | } else if (text.contains(token.getToken())) { 78 | text = text.replace(token.getToken(), value); 79 | } 80 | } 81 | return this; 82 | } 83 | 84 | private String deTokenized() { 85 | return text.replace("(", "").replace(")", ""); 86 | } 87 | 88 | @Override 89 | public String toString() { 90 | return deTokenized(); 91 | } 92 | } 93 | 94 | public enum PatternToken { 95 | MAJOR("%M"), MINOR("%m"), PATCH("%p"), COMMIT("%c"), BRANCH("%b"), HASH_SHORT("%h"), HASH("%H"); 96 | 97 | private final String token; 98 | private final String tokenGroupRegex; 99 | 100 | PatternToken(String token) { 101 | this.token = token; 102 | this.tokenGroupRegex = String.format("(\\([^(]*%s[^)]*\\))", token); 103 | } 104 | 105 | public String getToken() { 106 | return token; 107 | } 108 | 109 | public String getTokenGroupRegex() { 110 | return tokenGroupRegex; 111 | } 112 | 113 | @Override 114 | public String toString() { 115 | return getToken(); 116 | } 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* 50 | if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 124 | 125 | FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( 126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 127 | ) 128 | 129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 131 | if exist %WRAPPER_JAR% ( 132 | if "%MVNW_VERBOSE%" == "true" ( 133 | echo Found %WRAPPER_JAR% 134 | ) 135 | ) else ( 136 | if not "%MVNW_REPOURL%" == "" ( 137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 138 | ) 139 | if "%MVNW_VERBOSE%" == "true" ( 140 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 141 | echo Downloading from: %DOWNLOAD_URL% 142 | ) 143 | 144 | powershell -Command "&{"^ 145 | "$webclient = new-object System.Net.WebClient;"^ 146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ 147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ 148 | "}"^ 149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ 150 | "}" 151 | if "%MVNW_VERBOSE%" == "true" ( 152 | echo Finished downloading %WRAPPER_JAR% 153 | ) 154 | ) 155 | @REM End of extension 156 | 157 | @REM Provide a "standardized" way to retrieve the CLI args that will 158 | @REM work with both Windows and non-Windows executions. 159 | set MAVEN_CMD_LINE_ARGS=%* 160 | 161 | %MAVEN_JAVA_EXE% ^ 162 | %JVM_CONFIG_MAVEN_PROPS% ^ 163 | %MAVEN_OPTS% ^ 164 | %MAVEN_DEBUG_OPTS% ^ 165 | -classpath %WRAPPER_JAR% ^ 166 | "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ 167 | %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 168 | if ERRORLEVEL 1 goto error 169 | goto end 170 | 171 | :error 172 | set ERROR_CODE=1 173 | 174 | :end 175 | @endlocal & set ERROR_CODE=%ERROR_CODE% 176 | 177 | if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost 178 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 179 | if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" 180 | if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" 181 | :skipRcPost 182 | 183 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 184 | if "%MAVEN_BATCH_PAUSE%"=="on" pause 185 | 186 | if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% 187 | 188 | cmd /C exit /B %ERROR_CODE% 189 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | = Git Versioner Maven Plugin 2 | ifndef::env-github[:icons: font] 3 | ifdef::env-github[] 4 | :caution-caption: :fire: 5 | :important-caption: :exclamation: 6 | :note-caption: :paperclip: 7 | :tip-caption: :bulb: 8 | :warning-caption: :warning: 9 | endif::[] 10 | :toc: macro 11 | 12 | image:https://img.shields.io/github/release/manikmagar/git-versioner-maven-plugin.svg[Release,link=https://github.com/manikmagar/git-versioner-maven-plugin/releases] 13 | image:https://github.com/manikmagar/git-versioner-maven-plugin/workflows/build/badge.svg[Build Status,link=https://github.com/manikmagar/git-versioner-maven-plugin/actions] 14 | image:https://img.shields.io/github/license/manikmagar/git-versioner-maven-plugin[GitHub] 15 | 16 | Generate the semver version using the git commit history and automatically set it to maven pom. 17 | 18 | No more manually modifying the pom.xml to decide on the versions. 19 | You continue developing and adding commits to your project. 20 | When it is time to release, add a commit with a message containing 21 | a specific version keyword and watch the magic happen. 22 | 23 | toc::[] 24 | 25 | == How does it work? 26 | This extension iterates over all the commit history and looks for a predefined keywords representing version changes. 27 | It then computes the version number upto current commit. 28 | 29 | The extension supports generating Semantic Versions `x.y.z` format. The format pattern is configurable to use 30 | values such as Git hash, branch name etc. 31 | 32 | See https://github.com/manikmagar/git-versioner-maven-extension-examples[manikmagar/git-versioner-maven-extension-examples] 33 | for examples of using this extension. 34 | 35 | [#versionKeywords] 36 | == What are version keywords? 37 | *Version keywords* are the reserved words that describes which milestone of the release is this. 38 | 39 | By default, extension supports following keywords - 40 | 41 | - `[major]` - A Major version milestone Eg. 1.0.0 -> 2.0.0 42 | - `[minor]` - A Minor version milestone Eg. 1.1.0 -> 1.2. 43 | - `[patch]` - A Patch version milestone Eg. 1.1.1 -> 1.1.2 44 | 45 | To change the keywords, see how to link:#versionKeywords_custom[Customize Version Keywords]. 46 | 47 | == How to configure? 48 | This is a maven build core extension that can - 49 | 50 | - Participate in maven build lifecycle 51 | - Automatically set the building project's version 52 | - No explicit mojo executions needed to set the version 53 | - Project's POM remain unchanged 54 | 55 | To use as a maven build extension, 56 | 57 | Create (or modify) `extensions.xml` file in `${project.baseDir}/.mvn/` 58 | to have the following entry - 59 | 60 | NOTE: The artifact id is *git-versioner-maven-_extension_*. 61 | 62 | ..mvn/extensions.xml 63 | [source,xml] 64 | ---- 65 |
mvn git-versioner:help -Ddetail=true -Dgoal=<goal-name> to
27 | * display parameter details.
28 | *
29 | * @author maven-plugin-tools
30 | */
31 | @Mojo(name = "help", requiresProject = false, threadSafe = true)
32 | public class HelpMojo extends AbstractMojo {
33 | /**
34 | * If true, display all settable properties for each goal.
35 | *
36 | */
37 | @Parameter(property = "detail", defaultValue = "false")
38 | private boolean detail;
39 |
40 | /**
41 | * The name of the goal for which to show help. If unspecified, all goals will
42 | * be displayed.
43 | *
44 | */
45 | @Parameter(property = "goal")
46 | private java.lang.String goal;
47 |
48 | /**
49 | * The maximum length of a display line, should be positive.
50 | *
51 | */
52 | @Parameter(property = "lineLength", defaultValue = "80")
53 | private int lineLength;
54 |
55 | /**
56 | * The number of spaces per indentation level, should be positive.
57 | *
58 | */
59 | @Parameter(property = "indentSize", defaultValue = "2")
60 | private int indentSize;
61 |
62 | // groupId/artifactId/plugin-help.xml
63 | private static final String PLUGIN_HELP_PATH = "/META-INF/maven/com.github.manikmagar/git-versioner-maven-plugin/plugin-help.xml";
64 |
65 | private static final int DEFAULT_LINE_LENGTH = 80;
66 |
67 | private Document build() throws MojoExecutionException {
68 | getLog().debug("load plugin-help.xml: " + PLUGIN_HELP_PATH);
69 | InputStream is = null;
70 | try {
71 | is = getClass().getResourceAsStream(PLUGIN_HELP_PATH);
72 | DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
73 | DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
74 | return dBuilder.parse(is);
75 | } catch (IOException e) {
76 | throw new MojoExecutionException(e.getMessage(), e);
77 | } catch (ParserConfigurationException e) {
78 | throw new MojoExecutionException(e.getMessage(), e);
79 | } catch (SAXException e) {
80 | throw new MojoExecutionException(e.getMessage(), e);
81 | } finally {
82 | if (is != null) {
83 | try {
84 | is.close();
85 | } catch (IOException e) {
86 | throw new MojoExecutionException(e.getMessage(), e);
87 | }
88 | }
89 | }
90 | }
91 |
92 | /**
93 | * {@inheritDoc}
94 | */
95 | public void execute() throws MojoExecutionException {
96 | if (lineLength <= 0) {
97 | getLog().warn("The parameter 'lineLength' should be positive, using '80' as default.");
98 | lineLength = DEFAULT_LINE_LENGTH;
99 | }
100 | if (indentSize <= 0) {
101 | getLog().warn("The parameter 'indentSize' should be positive, using '2' as default.");
102 | indentSize = 2;
103 | }
104 |
105 | Document doc = build();
106 |
107 | StringBuilder sb = new StringBuilder();
108 | Node plugin = getSingleChild(doc, "plugin");
109 |
110 | String name = getValue(plugin, "name");
111 | String version = getValue(plugin, "version");
112 | String id = getValue(plugin, "groupId") + ":" + getValue(plugin, "artifactId") + ":" + version;
113 | if (isNotEmpty(name) && !name.contains(id)) {
114 | append(sb, name + " " + version, 0);
115 | } else {
116 | if (isNotEmpty(name)) {
117 | append(sb, name, 0);
118 | } else {
119 | append(sb, id, 0);
120 | }
121 | }
122 | append(sb, getValue(plugin, "description"), 1);
123 | append(sb, "", 0);
124 |
125 | //
253 | * Repeat a String n times to form a new string.
254 | *
repeat < 0
263 | * @throws NullPointerException
264 | * if str is null
265 | */
266 | private static String repeat(String str, int repeat) {
267 | StringBuilder buffer = new StringBuilder(repeat * str.length());
268 |
269 | for (int i = 0; i < repeat; i++) {
270 | buffer.append(str);
271 | }
272 |
273 | return buffer.toString();
274 | }
275 |
276 | /**
277 | * Append a description to the buffer by respecting the indentSize and
278 | * lineLength parameters. Note: The last character is always a new line.
279 | *
280 | * @param sb
281 | * The buffer to append the description, not null.
282 | * @param description
283 | * The description, not null.
284 | * @param indent
285 | * The base indentation level of each line, must not be negative.
286 | */
287 | private void append(StringBuilder sb, String description, int indent) {
288 | for (String line : toLines(description, indent, indentSize, lineLength)) {
289 | sb.append(line).append('\n');
290 | }
291 | }
292 |
293 | /**
294 | * Splits the specified text into lines of convenient display length.
295 | *
296 | * @param text
297 | * The text to split into lines, must not be null.
298 | * @param indent
299 | * The base indentation level of each line, must not be negative.
300 | * @param indentSize
301 | * The size of each indentation, must not be negative.
302 | * @param lineLength
303 | * The length of the line, must not be negative.
304 | * @return The sequence of display lines, never null.
305 | * @throws NegativeArraySizeException
306 | * if indent < 0
307 | */
308 | private static Listnull.
328 | * @param line
329 | * The line to add, must not be null.
330 | * @param indentSize
331 | * The size of each indentation, must not be negative.
332 | * @param lineLength
333 | * The length of the line, must not be negative.
334 | */
335 | private static void toLines(Listnull.
372 | * @return The indentation level of the line.
373 | */
374 | private static int getIndentLevel(String line) {
375 | int level = 0;
376 | for (int i = 0; i < line.length() && line.charAt(i) == '\t'; i++) {
377 | level++;
378 | }
379 | for (int i = level + 1; i <= level + 4 && i < line.length(); i++) {
380 | if (line.charAt(i) == '\t') {
381 | level++;
382 | break;
383 | }
384 | }
385 | return level;
386 | }
387 |
388 | private String getPropertyFromExpression(String expression) {
389 | if (expression != null && expression.startsWith("${") && expression.endsWith("}")
390 | && !expression.substring(2).contains("${")) {
391 | // expression="${xxx}" -> property="xxx"
392 | return expression.substring(2, expression.length() - 1);
393 | }
394 | // no property can be extracted
395 | return null;
396 | }
397 | }
398 |
--------------------------------------------------------------------------------
/git-versioner-maven-extension/src/test/java/com/github/manikmagar/maven/versioner/extension/ExtensionTestIT.java:
--------------------------------------------------------------------------------
1 | package com.github.manikmagar.maven.versioner.extension;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 | import java.nio.file.Files;
6 | import java.nio.file.Path;
7 | import java.nio.file.Paths;
8 | import java.nio.file.StandardCopyOption;
9 |
10 | import org.apache.commons.io.FileUtils;
11 | import org.apache.maven.it.Verifier;
12 | import org.eclipse.jgit.api.Git;
13 | import org.eclipse.jgit.api.errors.GitAPIException;
14 | import org.eclipse.jgit.lib.StoredConfig;
15 | import org.eclipse.jgit.revwalk.RevCommit;
16 | import org.junit.*;
17 | import org.junit.rules.TemporaryFolder;
18 | import org.junit.runner.RunWith;
19 |
20 | import junitparams.JUnitParamsRunner;
21 | import junitparams.Parameters;
22 |
23 | import static com.github.manikmagar.maven.versioner.extension.GitVersionerModelProcessor.DOT_MVN;
24 | import static com.github.manikmagar.maven.versioner.extension.GitVersionerModelProcessor.GIT_VERSIONER_EXTENSIONS_PROPERTIES;
25 | import static org.assertj.core.api.Assertions.assertThat;
26 |
27 | @RunWith(JUnitParamsRunner.class)
28 | public class ExtensionTestIT {
29 |
30 | @Rule
31 | public TemporaryFolder temporaryFolder = new TemporaryFolder();
32 |
33 | @Before
34 | public void housekeeping() {
35 | // IT tests do not print to standard maven logs
36 | // It may look like process is stuck until all tests are executed in background.
37 | System.out.print(".");
38 | }
39 | @AfterClass
40 | public static void cleanHousekeeping() {
41 | System.out.println(".");
42 | System.out.println("IT Log files are available in target/it-logs/");
43 | }
44 |
45 | @Test
46 | public void extensionBuildInitialVersion() throws Exception {
47 | File tempProject = setupTestProject();
48 | try (Git git = getMain(tempProject)) {
49 | addEmptyCommit(git);
50 | Verifier verifier = new Verifier(tempProject.getAbsolutePath(), true);
51 | verifier.displayStreamBuffers();
52 | verifier.executeGoal("verify");
53 | copyExecutionLog(tempProject, verifier, "extensionBuildInitialVersion.log.txt");
54 | verifier.verifyErrorFreeLog();
55 | String expectedVersion = "0.0.0-1";
56 | verifier.verifyTextInLog("Building versioner-maven-extension-test " + expectedVersion);
57 | verifier.verifyTextInLog("versioner-maven-extension-test-" + expectedVersion + ".jar");
58 | assertThat(tempProject.toPath().resolve(Util.GIT_VERSIONER_POM_XML).toFile()).as("Git versioner pom file")
59 | .exists();
60 | }
61 | }
62 |
63 | @Test
64 | public void extensionBuildVersionWithCommits() throws Exception {
65 | File tempProject = setupTestProject();
66 | try (Git git = getMain(tempProject)) {
67 | addEmptyCommit(git);
68 | addEmptyCommit(git);
69 | addEmptyCommit(git);
70 | Verifier verifier = new Verifier(tempProject.getAbsolutePath(), true);
71 | verifier.displayStreamBuffers();
72 | verifier.executeGoal("verify");
73 | copyExecutionLog(tempProject, verifier, "extensionBuildVersionWithCommits.log.txt");
74 | verifier.verifyErrorFreeLog();
75 | String expectedVersion = "0.0.0-3";
76 | verifier.verifyTextInLog("Building versioner-maven-extension-test " + expectedVersion);
77 | verifier.verifyTextInLog("versioner-maven-extension-test-" + expectedVersion + ".jar");
78 | assertThat(tempProject.toPath().resolve(Util.GIT_VERSIONER_POM_XML).toFile()).as("Git versioner pom file")
79 | .exists();
80 | }
81 | }
82 |
83 | @Test
84 | public void extensionBuildWithExistingPlugin() throws Exception {
85 | File tempProject = temporaryFolder.newFolder("test").toPath().toFile();
86 | FileUtils.copyDirectory(Paths.get("src/test/resources/project-with-extension-plugin").toFile(), tempProject);
87 | try (Git git = getMain(tempProject)) {
88 | addEmptyCommit(git);
89 | Verifier verifier = new Verifier(tempProject.getAbsolutePath(), true);
90 | verifier.displayStreamBuffers();
91 | verifier.executeGoal("verify");
92 | copyExecutionLog(tempProject, verifier, "extensionBuildWithExistingPlugin.log.txt");
93 | verifier.verifyErrorFreeLog();
94 | String expectedVersion = "0.0.0-1";
95 | verifier.verifyTextInLog("Building versioner-maven-extension-test " + expectedVersion);
96 | verifier.verifyTextInLog("versioner-maven-extension-test-" + expectedVersion + ".jar");
97 | verifier.verifyTextInLog("Using existing plugin execution with id set-version");
98 | assertThat(tempProject.toPath().resolve(Util.GIT_VERSIONER_POM_XML).toFile()).as("Git versioner pom file")
99 | .exists();
100 | }
101 | }
102 |
103 | @Test
104 | public void extensionValidateVersionProperties() throws Exception {
105 | File tempProject = setupTestProject();
106 | try (Git git = getMain(tempProject)) {
107 | addEmptyCommit(git);
108 | addCommit(git, "[patch]");
109 | Verifier verifier = new Verifier(tempProject.getAbsolutePath(), true);
110 | verifier.displayStreamBuffers();
111 | verifier.executeGoal("verify");
112 | copyExecutionLog(tempProject, verifier, "extensionValidateVersionProperties.log.txt");
113 | verifier.verifyErrorFreeLog();
114 | String expectedVersion = "0.0.1";
115 | verifier.verifyTextInLog("Building versioner-maven-extension-test " + expectedVersion);
116 | verifier.verifyTextInLog("versioner-maven-extension-test-" + expectedVersion + ".jar");
117 | verifier.verifyTextInLog("git-versioner.commitNumber=0");
118 | verifier.verifyTextInLog("git-versioner.major=0");
119 | verifier.verifyTextInLog("git-versioner.minor=0");
120 | verifier.verifyTextInLog("git-versioner.patch=1");
121 | verifier.verifyTextInLog("git-versioner.version=0.0.1");
122 | verifier.verifyTextInLog("git.branch=");
123 | verifier.verifyTextInLog("git.hash=");
124 | verifier.verifyTextInLog("git.hash.short=");
125 | }
126 | }
127 | @Test
128 | public void extensionBuildPatchVersion() throws Exception {
129 | File tempProject = setupTestProject();
130 | try (Git git = getMain(tempProject)) {
131 | addEmptyCommit(git);
132 | addCommit(git, "[patch]");
133 | Verifier verifier = new Verifier(tempProject.getAbsolutePath(), true);
134 | verifier.displayStreamBuffers();
135 | verifier.executeGoal("verify");
136 | copyExecutionLog(tempProject, verifier, "extensionBuildPatchVersion.log.txt");
137 | verifier.verifyErrorFreeLog();
138 | String expectedVersion = "0.0.1";
139 | verifier.verifyTextInLog("Building versioner-maven-extension-test " + expectedVersion);
140 | verifier.verifyTextInLog("versioner-maven-extension-test-" + expectedVersion + ".jar");
141 | }
142 | }
143 | @Test
144 | public void extensionBuildMinorVersion() throws Exception {
145 | File tempProject = setupTestProject();
146 | try (Git git = getMain(tempProject)) {
147 | addEmptyCommit(git);
148 | addCommit(git, "[minor]");
149 | Verifier verifier = new Verifier(tempProject.getAbsolutePath(), true);
150 | verifier.displayStreamBuffers();
151 | verifier.executeGoal("verify");
152 | copyExecutionLog(tempProject, verifier, "extensionBuildMinorVersion.log.txt");
153 | verifier.verifyErrorFreeLog();
154 | String expectedVersion = "0.1.0";
155 | verifier.verifyTextInLog("Building versioner-maven-extension-test " + expectedVersion);
156 | verifier.verifyTextInLog("versioner-maven-extension-test-" + expectedVersion + ".jar");
157 | }
158 | }
159 | @Test
160 | public void extensionBuildMajorVersion() throws Exception {
161 | File tempProject = setupTestProject();
162 | try (Git git = getMain(tempProject)) {
163 | addEmptyCommit(git);
164 | addCommit(git, "[major]");
165 | Verifier verifier = new Verifier(tempProject.getAbsolutePath(), true);
166 | verifier.displayStreamBuffers();
167 | verifier.executeGoal("verify");
168 | copyExecutionLog(tempProject, verifier, "extensionBuildMajorVersion.log.txt");
169 | verifier.verifyErrorFreeLog();
170 | String expectedVersion = "1.0.0";
171 | verifier.verifyTextInLog("Building versioner-maven-extension-test " + expectedVersion);
172 | verifier.verifyTextInLog("versioner-maven-extension-test-" + expectedVersion + ".jar");
173 | }
174 | }
175 | @Test
176 | public void extensionBuildHashVersion() throws Exception {
177 | File tempProject = setupTestProject(true, "3.");
178 | try (Git git = getMain(tempProject)) {
179 | addEmptyCommit(git);
180 | addCommit(git, "[patch]");
181 | String hash = addCommit(git, "new commit");
182 | Verifier verifier = new Verifier(tempProject.getAbsolutePath(), true);
183 | verifier.displayStreamBuffers();
184 | verifier.executeGoal("verify");
185 | copyExecutionLog(tempProject, verifier, "extensionBuildHashVersion.log.txt");
186 | verifier.verifyErrorFreeLog();
187 | String expectedVersion = "1.3.5+" + hash.substring(0, 7);
188 | verifier.verifyTextInLog("Building versioner-maven-extension-test " + expectedVersion);
189 | verifier.verifyTextInLog("versioner-maven-extension-test-" + expectedVersion + ".jar");
190 | }
191 | }
192 |
193 | @Test
194 | public void extensionWithInitialVersionProperties() throws Exception {
195 | File tempProject = setupTestProject(true, "1.");
196 | try (Git git = getMain(tempProject)) {
197 | addEmptyCommit(git);
198 | addCommit(git, "[patch]");
199 | String hash = addCommit(git, "new commit");
200 | Verifier verifier = new Verifier(tempProject.getAbsolutePath(), true);
201 | verifier.displayStreamBuffers();
202 | verifier.executeGoal("verify");
203 | copyExecutionLog(tempProject, verifier, "extensionWithInitialVersionProperties.log.txt");
204 | verifier.verifyErrorFreeLog();
205 | String expectedVersion = "1.3.5-1";
206 | verifier.verifyTextInLog("Building versioner-maven-extension-test " + expectedVersion);
207 | verifier.verifyTextInLog("versioner-maven-extension-test-" + expectedVersion + ".jar");
208 | }
209 | }
210 | @Test
211 | public void extensionWithModule() throws Exception {
212 | File tempProject = temporaryFolder.newFolder("test").toPath().toFile();
213 | FileUtils.copyDirectory(Paths.get("src/test/resources/multi-module-project").toFile(), tempProject);
214 | try (Git git = getMain(tempProject)) {
215 | addEmptyCommit(git);
216 | addCommit(git, "[patch]");
217 | Verifier verifier = new Verifier(tempProject.getAbsolutePath(), true);
218 | verifier.displayStreamBuffers();
219 | verifier.executeGoal("verify");
220 | copyExecutionLog(tempProject, verifier, "extensionWithModule.log.txt");
221 | verifier.verifyErrorFreeLog();
222 | String expectedVersion = "0.0.1";
223 | verifier.verifyTextInLog("Building multi-module-parent " + expectedVersion);
224 | verifier.verifyTextInLog("Building cli " + expectedVersion);
225 | verifier.verifyTextInLog("Building lib " + expectedVersion);
226 | }
227 | }
228 | @Test
229 | public void extensionWithParentChild() throws Exception {
230 | File tempProject = temporaryFolder.newFolder("test").toPath().toFile();
231 | FileUtils.copyDirectory(Paths.get("src/test/resources/parent-child-project").toFile(), tempProject);
232 | try (Git git = getMain(tempProject)) {
233 | addEmptyCommit(git);
234 | addCommit(git, "[patch]");
235 | Verifier verifier = new Verifier(tempProject.getAbsolutePath(), true);
236 | verifier.displayStreamBuffers();
237 | verifier.executeGoal("verify");
238 | copyExecutionLog(tempProject, verifier, "extensionWithParentChild.log.txt");
239 | verifier.verifyErrorFreeLog();
240 | String expectedVersion = "0.0.1";
241 | verifier.verifyTextInLog("Building parent-test-pom " + expectedVersion);
242 | verifier.verifyTextInLog("Building cli " + expectedVersion);
243 | verifier.verifyTextInLog(
244 | "Setting parent com.github.manikmagar:parent-test-pom:pom:0 version to " + expectedVersion);
245 | verifier.verifyTextInLog("Building lib " + expectedVersion);
246 | }
247 | }
248 |
249 | @Test
250 | @Parameters(value = {"[BIG], 1.0.0", "[MEDIUM], 0.1.0", "[SMALL], 0.0.1"})
251 | public void extensionWithVersionKeywordProperties(String key, String expectedVersion) throws Exception {
252 | File tempProject = setupTestProject(true, "2.");
253 | try (Git git = getMain(tempProject)) {
254 | addEmptyCommit(git);
255 | addCommit(git, key);
256 | Verifier verifier = new Verifier(tempProject.getAbsolutePath(), true);
257 | verifier.displayStreamBuffers();
258 | verifier.executeGoal("verify");
259 | copyExecutionLog(tempProject, verifier, "extensionWithVersionKeywordProperties" + key + ".log.txt");
260 | verifier.verifyErrorFreeLog();
261 | verifier.verifyTextInLog("Building versioner-maven-extension-test " + expectedVersion);
262 | }
263 | }
264 |
265 | @Test
266 | @Parameters(value = {"[BIG], 1.0.0, commit-major", "[MEDIUM], 0.1.0, commit-minor", "[SMALL], 0.0.1, commit-patch"})
267 | public void extensionWithVersionKeyword_AddCommits(String key, String expectedVersion, String goal)
268 | throws Exception {
269 | File tempProject = setupTestProject(true, "2.");
270 | try (Git git = getMain(tempProject)) {
271 | addEmptyCommit(git);
272 | Verifier verifier = new Verifier(tempProject.getAbsolutePath(), true);
273 | verifier.displayStreamBuffers();
274 | verifier.executeGoal("git-versioner:" + goal);
275 | verifier.executeGoal("verify");
276 | copyExecutionLog(tempProject, verifier, "extensionWithVersionKeyword_AddCommits" + key + ".log.txt");
277 | verifier.verifyErrorFreeLog();
278 | verifier.verifyTextInLog("Building versioner-maven-extension-test " + expectedVersion);
279 | }
280 | }
281 |
282 | private static void copyExecutionLog(File tempProject, Verifier verifier, String logName) throws IOException {
283 | Path target = Files.createDirectories(Paths.get("./target/it-logs/")).resolve(logName);
284 | if (target.toFile().exists())
285 | target.toFile().delete();
286 | Files.copy(tempProject.toPath().resolve(verifier.getLogFileName()), target);
287 | }
288 |
289 | private static void addEmptyCommit(Git git) throws GitAPIException {
290 | git.commit().setSign(false).setMessage("Empty commit").setAllowEmpty(true).call();
291 | }
292 | private static String addCommit(Git git, String message) throws GitAPIException {
293 | RevCommit commit = git.commit().setSign(false).setMessage(message).setAllowEmpty(true).call();
294 | return commit.toObjectId().getName();
295 | }
296 |
297 | private static Git getMain(File tempProject) throws GitAPIException, IOException {
298 | Git main = Git.init().setInitialBranch("main").setDirectory(tempProject).call();
299 | StoredConfig config = main.getRepository().getConfig();
300 | config.setString("user", null, "name", "GitHub Actions Test");
301 | config.setString("user", null, "email", "");
302 | config.save();
303 | return main;
304 | }
305 | private File setupTestProject() throws IOException {
306 | return setupTestProject(false, "");
307 | }
308 | private File setupTestProject(boolean copyProperties, String propPrefix) throws IOException {
309 | File tempProject = temporaryFolder.newFolder();
310 | Path testProject = Paths.get("src/test/resources/project-with-extension/");
311 | Files.copy(testProject.resolve("pom.xml"), tempProject.toPath().resolve("pom.xml"),
312 | StandardCopyOption.REPLACE_EXISTING);
313 | Path mvnDir = tempProject.toPath().resolve(DOT_MVN);
314 | Files.createDirectory(mvnDir);
315 | Files.copy(testProject.resolve(DOT_MVN).resolve("extensions.xml"), mvnDir.resolve("extensions.xml"),
316 | StandardCopyOption.REPLACE_EXISTING);
317 | if (copyProperties) {
318 | Files.copy(testProject.resolve(DOT_MVN).resolve(propPrefix.concat(GIT_VERSIONER_EXTENSIONS_PROPERTIES)),
319 | mvnDir.resolve(GIT_VERSIONER_EXTENSIONS_PROPERTIES), StandardCopyOption.REPLACE_EXISTING);
320 | assertThat(mvnDir.toFile().list()).contains(GIT_VERSIONER_EXTENSIONS_PROPERTIES);
321 | }
322 | assertThat(tempProject.list()).contains("pom.xml");
323 | assertThat(mvnDir.toFile().list()).contains("extensions.xml");
324 | return tempProject;
325 | }
326 | }
327 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |