Record submit records in notedb at submit time
Record a new footer, Submitted-with, to indicate the results of the submit rule evaluator. Record additional normalized labels during Submit by recording multiple commits in a single batch update, prior to the update that actually submits the change. Change-Id: Ia87913ad9d710fe0dea59ea56537e4ec1dd9f648
This commit is contained in:
@@ -16,21 +16,27 @@ package com.google.gerrit.server.notedb;
|
||||
|
||||
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_STATUS;
|
||||
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_SUBMITTED_WITH;
|
||||
import static com.google.gerrit.server.notedb.ChangeNoteUtil.GERRIT_PLACEHOLDER_HOST;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Enums;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableListMultimap;
|
||||
import com.google.common.collect.ImmutableSetMultimap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.Ordering;
|
||||
import com.google.common.collect.Table;
|
||||
import com.google.common.collect.Tables;
|
||||
import com.google.common.primitives.Ints;
|
||||
import com.google.gerrit.common.data.SubmitRecord;
|
||||
import com.google.gerrit.reviewdb.client.Account;
|
||||
import com.google.gerrit.reviewdb.client.Change;
|
||||
import com.google.gerrit.reviewdb.client.PatchSet;
|
||||
@@ -48,6 +54,7 @@ import org.eclipse.jgit.lib.CommitBuilder;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.lib.PersonIdent;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.revwalk.FooterKey;
|
||||
import org.eclipse.jgit.revwalk.RevCommit;
|
||||
import org.eclipse.jgit.revwalk.RevWalk;
|
||||
import org.eclipse.jgit.util.RawParseUtils;
|
||||
@@ -93,6 +100,8 @@ public class ChangeNotes extends VersionedMetaData {
|
||||
private final Map<PatchSet.Id,
|
||||
Table<Account.Id, String, Optional<PatchSetApproval>>> approvals;
|
||||
private final Map<Account.Id, ReviewerState> reviewers;
|
||||
private final List<SubmitRecord> submitRecords;
|
||||
private Change.Status status;
|
||||
|
||||
private Parser(Change.Id changeId, ObjectId tip, RevWalk walk) {
|
||||
this.changeId = changeId;
|
||||
@@ -100,6 +109,7 @@ public class ChangeNotes extends VersionedMetaData {
|
||||
this.walk = walk;
|
||||
approvals = Maps.newHashMap();
|
||||
reviewers = Maps.newLinkedHashMap();
|
||||
submitRecords = Lists.newArrayListWithExpectedSize(1);
|
||||
}
|
||||
|
||||
private void parseAll() throws ConfigInvalidException, IOException {
|
||||
@@ -127,12 +137,22 @@ public class ChangeNotes extends VersionedMetaData {
|
||||
}
|
||||
|
||||
private void parse(RevCommit commit) throws ConfigInvalidException {
|
||||
if (status == null) {
|
||||
status = parseStatus(commit);
|
||||
}
|
||||
PatchSet.Id psId = parsePatchSetId(commit);
|
||||
Account.Id accountId = parseIdent(commit);
|
||||
|
||||
if (submitRecords.isEmpty()) {
|
||||
// Only parse the most recent set of submit records; any older ones are
|
||||
// still there, but not currently used.
|
||||
parseSubmitRecords(commit.getFooterLines(FOOTER_SUBMITTED_WITH));
|
||||
}
|
||||
|
||||
for (String line : commit.getFooterLines(FOOTER_LABEL)) {
|
||||
parseApproval(psId, accountId, commit, line);
|
||||
}
|
||||
|
||||
for (ReviewerState state : ReviewerState.values()) {
|
||||
for (String line : commit.getFooterLines(state.getFooterKey())) {
|
||||
parseReviewer(state, line);
|
||||
@@ -140,17 +160,31 @@ public class ChangeNotes extends VersionedMetaData {
|
||||
}
|
||||
}
|
||||
|
||||
private Change.Status parseStatus(RevCommit commit)
|
||||
throws ConfigInvalidException {
|
||||
List<String> statusLines = commit.getFooterLines(FOOTER_STATUS);
|
||||
if (statusLines.isEmpty()) {
|
||||
return null;
|
||||
} else if (statusLines.size() > 1) {
|
||||
throw expectedOneFooter(FOOTER_STATUS, statusLines);
|
||||
}
|
||||
Optional<Change.Status> status = Enums.getIfPresent(
|
||||
Change.Status.class, statusLines.get(0).toUpperCase());
|
||||
if (!status.isPresent()) {
|
||||
throw invalidFooter(FOOTER_STATUS, statusLines.get(0));
|
||||
}
|
||||
return status.get();
|
||||
}
|
||||
|
||||
private PatchSet.Id parsePatchSetId(RevCommit commit)
|
||||
throws ConfigInvalidException {
|
||||
List<String> psIdLines = commit.getFooterLines(FOOTER_PATCH_SET);
|
||||
if (psIdLines.size() != 1) {
|
||||
throw parseException("missing or multiple %s: %s",
|
||||
FOOTER_PATCH_SET, psIdLines);
|
||||
throw expectedOneFooter(FOOTER_PATCH_SET, psIdLines);
|
||||
}
|
||||
Integer psId = Ints.tryParse(psIdLines.get(0));
|
||||
if (psId == null) {
|
||||
throw parseException("invalid %s: %s",
|
||||
FOOTER_PATCH_SET, psIdLines.get(0));
|
||||
throw invalidFooter(FOOTER_PATCH_SET, psIdLines.get(0));
|
||||
}
|
||||
return new PatchSet.Id(changeId, psId);
|
||||
}
|
||||
@@ -199,6 +233,50 @@ public class ChangeNotes extends VersionedMetaData {
|
||||
}
|
||||
}
|
||||
|
||||
private void parseSubmitRecords(List<String> lines)
|
||||
throws ConfigInvalidException {
|
||||
SubmitRecord rec = null;
|
||||
|
||||
for (String line : lines) {
|
||||
int c = line.indexOf(": ");
|
||||
if (c < 0) {
|
||||
rec = new SubmitRecord();
|
||||
submitRecords.add(rec);
|
||||
int s = line.indexOf(' ');
|
||||
String statusStr = s >= 0 ? line.substring(0, s) : line;
|
||||
Optional<SubmitRecord.Status> status =
|
||||
Enums.getIfPresent(SubmitRecord.Status.class, statusStr);
|
||||
checkFooter(status.isPresent(), FOOTER_SUBMITTED_WITH, line);
|
||||
rec.status = status.get();
|
||||
if (s >= 0) {
|
||||
rec.errorMessage = line.substring(s);
|
||||
}
|
||||
} else {
|
||||
checkFooter(rec != null, FOOTER_SUBMITTED_WITH, line);
|
||||
SubmitRecord.Label label = new SubmitRecord.Label();
|
||||
if (rec.labels == null) {
|
||||
rec.labels = Lists.newArrayList();
|
||||
}
|
||||
rec.labels.add(label);
|
||||
|
||||
Optional<SubmitRecord.Label.Status> status = Enums.getIfPresent(
|
||||
SubmitRecord.Label.Status.class, line.substring(0, c));
|
||||
checkFooter(status.isPresent(), FOOTER_SUBMITTED_WITH, line);
|
||||
label.status = status.get();
|
||||
int c2 = line.indexOf(": ", c + 2);
|
||||
if (c2 >= 0) {
|
||||
label.label = line.substring(c + 2, c2);
|
||||
PersonIdent ident =
|
||||
RawParseUtils.parsePersonIdent(line.substring(c2 + 2));
|
||||
checkFooter(ident != null, FOOTER_SUBMITTED_WITH, line);
|
||||
label.appliedBy = parseIdent(ident);
|
||||
} else {
|
||||
label.label = line.substring(c + 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Account.Id parseIdent(RevCommit commit)
|
||||
throws ConfigInvalidException {
|
||||
return parseIdent(commit.getAuthorIdent());
|
||||
@@ -223,8 +301,7 @@ public class ChangeNotes extends VersionedMetaData {
|
||||
throws ConfigInvalidException {
|
||||
PersonIdent ident = RawParseUtils.parsePersonIdent(line);
|
||||
if (ident == null) {
|
||||
throw parseException(
|
||||
"invalid %s: %s", state.getFooterKey().getName(), line);
|
||||
throw invalidFooter(state.getFooterKey(), line);
|
||||
}
|
||||
Account.Id accountId = parseIdent(ident);
|
||||
if (!reviewers.containsKey(accountId)) {
|
||||
@@ -250,6 +327,24 @@ public class ChangeNotes extends VersionedMetaData {
|
||||
return new ConfigInvalidException("Change " + changeId + ": "
|
||||
+ String.format(fmt, args));
|
||||
}
|
||||
|
||||
private ConfigInvalidException expectedOneFooter(FooterKey footer,
|
||||
List<String> actual) {
|
||||
return parseException("missing or multiple %s: %s",
|
||||
footer.getName(), actual);
|
||||
}
|
||||
|
||||
private ConfigInvalidException invalidFooter(FooterKey footer,
|
||||
String actual) {
|
||||
return parseException("invalid %s: %s", footer.getName(), actual);
|
||||
}
|
||||
|
||||
private void checkFooter(boolean expr, FooterKey footer, String actual)
|
||||
throws ConfigInvalidException {
|
||||
if (!expr) {
|
||||
throw invalidFooter(footer, actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final GitRepositoryManager repoManager;
|
||||
@@ -257,11 +352,12 @@ public class ChangeNotes extends VersionedMetaData {
|
||||
private boolean loaded;
|
||||
private ImmutableListMultimap<PatchSet.Id, PatchSetApproval> approvals;
|
||||
private ImmutableSetMultimap<ReviewerState, Account.Id> reviewers;
|
||||
private ImmutableList<SubmitRecord> submitRecords;
|
||||
|
||||
@VisibleForTesting
|
||||
ChangeNotes(GitRepositoryManager repoManager, Change change) {
|
||||
this.repoManager = repoManager;
|
||||
this.change = change;
|
||||
this.change = new Change(change);
|
||||
}
|
||||
|
||||
// TODO(dborowitz): Wrap fewer exceptions if/when we kill gwtorm.
|
||||
@@ -301,6 +397,14 @@ public class ChangeNotes extends VersionedMetaData {
|
||||
return reviewers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return submit records stored during the most recent submit; only for
|
||||
* changes that were actually submitted.
|
||||
*/
|
||||
public ImmutableList<SubmitRecord> getSubmitRecords() {
|
||||
return submitRecords;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getRefName() {
|
||||
return ChangeNoteUtil.changeRefName(change.getId());
|
||||
@@ -316,7 +420,12 @@ public class ChangeNotes extends VersionedMetaData {
|
||||
try {
|
||||
Parser parser = new Parser(change.getId(), rev, walk);
|
||||
parser.parseAll();
|
||||
|
||||
if (parser.status != null) {
|
||||
change.setStatus(parser.status);
|
||||
}
|
||||
approvals = parser.buildApprovals();
|
||||
|
||||
ImmutableSetMultimap.Builder<ReviewerState, Account.Id> reviewers =
|
||||
ImmutableSetMultimap.builder();
|
||||
for (Map.Entry<Account.Id, ReviewerState> e
|
||||
@@ -324,6 +433,7 @@ public class ChangeNotes extends VersionedMetaData {
|
||||
reviewers.put(e.getValue(), e.getKey());
|
||||
}
|
||||
this.reviewers = reviewers.build();
|
||||
submitRecords = ImmutableList.copyOf(parser.submitRecords);
|
||||
} finally {
|
||||
walk.release();
|
||||
}
|
||||
|
Reference in New Issue
Block a user