Skip to content

Commit 8531891

Browse files
committed
Merge pull request #195 from TheSnoozer/master
#54: Reveal describe details (tag name, number of commits)
2 parents b43afd2 + 52a5375 commit 8531891

38 files changed

+721
-392
lines changed

README.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,11 +306,14 @@ git.commit.user.email=${git.commit.user.email}
306306
git.commit.message.full=${git.commit.message.full}
307307
git.commit.message.short=${git.commit.message.short}
308308
git.commit.time=${git.commit.time}
309+
git.closest.tag.name=${git.closest.tag.name}
310+
git.closest.tag.commit.count=${git.closest.tag.commit.count}
309311
310312
git.build.user.name=${git.build.user.name}
311313
git.build.user.email=${git.build.user.email}
312314
git.build.time=${git.build.time}
313315
git.build.host=${git.build.host}
316+
git.build.version=${git.build.version}
314317
```
315318

316319
The `git` prefix may be configured in the plugin declaration above.
@@ -341,11 +344,14 @@ Start out with with adding the above steps to your project, next paste this **gi
341344
<property name="commitMessageFull" value="${git.commit.message.full}"/>
342345
<property name="commitMessageShort" value="${git.commit.message.short}"/>
343346
<property name="commitTime" value="${git.commit.time}"/>
347+
<property name="closestTagName" value="${git.closest.tag.name}"/>
348+
<property name="closestTagCommitCount" value="${git.closest.tag.commit.count}"/>
344349

345350
<property name="buildUserName" value="${git.build.user.name}"/>
346351
<property name="buildUserEmail" value="${git.build.user.email}"/>
347352
<property name="buildTime" value="${git.build.time}"/>
348353
<property name="buildHost" value="${git.build.host}"/>
354+
<porperty name="buildVersion" value="${git.build.version}"/>
349355
</bean>
350356
</beans>
351357
```
@@ -378,12 +384,15 @@ public class GitRepositoryState {
378384
String commitMessageFull; // =${git.commit.message.full}
379385
String commitMessageShort; // =${git.commit.message.short}
380386
String commitTime; // =${git.commit.time}
387+
String closestTagName; // =${git.closest.tag.name}
388+
String closestTagCommitCount; // =${git.closest.tag.commit.count}
381389

382390
String buildUserName; // =${git.build.user.name}
383391
String buildUserEmail; // =${git.build.user.email}
384392
String buildTime; // =${git.build.time}
385393
String buildHost; // =${git.build.host}
386-
394+
String buildVersion // =${git.build.version}
395+
387396
public GitRepositoryState() {
388397
}
389398
/* Generate setters and getters here */
@@ -438,11 +447,14 @@ In the end *this is what this service would return*:
438447
+ added license etc",
439448
"commitMessageShort" : "releasing my fun plugin :-)",
440449
"commitTime" : "06.01.1970 @ 16:16:26 CET",
450+
"closestTagName" : "v2.1.0",
451+
"closestTagCommitCount" : "2",
441452

442453
"buildUserName" : "Konrad Malawski",
443454
"buildUserEmail" : "konrad.malawski@java.pl",
444455
"buildTime" : "06.01.1970 @ 16:17:53 CET",
445-
"buildHost" : "github.com"
456+
"buildHost" : "github.com",
457+
"buildVersion" : "v2.1.0-SNAPSHOT"
446458
}
447459
```
448460

@@ -503,11 +515,14 @@ public GitRepositoryState(Properties properties)
503515
this.commitMessageFull = properties.get("git.commit.message.full").toString();
504516
this.commitMessageShort = properties.get("git.commit.message.short").toString();
505517
this.commitTime = properties.get("git.commit.time").toString();
518+
this.closestTagName = properties.get("git.closest.tag.name").toString();
519+
this.closestTagCommitCount = properties.get("git.closest.tag.commit.count").toString();
506520

507521
this.buildUserName = properties.get("git.build.user.name").toString();
508522
this.buildUserEmail = properties.get("git.build.user.email").toString();
509523
this.buildTime = properties.get("git.build.time").toString();
510524
this.buildHost = properties.get("git.build.host").toString();
525+
this.buildVersion = properties.get("git.build.version").toString();
511526
}
512527
```
513528

src/main/java/pl/project13/jgit/DescribeCommand.java

Lines changed: 11 additions & 223 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* This file is part of git-commit-id-plugin by Konrad Malawski <konrad.malawski@java.pl>
2+
* This file is part of git-commit-id-plugin by Konrad 'ktoso' Malawski <konrad.malawski@java.pl>
33
*
44
* git-commit-id-plugin is free software: you can redistribute it and/or modify
55
* it under the terms of the GNU Lesser General Public License as published by
@@ -18,25 +18,21 @@
1818
package pl.project13.jgit;
1919

2020
import com.google.common.annotations.VisibleForTesting;
21-
import com.google.common.base.Function;
2221
import com.google.common.base.Optional;
2322
import com.google.common.base.Preconditions;
24-
import com.google.common.base.Throwables;
25-
import com.google.common.collect.Lists;
23+
2624
import org.eclipse.jgit.api.Git;
2725
import org.eclipse.jgit.api.GitCommand;
2826
import org.eclipse.jgit.api.Status;
2927
import org.eclipse.jgit.api.errors.GitAPIException;
30-
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
3128
import org.eclipse.jgit.lib.ObjectId;
3229
import org.eclipse.jgit.lib.ObjectReader;
33-
import org.eclipse.jgit.lib.Ref;
3430
import org.eclipse.jgit.lib.Repository;
3531
import org.eclipse.jgit.revwalk.RevCommit;
36-
import org.eclipse.jgit.revwalk.RevTag;
3732
import org.eclipse.jgit.revwalk.RevWalk;
3833
import org.jetbrains.annotations.NotNull;
3934
import org.jetbrains.annotations.Nullable;
35+
4036
import pl.project13.jgit.dummy.DatedRevTag;
4137
import pl.project13.maven.git.GitDescribeConfig;
4238
import pl.project13.maven.git.log.LoggerBridge;
@@ -45,23 +41,16 @@
4541

4642
import java.io.IOException;
4743
import java.util.*;
48-
import java.util.regex.Pattern;
49-
50-
import static com.google.common.collect.Lists.newArrayList;
51-
import static com.google.common.collect.Lists.newLinkedList;
52-
import static com.google.common.collect.Maps.newHashMap;
53-
import static com.google.common.collect.Sets.newHashSet;
5444

5545
/**
5646
* Implements git's <pre>describe</pre> command.
57-
*
58-
* @author Konrad Malawski
5947
*/
6048
public class DescribeCommand extends GitCommand<DescribeResult> {
6149

6250
private LoggerBridge loggerBridge;
51+
private JGitCommon jGitCommon;
6352

64-
// todo not yet implemented options:
53+
// TODO not yet implemented options:
6554
// private boolean containsFlag = false;
6655
// private boolean allFlag = false;
6756
// private boolean tagsFlag = false;
@@ -116,6 +105,7 @@ private DescribeCommand(Repository repo, boolean verbose) {
116105
super(repo);
117106
initDefaultLoggerBridge(verbose);
118107
setVerbose(verbose);
108+
this.jGitCommon = new JGitCommon();
119109
}
120110

121111
private void initDefaultLoggerBridge(boolean verbose) {
@@ -305,7 +295,7 @@ public DescribeResult call() throws GitAPIException {
305295
}
306296

307297
// get commits, up until the nearest tag
308-
List<RevCommit> commits = findCommitsUntilSomeTag(repo, headCommit, tagObjectIdToName);
298+
List<RevCommit> commits = jGitCommon.findCommitsUntilSomeTag(repo, headCommit, tagObjectIdToName);
309299

310300
// if there is no tags or any tag is not on that branch then return generic describe
311301
if (foundZeroTags(tagObjectIdToName) || commits.isEmpty()) {
@@ -315,7 +305,7 @@ public DescribeResult call() throws GitAPIException {
315305

316306
// check how far away from a tag we are
317307

318-
int distance = distanceBetween(repo, headCommit, commits.get(0));
308+
int distance = jGitCommon.distanceBetween(repo, headCommit, commits.get(0));
319309
String tagName = tagObjectIdToName.get(commits.get(0)).iterator().next();
320310
Pair<Integer, String> howFarFromWhichTag = Pair.of(distance, tagName);
321311

@@ -396,206 +386,14 @@ RevCommit findHeadObjectId(@NotNull Repository repo) throws RuntimeException {
396386
}
397387
}
398388

399-
private List<RevCommit> findCommitsUntilSomeTag(Repository repo, RevCommit head, @NotNull Map<ObjectId, List<String>> tagObjectIdToName) {
400-
RevWalk revWalk = new RevWalk(repo);
401-
try {
402-
revWalk.markStart(head);
403-
404-
for (RevCommit commit : revWalk) {
405-
ObjectId objId = commit.getId();
406-
if (tagObjectIdToName.size() > 0) {
407-
List<String> maybeList = tagObjectIdToName.get(objId);
408-
if (maybeList != null && maybeList.get(0) != null) {
409-
return Collections.singletonList(commit);
410-
}
411-
}
412-
}
413-
414-
return Collections.emptyList();
415-
} catch (Exception e) {
416-
throw new RuntimeException("Unable to find commits until some tag", e);
417-
}
418-
}
419-
420-
/**
421-
* Calculates the distance (number of commits) between the given parent and child commits.
422-
*
423-
* @return distance (number of commits) between the given commits
424-
* @see <a href="https://github.com/mdonoughe/jgit-describe/blob/master/src/org/mdonoughe/JGitDescribeTask.java">mdonoughe/jgit-describe/blob/master/src/org/mdonoughe/JGitDescribeTask.java</a>
425-
*/
426-
private int distanceBetween(@NotNull Repository repo, @NotNull RevCommit child, @NotNull RevCommit parent) {
427-
RevWalk revWalk = new RevWalk(repo);
428-
429-
try {
430-
revWalk.markStart(child);
431-
432-
Set<ObjectId> seena = newHashSet();
433-
Set<ObjectId> seenb = newHashSet();
434-
Queue<RevCommit> q = newLinkedList();
435-
436-
q.add(revWalk.parseCommit(child));
437-
int distance = 0;
438-
ObjectId parentId = parent.getId();
439-
440-
while (q.size() > 0) {
441-
RevCommit commit = q.remove();
442-
ObjectId commitId = commit.getId();
443-
444-
if (seena.contains(commitId)) {
445-
continue;
446-
}
447-
seena.add(commitId);
448-
449-
if (parentId.equals(commitId)) {
450-
// don't consider commits that are included in this commit
451-
seeAllParents(revWalk, commit, seenb);
452-
// remove things we shouldn't have included
453-
for (ObjectId oid : seenb) {
454-
if (seena.contains(oid)) {
455-
distance--;
456-
}
457-
}
458-
seena.addAll(seenb);
459-
continue;
460-
}
461-
462-
for (ObjectId oid : commit.getParents()) {
463-
if (!seena.contains(oid)) {
464-
q.add(revWalk.parseCommit(oid));
465-
}
466-
}
467-
distance++;
468-
}
469-
470-
return distance;
471-
472-
} catch (Exception e) {
473-
throw new RuntimeException(String.format("Unable to calculate distance between [%s] and [%s]", child, parent), e);
474-
} finally {
475-
revWalk.dispose();
476-
}
477-
}
478-
479-
private static void seeAllParents(@NotNull RevWalk revWalk, RevCommit child, @NotNull Set<ObjectId> seen) throws IOException {
480-
Queue<RevCommit> q = newLinkedList();
481-
q.add(child);
482-
483-
while (q.size() > 0) {
484-
RevCommit commit = q.remove();
485-
for (ObjectId oid : commit.getParents()) {
486-
if (seen.contains(oid)) {
487-
continue;
488-
}
489-
seen.add(oid);
490-
q.add(revWalk.parseCommit(oid));
491-
}
492-
}
493-
}
494-
495389
// git commit id -> its tag (or tags)
496390
private Map<ObjectId, List<String>> findTagObjectIds(@NotNull Repository repo, boolean tagsFlag) {
497-
Map<ObjectId, List<DatedRevTag>> commitIdsToTags = newHashMap();
498-
499-
RevWalk walk = new RevWalk(repo);
500-
try {
501-
walk.markStart(walk.parseCommit(repo.resolve("HEAD")));
502-
503-
List<Ref> tagRefs = Git.wrap(repo).tagList().call();
504-
String matchPattern = createMatchPattern();
505-
Pattern regex = Pattern.compile(matchPattern);
506-
log("Tag refs [", tagRefs, "]");
507-
508-
for (Ref tagRef : tagRefs) {
509-
walk.reset();
510-
String name = tagRef.getName();
511-
if (!regex.matcher(name).matches()) {
512-
log("Skipping tagRef with name [", name, "] as it doesn't match [", matchPattern, "]");
513-
continue;
514-
}
515-
ObjectId resolvedCommitId = repo.resolve(name);
516-
517-
// todo that's a bit of a hack...
518-
try {
519-
final RevTag revTag = walk.parseTag(resolvedCommitId);
520-
ObjectId taggedCommitId = revTag.getObject().getId();
521-
log("Resolved tag [",revTag.getTagName(),"] [",revTag.getTaggerIdent(),"], points at [",taggedCommitId,"] ");
522-
523-
// sometimes a tag, may point to another tag, so we need to unpack it
524-
while (isTagId(taggedCommitId)) {
525-
taggedCommitId = walk.parseTag(taggedCommitId).getObject().getId();
526-
}
527-
528-
if (commitIdsToTags.containsKey(taggedCommitId)) {
529-
commitIdsToTags.get(taggedCommitId).add(new DatedRevTag(revTag));
530-
} else {
531-
commitIdsToTags.put(taggedCommitId, newArrayList(new DatedRevTag(revTag)));
532-
}
533-
534-
} catch (IncorrectObjectTypeException ex) {
535-
// it's an lightweight tag! (yeah, really)
536-
if (tagsFlag) {
537-
// --tags means "include lightweight tags"
538-
log("Including lightweight tag [", name, "]");
539-
540-
DatedRevTag datedRevTag = new DatedRevTag(resolvedCommitId, name);
541-
542-
if (commitIdsToTags.containsKey(resolvedCommitId)) {
543-
commitIdsToTags.get(resolvedCommitId).add(datedRevTag);
544-
} else {
545-
commitIdsToTags.put(resolvedCommitId, newArrayList(datedRevTag));
546-
}
547-
}
548-
} catch (Exception ignored) {
549-
error("Failed while parsing [",tagRef,"] -- ", Throwables.getStackTraceAsString(ignored));
550-
}
551-
}
552-
553-
for (Map.Entry<ObjectId, List<DatedRevTag>> entry : commitIdsToTags.entrySet()) {
554-
log("key [",entry.getKey(),"], tags => [",entry.getValue(),"] ");
555-
}
556-
557-
Map<ObjectId, List<String>> commitIdsToTagNames = transformRevTagsMapToDateSortedTagNames(commitIdsToTags);
558-
391+
String matchPattern = createMatchPattern();
392+
Map<ObjectId, List<DatedRevTag>> commitIdsToTags = jGitCommon.getCommitIdsToTags(loggerBridge, repo, tagsFlag, matchPattern);
393+
Map<ObjectId, List<String>> commitIdsToTagNames = jGitCommon.transformRevTagsMapToDateSortedTagNames(commitIdsToTags);
559394
log("Created map: [",commitIdsToTagNames,"] ");
560395

561396
return commitIdsToTagNames;
562-
} catch (Exception e) {
563-
log("Unable to locate tags\n[",Throwables.getStackTraceAsString(e),"]");
564-
} finally {
565-
walk.release();
566-
}
567-
568-
return Collections.emptyMap();
569-
}
570-
571-
/** Checks if the given object id resolved to a tag object */
572-
private boolean isTagId(ObjectId objectId) {
573-
return objectId.toString().startsWith("tag ");
574-
}
575-
576-
private HashMap<ObjectId, List<String>> transformRevTagsMapToDateSortedTagNames(Map<ObjectId, List<DatedRevTag>> commitIdsToTags) {
577-
HashMap<ObjectId, List<String>> commitIdsToTagNames = newHashMap();
578-
for (Map.Entry<ObjectId, List<DatedRevTag>> objectIdListEntry : commitIdsToTags.entrySet()) {
579-
List<DatedRevTag> tags = objectIdListEntry.getValue();
580-
581-
List<DatedRevTag> newTags = newArrayList(tags);
582-
Collections.sort(newTags, new Comparator<DatedRevTag>() {
583-
@Override
584-
public int compare(DatedRevTag revTag, DatedRevTag revTag2) {
585-
return revTag2.date.compareTo(revTag.date);
586-
}
587-
});
588-
589-
List<String> tagNames = Lists.transform(newTags, new Function<DatedRevTag, String>() {
590-
@Override
591-
public String apply(DatedRevTag input) {
592-
return trimFullTagName(input.tagName);
593-
}
594-
});
595-
596-
commitIdsToTagNames.put(objectIdListEntry.getKey(), tagNames);
597-
}
598-
return commitIdsToTagNames;
599397
}
600398

601399
private String createMatchPattern() {
@@ -610,18 +408,8 @@ private String createMatchPattern() {
610408
return buf.toString();
611409
}
612410

613-
@VisibleForTesting
614-
static String trimFullTagName(@NotNull String tagName) {
615-
return tagName.replaceFirst("refs/tags/", "");
616-
}
617-
618411
private void log(Object... parts) {
619412
loggerBridge.log(parts);
620413
}
621-
622-
private void error(Object... parts) {
623-
loggerBridge.error(parts);
624-
}
625-
626414
}
627415

0 commit comments

Comments
 (0)