Support for reading and writing Hashtags from/to NoteDB

Change-Id: If8539f21bb29685d2fba8ab4d8612c3f588cb28b
This commit is contained in:
Gustaf Lundh
2014-09-09 10:26:57 +02:00
parent bcf97bd354
commit 8c9d00e005
5 changed files with 80 additions and 1 deletions

View File

@@ -27,6 +27,7 @@ import java.util.Date;
public class ChangeNoteUtil { public class ChangeNoteUtil {
static final String GERRIT_PLACEHOLDER_HOST = "gerrit"; static final String GERRIT_PLACEHOLDER_HOST = "gerrit";
static final FooterKey FOOTER_HASHTAGS = new FooterKey("Hashtags");
static final FooterKey FOOTER_LABEL = new FooterKey("Label"); static final FooterKey FOOTER_LABEL = new FooterKey("Label");
static final FooterKey FOOTER_PATCH_SET = new FooterKey("Patch-set"); static final FooterKey FOOTER_PATCH_SET = new FooterKey("Patch-set");
static final FooterKey FOOTER_STATUS = new FooterKey("Status"); static final FooterKey FOOTER_STATUS = new FooterKey("Status");

View File

@@ -22,6 +22,7 @@ import com.google.common.base.Function;
import com.google.common.collect.ComparisonChain; import com.google.common.collect.ComparisonChain;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap; import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap; import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Ordering; import com.google.common.collect.Ordering;
import com.google.common.collect.Table; import com.google.common.collect.Table;
@@ -138,6 +139,7 @@ public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
private ImmutableListMultimap<PatchSet.Id, ChangeMessage> changeMessages; private ImmutableListMultimap<PatchSet.Id, ChangeMessage> changeMessages;
private ImmutableListMultimap<PatchSet.Id, PatchLineComment> commentsForBase; private ImmutableListMultimap<PatchSet.Id, PatchLineComment> commentsForBase;
private ImmutableListMultimap<PatchSet.Id, PatchLineComment> commentsForPS; private ImmutableListMultimap<PatchSet.Id, PatchLineComment> commentsForPS;
private ImmutableSet<String> hashtags;
NoteMap noteMap; NoteMap noteMap;
private final AllUsersName allUsers; private final AllUsersName allUsers;
@@ -163,6 +165,10 @@ public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
return reviewers; return reviewers;
} }
public ImmutableSet<String> getHashtags() {
return hashtags;
}
/** /**
* @return a list of all users who have ever been a reviewer on this change. * @return a list of all users who have ever been a reviewer on this change.
*/ */
@@ -275,6 +281,11 @@ public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
commentsForPS = ImmutableListMultimap.copyOf(parser.commentsForPs); commentsForPS = ImmutableListMultimap.copyOf(parser.commentsForPs);
noteMap = parser.commentNoteMap; noteMap = parser.commentNoteMap;
if (parser.hashtags != null) {
hashtags = ImmutableSet.copyOf(parser.hashtags);
} else {
hashtags = ImmutableSet.of();
}
ImmutableSetMultimap.Builder<ReviewerState, Account.Id> reviewers = ImmutableSetMultimap.Builder<ReviewerState, Account.Id> reviewers =
ImmutableSetMultimap.builder(); ImmutableSetMultimap.builder();
for (Map.Entry<Account.Id, ReviewerState> e for (Map.Entry<Account.Id, ReviewerState> e

View File

@@ -14,6 +14,7 @@
package com.google.gerrit.server.notedb; package com.google.gerrit.server.notedb;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_HASHTAGS;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_LABEL; import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_LABEL;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_PATCH_SET; import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_PATCH_SET;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_STATUS; import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_STATUS;
@@ -22,6 +23,7 @@ import static com.google.gerrit.server.notedb.ChangeNoteUtil.GERRIT_PLACEHOLDER_
import com.google.common.base.Enums; import com.google.common.base.Enums;
import com.google.common.base.Optional; import com.google.common.base.Optional;
import com.google.common.base.Splitter;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableListMultimap; import com.google.common.collect.ImmutableListMultimap;
@@ -29,6 +31,7 @@ import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.google.common.collect.Table; import com.google.common.collect.Table;
import com.google.common.collect.Tables; import com.google.common.collect.Tables;
import com.google.common.primitives.Ints; import com.google.common.primitives.Ints;
@@ -63,6 +66,7 @@ import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
class ChangeNotesParser implements AutoCloseable { class ChangeNotesParser implements AutoCloseable {
final Map<Account.Id, ReviewerState> reviewers; final Map<Account.Id, ReviewerState> reviewers;
@@ -72,6 +76,7 @@ class ChangeNotesParser implements AutoCloseable {
final Multimap<PatchSet.Id, PatchLineComment> commentsForBase; final Multimap<PatchSet.Id, PatchLineComment> commentsForBase;
NoteMap commentNoteMap; NoteMap commentNoteMap;
Change.Status status; Change.Status status;
Set<String> hashtags;
private final Change.Id changeId; private final Change.Id changeId;
private final ObjectId tip; private final ObjectId tip;
@@ -143,6 +148,7 @@ class ChangeNotesParser implements AutoCloseable {
PatchSet.Id psId = parsePatchSetId(commit); PatchSet.Id psId = parsePatchSetId(commit);
Account.Id accountId = parseIdent(commit); Account.Id accountId = parseIdent(commit);
parseChangeMessage(psId, accountId, commit); parseChangeMessage(psId, accountId, commit);
parseHashtags(commit);
if (submitRecords.isEmpty()) { if (submitRecords.isEmpty()) {
@@ -162,6 +168,20 @@ class ChangeNotesParser implements AutoCloseable {
} }
} }
private void parseHashtags(RevCommit commit) throws ConfigInvalidException {
// Commits are parsed in reverse order and only the last set of hashtags should be used.
if (hashtags != null) {
return;
}
List<String> hashtagsLines = commit.getFooterLines(FOOTER_HASHTAGS);
if (hashtagsLines.isEmpty()) {
return;
} else if (hashtagsLines.size() > 1) {
throw expectedOneFooter(FOOTER_HASHTAGS, hashtagsLines);
}
hashtags = Sets.newHashSet(Splitter.on(',').split(hashtagsLines.get(0)));
}
private Change.Status parseStatus(RevCommit commit) private Change.Status parseStatus(RevCommit commit)
throws ConfigInvalidException { throws ConfigInvalidException {
List<String> statusLines = commit.getFooterLines(FOOTER_STATUS); List<String> statusLines = commit.getFooterLines(FOOTER_STATUS);

View File

@@ -15,6 +15,7 @@
package com.google.gerrit.server.notedb; package com.google.gerrit.server.notedb;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_HASHTAGS;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_LABEL; import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_LABEL;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_PATCH_SET; import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_PATCH_SET;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_STATUS; import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_STATUS;
@@ -22,6 +23,7 @@ import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_SUBMITTED_WI
import static com.google.gerrit.server.notedb.CommentsInNotesUtil.getCommentPsId; import static com.google.gerrit.server.notedb.CommentsInNotesUtil.getCommentPsId;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
import com.google.common.base.Optional; import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
@@ -62,6 +64,7 @@ import java.util.Comparator;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
/** /**
* A delta to apply to a change. * A delta to apply to a change.
@@ -93,6 +96,7 @@ public class ChangeUpdate extends AbstractChangeUpdate {
private final CommentsInNotesUtil commentsUtil; private final CommentsInNotesUtil commentsUtil;
private List<PatchLineComment> commentsForBase; private List<PatchLineComment> commentsForBase;
private List<PatchLineComment> commentsForPs; private List<PatchLineComment> commentsForPs;
private Set<String> hashtags;
private String changeMessage; private String changeMessage;
private ChangeNotes notes; private ChangeNotes notes;
@@ -342,6 +346,10 @@ public class ChangeUpdate extends AbstractChangeUpdate {
} }
public void setHashtags(Set<String> hashtags) {
this.hashtags = hashtags;
}
public void putReviewer(Account.Id reviewer, ReviewerState type) { public void putReviewer(Account.Id reviewer, ReviewerState type) {
checkArgument(type != ReviewerState.REMOVED, "invalid ReviewerType"); checkArgument(type != ReviewerState.REMOVED, "invalid ReviewerType");
reviewers.put(reviewer, type); reviewers.put(reviewer, type);
@@ -448,6 +456,10 @@ public class ChangeUpdate extends AbstractChangeUpdate {
addFooter(msg, FOOTER_STATUS, status.name().toLowerCase()); addFooter(msg, FOOTER_STATUS, status.name().toLowerCase());
} }
if (hashtags != null) {
addFooter(msg, FOOTER_HASHTAGS, Joiner.on(",").join(hashtags));
}
for (Map.Entry<Account.Id, ReviewerState> e : reviewers.entrySet()) { for (Map.Entry<Account.Id, ReviewerState> e : reviewers.entrySet()) {
Account account = accountCache.get(e.getKey()).getAccount(); Account account = accountCache.get(e.getKey()).getAccount();
PersonIdent ident = newIdent(account, when); PersonIdent ident = newIdent(account, when);
@@ -507,7 +519,8 @@ public class ChangeUpdate extends AbstractChangeUpdate {
&& reviewers.isEmpty() && reviewers.isEmpty()
&& status == null && status == null
&& subject == null && subject == null
&& submitRecords == null; && submitRecords == null
&& hashtags == null;
} }
private static StringBuilder addFooter(StringBuilder sb, FooterKey footer) { private static StringBuilder addFooter(StringBuilder sb, FooterKey footer) {

View File

@@ -58,6 +58,7 @@ import org.junit.Test;
import java.io.IOException; import java.io.IOException;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
public class ChangeNotesTest extends AbstractChangeNotesTest { public class ChangeNotesTest extends AbstractChangeNotesTest {
@@ -338,6 +339,39 @@ public class ChangeNotesTest extends AbstractChangeNotesTest {
assertNull(update.getRevision()); assertNull(update.getRevision());
} }
@Test
public void hashtagCommit() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
LinkedHashSet<String> hashtags = new LinkedHashSet<String>();
hashtags.add("tag1");
hashtags.add("tag2");
update.setHashtags(hashtags);
update.commit();
RevWalk walk = new RevWalk(repo);
try {
RevCommit commit = walk.parseCommit(update.getRevision());
walk.parseBody(commit);
assertTrue(commit.getFullMessage().endsWith("Hashtags: tag1,tag2\n"));
} finally {
walk.release();
}
}
@Test
public void hashtagChangeNotes() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
LinkedHashSet<String> hashtags = new LinkedHashSet<String>();
hashtags.add("tag1");
hashtags.add("tag2");
update.setHashtags(hashtags);
update.commit();
ChangeNotes notes = newNotes(c);
assertEquals(hashtags, notes.getHashtags());
}
@Test @Test
public void emptyExceptSubject() throws Exception { public void emptyExceptSubject() throws Exception {
ChangeUpdate update = newUpdate(newChange(), changeOwner); ChangeUpdate update = newUpdate(newChange(), changeOwner);