Add REST endpoint to add new label definitions
Bug: Issue 11522 Signed-off-by: Edwin Kempin <ekempin@google.com> Change-Id: I09b8642d266feeeef0c5ae2bdeb106615e4f5bfe
This commit is contained in:
@@ -3139,6 +3139,65 @@ returned that describes the label.
|
|||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
[[create-label]]
|
||||||
|
=== Create Label
|
||||||
|
--
|
||||||
|
'PUT /projects/link:#project-name[\{project-name\}]/labels/link:#label-name[\{label-name\}]'
|
||||||
|
--
|
||||||
|
|
||||||
|
Creates a new label definition in this project.
|
||||||
|
|
||||||
|
The calling user must have write access to the `refs/meta/config` branch of the
|
||||||
|
project.
|
||||||
|
|
||||||
|
If a label with this name is already defined in this project, this label
|
||||||
|
definition is updated (see link:#set-label[Set Label]).
|
||||||
|
|
||||||
|
.Request
|
||||||
|
----
|
||||||
|
PUT /projects/My-Project/labels/Foo HTTP/1.0
|
||||||
|
Content-Type: application/json; charset=UTF-8
|
||||||
|
|
||||||
|
{
|
||||||
|
"commit_message": "Create Foo Label",
|
||||||
|
"values": {
|
||||||
|
" 0": "No score",
|
||||||
|
"-1": "I would prefer this is not merged as is",
|
||||||
|
"-2": "This shall not be merged",
|
||||||
|
"+1": "Looks good to me, but someone else must approve",
|
||||||
|
"+2": "Looks good to me, approved"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
As response a link:#label-definition-info[LabelDefinitionInfo] entity is
|
||||||
|
returned that describes the created label.
|
||||||
|
|
||||||
|
.Response
|
||||||
|
----
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Content-Disposition: attachment
|
||||||
|
Content-Type: application/json; charset=UTF-8
|
||||||
|
|
||||||
|
)]}'
|
||||||
|
{
|
||||||
|
"name": "Foo",
|
||||||
|
"project_name": "My-Project",
|
||||||
|
"function": "MaxWithBlock",
|
||||||
|
"values": {
|
||||||
|
" 0": "No score",
|
||||||
|
"-1": "I would prefer this is not merged as is",
|
||||||
|
"-2": "This shall not be merged",
|
||||||
|
"+1": "Looks good to me, but someone else must approve",
|
||||||
|
"+2": "Looks good to me, approved"
|
||||||
|
},
|
||||||
|
"default_value": 0,
|
||||||
|
"can_override": true,
|
||||||
|
"copy_all_scores_if_no_change": true,
|
||||||
|
"allow_post_submit": true
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
[[set-label]]
|
[[set-label]]
|
||||||
=== Set Label
|
=== Set Label
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ import com.google.gerrit.extensions.restapi.NotImplementedException;
|
|||||||
import com.google.gerrit.extensions.restapi.RestApiException;
|
import com.google.gerrit.extensions.restapi.RestApiException;
|
||||||
|
|
||||||
public interface LabelApi {
|
public interface LabelApi {
|
||||||
|
LabelApi create(LabelDefinitionInput input) throws RestApiException;
|
||||||
|
|
||||||
LabelDefinitionInfo get() throws RestApiException;
|
LabelDefinitionInfo get() throws RestApiException;
|
||||||
|
|
||||||
LabelDefinitionInfo update(LabelDefinitionInput input) throws RestApiException;
|
LabelDefinitionInfo update(LabelDefinitionInput input) throws RestApiException;
|
||||||
@@ -29,6 +31,11 @@ public interface LabelApi {
|
|||||||
* interface.
|
* interface.
|
||||||
*/
|
*/
|
||||||
class NotImplemented implements LabelApi {
|
class NotImplemented implements LabelApi {
|
||||||
|
@Override
|
||||||
|
public LabelApi create(LabelDefinitionInput input) throws RestApiException {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LabelDefinitionInfo get() throws RestApiException {
|
public LabelDefinitionInfo get() throws RestApiException {
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
|
|||||||
@@ -19,33 +19,70 @@ import static com.google.gerrit.server.api.ApiUtil.asRestApiException;
|
|||||||
import com.google.gerrit.extensions.api.projects.LabelApi;
|
import com.google.gerrit.extensions.api.projects.LabelApi;
|
||||||
import com.google.gerrit.extensions.common.LabelDefinitionInfo;
|
import com.google.gerrit.extensions.common.LabelDefinitionInfo;
|
||||||
import com.google.gerrit.extensions.common.LabelDefinitionInput;
|
import com.google.gerrit.extensions.common.LabelDefinitionInput;
|
||||||
|
import com.google.gerrit.extensions.restapi.IdString;
|
||||||
import com.google.gerrit.extensions.restapi.RestApiException;
|
import com.google.gerrit.extensions.restapi.RestApiException;
|
||||||
|
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||||
import com.google.gerrit.server.project.LabelResource;
|
import com.google.gerrit.server.project.LabelResource;
|
||||||
|
import com.google.gerrit.server.project.ProjectCache;
|
||||||
|
import com.google.gerrit.server.project.ProjectResource;
|
||||||
|
import com.google.gerrit.server.restapi.project.CreateLabel;
|
||||||
import com.google.gerrit.server.restapi.project.GetLabel;
|
import com.google.gerrit.server.restapi.project.GetLabel;
|
||||||
|
import com.google.gerrit.server.restapi.project.LabelsCollection;
|
||||||
import com.google.gerrit.server.restapi.project.SetLabel;
|
import com.google.gerrit.server.restapi.project.SetLabel;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.assistedinject.Assisted;
|
import com.google.inject.assistedinject.Assisted;
|
||||||
|
|
||||||
public class LabelApiImpl implements LabelApi {
|
public class LabelApiImpl implements LabelApi {
|
||||||
interface Factory {
|
interface Factory {
|
||||||
LabelApiImpl create(LabelResource rsrc);
|
LabelApiImpl create(ProjectResource project, String label);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final LabelsCollection labels;
|
||||||
|
private final CreateLabel createLabel;
|
||||||
private final GetLabel getLabel;
|
private final GetLabel getLabel;
|
||||||
private final SetLabel setLabel;
|
private final SetLabel setLabel;
|
||||||
private final LabelResource rsrc;
|
private final ProjectCache projectCache;
|
||||||
|
private final String label;
|
||||||
|
|
||||||
|
private ProjectResource project;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
LabelApiImpl(GetLabel getLabel, SetLabel setLabel, @Assisted LabelResource rsrc) {
|
LabelApiImpl(
|
||||||
|
LabelsCollection labels,
|
||||||
|
CreateLabel createLabel,
|
||||||
|
GetLabel getLabel,
|
||||||
|
SetLabel setLabel,
|
||||||
|
ProjectCache projectCache,
|
||||||
|
@Assisted ProjectResource project,
|
||||||
|
@Assisted String label) {
|
||||||
|
this.labels = labels;
|
||||||
|
this.createLabel = createLabel;
|
||||||
this.getLabel = getLabel;
|
this.getLabel = getLabel;
|
||||||
this.setLabel = setLabel;
|
this.setLabel = setLabel;
|
||||||
this.rsrc = rsrc;
|
this.projectCache = projectCache;
|
||||||
|
this.project = project;
|
||||||
|
this.label = label;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LabelApi create(LabelDefinitionInput input) throws RestApiException {
|
||||||
|
try {
|
||||||
|
createLabel.apply(project, IdString.fromDecoded(label), input);
|
||||||
|
|
||||||
|
// recreate project resource because project state was updated by creating the new label and
|
||||||
|
// needs to be reloaded
|
||||||
|
project =
|
||||||
|
new ProjectResource(projectCache.checkedGet(project.getNameKey()), project.getUser());
|
||||||
|
return this;
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw asRestApiException("Cannot create branch", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LabelDefinitionInfo get() throws RestApiException {
|
public LabelDefinitionInfo get() throws RestApiException {
|
||||||
try {
|
try {
|
||||||
return getLabel.apply(rsrc).value();
|
return getLabel.apply(resource()).value();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw asRestApiException("Cannot get label", e);
|
throw asRestApiException("Cannot get label", e);
|
||||||
}
|
}
|
||||||
@@ -54,9 +91,13 @@ public class LabelApiImpl implements LabelApi {
|
|||||||
@Override
|
@Override
|
||||||
public LabelDefinitionInfo update(LabelDefinitionInput input) throws RestApiException {
|
public LabelDefinitionInfo update(LabelDefinitionInput input) throws RestApiException {
|
||||||
try {
|
try {
|
||||||
return setLabel.apply(rsrc, input).value();
|
return setLabel.apply(resource(), input).value();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw asRestApiException("Cannot update label", e);
|
throw asRestApiException("Cannot update label", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private LabelResource resource() throws RestApiException, PermissionBackendException {
|
||||||
|
return labels.parse(project, IdString.fromDecoded(label));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,7 +73,6 @@ import com.google.gerrit.server.restapi.project.GetHead;
|
|||||||
import com.google.gerrit.server.restapi.project.GetParent;
|
import com.google.gerrit.server.restapi.project.GetParent;
|
||||||
import com.google.gerrit.server.restapi.project.Index;
|
import com.google.gerrit.server.restapi.project.Index;
|
||||||
import com.google.gerrit.server.restapi.project.IndexChanges;
|
import com.google.gerrit.server.restapi.project.IndexChanges;
|
||||||
import com.google.gerrit.server.restapi.project.LabelsCollection;
|
|
||||||
import com.google.gerrit.server.restapi.project.ListBranches;
|
import com.google.gerrit.server.restapi.project.ListBranches;
|
||||||
import com.google.gerrit.server.restapi.project.ListDashboards;
|
import com.google.gerrit.server.restapi.project.ListDashboards;
|
||||||
import com.google.gerrit.server.restapi.project.ListLabels;
|
import com.google.gerrit.server.restapi.project.ListLabels;
|
||||||
@@ -132,7 +131,6 @@ public class ProjectApiImpl implements ProjectApi {
|
|||||||
private final Index index;
|
private final Index index;
|
||||||
private final IndexChanges indexChanges;
|
private final IndexChanges indexChanges;
|
||||||
private final Provider<ListLabels> listLabels;
|
private final Provider<ListLabels> listLabels;
|
||||||
private final LabelsCollection labels;
|
|
||||||
private final LabelApiImpl.Factory labelApi;
|
private final LabelApiImpl.Factory labelApi;
|
||||||
|
|
||||||
@AssistedInject
|
@AssistedInject
|
||||||
@@ -171,7 +169,6 @@ public class ProjectApiImpl implements ProjectApi {
|
|||||||
IndexChanges indexChanges,
|
IndexChanges indexChanges,
|
||||||
Provider<ListLabels> listLabels,
|
Provider<ListLabels> listLabels,
|
||||||
LabelApiImpl.Factory labelApi,
|
LabelApiImpl.Factory labelApi,
|
||||||
LabelsCollection labels,
|
|
||||||
@Assisted ProjectResource project) {
|
@Assisted ProjectResource project) {
|
||||||
this(
|
this(
|
||||||
permissionBackend,
|
permissionBackend,
|
||||||
@@ -209,7 +206,6 @@ public class ProjectApiImpl implements ProjectApi {
|
|||||||
indexChanges,
|
indexChanges,
|
||||||
listLabels,
|
listLabels,
|
||||||
labelApi,
|
labelApi,
|
||||||
labels,
|
|
||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,7 +245,6 @@ public class ProjectApiImpl implements ProjectApi {
|
|||||||
IndexChanges indexChanges,
|
IndexChanges indexChanges,
|
||||||
Provider<ListLabels> listLabels,
|
Provider<ListLabels> listLabels,
|
||||||
LabelApiImpl.Factory labelApi,
|
LabelApiImpl.Factory labelApi,
|
||||||
LabelsCollection labels,
|
|
||||||
@Assisted String name) {
|
@Assisted String name) {
|
||||||
this(
|
this(
|
||||||
permissionBackend,
|
permissionBackend,
|
||||||
@@ -287,7 +282,6 @@ public class ProjectApiImpl implements ProjectApi {
|
|||||||
indexChanges,
|
indexChanges,
|
||||||
listLabels,
|
listLabels,
|
||||||
labelApi,
|
labelApi,
|
||||||
labels,
|
|
||||||
name);
|
name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,7 +321,6 @@ public class ProjectApiImpl implements ProjectApi {
|
|||||||
IndexChanges indexChanges,
|
IndexChanges indexChanges,
|
||||||
Provider<ListLabels> listLabels,
|
Provider<ListLabels> listLabels,
|
||||||
LabelApiImpl.Factory labelApi,
|
LabelApiImpl.Factory labelApi,
|
||||||
LabelsCollection labels,
|
|
||||||
String name) {
|
String name) {
|
||||||
this.permissionBackend = permissionBackend;
|
this.permissionBackend = permissionBackend;
|
||||||
this.createProject = createProject;
|
this.createProject = createProject;
|
||||||
@@ -365,7 +358,6 @@ public class ProjectApiImpl implements ProjectApi {
|
|||||||
this.indexChanges = indexChanges;
|
this.indexChanges = indexChanges;
|
||||||
this.listLabels = listLabels;
|
this.listLabels = listLabels;
|
||||||
this.labelApi = labelApi;
|
this.labelApi = labelApi;
|
||||||
this.labels = labels;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -715,7 +707,7 @@ public class ProjectApiImpl implements ProjectApi {
|
|||||||
@Override
|
@Override
|
||||||
public LabelApi label(String labelName) throws RestApiException {
|
public LabelApi label(String labelName) throws RestApiException {
|
||||||
try {
|
try {
|
||||||
return labelApi.create(labels.parse(checkExists(), IdString.fromDecoded(labelName)));
|
return labelApi.create(checkExists(), labelName);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw asRestApiException("Cannot parse label", e);
|
throw asRestApiException("Cannot parse label", e);
|
||||||
}
|
}
|
||||||
|
|||||||
172
java/com/google/gerrit/server/restapi/project/CreateLabel.java
Normal file
172
java/com/google/gerrit/server/restapi/project/CreateLabel.java
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
// 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.restapi.project;
|
||||||
|
|
||||||
|
import com.google.common.base.Strings;
|
||||||
|
import com.google.gerrit.common.data.LabelFunction;
|
||||||
|
import com.google.gerrit.common.data.LabelType;
|
||||||
|
import com.google.gerrit.common.data.LabelValue;
|
||||||
|
import com.google.gerrit.extensions.common.LabelDefinitionInfo;
|
||||||
|
import com.google.gerrit.extensions.common.LabelDefinitionInput;
|
||||||
|
import com.google.gerrit.extensions.restapi.AuthException;
|
||||||
|
import com.google.gerrit.extensions.restapi.BadRequestException;
|
||||||
|
import com.google.gerrit.extensions.restapi.IdString;
|
||||||
|
import com.google.gerrit.extensions.restapi.ResourceConflictException;
|
||||||
|
import com.google.gerrit.extensions.restapi.Response;
|
||||||
|
import com.google.gerrit.extensions.restapi.RestCollectionCreateView;
|
||||||
|
import com.google.gerrit.server.git.meta.MetaDataUpdate;
|
||||||
|
import com.google.gerrit.server.permissions.PermissionBackend;
|
||||||
|
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||||
|
import com.google.gerrit.server.permissions.ProjectPermission;
|
||||||
|
import com.google.gerrit.server.project.LabelDefinitionJson;
|
||||||
|
import com.google.gerrit.server.project.LabelResource;
|
||||||
|
import com.google.gerrit.server.project.ProjectCache;
|
||||||
|
import com.google.gerrit.server.project.ProjectConfig;
|
||||||
|
import com.google.gerrit.server.project.ProjectResource;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Singleton;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
import org.eclipse.jgit.errors.ConfigInvalidException;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
public class CreateLabel
|
||||||
|
implements RestCollectionCreateView<ProjectResource, LabelResource, LabelDefinitionInput> {
|
||||||
|
private final PermissionBackend permissionBackend;
|
||||||
|
private final MetaDataUpdate.User updateFactory;
|
||||||
|
private final ProjectConfig.Factory projectConfigFactory;
|
||||||
|
private final ProjectCache projectCache;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public CreateLabel(
|
||||||
|
PermissionBackend permissionBackend,
|
||||||
|
MetaDataUpdate.User updateFactory,
|
||||||
|
ProjectConfig.Factory projectConfigFactory,
|
||||||
|
ProjectCache projectCache) {
|
||||||
|
this.permissionBackend = permissionBackend;
|
||||||
|
this.updateFactory = updateFactory;
|
||||||
|
this.projectConfigFactory = projectConfigFactory;
|
||||||
|
this.projectCache = projectCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response<LabelDefinitionInfo> apply(
|
||||||
|
ProjectResource rsrc, IdString id, LabelDefinitionInput input)
|
||||||
|
throws AuthException, BadRequestException, ResourceConflictException,
|
||||||
|
PermissionBackendException, IOException, ConfigInvalidException {
|
||||||
|
permissionBackend
|
||||||
|
.currentUser()
|
||||||
|
.project(rsrc.getNameKey())
|
||||||
|
.check(ProjectPermission.WRITE_CONFIG);
|
||||||
|
|
||||||
|
if (input == null) {
|
||||||
|
input = new LabelDefinitionInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.name != null && !input.name.equals(id.get())) {
|
||||||
|
throw new BadRequestException("name in input must match name in URL");
|
||||||
|
}
|
||||||
|
|
||||||
|
try (MetaDataUpdate md = updateFactory.create(rsrc.getNameKey())) {
|
||||||
|
ProjectConfig config = projectConfigFactory.read(md);
|
||||||
|
|
||||||
|
if (config.getLabelSections().containsKey(id.get())) {
|
||||||
|
throw new ResourceConflictException("label " + id.get() + " already exists");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.values == null || input.values.isEmpty()) {
|
||||||
|
throw new BadRequestException("values are required");
|
||||||
|
}
|
||||||
|
|
||||||
|
List<LabelValue> values = LabelDefinitionInputParser.parseValues(input.values);
|
||||||
|
|
||||||
|
LabelType labelType;
|
||||||
|
try {
|
||||||
|
labelType = new LabelType(id.get(), values);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw new BadRequestException("invalid name: " + id.get(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.function != null && !input.function.trim().isEmpty()) {
|
||||||
|
labelType.setFunction(LabelDefinitionInputParser.parseFunction(input.function));
|
||||||
|
} else {
|
||||||
|
labelType.setFunction(LabelFunction.MAX_WITH_BLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.defaultValue != null) {
|
||||||
|
labelType.setDefaultValue(
|
||||||
|
LabelDefinitionInputParser.parseDefaultValue(labelType, input.defaultValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.branches != null) {
|
||||||
|
labelType.setRefPatterns(LabelDefinitionInputParser.parseBranches(input.branches));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.canOverride != null) {
|
||||||
|
labelType.setCanOverride(input.canOverride);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.copyAnyScore != null) {
|
||||||
|
labelType.setCopyAnyScore(input.copyAnyScore);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.copyMinScore != null) {
|
||||||
|
labelType.setCopyMinScore(input.copyMinScore);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.copyMaxScore != null) {
|
||||||
|
labelType.setCopyMaxScore(input.copyMaxScore);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.copyAllScoresIfNoChange != null) {
|
||||||
|
labelType.setCopyAllScoresIfNoChange(input.copyAllScoresIfNoChange);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.copyAllScoresIfNoCodeChange != null) {
|
||||||
|
labelType.setCopyAllScoresIfNoCodeChange(input.copyAllScoresIfNoCodeChange);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.copyAllScoresOnTrivialRebase != null) {
|
||||||
|
labelType.setCopyAllScoresOnTrivialRebase(input.copyAllScoresOnTrivialRebase);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.copyAllScoresOnMergeFirstParentUpdate != null) {
|
||||||
|
labelType.setCopyAllScoresOnMergeFirstParentUpdate(
|
||||||
|
input.copyAllScoresOnMergeFirstParentUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.allowPostSubmit != null) {
|
||||||
|
labelType.setAllowPostSubmit(input.allowPostSubmit);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.ignoreSelfApproval != null) {
|
||||||
|
labelType.setIgnoreSelfApproval(input.ignoreSelfApproval);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.commitMessage != null) {
|
||||||
|
md.setMessage(Strings.emptyToNull(input.commitMessage.trim()));
|
||||||
|
} else {
|
||||||
|
md.setMessage("Update label");
|
||||||
|
}
|
||||||
|
|
||||||
|
config.getLabelSections().put(labelType.getName(), labelType);
|
||||||
|
config.commit(md);
|
||||||
|
|
||||||
|
projectCache.evict(rsrc.getProjectState().getProject());
|
||||||
|
|
||||||
|
return Response.created(LabelDefinitionJson.format(rsrc.getNameKey(), labelType));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
// 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.restapi.project;
|
||||||
|
|
||||||
|
import com.google.common.primitives.Shorts;
|
||||||
|
import com.google.gerrit.common.data.LabelFunction;
|
||||||
|
import com.google.gerrit.common.data.LabelType;
|
||||||
|
import com.google.gerrit.common.data.LabelValue;
|
||||||
|
import com.google.gerrit.common.data.PermissionRule;
|
||||||
|
import com.google.gerrit.entities.RefNames;
|
||||||
|
import com.google.gerrit.exceptions.InvalidNameException;
|
||||||
|
import com.google.gerrit.extensions.restapi.BadRequestException;
|
||||||
|
import com.google.gerrit.server.project.RefPattern;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class LabelDefinitionInputParser {
|
||||||
|
public static LabelFunction parseFunction(String functionString) throws BadRequestException {
|
||||||
|
Optional<LabelFunction> function = LabelFunction.parse(functionString.trim());
|
||||||
|
return function.orElseThrow(
|
||||||
|
() -> new BadRequestException("unknown function: " + functionString));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<LabelValue> parseValues(Map<String, String> values)
|
||||||
|
throws BadRequestException {
|
||||||
|
List<LabelValue> valueList = new ArrayList<>();
|
||||||
|
for (Entry<String, String> e : values.entrySet()) {
|
||||||
|
short value;
|
||||||
|
try {
|
||||||
|
value = Shorts.checkedCast(PermissionRule.parseInt(e.getKey().trim()));
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
throw new BadRequestException("invalid value: " + e.getKey(), ex);
|
||||||
|
}
|
||||||
|
String valueDescription = e.getValue().trim();
|
||||||
|
if (valueDescription.isEmpty()) {
|
||||||
|
throw new BadRequestException("description for value '" + e.getKey() + "' cannot be empty");
|
||||||
|
}
|
||||||
|
valueList.add(new LabelValue(value, valueDescription));
|
||||||
|
}
|
||||||
|
return valueList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static short parseDefaultValue(LabelType labelType, short defaultValue)
|
||||||
|
throws BadRequestException {
|
||||||
|
if (labelType.getValue(defaultValue) == null) {
|
||||||
|
throw new BadRequestException("invalid default value: " + defaultValue);
|
||||||
|
}
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<String> parseBranches(List<String> branches) throws BadRequestException {
|
||||||
|
List<String> validBranches = new ArrayList<>();
|
||||||
|
for (String branch : branches) {
|
||||||
|
String newBranch = branch.trim();
|
||||||
|
if (newBranch.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!RefPattern.isRE(newBranch) && !newBranch.startsWith(RefNames.REFS)) {
|
||||||
|
newBranch = RefNames.REFS_HEADS + newBranch;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
RefPattern.validate(newBranch);
|
||||||
|
} catch (InvalidNameException e) {
|
||||||
|
throw new BadRequestException("invalid branch: " + branch, e);
|
||||||
|
}
|
||||||
|
validBranches.add(newBranch);
|
||||||
|
}
|
||||||
|
return validBranches;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LabelDefinitionInputParser() {}
|
||||||
|
}
|
||||||
@@ -68,6 +68,7 @@ public class Module extends RestApiModule {
|
|||||||
get(CHILD_PROJECT_KIND).to(GetChildProject.class);
|
get(CHILD_PROJECT_KIND).to(GetChildProject.class);
|
||||||
|
|
||||||
child(PROJECT_KIND, "labels").to(LabelsCollection.class);
|
child(PROJECT_KIND, "labels").to(LabelsCollection.class);
|
||||||
|
create(LABEL_KIND).to(CreateLabel.class);
|
||||||
get(LABEL_KIND).to(GetLabel.class);
|
get(LABEL_KIND).to(GetLabel.class);
|
||||||
put(LABEL_KIND).to(SetLabel.class);
|
put(LABEL_KIND).to(SetLabel.class);
|
||||||
|
|
||||||
|
|||||||
@@ -15,13 +15,7 @@
|
|||||||
package com.google.gerrit.server.restapi.project;
|
package com.google.gerrit.server.restapi.project;
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.primitives.Shorts;
|
|
||||||
import com.google.gerrit.common.data.LabelFunction;
|
|
||||||
import com.google.gerrit.common.data.LabelType;
|
import com.google.gerrit.common.data.LabelType;
|
||||||
import com.google.gerrit.common.data.LabelValue;
|
|
||||||
import com.google.gerrit.common.data.PermissionRule;
|
|
||||||
import com.google.gerrit.entities.RefNames;
|
|
||||||
import com.google.gerrit.exceptions.InvalidNameException;
|
|
||||||
import com.google.gerrit.extensions.common.LabelDefinitionInfo;
|
import com.google.gerrit.extensions.common.LabelDefinitionInfo;
|
||||||
import com.google.gerrit.extensions.common.LabelDefinitionInput;
|
import com.google.gerrit.extensions.common.LabelDefinitionInput;
|
||||||
import com.google.gerrit.extensions.restapi.AuthException;
|
import com.google.gerrit.extensions.restapi.AuthException;
|
||||||
@@ -37,14 +31,9 @@ import com.google.gerrit.server.project.LabelDefinitionJson;
|
|||||||
import com.google.gerrit.server.project.LabelResource;
|
import com.google.gerrit.server.project.LabelResource;
|
||||||
import com.google.gerrit.server.project.ProjectCache;
|
import com.google.gerrit.server.project.ProjectCache;
|
||||||
import com.google.gerrit.server.project.ProjectConfig;
|
import com.google.gerrit.server.project.ProjectConfig;
|
||||||
import com.google.gerrit.server.project.RefPattern;
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.Optional;
|
|
||||||
import org.eclipse.jgit.errors.ConfigInvalidException;
|
import org.eclipse.jgit.errors.ConfigInvalidException;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@@ -106,15 +95,10 @@ public class SetLabel implements RestModifyView<LabelResource, LabelDefinitionIn
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (input.function != null) {
|
if (input.function != null) {
|
||||||
String newFunctionName = input.function.trim();
|
if (input.function.trim().isEmpty()) {
|
||||||
if (newFunctionName.isEmpty()) {
|
|
||||||
throw new BadRequestException("function cannot be empty");
|
throw new BadRequestException("function cannot be empty");
|
||||||
}
|
}
|
||||||
Optional<LabelFunction> newFunction = LabelFunction.parse(newFunctionName);
|
labelType.setFunction(LabelDefinitionInputParser.parseFunction(input.function));
|
||||||
if (!newFunction.isPresent()) {
|
|
||||||
throw new BadRequestException("unknown function: " + input.function);
|
|
||||||
}
|
|
||||||
labelType.setFunction(newFunction.get());
|
|
||||||
dirty = true;
|
dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,52 +106,18 @@ public class SetLabel implements RestModifyView<LabelResource, LabelDefinitionIn
|
|||||||
if (input.values.isEmpty()) {
|
if (input.values.isEmpty()) {
|
||||||
throw new BadRequestException("values cannot be empty");
|
throw new BadRequestException("values cannot be empty");
|
||||||
}
|
}
|
||||||
|
labelType.setValues(LabelDefinitionInputParser.parseValues(input.values));
|
||||||
List<LabelValue> newValues = new ArrayList<>();
|
|
||||||
for (Entry<String, String> e : input.values.entrySet()) {
|
|
||||||
short value;
|
|
||||||
try {
|
|
||||||
value = Shorts.checkedCast(PermissionRule.parseInt(e.getKey().trim()));
|
|
||||||
} catch (NumberFormatException ex) {
|
|
||||||
throw new BadRequestException("invalid value: " + e.getKey(), ex);
|
|
||||||
}
|
|
||||||
String valueDescription = e.getValue().trim();
|
|
||||||
if (valueDescription.isEmpty()) {
|
|
||||||
throw new BadRequestException(
|
|
||||||
"description for value '" + e.getKey() + "' cannot be empty");
|
|
||||||
}
|
|
||||||
newValues.add(new LabelValue(value, valueDescription));
|
|
||||||
}
|
|
||||||
labelType.setValues(newValues);
|
|
||||||
dirty = true;
|
dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (input.defaultValue != null) {
|
if (input.defaultValue != null) {
|
||||||
if (labelType.getValue(input.defaultValue) == null) {
|
labelType.setDefaultValue(
|
||||||
throw new BadRequestException("invalid default value: " + input.defaultValue);
|
LabelDefinitionInputParser.parseDefaultValue(labelType, input.defaultValue));
|
||||||
}
|
|
||||||
labelType.setDefaultValue(input.defaultValue);
|
|
||||||
dirty = true;
|
dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (input.branches != null) {
|
if (input.branches != null) {
|
||||||
List<String> newBranches = new ArrayList<>();
|
labelType.setRefPatterns(LabelDefinitionInputParser.parseBranches(input.branches));
|
||||||
for (String branch : input.branches) {
|
|
||||||
String newBranch = branch.trim();
|
|
||||||
if (newBranch.isEmpty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!RefPattern.isRE(newBranch) && !newBranch.startsWith(RefNames.REFS)) {
|
|
||||||
newBranch = RefNames.REFS_HEADS + newBranch;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
RefPattern.validate(newBranch);
|
|
||||||
} catch (InvalidNameException e) {
|
|
||||||
throw new BadRequestException("invalid branch: " + branch, e);
|
|
||||||
}
|
|
||||||
newBranches.add(newBranch);
|
|
||||||
}
|
|
||||||
labelType.setRefPatterns(newBranches);
|
|
||||||
dirty = true;
|
dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -83,7 +83,8 @@ public class ProjectsRestApiBindingsIT extends AbstractDaemonTest {
|
|||||||
// GET /projects/<project>/branches/<branch>/commits is not implemented
|
// GET /projects/<project>/branches/<branch>/commits is not implemented
|
||||||
.expectedResponseCode(SC_NOT_FOUND)
|
.expectedResponseCode(SC_NOT_FOUND)
|
||||||
.build(),
|
.build(),
|
||||||
RestCall.get("/projects/%s/dashboards"));
|
RestCall.get("/projects/%s/dashboards"),
|
||||||
|
RestCall.put("/projects/%s/labels/new-label"));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Child project REST endpoints to be tested, each URL contains placeholders for the parent
|
* Child project REST endpoints to be tested, each URL contains placeholders for the parent
|
||||||
|
|||||||
@@ -0,0 +1,567 @@
|
|||||||
|
// 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.acceptance.rest.project;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allow;
|
||||||
|
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
|
||||||
|
import static com.google.gerrit.testing.GerritJUnit.assertThrows;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.gerrit.acceptance.AbstractDaemonTest;
|
||||||
|
import com.google.gerrit.acceptance.NoHttpd;
|
||||||
|
import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
|
||||||
|
import com.google.gerrit.acceptance.testsuite.request.RequestScopeOperations;
|
||||||
|
import com.google.gerrit.common.data.LabelFunction;
|
||||||
|
import com.google.gerrit.common.data.Permission;
|
||||||
|
import com.google.gerrit.entities.RefNames;
|
||||||
|
import com.google.gerrit.extensions.common.LabelDefinitionInfo;
|
||||||
|
import com.google.gerrit.extensions.common.LabelDefinitionInput;
|
||||||
|
import com.google.gerrit.extensions.restapi.AuthException;
|
||||||
|
import com.google.gerrit.extensions.restapi.BadRequestException;
|
||||||
|
import com.google.gerrit.extensions.restapi.ResourceConflictException;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
@NoHttpd
|
||||||
|
public class CreateLabelIT extends AbstractDaemonTest {
|
||||||
|
@Inject private RequestScopeOperations requestScopeOperations;
|
||||||
|
@Inject private ProjectOperations projectOperations;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void notAllowed() throws Exception {
|
||||||
|
projectOperations
|
||||||
|
.project(project)
|
||||||
|
.forUpdate()
|
||||||
|
.add(allow(Permission.READ).ref(RefNames.REFS_CONFIG).group(REGISTERED_USERS))
|
||||||
|
.update();
|
||||||
|
|
||||||
|
requestScopeOperations.setApiUser(user.id());
|
||||||
|
AuthException thrown =
|
||||||
|
assertThrows(
|
||||||
|
AuthException.class,
|
||||||
|
() ->
|
||||||
|
gApi.projects()
|
||||||
|
.name(project.get())
|
||||||
|
.label("Foo-Review")
|
||||||
|
.create(new LabelDefinitionInput()));
|
||||||
|
assertThat(thrown).hasMessageThat().contains("write refs/meta/config not permitted");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void cannotCreateLabelIfNameDoesntMatch() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.name = "Foo";
|
||||||
|
|
||||||
|
BadRequestException thrown =
|
||||||
|
assertThrows(
|
||||||
|
BadRequestException.class,
|
||||||
|
() -> gApi.projects().name(project.get()).label("Bar").create(input));
|
||||||
|
assertThat(thrown).hasMessageThat().contains("name in input must match name in URL");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void cannotCreateLabelWithNameThatIsAlreadyInUse() throws Exception {
|
||||||
|
ResourceConflictException thrown =
|
||||||
|
assertThrows(
|
||||||
|
ResourceConflictException.class,
|
||||||
|
() ->
|
||||||
|
gApi.projects()
|
||||||
|
.name(allProjects.get())
|
||||||
|
.label("Code-Review")
|
||||||
|
.create(new LabelDefinitionInput()));
|
||||||
|
assertThat(thrown).hasMessageThat().contains("label Code-Review already exists");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void cannotCreateLabelWithInvalidName() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", "0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
|
||||||
|
BadRequestException thrown =
|
||||||
|
assertThrows(
|
||||||
|
BadRequestException.class,
|
||||||
|
() -> gApi.projects().name(project.get()).label("INVALID_NAME").create(input));
|
||||||
|
assertThat(thrown).hasMessageThat().contains("invalid name: INVALID_NAME");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void cannotCreateLabelWithoutValues() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
BadRequestException thrown =
|
||||||
|
assertThrows(
|
||||||
|
BadRequestException.class,
|
||||||
|
() -> gApi.projects().name(project.get()).label("Foo").create(input));
|
||||||
|
assertThat(thrown).hasMessageThat().contains("values are required");
|
||||||
|
|
||||||
|
input.values = ImmutableMap.of();
|
||||||
|
thrown =
|
||||||
|
assertThrows(
|
||||||
|
BadRequestException.class,
|
||||||
|
() -> gApi.projects().name(project.get()).label("Foo").create(input));
|
||||||
|
assertThat(thrown).hasMessageThat().contains("values are required");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void cannotCreateLabelWithInvalidValues() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("invalidValue", "description");
|
||||||
|
|
||||||
|
BadRequestException thrown =
|
||||||
|
assertThrows(
|
||||||
|
BadRequestException.class,
|
||||||
|
() -> gApi.projects().name(project.get()).label("Foo").create(input));
|
||||||
|
assertThat(thrown).hasMessageThat().contains("invalid value: invalidValue");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void cannotCreateLabelWithValuesThatHaveEmptyDescription() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "");
|
||||||
|
|
||||||
|
BadRequestException thrown =
|
||||||
|
assertThrows(
|
||||||
|
BadRequestException.class,
|
||||||
|
() -> gApi.projects().name(project.get()).label("Foo").create(input));
|
||||||
|
assertThat(thrown).hasMessageThat().contains("description for value '+1' cannot be empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void cannotCreateLabelWithInvalidDefaultValue() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", "0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
input.defaultValue = 5;
|
||||||
|
|
||||||
|
BadRequestException thrown =
|
||||||
|
assertThrows(
|
||||||
|
BadRequestException.class,
|
||||||
|
() -> gApi.projects().name(project.get()).label("Foo").create(input));
|
||||||
|
assertThat(thrown).hasMessageThat().contains("invalid default value: " + input.defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void cannotCreateLabelWithUnknownFunction() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", "0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
input.function = "UnknownFuction";
|
||||||
|
|
||||||
|
BadRequestException thrown =
|
||||||
|
assertThrows(
|
||||||
|
BadRequestException.class,
|
||||||
|
() -> gApi.projects().name(project.get()).label("Foo").create(input));
|
||||||
|
assertThat(thrown).hasMessageThat().contains("unknown function: " + input.function);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void cannotCreateLabelWithInvalidBranch() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", "0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
input.branches = ImmutableList.of("refs heads master");
|
||||||
|
|
||||||
|
BadRequestException thrown =
|
||||||
|
assertThrows(
|
||||||
|
BadRequestException.class,
|
||||||
|
() -> gApi.projects().name(project.get()).label("Foo").create(input));
|
||||||
|
assertThat(thrown).hasMessageThat().contains("invalid branch: refs heads master");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createWithNameAndValuesOnly() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
|
||||||
|
LabelDefinitionInfo createdLabel =
|
||||||
|
gApi.projects().name(project.get()).label("Foo").create(input).get();
|
||||||
|
|
||||||
|
assertThat(createdLabel.name).isEqualTo("Foo");
|
||||||
|
assertThat(createdLabel.projectName).isEqualTo(project.get());
|
||||||
|
assertThat(createdLabel.function).isEqualTo(LabelFunction.MAX_WITH_BLOCK.getFunctionName());
|
||||||
|
assertThat(createdLabel.values).containsExactlyEntriesIn(input.values);
|
||||||
|
assertThat(createdLabel.defaultValue).isEqualTo(0);
|
||||||
|
assertThat(createdLabel.branches).isNull();
|
||||||
|
assertThat(createdLabel.canOverride).isTrue();
|
||||||
|
assertThat(createdLabel.copyAnyScore).isNull();
|
||||||
|
assertThat(createdLabel.copyMinScore).isNull();
|
||||||
|
assertThat(createdLabel.copyMaxScore).isNull();
|
||||||
|
assertThat(createdLabel.copyAllScoresIfNoChange).isTrue();
|
||||||
|
assertThat(createdLabel.copyAllScoresIfNoCodeChange).isNull();
|
||||||
|
assertThat(createdLabel.copyAllScoresOnTrivialRebase).isNull();
|
||||||
|
assertThat(createdLabel.copyAllScoresOnMergeFirstParentUpdate).isNull();
|
||||||
|
assertThat(createdLabel.allowPostSubmit).isTrue();
|
||||||
|
assertThat(createdLabel.ignoreSelfApproval).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createWithFunction() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
input.function = LabelFunction.NO_OP.getFunctionName();
|
||||||
|
|
||||||
|
LabelDefinitionInfo createdLabel =
|
||||||
|
gApi.projects().name(project.get()).label("Foo").create(input).get();
|
||||||
|
|
||||||
|
assertThat(createdLabel.function).isEqualTo(LabelFunction.NO_OP.getFunctionName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void functionEmptyAfterTrim() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
input.function = " ";
|
||||||
|
|
||||||
|
LabelDefinitionInfo createdLabel =
|
||||||
|
gApi.projects().name(project.get()).label("Foo").create(input).get();
|
||||||
|
|
||||||
|
assertThat(createdLabel.function).isEqualTo(LabelFunction.MAX_WITH_BLOCK.getFunctionName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void valuesAndDescriptionsAreTrimmed() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
// Positive values can be specified as '<value>' or '+<value>'.
|
||||||
|
input.values =
|
||||||
|
ImmutableMap.of(
|
||||||
|
" 2 ",
|
||||||
|
" Looks Very Good ",
|
||||||
|
" +1 ",
|
||||||
|
" Looks Good ",
|
||||||
|
" 0 ",
|
||||||
|
" Don't Know ",
|
||||||
|
" -1 ",
|
||||||
|
" Looks Bad ",
|
||||||
|
" -2 ",
|
||||||
|
" Looks Very Bad ");
|
||||||
|
|
||||||
|
LabelDefinitionInfo createdLabel =
|
||||||
|
gApi.projects().name(project.get()).label("Foo").create(input).get();
|
||||||
|
assertThat(createdLabel.values)
|
||||||
|
.containsExactly(
|
||||||
|
"+2", "Looks Very Good",
|
||||||
|
"+1", "Looks Good",
|
||||||
|
" 0", "Don't Know",
|
||||||
|
"-1", "Looks Bad",
|
||||||
|
"-2", "Looks Very Bad");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createWithDefaultValue() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
input.defaultValue = 1;
|
||||||
|
|
||||||
|
LabelDefinitionInfo createdLabel =
|
||||||
|
gApi.projects().name(project.get()).label("Foo").create(input).get();
|
||||||
|
|
||||||
|
assertThat(createdLabel.defaultValue).isEqualTo(input.defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createWithBranches() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
// Branches can be full ref, ref pattern or regular expression.
|
||||||
|
input.branches =
|
||||||
|
ImmutableList.of("refs/heads/master", "refs/heads/foo/*", "^refs/heads/stable-.*");
|
||||||
|
|
||||||
|
LabelDefinitionInfo createdLabel =
|
||||||
|
gApi.projects().name(project.get()).label("Foo").create(input).get();
|
||||||
|
assertThat(createdLabel.branches).containsExactlyElementsIn(input.branches);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void branchesAreTrimmed() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
input.branches =
|
||||||
|
ImmutableList.of(" refs/heads/master ", " refs/heads/foo/* ", " ^refs/heads/stable-.* ");
|
||||||
|
|
||||||
|
LabelDefinitionInfo createdLabel =
|
||||||
|
gApi.projects().name(project.get()).label("Foo").create(input).get();
|
||||||
|
assertThat(createdLabel.branches)
|
||||||
|
.containsExactly("refs/heads/master", "refs/heads/foo/*", "^refs/heads/stable-.*");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void emptyBranchesAreIgnored() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
input.branches = ImmutableList.of("refs/heads/master", "", " ");
|
||||||
|
|
||||||
|
LabelDefinitionInfo createdLabel =
|
||||||
|
gApi.projects().name(project.get()).label("Foo").create(input).get();
|
||||||
|
assertThat(createdLabel.branches).containsExactly("refs/heads/master");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void branchesAreAutomaticallyPrefixedWithRefsHeads() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
input.branches = ImmutableList.of("master", "refs/meta/config");
|
||||||
|
|
||||||
|
LabelDefinitionInfo createdLabel =
|
||||||
|
gApi.projects().name(project.get()).label("Foo").create(input).get();
|
||||||
|
assertThat(createdLabel.branches).containsExactly("refs/heads/master", "refs/meta/config");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createWithCanOverride() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
input.canOverride = true;
|
||||||
|
|
||||||
|
LabelDefinitionInfo createdLabel =
|
||||||
|
gApi.projects().name(project.get()).label("foo").create(input).get();
|
||||||
|
assertThat(createdLabel.canOverride).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createWithoutCanOverride() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
input.canOverride = false;
|
||||||
|
|
||||||
|
LabelDefinitionInfo createdLabel =
|
||||||
|
gApi.projects().name(project.get()).label("foo").create(input).get();
|
||||||
|
assertThat(createdLabel.canOverride).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createWithCopyAnyScore() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
input.copyAnyScore = true;
|
||||||
|
|
||||||
|
LabelDefinitionInfo createdLabel =
|
||||||
|
gApi.projects().name(project.get()).label("foo").create(input).get();
|
||||||
|
assertThat(createdLabel.copyAnyScore).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createWithoutCopyAnyScore() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
input.copyAnyScore = false;
|
||||||
|
|
||||||
|
LabelDefinitionInfo createdLabel =
|
||||||
|
gApi.projects().name(project.get()).label("foo").create(input).get();
|
||||||
|
assertThat(createdLabel.copyAnyScore).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createWithCopyMinScore() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
input.copyMinScore = true;
|
||||||
|
|
||||||
|
LabelDefinitionInfo createdLabel =
|
||||||
|
gApi.projects().name(project.get()).label("foo").create(input).get();
|
||||||
|
assertThat(createdLabel.copyMinScore).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createWithoutCopyMinScore() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
input.copyMinScore = false;
|
||||||
|
|
||||||
|
LabelDefinitionInfo createdLabel =
|
||||||
|
gApi.projects().name(project.get()).label("foo").create(input).get();
|
||||||
|
assertThat(createdLabel.copyMinScore).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createWithCopyMaxScore() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
input.copyMaxScore = true;
|
||||||
|
|
||||||
|
LabelDefinitionInfo createdLabel =
|
||||||
|
gApi.projects().name(project.get()).label("foo").create(input).get();
|
||||||
|
assertThat(createdLabel.copyMaxScore).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createWithoutCopyMaxScore() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
input.copyMaxScore = false;
|
||||||
|
|
||||||
|
LabelDefinitionInfo createdLabel =
|
||||||
|
gApi.projects().name(project.get()).label("foo").create(input).get();
|
||||||
|
assertThat(createdLabel.copyMaxScore).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createWithCopyAllScoresIfNoChange() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
input.copyAllScoresIfNoChange = true;
|
||||||
|
|
||||||
|
LabelDefinitionInfo createdLabel =
|
||||||
|
gApi.projects().name(project.get()).label("foo").create(input).get();
|
||||||
|
assertThat(createdLabel.copyAllScoresIfNoChange).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createWithoutCopyAllScoresIfNoChange() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
input.copyAllScoresIfNoChange = false;
|
||||||
|
|
||||||
|
LabelDefinitionInfo createdLabel =
|
||||||
|
gApi.projects().name(project.get()).label("foo").create(input).get();
|
||||||
|
assertThat(createdLabel.copyAllScoresIfNoChange).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createWithCopyAllScoresIfNoCodeChange() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
input.copyAllScoresIfNoCodeChange = true;
|
||||||
|
|
||||||
|
LabelDefinitionInfo createdLabel =
|
||||||
|
gApi.projects().name(project.get()).label("foo").create(input).get();
|
||||||
|
assertThat(createdLabel.copyAllScoresIfNoCodeChange).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createWithoutCopyAllScoresIfNoCodeChange() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
input.copyAllScoresIfNoCodeChange = false;
|
||||||
|
|
||||||
|
LabelDefinitionInfo createdLabel =
|
||||||
|
gApi.projects().name(project.get()).label("foo").create(input).get();
|
||||||
|
assertThat(createdLabel.copyAllScoresIfNoCodeChange).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createWithCopyAllScoresOnTrivialRebase() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
input.copyAllScoresOnTrivialRebase = true;
|
||||||
|
|
||||||
|
LabelDefinitionInfo createdLabel =
|
||||||
|
gApi.projects().name(project.get()).label("foo").create(input).get();
|
||||||
|
assertThat(createdLabel.copyAllScoresOnTrivialRebase).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createWithoutCopyAllScoresOnTrivialRebase() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
input.copyAllScoresOnTrivialRebase = false;
|
||||||
|
|
||||||
|
LabelDefinitionInfo createdLabel =
|
||||||
|
gApi.projects().name(project.get()).label("foo").create(input).get();
|
||||||
|
assertThat(createdLabel.copyAllScoresOnTrivialRebase).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createWithCopyAllScoresOnMergeFirstParentUpdate() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
input.copyAllScoresOnMergeFirstParentUpdate = true;
|
||||||
|
|
||||||
|
LabelDefinitionInfo createdLabel =
|
||||||
|
gApi.projects().name(project.get()).label("foo").create(input).get();
|
||||||
|
assertThat(createdLabel.copyAllScoresOnMergeFirstParentUpdate).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createWithoutCopyAllScoresOnMergeFirstParentUpdate() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
input.copyAllScoresOnMergeFirstParentUpdate = false;
|
||||||
|
|
||||||
|
LabelDefinitionInfo createdLabel =
|
||||||
|
gApi.projects().name(project.get()).label("foo").create(input).get();
|
||||||
|
assertThat(createdLabel.copyAllScoresOnMergeFirstParentUpdate).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createWithAllowPostSubmit() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
input.allowPostSubmit = true;
|
||||||
|
|
||||||
|
LabelDefinitionInfo createdLabel =
|
||||||
|
gApi.projects().name(project.get()).label("foo").create(input).get();
|
||||||
|
assertThat(createdLabel.allowPostSubmit).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createWithoutAllowPostSubmit() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
input.allowPostSubmit = false;
|
||||||
|
|
||||||
|
LabelDefinitionInfo createdLabel =
|
||||||
|
gApi.projects().name(project.get()).label("foo").create(input).get();
|
||||||
|
assertThat(createdLabel.allowPostSubmit).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createWithIgnoreSelfApproval() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
input.ignoreSelfApproval = true;
|
||||||
|
|
||||||
|
LabelDefinitionInfo createdLabel =
|
||||||
|
gApi.projects().name(project.get()).label("foo").create(input).get();
|
||||||
|
assertThat(createdLabel.ignoreSelfApproval).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createWithoutIgnoreSelfApproval() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
input.ignoreSelfApproval = false;
|
||||||
|
|
||||||
|
LabelDefinitionInfo createdLabel =
|
||||||
|
gApi.projects().name(project.get()).label("foo").create(input).get();
|
||||||
|
assertThat(createdLabel.ignoreSelfApproval).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void defaultCommitMessage() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
gApi.projects().name(project.get()).label("Foo").create(input);
|
||||||
|
assertThat(projectOperations.project(project).getHead(RefNames.REFS_CONFIG).getShortMessage())
|
||||||
|
.isEqualTo("Update label");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void withCommitMessage() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
input.commitMessage = "Add Foo Label";
|
||||||
|
gApi.projects().name(project.get()).label("Foo").create(input);
|
||||||
|
assertThat(projectOperations.project(project).getHead(RefNames.REFS_CONFIG).getShortMessage())
|
||||||
|
.isEqualTo(input.commitMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void commitMessageIsTrimmed() throws Exception {
|
||||||
|
LabelDefinitionInput input = new LabelDefinitionInput();
|
||||||
|
input.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad");
|
||||||
|
input.commitMessage = " Add Foo Label ";
|
||||||
|
gApi.projects().name(project.get()).label("Foo").create(input);
|
||||||
|
assertThat(projectOperations.project(project).getHead(RefNames.REFS_CONFIG).getShortMessage())
|
||||||
|
.isEqualTo("Add Foo Label");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user