Merge "Allow setting label types in project.config"

This commit is contained in:
Dave Borowitz
2013-03-14 21:16:59 +00:00
committed by Gerrit Code Review
5 changed files with 139 additions and 30 deletions

View File

@@ -252,7 +252,7 @@ public class PermissionRule implements Comparable<PermissionRule> {
return rule;
}
private static int parseInt(String value) {
public static int parseInt(String value) {
if (value.startsWith("+")) {
value = value.substring(1);
}

View File

@@ -16,13 +16,20 @@ package com.google.gerrit.server.git;
import static com.google.gerrit.common.data.Permission.isPermission;
import com.google.common.base.CharMatcher;
import com.google.common.base.Objects;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.primitives.Shorts;
import com.google.gerrit.common.data.AccessSection;
import com.google.gerrit.common.data.ContributorAgreement;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.common.data.GroupDescription;
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;
@@ -35,6 +42,7 @@ import com.google.gerrit.reviewdb.client.Project.SubmitType;
import com.google.gerrit.server.account.GroupBackend;
import com.google.gerrit.server.config.ConfigUtil;
import com.google.gerrit.server.mail.Address;
import com.google.gerrit.server.workflow.CategoryFunction;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.CommitBuilder;
@@ -98,6 +106,13 @@ public class ProjectConfig extends VersionedMetaData {
private static final String KEY_DEFAULT = "default";
private static final String KEY_LOCAL_DEFAULT = "local-default";
private static final String LABEL = "label";
private static final String KEY_ID = "id";
private static final String KEY_ABBREVIATION = "abbreviation";
private static final String KEY_FUNCTION = "function";
private static final String KEY_COPY_MIN_SCORE = "copyMinScore";
private static final String KEY_VALUE = "value";
private static final SubmitType defaultSubmitAction =
SubmitType.MERGE_IF_NECESSARY;
private static final State defaultStateValue =
@@ -110,6 +125,7 @@ public class ProjectConfig extends VersionedMetaData {
private Map<String, AccessSection> accessSections;
private Map<String, ContributorAgreement> contributorAgreements;
private Map<String, NotifyConfig> notifySections;
private Map<String, LabelType> labelSections;
private List<ValidationError> validationErrors;
private ObjectId rulesId;
@@ -208,6 +224,10 @@ public class ProjectConfig extends VersionedMetaData {
return notifySections.values();
}
public Collection<LabelType> getLabelSections() {
return labelSections.values();
}
public GroupReference resolve(AccountGroup group) {
return resolve(GroupReference.forGroup(group));
}
@@ -307,6 +327,7 @@ public class ProjectConfig extends VersionedMetaData {
loadContributorAgreements(rc, groupsByName);
loadAccessSections(rc, groupsByName);
loadNotifySections(rc, groupsByName);
loadLabelSections(rc);
}
private void loadAccountsSection(
@@ -496,6 +517,68 @@ public class ProjectConfig extends VersionedMetaData {
}
}
private static LabelValue parseLabelValue(String src) {
List<String> parts = ImmutableList.copyOf(
Splitter.on(CharMatcher.WHITESPACE).omitEmptyStrings().limit(2)
.split(src));
if (parts.isEmpty()) {
throw new IllegalArgumentException("empty value");
}
return new LabelValue(
Shorts.checkedCast(PermissionRule.parseInt(parts.get(0))),
parts.get(1));
}
private void loadLabelSections(Config rc) throws IOException {
labelSections = Maps.newLinkedHashMap();
for (String name : rc.getSubsections(LABEL)) {
List<LabelValue> values = Lists.newArrayList();
for (String value : rc.getStringList(LABEL, name, KEY_VALUE)) {
try {
values.add(parseLabelValue(value));
} catch (IllegalArgumentException notValue) {
error(new ValidationError(PROJECT_CONFIG, String.format(
"Invalid %s \"%s\" for label \"%s\": %s",
KEY_VALUE, value, name, notValue.getMessage())));
}
}
LabelType label;
String id = rc.getString(LABEL, name, KEY_ID);
if (id == null || id.length() > 4) {
error(new ValidationError(PROJECT_CONFIG, String.format(
"Invalid label ID \"%s\" for label \"%s\": "
+ "Label ID may have at most 4 characters", id, name)));
continue;
}
try {
label = new LabelType(id, name, values);
} catch (IllegalArgumentException badName) {
error(new ValidationError(PROJECT_CONFIG, String.format(
"Invalid label \"%s\"", name)));
continue;
}
String abbr = rc.getString(LABEL, name, KEY_ABBREVIATION);
if (abbr != null) {
label.setAbbreviatedName(abbr);
}
String functionName = Objects.firstNonNull(
rc.getString(LABEL, name, KEY_FUNCTION), "MaxWithBlock");
if (CategoryFunction.forName(functionName) != null) {
label.setFunctionName(functionName);
} else {
error(new ValidationError(PROJECT_CONFIG, String.format(
"Invalid %s for label \"%s\"", KEY_FUNCTION, name)));
label.setFunctionName(null);
}
label.setCopyMinScore(
rc.getBoolean(LABEL, name, KEY_COPY_MIN_SCORE, false));
labelSections.put(name, label);
}
}
private Map<String, GroupReference> readGroupList() throws IOException {
groupsByUUID = new HashMap<AccountGroup.UUID, GroupReference>();
Map<String, GroupReference> groupsByName =

View File

@@ -122,10 +122,10 @@ public class ProjectControl {
private List<SectionMatcher> allSections;
private List<SectionMatcher> localSections;
private LabelTypes labelTypes;
private Map<String, RefControl> refControls;
private Boolean declaredOwner;
@Inject
ProjectControl(@GitUploadPackGroups Set<AccountGroup.UUID> uploadGroups,
@GitReceivePackGroups Set<AccountGroup.UUID> receiveGroups,
@@ -183,7 +183,10 @@ public class ProjectControl {
}
public LabelTypes getLabelTypes() {
return state.getLabelTypes();
if (labelTypes == null) {
labelTypes = state.getLabelTypes();
}
return labelTypes;
}
private boolean isHidden() {

View File

@@ -18,8 +18,10 @@ import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.gerrit.common.data.AccessSection;
import com.google.gerrit.common.data.GroupReference;
import com.google.gerrit.common.data.LabelType;
import com.google.gerrit.common.data.LabelTypes;
import com.google.gerrit.common.data.Permission;
import com.google.gerrit.common.data.PermissionRule;
@@ -51,6 +53,7 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/** Cached information on a project. */
@@ -66,7 +69,7 @@ public class ProjectState {
private final PrologEnvironment.Factory envFactory;
private final GitRepositoryManager gitMgr;
private final RulesCache rulesCache;
private final LabelTypes labelTypes;
private final LabelTypes dbLabelTypes;
private final ProjectConfig config;
private final Set<AccountGroup.UUID> localOwners;
@@ -104,7 +107,7 @@ public class ProjectState {
this.capabilities = isAllProjects
? new CapabilityCollection(config.getAccessSection(AccessSection.GLOBAL_CAPABILITIES))
: null;
this.labelTypes = labelTypes;
this.dbLabelTypes = labelTypes;
if (isAllProjects && !Permission.canBeOnAllProjects(AccessSection.ALL, Permission.OWNER)) {
localOwners = Collections.emptySet();
@@ -342,7 +345,24 @@ public class ProjectState {
}
public LabelTypes getLabelTypes() {
return labelTypes;
Map<String, LabelType> types = Maps.newLinkedHashMap();
for (LabelType type : dbLabelTypes.getLabelTypes()) {
types.put(type.getName(), type);
}
List<ProjectState> projects = Lists.newArrayList(tree());
Collections.reverse(projects);
for (ProjectState s : projects) {
for (LabelType type : s.getConfig().getLabelSections()) {
types.put(type.getName(), type);
}
}
List<LabelType> all = Lists.newArrayListWithCapacity(types.size());
for (LabelType type : types.values()) {
if (!type.getValues().isEmpty()) {
all.add(type);
}
}
return new LabelTypes(Collections.unmodifiableList(all));
}
private boolean getInheritableBoolean(Function<Project, InheritableBoolean> func) {

View File

@@ -22,6 +22,7 @@ import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.Branch;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.git.ProjectConfig;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectState;
@@ -31,31 +32,24 @@ import java.util.Arrays;
import java.util.Set;
public class GerritCommonTest extends PrologTestCase {
private ProjectState project;
private Projects projects;
@Override
public void setUp() throws Exception {
super.setUp();
LabelTypes types =
new LabelTypes(Arrays.asList(
category("CRVW", "Code-Review",
value(2, "Looks good to me, approved"),
value(1, "Looks good to me, but someone else must approve"),
value(0, "No score"),
value(-1, "I would prefer that you didn't submit this"),
value(-2, "Do not submit")),
category("VRIF", "Verified", value(1, "Verified"),
value(0, "No score"), value(-1, "Fails"))));
ProjectConfig config = new ProjectConfig(new Project.NameKey("myproject"));
config.createInMemory();
project = new ProjectState(null, null, null, null, null,
null, types, config);
projects = new Projects(new LabelTypes(Arrays.asList(
category("CRVW", "Code-Review",
value(2, "Looks good to me, approved"),
value(1, "Looks good to me, but someone else must approve"),
value(0, "No score"),
value(-1, "I would prefer that you didn't submit this"),
value(-2, "Do not submit")),
category("VRIF", "Verified", value(1, "Verified"),
value(0, "No score"), value(-1, "Fails")))));
load("gerrit", "gerrit_common_test.pl", new AbstractModule() {
@Override
protected void configure() {
bind(ProjectCache.class).toInstance(new Projects(project));
bind(ProjectCache.class).toInstance(projects);
}
});
}
@@ -64,23 +58,32 @@ public class GerritCommonTest extends PrologTestCase {
protected void setUpEnvironment(PrologEnvironment env) {
env.set(StoredValues.CHANGE, new Change(
new Change.Key("Ibeef"), new Change.Id(1), new Account.Id(2),
new Branch.NameKey(project.getProject().getNameKey(), "master")));
new Branch.NameKey(projects.allProjectsName, "master")));
}
private static LabelValue value(int value, String text) {
return new LabelValue((short) value, text);
}
private static ProjectConfig config(String name) {
ProjectConfig config = new ProjectConfig(new Project.NameKey(name));
config.createInMemory();
return config;
}
private static LabelType category(String id, String name,
LabelValue... values) {
return new LabelType(id, name, Arrays.asList(values));
}
private static class Projects implements ProjectCache {
private final ProjectState project;
private final AllProjectsName allProjectsName;
private final ProjectState allProjects;
private Projects(ProjectState project) {
this.project = project;
private Projects(LabelTypes labelTypes) {
allProjectsName = new AllProjectsName("All-Projects");
allProjects = new ProjectState(this, allProjectsName, null,
null, null, null, labelTypes, config(allProjectsName.get()));
}
@Override
@@ -90,8 +93,8 @@ public class GerritCommonTest extends PrologTestCase {
@Override
public ProjectState get(Project.NameKey projectName) {
assertEquals(project.getProject().getNameKey(), projectName);
return project;
assertEquals(allProjectsName, projectName);
return allProjects;
}
@Override