aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJonathing <me@jonathing.me>2025-02-23 18:11:01 -0500
committerMatthias Sohn <matthias.sohn@sap.com>2025-02-25 11:01:00 +0100
commit68f454af418224b1ba654337c073bfb06cfb16c6 (patch)
tree130b35a6581dbeb15eb633af0e5597be817b6c6a
parent8720b352a924e321df299e1308eca490e6aa5f68 (diff)
downloadjgit-68f454af418224b1ba654337c073bfb06cfb16c6.tar.gz
jgit-68f454af418224b1ba654337c073bfb06cfb16c6.zip
DescribeCommand: Add exclusion matches using setExclude()
As of right now, the describe command in JGit only supports adding matches for tag inclusion. It does not support adding matches for excluding tags, which is something that can be done with git on the command line using the "--excludes" flag. This change adds a sister method to setMatches(), called setExcludes(), which does exactly that. A few preliminary tests have also been included in DescribeCommandTest. Change-Id: Id1449c7b83c42f1d875eabd5796c748507d69362 Signed-off-by: Jonathing <me@jonathing.me>
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java22
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java57
2 files changed, 72 insertions, 7 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java
index ab87fa9662..060e6d3e84 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java
@@ -12,6 +12,7 @@ package org.eclipse.jgit.api;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.eclipse.jgit.lib.Constants.OBJECT_ID_ABBREV_STRING_LENGTH;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -87,6 +88,9 @@ public class DescribeCommandTest extends RepositoryTestCase {
assertEquals("alice-t1", describe(c2, "alice*"));
assertEquals("alice-t1", describe(c2, "a*", "b*", "c*"));
+ assertNotEquals("alice-t1", describeExcluding(c2, "alice*"));
+ assertNotEquals("alice-t1", describeCommand(c2).setMatch("*").setExclude("alice*").call());
+
assertEquals("bob-t2", describe(c3));
assertEquals("bob-t2-0-g44579eb", describe(c3, true, false));
assertEquals("alice-t1-1-g44579eb", describe(c3, "alice*"));
@@ -95,6 +99,15 @@ public class DescribeCommandTest extends RepositoryTestCase {
assertEquals("bob-t2", describe(c3, "?ob*"));
assertEquals("bob-t2", describe(c3, "a*", "b*", "c*"));
+ assertNotEquals("alice-t1-1-g44579eb", describeExcluding(c3, "alice*"));
+ assertNotEquals("alice-t1-1-g44579eb", describeCommand(c3).setMatch("*").setExclude("alice*").call());
+ assertNotEquals("alice-t1-1-g44579eb", describeExcluding(c3, "a??c?-t*"));
+ assertNotEquals("alice-t1-1-g44579eb", describeCommand(c3).setMatch("bob*").setExclude("a??c?-t*").call());
+ assertNotEquals("bob-t2", describeExcluding(c3, "bob*"));
+ assertNotEquals("bob-t2", describeCommand(c3).setMatch("alice*").setExclude("bob*"));
+ assertNotEquals("bob-t2", describeExcluding(c3, "?ob*"));
+ assertNotEquals("bob-t2", describeCommand(c3).setMatch("a??c?-t*").setExclude("?ob*"));
+
// the value verified with git-describe(1)
assertEquals("bob-t2-1-g3e563c5", describe(c4));
assertEquals("bob-t2-1-g3e563c5", describe(c4, true, false));
@@ -518,6 +531,15 @@ public class DescribeCommandTest extends RepositoryTestCase {
.setMatch(patterns).call();
}
+ private String describeExcluding(ObjectId c1, String... patterns) throws Exception {
+ return git.describe().setTarget(c1).setTags(describeUseAllTags)
+ .setExclude(patterns).call();
+ }
+
+ private DescribeCommand describeCommand(ObjectId c1) throws Exception {
+ return git.describe().setTarget(c1).setTags(describeUseAllTags);
+ }
+
private static void assertNameStartsWith(ObjectId c4, String prefix) {
assertTrue(c4.name(), c4.name().startsWith(prefix));
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java
index 934245781f..898f4464fd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java
@@ -76,6 +76,11 @@ public class DescribeCommand extends GitCommand<String> {
private List<FileNameMatcher> matchers = new ArrayList<>();
/**
+ * Pattern matchers to be applied to tags for exclusion.
+ */
+ private List<FileNameMatcher> excludeMatchers = new ArrayList<>();
+
+ /**
* Whether to use all refs in the refs/ namespace
*/
private boolean useAll;
@@ -263,6 +268,27 @@ public class DescribeCommand extends GitCommand<String> {
return this;
}
+ /**
+ * Sets one or more {@code glob(7)} patterns that tags must not match to be
+ * considered. If multiple patterns are provided, they will all be applied.
+ *
+ * @param patterns
+ * the {@code glob(7)} pattern or patterns
+ * @return {@code this}
+ * @throws org.eclipse.jgit.errors.InvalidPatternException
+ * if the pattern passed in was invalid.
+ * @see <a href=
+ * "https://www.kernel.org/pub/software/scm/git/docs/git-describe.html"
+ * >Git documentation about describe</a>
+ * @since 7.2
+ */
+ public DescribeCommand setExclude(String... patterns) throws InvalidPatternException {
+ for (String p : patterns) {
+ excludeMatchers.add(new FileNameMatcher(p, null));
+ }
+ return this;
+ }
+
private final Comparator<Ref> TAG_TIE_BREAKER = new Comparator<>() {
@Override
@@ -284,22 +310,39 @@ public class DescribeCommand extends GitCommand<String> {
private Optional<Ref> getBestMatch(List<Ref> tags) {
if (tags == null || tags.isEmpty()) {
return Optional.empty();
- } else if (matchers.isEmpty()) {
+ } else if (matchers.isEmpty() && excludeMatchers.isEmpty()) {
Collections.sort(tags, TAG_TIE_BREAKER);
return Optional.of(tags.get(0));
} else {
- // Find the first tag that matches in the stream of all tags
- // filtered by matchers ordered by tie break order
- Stream<Ref> matchingTags = Stream.empty();
- for (FileNameMatcher matcher : matchers) {
- Stream<Ref> m = tags.stream().filter(
+ Stream<Ref> matchingTags;
+ if (!matchers.isEmpty()) {
+ // Find the first tag that matches in the stream of all tags
+ // filtered by matchers ordered by tie break order
+ matchingTags = Stream.empty();
+ for (FileNameMatcher matcher : matchers) {
+ Stream<Ref> m = tags.stream().filter(
tag -> {
matcher.append(formatRefName(tag.getName()));
boolean result = matcher.isMatch();
matcher.reset();
return result;
});
- matchingTags = Stream.of(matchingTags, m).flatMap(i -> i);
+ matchingTags = Stream.of(matchingTags, m).flatMap(i -> i);
+ }
+ } else {
+ // If there are no matchers, there are only excluders
+ // Assume all tags match for now before applying excluders
+ matchingTags = tags.stream();
+ }
+
+ for (FileNameMatcher matcher : excludeMatchers) {
+ matchingTags = matchingTags.filter(
+ tag -> {
+ matcher.append(formatRefName(tag.getName()));
+ boolean result = matcher.isMatch();
+ matcher.reset();
+ return !result;
+ });
}
return matchingTags.sorted(TAG_TIE_BREAKER).findFirst();
}