Support branch specific labels
By default a given project's label applicable scope is all changes on all branches of this project and its child projects. Label's applicable scope can be branch specific via configuration. E.g. create a label 'Video-Qualify' on parent project and configure the 'branch' as: [label "Video-Qualify"] branch = refs/heads/video-1.0/* branch = refs/heads/video-1.1/Kino Then ONLY changes in above branch scope of parent project and child projects will be affected by 'Video-Qualify'. Please note the 'branch' is independent from the branch scope related to access control defined in 'access' parts in 'project.config' file. That means from the UI a user can always assign permissions for that label on a branch, but this permission is then ignored if the label doesn't apply for that branch. Change-Id: I414e62503b0da4af022abbc9988593ba9ac87916
This commit is contained in:
@@ -244,6 +244,30 @@ If false, the label cannot be overridden by child projects. Any
|
||||
configuration for this label in child projects will be ignored. Defaults
|
||||
to true.
|
||||
|
||||
[[label_branch]]
|
||||
`label.Label-Name.branch`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
By default a given project's label applicable scope is all changes
|
||||
on all branches of this project and its child projects.
|
||||
|
||||
Label's applicable scope can be branch specific via configuration.
|
||||
E.g. create a label `Video-Qualify` on parent project and configure
|
||||
the `branch` as:
|
||||
|
||||
====
|
||||
[label "Video-Qualify"]
|
||||
branch = refs/heads/video-1.0/*
|
||||
branch = refs/heads/video-1.1/Kino
|
||||
====
|
||||
|
||||
Then *only* changes in above branch scope of parent project and child
|
||||
projects will be affected by `Video-Qualify`.
|
||||
|
||||
NOTE: The `branch` is independent from the branch scope defined in `access`
|
||||
parts in `project.config` file. That means from the UI a user can always
|
||||
assign permissions for that label on a branch, but this permission is then
|
||||
ignored if the label doesn't apply for that branch.
|
||||
|
||||
[[label_example]]
|
||||
Example
|
||||
|
@@ -103,6 +103,7 @@ public class LabelType {
|
||||
protected short maxPositive;
|
||||
|
||||
private transient boolean canOverride;
|
||||
private transient List<String> refPatterns;
|
||||
private transient List<Integer> intList;
|
||||
private transient Map<Short, LabelValue> byValue;
|
||||
|
||||
@@ -157,10 +158,18 @@ public class LabelType {
|
||||
return canOverride;
|
||||
}
|
||||
|
||||
public List<String> getRefPatterns() {
|
||||
return refPatterns;
|
||||
}
|
||||
|
||||
public void setCanOverride(boolean canOverride) {
|
||||
this.canOverride = canOverride;
|
||||
}
|
||||
|
||||
public void setRefPatterns(List<String> refPatterns) {
|
||||
this.refPatterns = refPatterns;
|
||||
}
|
||||
|
||||
public List<LabelValue> getValues() {
|
||||
return values;
|
||||
}
|
||||
|
@@ -59,6 +59,7 @@ import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
@@ -127,6 +128,7 @@ public class ProjectConfig extends VersionedMetaData {
|
||||
private static final String KEY_COPY_MAX_SCORE = "copyMaxScore";
|
||||
private static final String KEY_VALUE = "value";
|
||||
private static final String KEY_CAN_OVERRIDE = "canOverride";
|
||||
private static final String KEY_Branch = "branch";
|
||||
private static final Set<String> LABEL_FUNCTIONS = ImmutableSet.of(
|
||||
"MaxWithBlock", "AnyWithBlock", "MaxNoBlock", "NoBlock", "NoOp");
|
||||
|
||||
@@ -651,10 +653,17 @@ public class ProjectConfig extends VersionedMetaData {
|
||||
rc.getBoolean(LABEL, name, KEY_COPY_MAX_SCORE, false));
|
||||
label.setCanOverride(
|
||||
rc.getBoolean(LABEL, name, KEY_CAN_OVERRIDE, true));
|
||||
label.setRefPatterns(getStringListOrNull(rc, LABEL, name, KEY_Branch));
|
||||
labelSections.put(name, label);
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> getStringListOrNull(Config rc, String section,
|
||||
String subSection, String name) {
|
||||
String[] ac = rc.getStringList(section, subSection, name);
|
||||
return ac.length == 0 ? null : Arrays.asList(ac);
|
||||
}
|
||||
|
||||
private void loadCommentLinkSections(Config rc) {
|
||||
Set<String> subsections = rc.getSubsections(COMMENTLINK);
|
||||
commentLinkSections = Lists.newArrayListWithCapacity(subsections.size());
|
||||
|
@@ -14,8 +14,11 @@
|
||||
|
||||
package com.google.gerrit.server.project;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.gerrit.common.data.LabelType;
|
||||
import com.google.gerrit.common.data.LabelTypes;
|
||||
import com.google.gerrit.common.data.PermissionRange;
|
||||
import com.google.gerrit.common.data.RefConfigSection;
|
||||
import com.google.gerrit.common.data.SubmitRecord;
|
||||
import com.google.gerrit.common.data.SubmitTypeRecord;
|
||||
import com.google.gerrit.reviewdb.client.Account;
|
||||
@@ -242,9 +245,28 @@ public class ChangeControl {
|
||||
&& getRefControl().canUpload(); // as long as you can upload too
|
||||
}
|
||||
|
||||
/** All available label types for this project. */
|
||||
/** All available label types for this change. */
|
||||
public LabelTypes getLabelTypes() {
|
||||
return getProjectControl().getLabelTypes();
|
||||
String destBranch = getChange().getDest().get();
|
||||
List<LabelType> all = getProjectControl().getLabelTypes().getLabelTypes();
|
||||
|
||||
List<LabelType> r = Lists.newArrayListWithCapacity(all.size());
|
||||
for (LabelType l : all) {
|
||||
List<String> refs = l.getRefPatterns();
|
||||
if (refs == null) {
|
||||
r.add(l);
|
||||
} else {
|
||||
for (String refPattern : refs) {
|
||||
if (RefConfigSection.isValid(refPattern)
|
||||
&& match(destBranch, refPattern)) {
|
||||
r.add(l);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new LabelTypes(r);
|
||||
}
|
||||
|
||||
/** All value ranges of any allowed label permission. */
|
||||
@@ -403,6 +425,11 @@ public class ChangeControl {
|
||||
return resultsToSubmitRecord(evaluator.getSubmitRule(), results);
|
||||
}
|
||||
|
||||
private boolean match(String destBranch, String refPattern) {
|
||||
return RefPatternMatcher.getMatcher(refPattern).match(destBranch,
|
||||
this.getRefControl().getCurrentUser().getUserName());
|
||||
}
|
||||
|
||||
private List<SubmitRecord> cannotSubmitDraft(ReviewDb db, PatchSet patchSet,
|
||||
ChangeData cd) {
|
||||
try {
|
||||
|
@@ -16,9 +16,7 @@ package gerrit;
|
||||
|
||||
import com.google.gerrit.common.data.LabelType;
|
||||
import com.google.gerrit.common.data.LabelValue;
|
||||
import com.google.gerrit.rules.PrologEnvironment;
|
||||
import com.google.gerrit.rules.StoredValues;
|
||||
import com.google.gerrit.server.project.ProjectState;
|
||||
|
||||
import com.googlecode.prolog_cafe.lang.IntegerTerm;
|
||||
import com.googlecode.prolog_cafe.lang.ListTerm;
|
||||
@@ -55,14 +53,8 @@ class PRED_get_legacy_label_types_1 extends Predicate.P1 {
|
||||
public Operation exec(Prolog engine) throws PrologException {
|
||||
engine.setB0();
|
||||
Term a1 = arg1.dereference();
|
||||
|
||||
PrologEnvironment env = (PrologEnvironment) engine.control;
|
||||
ProjectState state = env.getArgs().getProjectCache()
|
||||
.get(StoredValues.CHANGE.get(engine).getDest().getParentKey());
|
||||
if (state == null) {
|
||||
return engine.fail();
|
||||
}
|
||||
List<LabelType> list = state.getLabelTypes().getLabelTypes();
|
||||
List<LabelType> list =
|
||||
StoredValues.CHANGE_CONTROL.get(engine).getLabelTypes().getLabelTypes();
|
||||
Term head = Prolog.Nil;
|
||||
for (int idx = list.size() - 1; 0 <= idx; idx--) {
|
||||
head = new ListTerm(export(list.get(idx)), head);
|
||||
|
Reference in New Issue
Block a user