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:
xchangcheng
2019-01-24 12:57:23 +00:00
committed by Gerrit Code Review
8 changed files with 607 additions and 135 deletions

View File

@@ -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.

View 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();
}
}

View File

@@ -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;

View File

@@ -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();

View File

@@ -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() {}
}

View 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",
],
)

View File

@@ -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",

View File

@@ -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);
}
}