Skip to content

Commit

Permalink
fix: handle lightweight tags
Browse files Browse the repository at this point in the history
  • Loading branch information
qoomon committed Jun 26, 2022
1 parent 8806494 commit 02b2a22
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 91 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@

# Changelog

## 9.0.1

##### Fixes
- handle lightweight tags

## 8.0.2
##### Fixes
* fix git describe tag selection, if multiple tags point to head
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

<groupId>me.qoomon</groupId>
<artifactId>maven-git-versioning-extension</artifactId>
<version>9.0.0</version>
<version>9.0.1</version>
<packaging>maven-plugin</packaging>

<name>Maven Git Versioning Extension</name>
Expand Down
16 changes: 5 additions & 11 deletions src/main/java/me/qoomon/gitversioning/commons/GitSituation.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
package me.qoomon.gitversioning.commons;

import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.errors.NoWorkTreeException;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import java.util.regex.Pattern;

Expand All @@ -31,7 +30,6 @@ public class GitSituation {
private final Supplier<ZonedDateTime> timestamp = Lazy.by(this::timestamp);
private Supplier<String> branch = Lazy.by(this::branch);

private final Supplier<Map<ObjectId, List<Ref>>> reverseTagRefMap = Lazy.by(this::reverseTagRefMap);
private Supplier<List<String>> tags = Lazy.by(this::tags);

private final Supplier<Boolean> clean = Lazy.by(this::clean);
Expand Down Expand Up @@ -127,19 +125,15 @@ private String branch() throws IOException {
return GitUtil.branch(repository);
}

private List<String> tags() {
return head != null ? GitUtil.tagsPointAt(repository, head, reverseTagRefMap.get()) : emptyList();
private List<String> tags() throws IOException {
return head != null ? GitUtil.tagsPointAt(head, repository) : emptyList();
}

private boolean clean() {
private boolean clean() throws GitAPIException {
return GitUtil.status(repository).isClean();
}

private GitDescription describe() throws IOException {
return GitUtil.describe(repository, head, describeTagPattern, reverseTagRefMap.get());
}

private Map<ObjectId, List<Ref>> reverseTagRefMap() throws IOException {
return GitUtil.reverseTagRefMap(repository);
return GitUtil.describe(head, describeTagPattern, repository);
}
}
78 changes: 34 additions & 44 deletions src/main/java/me/qoomon/gitversioning/commons/GitUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefDatabase;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
Expand All @@ -19,6 +18,7 @@
import java.util.Map;
import java.util.Optional;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static java.time.ZoneOffset.UTC;
import static java.util.Collections.emptyList;
Expand All @@ -31,12 +31,8 @@ public final class GitUtil {

public static String NO_COMMIT = "0000000000000000000000000000000000000000";

public static Status status(Repository repository) {
try {
return Git.wrap(repository).status().call();
} catch (GitAPIException e) {
throw new RuntimeException(e);
}
public static Status status(Repository repository) throws GitAPIException {
return Git.wrap(repository).status().call();
}

public static String branch(Repository repository) throws IOException {
Expand All @@ -47,29 +43,17 @@ public static String branch(Repository repository) throws IOException {
return branch;
}

public static List<String> tagsPointAt(Repository repository, ObjectId revObjectId) throws IOException {
return tagsPointAt(repository, revObjectId, reverseTagRefMap(repository));
}

public static List<String> tagsPointAt(Repository repository, ObjectId revObjectId,
Map<ObjectId, List<Ref>> reverseTagRefMap) {
return reverseTagRefMap.getOrDefault(revObjectId, emptyList()).stream()
.sorted(new TagComparator(repository))
.map(ref -> shortenRefName(ref.getName()))
.collect(toList());
public static List<String> tagsPointAt(ObjectId revObjectId, Repository repository) throws IOException {
return reverseTagRefMap(repository).getOrDefault(revObjectId, emptyList());
}

public static GitDescription describe(Repository repository, ObjectId revObjectId, Pattern tagPattern) throws IOException {
return describe(repository, revObjectId, tagPattern, reverseTagRefMap(repository));
}

public static GitDescription describe(Repository repository, ObjectId revObjectId, Pattern tagPattern,
Map<ObjectId, List<Ref>> reverseTagRefMap) throws IOException {

public static GitDescription describe(ObjectId revObjectId, Pattern tagPattern, Repository repository) throws IOException {
if (revObjectId == null) {
return new GitDescription(NO_COMMIT, "root", 0);
}

Map<ObjectId, List<String>> objectIdListMap = reverseTagRefMap(repository);

// Walk back commit ancestors looking for tagged one
try (RevWalk walk = new RevWalk(repository)) {
walk.setRetainBody(false);
Expand All @@ -80,14 +64,12 @@ public static GitDescription describe(Repository repository, ObjectId revObjectI
while (walkIterator.hasNext()) {
RevCommit rev = walkIterator.next();
depth++;

Optional<Ref> matchingTag = reverseTagRefMap.getOrDefault(rev, emptyList()).stream()
.sorted(new TagComparator(repository))
.filter(tag -> tagPattern.matcher(shortenRefName(tag.getName())).matches())
Optional<String> matchingTag = objectIdListMap.getOrDefault(rev, emptyList()).stream()
.filter(tag -> tagPattern.matcher(tag).matches())
.findFirst();

if (matchingTag.isPresent()) {
return new GitDescription(revObjectId.getName(), shortenRefName(matchingTag.get().getName()), depth);
return new GitDescription(revObjectId.getName(), matchingTag.get(), depth);
}
}

Expand All @@ -104,23 +86,31 @@ public static boolean isShallowRepository(Repository repository) {
}

public static List<Ref> tags(Repository repository) throws IOException {
return tags(repository.getRefDatabase());
}

public static List<Ref> tags(RefDatabase refDatabase) throws IOException {
return refDatabase.getRefsByPrefix(R_TAGS);
return repository.getRefDatabase().getRefsByPrefix(R_TAGS).stream()
// .sorted(new TagComparator(repository)) // TODO may can be removed
.collect(toList());
}

public static Map<ObjectId, List<Ref>> reverseTagRefMap(Repository repository) throws IOException {
RefDatabase refDatabase = repository.getRefDatabase();
return tags(refDatabase).stream().collect(groupingBy(ref -> {
try {
ObjectId peeledObjectId = refDatabase.peel(ref).getPeeledObjectId();
return peeledObjectId != null ? peeledObjectId : ref.getObjectId();
} catch (IOException e) {
throw new RuntimeException(e);
}
}));
public static Map<ObjectId, List<String>> reverseTagRefMap(Repository repository) throws IOException {
TagComparator tagComparator = new TagComparator(repository);
return tags(repository).stream()
.collect(groupingBy(r -> {
try {
Ref peel = repository.getRefDatabase().peel(r);
return peel.getPeeledObjectId() != null
? peel.getPeeledObjectId()
: peel.getObjectId();
} catch (IOException e) {
throw new RuntimeException(e);
}
}))
.entrySet().stream()
.collect(Collectors.toMap(
e -> e.getKey(),
e -> e.getValue().stream()
.sorted(tagComparator)
.map(v -> shortenRefName(v.getName())).collect(toList())
));
}

public static ZonedDateTime revTimestamp(Repository repository, ObjectId rev) throws IOException {
Expand Down
72 changes: 44 additions & 28 deletions src/main/java/me/qoomon/gitversioning/commons/TagComparator.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package me.qoomon.gitversioning.commons;

import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.*;
import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.revwalk.RevTag;
import org.eclipse.jgit.revwalk.RevWalk;

import java.io.IOException;
import java.util.Comparator;
import java.util.Date;

import static org.eclipse.jgit.lib.Constants.OBJ_TAG;
import java.util.concurrent.Callable;

public class TagComparator implements Comparator<Ref> {

Expand All @@ -20,32 +21,47 @@ public TagComparator(Repository repository) {

@Override
public int compare(Ref ref1, Ref ref2) {
RevObject rev1 = tryUnchecked(() -> revWalk.parseAny(ref1.getObjectId()));
RevObject rev2 = tryUnchecked(() -> revWalk.parseAny(ref2.getObjectId()));

// both tags are annotated tags
if (rev1 instanceof RevTag && rev2 instanceof RevTag) {
return compareTaggerDate((RevTag) rev1, (RevTag) rev2);
}

// only ref1 is annotated tag
if (rev1 instanceof RevTag) {
return -1;
}

// only ref2 is annotated tag
if (rev2 instanceof RevTag) {
return 1;
}

// both tags are lightweight tags
return compareTagVersion(ref1, ref2);
}

private static <R> R tryUnchecked(Callable<R> block) {
try {
RevTag revTag1 = revWalk.parseTag(ref1.getObjectId());
RevTag revTag2 = revWalk.parseTag(ref2.getObjectId());

// both tags are annotated tags
if (revTag1.getType() == OBJ_TAG && revTag2.getType() == OBJ_TAG) {
Date revTag1Date = revTag1.getTaggerIdent().getWhen();
Date revTag2Date = revTag2.getTaggerIdent().getWhen();
// most recent tags first
return -revTag1Date.compareTo(revTag2Date);
}

// only ref1 is annotated tag
if (revTag1.getType() == OBJ_TAG) {
return -1;
}

// only ref2 is annotated tag
if (revTag2.getType() == OBJ_TAG) {
return 1;
}

// both tags are lightweight tags
return revTag1.name().compareTo(revTag1.getName());
} catch (IOException e) {
return block.call();
} catch (Exception e) {
throw new RuntimeException(e);
}
}

private static int compareTagVersion(Ref ref1, Ref ref2) {
DefaultArtifactVersion version1 = new DefaultArtifactVersion(ref1.getName());
DefaultArtifactVersion version2 = new DefaultArtifactVersion(ref2.getName());
// sort the highest version first
return -version1.compareTo(version2);
}

private static int compareTaggerDate(RevTag rev1, RevTag rev2) {
Date revTag1Date = rev1.getTaggerIdent().getWhen();
Date revTag2Date = rev2.getTaggerIdent().getWhen();
// sort the most recent tags first
return -revTag1Date.compareTo(revTag2Date);
}
}
13 changes: 6 additions & 7 deletions src/test/java/me/qoomon/gitversioning/commons/GitUtilTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.Status;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.InvalidRefNameException;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -91,7 +90,7 @@ void tagsPointAt_emptyRepo() throws GitAPIException, IOException {
Git git = Git.init().setInitialBranch(MASTER).setDirectory(tempDir.toFile()).call();
// when

List<String> tags = GitUtil.tagsPointAt(git.getRepository(), head(git));
List<String> tags = GitUtil.tagsPointAt(head(git), git.getRepository());

// then
assertThat(tags).isEmpty();
Expand All @@ -106,7 +105,7 @@ void tagsPointAt_noTags() throws GitAPIException, IOException {
git.commit().setMessage("initial commit").setAllowEmpty(true).call();

// when
List<String> tags = GitUtil.tagsPointAt(git.getRepository(), head(git));
List<String> tags = GitUtil.tagsPointAt(head(git), git.getRepository());

// then
assertThat(tags).isEmpty();
Expand All @@ -123,7 +122,7 @@ void tagsPointAt_oneTag() throws GitAPIException, IOException {
git.tag().setName(givenTagName).setObjectId(givenCommit).call();

// when
List<String> tags = GitUtil.tagsPointAt(git.getRepository(), head(git));
List<String> tags = GitUtil.tagsPointAt(head(git), git.getRepository());

// then
assertThat(tags).containsExactly(givenTagName);
Expand All @@ -145,7 +144,7 @@ void tagsPointAt_multipleTags() throws GitAPIException, IOException {
git.tag().setName(givenTagName3).setObjectId(givenCommit).call();

// when
List<String> tags = GitUtil.tagsPointAt(git.getRepository(), head(git));
List<String> tags = GitUtil.tagsPointAt(head(git), git.getRepository());

// then
assertThat(tags).containsExactly(givenTagName2, givenTagName3, givenTagName1);
Expand All @@ -163,7 +162,7 @@ void tagsPointAt_lightweightTag() throws GitAPIException, IOException {
git.tag().setName(givenTagName).setAnnotated(false).setObjectId(givenCommit).call();

// when
List<String> tags = GitUtil.tagsPointAt(git.getRepository(), head(git));
List<String> tags = GitUtil.tagsPointAt(head(git), git.getRepository());

// then
assertThat(tags).containsExactlyInAnyOrder(givenTagName);
Expand All @@ -188,7 +187,7 @@ void describe() throws Exception {
git.tag().setName(givenTagName).setAnnotated(true).setObjectId(givenCommit).setMessage(".").call();

// when
GitDescription description = GitUtil.describe(git.getRepository(), head(git), Pattern.compile("v.+"));
GitDescription description = GitUtil.describe(head(git), Pattern.compile("v.+"), git.getRepository());

// then
assertThat(description).satisfies(it -> {
Expand Down

0 comments on commit 02b2a22

Please sign in to comment.