Add REST endpoint to update the project configuration
By PUT on /projects/*/config it is now possible to update the configuration of a project. We already have REST endpoints to get and set the project description (GET and PUT on /projects/*/description), however on the ProjectInfoScreen we have a single save button to save both the project description and the project configuration settings. Triggering two calls in parallel with a callback group, one to update the project description and one to update the project configuration, is likely failing because both requests need to update the project.config file. If it happens in parallel one request will get a LOCK_FAILURE. Also it would be bad to create two commits for a single save action. This is why it makes sense to also allow to get and set the project description via the GetConfig and PutConfig REST endpoints. Change-Id: I2109264d75dd50d103e58e8a9e73492e2aa5807c Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
This commit is contained in:
parent
3e05f81f8c
commit
a23eb10619
@ -436,6 +436,7 @@ read access to `refs/meta/config`.
|
||||
)]}'
|
||||
{
|
||||
"kind": "gerritcodereview#project_config",
|
||||
"description": "demo project",
|
||||
"use_contributor_agreements": {
|
||||
"value": true,
|
||||
"configured_value": "TRUE",
|
||||
@ -467,6 +468,77 @@ read access to `refs/meta/config`.
|
||||
}
|
||||
----
|
||||
|
||||
[[set-config]]
|
||||
Set Config
|
||||
~~~~~~~~~~
|
||||
[verse]
|
||||
'PUT /projects/link:#project-name[\{project-name\}]/config'
|
||||
|
||||
Sets the configuration of a project.
|
||||
|
||||
The new configuration must be provided in the request body as a
|
||||
link:#config-input[ConfigInput] entity.
|
||||
|
||||
.Request
|
||||
----
|
||||
PUT /projects/myproject/config HTTP/1.0
|
||||
Content-Type: application/json;charset=UTF-8
|
||||
|
||||
{
|
||||
"description": "demo project",
|
||||
"use_contributor_agreements": "FALSE",
|
||||
"use_content_merge": "INHERIT",
|
||||
"use_signed_off_by": "INHERIT",
|
||||
"require_change_id": "TRUE",
|
||||
"max_object_size_limit": "10m",
|
||||
"submit_type": "REBASE_IF_NECESSARY",
|
||||
"state": "ACTIVE"
|
||||
}
|
||||
----
|
||||
|
||||
As response the new configuration is returned as a link:#config-info[
|
||||
ConfigInfo] entity.
|
||||
|
||||
.Response
|
||||
----
|
||||
HTTP/1.1 200 OK
|
||||
Content-Disposition: attachment
|
||||
Content-Type: application/json;charset=UTF-8
|
||||
|
||||
)]}'
|
||||
{
|
||||
"kind": "gerritcodereview#project_config",
|
||||
"use_contributor_agreements": {
|
||||
"value": false,
|
||||
"configured_value": "FALSE",
|
||||
"inherited_value": false
|
||||
},
|
||||
"use_content_merge": {
|
||||
"value": true,
|
||||
"configured_value": "INHERIT",
|
||||
"inherited_value": true
|
||||
},
|
||||
"use_signed_off_by": {
|
||||
"value": false,
|
||||
"configured_value": "INHERIT",
|
||||
"inherited_value": false
|
||||
},
|
||||
"require_change_id": {
|
||||
"value": true,
|
||||
"configured_value": "TRUE",
|
||||
"inherited_value": true
|
||||
},
|
||||
"max_object_size_limit": {
|
||||
"value": "10m",
|
||||
"configured_value": "10m",
|
||||
"inherited_value": "20m"
|
||||
},
|
||||
"submit_type": "REBASE_IF_NECESSARY",
|
||||
"state": "ACTIVE",
|
||||
"commentlinks": {}
|
||||
}
|
||||
----
|
||||
|
||||
[[run-gc]]
|
||||
Run GC
|
||||
~~~~~~
|
||||
@ -1074,6 +1146,8 @@ configuration.
|
||||
[options="header",width="50%",cols="1,^2,4"]
|
||||
|=========================================
|
||||
|Field Name ||Description
|
||||
|`description` |optional|
|
||||
The description of the project.
|
||||
|`use_contributor_agreements`|optional|
|
||||
link:#inherited-boolean-info[InheritedBooleanInfo] that tells whether
|
||||
authors must complete a contributor agreement on the site before
|
||||
@ -1115,6 +1189,57 @@ The theme that is configured for the project as a link:#theme-info[
|
||||
ThemeInfo] entity.
|
||||
|=========================================
|
||||
|
||||
[[config-input]]
|
||||
ConfigInput
|
||||
~~~~~~~~~~~
|
||||
The `ConfigInput` entity describes a new project configuration.
|
||||
|
||||
[options="header",width="50%",cols="1,^2,4"]
|
||||
|=========================================
|
||||
|Field Name ||Description
|
||||
|`description` |optional|
|
||||
The new description of the project. +
|
||||
If not set, the description is removed.
|
||||
|`use_contributor_agreements`|optional|
|
||||
Whether authors must complete a contributor agreement on the site
|
||||
before pushing any commits or changes to this project. +
|
||||
Can be `TRUE`, `FALSE` or `INHERIT`. +
|
||||
If not set, this setting is not updated.
|
||||
|`use_content_merge` |optional|
|
||||
Whether Gerrit will try to perform a 3-way merge of text file content
|
||||
when a file has been modified by both the destination branch and the
|
||||
change being submitted. This option only takes effect if submit type is
|
||||
not FAST_FORWARD_ONLY. +
|
||||
Can be `TRUE`, `FALSE` or `INHERIT`. +
|
||||
If not set, this setting is not updated.
|
||||
|`use_signed_off_by` |optional|
|
||||
Whether each change must contain a Signed-off-by line from either the
|
||||
author or the uploader in the commit message. +
|
||||
Can be `TRUE`, `FALSE` or `INHERIT`. +
|
||||
If not set, this setting is not updated.
|
||||
|`require_change_id` |optional|
|
||||
Whether a valid link:user-changeid.html[Change-Id] footer in any commit
|
||||
uploaded for review is required. This does not apply to commits pushed
|
||||
directly to a branch or tag. +
|
||||
Can be `TRUE`, `FALSE` or `INHERIT`. +
|
||||
If not set, this setting is not updated.
|
||||
|`max_object_size_limit` |optional|
|
||||
The link:config-gerrit.html#receive.maxObjectSizeLimit[max object size
|
||||
limit] of this project as a link:#max-object-size-limit-info[
|
||||
MaxObjectSizeLimitInfo] entity. +
|
||||
If set to `0`, the max object size limit is removed. +
|
||||
If not set, this setting is not updated.
|
||||
|`submit_type` |optional|
|
||||
The default submit type of the project, can be `MERGE_IF_NECESSARY`,
|
||||
`FAST_FORWARD_ONLY`, `REBASE_IF_NECESSARY`, `MERGE_ALWAYS` or
|
||||
`CHERRY_PICK`. +
|
||||
If not set, the submit type is not updated.
|
||||
|`state` |optional|
|
||||
The state of the project, can be `ACTIVE`, `READ_ONLY` or `HIDDEN`. +
|
||||
Not set if the project state is `ACTIVE`. +
|
||||
If not set, the project state is not updated.
|
||||
|=========================================
|
||||
|
||||
[[dashboard-info]]
|
||||
DashboardInfo
|
||||
~~~~~~~~~~~~~
|
||||
|
@ -29,4 +29,9 @@ public class ResourceConflictException extends RestApiException {
|
||||
public ResourceConflictException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/** @param msg message to return to the client describing the error. */
|
||||
public ResourceConflictException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,11 @@ public class ResourceNotFoundException extends RestApiException {
|
||||
super(id);
|
||||
}
|
||||
|
||||
/** @param id portion of the resource URI that does not exist. */
|
||||
public ResourceNotFoundException(String id, Throwable cause) {
|
||||
super(id, cause);
|
||||
}
|
||||
|
||||
/** @param id portion of the resource URI that does not exist. */
|
||||
public ResourceNotFoundException(IdString id) {
|
||||
super(id.get());
|
||||
|
@ -0,0 +1,109 @@
|
||||
// Copyright (C) 2013 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.project;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.reviewdb.client.Project.InheritableBoolean;
|
||||
import com.google.gerrit.reviewdb.client.Project.SubmitType;
|
||||
import com.google.gerrit.server.git.TransferConfig;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class ConfigInfo {
|
||||
public final String kind = "gerritcodereview#project_config";
|
||||
|
||||
public String description;
|
||||
public InheritedBooleanInfo useContributorAgreements;
|
||||
public InheritedBooleanInfo useContentMerge;
|
||||
public InheritedBooleanInfo useSignedOffBy;
|
||||
public InheritedBooleanInfo requireChangeId;
|
||||
public MaxObjectSizeLimitInfo maxObjectSizeLimit;
|
||||
public SubmitType submitType;
|
||||
public Project.State state;
|
||||
|
||||
public Map<String, CommentLinkInfo> commentlinks;
|
||||
public ThemeInfo theme;
|
||||
|
||||
public ConfigInfo(ProjectState state, TransferConfig config) {
|
||||
Project p = state.getProject();
|
||||
this.description = Strings.emptyToNull(p.getDescription());
|
||||
|
||||
InheritedBooleanInfo useContributorAgreements =
|
||||
new InheritedBooleanInfo();
|
||||
InheritedBooleanInfo useSignedOffBy = new InheritedBooleanInfo();
|
||||
InheritedBooleanInfo useContentMerge = new InheritedBooleanInfo();
|
||||
InheritedBooleanInfo requireChangeId = new InheritedBooleanInfo();
|
||||
|
||||
useContributorAgreements.value = state.isUseContributorAgreements();
|
||||
useSignedOffBy.value = state.isUseSignedOffBy();
|
||||
useContentMerge.value = state.isUseContentMerge();
|
||||
requireChangeId.value = state.isRequireChangeID();
|
||||
|
||||
useContributorAgreements.configuredValue =
|
||||
p.getUseContributorAgreements();
|
||||
useSignedOffBy.configuredValue = p.getUseSignedOffBy();
|
||||
useContentMerge.configuredValue = p.getUseContentMerge();
|
||||
requireChangeId.configuredValue = p.getRequireChangeID();
|
||||
|
||||
ProjectState parentState = Iterables.getFirst(state.parents(), null);
|
||||
if (parentState != null) {
|
||||
useContributorAgreements.inheritedValue =
|
||||
parentState.isUseContributorAgreements();
|
||||
useSignedOffBy.inheritedValue = parentState.isUseSignedOffBy();
|
||||
useContentMerge.inheritedValue = parentState.isUseContentMerge();
|
||||
requireChangeId.inheritedValue = parentState.isRequireChangeID();
|
||||
}
|
||||
|
||||
this.useContributorAgreements = useContributorAgreements;
|
||||
this.useSignedOffBy = useSignedOffBy;
|
||||
this.useContentMerge = useContentMerge;
|
||||
this.requireChangeId = requireChangeId;
|
||||
|
||||
MaxObjectSizeLimitInfo maxObjectSizeLimit = new MaxObjectSizeLimitInfo();
|
||||
maxObjectSizeLimit.value =
|
||||
config.getEffectiveMaxObjectSizeLimit(state) == config
|
||||
.getMaxObjectSizeLimit() ? config
|
||||
.getFormattedMaxObjectSizeLimit() : p.getMaxObjectSizeLimit();
|
||||
maxObjectSizeLimit.configuredValue = p.getMaxObjectSizeLimit();
|
||||
maxObjectSizeLimit.inheritedValue =
|
||||
config.getFormattedMaxObjectSizeLimit();
|
||||
this.maxObjectSizeLimit = maxObjectSizeLimit;
|
||||
|
||||
this.submitType = p.getSubmitType();
|
||||
this.state = p.getState() != Project.State.ACTIVE ? p.getState() : null;
|
||||
|
||||
this.commentlinks = Maps.newLinkedHashMap();
|
||||
for (CommentLinkInfo cl : state.getCommentLinks()) {
|
||||
this.commentlinks.put(cl.name, cl);
|
||||
}
|
||||
|
||||
this.theme = state.getTheme();
|
||||
}
|
||||
|
||||
public static class InheritedBooleanInfo {
|
||||
public Boolean value;
|
||||
public InheritableBoolean configuredValue;
|
||||
public Boolean inheritedValue;
|
||||
}
|
||||
|
||||
public static class MaxObjectSizeLimitInfo {
|
||||
public String value;
|
||||
public String configuredValue;
|
||||
public String inheritedValue;
|
||||
}
|
||||
}
|
@ -14,17 +14,10 @@
|
||||
|
||||
package com.google.gerrit.server.project;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.gerrit.extensions.restapi.RestReadView;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.reviewdb.client.Project.InheritableBoolean;
|
||||
import com.google.gerrit.reviewdb.client.Project.SubmitType;
|
||||
import com.google.gerrit.server.git.TransferConfig;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class GetConfig implements RestReadView<ProjectResource> {
|
||||
|
||||
private final TransferConfig config;
|
||||
@ -36,82 +29,6 @@ public class GetConfig implements RestReadView<ProjectResource> {
|
||||
|
||||
@Override
|
||||
public ConfigInfo apply(ProjectResource resource) {
|
||||
ConfigInfo result = new ConfigInfo();
|
||||
ProjectState state = resource.getControl().getProjectState();
|
||||
Project p = state.getProject();
|
||||
InheritedBooleanInfo useContributorAgreements = new InheritedBooleanInfo();
|
||||
InheritedBooleanInfo useSignedOffBy = new InheritedBooleanInfo();
|
||||
InheritedBooleanInfo useContentMerge = new InheritedBooleanInfo();
|
||||
InheritedBooleanInfo requireChangeId = new InheritedBooleanInfo();
|
||||
|
||||
useContributorAgreements.value = state.isUseContributorAgreements();
|
||||
useSignedOffBy.value = state.isUseSignedOffBy();
|
||||
useContentMerge.value = state.isUseContentMerge();
|
||||
requireChangeId.value = state.isRequireChangeID();
|
||||
|
||||
useContributorAgreements.configuredValue = p.getUseContributorAgreements();
|
||||
useSignedOffBy.configuredValue = p.getUseSignedOffBy();
|
||||
useContentMerge.configuredValue = p.getUseContentMerge();
|
||||
requireChangeId.configuredValue = p.getRequireChangeID();
|
||||
|
||||
ProjectState parentState = Iterables.getFirst(state.parents(), null);
|
||||
if (parentState != null) {
|
||||
useContributorAgreements.inheritedValue = parentState.isUseContributorAgreements();
|
||||
useSignedOffBy.inheritedValue = parentState.isUseSignedOffBy();
|
||||
useContentMerge.inheritedValue = parentState.isUseContentMerge();
|
||||
requireChangeId.inheritedValue = parentState.isRequireChangeID();
|
||||
}
|
||||
|
||||
result.useContributorAgreements = useContributorAgreements;
|
||||
result.useSignedOffBy = useSignedOffBy;
|
||||
result.useContentMerge = useContentMerge;
|
||||
result.requireChangeId = requireChangeId;
|
||||
|
||||
MaxObjectSizeLimitInfo maxObjectSizeLimit = new MaxObjectSizeLimitInfo();
|
||||
maxObjectSizeLimit.value =
|
||||
config.getEffectiveMaxObjectSizeLimit(state) == config.getMaxObjectSizeLimit()
|
||||
? config.getFormattedMaxObjectSizeLimit()
|
||||
: p.getMaxObjectSizeLimit();
|
||||
maxObjectSizeLimit.configuredValue = p.getMaxObjectSizeLimit();
|
||||
maxObjectSizeLimit.inheritedValue = config.getFormattedMaxObjectSizeLimit();
|
||||
result.maxObjectSizeLimit = maxObjectSizeLimit;
|
||||
|
||||
result.submitType = p.getSubmitType();
|
||||
result.state = p.getState() != Project.State.ACTIVE ? p.getState() : null;
|
||||
|
||||
result.commentlinks = Maps.newLinkedHashMap();
|
||||
for (CommentLinkInfo cl : state.getCommentLinks()) {
|
||||
result.commentlinks.put(cl.name, cl);
|
||||
}
|
||||
|
||||
result.theme = state.getTheme();
|
||||
return result;
|
||||
}
|
||||
|
||||
public static class ConfigInfo {
|
||||
public final String kind = "gerritcodereview#project_config";
|
||||
|
||||
public InheritedBooleanInfo useContributorAgreements;
|
||||
public InheritedBooleanInfo useContentMerge;
|
||||
public InheritedBooleanInfo useSignedOffBy;
|
||||
public InheritedBooleanInfo requireChangeId;
|
||||
public MaxObjectSizeLimitInfo maxObjectSizeLimit;
|
||||
public SubmitType submitType;
|
||||
public Project.State state;
|
||||
|
||||
public Map<String, CommentLinkInfo> commentlinks;
|
||||
public ThemeInfo theme;
|
||||
}
|
||||
|
||||
public static class InheritedBooleanInfo {
|
||||
public Boolean value;
|
||||
public InheritableBoolean configuredValue;
|
||||
public Boolean inheritedValue;
|
||||
}
|
||||
|
||||
public static class MaxObjectSizeLimitInfo {
|
||||
public String value;
|
||||
public String configuredValue;
|
||||
public String inheritedValue;
|
||||
return new ConfigInfo(resource.getControl().getProjectState(), config);
|
||||
}
|
||||
}
|
||||
|
@ -65,5 +65,6 @@ public class Module extends RestApiModule {
|
||||
install(new FactoryModuleBuilder().build(CreateProject.Factory.class));
|
||||
|
||||
get(PROJECT_KIND, "config").to(GetConfig.class);
|
||||
put(PROJECT_KIND, "config").to(PutConfig.class);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,138 @@
|
||||
// Copyright (C) 2013 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.project;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.gerrit.extensions.restapi.BadRequestException;
|
||||
import com.google.gerrit.extensions.restapi.ResourceConflictException;
|
||||
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
|
||||
import com.google.gerrit.extensions.restapi.RestModifyView;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.reviewdb.client.Project.InheritableBoolean;
|
||||
import com.google.gerrit.reviewdb.client.Project.SubmitType;
|
||||
import com.google.gerrit.server.CurrentUser;
|
||||
import com.google.gerrit.server.git.MetaDataUpdate;
|
||||
import com.google.gerrit.server.git.ProjectConfig;
|
||||
import com.google.gerrit.server.git.TransferConfig;
|
||||
import com.google.gerrit.server.project.PutConfig.Input;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
|
||||
import org.eclipse.jgit.errors.ConfigInvalidException;
|
||||
import org.eclipse.jgit.errors.RepositoryNotFoundException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class PutConfig implements RestModifyView<ProjectResource, Input> {
|
||||
public static class Input {
|
||||
public String description;
|
||||
public InheritableBoolean useContributorAgreements;
|
||||
public InheritableBoolean useContentMerge;
|
||||
public InheritableBoolean useSignedOffBy;
|
||||
public InheritableBoolean requireChangeId;
|
||||
public String maxObjectSizeLimit;
|
||||
public SubmitType submitType;
|
||||
public Project.State state;
|
||||
}
|
||||
|
||||
private final MetaDataUpdate.User metaDataUpdateFactory;
|
||||
private final ProjectCache projectCache;
|
||||
private final Provider<CurrentUser> self;
|
||||
private final ProjectState.Factory projectStateFactory;
|
||||
private final TransferConfig config;
|
||||
|
||||
@Inject
|
||||
PutConfig(MetaDataUpdate.User metaDataUpdateFactory,
|
||||
ProjectCache projectCache,
|
||||
Provider<CurrentUser> self,
|
||||
ProjectState.Factory projectStateFactory,
|
||||
TransferConfig config) {
|
||||
this.metaDataUpdateFactory = metaDataUpdateFactory;
|
||||
this.projectCache = projectCache;
|
||||
this.self = self;
|
||||
this.projectStateFactory = projectStateFactory;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigInfo apply(ProjectResource rsrc, Input input)
|
||||
throws ResourceNotFoundException, BadRequestException,
|
||||
ResourceConflictException {
|
||||
Project.NameKey projectName = rsrc.getNameKey();
|
||||
if (!rsrc.getControl().isOwner()) {
|
||||
throw new ResourceNotFoundException(projectName.get());
|
||||
}
|
||||
|
||||
if (input == null) {
|
||||
throw new BadRequestException("config is required");
|
||||
}
|
||||
|
||||
final MetaDataUpdate md;
|
||||
try {
|
||||
md = metaDataUpdateFactory.create(projectName);
|
||||
} catch (RepositoryNotFoundException notFound) {
|
||||
throw new ResourceNotFoundException(projectName.get());
|
||||
} catch (IOException e) {
|
||||
throw new ResourceNotFoundException(projectName.get(), e);
|
||||
}
|
||||
try {
|
||||
ProjectConfig projectConfig = ProjectConfig.read(md);
|
||||
Project p = projectConfig.getProject();
|
||||
|
||||
p.setDescription(Strings.emptyToNull(input.description));
|
||||
|
||||
if (input.useContributorAgreements != null) {
|
||||
p.setUseContributorAgreements(input.useContributorAgreements);
|
||||
}
|
||||
if (input.useContentMerge != null) {
|
||||
p.setUseContentMerge(input.useContentMerge);
|
||||
}
|
||||
if (input.useSignedOffBy != null) {
|
||||
p.setUseSignedOffBy(input.useSignedOffBy);
|
||||
}
|
||||
if (input.requireChangeId != null) {
|
||||
p.setRequireChangeID(input.requireChangeId);
|
||||
}
|
||||
|
||||
if (input.maxObjectSizeLimit != null) {
|
||||
p.setMaxObjectSizeLimit(input.maxObjectSizeLimit);
|
||||
}
|
||||
|
||||
if (input.submitType != null) {
|
||||
p.setSubmitType(input.submitType);
|
||||
}
|
||||
|
||||
if (input.state != null) {
|
||||
p.setState(input.state);
|
||||
}
|
||||
|
||||
md.setMessage("Modified project settings\n");
|
||||
try {
|
||||
projectConfig.commit(md);
|
||||
(new PerRequestProjectControlCache(projectCache, self.get()))
|
||||
.evict(projectConfig.getProject());
|
||||
} catch (IOException e) {
|
||||
throw new ResourceConflictException("Cannot update " + projectName);
|
||||
}
|
||||
return new ConfigInfo(projectStateFactory.create(projectConfig), config);
|
||||
} catch (ConfigInvalidException err) {
|
||||
throw new ResourceConflictException("Cannot read project " + projectName, err);
|
||||
} catch (IOException err) {
|
||||
throw new ResourceConflictException("Cannot update project " + projectName, err);
|
||||
} finally {
|
||||
md.close();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user