Support for reading and writing Hashtags from/to NoteDB
Change-Id: If8539f21bb29685d2fba8ab4d8612c3f588cb28b
This commit is contained in:
@@ -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");
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user