Merge changes I95c012ed,Ia07a818c,Ia5dfa6a2,Ie2ecf50f,Id85b4ab3, ...
* changes: Move default AllProjects configs to a utility class for tests AllProjectsCreator: allow to initialize with only project description AllProjectsCreator: add an 'initDefaultAcls' boolean field AllProjectsCreator: move ACL initialization into separate methods Provide 'projectDescription' and 'booleanProjectConfig' in 'AllProjectsInput' Define 'AllProjectsInput' for 'AllProjectsCreator' Add a test for "AllProjectsCreator"
This commit is contained in:
@@ -22,25 +22,17 @@ import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS
|
||||
import static com.google.gerrit.server.schema.AclUtil.grant;
|
||||
import static com.google.gerrit.server.schema.AclUtil.rule;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.gerrit.common.Nullable;
|
||||
import com.google.gerrit.common.Version;
|
||||
import com.google.gerrit.common.data.AccessSection;
|
||||
import com.google.gerrit.common.data.GlobalCapability;
|
||||
import com.google.gerrit.common.data.GroupReference;
|
||||
import com.google.gerrit.common.data.LabelType;
|
||||
import com.google.gerrit.common.data.LabelValue;
|
||||
import com.google.gerrit.common.data.Permission;
|
||||
import com.google.gerrit.common.data.PermissionRule;
|
||||
import com.google.gerrit.common.data.PermissionRule.Action;
|
||||
import com.google.gerrit.extensions.client.InheritableBoolean;
|
||||
import com.google.gerrit.reviewdb.client.BooleanProjectConfig;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.reviewdb.client.RefNames;
|
||||
import com.google.gerrit.server.GerritPersonIdent;
|
||||
import com.google.gerrit.server.UsedAt;
|
||||
import com.google.gerrit.server.config.AllProjectsName;
|
||||
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
@@ -52,8 +44,6 @@ import com.google.gerrit.server.project.ProjectConfig;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.google.inject.Inject;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.eclipse.jgit.errors.ConfigInvalidException;
|
||||
import org.eclipse.jgit.errors.RepositoryNotFoundException;
|
||||
import org.eclipse.jgit.lib.BatchRefUpdate;
|
||||
@@ -77,13 +67,6 @@ public class AllProjectsCreator {
|
||||
private final GroupReference registered;
|
||||
private final GroupReference owners;
|
||||
|
||||
@Nullable private GroupReference admin;
|
||||
@Nullable private GroupReference batch;
|
||||
private String message;
|
||||
private int firstChangeId = Sequences.FIRST_CHANGE_ID;
|
||||
private LabelType codeReviewLabel;
|
||||
private List<LabelType> additionalLabelType;
|
||||
|
||||
@Inject
|
||||
AllProjectsCreator(
|
||||
GitRepositoryManager repositoryManager,
|
||||
@@ -101,57 +84,17 @@ public class AllProjectsCreator {
|
||||
this.anonymous = systemGroupBackend.getGroup(ANONYMOUS_USERS);
|
||||
this.registered = systemGroupBackend.getGroup(REGISTERED_USERS);
|
||||
this.owners = systemGroupBackend.getGroup(PROJECT_OWNERS);
|
||||
this.codeReviewLabel = getDefaultCodeReviewLabel();
|
||||
this.additionalLabelType = new ArrayList<>();
|
||||
}
|
||||
|
||||
/** If called, grant default permissions to this admin group */
|
||||
public AllProjectsCreator setAdministrators(GroupReference admin) {
|
||||
this.admin = admin;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** If called, grant stream-events permission and set appropriate priority for this group */
|
||||
public AllProjectsCreator setBatchUsers(GroupReference batch) {
|
||||
this.batch = batch;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AllProjectsCreator setCommitMessage(String message) {
|
||||
this.message = message;
|
||||
return this;
|
||||
}
|
||||
|
||||
@UsedAt(UsedAt.Project.GOOGLE)
|
||||
public AllProjectsCreator setFirstChangeIdForNoteDb(int id) {
|
||||
checkArgument(id > 0, "id must be positive: %s", id);
|
||||
firstChangeId = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** If called, the provided "Code-Review" label will be used rather than the default. */
|
||||
@UsedAt(UsedAt.Project.GOOGLE)
|
||||
public AllProjectsCreator setCodeReviewLabel(LabelType labelType) {
|
||||
checkArgument(
|
||||
labelType.getName().equals("Code-Review"), "label should have 'Code-Review' as its name");
|
||||
this.codeReviewLabel = labelType;
|
||||
return this;
|
||||
}
|
||||
|
||||
@UsedAt(UsedAt.Project.GOOGLE)
|
||||
public AllProjectsCreator addAdditionalLabel(LabelType labelType) {
|
||||
additionalLabelType.add(labelType);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void create() throws IOException, ConfigInvalidException, OrmException {
|
||||
public void create(AllProjectsInput input)
|
||||
throws IOException, ConfigInvalidException, OrmException {
|
||||
try (Repository git = repositoryManager.openRepository(allProjectsName)) {
|
||||
initAllProjects(git);
|
||||
initAllProjects(git, input);
|
||||
} catch (RepositoryNotFoundException notFound) {
|
||||
// A repository may be missing if this project existed only to store
|
||||
// inheritable permissions. For example 'All-Projects'.
|
||||
try (Repository git = repositoryManager.createRepository(allProjectsName)) {
|
||||
initAllProjects(git);
|
||||
initAllProjects(git, input);
|
||||
RefUpdate u = git.updateRef(Constants.HEAD);
|
||||
u.link(RefNames.REFS_CONFIG);
|
||||
} catch (RepositoryNotFoundException err) {
|
||||
@@ -161,7 +104,7 @@ public class AllProjectsCreator {
|
||||
}
|
||||
}
|
||||
|
||||
private void initAllProjects(Repository git)
|
||||
private void initAllProjects(Repository git, AllProjectsInput input)
|
||||
throws IOException, ConfigInvalidException, OrmException {
|
||||
BatchRefUpdate bru = git.getRefDatabase().newBatchUpdate();
|
||||
try (MetaDataUpdate md =
|
||||
@@ -169,68 +112,36 @@ public class AllProjectsCreator {
|
||||
md.getCommitBuilder().setAuthor(serverUser);
|
||||
md.getCommitBuilder().setCommitter(serverUser);
|
||||
md.setMessage(
|
||||
MoreObjects.firstNonNull(
|
||||
Strings.emptyToNull(message),
|
||||
"Initialized Gerrit Code Review " + Version.getVersion()));
|
||||
input.commitMessage().isPresent()
|
||||
? input.commitMessage().get()
|
||||
: "Initialized Gerrit Code Review " + Version.getVersion());
|
||||
|
||||
// init basic project configs.
|
||||
ProjectConfig config = projectConfigFactory.read(md);
|
||||
Project p = config.getProject();
|
||||
p.setDescription("Access inherited by all other projects.");
|
||||
p.setBooleanConfig(BooleanProjectConfig.REQUIRE_CHANGE_ID, InheritableBoolean.TRUE);
|
||||
p.setBooleanConfig(BooleanProjectConfig.USE_CONTENT_MERGE, InheritableBoolean.TRUE);
|
||||
p.setBooleanConfig(BooleanProjectConfig.USE_CONTRIBUTOR_AGREEMENTS, InheritableBoolean.FALSE);
|
||||
p.setBooleanConfig(BooleanProjectConfig.USE_SIGNED_OFF_BY, InheritableBoolean.FALSE);
|
||||
p.setBooleanConfig(BooleanProjectConfig.ENABLE_SIGNED_PUSH, InheritableBoolean.FALSE);
|
||||
p.setDescription(
|
||||
input.projectDescription().orElse("Access inherited by all other projects."));
|
||||
|
||||
AccessSection cap = config.getAccessSection(AccessSection.GLOBAL_CAPABILITIES, true);
|
||||
AccessSection all = config.getAccessSection(AccessSection.ALL, true);
|
||||
AccessSection heads = config.getAccessSection(AccessSection.HEADS, true);
|
||||
AccessSection tags = config.getAccessSection("refs/tags/*", true);
|
||||
AccessSection meta = config.getAccessSection(RefNames.REFS_CONFIG, true);
|
||||
AccessSection refsFor = config.getAccessSection("refs/for/*", true);
|
||||
AccessSection magic = config.getAccessSection("refs/for/" + AccessSection.ALL, true);
|
||||
// init boolean project configs.
|
||||
input.booleanProjectConfigs().forEach(p::setBooleanConfig);
|
||||
|
||||
grant(config, cap, GlobalCapability.ADMINISTRATE_SERVER, admin);
|
||||
grant(config, all, Permission.READ, admin, anonymous);
|
||||
grant(config, refsFor, Permission.ADD_PATCH_SET, registered);
|
||||
// init labels.
|
||||
input
|
||||
.codeReviewLabel()
|
||||
.ifPresent(
|
||||
codeReviewLabel ->
|
||||
config.getLabelSections().put(codeReviewLabel.getName(), codeReviewLabel));
|
||||
|
||||
if (batch != null) {
|
||||
Permission priority = cap.getPermission(GlobalCapability.PRIORITY, true);
|
||||
PermissionRule r = rule(config, batch);
|
||||
r.setAction(Action.BATCH);
|
||||
priority.add(r);
|
||||
|
||||
Permission stream = cap.getPermission(GlobalCapability.STREAM_EVENTS, true);
|
||||
stream.add(rule(config, batch));
|
||||
if (input.initDefaultAcls()) {
|
||||
// init access sections.
|
||||
initDefaultAcls(config, input);
|
||||
}
|
||||
|
||||
initLabels(config);
|
||||
grant(config, heads, codeReviewLabel, -1, 1, registered);
|
||||
|
||||
grant(config, heads, codeReviewLabel, -2, 2, admin, owners);
|
||||
grant(config, heads, Permission.CREATE, admin, owners);
|
||||
grant(config, heads, Permission.PUSH, admin, owners);
|
||||
grant(config, heads, Permission.SUBMIT, admin, owners);
|
||||
grant(config, heads, Permission.FORGE_AUTHOR, registered);
|
||||
grant(config, heads, Permission.FORGE_COMMITTER, admin, owners);
|
||||
grant(config, heads, Permission.EDIT_TOPIC_NAME, true, admin, owners);
|
||||
|
||||
grant(config, tags, Permission.CREATE, admin, owners);
|
||||
grant(config, tags, Permission.CREATE_TAG, admin, owners);
|
||||
grant(config, tags, Permission.CREATE_SIGNED_TAG, admin, owners);
|
||||
|
||||
grant(config, magic, Permission.PUSH, registered);
|
||||
grant(config, magic, Permission.PUSH_MERGE, registered);
|
||||
|
||||
meta.getPermission(Permission.READ, true).setExclusiveGroup(true);
|
||||
grant(config, meta, Permission.READ, admin, owners);
|
||||
grant(config, meta, codeReviewLabel, -2, 2, admin, owners);
|
||||
grant(config, meta, Permission.CREATE, admin, owners);
|
||||
grant(config, meta, Permission.PUSH, admin, owners);
|
||||
grant(config, meta, Permission.SUBMIT, admin, owners);
|
||||
|
||||
// commit all the above configs as a commit in "refs/meta/config" branch of the All-Projects.
|
||||
config.commitToNewRef(md, RefNames.REFS_CONFIG);
|
||||
initSequences(git, bru);
|
||||
|
||||
// init sequence number.
|
||||
initSequences(git, bru, input.firstChangeIdForNoteDb());
|
||||
|
||||
// init schema
|
||||
versionManager.init();
|
||||
@@ -239,28 +150,84 @@ public class AllProjectsCreator {
|
||||
}
|
||||
}
|
||||
|
||||
@UsedAt(UsedAt.Project.GOOGLE)
|
||||
public static LabelType getDefaultCodeReviewLabel() {
|
||||
LabelType type =
|
||||
new LabelType(
|
||||
"Code-Review",
|
||||
ImmutableList.of(
|
||||
new LabelValue((short) 2, "Looks good to me, approved"),
|
||||
new LabelValue((short) 1, "Looks good to me, but someone else must approve"),
|
||||
new LabelValue((short) 0, "No score"),
|
||||
new LabelValue((short) -1, "I would prefer this is not merged as is"),
|
||||
new LabelValue((short) -2, "This shall not be merged")));
|
||||
type.setCopyMinScore(true);
|
||||
type.setCopyAllScoresOnTrivialRebase(true);
|
||||
return type;
|
||||
private void initDefaultAcls(ProjectConfig config, AllProjectsInput input) {
|
||||
AccessSection capabilities = config.getAccessSection(AccessSection.GLOBAL_CAPABILITIES, true);
|
||||
AccessSection heads = config.getAccessSection(AccessSection.HEADS, true);
|
||||
|
||||
checkArgument(input.codeReviewLabel().isPresent());
|
||||
LabelType codeReviewLabel = input.codeReviewLabel().get();
|
||||
|
||||
initDefaultAclsForRegisteredUsers(heads, codeReviewLabel, config);
|
||||
|
||||
input
|
||||
.batchUsersGroup()
|
||||
.ifPresent(
|
||||
batchUsersGroup -> initDefaultAclsForBatchUsers(capabilities, config, batchUsersGroup));
|
||||
|
||||
input
|
||||
.administratorsGroup()
|
||||
.ifPresent(
|
||||
adminsGroup ->
|
||||
initDefaultAclsForAdmins(
|
||||
capabilities, config, heads, codeReviewLabel, adminsGroup));
|
||||
}
|
||||
|
||||
private void initLabels(ProjectConfig projectConfig) {
|
||||
projectConfig.getLabelSections().put(codeReviewLabel.getName(), codeReviewLabel);
|
||||
additionalLabelType.forEach(t -> projectConfig.getLabelSections().put(t.getName(), t));
|
||||
private void initDefaultAclsForRegisteredUsers(
|
||||
AccessSection heads, LabelType codeReviewLabel, ProjectConfig config) {
|
||||
AccessSection refsFor = config.getAccessSection("refs/for/*", true);
|
||||
AccessSection magic = config.getAccessSection("refs/for/" + AccessSection.ALL, true);
|
||||
|
||||
grant(config, refsFor, Permission.ADD_PATCH_SET, registered);
|
||||
grant(config, heads, codeReviewLabel, -1, 1, registered);
|
||||
grant(config, heads, Permission.FORGE_AUTHOR, registered);
|
||||
grant(config, magic, Permission.PUSH, registered);
|
||||
grant(config, magic, Permission.PUSH_MERGE, registered);
|
||||
}
|
||||
|
||||
private void initSequences(Repository git, BatchRefUpdate bru) throws IOException {
|
||||
private void initDefaultAclsForBatchUsers(
|
||||
AccessSection capabilities, ProjectConfig config, GroupReference batchUsersGroup) {
|
||||
Permission priority = capabilities.getPermission(GlobalCapability.PRIORITY, true);
|
||||
PermissionRule r = rule(config, batchUsersGroup);
|
||||
r.setAction(Action.BATCH);
|
||||
priority.add(r);
|
||||
|
||||
Permission stream = capabilities.getPermission(GlobalCapability.STREAM_EVENTS, true);
|
||||
stream.add(rule(config, batchUsersGroup));
|
||||
}
|
||||
|
||||
private void initDefaultAclsForAdmins(
|
||||
AccessSection capabilities,
|
||||
ProjectConfig config,
|
||||
AccessSection heads,
|
||||
LabelType codeReviewLabel,
|
||||
GroupReference adminsGroup) {
|
||||
AccessSection all = config.getAccessSection(AccessSection.ALL, true);
|
||||
AccessSection tags = config.getAccessSection("refs/tags/*", true);
|
||||
AccessSection meta = config.getAccessSection(RefNames.REFS_CONFIG, true);
|
||||
|
||||
grant(config, capabilities, GlobalCapability.ADMINISTRATE_SERVER, adminsGroup);
|
||||
grant(config, all, Permission.READ, adminsGroup, anonymous);
|
||||
grant(config, heads, codeReviewLabel, -2, 2, adminsGroup, owners);
|
||||
grant(config, heads, Permission.CREATE, adminsGroup, owners);
|
||||
grant(config, heads, Permission.PUSH, adminsGroup, owners);
|
||||
grant(config, heads, Permission.SUBMIT, adminsGroup, owners);
|
||||
grant(config, heads, Permission.FORGE_COMMITTER, adminsGroup, owners);
|
||||
grant(config, heads, Permission.EDIT_TOPIC_NAME, true, adminsGroup, owners);
|
||||
|
||||
grant(config, tags, Permission.CREATE, adminsGroup, owners);
|
||||
grant(config, tags, Permission.CREATE_TAG, adminsGroup, owners);
|
||||
grant(config, tags, Permission.CREATE_SIGNED_TAG, adminsGroup, owners);
|
||||
|
||||
meta.getPermission(Permission.READ, true).setExclusiveGroup(true);
|
||||
grant(config, meta, Permission.READ, adminsGroup, owners);
|
||||
grant(config, meta, codeReviewLabel, -2, 2, adminsGroup, owners);
|
||||
grant(config, meta, Permission.CREATE, adminsGroup, owners);
|
||||
grant(config, meta, Permission.PUSH, adminsGroup, owners);
|
||||
grant(config, meta, Permission.SUBMIT, adminsGroup, owners);
|
||||
}
|
||||
|
||||
private void initSequences(Repository git, BatchRefUpdate bru, int firstChangeId)
|
||||
throws IOException {
|
||||
if (git.exactRef(REFS_SEQUENCES + Sequences.NAME_CHANGES) == null) {
|
||||
// Can't easily reuse the inserter from MetaDataUpdate, but this shouldn't slow down site
|
||||
// initialization unduly.
|
||||
|
||||
136
java/com/google/gerrit/server/schema/AllProjectsInput.java
Normal file
136
java/com/google/gerrit/server/schema/AllProjectsInput.java
Normal file
@@ -0,0 +1,136 @@
|
||||
// Copyright (C) 2019 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.schema;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gerrit.common.data.GroupReference;
|
||||
import com.google.gerrit.common.data.LabelType;
|
||||
import com.google.gerrit.common.data.LabelValue;
|
||||
import com.google.gerrit.extensions.client.InheritableBoolean;
|
||||
import com.google.gerrit.reviewdb.client.BooleanProjectConfig;
|
||||
import com.google.gerrit.server.UsedAt;
|
||||
import com.google.gerrit.server.notedb.Sequences;
|
||||
import java.util.Optional;
|
||||
|
||||
@AutoValue
|
||||
public abstract class AllProjectsInput {
|
||||
|
||||
/** Default boolean configs set when initializing All-Projects. */
|
||||
public static final ImmutableMap<BooleanProjectConfig, InheritableBoolean>
|
||||
DEFAULT_BOOLEAN_PROJECT_CONFIGS =
|
||||
ImmutableMap.of(
|
||||
BooleanProjectConfig.REQUIRE_CHANGE_ID,
|
||||
InheritableBoolean.TRUE,
|
||||
BooleanProjectConfig.USE_CONTENT_MERGE,
|
||||
InheritableBoolean.TRUE,
|
||||
BooleanProjectConfig.USE_CONTRIBUTOR_AGREEMENTS,
|
||||
InheritableBoolean.FALSE,
|
||||
BooleanProjectConfig.USE_SIGNED_OFF_BY,
|
||||
InheritableBoolean.FALSE,
|
||||
BooleanProjectConfig.ENABLE_SIGNED_PUSH,
|
||||
InheritableBoolean.FALSE);
|
||||
|
||||
@UsedAt(UsedAt.Project.GOOGLE)
|
||||
public static LabelType getDefaultCodeReviewLabel() {
|
||||
LabelType type =
|
||||
new LabelType(
|
||||
"Code-Review",
|
||||
ImmutableList.of(
|
||||
new LabelValue((short) 2, "Looks good to me, approved"),
|
||||
new LabelValue((short) 1, "Looks good to me, but someone else must approve"),
|
||||
new LabelValue((short) 0, "No score"),
|
||||
new LabelValue((short) -1, "I would prefer this is not merged as is"),
|
||||
new LabelValue((short) -2, "This shall not be merged")));
|
||||
type.setCopyMinScore(true);
|
||||
type.setCopyAllScoresOnTrivialRebase(true);
|
||||
return type;
|
||||
}
|
||||
|
||||
/** The administrator group which gets default permissions granted. */
|
||||
public abstract Optional<GroupReference> administratorsGroup();
|
||||
|
||||
/** The group which gets stream-events permission granted and appropriate properties set. */
|
||||
public abstract Optional<GroupReference> batchUsersGroup();
|
||||
|
||||
/** The commit message used when commit the project config change. */
|
||||
public abstract Optional<String> commitMessage();
|
||||
|
||||
/** The first change-id used in this host. */
|
||||
@UsedAt(UsedAt.Project.GOOGLE)
|
||||
public abstract int firstChangeIdForNoteDb();
|
||||
|
||||
/** The "Code-Review" label to be defined in All-Projects. */
|
||||
@UsedAt(UsedAt.Project.GOOGLE)
|
||||
public abstract Optional<LabelType> codeReviewLabel();
|
||||
|
||||
/** Description for the All-Projects. */
|
||||
public abstract Optional<String> projectDescription();
|
||||
|
||||
/** Boolean project configs to be set in All-Projects. */
|
||||
public abstract ImmutableMap<BooleanProjectConfig, InheritableBoolean> booleanProjectConfigs();
|
||||
|
||||
/** Whether initializing default access sections in All-Projects. */
|
||||
public abstract boolean initDefaultAcls();
|
||||
|
||||
public abstract Builder toBuilder();
|
||||
|
||||
public static Builder builder() {
|
||||
Builder builder =
|
||||
new AutoValue_AllProjectsInput.Builder()
|
||||
.codeReviewLabel(getDefaultCodeReviewLabel())
|
||||
.firstChangeIdForNoteDb(Sequences.FIRST_CHANGE_ID)
|
||||
.initDefaultAcls(true);
|
||||
DEFAULT_BOOLEAN_PROJECT_CONFIGS.forEach(builder::addBooleanProjectConfig);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static Builder builderWithNoDefault() {
|
||||
return new AutoValue_AllProjectsInput.Builder();
|
||||
}
|
||||
|
||||
@AutoValue.Builder
|
||||
public abstract static class Builder {
|
||||
public abstract Builder administratorsGroup(GroupReference adminGroup);
|
||||
|
||||
public abstract Builder batchUsersGroup(GroupReference batchGroup);
|
||||
|
||||
public abstract Builder commitMessage(String commitMessage);
|
||||
|
||||
public abstract Builder firstChangeIdForNoteDb(int firstChangeId);
|
||||
|
||||
@UsedAt(UsedAt.Project.GOOGLE)
|
||||
public abstract Builder codeReviewLabel(LabelType codeReviewLabel);
|
||||
|
||||
@UsedAt(UsedAt.Project.GOOGLE)
|
||||
public abstract Builder projectDescription(String projectDescription);
|
||||
|
||||
public abstract ImmutableMap.Builder<BooleanProjectConfig, InheritableBoolean>
|
||||
booleanProjectConfigsBuilder();
|
||||
|
||||
public Builder addBooleanProjectConfig(
|
||||
BooleanProjectConfig booleanProjectConfig, InheritableBoolean inheritableBoolean) {
|
||||
booleanProjectConfigsBuilder().put(booleanProjectConfig, inheritableBoolean);
|
||||
return this;
|
||||
}
|
||||
|
||||
@UsedAt(UsedAt.Project.GOOGLE)
|
||||
public abstract Builder initDefaultAcls(boolean initDefaultACLs);
|
||||
|
||||
public abstract AllProjectsInput build();
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ package com.google.gerrit.server.schema;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
|
||||
import static com.google.gerrit.server.schema.AclUtil.grant;
|
||||
import static com.google.gerrit.server.schema.AllProjectsCreator.getDefaultCodeReviewLabel;
|
||||
import static com.google.gerrit.server.schema.AllProjectsInput.getDefaultCodeReviewLabel;
|
||||
|
||||
import com.google.gerrit.common.Nullable;
|
||||
import com.google.gerrit.common.Version;
|
||||
|
||||
@@ -94,7 +94,9 @@ public class SchemaCreatorImpl implements SchemaCreator {
|
||||
GroupReference admins = createGroupReference("Administrators");
|
||||
GroupReference batchUsers = createGroupReference("Non-Interactive Users");
|
||||
|
||||
allProjectsCreator.setAdministrators(admins).setBatchUsers(batchUsers).create();
|
||||
AllProjectsInput allProjectsInput =
|
||||
AllProjectsInput.builder().administratorsGroup(admins).batchUsersGroup(batchUsers).build();
|
||||
allProjectsCreator.create(allProjectsInput);
|
||||
// We have to create the All-Users repository before we can use it to store the groups in it.
|
||||
allUsersCreator.setAdministrators(admins).create();
|
||||
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
// Copyright (C) 2019 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.schema.testing;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.google.gerrit.reviewdb.client.RefNames;
|
||||
import com.google.gerrit.server.config.AllProjectsName;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.eclipse.jgit.errors.ConfigInvalidException;
|
||||
import org.eclipse.jgit.lib.BlobBasedConfig;
|
||||
import org.eclipse.jgit.lib.Config;
|
||||
import org.eclipse.jgit.lib.Ref;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
|
||||
public class AllProjectsCreatorTestUtil {
|
||||
private static final ImmutableList<String> DEFAULT_ALL_PROJECTS_PROJECT_SECTION =
|
||||
ImmutableList.of("[project]", " description = Access inherited by all other projects.");
|
||||
private static final ImmutableList<String> DEFAULT_ALL_PROJECTS_RECEIVE_SECTION =
|
||||
ImmutableList.of(
|
||||
"[receive]",
|
||||
" requireContributorAgreement = false",
|
||||
" requireSignedOffBy = false",
|
||||
" requireChangeId = true",
|
||||
" enableSignedPush = false");
|
||||
private static final ImmutableList<String> DEFAULT_ALL_PROJECTS_SUBMIT_SECTION =
|
||||
ImmutableList.of("[submit]", " mergeContent = true");
|
||||
private static final ImmutableList<String> DEFAULT_ALL_PROJECTS_CAPABILITY_SECTION =
|
||||
ImmutableList.of(
|
||||
"[capability]",
|
||||
" administrateServer = group Administrators",
|
||||
" priority = batch group Non-Interactive Users",
|
||||
" streamEvents = group Non-Interactive Users");
|
||||
private static final ImmutableList<String> DEFAULT_ALL_PROJECTS_ACCESS_SECTION =
|
||||
ImmutableList.of(
|
||||
"[access \"refs/*\"]",
|
||||
" read = group Administrators",
|
||||
" read = group Anonymous Users",
|
||||
"[access \"refs/for/*\"]",
|
||||
" addPatchSet = group Registered Users",
|
||||
"[access \"refs/for/refs/*\"]",
|
||||
" push = group Registered Users",
|
||||
" pushMerge = group Registered Users",
|
||||
"[access \"refs/heads/*\"]",
|
||||
" create = group Administrators",
|
||||
" create = group Project Owners",
|
||||
" editTopicName = +force group Administrators",
|
||||
" editTopicName = +force group Project Owners",
|
||||
" forgeAuthor = group Registered Users",
|
||||
" forgeCommitter = group Administrators",
|
||||
" forgeCommitter = group Project Owners",
|
||||
" label-Code-Review = -2..+2 group Administrators",
|
||||
" label-Code-Review = -2..+2 group Project Owners",
|
||||
" label-Code-Review = -1..+1 group Registered Users",
|
||||
" push = group Administrators",
|
||||
" push = group Project Owners",
|
||||
" submit = group Administrators",
|
||||
" submit = group Project Owners",
|
||||
"[access \"refs/meta/config\"]",
|
||||
" exclusiveGroupPermissions = read",
|
||||
" create = group Administrators",
|
||||
" create = group Project Owners",
|
||||
" label-Code-Review = -2..+2 group Administrators",
|
||||
" label-Code-Review = -2..+2 group Project Owners",
|
||||
" push = group Administrators",
|
||||
" push = group Project Owners",
|
||||
" read = group Administrators",
|
||||
" read = group Project Owners",
|
||||
" submit = group Administrators",
|
||||
" submit = group Project Owners",
|
||||
"[access \"refs/tags/*\"]",
|
||||
" create = group Administrators",
|
||||
" create = group Project Owners",
|
||||
" createSignedTag = group Administrators",
|
||||
" createSignedTag = group Project Owners",
|
||||
" createTag = group Administrators",
|
||||
" createTag = group Project Owners");
|
||||
private static final ImmutableList<String> DEFAULT_ALL_PROJECTS_LABEL_SECTION =
|
||||
ImmutableList.of(
|
||||
"[label \"Code-Review\"]",
|
||||
" function = MaxWithBlock",
|
||||
" defaultValue = 0",
|
||||
" copyMinScore = true",
|
||||
" copyAllScoresOnTrivialRebase = true",
|
||||
" value = -2 This shall not be merged",
|
||||
" value = -1 I would prefer this is not merged as is",
|
||||
" value = 0 No score",
|
||||
" value = +1 Looks good to me, but someone else must approve",
|
||||
" value = +2 Looks good to me, approved");
|
||||
|
||||
public static String getDefaultAllProjectsWithAllDefaultSections() {
|
||||
return Streams.stream(
|
||||
Iterables.concat(
|
||||
DEFAULT_ALL_PROJECTS_PROJECT_SECTION,
|
||||
DEFAULT_ALL_PROJECTS_RECEIVE_SECTION,
|
||||
DEFAULT_ALL_PROJECTS_SUBMIT_SECTION,
|
||||
DEFAULT_ALL_PROJECTS_CAPABILITY_SECTION,
|
||||
DEFAULT_ALL_PROJECTS_ACCESS_SECTION,
|
||||
DEFAULT_ALL_PROJECTS_LABEL_SECTION))
|
||||
.collect(Collectors.joining("\n"));
|
||||
}
|
||||
|
||||
public static String getAllProjectsWithoutDefaultAcls() {
|
||||
return Streams.stream(
|
||||
Iterables.concat(
|
||||
DEFAULT_ALL_PROJECTS_PROJECT_SECTION,
|
||||
DEFAULT_ALL_PROJECTS_RECEIVE_SECTION,
|
||||
DEFAULT_ALL_PROJECTS_SUBMIT_SECTION,
|
||||
DEFAULT_ALL_PROJECTS_LABEL_SECTION))
|
||||
.collect(Collectors.joining("\n"));
|
||||
}
|
||||
|
||||
// Loads the "project.config" from the All-Projects repo.
|
||||
public static Config readAllProjectsConfig(
|
||||
GitRepositoryManager repoManager, AllProjectsName allProjectsName)
|
||||
throws IOException, ConfigInvalidException {
|
||||
try (Repository repo = repoManager.openRepository(allProjectsName)) {
|
||||
Ref configRef = repo.exactRef(RefNames.REFS_CONFIG);
|
||||
return new BlobBasedConfig(null, repo, configRef.getObjectId(), "project.config");
|
||||
}
|
||||
}
|
||||
|
||||
public static void assertTwoConfigsEquivalent(Config config1, Config config2) {
|
||||
Set<String> sections1 = config1.getSections();
|
||||
Set<String> sections2 = config2.getSections();
|
||||
assertThat(sections1).containsExactlyElementsIn(sections2);
|
||||
|
||||
sections1.forEach(s -> assertSectionEquivalent(config1, config2, s));
|
||||
}
|
||||
|
||||
public static void assertSectionEquivalent(Config config1, Config config2, String section) {
|
||||
assertSubsectionEquivalent(config1, config2, section, null);
|
||||
|
||||
Set<String> subsections1 = config1.getSubsections(section);
|
||||
Set<String> subsections2 = config2.getSubsections(section);
|
||||
assertThat(subsections1)
|
||||
.named("section \"%s\"", section)
|
||||
.containsExactlyElementsIn(subsections2);
|
||||
|
||||
subsections1.forEach(s -> assertSubsectionEquivalent(config1, config2, section, s));
|
||||
}
|
||||
|
||||
private static void assertSubsectionEquivalent(
|
||||
Config config1, Config config2, String section, String subsection) {
|
||||
Set<String> subsectionNames1 = config1.getNames(section, subsection);
|
||||
Set<String> subsectionNames2 = config2.getNames(section, subsection);
|
||||
String name = String.format("subsection \"%s\" of section \"%s\"", subsection, section);
|
||||
assertThat(subsectionNames1).named(name).containsExactlyElementsIn(subsectionNames2);
|
||||
|
||||
subsectionNames1.forEach(
|
||||
n ->
|
||||
assertThat(config1.getStringList(section, subsection, n))
|
||||
.named(name)
|
||||
.asList()
|
||||
.containsExactlyElementsIn(config2.getStringList(section, subsection, n)));
|
||||
}
|
||||
|
||||
private AllProjectsCreatorTestUtil() {}
|
||||
}
|
||||
14
java/com/google/gerrit/server/schema/testing/BUILD
Normal file
14
java/com/google/gerrit/server/schema/testing/BUILD
Normal file
@@ -0,0 +1,14 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
java_library(
|
||||
name = "testing",
|
||||
testonly = True,
|
||||
srcs = glob(["*.java"]),
|
||||
deps = [
|
||||
"//java/com/google/gerrit/reviewdb:server",
|
||||
"//java/com/google/gerrit/server",
|
||||
"//lib:guava",
|
||||
"//lib/jgit/org.eclipse.jgit:jgit",
|
||||
"//lib/truth",
|
||||
],
|
||||
)
|
||||
@@ -56,6 +56,7 @@ junit_tests(
|
||||
"//java/com/google/gerrit/server/project/testing:project-test-util",
|
||||
"//java/com/google/gerrit/server/restapi",
|
||||
"//java/com/google/gerrit/server/schema",
|
||||
"//java/com/google/gerrit/server/schema/testing",
|
||||
"//java/com/google/gerrit/server/util/time",
|
||||
"//java/com/google/gerrit/testing:gerrit-test-util",
|
||||
"//java/com/google/gerrit/truth",
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
// Copyright (C) 2019 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.schema;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.gerrit.server.schema.AllProjectsInput.getDefaultCodeReviewLabel;
|
||||
import static com.google.gerrit.server.schema.testing.AllProjectsCreatorTestUtil.assertSectionEquivalent;
|
||||
import static com.google.gerrit.server.schema.testing.AllProjectsCreatorTestUtil.assertTwoConfigsEquivalent;
|
||||
import static com.google.gerrit.server.schema.testing.AllProjectsCreatorTestUtil.getAllProjectsWithoutDefaultAcls;
|
||||
import static com.google.gerrit.server.schema.testing.AllProjectsCreatorTestUtil.getDefaultAllProjectsWithAllDefaultSections;
|
||||
import static com.google.gerrit.server.schema.testing.AllProjectsCreatorTestUtil.readAllProjectsConfig;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.gerrit.common.data.GroupReference;
|
||||
import com.google.gerrit.common.data.LabelType;
|
||||
import com.google.gerrit.common.data.LabelValue;
|
||||
import com.google.gerrit.extensions.client.InheritableBoolean;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
import com.google.gerrit.reviewdb.client.BooleanProjectConfig;
|
||||
import com.google.gerrit.server.GerritPersonIdent;
|
||||
import com.google.gerrit.server.account.GroupUUID;
|
||||
import com.google.gerrit.server.config.AllProjectsName;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
import com.google.gerrit.server.notedb.Sequences;
|
||||
import com.google.gerrit.testing.GerritBaseTests;
|
||||
import com.google.gerrit.testing.InMemoryModule;
|
||||
import com.google.inject.Inject;
|
||||
import org.eclipse.jgit.lib.Config;
|
||||
import org.eclipse.jgit.lib.PersonIdent;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class AllProjectsCreatorTest extends GerritBaseTests {
|
||||
private static final LabelType TEST_LABEL =
|
||||
new LabelType(
|
||||
"Test-Label",
|
||||
ImmutableList.of(
|
||||
new LabelValue((short) 2, "Two"),
|
||||
new LabelValue((short) 0, "Zero"),
|
||||
new LabelValue((short) 1, "One")));
|
||||
|
||||
private static final String TEST_LABEL_STRING =
|
||||
String.join(
|
||||
"\n",
|
||||
ImmutableList.of(
|
||||
"[label \"Test-Label\"]",
|
||||
"\tfunction = MaxWithBlock",
|
||||
"\tdefaultValue = 0",
|
||||
"\tvalue = 0 Zero",
|
||||
"\tvalue = +1 One",
|
||||
"\tvalue = +2 Two"));
|
||||
|
||||
@Inject private AllProjectsName allProjectsName;
|
||||
|
||||
@Inject @GerritPersonIdent private PersonIdent serverUser;
|
||||
|
||||
@Inject private AllProjectsCreator allProjectsCreator;
|
||||
|
||||
@Inject private GitRepositoryManager repoManager;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
InMemoryModule inMemoryModule = new InMemoryModule();
|
||||
inMemoryModule.inject(this);
|
||||
|
||||
// Creates an empty All-Projects.
|
||||
Repository repo = repoManager.createRepository(allProjectsName);
|
||||
repo.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createDefaultAllProjectsConfig() throws Exception {
|
||||
// Loads the expected configs.
|
||||
Config expectedConfig = new Config();
|
||||
expectedConfig.fromText(getDefaultAllProjectsWithAllDefaultSections());
|
||||
|
||||
GroupReference adminsGroup = createGroupReference("Administrators");
|
||||
GroupReference batchUsersGroup = createGroupReference("Non-Interactive Users");
|
||||
AllProjectsInput allProjectsInput =
|
||||
AllProjectsInput.builder()
|
||||
.administratorsGroup(adminsGroup)
|
||||
.batchUsersGroup(batchUsersGroup)
|
||||
.build();
|
||||
allProjectsCreator.create(allProjectsInput);
|
||||
|
||||
Config config = readAllProjectsConfig(repoManager, allProjectsName);
|
||||
assertTwoConfigsEquivalent(config, expectedConfig);
|
||||
}
|
||||
|
||||
private GroupReference createGroupReference(String name) {
|
||||
AccountGroup.UUID groupUuid = GroupUUID.make(name, serverUser);
|
||||
return new GroupReference(groupUuid, name);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createAllProjectsWithNewCodeReviewLabel() throws Exception {
|
||||
Config expectedLabelConfig = new Config();
|
||||
expectedLabelConfig.fromText(TEST_LABEL_STRING);
|
||||
|
||||
AllProjectsInput allProjectsInput =
|
||||
AllProjectsInput.builder().codeReviewLabel(TEST_LABEL).build();
|
||||
allProjectsCreator.create(allProjectsInput);
|
||||
|
||||
Config config = readAllProjectsConfig(repoManager, allProjectsName);
|
||||
assertSectionEquivalent(config, expectedLabelConfig, "label");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createAllProjectsWithProjectDescription() throws Exception {
|
||||
String testDescription = "test description";
|
||||
AllProjectsInput allProjectsInput =
|
||||
AllProjectsInput.builder().projectDescription(testDescription).build();
|
||||
allProjectsCreator.create(allProjectsInput);
|
||||
|
||||
Config config = readAllProjectsConfig(repoManager, allProjectsName);
|
||||
assertThat(config.getString("project", null, "description")).isEqualTo(testDescription);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createAllProjectsWithBooleanConfigs() throws Exception {
|
||||
AllProjectsInput allProjectsInput =
|
||||
AllProjectsInput.builderWithNoDefault()
|
||||
.codeReviewLabel(getDefaultCodeReviewLabel())
|
||||
.firstChangeIdForNoteDb(Sequences.FIRST_CHANGE_ID)
|
||||
.addBooleanProjectConfig(
|
||||
BooleanProjectConfig.REJECT_EMPTY_COMMIT, InheritableBoolean.TRUE)
|
||||
.initDefaultAcls(true)
|
||||
.build();
|
||||
allProjectsCreator.create(allProjectsInput);
|
||||
|
||||
Config config = readAllProjectsConfig(repoManager, allProjectsName);
|
||||
assertThat(config.getBoolean("submit", null, "rejectEmptyCommit", false)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createAllProjectsWithoutInitializingDefaultACLs() throws Exception {
|
||||
AllProjectsInput allProjectsInput = AllProjectsInput.builder().initDefaultAcls(false).build();
|
||||
allProjectsCreator.create(allProjectsInput);
|
||||
|
||||
Config expectedConfig = new Config();
|
||||
expectedConfig.fromText(getAllProjectsWithoutDefaultAcls());
|
||||
Config config = readAllProjectsConfig(repoManager, allProjectsName);
|
||||
assertTwoConfigsEquivalent(config, expectedConfig);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createAllProjectsOnlyInitializingProjectDescription() throws Exception {
|
||||
String description = "a project.config with just a project description";
|
||||
AllProjectsInput allProjectsInput =
|
||||
AllProjectsInput.builderWithNoDefault()
|
||||
.firstChangeIdForNoteDb(Sequences.FIRST_CHANGE_ID)
|
||||
.projectDescription(description)
|
||||
.initDefaultAcls(false)
|
||||
.build();
|
||||
allProjectsCreator.create(allProjectsInput);
|
||||
|
||||
Config expectedConfig = new Config();
|
||||
expectedConfig.setString("project", null, "description", description);
|
||||
Config config = readAllProjectsConfig(repoManager, allProjectsName);
|
||||
assertTwoConfigsEquivalent(config, expectedConfig);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user