Add copyAnyScore configuration option to label.

This option, when enabled, copies all votes from previous
patch sets to new patch sets. This is useful for *very*
sticky approvals. Without this there is no way to allow
for Code-Review +1 and +2 votes and to have Code-Review
+1 votes be sticky.

Change-Id: Id9c3916c60063b96d1812e6ced6ac4c52db64d2b
This commit is contained in:
Eli Ribble 2019-10-09 01:44:47 -07:00
parent 5fc7a69f19
commit 99c48ed655
6 changed files with 56 additions and 1 deletions

View File

@ -262,6 +262,12 @@ the past and affect submission somehow.
Defaults to true.
[[label_copyAnyScore]]
=== `label.Label-Name.copyAnyScore`
If true, any score for the label is copied forward when a new patch
set is uploaded. Defaults to false.
[[label_copyMinScore]]
=== `label.Label-Name.copyMinScore`

View File

@ -34,6 +34,7 @@ public class LabelType {
public static final boolean DEF_COPY_ALL_SCORES_IF_NO_CODE_CHANGE = false;
public static final boolean DEF_COPY_ALL_SCORES_ON_TRIVIAL_REBASE = false;
public static final boolean DEF_COPY_ALL_SCORES_ON_MERGE_FIRST_PARENT_UPDATE = false;
public static final boolean DEF_COPY_ANY_SCORE = false;
public static final boolean DEF_COPY_MAX_SCORE = false;
public static final boolean DEF_COPY_MIN_SCORE = false;
public static final boolean DEF_IGNORE_SELF_APPROVAL = false;
@ -96,6 +97,7 @@ public class LabelType {
protected LabelFunction function;
protected boolean copyAnyScore;
protected boolean copyMinScore;
protected boolean copyMaxScore;
protected boolean copyAllScoresOnMergeFirstParentUpdate;
@ -139,6 +141,7 @@ public class LabelType {
setCopyAllScoresIfNoCodeChange(DEF_COPY_ALL_SCORES_IF_NO_CODE_CHANGE);
setCopyAllScoresOnTrivialRebase(DEF_COPY_ALL_SCORES_ON_TRIVIAL_REBASE);
setCopyAllScoresOnMergeFirstParentUpdate(DEF_COPY_ALL_SCORES_ON_MERGE_FIRST_PARENT_UPDATE);
setCopyAnyScore(DEF_COPY_ANY_SCORE);
setCopyMaxScore(DEF_COPY_MAX_SCORE);
setCopyMinScore(DEF_COPY_MIN_SCORE);
setAllowPostSubmit(DEF_ALLOW_POST_SUBMIT);
@ -229,6 +232,14 @@ public class LabelType {
this.defaultValue = defaultValue;
}
public boolean isCopyAnyScore() {
return copyAnyScore;
}
public void setCopyAnyScore(boolean copyAnyScore) {
this.copyAnyScore = copyAnyScore;
}
public boolean isCopyMinScore() {
return copyMinScore;
}

View File

@ -99,6 +99,8 @@ public class ApprovalInference {
} else if ((type.isCopyMinScore() && type.isMaxNegative(psa))
|| (type.isCopyMaxScore() && type.isMaxPositive(psa))) {
return true;
} else if (type.isCopyAnyScore()) {
return true;
}
switch (kind) {
case MERGE_FIRST_PARENT_UPDATE:

View File

@ -101,6 +101,7 @@ public class ProjectConfig extends VersionedMetaData implements ValidationError.
public static final String KEY_COPY_MIN_SCORE = "copyMinScore";
public static final String KEY_ALLOW_POST_SUBMIT = "allowPostSubmit";
public static final String KEY_IGNORE_SELF_APPROVAL = "ignoreSelfApproval";
public static final String KEY_COPY_ANY_SCORE = "copyAnyScore";
public static final String KEY_COPY_MAX_SCORE = "copyMaxScore";
public static final String KEY_COPY_ALL_SCORES_ON_MERGE_FIRST_PARENT_UPDATE =
"copyAllScoresOnMergeFirstParentUpdate";
@ -960,6 +961,8 @@ public class ProjectConfig extends VersionedMetaData implements ValidationError.
rc.getBoolean(LABEL, name, KEY_ALLOW_POST_SUBMIT, LabelType.DEF_ALLOW_POST_SUBMIT));
label.setIgnoreSelfApproval(
rc.getBoolean(LABEL, name, KEY_IGNORE_SELF_APPROVAL, LabelType.DEF_IGNORE_SELF_APPROVAL));
label.setCopyAnyScore(
rc.getBoolean(LABEL, name, KEY_COPY_ANY_SCORE, LabelType.DEF_COPY_ANY_SCORE));
label.setCopyMinScore(
rc.getBoolean(LABEL, name, KEY_COPY_MIN_SCORE, LabelType.DEF_COPY_MIN_SCORE));
label.setCopyMaxScore(
@ -1417,6 +1420,13 @@ public class ProjectConfig extends VersionedMetaData implements ValidationError.
KEY_IGNORE_SELF_APPROVAL,
label.ignoreSelfApproval(),
LabelType.DEF_IGNORE_SELF_APPROVAL);
setBooleanConfigKey(
rc,
LABEL,
name,
KEY_COPY_ANY_SCORE,
label.isCopyAnyScore(),
LabelType.DEF_COPY_ANY_SCORE);
setBooleanConfigKey(
rc,
LABEL,

View File

@ -118,6 +118,28 @@ public class StickyApprovalsIT extends AbstractDaemonTest {
EnumSet.of(REWORK, TRIVIAL_REBASE, NO_CODE_CHANGE, MERGE_FIRST_PARENT_UPDATE, NO_CHANGE));
}
@Test
public void stickyOnAnyScore() throws Exception {
try (ProjectConfigUpdate u = updateProject(project)) {
u.getConfig().getLabelSections().get("Code-Review").setCopyAnyScore(true);
u.save();
}
for (ChangeKind changeKind :
EnumSet.of(REWORK, TRIVIAL_REBASE, NO_CODE_CHANGE, MERGE_FIRST_PARENT_UPDATE, NO_CHANGE)) {
testRepo.reset(projectOperations.project(project).getHead("master"));
String changeId = createChange(changeKind);
vote(admin, changeId, 2, 1);
vote(user, changeId, 1, -1);
updateChange(changeId, changeKind);
ChangeInfo c = detailedChange(changeId);
assertVotes(c, admin, 2, 0, changeKind);
assertVotes(c, user, 1, 0, changeKind);
}
}
@Test
public void stickyOnMinScore() throws Exception {
try (ProjectConfigUpdate u = updateProject(project)) {

View File

@ -63,7 +63,10 @@ import org.junit.rules.TemporaryFolder;
public class ProjectConfigTest {
private static final String LABEL_SCORES_CONFIG =
" copyMinScore = "
" copyAnyScore = "
+ !LabelType.DEF_COPY_ANY_SCORE
+ "\n"
+ " copyMinScore = "
+ !LabelType.DEF_COPY_MIN_SCORE
+ "\n"
+ " copyMaxScore = "
@ -259,6 +262,7 @@ public class ProjectConfigTest {
ProjectConfig cfg = read(rev);
Map<String, LabelType> labels = cfg.getLabelSections();
LabelType type = labels.entrySet().iterator().next().getValue();
assertThat(type.isCopyAnyScore()).isNotEqualTo(LabelType.DEF_COPY_ANY_SCORE);
assertThat(type.isCopyMinScore()).isNotEqualTo(LabelType.DEF_COPY_MIN_SCORE);
assertThat(type.isCopyMaxScore()).isNotEqualTo(LabelType.DEF_COPY_MAX_SCORE);
assertThat(type.isCopyAllScoresOnMergeFirstParentUpdate())