Merge branch 'stable-3.1' into stable-3.2
* stable-3.1:
Add new documentation for the owners-autoassign plugin
Allow async assignment of reviewers
Change-Id: I032a06624ff327952d667f786d52f3a5e9261a28
diff --git a/WORKSPACE b/WORKSPACE
index 96a6228..67f7e9e 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -3,7 +3,7 @@
load("//:bazlets.bzl", "load_bazlets")
load_bazlets(
- commit = "56aafc4c0bb1b72fba34f5bdfb29ddb1e1a17801",
+ commit = "4a27255dff75eadc98b86391806be13e030e6ff3",
#local_path = "/home/<user>/projects/bazlets",
)
diff --git a/owners-autoassign/src/main/java/com/googlesource/gerrit/owners/common/GitRefListener.java b/owners-autoassign/src/main/java/com/googlesource/gerrit/owners/common/GitRefListener.java
index 81559f7..6f53d04 100644
--- a/owners-autoassign/src/main/java/com/googlesource/gerrit/owners/common/GitRefListener.java
+++ b/owners-autoassign/src/main/java/com/googlesource/gerrit/owners/common/GitRefListener.java
@@ -18,10 +18,12 @@
import static com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace.IGNORE_NONE;
+import com.google.common.base.Predicates;
import com.google.common.collect.Sets;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.Project;
+import com.google.gerrit.entities.Project.NameKey;
import com.google.gerrit.entities.RefNames;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.annotations.Listen;
@@ -32,8 +34,10 @@
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.events.GitReferenceUpdatedListener;
import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.server.ChangeMessagesUtil;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.patch.PatchList;
import com.google.gerrit.server.patch.PatchListCache;
import com.google.gerrit.server.patch.PatchListKey;
@@ -46,6 +50,7 @@
import java.util.Set;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -64,6 +69,8 @@
private Provider<CurrentUser> currentUserProvider;
+ private ChangeNotes.Factory notesFactory;
+
@Inject
public GitRefListener(
GerritApi api,
@@ -72,7 +79,8 @@
Accounts accounts,
ReviewerManager reviewerManager,
OneOffRequestContext oneOffReqCtx,
- Provider<CurrentUser> currentUserProvider) {
+ Provider<CurrentUser> currentUserProvider,
+ ChangeNotes.Factory notesFactory) {
this.api = api;
this.patchListCache = patchListCache;
this.repositoryManager = repositoryManager;
@@ -80,6 +88,7 @@
this.reviewerManager = reviewerManager;
this.oneOffReqCtx = oneOffReqCtx;
this.currentUserProvider = currentUserProvider;
+ this.notesFactory = notesFactory;
}
@Override
@@ -120,11 +129,15 @@
String projectName = event.getProjectName();
Repository repository;
try {
- repository = repositoryManager.openRepository(Project.NameKey.parse(projectName));
+ NameKey projectNameKey = Project.NameKey.parse(projectName);
+ repository = repositoryManager.openRepository(projectNameKey);
try {
String refName = event.getRefName();
- if (refName.startsWith(RefNames.REFS_CHANGES) && !RefNames.isNoteDbMetaRef(refName)) {
- processEvent(repository, event);
+ Change.Id changeId = Change.Id.fromRef(refName);
+ if (changeId != null
+ && (!RefNames.isNoteDbMetaRef(refName)
+ || isChangeSetReadyForReview(projectNameKey, changeId, event.getNewObjectId()))) {
+ processEvent(repository, event, changeId);
}
} finally {
repository.close();
@@ -134,15 +147,25 @@
}
}
- public void processEvent(Repository repository, Event event) {
- Change.Id cId = Change.Id.fromRef(event.getRefName());
+ private boolean isChangeSetReadyForReview(
+ NameKey project, Change.Id changeId, String metaObjectId) {
+ ChangeNotes changeNotes = notesFactory.createChecked(project, changeId);
+ return !changeNotes.getChange().isWorkInProgress()
+ && changeNotes.getChangeMessages().stream()
+ .filter(message -> message.getKey().uuid().equals(metaObjectId))
+ .map(message -> message.getTag())
+ .filter(Predicates.notNull())
+ .anyMatch(tag -> tag.contains(ChangeMessagesUtil.TAG_SET_READY));
+ }
+
+ public void processEvent(Repository repository, Event event, Change.Id cId) {
Changes changes = api.changes();
// The provider injected by Gerrit is shared with other workers on the
// same local thread and thus cannot be closed in this event listener.
try {
ChangeApi cApi = changes.id(cId.get());
ChangeInfo change = cApi.get();
- PatchList patchList = getPatchList(event, change);
+ PatchList patchList = getPatchList(repository, event, change);
if (patchList != null) {
PathOwners owners = new PathOwners(accounts, repository, change.branch, patchList);
Set<Account.Id> allReviewers = Sets.newHashSet();
@@ -160,17 +183,23 @@
}
}
- private PatchList getPatchList(Event event, ChangeInfo change) {
+ private PatchList getPatchList(Repository repository, Event event, ChangeInfo change) {
ObjectId newId = null;
- if (event.getNewObjectId() != null) {
- newId = ObjectId.fromString(event.getNewObjectId());
- }
-
- PatchListKey plKey = PatchListKey.againstCommit(null, newId, IGNORE_NONE);
+ PatchListKey plKey;
try {
+ if (RefNames.isNoteDbMetaRef(event.getRefName())) {
+ newId = ObjectId.fromString(change.currentRevision);
+ RevCommit revCommit = repository.parseCommit(newId);
+ plKey = PatchListKey.againstBase(newId, revCommit.getParentCount());
+ } else {
+ if (event.getNewObjectId() != null) {
+ newId = ObjectId.fromString(event.getNewObjectId());
+ }
+ plKey = PatchListKey.againstCommit(null, newId, IGNORE_NONE);
+ }
return patchListCache.get(plKey, Project.nameKey(change.project));
- } catch (PatchListNotAvailableException e) {
- logger.warn("Could not load patch list: {}", plKey, e);
+ } catch (PatchListNotAvailableException | IOException e) {
+ logger.warn("Could not load patch list for change {}", change.id, e);
}
return null;
}
diff --git a/owners-autoassign/src/test/java/com/googlesource/gerrit/owners/common/GitRefListenerIT.java b/owners-autoassign/src/test/java/com/googlesource/gerrit/owners/common/GitRefListenerIT.java
index 58db2d8..18dea29 100644
--- a/owners-autoassign/src/test/java/com/googlesource/gerrit/owners/common/GitRefListenerIT.java
+++ b/owners-autoassign/src/test/java/com/googlesource/gerrit/owners/common/GitRefListenerIT.java
@@ -21,11 +21,14 @@
import com.google.gerrit.acceptance.TestPlugin;
import com.google.gerrit.entities.RefNames;
import com.google.gerrit.extensions.events.GitReferenceUpdatedListener;
+import com.google.gerrit.extensions.registration.DynamicSet;
+import com.google.gerrit.extensions.registration.Extension;
import com.google.gerrit.server.AnonymousUser;
import com.google.gerrit.server.util.ManualRequestContext;
import com.google.gerrit.server.util.ThreadLocalRequestContext;
import com.google.inject.AbstractModule;
import com.google.inject.Inject;
+import java.util.stream.StreamSupport;
import com.googlesource.gerrit.owners.common.ReviewerManager;
import org.eclipse.jgit.transport.ReceiveCommand.Type;
@@ -36,62 +39,97 @@
sysModule = "com.googlesource.gerrit.owners.common.GitRefListenerIT$TestModule")
public class GitRefListenerIT extends LightweightPluginDaemonTest {
- @Inject GitRefListenerTest gitRefListener;
+ @Inject DynamicSet<GitReferenceUpdatedListener> allRefUpdateListeners;
@Inject ThreadLocalRequestContext requestContext;
- String aRefChange = RefNames.REFS_CHANGES + "01/01/01";
String anOldObjectId = "anOldRef";
String aNewObjectId = "aNewRef";
public static class TestModule extends AbstractModule {
@Override
protected void configure() {
- bind(GitReferenceUpdatedListener.class).to(GitRefListenerTest.class);
+ DynamicSet.bind(binder(), GitReferenceUpdatedListener.class).to(GitRefListenerTest.class);
}
}
@Test
- public void shouldNotProcessNoteDbOnlyRefs() {
+ public void shouldNotProcessNoteDbOnlyRefs() throws Exception {
+ String changeRefPrefix = createChange().getChange().getId().toRefPrefix();
+ int baselineProcessedEvents = gitRefListener().getProcessedEvents();
+
ReferenceUpdatedEventTest refUpdatedEvent =
new ReferenceUpdatedEventTest(
project,
- RefNames.REFS_CHANGES + "01/01" + RefNames.META_SUFFIX,
+ changeRefPrefix + RefNames.META_SUFFIX.substring(1),
anOldObjectId,
aNewObjectId,
Type.CREATE,
admin.id());
- gitRefListener.onGitReferenceUpdated(refUpdatedEvent);
- assertEquals(0, gitRefListener.getProcessedEvents());
+ gitRefListener().onGitReferenceUpdated(refUpdatedEvent);
+ assertEquals(baselineProcessedEvents, gitRefListener().getProcessedEvents());
}
@Test
- public void shouldProcessRefChanges() {
- gitRefListener.onGitReferenceUpdated(newRefUpdateEvent());
- assertEquals(1, gitRefListener.getProcessedEvents());
+ public void shoulProcessSetReadyForReviewOnNoteDb() throws Exception {
+ int wipChangeNum = createChange().getChange().getId().get();
+ gApi.changes().id(wipChangeNum).setWorkInProgress();
+
+ int baselineProcessedEvents = gitRefListener().getProcessedEvents();
+
+ gApi.changes().id(wipChangeNum).setReadyForReview();
+ assertEquals(1, gitRefListener().getProcessedEvents() - baselineProcessedEvents);
+ }
+
+ @Test
+ public void shoulNotProcessEmptyMetaRefUpdatesAfterSetReadyForReviewOnNoteDb() throws Exception {
+ int wipChangeNum = createChange().getChange().getId().get();
+ gApi.changes().id(wipChangeNum).setWorkInProgress();
+ gApi.changes().id(wipChangeNum).setReadyForReview();
+ int baselineProcessedEvents = gitRefListener().getProcessedEvents();
+
+ gApi.changes().id(wipChangeNum).addReviewer("user");
+ assertEquals(baselineProcessedEvents, gitRefListener().getProcessedEvents());
+ }
+
+ @Test
+ public void shouldProcessRefChanges() throws Exception {
+ gitRefListener().onGitReferenceUpdated(newRefUpdateEvent());
+ assertEquals(1, gitRefListener().getProcessedEvents());
}
@Test
public void shouldRetrieveChangeFromAnonymousContext() throws Exception {
try (ManualRequestContext ctx = new ManualRequestContext(new AnonymousUser(), requestContext)) {
- gitRefListener.onGitReferenceUpdated(newRefUpdateEvent());
- assertEquals(1, gitRefListener.getProcessedEvents());
+ gitRefListener().onGitReferenceUpdated(newRefUpdateEvent());
+ assertEquals(1, gitRefListener().getProcessedEvents());
}
}
@Test
public void shouldRetrieveChangeFromAnonymousContextWithoutAccountId() throws Exception {
+ String refPrefix = createChange().getChange().getId().toRefPrefix();
ReferenceUpdatedEventTest refUpdateWithoutAccountId =
new ReferenceUpdatedEventTest(
- project, aRefChange, anOldObjectId, aNewObjectId, Type.CREATE, null);
+ project, refPrefix, anOldObjectId, aNewObjectId, Type.CREATE, null);
try (ManualRequestContext ctx = new ManualRequestContext(new AnonymousUser(), requestContext)) {
- gitRefListener.onGitReferenceUpdated(refUpdateWithoutAccountId);
- assertEquals(1, gitRefListener.getProcessedEvents());
+ gitRefListener().onGitReferenceUpdated(refUpdateWithoutAccountId);
+ assertEquals(1, gitRefListener().getProcessedEvents());
}
}
- private ReferenceUpdatedEventTest newRefUpdateEvent() {
+ private GitRefListenerTest gitRefListener() {
+ return (GitRefListenerTest)
+ StreamSupport.stream(allRefUpdateListeners.entries().spliterator(), false)
+ .map(Extension::get)
+ .filter(listener -> GitRefListenerTest.class.isAssignableFrom(listener.getClass()))
+ .findFirst()
+ .get();
+ }
+
+ private ReferenceUpdatedEventTest newRefUpdateEvent() throws Exception {
+ String refPrefix = createChange().getChange().getId().toRefPrefix();
return new ReferenceUpdatedEventTest(
- project, aRefChange, anOldObjectId, aNewObjectId, Type.CREATE, admin.id());
+ project, refPrefix, anOldObjectId, aNewObjectId, Type.CREATE, admin.id());
}
}
diff --git a/owners-autoassign/src/test/java/com/googlesource/gerrit/owners/common/GitRefListenerTest.java b/owners-autoassign/src/test/java/com/googlesource/gerrit/owners/common/GitRefListenerTest.java
index e862ed9..fef3f29 100644
--- a/owners-autoassign/src/test/java/com/googlesource/gerrit/owners/common/GitRefListenerTest.java
+++ b/owners-autoassign/src/test/java/com/googlesource/gerrit/owners/common/GitRefListenerTest.java
@@ -15,13 +15,17 @@
package com.googlesource.gerrit.owners.common;
+import com.google.gerrit.entities.Change;
import com.google.gerrit.extensions.api.GerritApi;
+import com.google.gerrit.extensions.events.GitReferenceUpdatedListener.Event;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.patch.PatchListCache;
import com.google.gerrit.server.util.OneOffRequestContext;
import com.google.inject.Inject;
import com.google.inject.Provider;
+import com.google.inject.Singleton;
import com.googlesource.gerrit.owners.common.Accounts;
import com.googlesource.gerrit.owners.common.GitRefListener;
import com.googlesource.gerrit.owners.common.ReviewerManager;
@@ -29,6 +33,7 @@
import org.junit.Ignore;
@Ignore
+@Singleton
public class GitRefListenerTest extends GitRefListener {
int processedEvents = 0;
@@ -40,7 +45,8 @@
Accounts accounts,
SyncReviewerManager reviewerManager,
OneOffRequestContext oneOffReqCtx,
- Provider<CurrentUser> currentUserProvider) {
+ Provider<CurrentUser> currentUserProvider,
+ ChangeNotes.Factory notesFactory) {
super(
api,
patchListCache,
@@ -48,11 +54,12 @@
accounts,
reviewerManager,
oneOffReqCtx,
- currentUserProvider);
+ currentUserProvider,
+ notesFactory);
}
@Override
- public void processEvent(Repository repository, Event event) {
+ public void processEvent(Repository repository, Event event, Change.Id cId) {
processedEvents++;
}