Skip to content

Commit 687d454

Browse files
Templates API - index, show, create, update. (#2233)
1 parent 4389c1f commit 687d454

File tree

19 files changed

+1244
-16
lines changed

19 files changed

+1244
-16
lines changed

config/config-api/src/com/thoughtworks/go/config/PipelineConfig.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2015 ThoughtWorks, Inc.
2+
* Copyright 2016 ThoughtWorks, Inc.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -320,6 +320,10 @@ public CaseInsensitiveString name() {
320320
return name;
321321
}
322322

323+
public CaseInsensitiveString getName() {
324+
return name;
325+
}
326+
323327
public StageConfig previousStage(final CaseInsensitiveString stageName) {
324328
StageConfig lastStageConfig = null;
325329
for (StageConfig currentStageConfig : this) {

config/config-api/src/com/thoughtworks/go/config/PipelineTemplateConfig.java

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
/*************************GO-LICENSE-START*********************************
2-
* Copyright 2014 ThoughtWorks, Inc.
1+
/*
2+
* Copyright 2016 ThoughtWorks, Inc.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
66
* You may obtain a copy of the License at
77
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
8+
* http://www.apache.org/licenses/LICENSE-2.0
99
*
1010
* Unless required by applicable law or agreed to in writing, software
1111
* distributed under the License is distributed on an "AS IS" BASIS,
1212
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
15-
*************************GO-LICENSE-END***********************************/
15+
*/
1616

1717
package com.thoughtworks.go.config;
1818

@@ -26,6 +26,7 @@
2626
import com.thoughtworks.go.domain.ConfigErrors;
2727

2828
import java.util.HashMap;
29+
import java.util.List;
2930
import java.util.Map;
3031

3132
/**
@@ -96,6 +97,18 @@ public StageConfig getStage(final CaseInsensitiveString stageName) {
9697
return findBy(stageName);
9798
}
9899

100+
public List<StageConfig> getStages() {
101+
return this;
102+
}
103+
104+
public void setName(String name) {
105+
this.name = new CaseInsensitiveString(name);
106+
}
107+
108+
public void setName(CaseInsensitiveString name) {
109+
this.name = name;
110+
}
111+
99112
public StageConfig findBy(final CaseInsensitiveString stageName) {
100113
for (StageConfig stageConfig : this) {
101114
if (stageConfig.name().equals(stageName)) {
@@ -209,4 +222,8 @@ public void copyStages(PipelineConfig pipeline) {
209222
public Authorization getAuthorization() {
210223
return authorization;
211224
}
225+
226+
public List<ConfigErrors> getAllErrors() {
227+
return ErrorCollector.getAllErrors(this);
228+
}
212229
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright 2016 ThoughtWorks, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.thoughtworks.go.config.update;
18+
19+
import com.thoughtworks.go.config.CruiseConfig;
20+
import com.thoughtworks.go.config.PipelineTemplateConfig;
21+
import com.thoughtworks.go.i18n.LocalizedMessage;
22+
import com.thoughtworks.go.server.domain.Username;
23+
import com.thoughtworks.go.server.service.GoConfigService;
24+
import com.thoughtworks.go.server.service.result.LocalizedOperationResult;
25+
import com.thoughtworks.go.serverhealth.HealthStateType;
26+
27+
28+
public class CreateTemplateConfigCommand extends TemplateConfigCommand {
29+
private final Username currentUser;
30+
private GoConfigService goConfigService;
31+
32+
public CreateTemplateConfigCommand(PipelineTemplateConfig templateConfig, Username currentUser, GoConfigService goConfigService, LocalizedOperationResult result) {
33+
super(templateConfig, result);
34+
this.currentUser = currentUser;
35+
this.goConfigService = goConfigService;
36+
}
37+
38+
@Override
39+
public void update(CruiseConfig modifiedConfig) throws Exception {
40+
modifiedConfig.addTemplate(templateConfig);
41+
}
42+
43+
@Override
44+
public boolean canContinue(CruiseConfig cruiseConfig) {
45+
if (!(goConfigService.isUserAdmin(currentUser))) {
46+
result.unauthorized(LocalizedMessage.string("UNAUTHORIZED_TO_EDIT"), HealthStateType.unauthorised());
47+
return false;
48+
}
49+
return true;
50+
}
51+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright 2016 ThoughtWorks, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.thoughtworks.go.config.update;
18+
19+
import com.thoughtworks.go.config.BasicCruiseConfig;
20+
import com.thoughtworks.go.config.CruiseConfig;
21+
import com.thoughtworks.go.config.PipelineTemplateConfig;
22+
import com.thoughtworks.go.config.TemplatesConfig;
23+
import com.thoughtworks.go.config.commands.EntityConfigUpdateCommand;
24+
import com.thoughtworks.go.i18n.LocalizedMessage;
25+
import com.thoughtworks.go.server.service.result.LocalizedOperationResult;
26+
import com.thoughtworks.go.serverhealth.HealthStateType;
27+
28+
29+
public abstract class TemplateConfigCommand implements EntityConfigUpdateCommand<PipelineTemplateConfig> {
30+
31+
private PipelineTemplateConfig preprocessedTemplateConfig;
32+
protected final LocalizedOperationResult result;
33+
protected PipelineTemplateConfig templateConfig;
34+
35+
36+
public TemplateConfigCommand(PipelineTemplateConfig templateConfig, LocalizedOperationResult result) {
37+
this.templateConfig = templateConfig;
38+
this.result = result;
39+
}
40+
41+
@Override
42+
public boolean isValid(CruiseConfig preprocessedConfig) {
43+
TemplatesConfig templatesConfig = preprocessedConfig.getTemplates();
44+
preprocessedTemplateConfig = findAddedTemplate(preprocessedConfig);
45+
preprocessedTemplateConfig.validate(null);
46+
if(preprocessedTemplateConfig.getAllErrors().isEmpty()) {
47+
templatesConfig.validate(null);
48+
BasicCruiseConfig.copyErrors(preprocessedTemplateConfig, templateConfig);
49+
return preprocessedTemplateConfig.getAllErrors().isEmpty() && templatesConfig.errors().isEmpty();
50+
}
51+
BasicCruiseConfig.copyErrors(preprocessedTemplateConfig, templateConfig);
52+
return false;
53+
}
54+
55+
protected PipelineTemplateConfig findAddedTemplate(CruiseConfig cruiseConfig) {
56+
try {
57+
PipelineTemplateConfig pipelineTemplateConfig = cruiseConfig.findTemplate(templateConfig.name());
58+
if(pipelineTemplateConfig == null) {
59+
result.notFound(LocalizedMessage.string("RESOURCE_NOT_FOUND"), HealthStateType.notFound());
60+
throw new NullPointerException(String.format("The template with name '%s' is not found or should not be null.", templateConfig.name()));
61+
}
62+
return pipelineTemplateConfig;
63+
}catch (NullPointerException e) {
64+
throw new NullPointerException(String.format("The template with name '%s' is not found or should not be null.", templateConfig.name()));
65+
}
66+
67+
}
68+
69+
@Override
70+
public void clearErrors() {
71+
BasicCruiseConfig.clearErrors(templateConfig);
72+
}
73+
74+
@Override
75+
public PipelineTemplateConfig getPreprocessedEntityConfig() {
76+
return preprocessedTemplateConfig;
77+
}
78+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* Copyright 2016 ThoughtWorks, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.thoughtworks.go.config.update;
18+
19+
import com.thoughtworks.go.config.CruiseConfig;
20+
import com.thoughtworks.go.config.PipelineTemplateConfig;
21+
import com.thoughtworks.go.config.TemplatesConfig;
22+
import com.thoughtworks.go.i18n.LocalizedMessage;
23+
import com.thoughtworks.go.server.domain.Username;
24+
import com.thoughtworks.go.server.service.EntityHashingService;
25+
import com.thoughtworks.go.server.service.GoConfigService;
26+
import com.thoughtworks.go.server.service.result.LocalizedOperationResult;
27+
import com.thoughtworks.go.serverhealth.HealthStateType;
28+
29+
public class UpdateTemplateConfigCommand extends TemplateConfigCommand{
30+
private final Username currentUser;
31+
private String md5;
32+
private EntityHashingService entityHashingService;
33+
private GoConfigService goConfigService;
34+
35+
public UpdateTemplateConfigCommand(PipelineTemplateConfig templateConfig, Username currentUser, GoConfigService goConfigService, LocalizedOperationResult result, String md5, EntityHashingService entityHashingService) {
36+
super(templateConfig, result);
37+
this.currentUser = currentUser;
38+
this.goConfigService = goConfigService;
39+
this.md5 = md5;
40+
this.entityHashingService = entityHashingService;
41+
}
42+
43+
@Override
44+
public void update(CruiseConfig modifiedConfig) throws Exception {
45+
PipelineTemplateConfig existingTemplateConfig = findAddedTemplate(modifiedConfig);
46+
TemplatesConfig templatesConfig = modifiedConfig.getTemplates();
47+
templatesConfig.removeTemplateNamed(existingTemplateConfig.name());
48+
templatesConfig.add(templateConfig);
49+
modifiedConfig.setTemplates(templatesConfig);
50+
}
51+
52+
@Override
53+
public boolean canContinue(CruiseConfig cruiseConfig) {
54+
return isUserAuthorized() && isRequestFresh(cruiseConfig);
55+
}
56+
57+
private boolean isRequestFresh(CruiseConfig cruiseConfig) {
58+
PipelineTemplateConfig pipelineTemplateConfig = findAddedTemplate(cruiseConfig);
59+
boolean freshRequest = entityHashingService.md5ForEntity(pipelineTemplateConfig, pipelineTemplateConfig.name().toString()).equals(md5);
60+
if (!freshRequest) {
61+
result.stale(LocalizedMessage.string("STALE_RESOURCE_CONFIG", "Template", templateConfig.name()));
62+
}
63+
64+
return freshRequest;
65+
}
66+
67+
private boolean isUserAuthorized() {
68+
if (!(goConfigService.isUserAdmin(currentUser))) {
69+
result.unauthorized(LocalizedMessage.string("UNAUTHORIZED_TO_EDIT"), HealthStateType.unauthorised());
70+
return false;
71+
}
72+
return true;
73+
}
74+
}
75+

server/src/com/thoughtworks/go/server/service/EntityHashingService.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public void initialize() {
4747
goConfigService.register(this);
4848
goConfigService.register(new PipelineConfigChangedListener());
4949
goConfigService.register(new SCMConfigChangedListner());
50+
goConfigService.register(new TemplateConfigChangedListner());
5051
goConfigService.register(new EnvironmentConfigListener());
5152
}
5253

@@ -109,6 +110,14 @@ public void onEntityConfigChange(SCM scm) {
109110
}
110111
}
111112

113+
class TemplateConfigChangedListner extends EntityConfigChangedListener<PipelineTemplateConfig> {
114+
@Override
115+
public void onEntityConfigChange(PipelineTemplateConfig pipelineTemplateConfig) {
116+
String cacheKey = pipelineTemplateConfig.getClass().getName() + pipelineTemplateConfig.name().toLower();
117+
goCache.remove(ETAG_CACHE_KEY, cacheKey.toLowerCase());
118+
}
119+
}
120+
112121
class EnvironmentConfigListener extends EntityConfigChangedListener<BasicEnvironmentConfig> {
113122
@Override
114123
public void onEntityConfigChange(BasicEnvironmentConfig config) {

server/src/com/thoughtworks/go/server/service/TemplateConfigService.java

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
/*************************GO-LICENSE-START*********************************
2-
* Copyright 2014 ThoughtWorks, Inc.
1+
/*
2+
* Copyright 2016 ThoughtWorks, Inc.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
66
* You may obtain a copy of the License at
77
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
8+
* http://www.apache.org/licenses/LICENSE-2.0
99
*
1010
* Unless required by applicable law or agreed to in writing, software
1111
* distributed under the License is distributed on an "AS IS" BASIS,
1212
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
15-
*************************GO-LICENSE-END***********************************/
15+
*/
1616

1717
package com.thoughtworks.go.server.service;
1818

@@ -28,26 +28,34 @@
2828
import com.thoughtworks.go.config.PipelineConfig;
2929
import com.thoughtworks.go.config.PipelineTemplateConfig;
3030
import com.thoughtworks.go.config.TemplatesConfig;
31+
import com.thoughtworks.go.config.commands.EntityConfigUpdateCommand;
32+
import com.thoughtworks.go.config.update.ConfigUpdateCheckFailedException;
33+
import com.thoughtworks.go.config.update.CreateTemplateConfigCommand;
34+
import com.thoughtworks.go.config.update.UpdateTemplateConfigCommand;
3135
import com.thoughtworks.go.i18n.LocalizedMessage;
3236
import com.thoughtworks.go.presentation.ConfigForEdit;
3337
import com.thoughtworks.go.server.domain.Username;
3438
import com.thoughtworks.go.server.service.result.HttpLocalizedOperationResult;
3539
import com.thoughtworks.go.server.service.result.LocalizedOperationResult;
3640
import com.thoughtworks.go.serverhealth.HealthStateScope;
3741
import com.thoughtworks.go.serverhealth.HealthStateType;
42+
import org.slf4j.LoggerFactory;
3843
import org.springframework.beans.factory.annotation.Autowired;
3944
import org.springframework.stereotype.Service;
4045

4146
@Service
4247
public class TemplateConfigService {
4348
private final GoConfigService goConfigService;
4449
private final SecurityService securityService;
50+
private org.slf4j.Logger LOGGER = LoggerFactory.getLogger(TemplateConfigService.class);
4551
private Cloner cloner = new Cloner();
52+
private EntityHashingService entityHashingService;
4653

4754
@Autowired
48-
public TemplateConfigService(GoConfigService goConfigService, SecurityService securityService) {
55+
public TemplateConfigService(GoConfigService goConfigService, SecurityService securityService, EntityHashingService entityHashingService) {
4956
this.goConfigService = goConfigService;
5057
this.securityService = securityService;
58+
this.entityHashingService = entityHashingService;
5159
}
5260

5361
public Map<CaseInsensitiveString, List<CaseInsensitiveString>> templatesWithPipelinesForUser(String username) {
@@ -61,6 +69,28 @@ public void removeTemplate(String templateName, CruiseConfig cruiseConfig, Strin
6169
goConfigService.updateConfig(new DeleteTemplateCommand(templateName, md5));
6270
}
6371

72+
public void createTemplateConfig(final Username currentUser, final PipelineTemplateConfig templateConfig, final LocalizedOperationResult result) {
73+
CreateTemplateConfigCommand command = new CreateTemplateConfigCommand(templateConfig, currentUser, goConfigService, result);
74+
update(currentUser, result, command);
75+
}
76+
77+
public void updateTemplateConfig(final Username currentUser, final PipelineTemplateConfig templateConfig, final LocalizedOperationResult result, String md5) {
78+
UpdateTemplateConfigCommand command = new UpdateTemplateConfigCommand(templateConfig, currentUser, goConfigService, result, md5, entityHashingService);
79+
update(currentUser, result, command);
80+
}
81+
82+
private void update(Username currentUser, LocalizedOperationResult result, EntityConfigUpdateCommand command) {
83+
try {
84+
goConfigService.updateConfig(command, currentUser);
85+
} catch (Exception e) {
86+
if (e instanceof ConfigUpdateCheckFailedException) {
87+
return;
88+
}
89+
LOGGER.error(e.getMessage(), e);
90+
result.unprocessableEntity(LocalizedMessage.string("SAVE_FAILED_WITH_REASON", e.getMessage()));
91+
}
92+
}
93+
6494
public ConfigForEdit<PipelineTemplateConfig> loadForEdit(String templateName, Username username, HttpLocalizedOperationResult result) {
6595
if (!securityService.isAuthorizedToEditTemplate(templateName, username)) {
6696
result.unauthorized(LocalizedMessage.string("UNAUTHORIZED_TO_EDIT_TEMPLATE", templateName), HealthStateType.unauthorised());

0 commit comments

Comments
 (0)