Skip to content

Commit 704cbaf

Browse files
authored
Merge pull request #247 from mharriger/per-module-versions
Add support for per-module versions to core
2 parents d543def + 1bab691 commit 704cbaf

File tree

6 files changed

+222
-25
lines changed

6 files changed

+222
-25
lines changed

src/main/java/pl/project13/core/GitCommitIdPlugin.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,22 @@ default Map<String, String> getSystemEnv() {
282282
boolean shouldPropertiesEscapeUnicode();
283283

284284
boolean shouldFailOnNoGitDirectory();
285+
286+
/**
287+
* When set to {@code true}, the plugin will consider only commits affecting
288+
* the folder containing this module.
289+
*
290+
* When set to {@code false}, the plugin will consider all commits in the
291+
* repository.
292+
*
293+
* @return Controls whether the plugin only considers commits in the current module's directory.
294+
*/
295+
boolean getPerModuleVersions();
296+
297+
/**
298+
* @return Base directory (folder) of the current module.
299+
*/
300+
File getModuleBaseDir();
285301
}
286302

287303
protected static final Pattern allowedCharactersForEvaluateOnCommit = Pattern.compile("[a-zA-Z0-9\\_\\-\\^\\/\\.]+");
@@ -378,6 +394,8 @@ private static void loadGitDataWithNativeGit(
378394
.setUseBranchNameFromBuildEnvironment(cb.getUseBranchNameFromBuildEnvironment())
379395
.setExcludeProperties(cb.getExcludeProperties())
380396
.setIncludeOnlyProperties(cb.getIncludeOnlyProperties())
397+
.setPerModuleVersions(cb.getPerModuleVersions())
398+
.setModuleBaseDir(cb.getModuleBaseDir())
381399
.setOffline(cb.isOffline());
382400

383401
nativeGitProvider.loadGitData(cb.getEvaluateOnCommit(), cb.getSystemEnv(), properties);
@@ -398,6 +416,8 @@ private static void loadGitDataWithJGit(
398416
.setUseBranchNameFromBuildEnvironment(cb.getUseBranchNameFromBuildEnvironment())
399417
.setExcludeProperties(cb.getExcludeProperties())
400418
.setIncludeOnlyProperties(cb.getIncludeOnlyProperties())
419+
.setPerModuleVersions(cb.getPerModuleVersions())
420+
.setModuleBaseDir(cb.getModuleBaseDir())
401421
.setOffline(cb.isOffline());
402422

403423
jGitProvider.loadGitData(cb.getEvaluateOnCommit(), cb.getSystemEnv(), properties);

src/main/java/pl/project13/core/GitDataProvider.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import pl.project13.core.util.PropertyManager;
2525

2626
import javax.annotation.Nonnull;
27+
28+
import java.io.File;
2729
import java.net.URI;
2830
import java.net.URLEncoder;
2931
import java.nio.charset.StandardCharsets;
@@ -108,6 +110,20 @@ public abstract class GitDataProvider implements GitProvider {
108110
*/
109111
protected List<String> includeOnlyProperties;
110112

113+
/**
114+
* When set to {@code true}, the plugin will consider only commits affecting
115+
* the folder containing this module.
116+
*
117+
* When set to {@code false}, the plugin will consider all commits in the
118+
* repository.
119+
*/
120+
protected boolean perModuleVersions = false;
121+
122+
/**
123+
* The directory containing this project.
124+
*/
125+
protected File moduleBaseDir;
126+
111127
/**
112128
* When set to {@code true}, the plugin will not try to contact any remote repositories.
113129
* Any operations will only use the local state of the repo.
@@ -242,6 +258,31 @@ public GitDataProvider setOffline(boolean offline) {
242258
return this;
243259
}
244260

261+
/**
262+
* When set to {@code true}, the plugin will consider only commits affecting
263+
* the folder containing this module.
264+
*
265+
* When set to {@code false}, the plugin will consider all commits in the
266+
* repository.
267+
* @param perModuleVersions Only consider commits affecting the folder containing this module.
268+
* @return The {@code GitProvider} with the corresponding {@code perModuleVersions} flag set.
269+
*/
270+
public GitDataProvider setPerModuleVersions(boolean perModuleVersions) {
271+
this.perModuleVersions = perModuleVersions;
272+
return this;
273+
}
274+
275+
/**
276+
* Path to the module base directory.
277+
*
278+
* @param moduleBaseDir The path to the directory containing this module.
279+
* @return The {@code GitProvider} with the corresponding {@code moduleBaseDir} set.
280+
*/
281+
public GitDataProvider setModuleBaseDir(File moduleBaseDir) {
282+
this.moduleBaseDir = moduleBaseDir;
283+
return this;
284+
}
285+
245286
/**
246287
* Main function that will attempt to load the desired properties from the git repository.
247288
*

src/main/java/pl/project13/core/JGitProvider.java

Lines changed: 59 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -84,29 +84,13 @@ public String getBuildAuthorEmail() throws GitCommitIdExecutionException {
8484
@Override
8585
public void prepareGitToExtractMoreDetailedRepoInformation() throws GitCommitIdExecutionException {
8686
try {
87-
// more details parsed out bellow
88-
Ref evaluateOnCommitReference = git.findRef(evaluateOnCommit);
89-
ObjectId evaluateOnCommitResolvedObjectId = git.resolve(evaluateOnCommit);
90-
91-
if ((evaluateOnCommitReference == null) && (evaluateOnCommitResolvedObjectId == null)) {
92-
throw new GitCommitIdExecutionException(
93-
"Could not get " + evaluateOnCommit + " Ref, are you sure you have set the dotGitDirectory " +
94-
"property of this plugin to a valid path (currently set to " + dotGitDirectory + ")?");
95-
}
87+
// more details parsed out below
9688
revWalk = new RevWalk(git);
97-
ObjectId headObjectId;
98-
if (evaluateOnCommitReference != null) {
99-
headObjectId = evaluateOnCommitReference.getObjectId();
89+
if (perModuleVersions && moduleBaseDir != null) {
90+
evalCommit = getCommitFromModuleDirectory(moduleBaseDir);
10091
} else {
101-
headObjectId = evaluateOnCommitResolvedObjectId;
102-
}
103-
104-
if (headObjectId == null) {
105-
throw new GitCommitIdExecutionException(
106-
"Could not get " + evaluateOnCommit + " Ref, are you sure you have some " +
107-
"commits in the dotGitDirectory (currently set to " + dotGitDirectory + ")?");
92+
evalCommit = getCommitFromRef();
10893
}
109-
evalCommit = revWalk.parseCommit(headObjectId);
11094
revWalk.markStart(evalCommit);
11195
} catch (GitCommitIdExecutionException e) {
11296
throw e;
@@ -115,6 +99,61 @@ public void prepareGitToExtractMoreDetailedRepoInformation() throws GitCommitIdE
11599
}
116100
}
117101

102+
private RevCommit getCommitFromModuleDirectory(File moduleBaseDir) throws GitAPIException, GitCommitIdExecutionException {
103+
//retrieve last commit in folder moduleBaseDir
104+
try (Git gitInstance = new Git(git)) {
105+
String relativePath = git.getDirectory().getParentFile().getAbsoluteFile().toPath().relativize(moduleBaseDir.getAbsoluteFile().toPath()).toString();
106+
Iterator<RevCommit> iterator;
107+
if (relativePath.trim().isEmpty()) {
108+
// if the relative path is empty, we are in the root of the repository
109+
iterator = gitInstance.log().call().iterator();
110+
} else {
111+
// otherwise, we need to specify the path to get commits for that specific directory
112+
iterator = gitInstance.log()
113+
.addPath(relativePath).call().iterator();
114+
}
115+
if (!iterator.hasNext()) {
116+
throw new GitCommitIdExecutionException(
117+
"Could not get commit from folder " + relativePath + " , are you sure you have some " +
118+
"commits in the folder " + moduleBaseDir + "?");
119+
}
120+
121+
RevCommit revCommit = iterator.next();
122+
if (revCommit == null) {
123+
throw new GitCommitIdExecutionException(
124+
"Could not get commit from folder " + relativePath +
125+
" , are you sure you have some commits in the folder " + moduleBaseDir + "?");
126+
}
127+
128+
return revCommit;
129+
}
130+
}
131+
132+
private RevCommit getCommitFromRef() throws IOException, GitCommitIdExecutionException {
133+
// more details parsed out below
134+
Ref evaluateOnCommitReference = git.findRef(evaluateOnCommit);
135+
ObjectId evaluateOnCommitResolvedObjectId = git.resolve(evaluateOnCommit);
136+
137+
if ((evaluateOnCommitReference == null) && (evaluateOnCommitResolvedObjectId == null)) {
138+
throw new GitCommitIdExecutionException(
139+
"Could not get " + evaluateOnCommit + " Ref, are you sure you have set the dotGitDirectory " +
140+
"property of this plugin to a valid path (currently set to " + dotGitDirectory + ")?");
141+
}
142+
ObjectId headObjectId;
143+
if (evaluateOnCommitReference != null) {
144+
headObjectId = evaluateOnCommitReference.getObjectId();
145+
} else {
146+
headObjectId = evaluateOnCommitResolvedObjectId;
147+
}
148+
149+
if (headObjectId == null) {
150+
throw new GitCommitIdExecutionException(
151+
"Could not get " + evaluateOnCommit + " Ref, are you sure you have some " +
152+
"commits in the dotGitDirectory (currently set to " + dotGitDirectory + ")?");
153+
}
154+
return revWalk.parseCommit(headObjectId);
155+
}
156+
118157
@Override
119158
public String getBranchName() throws GitCommitIdExecutionException {
120159
try {

src/main/java/pl/project13/core/NativeGitProvider.java

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ public class NativeGitProvider extends GitDataProvider {
4343

4444
final File canonical;
4545

46+
private String moduleRelativePath;
47+
4648
@Nonnull
4749
public static NativeGitProvider on(@Nonnull File dotGitDirectory, long nativeGitTimeoutInMs, @Nonnull LogInterface log) {
4850
return new NativeGitProvider(dotGitDirectory, nativeGitTimeoutInMs, log);
@@ -90,6 +92,19 @@ public String getBuildAuthorEmail() throws GitCommitIdExecutionException {
9092

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

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

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

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

230247
@Override
@@ -311,14 +328,16 @@ public String getClosestTagName() throws GitCommitIdExecutionException {
311328
public String getClosestTagCommitCount() throws GitCommitIdExecutionException {
312329
String closestTagName = getClosestTagName();
313330
if (closestTagName != null && !closestTagName.trim().isEmpty()) {
314-
return runQuietGitCommand(canonical, nativeGitTimeoutInMs, "rev-list " + closestTagName + ".." + evaluateOnCommit + " --count");
331+
String pathspec = moduleRelativePath != null ? " -- " + moduleRelativePath : "";
332+
return runQuietGitCommand(canonical, nativeGitTimeoutInMs, "rev-list " + closestTagName + ".." + evaluateOnCommit + " --count" + pathspec);
315333
}
316334
return "";
317335
}
318336

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

324343
@Override

src/test/java/pl/project13/core/GitCommitIdPluginIntegrationTest.java

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1743,6 +1743,62 @@ public void verifyAllowedCharactersForEvaluateOnCommit() {
17431743
Assertions.assertFalse(p.matcher("&&cat /etc/passwd").matches());
17441744
}
17451745

1746+
@Test
1747+
public void shouldGiveCommitIdForEachFolderWhenPerModuleVersionsEnabled() throws Exception {
1748+
// given
1749+
File dotGitDirectory = createTmpDotGitDirectory(AvailableGitTestRepo.GIT_COMMIT_ID);
1750+
1751+
GitCommitIdPlugin.Callback cbSrc =
1752+
new GitCommitIdTestCallback()
1753+
.setDotGitDirectory(dotGitDirectory)
1754+
.setUseNativeGit(false)
1755+
.setPerModuleVersions(true)
1756+
.setModuleBaseDir(dotGitDirectory.getParentFile().toPath().resolve("src").toFile())
1757+
.build();
1758+
Properties propertiesSrcFolder = new Properties();
1759+
1760+
GitCommitIdPlugin.Callback cbSrcTest =
1761+
new GitCommitIdTestCallback()
1762+
.setDotGitDirectory(dotGitDirectory)
1763+
.setUseNativeGit(false)
1764+
.setPerModuleVersions(true)
1765+
.setModuleBaseDir(dotGitDirectory.getParentFile().toPath().resolve("src/test").toFile())
1766+
.build();
1767+
Properties propertiesSrcTestFolder = new Properties();
1768+
1769+
GitCommitIdPlugin.Callback cbSrcNative =
1770+
new GitCommitIdTestCallback()
1771+
.setDotGitDirectory(dotGitDirectory)
1772+
.setUseNativeGit(true)
1773+
.setPerModuleVersions(true)
1774+
.setModuleBaseDir(dotGitDirectory.getParentFile().toPath().resolve("src").toFile())
1775+
.build();
1776+
Properties propertiesSrcFolderNative = new Properties();
1777+
1778+
GitCommitIdPlugin.Callback cbSrcTestNative =
1779+
new GitCommitIdTestCallback()
1780+
.setDotGitDirectory(dotGitDirectory)
1781+
.setUseNativeGit(true)
1782+
.setPerModuleVersions(true)
1783+
.setModuleBaseDir(dotGitDirectory.getParentFile().toPath().resolve("src/test").toFile())
1784+
.build();
1785+
Properties propertiesSrcTestFolderNative = new Properties();
1786+
1787+
// when
1788+
GitCommitIdPlugin.runPlugin(cbSrc, propertiesSrcFolder);
1789+
GitCommitIdPlugin.runPlugin(cbSrcTest, propertiesSrcTestFolder);
1790+
GitCommitIdPlugin.runPlugin(cbSrcNative, propertiesSrcFolderNative);
1791+
GitCommitIdPlugin.runPlugin(cbSrcTestNative, propertiesSrcTestFolderNative);
1792+
1793+
// then
1794+
assertThat(propertiesSrcFolder).containsKey("git.commit.id");
1795+
assertThat(propertiesSrcTestFolder).containsKey("git.commit.id");
1796+
assertThat(propertiesSrcFolder.getProperty("git.commit.id")).isNotEqualTo(propertiesSrcTestFolder.getProperty("git.commit.id"));
1797+
assertThat(propertiesSrcFolderNative).containsKey("git.commit.id");
1798+
assertThat(propertiesSrcTestFolderNative).containsKey("git.commit.id");
1799+
assertThat(propertiesSrcFolderNative.getProperty("git.commit.id")).isNotEqualTo(propertiesSrcTestFolderNative.getProperty("git.commit.id"));
1800+
}
1801+
17461802
private GitDescribeConfig createGitDescribeConfig(boolean forceLongFormat, int abbrev) {
17471803
GitDescribeConfig gitDescribeConfig = new GitDescribeConfig();
17481804
gitDescribeConfig.setTags(true);

src/test/java/pl/project13/core/GitCommitIdTestCallback.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ public class GitCommitIdTestCallback {
5959
private Charset propertiesSourceCharset = StandardCharsets.UTF_8;
6060
private boolean shouldPropertiesEscapeUnicode = false;
6161
private boolean shouldFailOnNoGitDirectory = false;
62+
private boolean perModuleVersions = false;
63+
private File moduleBaseDir;
6264

6365
public GitCommitIdTestCallback() {
6466
try {
@@ -200,6 +202,16 @@ public GitCommitIdTestCallback setShouldFailOnNoGitDirectory(boolean shouldFailO
200202
return this;
201203
}
202204

205+
public GitCommitIdTestCallback setPerModuleVersions(boolean perModuleVersions) {
206+
this.perModuleVersions = perModuleVersions;
207+
return this;
208+
}
209+
210+
public GitCommitIdTestCallback setModuleBaseDir(File moduleBaseDir) {
211+
this.moduleBaseDir = moduleBaseDir;
212+
return this;
213+
}
214+
203215
public GitCommitIdPlugin.Callback build() {
204216
return new GitCommitIdPlugin.Callback() {
205217
@Override
@@ -353,6 +365,16 @@ public boolean shouldPropertiesEscapeUnicode() {
353365
public boolean shouldFailOnNoGitDirectory() {
354366
return shouldFailOnNoGitDirectory;
355367
}
368+
369+
@Override
370+
public boolean getPerModuleVersions() {
371+
return perModuleVersions;
372+
}
373+
374+
@Override
375+
public File getModuleBaseDir() {
376+
return moduleBaseDir;
377+
}
356378
};
357379
}
358380

0 commit comments

Comments
 (0)