diff --git a/src/main/java/pl/project13/core/GitCommitIdPlugin.java b/src/main/java/pl/project13/core/GitCommitIdPlugin.java index faccfb7..bf62050 100644 --- a/src/main/java/pl/project13/core/GitCommitIdPlugin.java +++ b/src/main/java/pl/project13/core/GitCommitIdPlugin.java @@ -282,6 +282,22 @@ default Map getSystemEnv() { boolean shouldPropertiesEscapeUnicode(); boolean shouldFailOnNoGitDirectory(); + + /** + * When set to {@code true}, the plugin will consider only commits affecting + * the folder containing this module. + * + * When set to {@code false}, the plugin will consider all commits in the + * repository. + * + * @return Controls whether the plugin only considers commits in the current module's directory. + */ + boolean getPerModuleVersions(); + + /** + * @return Base directory (folder) of the current module. + */ + File getModuleBaseDir(); } protected static final Pattern allowedCharactersForEvaluateOnCommit = Pattern.compile("[a-zA-Z0-9\\_\\-\\^\\/\\.]+"); @@ -367,6 +383,9 @@ private static void loadGitDataWithNativeGit( @Nonnull Callback cb, @Nonnull File dotGitDirectory, @Nonnull Properties properties) throws GitCommitIdExecutionException { + if (cb.getPerModuleVersions()) { + throw new GitCommitIdExecutionException("The native git provider does not support per module versions."); + } GitDataProvider nativeGitProvider = NativeGitProvider .on(dotGitDirectory, cb.getNativeGitTimeoutInMs(), cb.getLogInterface()) .setPrefixDot(cb.getPrefixDot()) @@ -378,6 +397,7 @@ private static void loadGitDataWithNativeGit( .setUseBranchNameFromBuildEnvironment(cb.getUseBranchNameFromBuildEnvironment()) .setExcludeProperties(cb.getExcludeProperties()) .setIncludeOnlyProperties(cb.getIncludeOnlyProperties()) + .setModuleBaseDir(cb.getModuleBaseDir()) .setOffline(cb.isOffline()); nativeGitProvider.loadGitData(cb.getEvaluateOnCommit(), cb.getSystemEnv(), properties); @@ -398,6 +418,8 @@ private static void loadGitDataWithJGit( .setUseBranchNameFromBuildEnvironment(cb.getUseBranchNameFromBuildEnvironment()) .setExcludeProperties(cb.getExcludeProperties()) .setIncludeOnlyProperties(cb.getIncludeOnlyProperties()) + .setPerModuleVersions(cb.getPerModuleVersions()) + .setModuleBaseDir(cb.getModuleBaseDir()) .setOffline(cb.isOffline()); jGitProvider.loadGitData(cb.getEvaluateOnCommit(), cb.getSystemEnv(), properties); diff --git a/src/main/java/pl/project13/core/GitDataProvider.java b/src/main/java/pl/project13/core/GitDataProvider.java index 65b1dd7..52ab487 100644 --- a/src/main/java/pl/project13/core/GitDataProvider.java +++ b/src/main/java/pl/project13/core/GitDataProvider.java @@ -24,6 +24,8 @@ import pl.project13.core.util.PropertyManager; import javax.annotation.Nonnull; + +import java.io.File; import java.net.URI; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; @@ -108,6 +110,20 @@ public abstract class GitDataProvider implements GitProvider { */ protected List includeOnlyProperties; + /** + * When set to {@code true}, the plugin will consider only commits affecting + * the folder containing this module. + * + * When set to {@code false}, the plugin will consider all commits in the + * repository. + */ + protected boolean perModuleVersions = false; + + /** + * The directory containing this project. + */ + protected File moduleBaseDir; + /** * When set to {@code true}, the plugin will not try to contact any remote repositories. * Any operations will only use the local state of the repo. @@ -242,6 +258,31 @@ public GitDataProvider setOffline(boolean offline) { return this; } + /** + * When set to {@code true}, the plugin will consider only commits affecting + * the folder containing this module. + * + * When set to {@code false}, the plugin will consider all commits in the + * repository. + * @param perModuleVersions Only consider commits affecting the folder containing this module. + * @return The {@code GitProvider} with the corresponding {@code perModuleVersions} flag set. + */ + public GitDataProvider setPerModuleVersions(boolean perModuleVersions) { + this.perModuleVersions = perModuleVersions; + return this; + } + + /** + * Path to the module base directory. + * + * @param moduleBaseDir The path to the directory containing this module. + * @return The {@code GitProvider} with the corresponding {@code moduleBaseDir} set. + */ + public GitDataProvider setModuleBaseDir(File moduleBaseDir) { + this.moduleBaseDir = moduleBaseDir; + return this; + } + /** * Main function that will attempt to load the desired properties from the git repository. * diff --git a/src/main/java/pl/project13/core/JGitProvider.java b/src/main/java/pl/project13/core/JGitProvider.java index c018603..9b8585a 100644 --- a/src/main/java/pl/project13/core/JGitProvider.java +++ b/src/main/java/pl/project13/core/JGitProvider.java @@ -84,29 +84,13 @@ public String getBuildAuthorEmail() throws GitCommitIdExecutionException { @Override public void prepareGitToExtractMoreDetailedRepoInformation() throws GitCommitIdExecutionException { try { - // more details parsed out bellow - Ref evaluateOnCommitReference = git.findRef(evaluateOnCommit); - ObjectId evaluateOnCommitResolvedObjectId = git.resolve(evaluateOnCommit); - - if ((evaluateOnCommitReference == null) && (evaluateOnCommitResolvedObjectId == null)) { - throw new GitCommitIdExecutionException( - "Could not get " + evaluateOnCommit + " Ref, are you sure you have set the dotGitDirectory " + - "property of this plugin to a valid path (currently set to " + dotGitDirectory + ")?"); - } + // more details parsed out below revWalk = new RevWalk(git); - ObjectId headObjectId; - if (evaluateOnCommitReference != null) { - headObjectId = evaluateOnCommitReference.getObjectId(); + if (perModuleVersions && moduleBaseDir != null) { + evalCommit = getCommitFromModuleDirectory(moduleBaseDir); } else { - headObjectId = evaluateOnCommitResolvedObjectId; - } - - if (headObjectId == null) { - throw new GitCommitIdExecutionException( - "Could not get " + evaluateOnCommit + " Ref, are you sure you have some " + - "commits in the dotGitDirectory (currently set to " + dotGitDirectory + ")?"); + evalCommit = getCommitFromRef(); } - evalCommit = revWalk.parseCommit(headObjectId); revWalk.markStart(evalCommit); } catch (GitCommitIdExecutionException e) { throw e; @@ -115,6 +99,61 @@ public void prepareGitToExtractMoreDetailedRepoInformation() throws GitCommitIdE } } + private RevCommit getCommitFromModuleDirectory(File moduleBaseDir) throws GitAPIException, GitCommitIdExecutionException { + //retrieve last commit in folder moduleBaseDir + try (Git gitInstance = new Git(git)) { + String relativePath = git.getDirectory().getParentFile().getAbsoluteFile().toPath().relativize(moduleBaseDir.getAbsoluteFile().toPath()).toString(); + Iterator iterator; + if (relativePath.trim().isEmpty()) { + // if the relative path is empty, we are in the root of the repository + iterator = gitInstance.log().call().iterator(); + } else { + // otherwise, we need to specify the path to get commits for that specific directory + iterator = gitInstance.log() + .addPath(relativePath).call().iterator(); + } + if (!iterator.hasNext()) { + throw new GitCommitIdExecutionException( + "Could not get commit from folder " + relativePath + " , are you sure you have some " + + "commits in the folder " + moduleBaseDir + "?"); + } + + RevCommit revCommit = iterator.next(); + if (revCommit == null) { + throw new GitCommitIdExecutionException( + "Could not get commit from folder " + relativePath + + " , are you sure you have some commits in the folder " + moduleBaseDir + "?"); + } + + return revCommit; + } + } + + private RevCommit getCommitFromRef() throws IOException, GitCommitIdExecutionException { + // more details parsed out below + Ref evaluateOnCommitReference = git.findRef(evaluateOnCommit); + ObjectId evaluateOnCommitResolvedObjectId = git.resolve(evaluateOnCommit); + + if ((evaluateOnCommitReference == null) && (evaluateOnCommitResolvedObjectId == null)) { + throw new GitCommitIdExecutionException( + "Could not get " + evaluateOnCommit + " Ref, are you sure you have set the dotGitDirectory " + + "property of this plugin to a valid path (currently set to " + dotGitDirectory + ")?"); + } + ObjectId headObjectId; + if (evaluateOnCommitReference != null) { + headObjectId = evaluateOnCommitReference.getObjectId(); + } else { + headObjectId = evaluateOnCommitResolvedObjectId; + } + + if (headObjectId == null) { + throw new GitCommitIdExecutionException( + "Could not get " + evaluateOnCommit + " Ref, are you sure you have some " + + "commits in the dotGitDirectory (currently set to " + dotGitDirectory + ")?"); + } + return revWalk.parseCommit(headObjectId); + } + @Override public String getBranchName() throws GitCommitIdExecutionException { try { diff --git a/src/test/java/pl/project13/core/GitCommitIdPluginIntegrationTest.java b/src/test/java/pl/project13/core/GitCommitIdPluginIntegrationTest.java index 83dead2..6ac1d03 100644 --- a/src/test/java/pl/project13/core/GitCommitIdPluginIntegrationTest.java +++ b/src/test/java/pl/project13/core/GitCommitIdPluginIntegrationTest.java @@ -1743,6 +1743,39 @@ public void verifyAllowedCharactersForEvaluateOnCommit() { Assertions.assertFalse(p.matcher("&&cat /etc/passwd").matches()); } + @Test + public void shouldGiveCommitIdForEachFolderWhenPerModuleVersionsEnabled() throws Exception { + // given + File dotGitDirectory = createTmpDotGitDirectory(AvailableGitTestRepo.GIT_COMMIT_ID); + + GitCommitIdPlugin.Callback cbSrc = + new GitCommitIdTestCallback() + .setDotGitDirectory(dotGitDirectory) + .setUseNativeGit(false) + .setPerModuleVersions(true) + .setModuleBaseDir(dotGitDirectory.getParentFile().toPath().resolve("src").toFile()) + .build(); + Properties propertiesSrcFolder = new Properties(); + + GitCommitIdPlugin.Callback cbSrcTest = + new GitCommitIdTestCallback() + .setDotGitDirectory(dotGitDirectory) + .setUseNativeGit(false) + .setPerModuleVersions(true) + .setModuleBaseDir(dotGitDirectory.getParentFile().toPath().resolve("src/test").toFile()) + .build(); + Properties propertiesSrcTestFolder = new Properties(); + + // when + GitCommitIdPlugin.runPlugin(cbSrc, propertiesSrcFolder); + GitCommitIdPlugin.runPlugin(cbSrcTest, propertiesSrcTestFolder); + + // then + assertThat(propertiesSrcFolder).containsKey("git.commit.id"); + assertThat(propertiesSrcTestFolder).containsKey("git.commit.id"); + assertThat(propertiesSrcFolder.getProperty("git.commit.id")).isNotEqualTo(propertiesSrcTestFolder.getProperty("git.commit.id")); + } + private GitDescribeConfig createGitDescribeConfig(boolean forceLongFormat, int abbrev) { GitDescribeConfig gitDescribeConfig = new GitDescribeConfig(); gitDescribeConfig.setTags(true); diff --git a/src/test/java/pl/project13/core/GitCommitIdTestCallback.java b/src/test/java/pl/project13/core/GitCommitIdTestCallback.java index a637d12..3d9e321 100644 --- a/src/test/java/pl/project13/core/GitCommitIdTestCallback.java +++ b/src/test/java/pl/project13/core/GitCommitIdTestCallback.java @@ -59,6 +59,8 @@ public class GitCommitIdTestCallback { private Charset propertiesSourceCharset = StandardCharsets.UTF_8; private boolean shouldPropertiesEscapeUnicode = false; private boolean shouldFailOnNoGitDirectory = false; + private boolean perModuleVersions = false; + private File moduleBaseDir; public GitCommitIdTestCallback() { try { @@ -200,6 +202,16 @@ public GitCommitIdTestCallback setShouldFailOnNoGitDirectory(boolean shouldFailO return this; } + public GitCommitIdTestCallback setPerModuleVersions(boolean perModuleVersions) { + this.perModuleVersions = perModuleVersions; + return this; + } + + public GitCommitIdTestCallback setModuleBaseDir(File moduleBaseDir) { + this.moduleBaseDir = moduleBaseDir; + return this; + } + public GitCommitIdPlugin.Callback build() { return new GitCommitIdPlugin.Callback() { @Override @@ -353,6 +365,16 @@ public boolean shouldPropertiesEscapeUnicode() { public boolean shouldFailOnNoGitDirectory() { return shouldFailOnNoGitDirectory; } + + @Override + public boolean getPerModuleVersions() { + return perModuleVersions; + } + + @Override + public File getModuleBaseDir() { + return moduleBaseDir; + } }; }