Merge branch 'stable-2.16' into stable-3.0 * stable-2.16: Add its-jira configuration to the new PolyGerrit UI Since stable-3.0, this change is not needed because PolyGerrit UI binds automatically the configuration fields of the plugins. Change-Id: I14b793907abc2222e20a3b28abbab056a5124509
diff --git a/BUILD b/BUILD index 6f00197..eca48a1 100644 --- a/BUILD +++ b/BUILD
@@ -5,8 +5,6 @@ "PLUGIN_DEPS", "PLUGIN_TEST_DEPS", ) -load("//tools/bzl:genrule2.bzl", "genrule2") -load("//tools/bzl:js.bzl", "polygerrit_plugin") gerrit_plugin( name = "its-jira", @@ -19,36 +17,12 @@ "Implementation-Title: Jira ITS Plugin", "Implementation-URL: http://www.gerritforge.com", ], - resource_jars = [":cs-its-jira-static"], resources = glob(["src/main/resources/**/*"]), deps = [ "//plugins/its-base", ], ) -genrule2( - name = "cs-its-jira-static", - srcs = [ - ":cs-its-jira-config", - ], - outs = ["cs-its-jira-static.jar"], - cmd = " && ".join([ - "mkdir $$TMP/static", - "cp -r $(locations :cs-its-jira-config) $$TMP/static", - "cd $$TMP", - "zip -Drq $$ROOT/$@ -g .", - ]), -) - -polygerrit_plugin( - name = "cs-its-jira-config", - srcs = glob([ - "cs-its-jira-config/*.html", - "cs-its-jira-config/*.js", - ]), - app = "plugin-config.html", -) - junit_tests( name = "its_jira_tests", testonly = 1,
diff --git a/cs-its-jira-config/cs-its-jira-config.html b/cs-its-jira-config/cs-its-jira-config.html deleted file mode 100644 index c4f9f41..0000000 --- a/cs-its-jira-config/cs-its-jira-config.html +++ /dev/null
@@ -1,82 +0,0 @@ -<!-- -@license -Copyright (C) 2021 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. ---> - -<dom-module id="cs-its-jira-config"> - <template> - <style include="shared-styles"></style> - <style include="gr-form-styles"></style> - <fieldset class="gr-form-styles"> - <h2 class="sectionTitle">its-jira plugin</h2> - <section> - <section> - <span class="title">Enable its-jira integration</span> - <span class="value"> - <gr-select id="enabled" - bind-value="{{_changedConfig.enabled.value}}" - on-change="_handlePrefsChanged"> - <select disabled$="[[readOnly]]"> - <option value="true">true</option> - <option value="false">false</option> - <option value="enforced">enforced</option> - </select> - </gr-select> - </span> - </section> - <section> - <span class="title">Server URL</span> - <span class="value"> - <iron-input bind-value="{{_changedConfig.instanceUrl.value}}"> - <input id="instanceUrl" - value="{{_changedConfig.instanceUrl.value::input}}" - on-keypress="_handlePrefsChanged" - on-change="_handlePrefsChanged" - type="text"> - </iron-input> - </span> - </section> - <section> - <span class="title">JIRA username</span> - <span class="value"> - <iron-input bind-value="{{_changedConfig.username.value}}"> - <input id="username" - value="{{_changedConfig.username.value::input}}" - on-keypress="_handlePrefsChanged" - on-change="_handlePrefsChanged" - type="text"> - </iron-input> - </span> - </section> - <section> - <span class="title">JIRA password</span> - <span class="value"> - <iron-input bind-value="{{_changedConfig.password.value}}"> - <input id="password" - value="{{_changedConfig.password.value::input}}" - on-keypress="_handlePrefsChanged" - on-change="_handlePrefsChanged" - type="password"> - </iron-input> - </span> - </section> - <gr-button - id="saveButton" - on-click="_handlePrefsSave" - disabled="[[!_prefsChanged]]"> - Save Changes - </gr-button> - </section> - </fieldset> - </template> - <script src="cs-its-jira-config.js"></script> -</dom-module>
diff --git a/cs-its-jira-config/cs-its-jira-config.js b/cs-its-jira-config/cs-its-jira-config.js deleted file mode 100644 index 49b53b7..0000000 --- a/cs-its-jira-config/cs-its-jira-config.js +++ /dev/null
@@ -1,75 +0,0 @@ -// Copyright (C) 2021 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. - -(function () { - 'use strict'; - - Polymer({ - is: 'cs-its-jira-config', - - properties: { - repoName: String, - readOnly: { - type: Boolean, - value: true, - }, - _config: Object, - _changedConfig: Object, - _prefsChanged: { - type: Boolean, - value: false, - }, - _projectRestApi: Object, - }, - - attached() { - this._projectRestApi = this.plugin.restApi('/projects/'); - this._getPreferences().then(() => { - this._changedConfig = Object.assign({}, this._config); - }) - }, - - _getPreferences() { - return this._projectRestApi.get(`${encodeURIComponent(this.repoName)}/config`) - .then(config => { - if (!config) { - return; - } - if (config.plugin_config && config.plugin_config["its-jira"]) { - this._config = config.plugin_config["its-jira"]; - } - }) - }, - - _handleListDataChanged(event) { - this._changedConfig[event.target.id] = { values: event.detail.allEntries }; - this._handlePrefsChanged(); - }, - - _handlePrefsChanged() { - this._prefsChanged = true; - }, - - _handlePrefsSave() { - let body = { plugin_config_values: {} }; - body.plugin_config_values['its-jira'] = this._changedConfig; - this._projectRestApi.put(`${encodeURIComponent(this.repoName)}/config`, body) - .then(() => { - this._prefsChanged = false; - }).catch(response => { - this.fire('show-error', { message: response }); - }); - }, - }); -})();
diff --git a/plugin-config.html b/plugin-config.html deleted file mode 100644 index 22913ed..0000000 --- a/plugin-config.html +++ /dev/null
@@ -1,27 +0,0 @@ -<!-- -Copyright (C) 2021 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. ---> - -<link rel="import" href="./cs-its-jira-config/cs-its-jira-config.html"> - -<dom-module id="repo-its-jira-config"> - <script> - if(window.Polymer) { - Gerrit.install(plugin => { - plugin.registerCustomComponent('repo-config', 'cs-its-jira-config'); - }); - } - </script> -</dom-module>
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/InitJira.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/InitJira.java index e362d3e..a5c16ec 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/its/jira/InitJira.java +++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/InitJira.java
@@ -109,7 +109,10 @@ ui.header("Jira issue-tracking association"); jiraComment.string("Jira issue-Id regex", "match", "([A-Z]+-[0-9]+)"); - jiraComment.set("html", String.format("<a href=\"%s/browse/$1\">$1</a>", jiraUrl)); + jiraComment.string( + "What html would you like to use?", + "html", + String.format("<a href=\"%s/browse/$1\">$1</a>", jiraUrl)); Section pluginConfig = sections.get("plugin", pluginName);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraClient.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraClient.java index c17affd..5544df2 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraClient.java +++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraClient.java
@@ -25,13 +25,18 @@ import com.googlesource.gerrit.plugins.its.base.its.InvalidTransitionException; import com.googlesource.gerrit.plugins.its.jira.restapi.JiraComment; import com.googlesource.gerrit.plugins.its.jira.restapi.JiraIssue; +import com.googlesource.gerrit.plugins.its.jira.restapi.JiraIssueUpdate; +import com.googlesource.gerrit.plugins.its.jira.restapi.JiraPageRequest; import com.googlesource.gerrit.plugins.its.jira.restapi.JiraProject; import com.googlesource.gerrit.plugins.its.jira.restapi.JiraRestApi; import com.googlesource.gerrit.plugins.its.jira.restapi.JiraRestApiProvider; import com.googlesource.gerrit.plugins.its.jira.restapi.JiraServerInfo; import com.googlesource.gerrit.plugins.its.jira.restapi.JiraTransition; +import com.googlesource.gerrit.plugins.its.jira.restapi.JiraVersion; +import com.googlesource.gerrit.plugins.its.jira.restapi.JiraVersionsPage; import java.io.IOException; import java.util.Arrays; +import java.util.Date; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -94,13 +99,77 @@ log.debug("Trying to add comment for issue {}", issueKey); apiBuilder .getIssue(server) - .doPost(issueKey + "/comment", gson.toJson(new JiraComment(comment)), HTTP_CREATED); + .doPost( + issueKey + "/comment", + gson.toJson(new JiraComment(comment, server.getVisibility())), + HTTP_CREATED); log.debug("Comment added to issue {}", issueKey); } else { log.error("Issue {} does not exist or no access permission", issueKey); } } + public void createVersion(JiraItsServerInfo server, String projectKey, String version) + throws IOException { + log.debug("Trying to create version {} on project {}", version, projectKey); + JiraVersion jiraVersion = JiraVersion.builder().project(projectKey).name(version).build(); + apiBuilder.getVersions(server).doPost("", gson.toJson(jiraVersion), HTTP_CREATED); + log.debug("Version {} created on project {}", version, projectKey); + } + + public void markVersionAsReleased(JiraItsServerInfo server, String projectKey, String version) + throws IOException { + JiraVersion jiraVersion = findVersion(server, projectKey, version); + if (jiraVersion == null) { + log.error( + "Version {} of project {} does not exist or no access permission", version, projectKey); + return; + } + + log.debug( + "Trying to mark version {} with id {} of project {} as released", + version, + jiraVersion.getId(), + projectKey); + + JiraVersion markAsReleased = + JiraVersion.builder().released(true).releaseDate(new Date()).build(); + apiBuilder.getVersions(server).doPut(jiraVersion.getId(), gson.toJson(markAsReleased), HTTP_OK); + + log.debug("Version {} of project {} was marked as released", version, projectKey); + } + + private JiraVersion findVersion(JiraItsServerInfo server, String projectKey, String version) + throws IOException { + JiraRestApi<JiraVersionsPage> api = apiBuilder.getProjectVersions(server, projectKey); + + JiraPageRequest pageRequest = JiraPageRequest.builder().orderBy("-sequence").build(); + JiraVersion jiraVersion = null; + while (pageRequest != null) { + JiraVersionsPage versionsPage = api.doGet(pageRequest.toSpec(), HTTP_OK); + jiraVersion = versionsPage.findByName(version); + if (jiraVersion != null) { + break; + } + pageRequest = versionsPage.nextPageRequest(pageRequest); + } + + return jiraVersion; + } + + public void addValueToField( + JiraItsServerInfo server, String issueKey, String value, String fieldId) throws IOException { + if (!issueExists(server, issueKey)) { + log.error("Issue {} does not exist", issueKey); + return; + } + + log.debug("Trying to add value {} to field {} for issue {}", value, fieldId, issueKey); + JiraIssueUpdate edition = JiraIssueUpdate.builder().appendUpdate(fieldId, "add", value).build(); + apiBuilder.getIssue(server).doPut(issueKey, gson.toJson(edition), HTTP_NO_CONTENT); + log.debug("Value {} added to field {} for issue {}", value, fieldId, issueKey); + } + /** * @param issueKey Jira Issue key * @param transition JiraTransition.Item to perform
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraConfig.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraConfig.java index 5b4e197..baa93be 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraConfig.java +++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraConfig.java
@@ -33,6 +33,7 @@ import com.google.inject.Inject; import com.google.inject.Singleton; import com.googlesource.gerrit.plugins.its.jira.restapi.JiraURL; +import com.googlesource.gerrit.plugins.its.jira.restapi.JiraVisibilityType; import java.io.IOException; import org.eclipse.jgit.errors.ConfigInvalidException; import org.eclipse.jgit.lib.Config; @@ -47,12 +48,16 @@ static final String PROJECT_CONFIG_URL_KEY = "instanceUrl"; static final String PROJECT_CONFIG_USERNAME_KEY = "username"; static final String PROJECT_CONFIG_PASSWORD_KEY = "password"; + static final String PROJECT_CONFIG_COMMENT_VISIBILITY_TYPE = "visibilityType"; + static final String PROJECT_CONFIG_COMMENT_VISIBILITY_VALUE = "visibilityValue"; private static final Logger log = LoggerFactory.getLogger(JiraConfig.class); private static final String COMMENTLINK = "commentlink"; private static final String GERRIT_CONFIG_URL = "url"; private static final String GERRIT_CONFIG_USERNAME = "username"; private static final String GERRIT_CONFIG_PASSWORD = "password"; + private static final String GERRIT_CONFIG_COMMENT_VISIBILITY_TYPE = "visibilityType"; + private static final String GERRIT_CONFIG_COMMENT_VISIBILITY_VALUE = "visibilityValue"; private final String pluginName; private final PluginConfigFactory cfgFactory; @@ -60,6 +65,7 @@ private final JiraItsServerInfo defaultJiraServerInfo; private final GitRepositoryManager repoManager; private final ProjectCache projectCache; + private final ProjectConfig.Factory projectConfigFactory; private final PersonIdent serverUser; @Inject @@ -69,13 +75,15 @@ PluginConfigFactory cfgFactory, @GerritPersonIdent PersonIdent serverUser, ProjectCache projectCache, - GitRepositoryManager repoManager) { + GitRepositoryManager repoManager, + ProjectConfig.Factory projectConfigFactory) { this.gerritConfig = config; this.pluginName = pluginName; this.cfgFactory = cfgFactory; this.serverUser = serverUser; this.projectCache = projectCache; this.repoManager = repoManager; + this.projectConfigFactory = projectConfigFactory; this.defaultJiraServerInfo = buildDefaultServerInfo(gerritConfig, pluginName); } @@ -84,6 +92,10 @@ .url(gerritConfig.getString(pluginName, null, GERRIT_CONFIG_URL)) .username(gerritConfig.getString(pluginName, null, GERRIT_CONFIG_USERNAME)) .password(gerritConfig.getString(pluginName, null, GERRIT_CONFIG_PASSWORD)) + .visibility( + gerritConfig.getEnum( + pluginName, null, GERRIT_CONFIG_COMMENT_VISIBILITY_TYPE, JiraVisibilityType.NOTSET), + gerritConfig.getString(pluginName, null, GERRIT_CONFIG_COMMENT_VISIBILITY_VALUE)) .build(); } @@ -101,13 +113,19 @@ .url(pluginConfig.getString(PROJECT_CONFIG_URL_KEY, null)) .username(pluginConfig.getString(PROJECT_CONFIG_USERNAME_KEY, null)) .password(pluginConfig.getString(PROJECT_CONFIG_PASSWORD_KEY, null)) + .visibility( + pluginConfig.getEnum( + JiraVisibilityType.values(), + PROJECT_CONFIG_COMMENT_VISIBILITY_TYPE, + JiraVisibilityType.NOTSET), + pluginConfig.getString(PROJECT_CONFIG_COMMENT_VISIBILITY_VALUE, null)) .build(); } void addCommentLinksSection(Project.NameKey projectName, JiraItsServerInfo jiraItsServerInfo) { try (Repository git = repoManager.openRepository(projectName); MetaDataUpdate md = new MetaDataUpdate(GitReferenceUpdated.DISABLED, projectName, git)) { - ProjectConfig config = ProjectConfig.read(md); + ProjectConfig config = projectConfigFactory.read(md); String link = CharMatcher.is('/').trimFrom(jiraItsServerInfo.getUrl().toString()) + JiraURL.URL_SUFFIX; if (!commentLinksExist(config, link)) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraItsFacade.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraItsFacade.java index 00f965f..c67cabf 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraItsFacade.java +++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraItsFacade.java
@@ -69,6 +69,17 @@ } @Override + public void addValueToField(String issueKey, String value, String fieldId) throws IOException { + execute( + () -> { + log.debug("Adding value {} to field {} on issue {}", value, fieldId, issueKey); + jiraClient.addValueToField(itsServerInfo, issueKey, value, fieldId); + // No value to return + return null; + }); + } + + @Override public void performAction(String issueKey, String actionName) throws IOException { execute( () -> { @@ -90,6 +101,16 @@ } @Override + public void createVersion(String projectKey, String version) throws IOException { + execute( + () -> { + log.debug("Creating version {} on project {}", version, projectKey); + jiraClient.createVersion(itsServerInfo, projectKey, version); + return projectKey; + }); + } + + @Override public boolean exists(String issueKey) throws IOException { return execute(() -> jiraClient.issueExists(getJiraServerInstance(), issueKey)); }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraItsServer.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraItsServer.java index 0a698aa..7666239 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraItsServer.java +++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraItsServer.java
@@ -24,16 +24,13 @@ * to its-base to perform the its-actions. */ public class JiraItsServer implements ItsFacadeFactory { - private final JiraConfig jiraConfig; + private final JiraItsServerInfoProvider serverInfoProvider; private final JiraItsFacade itsFacade; - private final JiraItsServerCache serverCache; @Inject - public JiraItsServer( - JiraConfig jiraConfig, JiraItsFacade itsFacade, JiraItsServerCache serverCache) { - this.jiraConfig = jiraConfig; + public JiraItsServer(JiraItsServerInfoProvider serverInfoProvider, JiraItsFacade itsFacade) { + this.serverInfoProvider = serverInfoProvider; this.itsFacade = itsFacade; - this.serverCache = serverCache; } /** @@ -48,25 +45,7 @@ */ @Override public JiraItsFacade getFacade(Project.NameKey projectName) { - JiraItsServerInfo jiraItsServerInfo = serverCache.get(projectName.get()); - if (jiraItsServerInfo.isValid()) { - jiraConfig.addCommentLinksSection(projectName, jiraItsServerInfo); - } else { - jiraItsServerInfo = jiraConfig.getDefaultServerInfo(); - } - - if (!jiraItsServerInfo.isValid()) { - throw new RuntimeException( - String.format( - "No valid Jira server configuration was found for project '%s' %n." - + "Missing one or more configuration values: url: %s, username: %s, password: %s", - projectName.get(), - jiraItsServerInfo.getUrl(), - jiraItsServerInfo.getUsername(), - jiraItsServerInfo.getPassword())); - } - - itsFacade.setJiraServerInstance(jiraItsServerInfo); + itsFacade.setJiraServerInstance(serverInfoProvider.get(projectName)); return itsFacade; } }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraItsServerInfo.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraItsServerInfo.java index b384189..4ffb72d 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraItsServerInfo.java +++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraItsServerInfo.java
@@ -16,9 +16,12 @@ package com.googlesource.gerrit.plugins.its.jira; import com.googlesource.gerrit.plugins.its.jira.restapi.JiraURL; +import com.googlesource.gerrit.plugins.its.jira.restapi.JiraVisibility; +import com.googlesource.gerrit.plugins.its.jira.restapi.JiraVisibilityType; import java.net.MalformedURLException; public class JiraItsServerInfo { + public static class Builder { private JiraItsServerInfo instance = new JiraItsServerInfo(); @@ -43,6 +46,15 @@ return this; } + public Builder visibility(JiraVisibilityType type, String value) { + try { + instance.visibility = new JiraVisibility(type, value); + } catch (IllegalArgumentException e) { + instance.visibility = null; + } + return this; + } + public JiraItsServerInfo build() { return instance; } @@ -51,6 +63,7 @@ private JiraURL url; private String username; private String password; + private JiraVisibility visibility; public static Builder builder() { return new JiraItsServerInfo.Builder(); @@ -68,6 +81,10 @@ return password; } + public JiraVisibility getVisibility() { + return visibility; + } + public boolean isValid() { return url != null && username != null && password != null; }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraItsServerInfoProvider.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraItsServerInfoProvider.java new file mode 100644 index 0000000..b5e0128 --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraItsServerInfoProvider.java
@@ -0,0 +1,52 @@ +// Copyright (C) 2019 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.googlesource.gerrit.plugins.its.jira; + +import com.google.gerrit.reviewdb.client.Project; +import com.google.inject.Inject; + +public class JiraItsServerInfoProvider { + + private final JiraConfig jiraConfig; + private final JiraItsServerCache serverCache; + + @Inject + public JiraItsServerInfoProvider(JiraConfig jiraConfig, JiraItsServerCache serverCache) { + this.jiraConfig = jiraConfig; + this.serverCache = serverCache; + } + + public JiraItsServerInfo get(Project.NameKey projectName) { + JiraItsServerInfo jiraItsServerInfo = serverCache.get(projectName.get()); + if (jiraItsServerInfo.isValid()) { + jiraConfig.addCommentLinksSection(projectName, jiraItsServerInfo); + } else { + jiraItsServerInfo = jiraConfig.getDefaultServerInfo(); + } + + if (!jiraItsServerInfo.isValid()) { + throw new RuntimeException( + String.format( + "No valid Jira server configuration was found for project '%s' %n." + + "Missing one or more configuration values: url: %s, username: %s, password: %s", + projectName.get(), + jiraItsServerInfo.getUrl(), + jiraItsServerInfo.getUsername(), + jiraItsServerInfo.getPassword())); + } + + return jiraItsServerInfo; + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraModule.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraModule.java index 94d631e..3d59458 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraModule.java +++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraModule.java
@@ -20,9 +20,6 @@ import com.google.gerrit.extensions.annotations.Exports; import com.google.gerrit.extensions.annotations.PluginName; -import com.google.gerrit.extensions.registration.DynamicSet; -import com.google.gerrit.extensions.webui.JavaScriptPlugin; -import com.google.gerrit.extensions.webui.WebUiPlugin; import com.google.gerrit.lifecycle.LifecycleModule; import com.google.gerrit.server.config.PluginConfigFactory; import com.google.gerrit.server.config.ProjectConfigEntry; @@ -31,6 +28,8 @@ import com.googlesource.gerrit.plugins.its.base.its.ItsConfig; import com.googlesource.gerrit.plugins.its.base.its.ItsFacade; import com.googlesource.gerrit.plugins.its.base.its.ItsFacadeFactory; +import com.googlesource.gerrit.plugins.its.base.workflow.CustomAction; +import com.googlesource.gerrit.plugins.its.jira.workflow.MarkPropertyAsReleasedVersion; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -61,11 +60,13 @@ .annotatedWith(Exports.named(PROJECT_CONFIG_PASSWORD_KEY)) .toInstance(new ProjectConfigEntry("JIRA password", "")); bind(ItsConfig.class); + bind(JiraItsServerInfoProvider.class); + bind(CustomAction.class) + .annotatedWith(Exports.named(MarkPropertyAsReleasedVersion.ACTION_NAME)) + .to(MarkPropertyAsReleasedVersion.class); install(new ItsHookModule(pluginName, pluginCfgFactory)); install(JiraItsServerCacheImpl.module()); listener().to(JiraItsStartupHealthcheck.class); - DynamicSet.bind(binder(), WebUiPlugin.class) - .toInstance(new JavaScriptPlugin("cs-its-jira-config.html")); LOG.info("JIRA is configured as ITS"); }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraComment.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraComment.java index eb2755d..d629018 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraComment.java +++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraComment.java
@@ -17,9 +17,11 @@ public class JiraComment { private final String body; + private final JiraVisibility visibility; - public JiraComment(String body) { + public JiraComment(String body, JiraVisibility visibility) { this.body = body; + this.visibility = visibility; } public String getBody() {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraIssueUpdate.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraIssueUpdate.java new file mode 100644 index 0000000..bf9ea15 --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraIssueUpdate.java
@@ -0,0 +1,62 @@ +// Copyright (C) 2018 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.googlesource.gerrit.plugins.its.jira.restapi; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class JiraIssueUpdate { + + private final Map<String, List<Map<String, Object>>> update; + + private JiraIssueUpdate(Map<String, List<Map<String, Object>>> update) { + this.update = Collections.unmodifiableMap(update); + } + + public Map<String, List<Map<String, Object>>> getUpdate() { + return update; + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private final Map<String, List<Map<String, Object>>> update; + + private Builder() { + this.update = new HashMap<>(); + } + + public Builder appendUpdate(String fieldId, String operation, String value) { + Object valueToPut = value; + if ("fixVersions".equals(fieldId)) { + valueToPut = Collections.singletonMap("name", value); + } + + this.update + .computeIfAbsent(fieldId, key -> new ArrayList<>()) + .add(Collections.singletonMap(operation, valueToPut)); + return this; + } + + public JiraIssueUpdate build() { + return new JiraIssueUpdate(update); + } + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraPage.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraPage.java new file mode 100644 index 0000000..3de05f4 --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraPage.java
@@ -0,0 +1,80 @@ +// Copyright (C) 2018 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.googlesource.gerrit.plugins.its.jira.restapi; + +import java.util.List; + +public class JiraPage<T> { + + private final String self; + private final String nextPage; + private final long maxResults; + private final long startAt; + private final long total; + private final boolean isLast; + private final List<T> values; + + public JiraPage( + String self, + String nextPage, + long maxResults, + long startAt, + long total, + boolean isLast, + List<T> values) { + this.self = self; + this.nextPage = nextPage; + this.maxResults = maxResults; + this.startAt = startAt; + this.total = total; + this.isLast = isLast; + this.values = values; + } + + public JiraPageRequest nextPageRequest(JiraPageRequest currentPageRequest) { + if (isLast) { + return null; + } + return currentPageRequest.nextPageRequest(); + } + + public String getSelf() { + return self; + } + + public String getNextPage() { + return nextPage; + } + + public long getMaxResults() { + return maxResults; + } + + public long getStartAt() { + return startAt; + } + + public long getTotal() { + return total; + } + + public boolean isLast() { + return isLast; + } + + public List<T> getValues() { + return values; + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraPageRequest.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraPageRequest.java new file mode 100644 index 0000000..5e87ec3 --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraPageRequest.java
@@ -0,0 +1,88 @@ +// Copyright (C) 2018 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.googlesource.gerrit.plugins.its.jira.restapi; + +import com.google.common.base.Strings; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + +public class JiraPageRequest { + + private final Long startAt; + private final Long maxResults; + private final String orderBy; + + private JiraPageRequest(Long startAt, Long maxResults, String orderBy) { + this.startAt = startAt; + this.maxResults = maxResults; + this.orderBy = orderBy; + } + + public JiraPageRequest nextPageRequest() { + return new JiraPageRequest(startAt + 1, maxResults, orderBy); + } + + public String toSpec() { + Map<String, Object> parameters = new HashMap<>(); + if (startAt != null) { + parameters.put("startAt", startAt); + } + if (maxResults != null) { + parameters.put("maxResults", maxResults); + } + if (!Strings.isNullOrEmpty(orderBy)) { + parameters.put("orderBy", orderBy); + } + String requestParameters = + parameters + .entrySet() + .stream() + .map(parameter -> parameter.getKey() + "=" + parameter.getValue()) + .collect(Collectors.joining("&")); + return "?" + requestParameters; + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private Long startAt; + private Long maxResults; + private String orderBy; + + private Builder() {} + + public Builder startAt(Long startAt) { + this.startAt = startAt; + return this; + } + + public Builder maxResults(Long maxResults) { + this.maxResults = maxResults; + return this; + } + + public Builder orderBy(String orderBy) { + this.orderBy = orderBy; + return this; + } + + public JiraPageRequest build() { + return new JiraPageRequest(startAt, maxResults, orderBy); + } + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraRestApiProvider.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraRestApiProvider.java index 2e31d1b..9159068 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraRestApiProvider.java +++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraRestApiProvider.java
@@ -39,4 +39,13 @@ public JiraRestApi<JiraProject[]> getProjects(JiraItsServerInfo serverInfo) { return get(serverInfo, JiraProject[].class, "/project"); } + + public JiraRestApi<JiraVersion[]> getVersions(JiraItsServerInfo serverInfo) { + return get(serverInfo, JiraVersion[].class, "/version"); + } + + public JiraRestApi<JiraVersionsPage> getProjectVersions( + JiraItsServerInfo serverInfo, String projectKey) { + return get(serverInfo, JiraVersionsPage.class, "/project/" + projectKey + "/version"); + } }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraVersion.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraVersion.java new file mode 100644 index 0000000..36022be --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraVersion.java
@@ -0,0 +1,148 @@ +// Copyright (C) 2018 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.googlesource.gerrit.plugins.its.jira.restapi; + +import java.text.SimpleDateFormat; +import java.util.Date; + +/** Represents a version in JIRA. */ +public class JiraVersion { + + private final String id; + private final String description; + private final String name; + private final boolean archived; + private final boolean released; + private final String releaseDate; + private final String project; + private final Long projectId; + + private JiraVersion( + String id, + String description, + String name, + boolean archived, + boolean released, + Date releaseDate, + String project, + Long projectId) { + this.id = id; + this.description = description; + this.name = name; + this.archived = archived; + this.released = released; + if (releaseDate == null) { + this.releaseDate = null; + } else { + this.releaseDate = new SimpleDateFormat("yyyy-MM-dd").format(releaseDate); + } + this.project = project; + this.projectId = projectId; + } + + public String getId() { + return id; + } + + public String getDescription() { + return description; + } + + public String getName() { + return name; + } + + public boolean isArchived() { + return archived; + } + + public boolean isReleased() { + return released; + } + + public String getReleaseDate() { + return releaseDate; + } + + public String getProject() { + return project; + } + + public Long getProjectId() { + return projectId; + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private String id; + private String description; + private String name; + private boolean archived; + private boolean released; + private Date releaseDate; + private String project; + private Long projectId; + + private Builder() {} + + public Builder id(String id) { + this.id = id; + return this; + } + + public Builder description(String description) { + this.description = description; + return this; + } + + public Builder name(String name) { + this.name = name; + return this; + } + + public Builder archived(boolean archived) { + this.archived = archived; + return this; + } + + public Builder released(boolean released) { + this.released = released; + return this; + } + + public Builder releaseDate(Date releaseDate) { + this.releaseDate = releaseDate; + return this; + } + + public Builder project(String project) { + this.project = project; + return this; + } + + public Builder projectId(Long projectId) { + this.projectId = projectId; + return this; + } + + public JiraVersion build() { + return new JiraVersion( + id, description, name, archived, released, releaseDate, project, projectId); + } + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraVersionsPage.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraVersionsPage.java new file mode 100644 index 0000000..5fa684f --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraVersionsPage.java
@@ -0,0 +1,25 @@ +package com.googlesource.gerrit.plugins.its.jira.restapi; + +import java.util.List; + +/** + * Created on 03/06/18. + * + * @author Reda.Housni-Alaoui + */ +public class JiraVersionsPage extends JiraPage<JiraVersion> { + public JiraVersionsPage( + String self, + String nextPage, + int maxResults, + int startAt, + int total, + boolean isLast, + List<JiraVersion> values) { + super(self, nextPage, maxResults, startAt, total, isLast, values); + } + + public JiraVersion findByName(String name) { + return this.getValues().stream().filter(v -> name.equals(v.getName())).findFirst().orElse(null); + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraVisibility.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraVisibility.java new file mode 100644 index 0000000..6037dbb --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraVisibility.java
@@ -0,0 +1,46 @@ +// Copyright (C) 2020 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.googlesource.gerrit.plugins.its.jira.restapi; + +import com.googlesource.gerrit.plugins.its.jira.JiraItsServerInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class JiraVisibility { + private static final Logger log = LoggerFactory.getLogger(JiraItsServerInfo.class); + + private final JiraVisibilityType type; + private final String value; + + public JiraVisibility(JiraVisibilityType type, String value) { + if (type != JiraVisibilityType.NOTSET && value != null) { + this.type = type; + this.value = value; + } else { + if (type != JiraVisibilityType.NOTSET || value != null) { + log.error("visibilityType and visibilityValue must be set together"); + } + throw new IllegalArgumentException(); + } + } + + public JiraVisibilityType getType() { + return type; + } + + public String getValue() { + return value; + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraVisibilityType.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraVisibilityType.java new file mode 100644 index 0000000..d9c7a29 --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraVisibilityType.java
@@ -0,0 +1,36 @@ +// Copyright (C) 2020 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.googlesource.gerrit.plugins.its.jira.restapi; + +import com.google.gson.annotations.SerializedName; + +public enum JiraVisibilityType { + NOTSET(null), + + @SerializedName("role") + ROLE("role"), + @SerializedName("group") + GROUP("group"); + + private String type; + + JiraVisibilityType(String type) { + this.type = type; + } + + public String toString() { + return this.type; + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/workflow/MarkPropertyAsReleasedVersion.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/workflow/MarkPropertyAsReleasedVersion.java new file mode 100644 index 0000000..db6de54 --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/workflow/MarkPropertyAsReleasedVersion.java
@@ -0,0 +1,67 @@ +// Copyright (C) 2018 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.googlesource.gerrit.plugins.its.jira.workflow; + +import com.google.gerrit.reviewdb.client.Project; +import com.google.inject.Inject; +import com.googlesource.gerrit.plugins.its.base.its.ItsFacade; +import com.googlesource.gerrit.plugins.its.base.workflow.ActionRequest; +import com.googlesource.gerrit.plugins.its.base.workflow.ActionType; +import com.googlesource.gerrit.plugins.its.base.workflow.CustomAction; +import com.googlesource.gerrit.plugins.its.jira.JiraClient; +import com.googlesource.gerrit.plugins.its.jira.JiraItsServerInfo; +import com.googlesource.gerrit.plugins.its.jira.JiraItsServerInfoProvider; +import java.io.IOException; +import java.util.Map; +import java.util.Optional; + +public class MarkPropertyAsReleasedVersion implements CustomAction { + + public static final String ACTION_NAME = "mark-property-as-released-version"; + + private final JiraItsServerInfoProvider serverInfoProvider; + private final JiraClient jiraClient; + private final MarkPropertyAsReleasedVersionParametersExtractor parametersExtractor; + + @Inject + public MarkPropertyAsReleasedVersion( + JiraItsServerInfoProvider serverInfoProvider, + JiraClient jiraClient, + MarkPropertyAsReleasedVersionParametersExtractor parametersExtractor) { + this.serverInfoProvider = serverInfoProvider; + this.jiraClient = jiraClient; + this.parametersExtractor = parametersExtractor; + } + + @Override + public void execute( + ItsFacade its, String itsProject, ActionRequest actionRequest, Map<String, String> properties) + throws IOException { + Optional<MarkPropertyAsReleasedVersionParameters> parameters = + parametersExtractor.extract(actionRequest, properties); + if (!parameters.isPresent()) { + return; + } + Project.NameKey projectName = new Project.NameKey(properties.get("project")); + JiraItsServerInfo jiraItsServerInfo = serverInfoProvider.get(projectName); + jiraClient.markVersionAsReleased( + jiraItsServerInfo, itsProject, parameters.get().getPropertyValue()); + } + + @Override + public ActionType getType() { + return ActionType.PROJECT; + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/workflow/MarkPropertyAsReleasedVersionParameters.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/workflow/MarkPropertyAsReleasedVersionParameters.java new file mode 100644 index 0000000..43b1a9a --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/workflow/MarkPropertyAsReleasedVersionParameters.java
@@ -0,0 +1,32 @@ +// Copyright (C) 2018 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.googlesource.gerrit.plugins.its.jira.workflow; + +/** Parameters needed by {@link MarkPropertyAsReleasedVersion} action */ +public class MarkPropertyAsReleasedVersionParameters { + + private final String propertyValue; + + public MarkPropertyAsReleasedVersionParameters(String propertyValue) { + this.propertyValue = propertyValue; + } + + /** + * @return The extracted property value that will be used as the version value to mark as released + */ + public String getPropertyValue() { + return propertyValue; + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/workflow/MarkPropertyAsReleasedVersionParametersExtractor.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/workflow/MarkPropertyAsReleasedVersionParametersExtractor.java new file mode 100644 index 0000000..d55e550 --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/workflow/MarkPropertyAsReleasedVersionParametersExtractor.java
@@ -0,0 +1,58 @@ +// Copyright (C) 2018 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.googlesource.gerrit.plugins.its.jira.workflow; + +import com.google.common.base.Strings; +import com.googlesource.gerrit.plugins.its.base.workflow.ActionRequest; +import java.util.Arrays; +import java.util.Map; +import java.util.Optional; +import javax.inject.Inject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +class MarkPropertyAsReleasedVersionParametersExtractor { + + private static final Logger log = + LoggerFactory.getLogger(MarkPropertyAsReleasedVersionParametersExtractor.class); + + @Inject + public MarkPropertyAsReleasedVersionParametersExtractor() {} + + public Optional<MarkPropertyAsReleasedVersionParameters> extract( + ActionRequest actionRequest, Map<String, String> properties) { + String[] parameters = actionRequest.getParameters(); + if (parameters.length != 1) { + log.error( + "Wrong number of received parameters. Received parameters are {}. Only one parameter is expected, the property id.", + Arrays.toString(parameters)); + return Optional.empty(); + } + + String propertyId = parameters[0]; + if (Strings.isNullOrEmpty(propertyId)) { + log.error("Received property id is blank"); + return Optional.empty(); + } + + if (!properties.containsKey(propertyId)) { + log.error("No event property found for id {}", propertyId); + return Optional.empty(); + } + + String propertyValue = properties.get(propertyId); + return Optional.of(new MarkPropertyAsReleasedVersionParameters(propertyValue)); + } +}
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md index db66b9b..9e35208 100644 --- a/src/main/resources/Documentation/config.md +++ b/src/main/resources/Documentation/config.md
@@ -149,20 +149,20 @@ [rule "open"] event-type = patchset-created - action = add-velocity-comment inline Change ${its.formatLink($changeUrl)} is created. + action = add-standard-comment action = In Progress [rule "resolve"] event-type = comment-added - approval-Code-Review = 2 - action = add-velocity-comment inline Change ${its.formatLink($changeUrl)} is verified. + approvalCodeReview = 2 + action = add-standard-comment action = In Review [rule "merged"] event-type = change-merged - action = add-velocity-comment inline Change ${its.formatLink($changeUrl)} is merged. + action = add-standard-comment action = Done [rule "abandoned"] - event-type = change-abandoned' - action = add-velocity-comment inline Change ${its.formatLink($changeUrl)} is abandoned. + event-type = change-abandoned + action = add-standard-comment action = To Do The first rule triggers an action which adds a comment and a hyperlink to the change created @@ -171,14 +171,6 @@ in Jira to `In Progress`. The title of the action `In Progress` should match the workflow actions used by the JIRA server as different versions of JIRA can have different workflow actions. -**Note:** Velocity comments were deprecated in Gerrit 2.14 and will be removed in Gerrit 2.16/3.0; -the `actions-@Plugin@.config` needs to be changed accordingly. For example, to use Soy comments -instead of velocity comments: - - [rule "open"] - event-type = patchset-created - action = add-soy-comment Change ${its.formatLink($changeUrl)} is created. - action = In Progress Multiple Jira servers integration --------------------------------- @@ -240,3 +232,44 @@ limitation and the reason why this feature is marked as experimental, i.e., not production ready. Additional work is needed in order to offer a secure level of encryption for this information. + +Specific actions +---------------- + +### mark-property-as-released-version + +The `mark-property-as-released-version` action marks a version as released in +JIRA. +The version to mark as released is identified by an event property value. + +This is useful when you want to mark a version as released in JIRA when a +tag is created in the Gerrit project. + +Example with the event property `ref`: + +``` + action = mark-property-as-released-version ref +``` + +### add-comment + +The `add-comment`, `add-standard-comment` or `add-soy-comment` actions add comment for +certain events. By default, these comments are visible to all on JIRA instance. + +It is possible to get better control over comments visibility by adding configuration +entries in *gerrit.config* or *project.config* file in the *refs/meta/config* branch. + +A typical visibility configuration will look like: + +``` + [plugin "its-jira"] + visibilityType = role + visibilityValue = Dev +``` + +This will publish comments visible only by users with *role* set as *Dev* in JIRA. + +`visibilityType` and `visibilityValue` must be set together. + +`visibilityType` could be set to **role** or **group**, and `visibilityValue` refers +to JIRA *role* or *group*.
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/jira/JiraConfigTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/jira/JiraConfigTest.java index 66e151e..5348e8f 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/its/jira/JiraConfigTest.java +++ b/src/test/java/com/googlesource/gerrit/plugins/its/jira/JiraConfigTest.java
@@ -23,6 +23,7 @@ import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.project.NoSuchProjectException; import com.google.gerrit.server.project.ProjectCache; +import com.google.gerrit.server.project.ProjectConfig; import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.PersonIdent; import org.junit.Before; @@ -44,13 +45,21 @@ @Mock private PersonIdent serverUser; @Mock private ProjectCache projectCache; @Mock private GitRepositoryManager repoManager; + @Mock private ProjectConfig.Factory projectConfigFactory; private JiraConfig jiraConfig; @Before public void createJiraConfig() { jiraConfig = - new JiraConfig(cfg, PLUGIN_NAME, cfgFactory, serverUser, projectCache, repoManager); + new JiraConfig( + cfg, + PLUGIN_NAME, + cfgFactory, + serverUser, + projectCache, + repoManager, + projectConfigFactory); } @Test
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/jira/JiraITTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/jira/JiraITTest.java index 5ec0021..a955363 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/its/jira/JiraITTest.java +++ b/src/test/java/com/googlesource/gerrit/plugins/its/jira/JiraITTest.java
@@ -15,12 +15,15 @@ package com.googlesource.gerrit.plugins.its.jira; import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.matchingJsonPath; import static com.github.tomakehurst.wiremock.client.WireMock.noContent; import static com.github.tomakehurst.wiremock.client.WireMock.ok; import static com.github.tomakehurst.wiremock.client.WireMock.okJson; import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; import static java.lang.String.format; import static java.net.HttpURLConnection.HTTP_CREATED; import static java.net.HttpURLConnection.HTTP_FORBIDDEN; @@ -68,7 +71,7 @@ private Path its_dir; - @Rule public WireMockRule wireMockRule = new WireMockRule(PORT); + @Rule public WireMockRule wireMockRule = new WireMockRule(options().port(PORT)); @Override public void beforeTest(Description description) throws Exception { @@ -210,6 +213,30 @@ verifyIssueCall(); } + @Test + @GerritConfig(name = COMMENT_SECTION + ".match", value = "([A-Z]+-[0-9]+)") + @GerritConfig( + name = COMMENT_SECTION + ".html", + value = "<a href=\"" + URL + "/browse/$1\">$1</a>") + @GerritConfig(name = COMMENT_SECTION + ".association", value = "SUGGESTED") + @GerritConfig(name = PLUGIN_NAME + ".url", value = URL) + @GerritConfig(name = PLUGIN_NAME + ".username", value = "user") + @GerritConfig(name = PLUGIN_NAME + ".password", value = "pass") + @GerritConfig(name = PLUGIN_NAME + ".visibilityType", value = "group") + @GerritConfig(name = PLUGIN_NAME + ".visibilityValue", value = "AllDev") + public void testIssueWithVisibility() throws Exception { + createItsRulesConfigWithComment(); + mockServerCall(); + mockCommentCall(); + wireMockRule.givenThat( + WireMock.get(urlEqualTo(BASE_PREFIX + ISSUE_CLASS_PREFIX + JIRA_ISSUE)).willReturn(ok())); + + createChangeWithIssue(); + + verifyIssueCall(); + verifyCommentCallWithVisibility(); + } + private void mockServerCall() { wireMockRule.resetRequests(); wireMockRule.givenThat( @@ -255,9 +282,17 @@ urlEqualTo(BASE_PREFIX + ISSUE_CLASS_PREFIX + JIRA_ISSUE + COMMENT_CLASS_PREFIX))); } + private void verifyCommentCallWithVisibility() { + wireMockRule.verify( + postRequestedFor( + urlEqualTo(BASE_PREFIX + ISSUE_CLASS_PREFIX + JIRA_ISSUE + COMMENT_CLASS_PREFIX)) + .withRequestBody(matchingJsonPath("$.visibility.type", equalTo("group"))) + .withRequestBody(matchingJsonPath("$.visibility.value", equalTo("AllDev")))); + } + private void createChangeWithIssue() throws Exception { pushFactory - .create(db, admin.getIdent(), testRepo, JIRA_ISSUE, "a.txt", "test") + .create(admin.newIdent(), testRepo, JIRA_ISSUE, "a.txt", "test") .to("refs/for/master"); }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/jira/JiraItsFacadeTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/jira/JiraItsFacadeTest.java index 9241d36..793f09f 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/its/jira/JiraItsFacadeTest.java +++ b/src/test/java/com/googlesource/gerrit/plugins/its/jira/JiraItsFacadeTest.java
@@ -31,6 +31,9 @@ private static final String ACTION = "action"; private static final String COMMENT = "comment"; private static final String ISSUE_KEY = "issueKey"; + private static final String PROJECT_KEY = "projectKey"; + private static final String FIELD_ID = "fieldId"; + private static final String VALUE = "value"; @Mock private JiraClient jiraClient; private JiraItsServerInfo server; @@ -65,6 +68,13 @@ } @Test + public void addValueToField() throws IOException { + jiraFacade = new JiraItsFacade(jiraClient); + jiraFacade.addValueToField(ISSUE_KEY, VALUE, FIELD_ID); + verify(jiraClient).addValueToField(server, ISSUE_KEY, VALUE, FIELD_ID); + } + + @Test public void performAction() throws IOException, InvalidTransitionException { jiraFacade = new JiraItsFacade(jiraClient); jiraFacade.performAction(ISSUE_KEY, ACTION); @@ -72,6 +82,13 @@ } @Test + public void createVersion() throws IOException { + jiraFacade = new JiraItsFacade(jiraClient); + jiraFacade.createVersion(PROJECT_KEY, "1.0"); + verify(jiraClient).createVersion(server, PROJECT_KEY, "1.0"); + } + + @Test public void exists() throws IOException { jiraFacade = new JiraItsFacade(jiraClient); jiraFacade.exists(ISSUE_KEY);
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/jira/JiraItsServerInfoProviderTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/jira/JiraItsServerInfoProviderTest.java new file mode 100644 index 0000000..c8fabc7 --- /dev/null +++ b/src/test/java/com/googlesource/gerrit/plugins/its/jira/JiraItsServerInfoProviderTest.java
@@ -0,0 +1,69 @@ +// Copyright (C) 2018 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.googlesource.gerrit.plugins.its.jira; + +import static org.mockito.Mockito.*; +import static org.mockito.Mockito.when; + +import com.google.gerrit.reviewdb.client.Project; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class JiraItsServerInfoProviderTest { + + private static final Project.NameKey PROJECT_NAMEKEY = new Project.NameKey("project"); + + @Mock private JiraConfig jiraConfig; + @Mock private JiraItsServerCache serverCache; + @Mock private JiraItsServerInfo jiraItsServerInfo; + + @Rule public ExpectedException expectedException = ExpectedException.none(); + + private JiraItsServerInfoProvider jiraItsServerInfoProvider; + + @Test + public void testValidServerInfoIsreturnedFromTheCache() { + when(jiraItsServerInfo.isValid()).thenReturn(true); + when(serverCache.get(PROJECT_NAMEKEY.get())).thenReturn(jiraItsServerInfo); + jiraItsServerInfoProvider = new JiraItsServerInfoProvider(jiraConfig, serverCache); + jiraItsServerInfoProvider.get(PROJECT_NAMEKEY); + verify(jiraConfig).addCommentLinksSection(PROJECT_NAMEKEY, jiraItsServerInfo); + } + + @Test + public void testGetDefaultServerInfo() { + when(jiraItsServerInfo.isValid()).thenReturn(false).thenReturn(true); + when(serverCache.get(PROJECT_NAMEKEY.get())).thenReturn(jiraItsServerInfo); + when(jiraConfig.getDefaultServerInfo()).thenReturn(jiraItsServerInfo); + jiraItsServerInfoProvider = new JiraItsServerInfoProvider(jiraConfig, serverCache); + jiraItsServerInfoProvider.get(PROJECT_NAMEKEY); + verify(jiraConfig, never()).addCommentLinksSection(PROJECT_NAMEKEY, jiraItsServerInfo); + } + + @Test + public void testNoConfiguredServerInfo() { + when(serverCache.get(PROJECT_NAMEKEY.get())).thenReturn(jiraItsServerInfo); + when(jiraItsServerInfo.isValid()).thenReturn(false).thenReturn(false); + when(jiraConfig.getDefaultServerInfo()).thenReturn(jiraItsServerInfo); + jiraItsServerInfoProvider = new JiraItsServerInfoProvider(jiraConfig, serverCache); + expectedException.expect(RuntimeException.class); + jiraItsServerInfoProvider.get(PROJECT_NAMEKEY); + } +}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/jira/JiraItsServerTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/jira/JiraItsServerTest.java index 06daa15..78cb0fb 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/its/jira/JiraItsServerTest.java +++ b/src/test/java/com/googlesource/gerrit/plugins/its/jira/JiraItsServerTest.java
@@ -14,7 +14,6 @@ package com.googlesource.gerrit.plugins.its.jira; -import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -30,43 +29,17 @@ public class JiraItsServerTest { private static final Project.NameKey PROJECT_NAMEKEY = new Project.NameKey("project"); - @Mock private JiraConfig jiraConfig; + @Mock private JiraItsServerInfoProvider jiraItsserverInfoProvider; @Mock private JiraItsFacade itsFacade; - @Mock private JiraItsServerCache serverCache; @Mock private JiraItsServerInfo jiraItsServerInfo; @Rule public ExpectedException expectedException = ExpectedException.none(); - private JiraItsServer jiraItsServer; - @Test - public void testValidServerInfoIsreturnedFromTheCache() throws Exception { - when(jiraItsServerInfo.isValid()).thenReturn(true); - when(serverCache.get(PROJECT_NAMEKEY.get())).thenReturn(jiraItsServerInfo); - jiraItsServer = new JiraItsServer(jiraConfig, itsFacade, serverCache); + public void testGetFacade() { + when(jiraItsserverInfoProvider.get(PROJECT_NAMEKEY)).thenReturn(jiraItsServerInfo); + JiraItsServer jiraItsServer = new JiraItsServer(jiraItsserverInfoProvider, itsFacade); jiraItsServer.getFacade(PROJECT_NAMEKEY); - verify(jiraConfig).addCommentLinksSection(PROJECT_NAMEKEY, jiraItsServerInfo); verify(itsFacade).setJiraServerInstance(jiraItsServerInfo); } - - @Test - public void testGetDefaultServerInfo() throws Exception { - when(jiraItsServerInfo.isValid()).thenReturn(false).thenReturn(true); - when(serverCache.get(PROJECT_NAMEKEY.get())).thenReturn(jiraItsServerInfo); - when(jiraConfig.getDefaultServerInfo()).thenReturn(jiraItsServerInfo); - jiraItsServer = new JiraItsServer(jiraConfig, itsFacade, serverCache); - jiraItsServer.getFacade(PROJECT_NAMEKEY); - verify(jiraConfig, never()).addCommentLinksSection(PROJECT_NAMEKEY, jiraItsServerInfo); - verify(itsFacade).setJiraServerInstance(jiraItsServerInfo); - } - - @Test - public void testNoConfiguredServerInfo() throws Exception { - when(serverCache.get(PROJECT_NAMEKEY.get())).thenReturn(jiraItsServerInfo); - when(jiraItsServerInfo.isValid()).thenReturn(false).thenReturn(false); - when(jiraConfig.getDefaultServerInfo()).thenReturn(jiraItsServerInfo); - jiraItsServer = new JiraItsServer(jiraConfig, itsFacade, serverCache); - expectedException.expect(RuntimeException.class); - jiraItsServer.getFacade(PROJECT_NAMEKEY); - } }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraIssueUpdateTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraIssueUpdateTest.java new file mode 100644 index 0000000..1ecba22 --- /dev/null +++ b/src/test/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraIssueUpdateTest.java
@@ -0,0 +1,50 @@ +// Copyright (C) 2018 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.googlesource.gerrit.plugins.its.jira.restapi; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.gerrit.json.OutputFormat; +import com.google.gson.Gson; +import org.junit.Test; + +public class JiraIssueUpdateTest { + + private static final String FIELD_ID = "fieldId"; + private static final String OPERATION = "operation"; + private static final String VALUE = "value"; + + @Test + public void testSerialization() { + JiraIssueUpdate issueUpdate = + JiraIssueUpdate.builder().appendUpdate(FIELD_ID, OPERATION, VALUE).build(); + + assertThat(newGson().toJson(issueUpdate)) + .isEqualTo("{\"update\":{\"fieldId\":[{\"operation\":\"value\"}]}}"); + } + + @Test + public void testSerializationForFixVersions() { + JiraIssueUpdate issueUpdate = + JiraIssueUpdate.builder().appendUpdate("fixVersions", OPERATION, VALUE).build(); + + assertThat(newGson().toJson(issueUpdate)) + .isEqualTo("{\"update\":{\"fixVersions\":[{\"operation\":{\"name\":\"value\"}}]}}"); + } + + private Gson newGson() { + return OutputFormat.JSON_COMPACT.newGson(); + } +}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/jira/workflow/MarkPropertyAsReleasedVersionParametersExtractorTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/jira/workflow/MarkPropertyAsReleasedVersionParametersExtractorTest.java new file mode 100644 index 0000000..81dc49a --- /dev/null +++ b/src/test/java/com/googlesource/gerrit/plugins/its/jira/workflow/MarkPropertyAsReleasedVersionParametersExtractorTest.java
@@ -0,0 +1,90 @@ +// Copyright (C) 2018 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.googlesource.gerrit.plugins.its.jira.workflow; + +import static junit.framework.TestCase.assertTrue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.googlesource.gerrit.plugins.its.base.workflow.ActionRequest; +import java.util.Collections; +import java.util.Optional; +import org.junit.Before; +import org.junit.Test; + +public class MarkPropertyAsReleasedVersionParametersExtractorTest { + + private static final String PROPERTY_ID = "propertyId"; + private static final String PROPERTY_VALUE = "propertyValue"; + + private MarkPropertyAsReleasedVersionParametersExtractor extractor; + + @Before + public void before() { + extractor = new MarkPropertyAsReleasedVersionParametersExtractor(); + } + + @Test + public void testNoParameter() { + testWrongNumberOfReceivedParameters(new String[] {}); + } + + @Test + public void testTwoParameters() { + testWrongNumberOfReceivedParameters(new String[] {PROPERTY_ID, PROPERTY_ID}); + } + + private void testWrongNumberOfReceivedParameters(String[] parameters) { + ActionRequest actionRequest = mock(ActionRequest.class); + when(actionRequest.getParameters()).thenReturn(parameters); + + Optional<MarkPropertyAsReleasedVersionParameters> extractedParameters = + extractor.extract(actionRequest, Collections.emptyMap()); + assertFalse(extractedParameters.isPresent()); + } + + @Test + public void testBlankPropertyId() { + ActionRequest actionRequest = mock(ActionRequest.class); + when(actionRequest.getParameters()).thenReturn(new String[] {""}); + + Optional<MarkPropertyAsReleasedVersionParameters> extractedParameters = + extractor.extract(actionRequest, Collections.emptyMap()); + assertFalse(extractedParameters.isPresent()); + } + + @Test + public void testUnknownPropertyId() { + ActionRequest actionRequest = mock(ActionRequest.class); + when(actionRequest.getParameters()).thenReturn(new String[] {PROPERTY_ID}); + + Optional<MarkPropertyAsReleasedVersionParameters> extractedParameters = + extractor.extract(actionRequest, Collections.emptyMap()); + assertFalse(extractedParameters.isPresent()); + } + + @Test + public void testHappyPath() { + ActionRequest actionRequest = mock(ActionRequest.class); + when(actionRequest.getParameters()).thenReturn(new String[] {PROPERTY_ID}); + + Optional<MarkPropertyAsReleasedVersionParameters> extractedParameters = + extractor.extract(actionRequest, Collections.singletonMap(PROPERTY_ID, PROPERTY_VALUE)); + assertTrue(extractedParameters.isPresent()); + assertEquals(PROPERTY_VALUE, extractedParameters.get().getPropertyValue()); + } +}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/jira/workflow/MarkPropertyAsReleasedVersionTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/jira/workflow/MarkPropertyAsReleasedVersionTest.java new file mode 100644 index 0000000..ad29c2a --- /dev/null +++ b/src/test/java/com/googlesource/gerrit/plugins/its/jira/workflow/MarkPropertyAsReleasedVersionTest.java
@@ -0,0 +1,80 @@ +// Copyright (C) 2018 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.googlesource.gerrit.plugins.its.jira.workflow; + +import static org.mockito.Mockito.*; + +import com.google.gerrit.reviewdb.client.Project; +import com.googlesource.gerrit.plugins.its.base.its.ItsFacade; +import com.googlesource.gerrit.plugins.its.base.workflow.ActionRequest; +import com.googlesource.gerrit.plugins.its.jira.JiraClient; +import com.googlesource.gerrit.plugins.its.jira.JiraItsServerInfo; +import com.googlesource.gerrit.plugins.its.jira.JiraItsServerInfoProvider; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import org.junit.Before; +import org.junit.Test; + +public class MarkPropertyAsReleasedVersionTest { + + private static final String ITS_PROJECT = "test-project"; + private static final String PROJECT_KEY = "project"; + private static final String PROJECT_NAME = "projectName"; + private static final String PROPERTY_ID = "propertyId"; + private static final String PROPERTY_VALUE = "propertyValue"; + + private ItsFacade its; + private JiraItsServerInfo serverInfo; + private JiraClient jiraClient; + private MarkPropertyAsReleasedVersionParametersExtractor parametersExtractor; + private MarkPropertyAsReleasedVersion markPropertyAsReleasedVersion; + + @Before + public void before() { + its = mock(ItsFacade.class); + JiraItsServerInfoProvider serverInfoProvider = mock(JiraItsServerInfoProvider.class); + serverInfo = mock(JiraItsServerInfo.class); + when(serverInfoProvider.get(new Project.NameKey(PROJECT_NAME))).thenReturn(serverInfo); + jiraClient = mock(JiraClient.class); + parametersExtractor = mock(MarkPropertyAsReleasedVersionParametersExtractor.class); + markPropertyAsReleasedVersion = + new MarkPropertyAsReleasedVersion(serverInfoProvider, jiraClient, parametersExtractor); + } + + @Test + public void testHappyPath() throws IOException { + MarkPropertyAsReleasedVersionParameters extractedParameters = + mock(MarkPropertyAsReleasedVersionParameters.class); + when(extractedParameters.getPropertyValue()).thenReturn(PROPERTY_VALUE); + + ActionRequest actionRequest = mock(ActionRequest.class); + Map<String, String> properties = buildProperties(); + when(parametersExtractor.extract(actionRequest, properties)) + .thenReturn(Optional.of(extractedParameters)); + + markPropertyAsReleasedVersion.execute(its, ITS_PROJECT, actionRequest, properties); + + verify(jiraClient).markVersionAsReleased(serverInfo, ITS_PROJECT, PROPERTY_VALUE); + } + + private Map<String, String> buildProperties() { + Map<String, String> properties = new HashMap<>(); + properties.put(PROPERTY_ID, PROJECT_NAME); + properties.put(PROJECT_KEY, PROJECT_NAME); + return properties; + } +}