assertEquals("bob-t2-1-g3e563c5", git.describe().call());
}
+ @Test
+ public void testDescribeMultiMatch() throws Exception {
+ ObjectId c1 = modify("aaa");
+ tag("v1.0.0");
+ tag("v1.1.1");
+ ObjectId c2 = modify("bbb");
+
+ // Ensure that if we're interested in any tags, we get the first match as per Git behaviour
+ assertEquals("v1.0.0", describe(c1));
+ assertEquals("v1.0.0-1-g3747db3", describe(c2));
+
+ // Ensure that if we're only interested in one of multiple tags, we get the right match
+ assertEquals("v1.0.0", describe(c1, "v1.0*"));
+ assertEquals("v1.1.1", describe(c1, "v1.1*"));
+ assertEquals("v1.0.0-1-g3747db3", describe(c2, "v1.0*"));
+ assertEquals("v1.1.1-1-g3747db3", describe(c2, "v1.1*"));
+
+ // Ensure that ordering of match precedence is preserved as per Git behaviour
+ assertEquals("v1.0.0", describe(c1, "v1.0*", "v1.1*"));
+ assertEquals("v1.1.1", describe(c1, "v1.1*", "v1.0*"));
+ assertEquals("v1.0.0-1-g3747db3", describe(c2, "v1.0*", "v1.1*"));
+ assertEquals("v1.1.1-1-g3747db3", describe(c2, "v1.1*", "v1.0*"));
+ }
+
/**
* Make sure it finds a tag when not all ancestries include a tag.
*
import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.JGitInternalException;
return this;
}
- private boolean tagMatches(Ref tag) {
- if (tag == null) {
- return false;
+ private Optional<Ref> getBestMatch(List<Ref> tags) {
+ if (tags == null || tags.size() == 0) {
+ return Optional.empty();
} else if (matchers.size() == 0) {
- return true;
+ // No matchers, simply return the first tag entry
+ return Optional.of(tags.get(0));
} else {
- return matchers.stream()
- .anyMatch(m -> m.matches(tag.getName(), false));
+ // Find the first tag that matches one of the matchers; precedence according to matcher definition order
+ for (IMatcher matcher : matchers) {
+ Optional<Ref> match = tags.stream()
+ .filter(tag -> matcher.matches(tag.getName(), false))
+ .findFirst();
+ if (match.isPresent()) {
+ return match;
+ }
+ }
+ return Optional.empty();
}
}
+ private ObjectId getObjectIdFromRef(Ref r) {
+ ObjectId key = repo.peel(r).getPeeledObjectId();
+ if (key == null) {
+ key = r.getObjectId();
+ }
+ return key;
+ }
+
/**
* Describes the specified commit. Target defaults to HEAD if no commit was
* set explicitly.
if (target == null)
setTarget(Constants.HEAD);
- Map<ObjectId, Ref> tags = new HashMap<>();
-
- for (Ref r : repo.getRefDatabase().getRefs(R_TAGS).values()) {
- ObjectId key = repo.peel(r).getPeeledObjectId();
- if (key == null)
- key = r.getObjectId();
- tags.put(key, r);
- }
+ Collection<Ref> tagList = repo.getRefDatabase().getRefs(R_TAGS).values();
+ Map<ObjectId, List<Ref>> tags = tagList.stream()
+ .collect(Collectors.groupingBy(this::getObjectIdFromRef));
// combined flags of all the candidate instances
final RevFlagSet allFlags = new RevFlagSet();
}
List<Candidate> candidates = new ArrayList<>(); // all the candidates we find
- // is the target already pointing to a tag? if so, we are done!
- Ref tagOnTarget = tags.get(target);
- if (tagMatches(tagOnTarget)) {
- return longDesc ? longDescription(tagOnTarget, 0, target) : tagOnTarget
- .getName().substring(R_TAGS.length());
+ // is the target already pointing to a suitable tag? if so, we are done!
+ Optional<Ref> bestMatch = getBestMatch(tags.get(target));
+ if (bestMatch.isPresent()) {
+ return longDesc ? longDescription(bestMatch.get(), 0, target) :
+ bestMatch.get().getName().substring(R_TAGS.length());
}
w.markStart(target);
// if a tag already dominates this commit,
// then there's no point in picking a tag on this commit
// since the one that dominates it is always more preferable
- Ref t = tags.get(c);
- if (tagMatches(t)) {
- Candidate cd = new Candidate(c, t);
+ bestMatch = getBestMatch(tags.get(c));
+ if (bestMatch.isPresent()) {
+ Candidate cd = new Candidate(c, bestMatch.get());
candidates.add(cd);
cd.depth = seen;
}