Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/main/java/pl/project13/core/GitCommitIdPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,22 @@ default Map<String, String> 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\\_\\-\\^\\/\\.]+");
Expand Down Expand Up @@ -378,6 +394,8 @@ private static void loadGitDataWithNativeGit(
.setUseBranchNameFromBuildEnvironment(cb.getUseBranchNameFromBuildEnvironment())
.setExcludeProperties(cb.getExcludeProperties())
.setIncludeOnlyProperties(cb.getIncludeOnlyProperties())
.setPerModuleVersions(cb.getPerModuleVersions())
.setModuleBaseDir(cb.getModuleBaseDir())
.setOffline(cb.isOffline());

nativeGitProvider.loadGitData(cb.getEvaluateOnCommit(), cb.getSystemEnv(), properties);
Expand All @@ -398,6 +416,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);
Expand Down
41 changes: 41 additions & 0 deletions src/main/java/pl/project13/core/GitDataProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -108,6 +110,20 @@ public abstract class GitDataProvider implements GitProvider {
*/
protected List<String> 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.
Expand Down Expand Up @@ -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.
*
Expand Down
79 changes: 59 additions & 20 deletions src/main/java/pl/project13/core/JGitProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<RevCommit> 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 {
Expand Down
29 changes: 24 additions & 5 deletions src/main/java/pl/project13/core/NativeGitProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ public class NativeGitProvider extends GitDataProvider {

final File canonical;

private String moduleRelativePath;

@Nonnull
public static NativeGitProvider on(@Nonnull File dotGitDirectory, long nativeGitTimeoutInMs, @Nonnull LogInterface log) {
return new NativeGitProvider(dotGitDirectory, nativeGitTimeoutInMs, log);
Expand Down Expand Up @@ -90,6 +92,19 @@ public String getBuildAuthorEmail() throws GitCommitIdExecutionException {

@Override
public void prepareGitToExtractMoreDetailedRepoInformation() throws GitCommitIdExecutionException {
if (perModuleVersions && moduleBaseDir != null) {
// For per-module versions, we need to determine the relative path of the module
// This will be used in git commands with the -- pathspec limiter
try {
File gitRoot = canonical.getParentFile();
String relativePath = gitRoot.getAbsoluteFile().toPath()
.relativize(moduleBaseDir.getAbsoluteFile().toPath()).toString();
// Store the relative path for use in git commands
this.moduleRelativePath = relativePath.isEmpty() ? null : relativePath;
} catch (Exception e) {
throw new GitCommitIdExecutionException("Unable to compute module relative path", e);
}
}
}

@Override
Expand Down Expand Up @@ -196,15 +211,16 @@ private String getArgumentsForGitDescribe(GitDescribeConfig describeConfig) {
@Override
public String getCommitId() throws GitCommitIdExecutionException {
boolean evaluateOnCommitIsSet = evalCommitIsNotHead();
String pathspec = moduleRelativePath != null ? " -- " + moduleRelativePath : "";
if (evaluateOnCommitIsSet) {
// if evaluateOnCommit represents a tag we need to perform the rev-parse on the actual commit reference
// in case evaluateOnCommit is not a reference rev-list will just return the argument given
// and thus it's always safe(r) to unwrap it
// however when evaluateOnCommit is not set we don't want to waste calls to the native binary
String actualCommitId = runQuietGitCommand(canonical, nativeGitTimeoutInMs, "rev-list -n 1 " + evaluateOnCommit);
String actualCommitId = runQuietGitCommand(canonical, nativeGitTimeoutInMs, "rev-list -n 1 " + evaluateOnCommit + pathspec);
return runQuietGitCommand(canonical, nativeGitTimeoutInMs, "rev-parse " + actualCommitId);
} else {
return runQuietGitCommand(canonical, nativeGitTimeoutInMs, "rev-parse HEAD");
return runQuietGitCommand(canonical, nativeGitTimeoutInMs, "rev-parse HEAD" + pathspec);
}
}

Expand All @@ -224,7 +240,8 @@ public String getAbbrevCommitId() throws GitCommitIdExecutionException {

@Override
public boolean isDirty() throws GitCommitIdExecutionException {
return !tryCheckEmptyRunGitCommand(canonical, nativeGitTimeoutInMs, "status -s");
String pathspec = moduleRelativePath != null ? " -- " + moduleRelativePath : "";
return !tryCheckEmptyRunGitCommand(canonical, nativeGitTimeoutInMs, "status -s" + pathspec);
}

@Override
Expand Down Expand Up @@ -311,14 +328,16 @@ public String getClosestTagName() throws GitCommitIdExecutionException {
public String getClosestTagCommitCount() throws GitCommitIdExecutionException {
String closestTagName = getClosestTagName();
if (closestTagName != null && !closestTagName.trim().isEmpty()) {
return runQuietGitCommand(canonical, nativeGitTimeoutInMs, "rev-list " + closestTagName + ".." + evaluateOnCommit + " --count");
String pathspec = moduleRelativePath != null ? " -- " + moduleRelativePath : "";
return runQuietGitCommand(canonical, nativeGitTimeoutInMs, "rev-list " + closestTagName + ".." + evaluateOnCommit + " --count" + pathspec);
}
return "";
}

@Override
public String getTotalCommitCount() throws GitCommitIdExecutionException {
return runQuietGitCommand(canonical, nativeGitTimeoutInMs, "rev-list " + evaluateOnCommit + " --count");
String pathspec = moduleRelativePath != null ? " -- " + moduleRelativePath : "";
return runQuietGitCommand(canonical, nativeGitTimeoutInMs, "rev-list " + evaluateOnCommit + " --count" + pathspec);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1743,6 +1743,62 @@ 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();

GitCommitIdPlugin.Callback cbSrcNative =
new GitCommitIdTestCallback()
.setDotGitDirectory(dotGitDirectory)
.setUseNativeGit(true)
.setPerModuleVersions(true)
.setModuleBaseDir(dotGitDirectory.getParentFile().toPath().resolve("src").toFile())
.build();
Properties propertiesSrcFolderNative = new Properties();

GitCommitIdPlugin.Callback cbSrcTestNative =
new GitCommitIdTestCallback()
.setDotGitDirectory(dotGitDirectory)
.setUseNativeGit(true)
.setPerModuleVersions(true)
.setModuleBaseDir(dotGitDirectory.getParentFile().toPath().resolve("src/test").toFile())
.build();
Properties propertiesSrcTestFolderNative = new Properties();

// when
GitCommitIdPlugin.runPlugin(cbSrc, propertiesSrcFolder);
GitCommitIdPlugin.runPlugin(cbSrcTest, propertiesSrcTestFolder);
GitCommitIdPlugin.runPlugin(cbSrcNative, propertiesSrcFolderNative);
GitCommitIdPlugin.runPlugin(cbSrcTestNative, propertiesSrcTestFolderNative);

// 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"));
assertThat(propertiesSrcFolderNative).containsKey("git.commit.id");
assertThat(propertiesSrcTestFolderNative).containsKey("git.commit.id");
assertThat(propertiesSrcFolderNative.getProperty("git.commit.id")).isNotEqualTo(propertiesSrcTestFolderNative.getProperty("git.commit.id"));
}

private GitDescribeConfig createGitDescribeConfig(boolean forceLongFormat, int abbrev) {
GitDescribeConfig gitDescribeConfig = new GitDescribeConfig();
gitDescribeConfig.setTags(true);
Expand Down
22 changes: 22 additions & 0 deletions src/test/java/pl/project13/core/GitCommitIdTestCallback.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -353,6 +365,16 @@ public boolean shouldPropertiesEscapeUnicode() {
public boolean shouldFailOnNoGitDirectory() {
return shouldFailOnNoGitDirectory;
}

@Override
public boolean getPerModuleVersions() {
return perModuleVersions;
}

@Override
public File getModuleBaseDir() {
return moduleBaseDir;
}
};
}

Expand Down