Merge "Add test for multiple VersionedMetaDatas in one BatchRefUpdate"
diff --git a/java/com/google/gerrit/reviewdb/client/AccountGroupByIdAud.java b/java/com/google/gerrit/reviewdb/client/AccountGroupByIdAud.java
index b058f04..33955c4 100644
--- a/java/com/google/gerrit/reviewdb/client/AccountGroupByIdAud.java
+++ b/java/com/google/gerrit/reviewdb/client/AccountGroupByIdAud.java
@@ -93,6 +93,14 @@
return key;
}
+ public AccountGroup.Id getGroupId() {
+ return key.getParentKey();
+ }
+
+ public AccountGroup.UUID getIncludeUUID() {
+ return key.getIncludeUUID();
+ }
+
public boolean isActive() {
return removedOn == null;
}
@@ -106,6 +114,10 @@
return addedBy;
}
+ public Timestamp getAddedOn() {
+ return key.getAddedOn();
+ }
+
public Account.Id getRemovedBy() {
return removedBy;
}
diff --git a/java/com/google/gerrit/reviewdb/client/AccountGroupMemberAudit.java b/java/com/google/gerrit/reviewdb/client/AccountGroupMemberAudit.java
index 5b838ce..9968b7d 100644
--- a/java/com/google/gerrit/reviewdb/client/AccountGroupMemberAudit.java
+++ b/java/com/google/gerrit/reviewdb/client/AccountGroupMemberAudit.java
@@ -93,6 +93,14 @@
return key;
}
+ public AccountGroup.Id getGroupId() {
+ return key.getGroupId();
+ }
+
+ public Account.Id getMemberId() {
+ return key.getParentKey();
+ }
+
public boolean isActive() {
return removedOn == null;
}
@@ -111,6 +119,10 @@
return addedBy;
}
+ public Timestamp getAddedOn() {
+ return key.getAddedOn();
+ }
+
public Account.Id getRemovedBy() {
return removedBy;
}
diff --git a/java/com/google/gerrit/reviewdb/server/ReviewDbWrapper.java b/java/com/google/gerrit/reviewdb/server/ReviewDbWrapper.java
index 29b4be3..7fd2c73 100644
--- a/java/com/google/gerrit/reviewdb/server/ReviewDbWrapper.java
+++ b/java/com/google/gerrit/reviewdb/server/ReviewDbWrapper.java
@@ -138,6 +138,7 @@
}
@Override
+ @SuppressWarnings("deprecation")
public int nextAccountGroupId() throws OrmException {
return delegate.nextAccountGroupId();
}
diff --git a/java/com/google/gerrit/server/group/GetAuditLog.java b/java/com/google/gerrit/server/group/GetAuditLog.java
index 8c94f65..ebada0b 100644
--- a/java/com/google/gerrit/server/group/GetAuditLog.java
+++ b/java/com/google/gerrit/server/group/GetAuditLog.java
@@ -14,6 +14,8 @@
package com.google.gerrit.server.group;
+import static java.util.Comparator.comparing;
+
import com.google.gerrit.common.data.GroupDescription;
import com.google.gerrit.extensions.common.AccountInfo;
import com.google.gerrit.extensions.common.GroupAuditEventInfo;
@@ -29,13 +31,13 @@
import com.google.gerrit.server.account.AccountLoader;
import com.google.gerrit.server.account.GroupBackend;
import com.google.gerrit.server.account.GroupCache;
+import com.google.gerrit.server.group.db.Groups;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.Comparator;
import java.util.List;
import java.util.Optional;
@@ -46,6 +48,7 @@
private final GroupCache groupCache;
private final GroupJson groupJson;
private final GroupBackend groupBackend;
+ private final Groups groups;
@Inject
public GetAuditLog(
@@ -53,12 +56,14 @@
AccountLoader.Factory accountLoaderFactory,
GroupCache groupCache,
GroupJson groupJson,
- GroupBackend groupBackend) {
+ GroupBackend groupBackend,
+ Groups groups) {
this.db = db;
this.accountLoaderFactory = accountLoaderFactory;
this.groupCache = groupCache;
this.groupJson = groupJson;
this.groupBackend = groupBackend;
+ this.groups = groups;
}
@Override
@@ -75,14 +80,12 @@
List<GroupAuditEventInfo> auditEvents = new ArrayList<>();
for (AccountGroupMemberAudit auditEvent :
- db.get().accountGroupMembersAudit().byGroup(group.getId()).toList()) {
- AccountInfo member = accountLoader.get(auditEvent.getKey().getParentKey());
+ groups.getMembersAudit(db.get(), group.getGroupUUID())) {
+ AccountInfo member = accountLoader.get(auditEvent.getMemberId());
auditEvents.add(
GroupAuditEventInfo.createAddUserEvent(
- accountLoader.get(auditEvent.getAddedBy()),
- auditEvent.getKey().getAddedOn(),
- member));
+ accountLoader.get(auditEvent.getAddedBy()), auditEvent.getAddedOn(), member));
if (!auditEvent.isActive()) {
auditEvents.add(
@@ -92,8 +95,8 @@
}
for (AccountGroupByIdAud auditEvent :
- db.get().accountGroupByIdAud().byGroup(group.getId()).toList()) {
- AccountGroup.UUID includedGroupUUID = auditEvent.getKey().getIncludeUUID();
+ groups.getSubgroupsAudit(db.get(), group.getGroupUUID())) {
+ AccountGroup.UUID includedGroupUUID = auditEvent.getIncludeUUID();
Optional<InternalGroup> includedGroup = groupCache.get(includedGroupUUID);
GroupInfo member;
if (includedGroup.isPresent()) {
@@ -121,14 +124,7 @@
accountLoader.fill();
// sort by date in reverse order so that the newest audit event comes first
- Collections.sort(
- auditEvents,
- new Comparator<GroupAuditEventInfo>() {
- @Override
- public int compare(GroupAuditEventInfo e1, GroupAuditEventInfo e2) {
- return e2.date.compareTo(e1.date);
- }
- });
+ Collections.sort(auditEvents, comparing((GroupAuditEventInfo a) -> a.date).reversed());
return auditEvents;
}
diff --git a/java/com/google/gerrit/server/group/db/GroupConfig.java b/java/com/google/gerrit/server/group/db/GroupConfig.java
index ea2e22b..af05bf8 100644
--- a/java/com/google/gerrit/server/group/db/GroupConfig.java
+++ b/java/com/google/gerrit/server/group/db/GroupConfig.java
@@ -394,12 +394,12 @@
Sets.difference(oldSubgroups, newSubgroups)
.stream()
.map(groupNameRetriever)
- .map("Remove: group "::concat);
+ .map("Remove-group: "::concat);
Stream<String> addedMembers =
Sets.difference(newSubgroups, oldSubgroups)
.stream()
.map(groupNameRetriever)
- .map("Add: group "::concat);
+ .map("Add-group: "::concat);
return Stream.concat(removedMembers, addedMembers);
}
}
diff --git a/java/com/google/gerrit/server/group/db/Groups.java b/java/com/google/gerrit/server/group/db/Groups.java
index 53051c1..9ea78be 100644
--- a/java/com/google/gerrit/server/group/db/Groups.java
+++ b/java/com/google/gerrit/server/group/db/Groups.java
@@ -16,6 +16,7 @@
import static com.google.common.collect.ImmutableSet.toImmutableSet;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Streams;
@@ -23,7 +24,9 @@
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupById;
+import com.google.gerrit.reviewdb.client.AccountGroupByIdAud;
import com.google.gerrit.reviewdb.client.AccountGroupMember;
+import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.config.GerritServerConfig;
@@ -279,4 +282,46 @@
.distinct()
.filter(groupUuid -> !AccountGroup.isInternalGroup(groupUuid));
}
+
+ /**
+ * Returns the membership audit records for a given group.
+ *
+ * @param db the {@code ReviewDb} instance to use for lookups
+ * @param groupUuid the UUID of the group
+ * @return the audit records, in arbitrary order; empty if the group does not exist
+ * @throws OrmException if an error occurs while reading from ReviewDb
+ */
+ public List<AccountGroupMemberAudit> getMembersAudit(ReviewDb db, AccountGroup.UUID groupUuid)
+ throws OrmException {
+ if (readFromNoteDb) {
+ // TODO(dborowitz): Implement.
+ throw new OrmException("Audit logs not yet implemented in NoteDb");
+ }
+ Optional<AccountGroup> group = getGroupFromReviewDb(db, groupUuid);
+ if (!group.isPresent()) {
+ return ImmutableList.of();
+ }
+ return db.accountGroupMembersAudit().byGroup(group.get().getId()).toList();
+ }
+
+ /**
+ * Returns the subgroup audit records for a given group.
+ *
+ * @param db the {@code ReviewDb} instance to use for lookups
+ * @param groupUuid the UUID of the group
+ * @return the audit records, in arbitrary order; empty if the group does not exist
+ * @throws OrmException if an error occurs while reading from ReviewDb
+ */
+ public List<AccountGroupByIdAud> getSubgroupsAudit(ReviewDb db, AccountGroup.UUID groupUuid)
+ throws OrmException {
+ if (readFromNoteDb) {
+ // TODO(dborowitz): Implement.
+ throw new OrmException("Audit logs not yet implemented in NoteDb");
+ }
+ Optional<AccountGroup> group = getGroupFromReviewDb(db, groupUuid);
+ if (!group.isPresent()) {
+ return ImmutableList.of();
+ }
+ return db.accountGroupByIdAud().byGroup(group.get().getId()).toList();
+ }
}
diff --git a/java/com/google/gerrit/server/group/db/GroupsUpdate.java b/java/com/google/gerrit/server/group/db/GroupsUpdate.java
index 24d5bfa..799064f 100644
--- a/java/com/google/gerrit/server/group/db/GroupsUpdate.java
+++ b/java/com/google/gerrit/server/group/db/GroupsUpdate.java
@@ -516,14 +516,7 @@
.map(AccountState::getAccount)
.map(account -> account.getName(anonymousCowardName))
.orElse(anonymousCowardName);
- String email = getEmailForAuditLog(accountId, serverId);
-
- StringBuilder formattedResult = new StringBuilder();
- PersonIdent.appendSanitized(formattedResult, accountName);
- formattedResult.append(" <");
- PersonIdent.appendSanitized(formattedResult, email);
- formattedResult.append(">");
- return formattedResult.toString();
+ return formatNameEmail(accountName, getEmailForAuditLog(accountId, serverId));
}
private static String getEmailForAuditLog(Account.Id accountId, String serverId) {
@@ -534,10 +527,19 @@
return groupCache
.get(groupUuid)
.map(InternalGroup::getName)
- .map(name -> String.format("%s <%s>", name, groupUuid))
+ .map(name -> formatNameEmail(name, groupUuid.get()))
.orElse(groupUuid.get());
}
+ private static String formatNameEmail(String name, String email) {
+ StringBuilder formattedResult = new StringBuilder();
+ PersonIdent.appendSanitized(formattedResult, name);
+ formattedResult.append(" <");
+ PersonIdent.appendSanitized(formattedResult, email);
+ formattedResult.append(">");
+ return formattedResult.toString();
+ }
+
private void commit(GroupConfig groupConfig) throws IOException {
try (MetaDataUpdate metaDataUpdate = metaDataUpdateFactory.create(allUsersName)) {
groupConfig.commit(metaDataUpdate);
diff --git a/java/com/google/gerrit/server/notedb/ChangeNoteUtil.java b/java/com/google/gerrit/server/notedb/ChangeNoteUtil.java
index b23c1de..89326c8 100644
--- a/java/com/google/gerrit/server/notedb/ChangeNoteUtil.java
+++ b/java/com/google/gerrit/server/notedb/ChangeNoteUtil.java
@@ -23,7 +23,6 @@
import com.google.common.base.CharMatcher;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ListMultimap;
-import com.google.common.primitives.Ints;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Comment;
@@ -158,18 +157,14 @@
public Account.Id parseIdent(PersonIdent ident, Change.Id changeId)
throws ConfigInvalidException {
- String email = ident.getEmailAddress();
- int at = email.indexOf('@');
- if (at >= 0) {
- String host = email.substring(at + 1, email.length());
- if (host.equals(serverId)) {
- Integer id = Ints.tryParse(email.substring(0, at));
- if (id != null) {
- return new Account.Id(id);
- }
- }
- }
- throw parseException(changeId, "invalid identity, expected <id>@%s: %s", serverId, email);
+ return NoteDbUtil.parseIdent(ident, serverId)
+ .orElseThrow(
+ () ->
+ parseException(
+ changeId,
+ "invalid identity, expected <id>@%s: %s",
+ serverId,
+ ident.getEmailAddress()));
}
private static boolean match(byte[] note, MutableInteger p, byte[] expected) {
diff --git a/java/com/google/gerrit/server/notedb/NoteDbUtil.java b/java/com/google/gerrit/server/notedb/NoteDbUtil.java
new file mode 100644
index 0000000..59c4c62
--- /dev/null
+++ b/java/com/google/gerrit/server/notedb/NoteDbUtil.java
@@ -0,0 +1,39 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.notedb;
+
+import com.google.common.primitives.Ints;
+import com.google.gerrit.reviewdb.client.Account;
+import java.util.Optional;
+import org.eclipse.jgit.lib.PersonIdent;
+
+public class NoteDbUtil {
+ public static Optional<Account.Id> parseIdent(PersonIdent ident, String serverId) {
+ String email = ident.getEmailAddress();
+ int at = email.indexOf('@');
+ if (at >= 0) {
+ String host = email.substring(at + 1, email.length());
+ if (host.equals(serverId)) {
+ Integer id = Ints.tryParse(email.substring(0, at));
+ if (id != null) {
+ return Optional.of(new Account.Id(id));
+ }
+ }
+ }
+ return Optional.empty();
+ }
+
+ private NoteDbUtil() {}
+}
diff --git a/javatests/com/google/gerrit/acceptance/api/group/GroupsIT.java b/javatests/com/google/gerrit/acceptance/api/group/GroupsIT.java
index 3ac975d..6d0a31e 100644
--- a/javatests/com/google/gerrit/acceptance/api/group/GroupsIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/group/GroupsIT.java
@@ -15,6 +15,7 @@
package com.google.gerrit.acceptance.api.group;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.TruthJUnit.assume;
import static com.google.gerrit.acceptance.GitUtil.fetch;
import static com.google.gerrit.acceptance.api.group.GroupAssert.assertGroupInfo;
import static com.google.gerrit.acceptance.rest.account.AccountAssert.assertAccountInfos;
@@ -429,6 +430,7 @@
assertThat(gApi.groups().id(name).options().visibleToAll).isTrue();
}
+ @SuppressWarnings("deprecation")
@Test
public void groupOwner() throws Exception {
String adminUUID = getFromCache("Administrators").getGroupUUID().get();
@@ -722,6 +724,7 @@
@Test
public void getAuditLog() throws Exception {
+ assume().that(cfg.getBoolean("user", null, "readGroupsFromNoteDb", false)).isFalse();
GroupApi g = gApi.groups().create(name("group"));
List<? extends GroupAuditEventInfo> auditEvents = g.auditLog();
assertThat(auditEvents).hasSize(1);
diff --git a/javatests/com/google/gerrit/acceptance/api/project/SetParentIT.java b/javatests/com/google/gerrit/acceptance/api/project/SetParentIT.java
index 486a29e..0d9e582 100644
--- a/javatests/com/google/gerrit/acceptance/api/project/SetParentIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/project/SetParentIT.java
@@ -19,14 +19,19 @@
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.NoHttpd;
import com.google.gerrit.extensions.restapi.AuthException;
+import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.config.AllProjectsNameProvider;
+import com.google.gerrit.server.config.AllUsersName;
+import com.google.inject.Inject;
import org.junit.Test;
@NoHttpd
public class SetParentIT extends AbstractDaemonTest {
+ @Inject private AllUsersName allUsers;
+
@Test
public void setParentNotAllowed() throws Exception {
String parent = createProject("parent", null, true).get();
@@ -86,4 +91,15 @@
exception.expectMessage("not found");
gApi.projects().name(project.get()).parent("non-existing");
}
+
+ @Test
+ public void setParentForAllUsersMustBeAllProjects() throws Exception {
+ gApi.projects().name(allUsers.get()).parent(allProjects.get());
+
+ String parent = createProject("parent", null, true).get();
+
+ exception.expect(BadRequestException.class);
+ exception.expectMessage("All-Users must inherit from All-Projects");
+ gApi.projects().name(allUsers.get()).parent(parent);
+ }
}
diff --git a/polygerrit-ui/app/styles/app-theme.html b/polygerrit-ui/app/styles/app-theme.html
index 2fe7662..2d89272 100644
--- a/polygerrit-ui/app/styles/app-theme.html
+++ b/polygerrit-ui/app/styles/app-theme.html
@@ -18,7 +18,7 @@
/* Following vars have LTS for plugin API. */
--primary-text-color: #000;
--header-background-color: #eee;
- --header-title-content: 'PolyGerrit';
+ --header-title-content: 'Gerrit';
--header-icon: none;
--header-icon-size: 0em;
--footer-background-color: var(--header-background-color);