diff --git a/.gitignore b/.gitignore index 27a013e6..439f20b5 100644 --- a/.gitignore +++ b/.gitignore @@ -54,11 +54,13 @@ github-pr-status/build gitlab-mr-status/build gerrit-cs-status/build stash-pr-status/build +gitea-pr-status/build common/out github-pr-status/out gitlab-mr-status/out gerrit-cs-status/out stash-pr-status/out +gitea-pr-status/out # App # diff --git a/README.md b/README.md index 9f594b39..036c4610 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ Supported: * GitHub Pull Request status * Stash Pull Request status * Gerrit Change Set status +* Gitea Pull Request status ## Requirements These plugins require GoCD version >= v15.x or above @@ -20,7 +21,7 @@ These plugins require GoCD version >= v15.x or above ## Configuration -- You will see `Github Pull Requests status notifier` / `Stash Pull Requests status notifier` / `Gerrit Change Set status notifier` / `GitLab Feature Branch status notifier` on plugin listing page +- You will see `Github Pull Requests status notifier` / `Stash Pull Requests status notifier` / `Gerrit Change Set status notifier` / `GitLab Feature Branch status notifier` / `Gitea Pull Requests status notifier` on plugin listing page ![Plugins listing page][1] - You can configure the plugin (this feature requires GoCD version >= v15.2, use system properties to configure the plugin). The details should be as follows: @@ -115,6 +116,18 @@ Eg: -Dgo.plugin.build.status.gitlab.oauth=XXXX ``` +#### Gitea +**Setup:** +- You need to provide `GoCD Base URL`, `Gitea Base URL`, `Username`, `Password` using the plugin configuration view. +- (or) through system property `go.plugin.build.status.go-server`, `go.plugin.build.status.gitea.endpoint`, `go.plugin.build.status.gitea.username`, `go.plugin.build.status.gitea.password`. +Eg: +``` +-Dgo.plugin.build.status.go-server=https://gitea.com +-Dgo.plugin.build.status.gitea.endpoint=https://gitea.com +-Dgo.plugin.build.status.gitea.username=johndoe +-Dgo.plugin.build.status.gitea.password=thisaintapassword +``` + ## FAQs [1]: images/list-plugin.png "List Plugin" diff --git a/gitea-pr-status/build.gradle b/gitea-pr-status/build.gradle new file mode 100644 index 00000000..24e89723 --- /dev/null +++ b/gitea-pr-status/build.gradle @@ -0,0 +1,40 @@ +/* + * Copyright 2019 ThoughtWorks, Inc. + * + * 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. + */ + +repositories { + mavenCentral() +} + +dependencies { + compile project(":common") + + testCompile 'org.mockito:mockito-core:3.8.0' + testCompile 'junit:junit:4.13.2' +} + +processResources { + doFirst { + project.pluginDesc.id = "gitea.pr.status" + project.pluginDesc.name = "Gitea Pull Requests status notifier" + project.pluginDesc.description = "Updates build status for Gitea pull request" + } + + from("src/main/resources") { + filesMatching('plugin.xml') { + expand project.pluginDesc + } + } +} diff --git a/gitea-pr-status/src/main/java/com/tw/go/plugin/GiteaBuildStatusNotifierPlugin.java b/gitea-pr-status/src/main/java/com/tw/go/plugin/GiteaBuildStatusNotifierPlugin.java new file mode 100644 index 00000000..cd66bf95 --- /dev/null +++ b/gitea-pr-status/src/main/java/com/tw/go/plugin/GiteaBuildStatusNotifierPlugin.java @@ -0,0 +1,33 @@ +/* + * Copyright 2019 ThoughtWorks, Inc. + * + * 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.tw.go.plugin; + +import com.thoughtworks.go.plugin.api.annotation.Extension; +import com.tw.go.plugin.provider.Provider; +import com.tw.go.plugin.provider.GiteaProvider; + +@Extension +public class GiteaBuildStatusNotifierPlugin extends BuildStatusNotifierPlugin { + @Override + protected Provider loadProvider() { + try { + return new GiteaProvider(); + } catch (Exception e) { + throw new RuntimeException("could not create provider", e); + } + } +} diff --git a/gitea-pr-status/src/main/java/com/tw/go/plugin/provider/GiteaConfigurationView.java b/gitea-pr-status/src/main/java/com/tw/go/plugin/provider/GiteaConfigurationView.java new file mode 100644 index 00000000..ef624110 --- /dev/null +++ b/gitea-pr-status/src/main/java/com/tw/go/plugin/provider/GiteaConfigurationView.java @@ -0,0 +1,46 @@ +/* + * Copyright 2019 ThoughtWorks, Inc. + * + * 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.tw.go.plugin.provider; + +import com.tw.go.plugin.setting.PluginConfigurationView; + +import java.util.HashMap; +import java.util.Map; + +import static com.tw.go.plugin.setting.DefaultPluginConfigurationView.PLUGIN_SETTINGS_SERVER_BASE_URL; +import static com.tw.go.plugin.setting.DefaultPluginConfigurationView.PLUGIN_SETTINGS_END_POINT; +import static com.tw.go.plugin.setting.DefaultPluginConfigurationView.PLUGIN_SETTINGS_USERNAME; +import static com.tw.go.plugin.setting.DefaultPluginConfigurationView.PLUGIN_SETTINGS_PASSWORD; +import static com.tw.go.plugin.util.ConfigurationUtils.createField; + +public class GiteaConfigurationView implements PluginConfigurationView { + + @Override + public String templateName() { + return "plugin-settings-gitea.template.html"; + } + + @Override + public Map fields() { + Map response = new HashMap(); + response.put(PLUGIN_SETTINGS_SERVER_BASE_URL, createField("GoCD Base URL", null, true, false, "0")); + response.put(PLUGIN_SETTINGS_END_POINT, createField("Gitea Base URL", null, true, false, "1")); + response.put(PLUGIN_SETTINGS_USERNAME, createField("Username", null, true, false, "2")); + response.put(PLUGIN_SETTINGS_PASSWORD, createField("Password", null, true, true, "3")); + return response; + } +} diff --git a/gitea-pr-status/src/main/java/com/tw/go/plugin/provider/GiteaProvider.java b/gitea-pr-status/src/main/java/com/tw/go/plugin/provider/GiteaProvider.java new file mode 100644 index 00000000..92a031b1 --- /dev/null +++ b/gitea-pr-status/src/main/java/com/tw/go/plugin/provider/GiteaProvider.java @@ -0,0 +1,177 @@ +/* + * Copyright 2019 ThoughtWorks, Inc. + * + * 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.tw.go.plugin.provider; + +import com.tw.go.plugin.setting.PluginSettings; +import com.tw.go.plugin.util.AuthenticationType; +import com.tw.go.plugin.util.HTTPClient; +import com.tw.go.plugin.util.JSONUtils; +import org.apache.commons.lang3.StringUtils; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static com.tw.go.plugin.setting.DefaultPluginConfigurationView.PLUGIN_SETTINGS_SERVER_BASE_URL; +import static com.tw.go.plugin.setting.DefaultPluginConfigurationView.PLUGIN_SETTINGS_END_POINT; +import static com.tw.go.plugin.setting.DefaultPluginConfigurationView.PLUGIN_SETTINGS_USERNAME; +import static com.tw.go.plugin.setting.DefaultPluginConfigurationView.PLUGIN_SETTINGS_PASSWORD; +import static com.tw.go.plugin.util.ValidationUtils.getValidationError; + +public class GiteaProvider extends DefaultProvider { + public static final String PLUGIN_ID = "gitea.pr.status"; + public static final String GIT_FB_POLLER_PLUGIN_ID = "git.fb"; + public static final String STATUS_CONTEXT = "GoCD"; + + private final HTTPClient httpClient; + + public GiteaProvider() { + super(new GiteaConfigurationView()); + httpClient = new HTTPClient(); + } + + public GiteaProvider(HTTPClient httpClient) { + super(new GiteaConfigurationView()); + this.httpClient = httpClient; + } + + @Override + public String pluginId() { + return PLUGIN_ID; + } + + @Override + public String pollerPluginId() { + return GIT_FB_POLLER_PLUGIN_ID; + } + + @Override + public List> validateConfig(Map fields) { + List> errors = new ArrayList<>(); + + if (!validateUrl(getValueFromPluginSettings(fields.get(PLUGIN_SETTINGS_SERVER_BASE_URL)))) { + errors.add(getValidationError( + PLUGIN_SETTINGS_SERVER_BASE_URL, + "GoCD base url not set correctly" + )); + } + if (!validateUrl(getValueFromPluginSettings(fields.get(PLUGIN_SETTINGS_END_POINT)))) { + errors.add(getValidationError( + PLUGIN_SETTINGS_END_POINT, + "Gitea base url not set correctly" + )); + } + if (getValueFromPluginSettings(fields.get(PLUGIN_SETTINGS_USERNAME)).equals("")) { + errors.add(getValidationError( + PLUGIN_SETTINGS_USERNAME, + "Gitea Username not set correctly" + )); + } + if (getValueFromPluginSettings(fields.get(PLUGIN_SETTINGS_PASSWORD)).equals("")) { + errors.add(getValidationError( + PLUGIN_SETTINGS_PASSWORD, + "Gitea Password not set correctly" + )); + } + + return errors; + } + + @Override + public void updateStatus(String url, PluginSettings pluginSettings, String branch, String revision, String pipelineStage, + String result, String trackbackURL) throws Exception { + String giteaBaseURL = pluginSettings.getEndPoint(); + String username = pluginSettings.getUsername(); + String password = pluginSettings.getPassword(); + + if (StringUtils.isEmpty(giteaBaseURL)) { + giteaBaseURL = System.getProperty("go.plugin.build.status.gitea.endpoint"); + } + if (StringUtils.isEmpty(username)) { + username = System.getProperty("go.plugin.build.status.gitea.username"); + } + if (StringUtils.isEmpty(password)) { + password = System.getProperty("go.plugin.build.status.gitea.password"); + } + + String updateURL = formUpdateURL(giteaBaseURL, url, revision); + Map request = new HashMap<>(); + request.put("context", STATUS_CONTEXT); + request.put("description", GiteaState.descriptionFor(result)); + request.put("state", GiteaState.stateFor(result)); + request.put("target_url", trackbackURL); + String requestBody = JSONUtils.toJSON(request); + + httpClient.postRequest(updateURL, AuthenticationType.BASIC, username, password, requestBody); + } + + private String getValueFromPluginSettings(Object values) { + if (values == null) { + return ""; + } + Map vals = (Map) values; + String ret = vals.get("value"); + if (ret == null) { + return ""; + } + return ret; + } + + private boolean validateUrl(String uri) { + try { + new URL(uri); + } catch (MalformedURLException e) { + return false; + } + return true; + } + + public String formUpdateURL(String gitServerBaseURL, String url, String revision) { + if (gitServerBaseURL.endsWith("/")) { + gitServerBaseURL = gitServerBaseURL.substring(0, gitServerBaseURL.length() - 1); + } + return String.format("%s/api/v1/repos/%s/statuses/%s", gitServerBaseURL, getRepository(url), revision); + } + + public String getRepository(String url) { + String repoPath = null; + + String sshProtocolString = "(.*)@(.*):(.*?)(/*)$"; + Pattern sshPattern = Pattern.compile(sshProtocolString); + Matcher sshMatcher = sshPattern.matcher(url); + if (sshMatcher.find()) { + repoPath = sshMatcher.group(3); + } + + String httpProtocolString = "http(.?)://(.*?)/(.*?)(/*)$"; + Pattern httpPattern = Pattern.compile(httpProtocolString); + Matcher httpMatcher = httpPattern.matcher(url); + if (httpMatcher.find()) { + repoPath = httpMatcher.group(3); + } + + if (!StringUtils.isEmpty(repoPath) && repoPath.endsWith(".git")) { + repoPath = repoPath.substring(0, repoPath.length() - 4); + } + return repoPath; + } +} diff --git a/gitea-pr-status/src/main/java/com/tw/go/plugin/provider/GiteaState.java b/gitea-pr-status/src/main/java/com/tw/go/plugin/provider/GiteaState.java new file mode 100644 index 00000000..b0e73fca --- /dev/null +++ b/gitea-pr-status/src/main/java/com/tw/go/plugin/provider/GiteaState.java @@ -0,0 +1,57 @@ +/* + * Copyright 2019 ThoughtWorks, Inc. + * + * 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.tw.go.plugin.provider; + +public class GiteaState { + private static final String PENDING = "pending"; + private static final String PENDING_DESCRIPTION = "Build is pending"; + private static final String SUCCESS = "success"; + private static final String SUCCESS_DESCRIPTION = "Build is passing"; + private static final String FAILURE = "failure"; + private static final String FAILURE_DESCRIPTION = "Build is failing"; + private static final String ERROR = "error"; + private static final String ERROR_DESCRIPTION = "Build encountered an error"; + + public GiteaState() { + } + + static String stateFor(String result) { + result = result == null ? "" : result; + String state = PENDING; + if (result.equalsIgnoreCase("Passed")) { + state = SUCCESS; + } else if (result.equalsIgnoreCase("Failed")) { + state = FAILURE; + } else if (result.equalsIgnoreCase("Cancelled")) { + state = ERROR; + } + return state; + } + + static String descriptionFor(String result) { + result = result == null ? "" : result; + String description = PENDING_DESCRIPTION; + if (result.equalsIgnoreCase("Passed")) { + description = SUCCESS_DESCRIPTION; + } else if (result.equalsIgnoreCase("Failed")) { + description = FAILURE_DESCRIPTION; + } else if (result.equalsIgnoreCase("Cancelled")) { + description = ERROR_DESCRIPTION; + } + return description; + } +} diff --git a/gitea-pr-status/src/main/resources/defaults.properties b/gitea-pr-status/src/main/resources/defaults.properties new file mode 100644 index 00000000..3dbafbd2 --- /dev/null +++ b/gitea-pr-status/src/main/resources/defaults.properties @@ -0,0 +1,17 @@ +# +# Copyright 2019 ThoughtWorks, Inc. +# +# 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. +# + +provider=com.tw.go.plugin.provider.GiteaProvider \ No newline at end of file diff --git a/gitea-pr-status/src/main/resources/plugin-settings-gitea.template.html b/gitea-pr-status/src/main/resources/plugin-settings-gitea.template.html new file mode 100644 index 00000000..c1c63b23 --- /dev/null +++ b/gitea-pr-status/src/main/resources/plugin-settings-gitea.template.html @@ -0,0 +1,35 @@ + +
+ + + {{ GOINPUTNAME[server_base_url].$error.server }} +
+
+ + + {{ GOINPUTNAME[end_point].$error.server }} +
+
+ + + {{ GOINPUTNAME[username].$error.server }} +
+
+ + + {{ GOINPUTNAME[password].$error.server }} +
\ No newline at end of file diff --git a/gitea-pr-status/src/main/resources/plugin.xml b/gitea-pr-status/src/main/resources/plugin.xml new file mode 100644 index 00000000..9f902100 --- /dev/null +++ b/gitea-pr-status/src/main/resources/plugin.xml @@ -0,0 +1,29 @@ + + + + + + ${name} + ${version} + ${goCdVersion} + ${description} + + ${vendorName} + ${vendorUrl} + + + diff --git a/gitea-pr-status/src/test/java/com/tw/go/plugin/GiteaBuildStatusNotifierPluginTest.java b/gitea-pr-status/src/test/java/com/tw/go/plugin/GiteaBuildStatusNotifierPluginTest.java new file mode 100644 index 00000000..a66ef818 --- /dev/null +++ b/gitea-pr-status/src/test/java/com/tw/go/plugin/GiteaBuildStatusNotifierPluginTest.java @@ -0,0 +1,272 @@ +/* + * Copyright 2019 ThoughtWorks, Inc. + * + * 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.tw.go.plugin; + +import com.google.gson.Gson; +import com.thoughtworks.go.plugin.api.GoApplicationAccessor; +import com.thoughtworks.go.plugin.api.request.DefaultGoPluginApiRequest; +import com.thoughtworks.go.plugin.api.request.GoApiRequest; +import com.thoughtworks.go.plugin.api.request.GoPluginApiRequest; +import com.thoughtworks.go.plugin.api.response.DefaultGoApiResponse; +import com.tw.go.plugin.provider.GiteaProvider; +import com.tw.go.plugin.provider.Provider; +import com.tw.go.plugin.setting.PluginConfigurationView; +import com.tw.go.plugin.setting.PluginSettings; +import com.tw.go.plugin.util.JSONUtils; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static com.tw.go.plugin.BuildStatusNotifierPlugin.PLUGIN_SETTINGS_GET_CONFIGURATION; +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.*; +import static org.mockito.MockitoAnnotations.initMocks; + +public class GiteaBuildStatusNotifierPluginTest { + public static final String PLUGIN_ID = "gitea-plugin"; + public static final String POLLER_PLUGIN_ID = "gitea-poller-plugin-id"; + @Mock + private GoApplicationAccessor goApplicationAccessor; + @Mock + private Provider provider; + + private BuildStatusNotifierPlugin plugin; + + @Before + public void setUp() { + initMocks(this); + + plugin = new GiteaBuildStatusNotifierPlugin(); + + DefaultGoApiResponse pluginSettingsResponse = new DefaultGoApiResponse(200); + pluginSettingsResponse.setResponseBody(JSONUtils.toJSON(new HashMap())); + when(goApplicationAccessor.submit(any(GoApiRequest.class))).thenReturn(pluginSettingsResponse); + when(provider.pluginId()).thenReturn(PLUGIN_ID); + when(provider.pollerPluginId()).thenReturn(POLLER_PLUGIN_ID); + + plugin.initializeGoApplicationAccessor(goApplicationAccessor); + plugin.setProvider(provider); + } + + @Test + public void shouldRegisterForStageStatusChange() { + assertThat(plugin.handleNotificationsInterestedIn().responseBody(), is("{\"notifications\":[\"stage-status\"]}")); + } + + @Test + public void shouldDelegateUpdateStatusToProviderWithCorrectParameters() throws Exception { + PluginSettings mockSettings = mock(PluginSettings.class); + when(plugin.getPluginSettings()).thenReturn(mockSettings); + + String expectedURL = "url"; + String expectedUsername = "username"; + String expectedRevision = "sha-1"; + String expectedPRId = "1"; + String pipelineName = "pipeline"; + String pipelineCounter = "1"; + String stageName = "stage"; + String stageCounter = "1"; + String expectedPipelineStage = String.format("%s/%s", pipelineName, stageName); + String expectedPipelineInstance = String.format("%s/%s/%s/%s", pipelineName, pipelineCounter, stageName, stageCounter); + String expectedStageResult = "Passed"; + + Map requestBody = createRequestBodyMap(expectedURL, expectedUsername, expectedRevision, expectedPRId, pipelineName, pipelineCounter, stageName, stageCounter, expectedStageResult); + plugin.handleStageNotification(createGoPluginAPIRequest(requestBody)); + + verify(provider).updateStatus(eq(expectedURL), any(PluginSettings.class), eq("1"), eq(expectedRevision), eq(expectedPipelineStage), eq(expectedStageResult), eq("http://localhost:8153/go/pipelines/" + expectedPipelineInstance)); + } + + @Test + public void shouldDelegateUpdateStatusToProviderWithCorrectParametersWithoutPrID() throws Exception { + PluginSettings mockSettings = mock(PluginSettings.class); + when(plugin.getPluginSettings()).thenReturn(mockSettings); + + String expectedURL = "url"; + String expectedUsername = "username"; + String expectedRevision = "sha-1"; + String expectedBranch = "test-branch"; + String pipelineName = "pipeline"; + String pipelineCounter = "1"; + String stageName = "stage"; + String stageCounter = "1"; + String expectedPipelineStage = String.format("%s/%s", pipelineName, stageName); + String expectedPipelineInstance = String.format("%s/%s/%s/%s", pipelineName, pipelineCounter, stageName, stageCounter); + String expectedStageResult = "Passed"; + + Map requestBody = createRequestBodyMapWithBranch(expectedURL, expectedUsername, expectedRevision, expectedBranch, pipelineName, pipelineCounter, stageName, stageCounter, expectedStageResult); + plugin.handleStageNotification(createGoPluginAPIRequest(requestBody)); + + verify(provider).updateStatus(eq(expectedURL), any(PluginSettings.class), eq("test-branch"), eq(expectedRevision), eq(expectedPipelineStage), eq(expectedStageResult), eq("http://localhost:8153/go/pipelines/" + expectedPipelineInstance)); + } + + @Test + public void shouldReturnPluginSettings() throws Exception { + Provider mockProvider = mock(Provider.class); + PluginConfigurationView mockConfigView = mock(PluginConfigurationView.class); + when(mockProvider.configurationView()).thenReturn(mockConfigView); + Map fields = new HashMap(); + when(mockConfigView.fields()).thenReturn(fields); + + plugin.setProvider(mockProvider); + + Map configuration = new Gson().fromJson( + plugin.handle(createRequest(PLUGIN_SETTINGS_GET_CONFIGURATION) + ).responseBody(), Map.class); + + assertThat(configuration, is(fields)); + } + + private GoPluginApiRequest createRequest(final String name) { + return new GoPluginApiRequest() { + @Override + public String extension() { + return null; + } + + @Override + public String extensionVersion() { + return null; + } + + @Override + public String requestName() { + return name; + } + + @Override + public Map requestParameters() { + return null; + } + + @Override + public Map requestHeaders() { + return null; + } + + @Override + public String requestBody() { + return null; + } + }; + } + + private Map createRequestBodyMap(String url, String username, String revision, String prId, String pipelineName, String pipelineCounter, String stageName, String stageCounter, String stageResult) { + Map materialRevisionMap = new HashMap(); + Map materialMap = new HashMap(); + materialMap.put("type", "scm"); + materialMap.put("plugin-id", POLLER_PLUGIN_ID); + Map configurationMap = new HashMap(); + configurationMap.put("url", url); + configurationMap.put("username", username); + materialMap.put("scm-configuration", configurationMap); + materialRevisionMap.put("material", materialMap); + + List modifications = new ArrayList(); + Map modificationMap = new HashMap(); + modificationMap.put("revision", revision); + Map modificationDataMap = new HashMap(); + modificationDataMap.put("PR_ID", prId); + modificationMap.put("data", modificationDataMap); + modifications.add(modificationMap); + materialRevisionMap.put("modifications", modifications); + + Map pipelineMap = new HashMap(); + List buildCause = new ArrayList(); + buildCause.add(materialRevisionMap); + pipelineMap.put("build-cause", buildCause); + + Map stageMap = new HashMap(); + stageMap.put("name", stageName); + stageMap.put("counter", stageCounter); + stageMap.put("result", stageResult); + pipelineMap.put("stage", stageMap); + + pipelineMap.put("name", pipelineName); + pipelineMap.put("counter", pipelineCounter); + + Map requestBody = new HashMap(); + requestBody.put("pipeline", pipelineMap); + return requestBody; + } + + @Test + public void shouldReturnCorrectConfigForGiteaPlugin() throws Exception { + plugin.setProvider(new GiteaProvider()); + + Map configuration = new Gson().fromJson(plugin.handle(createRequest(PLUGIN_SETTINGS_GET_CONFIGURATION)).responseBody(), Map.class); + + assertThat(configuration.containsKey("server_base_url"), is(true)); + assertThat(configuration.containsKey("end_point"), is(true)); + assertThat(configuration.containsKey("username"), is(true)); + assertThat(configuration.containsKey("password"), is(true)); + assertThat(configuration.containsKey("oauth_token"), is(false)); + assertThat(configuration.containsKey("review_label"), is(false)); + } + + private Map createRequestBodyMapWithBranch(String url, String username, String revision, String branch, String pipelineName, String pipelineCounter, String stageName, String stageCounter, String stageResult) { + Map materialRevisionMap = new HashMap(); + Map materialMap = new HashMap(); + materialMap.put("type", "scm"); + materialMap.put("plugin-id", POLLER_PLUGIN_ID); + Map configurationMap = new HashMap(); + configurationMap.put("url", url); + configurationMap.put("username", username); + materialMap.put("scm-configuration", configurationMap); + materialRevisionMap.put("material", materialMap); + + List modifications = new ArrayList(); + Map modificationMap = new HashMap(); + modificationMap.put("revision", revision); + Map modificationDataMap = new HashMap(); + modificationDataMap.put("CURRENT_BRANCH", branch); + modificationMap.put("data", modificationDataMap); + modifications.add(modificationMap); + materialRevisionMap.put("modifications", modifications); + + Map pipelineMap = new HashMap(); + List buildCause = new ArrayList(); + buildCause.add(materialRevisionMap); + pipelineMap.put("build-cause", buildCause); + + Map stageMap = new HashMap(); + stageMap.put("name", stageName); + stageMap.put("counter", stageCounter); + stageMap.put("result", stageResult); + pipelineMap.put("stage", stageMap); + + pipelineMap.put("name", pipelineName); + pipelineMap.put("counter", pipelineCounter); + + Map requestBody = new HashMap(); + requestBody.put("pipeline", pipelineMap); + return requestBody; + } + + private DefaultGoPluginApiRequest createGoPluginAPIRequest(Map requestBody) { + DefaultGoPluginApiRequest request = new DefaultGoPluginApiRequest(BuildStatusNotifierPlugin.EXTENSION_NAME, "1.0", BuildStatusNotifierPlugin.REQUEST_STAGE_STATUS); + request.setRequestBody(JSONUtils.toJSON(requestBody)); + return request; + } +} diff --git a/gitea-pr-status/src/test/java/com/tw/go/plugin/provider/GiteaConfigurationViewTest.java b/gitea-pr-status/src/test/java/com/tw/go/plugin/provider/GiteaConfigurationViewTest.java new file mode 100644 index 00000000..f7ceb48c --- /dev/null +++ b/gitea-pr-status/src/test/java/com/tw/go/plugin/provider/GiteaConfigurationViewTest.java @@ -0,0 +1,55 @@ +/* + * Copyright 2019 ThoughtWorks, Inc. + * + * 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.tw.go.plugin.provider; + +import org.junit.Before; +import org.junit.Test; + +import java.util.HashSet; +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static com.tw.go.plugin.setting.DefaultPluginConfigurationView.PLUGIN_SETTINGS_SERVER_BASE_URL; +import static com.tw.go.plugin.setting.DefaultPluginConfigurationView.PLUGIN_SETTINGS_END_POINT; +import static com.tw.go.plugin.setting.DefaultPluginConfigurationView.PLUGIN_SETTINGS_USERNAME; +import static com.tw.go.plugin.setting.DefaultPluginConfigurationView.PLUGIN_SETTINGS_PASSWORD; + + +public class GiteaConfigurationViewTest { + + private GiteaConfigurationView view; + + @Before + public void setUp() { + view = new GiteaConfigurationView(); + } + + @Test + public void checkExpectedFields() throws Exception { + Set expected = new HashSet(); + expected.add(PLUGIN_SETTINGS_SERVER_BASE_URL); + expected.add(PLUGIN_SETTINGS_END_POINT); + expected.add(PLUGIN_SETTINGS_USERNAME); + expected.add(PLUGIN_SETTINGS_PASSWORD); + assertEquals(expected, view.fields().keySet()); + } + + @Test + public void checkTemplateName() throws Exception { + assertEquals("plugin-settings-gitea.template.html", view.templateName()); + } +} diff --git a/gitea-pr-status/src/test/java/com/tw/go/plugin/provider/GiteaProviderTest.java b/gitea-pr-status/src/test/java/com/tw/go/plugin/provider/GiteaProviderTest.java new file mode 100644 index 00000000..091090ed --- /dev/null +++ b/gitea-pr-status/src/test/java/com/tw/go/plugin/provider/GiteaProviderTest.java @@ -0,0 +1,162 @@ +/* + * Copyright 2019 ThoughtWorks, Inc. + * + * 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.tw.go.plugin.provider; + +import com.google.gson.internal.LinkedHashTreeMap; +import com.tw.go.plugin.setting.DefaultPluginSettings; +import com.tw.go.plugin.util.AuthenticationType; +import com.tw.go.plugin.util.HTTPClient; +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static com.tw.go.plugin.setting.DefaultPluginConfigurationView.PLUGIN_SETTINGS_SERVER_BASE_URL; +import static com.tw.go.plugin.setting.DefaultPluginConfigurationView.PLUGIN_SETTINGS_END_POINT; +import static com.tw.go.plugin.setting.DefaultPluginConfigurationView.PLUGIN_SETTINGS_USERNAME; +import static com.tw.go.plugin.setting.DefaultPluginConfigurationView.PLUGIN_SETTINGS_PASSWORD; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +public class GiteaProviderTest { + DefaultPluginSettings pluginSettings; + HTTPClient mockHttpClient; + GiteaProvider provider; + + private static final String serverBaseURL = "https://gocd-server.com"; + private static final String endpoint = "https://www.test-gitea.com"; + private static final String testUser = "testUser"; + private static final String testPassword = "testPassword"; + + @Before + public void setUp() throws Exception { + pluginSettings = new DefaultPluginSettings(); + pluginSettings.setServerBaseURL(serverBaseURL); + pluginSettings.setEndPoint(endpoint); + pluginSettings.setUsername(testUser); + pluginSettings.setPassword(testPassword); + mockHttpClient = mock(HTTPClient.class); + + provider = new GiteaProvider(mockHttpClient); + } + + @Test + public void checkIdsMatch() throws Exception { + assertEquals("gitea.pr.status", provider.pluginId()); + assertEquals("git.fb", provider.pollerPluginId()); + } + + @Test + public void checkValidationWithValidValues() throws Exception { + Map config = new LinkedHashTreeMap(); + List> errors = new ArrayList>(); + + Map dummyUrl = new LinkedHashTreeMap(); + dummyUrl.put("value", "http://localhost:8153"); + + Map dummyUsername = new LinkedHashTreeMap(); + dummyUsername.put("value", "testUser"); + + Map dummyPassword = new LinkedHashTreeMap(); + dummyPassword.put("value", "testPassword"); + + config.put(PLUGIN_SETTINGS_SERVER_BASE_URL, dummyUrl); + config.put(PLUGIN_SETTINGS_END_POINT, dummyUrl); + config.put(PLUGIN_SETTINGS_USERNAME, dummyUsername); + config.put(PLUGIN_SETTINGS_PASSWORD, dummyPassword); + + List> returnedErrors = provider.validateConfig(config); + assertEquals(errors, returnedErrors); + } + + @Test + public void checkValidationWithInvalidValues() throws Exception { + Map config = new LinkedHashTreeMap(); + + Map dummyUrl = new LinkedHashTreeMap(); + dummyUrl.put("value", "invalid"); + + Map dummyUsername = new LinkedHashTreeMap(); + dummyUsername.put("value", ""); + + Map dummyPassword = new LinkedHashTreeMap(); + dummyPassword.put("value", ""); + + config.put(PLUGIN_SETTINGS_SERVER_BASE_URL, dummyUrl); + config.put(PLUGIN_SETTINGS_END_POINT, dummyUrl); + config.put(PLUGIN_SETTINGS_USERNAME, dummyUsername); + config.put(PLUGIN_SETTINGS_PASSWORD, dummyPassword); + + List> returnedErrors = provider.validateConfig(config); + assertEquals(4, returnedErrors.size()); + } + + @Test + public void shouldGetRepositoryFromURL() { + assertThat(provider.getRepository("http://gitea.com/group/sample-repo"), is("group/sample-repo")); + assertThat(provider.getRepository("http://gitea.com/group/sample-repo.git"), is("group/sample-repo")); + assertThat(provider.getRepository("http://gitea.com/group/sample-repo/"), is("group/sample-repo")); + assertThat(provider.getRepository("http://gitea.com/group/sample-repo.git/"), is("group/sample-repo")); + assertThat(provider.getRepository("https://gitea.com/group/sample-repo"), is("group/sample-repo")); + assertThat(provider.getRepository("https://gitea.com/group/sample-repo.git"), is("group/sample-repo")); + assertThat(provider.getRepository("git@code.corp.yourcompany.com:group/sample-repo"), is("group/sample-repo")); + assertThat(provider.getRepository("git@code.corp.yourcompany.com:group/sample-repo.git"), is("group/sample-repo")); + assertThat(provider.getRepository("git@gitea.com:group/sample-repo.git"), is("group/sample-repo")); + assertThat(provider.getRepository("http://gitea.com/group/sub-group/sample-repo.git/"), is("group/sub-group/sample-repo")); + assertThat(provider.getRepository("https://gitea.com/group/sub-group/another-sub-group/sample-repo"), is("group/sub-group/another-sub-group/sample-repo")); + } + + @Test + public void checkFormUpdateURL() throws Exception { + String gitServerBaseURL = "https://www.test-gitea.com"; + String gitServerBaseURLWithEndingSlash = "https://www.test-gitea.com/"; + String repositoryURL = "https://www.test-gitea.com/test-owner/test-repo"; + String commitRevision = "revValue"; + + assertThat(provider.formUpdateURL(gitServerBaseURL, repositoryURL, commitRevision), is("https://www.test-gitea.com/api/v1/repos/test-owner/test-repo/statuses/revValue")); + assertThat(provider.formUpdateURL(gitServerBaseURLWithEndingSlash, repositoryURL, commitRevision), is("https://www.test-gitea.com/api/v1/repos/test-owner/test-repo/statuses/revValue")); + } + + @Test + public void shouldUpdateStatusForPR() throws Exception { + provider.updateStatus("https://www.test-gitea.com/test-owner/test-repo", + pluginSettings, + "test-branch", + "revValue", + "pipeline-name/stage-name", + "Passed", + "http://localhost:8153/go/pipelines/pipeline-name/1/stage-name/1"); + + verify(mockHttpClient).postRequest( + "https://www.test-gitea.com/api/v1/repos/test-owner/test-repo/statuses/revValue", + AuthenticationType.BASIC, + testUser, + testPassword, + "{" + + "\"target_url\":\"http://localhost:8153/go/pipelines/pipeline-name/1/stage-name/1\"," + + "\"context\":\"GoCD\"," + + "\"description\":\"Build is passing\"," + + "\"state\":\"success\"" + + "}" + ); + } +} diff --git a/gitea-pr-status/src/test/java/com/tw/go/plugin/provider/GiteaStateTest.java b/gitea-pr-status/src/test/java/com/tw/go/plugin/provider/GiteaStateTest.java new file mode 100644 index 00000000..5524a1e4 --- /dev/null +++ b/gitea-pr-status/src/test/java/com/tw/go/plugin/provider/GiteaStateTest.java @@ -0,0 +1,41 @@ +/* + * Copyright 2019 ThoughtWorks, Inc. + * + * 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.tw.go.plugin.provider; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class GiteaStateTest { + @Test + public void checkStates() throws Exception { + assertEquals("pending", GiteaState.stateFor("unknown")); + assertEquals("pending", GiteaState.stateFor(null)); + assertEquals("success", GiteaState.stateFor("Passed")); + assertEquals("failure", GiteaState.stateFor("Failed")); + assertEquals("error", GiteaState.stateFor("Cancelled")); + } + + @Test + public void checkDescriptions() throws Exception { + assertEquals("Build is pending", GiteaState.descriptionFor("unknown")); + assertEquals("Build is pending", GiteaState.descriptionFor(null)); + assertEquals("Build is passing", GiteaState.descriptionFor("Passed")); + assertEquals("Build is failing", GiteaState.descriptionFor("Failed")); + assertEquals("Build encountered an error", GiteaState.descriptionFor("Cancelled")); + } +} diff --git a/settings.gradle b/settings.gradle index 9fe35d18..6ec7272d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -19,3 +19,4 @@ include 'github-pr-status' include 'stash-pr-status' include 'gerrit-cs-status' include 'gitlab-mr-status' +include 'gitea-pr-status'