Skip to content

Commit 7203cb3

Browse files
committed
Introduce version 2 of artifacts API
Changes: - Allow "Fetch Artifact" message to return a list of environment variables. - These environment variables will eventually be made available to other tasks in the job. - Format (in response to the cd.go.artifact.fetch-artifact call) [ { "name": "VAR1", "value": "VALUE1", "secure": true }, { "name": "VAR2", "value": "VALUE2", "secure": false } ]
1 parent c24fa0d commit 7203cb3

File tree

14 files changed

+497
-44
lines changed

14 files changed

+497
-44
lines changed

common/src/main/java/com/thoughtworks/go/remote/work/artifact/ArtifactRequestProcessor.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package com.thoughtworks.go.remote.work.artifact;
1818

19+
import com.thoughtworks.go.plugin.access.artifact.ArtifactExtension;
20+
import com.thoughtworks.go.plugin.access.artifact.ArtifactExtensionConstants;
1921
import com.thoughtworks.go.plugin.api.request.GoApiRequest;
2022
import com.thoughtworks.go.plugin.api.response.DefaultGoApiResponse;
2123
import com.thoughtworks.go.plugin.api.response.GoApiResponse;
@@ -34,7 +36,7 @@
3436
import static java.util.Arrays.asList;
3537

3638
public class ArtifactRequestProcessor implements GoPluginApiRequestProcessor {
37-
private static final List<String> goSupportedVersions = asList("1.0");
39+
private static final List<String> goSupportedVersions = ArtifactExtensionConstants.SUPPORTED_VERSIONS;
3840
private final SafeOutputStreamConsumer safeOutputStreamConsumer;
3941
private final ProcessType processType;
4042

common/src/test/java/com/thoughtworks/go/remote/work/ArtifactRequestProcessorTest.java renamed to common/src/test/java/com/thoughtworks/go/remote/work/ArtifactRequestProcessorTestBase.java

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,32 +31,52 @@
3131

3232
import static com.thoughtworks.go.remote.work.artifact.ArtifactRequestProcessor.Request.CONSOLE_LOG;
3333
import static com.thoughtworks.go.util.command.TaggedStreamConsumer.*;
34+
import static org.hamcrest.MatcherAssert.assertThat;
35+
import static org.hamcrest.Matchers.containsString;
36+
import static org.junit.jupiter.api.Assertions.assertThrows;
37+
import static org.junit.jupiter.api.Assertions.fail;
3438
import static org.mockito.Mockito.*;
3539

36-
public class ArtifactRequestProcessorTest {
40+
public abstract class ArtifactRequestProcessorTestBase {
3741
private GoApiRequest request;
3842
private GoPluginDescriptor descriptor;
3943
private DefaultGoPublisher goPublisher;
4044
private ArtifactRequestProcessor artifactRequestProcessorForPublish;
4145
private ArtifactRequestProcessor artifactRequestProcessorForFetch;
42-
private EnvironmentVariableContext environmentVariableContext;
4346

4447
@Before
4548
public void setUp() throws Exception {
4649
request = mock(GoApiRequest.class);
4750
descriptor = mock(GoPluginDescriptor.class);
4851
goPublisher = mock(DefaultGoPublisher.class);
49-
environmentVariableContext = mock(EnvironmentVariableContext.class);
52+
EnvironmentVariableContext environmentVariableContext = mock(EnvironmentVariableContext.class);
5053
when(environmentVariableContext.secrets()).thenReturn(Collections.singletonList(new PasswordArgument("secret.value")));
5154

5255
artifactRequestProcessorForPublish = ArtifactRequestProcessor.forPublishArtifact(goPublisher, environmentVariableContext);
5356
artifactRequestProcessorForFetch = ArtifactRequestProcessor.forFetchArtifact(goPublisher, environmentVariableContext);
5457

55-
when(request.apiVersion()).thenReturn("1.0");
58+
when(request.apiVersion()).thenReturn(getRequestPluginVersion());
5659
when(descriptor.id()).thenReturn("cd.go.artifact.docker");
5760
when(request.api()).thenReturn(CONSOLE_LOG.requestName());
5861
}
5962

63+
protected abstract String getRequestPluginVersion();
64+
65+
@Test
66+
public void shouldFailForAVersionOutsideOfSupportedVersions() {
67+
reset(request);
68+
when(request.apiVersion()).thenReturn("3.0");
69+
when(request.api()).thenReturn(CONSOLE_LOG.requestName());
70+
71+
when(request.requestBody()).thenReturn("{\"logLevel\":\"ERROR\",\"message\":\"Error while pushing docker image to registry: foo.\"}");
72+
73+
RuntimeException exception = assertThrows(RuntimeException.class, () -> {
74+
artifactRequestProcessorForPublish.process(descriptor, request);
75+
});
76+
77+
assertThat(exception.getMessage(), containsString("Unsupported 'go.processor.artifact.console-log' API version: 3.0"));
78+
}
79+
6080
@Test
6181
public void shouldSendErrorLogToConsoleLogForPublish() {
6282
when(request.requestBody()).thenReturn("{\"logLevel\":\"ERROR\",\"message\":\"Error while pushing docker image to registry: foo.\"}");
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright 2018 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.remote.work;
18+
19+
import com.thoughtworks.go.plugin.api.request.GoApiRequest;
20+
import com.thoughtworks.go.plugin.infra.plugininfo.GoPluginDescriptor;
21+
import com.thoughtworks.go.remote.work.artifact.ArtifactRequestProcessor;
22+
import com.thoughtworks.go.util.command.EnvironmentVariableContext;
23+
import com.thoughtworks.go.util.command.PasswordArgument;
24+
import com.thoughtworks.go.work.DefaultGoPublisher;
25+
import org.junit.Before;
26+
import org.junit.Test;
27+
28+
import java.util.Collections;
29+
30+
import static com.thoughtworks.go.remote.work.artifact.ArtifactRequestProcessor.Request.CONSOLE_LOG;
31+
import static com.thoughtworks.go.util.command.TaggedStreamConsumer.*;
32+
import static org.mockito.Mockito.*;
33+
34+
public class ArtifactRequestProcessorV1Test extends ArtifactRequestProcessorTestBase {
35+
@Override
36+
protected String getRequestPluginVersion() {
37+
return "1.0";
38+
}
39+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright 2018 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.remote.work;
18+
19+
import com.thoughtworks.go.plugin.api.request.GoApiRequest;
20+
import com.thoughtworks.go.plugin.infra.plugininfo.GoPluginDescriptor;
21+
import com.thoughtworks.go.remote.work.artifact.ArtifactRequestProcessor;
22+
import com.thoughtworks.go.util.command.EnvironmentVariableContext;
23+
import com.thoughtworks.go.util.command.PasswordArgument;
24+
import com.thoughtworks.go.work.DefaultGoPublisher;
25+
import org.junit.Before;
26+
import org.junit.Test;
27+
28+
import java.util.Collections;
29+
30+
import static com.thoughtworks.go.remote.work.artifact.ArtifactRequestProcessor.Request.CONSOLE_LOG;
31+
import static com.thoughtworks.go.util.command.TaggedStreamConsumer.*;
32+
import static org.mockito.Mockito.*;
33+
34+
public class ArtifactRequestProcessorV2Test extends ArtifactRequestProcessorTestBase {
35+
@Override
36+
protected String getRequestPluginVersion() {
37+
return "2.0";
38+
}
39+
}

plugin-infra/go-plugin-access/build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
description = 'APIs to allow GoCD to communicate with GoCD Plugins'
1818

19+
apply plugin: 'groovy'
20+
1921
dependencies {
2022
compile project(':plugin-infra:go-plugin-infra')
2123
compile project(':domain')
@@ -25,6 +27,7 @@ dependencies {
2527

2628
compileOnly(group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: project.versions.bouncyCastle)
2729

30+
testCompile localGroovy()
2831
testCompile group: 'net.javacrumbs.json-unit', name: 'json-unit-fluent', version: project.versions.jsonUnit
2932
testCompile project(':test:test-utils')
3033
testCompile project(path: ':domain', configuration: 'testOutput')

plugin-infra/go-plugin-access/src/main/java/com/thoughtworks/go/plugin/access/artifact/ArtifactExtension.java

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222
import com.thoughtworks.go.plugin.access.DefaultPluginInteractionCallback;
2323
import com.thoughtworks.go.plugin.access.PluginRequestHelper;
2424
import com.thoughtworks.go.plugin.access.artifact.model.PublishArtifactResponse;
25+
import com.thoughtworks.go.plugin.access.artifact.models.FetchArtifactEnvironmentVariable;
2526
import com.thoughtworks.go.plugin.access.common.AbstractExtension;
27+
import com.thoughtworks.go.plugin.access.common.settings.PluginSettingsJsonMessageHandler;
2628
import com.thoughtworks.go.plugin.access.common.settings.PluginSettingsJsonMessageHandler1_0;
2729
import com.thoughtworks.go.plugin.api.response.validation.ValidationResult;
2830
import com.thoughtworks.go.plugin.domain.common.PluginConfiguration;
@@ -45,12 +47,13 @@ public class ArtifactExtension extends AbstractExtension {
4547
@Autowired
4648
protected ArtifactExtension(PluginManager pluginManager) {
4749
super(pluginManager, new PluginRequestHelper(pluginManager, SUPPORTED_VERSIONS, ARTIFACT_EXTENSION), ARTIFACT_EXTENSION);
48-
addHandler(ArtifactMessageConverterV1.VERSION, new ArtifactMessageConverterV1());
49-
registerHandler("1.0", new PluginSettingsJsonMessageHandler1_0());
50+
addHandler(V1, new ArtifactMessageConverterV1(), new PluginSettingsJsonMessageHandler1_0());
51+
addHandler(V2, new ArtifactMessageConverterV2(), new PluginSettingsJsonMessageHandler1_0());
5052
}
5153

52-
private void addHandler(String version, ArtifactMessageConverter extensionHandler) {
54+
private void addHandler(String version, ArtifactMessageConverter extensionHandler, PluginSettingsJsonMessageHandler pluginSettingsJsonMessageHandler) {
5355
messageHandlerMap.put(version, extensionHandler);
56+
registerHandler(version, pluginSettingsJsonMessageHandler);
5457
}
5558

5659
public com.thoughtworks.go.plugin.domain.artifact.Capabilities getCapabilities(String pluginId) {
@@ -192,12 +195,17 @@ protected List<String> goSupportedVersions() {
192195
}
193196

194197

195-
public void fetchArtifact(String pluginId, ArtifactStore artifactStore, Configuration configuration, Map<String, Object> metadata, String agentWorkingDirectory) {
196-
pluginRequestHelper.submitRequest(pluginId, REQUEST_FETCH_ARTIFACT, new DefaultPluginInteractionCallback<Void>() {
198+
public List<FetchArtifactEnvironmentVariable> fetchArtifact(String pluginId, ArtifactStore artifactStore, Configuration configuration, Map<String, Object> metadata, String agentWorkingDirectory) {
199+
return pluginRequestHelper.submitRequest(pluginId, REQUEST_FETCH_ARTIFACT, new DefaultPluginInteractionCallback<List<FetchArtifactEnvironmentVariable>>() {
197200
@Override
198201
public String requestBody(String resolvedExtensionVersion) {
199202
return getMessageHandler(resolvedExtensionVersion).fetchArtifactMessage(artifactStore, configuration, metadata, agentWorkingDirectory);
200203
}
204+
205+
@Override
206+
public List<FetchArtifactEnvironmentVariable> onSuccess(String responseBody, String resolvedExtensionVersion) {
207+
return getMessageHandler(resolvedExtensionVersion).getFetchArtifactEnvironmentVariablesFromResponseBody(responseBody);
208+
}
201209
});
202210
}
203211

plugin-infra/go-plugin-access/src/main/java/com/thoughtworks/go/plugin/access/artifact/ArtifactExtensionConstants.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
import java.util.List;
2121

2222
public interface ArtifactExtensionConstants {
23-
List<String> SUPPORTED_VERSIONS = Arrays.asList(ArtifactMessageConverterV1.VERSION);
23+
String V1 = "1.0";
24+
String V2 = "2.0";
25+
List<String> SUPPORTED_VERSIONS = Arrays.asList(V1, V2);
2426

2527
String REQUEST_PREFIX = "cd.go.artifact";
2628
String REQUEST_GET_CAPABILITIES = REQUEST_PREFIX + ".get-capabilities";

plugin-infra/go-plugin-access/src/main/java/com/thoughtworks/go/plugin/access/artifact/ArtifactMessageConverter.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.thoughtworks.go.domain.ArtifactPlan;
2121
import com.thoughtworks.go.domain.config.Configuration;
2222
import com.thoughtworks.go.plugin.access.artifact.model.PublishArtifactResponse;
23+
import com.thoughtworks.go.plugin.access.artifact.models.FetchArtifactEnvironmentVariable;
2324
import com.thoughtworks.go.plugin.api.response.validation.ValidationResult;
2425
import com.thoughtworks.go.plugin.domain.artifact.Capabilities;
2526
import com.thoughtworks.go.plugin.domain.common.Image;
@@ -47,4 +48,6 @@ String publishArtifactMessage(ArtifactPlan artifactPlan, ArtifactStore artifactS
4748
Image getImageResponseFromBody(String responseBody);
4849

4950
Capabilities getCapabilitiesFromResponseBody(String responseBody);
51+
52+
List<FetchArtifactEnvironmentVariable> getFetchArtifactEnvironmentVariablesFromResponseBody(String responseBody);
5053
}

plugin-infra/go-plugin-access/src/main/java/com/thoughtworks/go/plugin/access/artifact/ArtifactMessageConverterV1.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import com.thoughtworks.go.domain.ArtifactPlan;
2323
import com.thoughtworks.go.domain.config.Configuration;
2424
import com.thoughtworks.go.plugin.access.artifact.model.PublishArtifactResponse;
25+
import com.thoughtworks.go.plugin.access.artifact.models.FetchArtifactEnvironmentVariable;
2526
import com.thoughtworks.go.plugin.access.common.handler.JSONResultMessageHandler;
2627
import com.thoughtworks.go.plugin.access.common.models.ImageDeserializer;
2728
import com.thoughtworks.go.plugin.access.common.models.PluginProfileMetadataKeys;
@@ -30,12 +31,13 @@
3031
import com.thoughtworks.go.plugin.domain.common.PluginConfiguration;
3132
import org.apache.commons.lang3.StringUtils;
3233

34+
import java.util.ArrayList;
3335
import java.util.HashMap;
3436
import java.util.List;
3537
import java.util.Map;
3638

3739
public class ArtifactMessageConverterV1 implements ArtifactMessageConverter {
38-
public static final String VERSION = "1.0";
40+
public static final String VERSION = ArtifactExtensionConstants.V1;
3941
private static final Gson GSON = new GsonBuilder().serializeNulls().create();
4042

4143
@Override
@@ -101,6 +103,11 @@ public com.thoughtworks.go.plugin.domain.artifact.Capabilities getCapabilitiesFr
101103
return com.thoughtworks.go.plugin.access.artifact.models.Capabilities.fromJSON(responseBody).toCapabilities();
102104
}
103105

106+
@Override
107+
public List<FetchArtifactEnvironmentVariable> getFetchArtifactEnvironmentVariablesFromResponseBody(String responseBody) {
108+
return new ArrayList<>();
109+
}
110+
104111
private String getTemplateFromResponse(String responseBody, String message) {
105112
String template = (String) new Gson().fromJson(responseBody, Map.class).get("template");
106113
if (StringUtils.isBlank(template)) {
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
* Copyright 2018 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.plugin.access.artifact;
18+
19+
import com.google.gson.Gson;
20+
import com.google.gson.GsonBuilder;
21+
import com.google.gson.reflect.TypeToken;
22+
import com.thoughtworks.go.config.ArtifactStore;
23+
import com.thoughtworks.go.domain.ArtifactPlan;
24+
import com.thoughtworks.go.domain.config.Configuration;
25+
import com.thoughtworks.go.plugin.access.artifact.model.PublishArtifactResponse;
26+
import com.thoughtworks.go.plugin.access.artifact.models.FetchArtifactEnvironmentVariable;
27+
import com.thoughtworks.go.plugin.access.common.handler.JSONResultMessageHandler;
28+
import com.thoughtworks.go.plugin.access.common.models.ImageDeserializer;
29+
import com.thoughtworks.go.plugin.access.common.models.PluginProfileMetadataKeys;
30+
import com.thoughtworks.go.plugin.api.response.validation.ValidationResult;
31+
import com.thoughtworks.go.plugin.domain.common.Image;
32+
import com.thoughtworks.go.plugin.domain.common.PluginConfiguration;
33+
import org.apache.commons.lang3.StringUtils;
34+
35+
import java.util.ArrayList;
36+
import java.util.HashMap;
37+
import java.util.List;
38+
import java.util.Map;
39+
40+
public class ArtifactMessageConverterV2 implements ArtifactMessageConverter {
41+
public static final String VERSION = ArtifactExtensionConstants.V2;
42+
private static final Gson GSON = new GsonBuilder().serializeNulls().create();
43+
44+
@Override
45+
public String publishArtifactMessage(ArtifactPlan artifactPlan, ArtifactStore artifactStore, String agentWorkingDirectory,
46+
Map<String, String> environmentVariables) {
47+
final Map<String, Object> messageObject = new HashMap<>();
48+
messageObject.put("artifact_store", getArtifactStore(artifactStore));
49+
messageObject.put("artifact_plan", artifactPlan.getPluggableArtifactConfiguration());
50+
messageObject.put("agent_working_directory", agentWorkingDirectory);
51+
messageObject.put("environment_variables", environmentVariables);
52+
return GSON.toJson(messageObject);
53+
}
54+
55+
private Map getArtifactStore(ArtifactStore artifactStore) {
56+
final HashMap<String, Object> artifactStoreAndPlans = new HashMap<>();
57+
artifactStoreAndPlans.put("id", artifactStore.getId());
58+
artifactStoreAndPlans.put("configuration", artifactStore.getConfigurationAsMap(true));
59+
return artifactStoreAndPlans;
60+
}
61+
62+
@Override
63+
public PublishArtifactResponse publishArtifactResponse(String responseBody) {
64+
return PublishArtifactResponse.fromJSON(responseBody);
65+
}
66+
67+
@Override
68+
public List<PluginConfiguration> getMetadataResponseFromBody(String responseBody) {
69+
return PluginProfileMetadataKeys.fromJSON(responseBody).toPluginConfigurations();
70+
}
71+
72+
@Override
73+
public String getViewFromResponseBody(String responseBody, final String viewLabel) {
74+
return getTemplateFromResponse(responseBody, String.format("%s `template` was blank!", viewLabel));
75+
}
76+
77+
@Override
78+
public String validateConfigurationRequestBody(Map<String, String> configuration) {
79+
return GSON.toJson(configuration);
80+
}
81+
82+
@Override
83+
public ValidationResult getConfigurationValidationResultFromResponseBody(String responseBody) {
84+
return new JSONResultMessageHandler().toValidationResult(responseBody);
85+
}
86+
87+
@Override
88+
public String fetchArtifactMessage(ArtifactStore artifactStore, Configuration configuration, Map<String, Object> metadata, String agentWorkingDirectory) {
89+
final Map<String, Object> map = new HashMap<>();
90+
map.put("store_configuration", artifactStore.getConfigurationAsMap(true));
91+
map.put("fetch_artifact_configuration", configuration.getConfigurationAsMap(true));
92+
map.put("artifact_metadata", metadata);
93+
map.put("agent_working_directory", agentWorkingDirectory);
94+
return GSON.toJson(map);
95+
}
96+
97+
@Override
98+
public Image getImageResponseFromBody(String responseBody) {
99+
return new ImageDeserializer().fromJSON(responseBody);
100+
}
101+
102+
@Override
103+
public com.thoughtworks.go.plugin.domain.artifact.Capabilities getCapabilitiesFromResponseBody(String responseBody) {
104+
return com.thoughtworks.go.plugin.access.artifact.models.Capabilities.fromJSON(responseBody).toCapabilities();
105+
}
106+
107+
@Override
108+
public List<FetchArtifactEnvironmentVariable> getFetchArtifactEnvironmentVariablesFromResponseBody(String responseBody) {
109+
return new Gson().fromJson(responseBody, new TypeToken<List<FetchArtifactEnvironmentVariable>>() {}.getType());
110+
}
111+
112+
private String getTemplateFromResponse(String responseBody, String message) {
113+
String template = (String) new Gson().fromJson(responseBody, Map.class).get("template");
114+
if (StringUtils.isBlank(template)) {
115+
throw new RuntimeException(message);
116+
}
117+
return template;
118+
}
119+
}

0 commit comments

Comments
 (0)