Fix DescribeCommand with multiple match options

when multiple match options are given in git describe the result must
not depend on the order of the match options. JGit wrongly picked the
first match using the match options in the order they were defined. Fix
this by concatenating the streams of matching tags for all match options
and then choosing the first match on the concatenated stream sorted in
tie break order.

See https://git-scm.com/docs/git-describe#git-describe---matchltpatterngt

Change-Id: Id01433d35fa16fb4c30526605bee041ac1d954b2
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
This commit is contained in:
Matthias Sohn 2018-11-25 23:15:11 +01:00
parent f9de917547
commit df6263644b
2 changed files with 10 additions and 12 deletions

View File

@ -156,9 +156,9 @@ public void testDescribeMultiMatch() throws Exception {
assertEquals("v1.1.1-1-gb89dead", describe(c2, "v1.1*"));
// Ensure that ordering of match precedence is preserved as per Git behaviour
assertEquals("v1.0.1", describe(c1, "v1.0*", "v1.1*"));
assertEquals("v1.1.1", describe(c1, "v1.0*", "v1.1*"));
assertEquals("v1.1.1", describe(c1, "v1.1*", "v1.0*"));
assertEquals("v1.0.1-1-gb89dead", describe(c2, "v1.0*", "v1.1*"));
assertEquals("v1.1.1-1-gb89dead", describe(c2, "v1.0*", "v1.1*"));
assertEquals("v1.1.1-1-gb89dead", describe(c2, "v1.1*", "v1.0*"));
} else {
// no timestamps so no guarantees on which tag is chosen

View File

@ -55,6 +55,7 @@
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.JGitInternalException;
@ -230,18 +231,15 @@ private Optional<Ref> getBestMatch(List<Ref> tags) {
Collections.sort(tags, TAG_TIE_BREAKER);
return Optional.of(tags.get(0));
} else {
// Find the first tag that matches one of the matchers; precedence according to matcher definition order
// 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 (IMatcher matcher : matchers) {
Optional<Ref> match = tags.stream()
.filter(tag -> matcher.matches(tag.getName(), false,
false))
.sorted(TAG_TIE_BREAKER)
.findFirst();
if (match.isPresent()) {
return match;
}
Stream<Ref> m = tags.stream().filter(
tag -> matcher.matches(tag.getName(), false, false));
matchingTags = Stream.of(matchingTags, m).flatMap(i -> i);
}
return Optional.empty();
return matchingTags.sorted(TAG_TIE_BREAKER).findFirst();
}
}