Allow empty group name when converting from ReviewDb
Empty group names may be problematic when used elsewhere in Gerrit, but they are technically valid in ReviewDb, and various googlesource.com hosts actually have them. Rather than attempting to change such names during the migration, migrate them faithfully. Still refuse to update a group name to the empty string in a running server, however. Change-Id: Ib3269bd2eb637c00561f3ce1ee470365909dc20c
This commit is contained in:
@@ -19,6 +19,7 @@ import static com.google.common.base.Preconditions.checkState;
|
|||||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||||
|
|
||||||
import com.google.common.base.Splitter;
|
import com.google.common.base.Splitter;
|
||||||
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.google.common.collect.Streams;
|
import com.google.common.collect.Streams;
|
||||||
@@ -70,6 +71,7 @@ public class GroupConfig extends VersionedMetaData {
|
|||||||
private Function<Account.Id, String> accountNameEmailRetriever = Account.Id::toString;
|
private Function<Account.Id, String> accountNameEmailRetriever = Account.Id::toString;
|
||||||
private Function<AccountGroup.UUID, String> groupNameRetriever = AccountGroup.UUID::get;
|
private Function<AccountGroup.UUID, String> groupNameRetriever = AccountGroup.UUID::get;
|
||||||
private boolean isLoaded = false;
|
private boolean isLoaded = false;
|
||||||
|
private boolean allowSaveEmptyName;
|
||||||
|
|
||||||
private GroupConfig(AccountGroup.UUID groupUuid) {
|
private GroupConfig(AccountGroup.UUID groupUuid) {
|
||||||
this.groupUuid = checkNotNull(groupUuid);
|
this.groupUuid = checkNotNull(groupUuid);
|
||||||
@@ -106,6 +108,10 @@ public class GroupConfig extends VersionedMetaData {
|
|||||||
this.groupCreation = Optional.of(groupCreation);
|
this.groupCreation = Optional.of(groupCreation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setAllowSaveEmptyName() {
|
||||||
|
this.allowSaveEmptyName = true;
|
||||||
|
}
|
||||||
|
|
||||||
public void setGroupUpdate(
|
public void setGroupUpdate(
|
||||||
InternalGroupUpdate groupUpdate,
|
InternalGroupUpdate groupUpdate,
|
||||||
Function<Account.Id, String> accountNameEmailRetriever,
|
Function<Account.Id, String> accountNameEmailRetriever,
|
||||||
@@ -175,6 +181,11 @@ public class GroupConfig extends VersionedMetaData {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!allowSaveEmptyName && getNewName().equals(Optional.of(""))) {
|
||||||
|
throw new ConfigInvalidException(
|
||||||
|
String.format("Name of the group %s must be defined", groupUuid.get()));
|
||||||
|
}
|
||||||
|
|
||||||
Timestamp createdOn;
|
Timestamp createdOn;
|
||||||
if (groupCreation.isPresent()) {
|
if (groupCreation.isPresent()) {
|
||||||
createdOn = groupCreation.get().getCreatedOn();
|
createdOn = groupCreation.get().getCreatedOn();
|
||||||
@@ -217,6 +228,16 @@ public class GroupConfig extends VersionedMetaData {
|
|||||||
checkState(isLoaded, "Group %s not loaded yet", groupUuid.get());
|
checkState(isLoaded, "Group %s not loaded yet", groupUuid.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Optional<String> getNewName() {
|
||||||
|
if (groupUpdate.isPresent()) {
|
||||||
|
return groupUpdate.get().getName().map(n -> Strings.nullToEmpty(n.get()));
|
||||||
|
}
|
||||||
|
if (groupCreation.isPresent()) {
|
||||||
|
return Optional.of(Strings.nullToEmpty(groupCreation.get().getNameKey().get()));
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
private Config updateGroupProperties() throws IOException, ConfigInvalidException {
|
private Config updateGroupProperties() throws IOException, ConfigInvalidException {
|
||||||
Config config = readConfig(GROUP_CONFIG_FILE);
|
Config config = readConfig(GROUP_CONFIG_FILE);
|
||||||
groupCreation.ifPresent(
|
groupCreation.ifPresent(
|
||||||
|
|||||||
@@ -55,10 +55,11 @@ enum GroupConfigEntry {
|
|||||||
void readFromConfig(AccountGroup.UUID groupUuid, InternalGroup.Builder group, Config config)
|
void readFromConfig(AccountGroup.UUID groupUuid, InternalGroup.Builder group, Config config)
|
||||||
throws ConfigInvalidException {
|
throws ConfigInvalidException {
|
||||||
String name = config.getString(SECTION_NAME, null, super.keyName);
|
String name = config.getString(SECTION_NAME, null, super.keyName);
|
||||||
if (Strings.isNullOrEmpty(name)) {
|
// An empty name is invalid in NoteDb; GroupConfig will refuse to store it and it might be
|
||||||
throw new ConfigInvalidException(
|
// unusable in permissions. But, it was technically valid in the ReviewDb storage layer, and
|
||||||
String.format("Name of the group %s must be defined", groupUuid.get()));
|
// the NoteDb migration converted such groups faithfully, so we need to be able to read them
|
||||||
}
|
// back here.
|
||||||
|
name = Strings.nullToEmpty(name);
|
||||||
group.setNameKey(new AccountGroup.NameKey(name));
|
group.setNameKey(new AccountGroup.NameKey(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -118,6 +118,7 @@ public class GroupRebuilder {
|
|||||||
throws IOException, ConfigInvalidException, OrmDuplicateKeyException {
|
throws IOException, ConfigInvalidException, OrmDuplicateKeyException {
|
||||||
GroupConfig groupConfig = GroupConfig.loadForGroup(allUsersRepo, bundle.uuid());
|
GroupConfig groupConfig = GroupConfig.loadForGroup(allUsersRepo, bundle.uuid());
|
||||||
AccountGroup group = bundle.group();
|
AccountGroup group = bundle.group();
|
||||||
|
groupConfig.setAllowSaveEmptyName();
|
||||||
groupConfig.setGroupCreation(
|
groupConfig.setGroupCreation(
|
||||||
InternalGroupCreation.builder()
|
InternalGroupCreation.builder()
|
||||||
.setId(bundle.id())
|
.setId(bundle.id())
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
package com.google.gerrit.server.group.db;
|
package com.google.gerrit.server.group.db;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||||
|
|
||||||
import com.google.gerrit.common.TimeUtil;
|
import com.google.gerrit.common.TimeUtil;
|
||||||
@@ -120,12 +121,19 @@ public class GroupConfigTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void nameInConfigMustBeDefined() throws Exception {
|
public void nameInConfigMayBeUndefined() throws Exception {
|
||||||
populateGroupConfig(groupUuid, "[group]\n\tid = 42\n\townerGroupUuid = owners\n");
|
populateGroupConfig(groupUuid, "[group]\n\tid = 42\n\townerGroupUuid = owners\n");
|
||||||
|
|
||||||
expectedException.expect(ConfigInvalidException.class);
|
GroupConfig groupConfig = GroupConfig.loadForGroup(repository, groupUuid);
|
||||||
expectedException.expectMessage("Name of the group users-XYZ");
|
assertThat(groupConfig.getLoadedGroup().get().getName()).isEmpty();
|
||||||
GroupConfig.loadForGroup(repository, groupUuid);
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void nameInConfigMayBeEmpty() throws Exception {
|
||||||
|
populateGroupConfig(groupUuid, "[group]\n\tname=\n\tid = 42\n\townerGroupUuid = owners\n");
|
||||||
|
|
||||||
|
GroupConfig groupConfig = GroupConfig.loadForGroup(repository, groupUuid);
|
||||||
|
assertThat(groupConfig.getLoadedGroup().get().getName()).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -107,6 +107,18 @@ public class GroupRebuilderTest extends AbstractGroupTest {
|
|||||||
assertServerCommit(log.get(0), "Create group");
|
assertServerCommit(log.get(0), "Create group");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void emptyGroupName() throws Exception {
|
||||||
|
AccountGroup g = newGroup("");
|
||||||
|
GroupBundle b = builder().group(g).build();
|
||||||
|
|
||||||
|
rebuilder.rebuild(repo, b, null);
|
||||||
|
|
||||||
|
GroupBundle noteDbBundle = reload(g);
|
||||||
|
assertThat(noteDbBundle).isEqualTo(b);
|
||||||
|
assertThat(noteDbBundle.group().getName()).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void membersAndSubgroups() throws Exception {
|
public void membersAndSubgroups() throws Exception {
|
||||||
AccountGroup g = newGroup("a");
|
AccountGroup g = newGroup("a");
|
||||||
|
|||||||
Reference in New Issue
Block a user