diff --git a/.gitignore b/.gitignore index e3b1855..0390df0 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,9 @@ target/ bin/ #IDE specific files +projectFilesBackup/ .project .classpath -.idea *.iml + +.DS_Store diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..a3f3925 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,4 @@ +* +!codeStyleSettings.xml +!.gitignore +!codeStyles diff --git a/.idea/codeStyles/.gitignore b/.idea/codeStyles/.gitignore new file mode 100644 index 0000000..d7ec32e --- /dev/null +++ b/.idea/codeStyles/.gitignore @@ -0,0 +1 @@ +!*.xml diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..17804ca --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,135 @@ + + + + diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..79ee123 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index c395e28..5297975 100644 --- a/pom.xml +++ b/pom.xml @@ -13,12 +13,13 @@ See the License for the specific language governing permissions and limitations under the License. --> - + 4.0.0 com.meetme.plugins.jira gerrit-plugin - 3.5-SNAPSHOT + 3.4.1 MeetMe, Inc. @@ -67,14 +68,7 @@ ${jira.version} provided - - - + junit junit @@ -100,18 +94,11 @@ test - - com.atlassian.plugin - atlassian-spring-scanner-annotation - ${atlassian.spring.scanner.version} - compile - - com.atlassian.sal sal-api - 2.0.16 + ${atlas.sal.version} provided @@ -152,12 +139,26 @@ provided + + + com.google.guava + guava + 27.0.1-jre + provided + + + + org.slf4j + slf4j-api + 1.7.25 + provided + - com.sonyericsson.hudson.plugins.gerrit + com.sonymobile.tools.gerrit gerrit-events - 1.99.1 + 2.15.0 com.jcraft @@ -169,12 +170,12 @@ com.jcraft jsch - 0.1.54 + 0.1.55 commons-fileupload commons-fileupload - 1.3 + 1.4 @@ -207,13 +208,6 @@ - - maven-compiler-plugin - - 1.7 - 1.7 - - org.apache.maven.plugins maven-release-plugin @@ -222,35 +216,14 @@ org.apache.maven.scm maven-scm-provider-gitexe - 1.9.5 + 1.11.1 - - com.atlassian.plugin - atlassian-spring-scanner-maven-plugin - ${atlassian.spring.scanner.version} - - - - atlassian-spring-scanner - - process-classes - - - - - - com.atlassian.plugin - atlassian-spring-scanner-external-jar - - - false - - org.apache.maven.plugins maven-compiler-plugin + 3.8.0 1.8 1.8 @@ -261,19 +234,20 @@ 7.2.0 - 6.2.6 + 6.3.21 1.2.3 - 1.2.13 ${project.groupId}.${project.artifactId} 6.3.11 1.30.5 - 7.2.0 - 7.2.0 + ${jira.version} + ${jira.version} 3.0.8 3.0.0 3.0.0 - 3.0.5 + 3.1.0 + UTF-8 + UTF-8 diff --git a/src/aps/resources/log4j.properties b/src/aps/resources/log4j.properties index b7c5944..006197c 100644 --- a/src/aps/resources/log4j.properties +++ b/src/aps/resources/log4j.properties @@ -442,8 +442,8 @@ log4j.additivity.com.atlassian.mail.incoming = false log4j.logger.com.meetme = DEBUG, console, filelog log4j.additivity.com.meetme = true -log4j.logger.com.sonyericsson.hudson = INFO, console, filelog -log4j.additivity.com.sonyericsson.hudson = false +log4j.logger.com.sonymobile.tools = INFO, console, filelog +log4j.additivity.com.sonymobile.tools = false log4j.logger.com.jcraft = INFO, console, filelog log4j.additivity.com.jcraft = false diff --git a/src/main/java/com/meetme/plugins/jira/gerrit/adminui/AdminServlet.java b/src/main/java/com/meetme/plugins/jira/gerrit/adminui/AdminServlet.java index 61752f2..c74ea5a 100644 --- a/src/main/java/com/meetme/plugins/jira/gerrit/adminui/AdminServlet.java +++ b/src/main/java/com/meetme/plugins/jira/gerrit/adminui/AdminServlet.java @@ -1,11 +1,11 @@ /* * Copyright 2012 MeetMe, 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 @@ -17,14 +17,15 @@ import com.atlassian.jira.project.Project; import com.atlassian.jira.project.ProjectManager; import com.atlassian.sal.api.auth.LoginUriProvider; +import com.atlassian.sal.api.user.UserKey; import com.atlassian.sal.api.user.UserManager; import com.atlassian.templaterenderer.TemplateRenderer; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.meetme.plugins.jira.gerrit.data.GerritConfiguration; -import com.sonyericsson.hudson.plugins.gerrit.gerritevents.GerritQueryException; -import com.sonyericsson.hudson.plugins.gerrit.gerritevents.GerritQueryHandler; -import com.sonyericsson.hudson.plugins.gerrit.gerritevents.ssh.Authentication; +import com.sonymobile.tools.gerrit.gerritevents.GerritQueryException; +import com.sonymobile.tools.gerrit.gerritevents.GerritQueryHandler; +import com.sonymobile.tools.gerrit.gerritevents.ssh.Authentication; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileItemFactory; import org.apache.commons.fileupload.FileUploadException; @@ -54,12 +55,13 @@ public class AdminServlet extends HttpServlet { private static final long serialVersionUID = -9175363090552720328L; private static final Logger log = LoggerFactory.getLogger(AdminServlet.class); - private static final Object[] PACKAGE_PARTS = new String[] { "com", "meetme", "plugins", "jira", "gerrit" }; + private static final Object[] PACKAGE_PARTS = new String[]{"com", "meetme", "plugins", "jira", "gerrit"}; private static final String CONTENT_TYPE = "text/html;charset=utf-8"; private static final String FIELD_ACTION = "action"; private static final String ACTION_SAVE = "save"; private static final String ACTION_TEST = "test"; + private static final String ACTION_CLEAR_CACHE = "clear-cache"; private static String TEMPLATE_ADMIN = "templates/admin.vm"; @@ -71,7 +73,7 @@ public class AdminServlet extends HttpServlet { private final GerritConfiguration configurationManager; public AdminServlet(final UserManager userManager, final LoginUriProvider loginUriProvider, final TemplateRenderer renderer, - final JiraHome jiraHome, final GerritConfiguration configurationManager, final ProjectManager projectManager) { + final JiraHome jiraHome, final GerritConfiguration configurationManager, final ProjectManager projectManager) { this.userManager = userManager; this.loginUriProvider = loginUriProvider; this.renderer = renderer; @@ -82,7 +84,7 @@ public AdminServlet(final UserManager userManager, final LoginUriProvider loginU @Override protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException, ServletException { - String username = userManager.getRemoteUsername(request); + UserKey username = userManager.getRemoteUserKey(request); if (username == null || !userManager.isSystemAdmin(username)) { redirectToLogin(request, response); @@ -100,7 +102,7 @@ private Map configToMap(final GerritConfiguration config) { map.put(GerritConfiguration.FIELD_SSH_PORT, config.getSshPort()); map.put(GerritConfiguration.FIELD_SSH_USERNAME, config.getSshUsername()); map.put(GerritConfiguration.FIELD_SSH_PRIVATE_KEY, config.getSshPrivateKey()); - + map.put(GerritConfiguration.FIELD_SSH_TIMEOUT, config.getConnectionTimeout()); map.put(GerritConfiguration.FIELD_QUERY_ISSUE, config.getIssueSearchQuery()); map.put(GerritConfiguration.FIELD_QUERY_PROJECT, config.getProjectSearchQuery()); @@ -119,7 +121,7 @@ private Map configToMap(final GerritConfiguration config) { map.put(GerritConfiguration.FIELD_KNOWN_GERRIT_PROJECTS, projectsUsingGerrit); map.put(GerritConfiguration.FIELD_USE_GERRIT_PROJECT_WHITELIST, String.valueOf(config .getUseGerritProjectWhitelist())); - + map.put(GerritConfiguration.FIELD_CACHE_TIMEOUT, config.getCacheTimeout()); return map; } @@ -140,7 +142,7 @@ protected void doPost(final HttpServletRequest req, final HttpServletResponse re } private Map handlePost(HttpServletRequest req, HttpServletResponse resp) throws IOException { - String username = userManager.getRemoteUsername(req); + UserKey username = userManager.getRemoteUserKey(req); if (username == null || !userManager.isSystemAdmin(username)) { redirectToLogin(req, resp); @@ -183,6 +185,9 @@ private Map handlePost(HttpServletRequest req, HttpServletRespon if (ACTION_TEST.equals(action)) { performConnectionTest(configurationManager, map); } + if (ACTION_CLEAR_CACHE.equalsIgnoreCase(action)){ + + } return map; } @@ -196,20 +201,22 @@ private void performConnectionTest(GerritConfiguration configuration, Map items) { for (FileItem item : items) { final String fieldName = item.getFieldName(); @@ -227,24 +234,40 @@ private void setAllFields(final List items) { final String fieldName = item.getFieldName(); allFields.add(fieldName); - if (GerritConfiguration.FIELD_HTTP_BASE_URL.equals(fieldName)) { - configurationManager.setHttpBaseUrl(item.getString()); - } else if (GerritConfiguration.FIELD_HTTP_USERNAME.equals(fieldName)) { - configurationManager.setHttpUsername(item.getString()); - } else if (GerritConfiguration.FIELD_HTTP_PASSWORD.equals(fieldName)) { - configurationManager.setHttpPassword(item.getString()); - } else if (GerritConfiguration.FIELD_SSH_HOSTNAME.equals(fieldName)) { - configurationManager.setSshHostname(item.getString()); - } else if (GerritConfiguration.FIELD_SSH_USERNAME.equals(fieldName)) { - configurationManager.setSshUsername(item.getString()); - } else if (GerritConfiguration.FIELD_SSH_PORT.equals(fieldName)) { - configurationManager.setSshPort(Integer.parseInt(item.getString())); - } else if (GerritConfiguration.FIELD_QUERY_ISSUE.equals(fieldName)) { - configurationManager.setIssueSearchQuery(item.getString()); - } else if (GerritConfiguration.FIELD_QUERY_PROJECT.equals(fieldName)) { - configurationManager.setProjectSearchQuery(item.getString()); - } else if (GerritConfiguration.FIELD_KNOWN_GERRIT_PROJECTS.equals(fieldName)) { - idsOfSelectedGerritProjects.add(item.getString()); + switch (fieldName) { + case GerritConfiguration.FIELD_HTTP_BASE_URL: + configurationManager.setHttpBaseUrl(item.getString()); + break; + case GerritConfiguration.FIELD_HTTP_USERNAME: + configurationManager.setHttpUsername(item.getString()); + break; + case GerritConfiguration.FIELD_HTTP_PASSWORD: + configurationManager.setHttpPassword(item.getString()); + break; + case GerritConfiguration.FIELD_SSH_HOSTNAME: + configurationManager.setSshHostname(item.getString()); + break; + case GerritConfiguration.FIELD_SSH_USERNAME: + configurationManager.setSshUsername(item.getString()); + break; + case GerritConfiguration.FIELD_SSH_PORT: + configurationManager.setSshPort(Integer.parseInt(item.getString())); + break; + case GerritConfiguration.FIELD_SSH_TIMEOUT: + configurationManager.setConnectionTimeout(Integer.parseInt(item.getString())); + break; + case GerritConfiguration.FIELD_QUERY_ISSUE: + configurationManager.setIssueSearchQuery(item.getString()); + break; + case GerritConfiguration.FIELD_QUERY_PROJECT: + configurationManager.setProjectSearchQuery(item.getString()); + break; + case GerritConfiguration.FIELD_KNOWN_GERRIT_PROJECTS: + idsOfSelectedGerritProjects.add(item.getString()); + break; + case GerritConfiguration.FIELD_CACHE_TIMEOUT: + configurationManager.setCacheTimeout(Integer.parseInt(item.getString())); + break; } } diff --git a/src/main/java/com/meetme/plugins/jira/gerrit/data/GerritCommand.java b/src/main/java/com/meetme/plugins/jira/gerrit/data/GerritCommand.java index 3a5d51d..1f28398 100644 --- a/src/main/java/com/meetme/plugins/jira/gerrit/data/GerritCommand.java +++ b/src/main/java/com/meetme/plugins/jira/gerrit/data/GerritCommand.java @@ -19,26 +19,25 @@ import java.io.InputStreamReader; import java.util.List; +import com.atlassian.jira.user.preferences.ExtendedPreferences; +import com.sonymobile.tools.gerrit.gerritevents.ssh.Authentication; +import com.sonymobile.tools.gerrit.gerritevents.ssh.SshConnection; +import com.sonymobile.tools.gerrit.gerritevents.ssh.SshConnectionFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.atlassian.core.user.preferences.Preferences; import com.jcraft.jsch.ChannelExec; import com.meetme.plugins.jira.gerrit.data.dto.GerritChange; -import com.sonyericsson.hudson.plugins.gerrit.gerritevents.ssh.Authentication; -import com.sonyericsson.hudson.plugins.gerrit.gerritevents.ssh.SshConnection; -import com.sonyericsson.hudson.plugins.gerrit.gerritevents.ssh.SshConnectionFactory; -import com.sonyericsson.hudson.plugins.gerrit.gerritevents.ssh.SshException; public class GerritCommand { private static final Logger log = LoggerFactory.getLogger(GerritCommand.class); private final static String BASE_COMMAND = "gerrit review"; private GerritConfiguration config; - private Preferences userPreferences; + private ExtendedPreferences extendedPreferences; - public GerritCommand(GerritConfiguration config, Preferences userPreferences) { + public GerritCommand(GerritConfiguration config, ExtendedPreferences extendedPreferences) { this.config = config; - this.userPreferences = userPreferences; + this.extendedPreferences = extendedPreferences; } public boolean doReview(GerritChange change, String args) throws IOException { @@ -63,13 +62,11 @@ private boolean runCommand(String command) throws IOException { @SuppressWarnings("deprecation") private String getCommand(GerritChange change, String args) { - StringBuilder sb = new StringBuilder(BASE_COMMAND); - sb.append(' '); - sb.append(change.getNumber()).append(',').append(change.getPatchSet().getNumber()); // TODO: escape args? Or build manually with String reviewType,int reviewScore,etc..? - sb.append(' ').append(args); - return sb.toString(); + return BASE_COMMAND + ' ' + + change.getNumber() + ',' + change.getPatchSet().getNumber() + + ' ' + args; } private boolean runCommands(String[] commands) throws IOException { @@ -103,11 +100,11 @@ private boolean runCommands(String[] commands) throws IOException { private Authentication getAuthentication() { Authentication auth = null; - if (userPreferences != null) { + if (extendedPreferences != null) { // Attempt to get a per-user authentication mechanism, so JIRA can act as the user. try { - String privateKey = userPreferences.getString("gerrit.privateKey"); - String username = userPreferences.getString("gerrit.username"); + String privateKey = extendedPreferences.getString("gerrit.privateKey"); + String username = extendedPreferences.getString("gerrit.username"); if (privateKey != null && username != null && !privateKey.isEmpty() && !username.isEmpty()) { @@ -129,7 +126,7 @@ private Authentication getAuthentication() { return auth; } - private boolean runCommand(SshConnection ssh, String command) throws SshException, IOException { + private boolean runCommand(SshConnection ssh, String command) throws IOException { boolean success = false; ChannelExec channel = null; diff --git a/src/main/java/com/meetme/plugins/jira/gerrit/data/GerritConfiguration.java b/src/main/java/com/meetme/plugins/jira/gerrit/data/GerritConfiguration.java index a82a990..0f05c84 100644 --- a/src/main/java/com/meetme/plugins/jira/gerrit/data/GerritConfiguration.java +++ b/src/main/java/com/meetme/plugins/jira/gerrit/data/GerritConfiguration.java @@ -13,20 +13,25 @@ */ package com.meetme.plugins.jira.gerrit.data; +import com.atlassian.jira.issue.Issue; + import java.io.File; import java.net.URI; import java.util.List; +import static org.apache.commons.collections.CollectionUtils.isEmpty; + public interface GerritConfiguration { int DEFAULT_SSH_PORT = 29418; String DEFAULT_QUERY_ISSUE = "tr:%s"; String DEFAULT_QUERY_PROJECT = "message:%s-*"; + int DEFAULT_SSH_TIMEOUT = 0; String FIELD_SSH_HOSTNAME = "sshHostname"; String FIELD_SSH_USERNAME = "sshUsername"; String FIELD_SSH_PORT = "sshPort"; String FIELD_SSH_PRIVATE_KEY = "sshPrivateKey"; - + String FIELD_SSH_TIMEOUT = "sshTimeout"; String FIELD_QUERY_ISSUE = "issueSearchQuery"; String FIELD_QUERY_PROJECT = "projectSearchQuery"; @@ -39,6 +44,9 @@ public interface GerritConfiguration { String FIELD_KNOWN_GERRIT_PROJECTS = "knownGerritProjects"; String FIELD_USE_GERRIT_PROJECT_WHITELIST = "useGerritProjectWhitelist"; + long DEFAULT_CACHE_TIMEOUT = 30000; + String FIELD_CACHE_TIMEOUT = "cacheTimeout"; + URI getHttpBaseUrl(); String getHttpPassword(); @@ -59,6 +67,10 @@ public interface GerritConfiguration { boolean getShowsEmptyPanel(); + int getConnectionTimeout(); + + long getCacheTimeout(); + void setHttpBaseUrl(String httpBaseUrl); void setHttpPassword(String httpPassword); @@ -79,8 +91,14 @@ public interface GerritConfiguration { void setShowEmptyPanel(boolean show); + void setConnectionTimeout(int connectionTimeout); + + void setCacheTimeout(long cacheTimeout); + boolean isSshValid(); + boolean isGerritProject(final Issue issue); + List getIdsOfKnownGerritProjects(); void setIdsOfKnownGerritProjects(List idsOfSelectedGerritProjects); @@ -107,4 +125,5 @@ public NotConfiguredException(String message, Throwable cause, boolean enableSup super(message, cause, enableSuppression, writableStackTrace); } } + } diff --git a/src/main/java/com/meetme/plugins/jira/gerrit/data/GerritConfigurationImpl.java b/src/main/java/com/meetme/plugins/jira/gerrit/data/GerritConfigurationImpl.java index 0cfc92d..35b7b9a 100644 --- a/src/main/java/com/meetme/plugins/jira/gerrit/data/GerritConfigurationImpl.java +++ b/src/main/java/com/meetme/plugins/jira/gerrit/data/GerritConfigurationImpl.java @@ -13,15 +13,19 @@ */ package com.meetme.plugins.jira.gerrit.data; +import com.atlassian.jira.issue.Issue; import com.atlassian.sal.api.pluginsettings.PluginSettings; import com.atlassian.sal.api.pluginsettings.PluginSettingsFactory; import com.google.common.base.Strings; import com.google.common.collect.Lists; +import com.sonymobile.tools.gerrit.gerritevents.GerritDefaultValues; import java.io.File; import java.net.URI; import java.util.List; +import static org.apache.commons.collections.CollectionUtils.isEmpty; + /** * {@link GerritConfiguration} implementation that uses {@link PluginSettings} to store * configuration data. @@ -131,6 +135,29 @@ public void setSshUsername(String username) { settings.put(FIELD_SSH_USERNAME, username); } + @Override + public int getConnectionTimeout() { + String timeout = (String) settings.get(FIELD_SSH_TIMEOUT); + return timeout == null ? DEFAULT_SSH_TIMEOUT : Integer.parseInt(timeout); + } + + @Override + public void setConnectionTimeout(int connectionTimeout) { + settings.put(FIELD_SSH_TIMEOUT, connectionTimeout < 0 ? GerritDefaultValues.DEFAULT_GERRIT_SSH_CONNECTION_TIMEOUT : Integer.toString(connectionTimeout)); + } + + @Override + public long getCacheTimeout() { + String timeout = (String) settings.get(FIELD_CACHE_TIMEOUT); + return timeout == null ? DEFAULT_CACHE_TIMEOUT : Integer.parseInt(timeout); + } + + @Override + public void setCacheTimeout(long cacheTimeout) { + settings.put(FIELD_CACHE_TIMEOUT, cacheTimeout < 0 ? DEFAULT_CACHE_TIMEOUT : Long.toString(cacheTimeout)); + } + + @Override public boolean getShowsEmptyPanel() { String shows = (String) settings.get(FIELD_SHOW_EMPTY_PANEL); @@ -151,6 +178,11 @@ && getSshPrivateKey() != null && getSshPrivateKey().exists(); } + @Override + public boolean isGerritProject(final Issue issue) { + return issue.getProjectId() != null && !isEmpty(getIdsOfKnownGerritProjects()) && getIdsOfKnownGerritProjects().contains(issue.getProjectId().toString()); + } + @Override public List getIdsOfKnownGerritProjects() { List idsOfKnownGerritProjects = (List) settings.get(FIELD_KNOWN_GERRIT_PROJECTS); @@ -166,7 +198,10 @@ public void setIdsOfKnownGerritProjects(final List idsOfSelectedGerritPr public boolean getUseGerritProjectWhitelist() { String useGerritProjectWhitelist = (String) settings.get(FIELD_USE_GERRIT_PROJECT_WHITELIST); // Defaults to the behavior without whitelist: - return useGerritProjectWhitelist == null ? false : "true".equals(useGerritProjectWhitelist); + if (useGerritProjectWhitelist == null || useGerritProjectWhitelist.isEmpty()){ + return false; + } + return "true".equals(useGerritProjectWhitelist); } @Override diff --git a/src/main/java/com/meetme/plugins/jira/gerrit/data/IssueReviewsCache.java b/src/main/java/com/meetme/plugins/jira/gerrit/data/IssueReviewsCache.java index 6fab2d3..e061060 100644 --- a/src/main/java/com/meetme/plugins/jira/gerrit/data/IssueReviewsCache.java +++ b/src/main/java/com/meetme/plugins/jira/gerrit/data/IssueReviewsCache.java @@ -7,15 +7,17 @@ import java.util.List; import java.util.Map; +import static com.meetme.plugins.jira.gerrit.data.GerritConfiguration.DEFAULT_CACHE_TIMEOUT; + /** * Created by jhansche on 9/2/16. */ -public class IssueReviewsCache { +class IssueReviewsCache { /** Max number of items to retain in the cache */ private static final int CACHE_CAPACITY = 30; /** Number of milliseconds an item may stay in cache: 30 seconds */ - private static final long CACHE_EXPIRATION = 30000; + private static final long CACHE_EXPIRATION = DEFAULT_CACHE_TIMEOUT; /** * LRU (least recently used) Cache object to avoid slamming the Gerrit server too many times. @@ -32,6 +34,8 @@ public static synchronized Map> getCache() { return lruCache; } + public static void clearCache(){ lruCache.clear();} + private static class TimedCache extends LinkedHashMap> { private static final long serialVersionUID = 296909003142207307L; @@ -42,7 +46,7 @@ private static class TimedCache extends LinkedHashMap public TimedCache(final int capacity, final long expiration) { super(capacity + 1, 1.0f, true); this.capacity = capacity; - this.timestamps = new LinkedHashMap(capacity + 1, 1.0f, true); + this.timestamps = new LinkedHashMap<>(capacity + 1, 1.0f, true); this.expiration = expiration; } @@ -53,12 +57,12 @@ public TimedCache(final int capacity, final long expiration) { * @return whether the associated value exists and has expired */ private boolean hasKeyExpired(Object key) { - if (timestamps.containsKey(key)) { - Long lastUpdatedTimestamp = timestamps.get(key); - return lastUpdatedTimestamp <= System.currentTimeMillis() - expiration; + if (!timestamps.containsKey(key)) { + return false; } + Long lastUpdatedTimestamp = timestamps.get(key); + return lastUpdatedTimestamp <= System.currentTimeMillis() - expiration; - return false; } @Override @@ -101,5 +105,13 @@ public List remove(Object key) { timestamps.remove(key); return super.remove(key); } + + /** + * Clean all values from maps + */ + @Override + public void clear(){ + super.clear(); + } } } diff --git a/src/main/java/com/meetme/plugins/jira/gerrit/data/IssueReviewsImpl.java b/src/main/java/com/meetme/plugins/jira/gerrit/data/IssueReviewsImpl.java index ce1ad33..e52563a 100644 --- a/src/main/java/com/meetme/plugins/jira/gerrit/data/IssueReviewsImpl.java +++ b/src/main/java/com/meetme/plugins/jira/gerrit/data/IssueReviewsImpl.java @@ -13,21 +13,23 @@ */ package com.meetme.plugins.jira.gerrit.data; +import com.atlassian.jira.user.preferences.ExtendedPreferences; import com.meetme.plugins.jira.gerrit.data.dto.GerritChange; -import com.atlassian.core.user.preferences.Preferences; import com.atlassian.jira.issue.Issue; import com.atlassian.jira.issue.IssueManager; -import com.sonyericsson.hudson.plugins.gerrit.gerritevents.GerritQueryException; -import com.sonyericsson.hudson.plugins.gerrit.gerritevents.GerritQueryHandler; -import com.sonyericsson.hudson.plugins.gerrit.gerritevents.ssh.Authentication; -import com.sonyericsson.hudson.plugins.gerrit.gerritevents.ssh.SshException; +import com.sonymobile.tools.gerrit.gerritevents.GerritQueryException; +import com.sonymobile.tools.gerrit.gerritevents.GerritQueryHandler; +import com.sonymobile.tools.gerrit.gerritevents.GerritQueryHandlerWithPersistedConnection; +import com.sonymobile.tools.gerrit.gerritevents.ssh.Authentication; +import com.sonymobile.tools.gerrit.gerritevents.ssh.SshException; import net.sf.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; @@ -43,6 +45,10 @@ public class IssueReviewsImpl implements IssueReviewsManager { private IssueManager jiraIssueManager; + private GerritQueryHandlerWithPersistedConnection queryHandler; + + private QueryHandlerConfig queryHandlerConfig; + public IssueReviewsImpl(GerritConfiguration configuration, IssueManager jiraIssueManager) { this.configuration = configuration; this.jiraIssueManager = jiraIssueManager; @@ -56,7 +62,7 @@ public Set getIssueKeys(Issue issue) { @Override public List getReviewsForIssue(Issue issue) throws GerritQueryException { - List gerritChanges = new ArrayList(); + List gerritChanges = new ArrayList<>(); Set allIssueKeys = getIssueKeys(issue); for (String key : allIssueKeys) { @@ -81,15 +87,13 @@ protected List getReviewsFromGerrit(String searchQuery) throws Ger List changes; if (!configuration.isSshValid()) { - // return Collections.emptyList(); throw new GerritConfiguration.NotConfiguredException("Not configured for SSH access"); } - Authentication auth = new Authentication(configuration.getSshPrivateKey(), configuration.getSshUsername()); - GerritQueryHandler query = new GerritQueryHandler(configuration.getSshHostname(), configuration.getSshPort(), null, auth); List reviews; try { + GerritQueryHandler query = getQueryHandler(configuration); reviews = query.queryJava(searchQuery, false, true, false); } catch (SshException e) { throw new GerritQueryException("An ssh error occurred while querying for reviews.", e); @@ -97,7 +101,7 @@ protected List getReviewsFromGerrit(String searchQuery) throws Ger throw new GerritQueryException("An error occurred while querying for reviews.", e); } - changes = new ArrayList(reviews.size()); + changes = new ArrayList<>(reviews.size()); for (JSONObject obj : reviews) { if (obj.has("type") && "stats".equalsIgnoreCase(obj.getString("type"))) { @@ -116,13 +120,33 @@ protected List getReviewsFromGerrit(String searchQuery) throws Ger return changes; } + private GerritQueryHandler getQueryHandler(GerritConfiguration configuration) { + QueryHandlerConfig config = new QueryHandlerConfig(configuration.getSshPrivateKey(), + configuration.getSshUsername(), configuration.getSshHostname(), + configuration.getSshPort(), configuration.getConnectionTimeout()); + boolean configChanged = !config.equals(queryHandlerConfig); + + if (queryHandler == null || configChanged) { + if (queryHandler != null) { + log.debug("QueryHandler configuration has changed, creating a fresh connection."); + queryHandler.disconnect(); + } + Authentication auth = new Authentication(configuration.getSshPrivateKey(), configuration.getSshUsername()); + queryHandler = new GerritQueryHandlerWithPersistedConnection(configuration.getSshHostname(), configuration.getSshPort(), + null, auth, configuration.getConnectionTimeout()); + queryHandlerConfig = config; + log.debug("QueryHandler with a fresh SSH connection was created."); + } + return queryHandler; + } + @Override - public boolean doApprovals(Issue issue, List changes, String args, Preferences prefs) throws IOException { + public boolean doApprovals(Issue issue, List changes, String args, ExtendedPreferences prefs) throws IOException { Set issueKeys = getIssueKeys(issue); boolean result = true; for (String issueKey : issueKeys) { - GerritCommand command = new GerritCommand(configuration, prefs); + GerritCommand command = new GerritCommand(configuration,prefs); boolean commandResult = command.doReviews(changes, args); result &= commandResult; @@ -137,4 +161,45 @@ public boolean doApprovals(Issue issue, List changes, String args, return result; } + + private static class QueryHandlerConfig { + File currentSshPrivateKey; + String currentSshUsername; + String currentSshHostname; + int currentSshPort; + int currentConnectionTimeout; + + QueryHandlerConfig(File currentSshPrivateKey, String currentSshUsername, String currentSshHostname, + int currentSshPort, int currentConnectionTimeout) { + this.currentSshPrivateKey = currentSshPrivateKey; + this.currentSshUsername = currentSshUsername; + this.currentSshHostname = currentSshHostname; + this.currentSshPort = currentSshPort; + this.currentConnectionTimeout = currentConnectionTimeout; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + QueryHandlerConfig that = (QueryHandlerConfig) o; + + if (currentSshPort != that.currentSshPort) return false; + if (currentConnectionTimeout != that.currentConnectionTimeout) return false; + if (!currentSshPrivateKey.equals(that.currentSshPrivateKey)) return false; + if (!currentSshUsername.equals(that.currentSshUsername)) return false; + return currentSshHostname.equals(that.currentSshHostname); + } + + // we don't care about hashcode + @Override + public int hashCode() { + return 0; + } + } } diff --git a/src/main/java/com/meetme/plugins/jira/gerrit/data/IssueReviewsManager.java b/src/main/java/com/meetme/plugins/jira/gerrit/data/IssueReviewsManager.java index aeada63..56a4423 100644 --- a/src/main/java/com/meetme/plugins/jira/gerrit/data/IssueReviewsManager.java +++ b/src/main/java/com/meetme/plugins/jira/gerrit/data/IssueReviewsManager.java @@ -13,13 +13,12 @@ */ package com.meetme.plugins.jira.gerrit.data; -import com.atlassian.core.user.preferences.Preferences; import com.atlassian.jira.issue.Issue; -import com.atlassian.jira.project.Project; +import com.atlassian.jira.user.preferences.ExtendedPreferences; import com.meetme.plugins.jira.gerrit.data.dto.GerritChange; -import com.sonyericsson.hudson.plugins.gerrit.gerritevents.GerritQueryException; -import com.sonyericsson.hudson.plugins.gerrit.gerritevents.GerritQueryHandler; +import com.sonymobile.tools.gerrit.gerritevents.GerritQueryException; +import com.sonymobile.tools.gerrit.gerritevents.GerritQueryHandler; import net.sf.json.JSONObject; import java.io.IOException; @@ -52,9 +51,9 @@ public interface IssueReviewsManager { * @param issue the JIRA issue * @param changes the set of Gerrit changes * @param args arguments to add to each approval - * @param prefs the {@link Preferences} for the viewing user + * @param prefs the {@link ExtendedPreferences} for the viewing user * @return whether the approvals were successful * @throws IOException if so */ - boolean doApprovals(Issue issue, List changes, String args, Preferences prefs) throws IOException; + boolean doApprovals(Issue issue, List changes, String args, ExtendedPreferences prefs) throws IOException; } diff --git a/src/main/java/com/meetme/plugins/jira/gerrit/data/dto/GerritApproval.java b/src/main/java/com/meetme/plugins/jira/gerrit/data/dto/GerritApproval.java index dd24042..eca717b 100644 --- a/src/main/java/com/meetme/plugins/jira/gerrit/data/dto/GerritApproval.java +++ b/src/main/java/com/meetme/plugins/jira/gerrit/data/dto/GerritApproval.java @@ -13,28 +13,21 @@ */ package com.meetme.plugins.jira.gerrit.data.dto; -import com.atlassian.crowd.embedded.api.User; -import com.sonyericsson.hudson.plugins.gerrit.gerritevents.dto.attr.Approval; - +import com.sonymobile.tools.gerrit.gerritevents.dto.attr.Approval; import net.sf.json.JSONObject; - import com.atlassian.jira.user.ApplicationUser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static com.meetme.plugins.jira.gerrit.tabpanel.GerritEventKeys.BY; -import static com.sonyericsson.hudson.plugins.gerrit.gerritevents.dto.GerritEventKeys.EMAIL; -import static com.sonyericsson.hudson.plugins.gerrit.gerritevents.dto.GerritEventKeys.NAME; -import com.sonyericsson.hudson.plugins.gerrit.gerritevents.dto.attr.Approval; +import static com.sonymobile.tools.gerrit.gerritevents.dto.GerritEventKeys.BY; +import static com.sonymobile.tools.gerrit.gerritevents.dto.GerritEventKeys.EMAIL; +import static com.sonymobile.tools.gerrit.gerritevents.dto.GerritEventKeys.NAME; public class GerritApproval extends Approval implements Comparable { private static final Logger log = LoggerFactory.getLogger(GerritApproval.class); - /** The approver's name */ - private String by; - /** The approver's email */ - private String byEmail; + /** The JIRA user associated with the same email */ private ApplicationUser user; @@ -63,18 +56,6 @@ public ApplicationUser getUser() { public void fromJson(JSONObject json) { log.debug("GerritApproval from json: " + json.toString(4, 0)); super.fromJson(json); - - if (json.containsKey(BY)) { - JSONObject by = json.getJSONObject(BY); - - if (by.containsKey(NAME)) { - this.setBy(by.getString(NAME)); - } - - if (by.containsKey(EMAIL)) { - this.setByEmail(by.getString(EMAIL)); - } - } } @Override @@ -95,24 +76,6 @@ public static String getUpgradedLabelType(String type) { return type; } - /** - * Returns the approver's name. - * - * @return Approver's name as a string. - */ - public String getBy() { - return by; - } - - /** - * Sets the approver's name. - * - * @param by Approver's name - */ - public void setBy(String by) { - this.by = by; - } - /** * Returns the approval score as an integer. * @@ -128,14 +91,6 @@ public int getValueAsInt() { return 0; } - public String getByEmail() { - return byEmail; - } - - public void setByEmail(String byEmail) { - this.byEmail = byEmail; - } - @Override public int compareTo(GerritApproval o) { int lhs = getValueAsInt(); @@ -151,6 +106,6 @@ public int compareTo(GerritApproval o) { @Override public String toString() { int value = getValueAsInt(); - return (value > 0 ? "+" : "") + value + " by " + getBy(); + return (value > 0 ? "+" : "") + value + " by " + getBy().getName(); } } diff --git a/src/main/java/com/meetme/plugins/jira/gerrit/data/dto/GerritChange.java b/src/main/java/com/meetme/plugins/jira/gerrit/data/dto/GerritChange.java index 058346e..544a55c 100644 --- a/src/main/java/com/meetme/plugins/jira/gerrit/data/dto/GerritChange.java +++ b/src/main/java/com/meetme/plugins/jira/gerrit/data/dto/GerritChange.java @@ -14,8 +14,9 @@ package com.meetme.plugins.jira.gerrit.data.dto; import com.meetme.plugins.jira.gerrit.tabpanel.GerritEventKeys; -import com.sonyericsson.hudson.plugins.gerrit.gerritevents.dto.attr.Change; +import com.sonymobile.tools.gerrit.gerritevents.dto.GerritChangeStatus; +import com.sonymobile.tools.gerrit.gerritevents.dto.attr.Change; import net.sf.json.JSONObject; import java.util.Date; @@ -31,7 +32,7 @@ public class GerritChange extends Change implements Comparable { * Gerrit review status enumeration, corresponding to the status string in the Gerrit change * payload. */ - public static enum Status + public enum Status { NEW, SUBMITTED, DRAFT, MERGED, ABANDONED } @@ -42,7 +43,7 @@ public static enum Status private boolean isOpen; - private Status status; + private GerritChangeStatus status; public GerritChange() { super(); @@ -60,7 +61,6 @@ public GerritChange(JSONObject obj) { * refactored such that it is then dependent on a later change! */ @Override - @SuppressWarnings("deprecation") public int compareTo(GerritChange obj) { if (this != obj && obj != null) { int aNum = Integer.parseInt(this.getNumber()); @@ -87,7 +87,7 @@ public void fromJson(JSONObject json) { } if (json.containsKey(GerritEventKeys.STATUS)) { - this.setStatus(Status.valueOf(json.getString(GerritEventKeys.STATUS))); + this.setStatus(GerritChangeStatus.valueOf(json.getString(com.sonymobile.tools.gerrit.gerritevents.dto.GerritEventKeys.STATUS))); } this.isOpen = json.getBoolean(GerritEventKeys.OPEN); @@ -101,7 +101,7 @@ public GerritPatchSet getPatchSet() { return patchSet; } - public Status getStatus() { + public GerritChangeStatus getStatus() { return status; } @@ -121,7 +121,7 @@ public void setPatchSet(GerritPatchSet patchSet) { this.patchSet = patchSet; } - public void setStatus(Status status) { + public void setStatus(GerritChangeStatus status) { this.status = status; } } diff --git a/src/main/java/com/meetme/plugins/jira/gerrit/data/dto/GerritPatchSet.java b/src/main/java/com/meetme/plugins/jira/gerrit/data/dto/GerritPatchSet.java index dc3f048..a22e33b 100644 --- a/src/main/java/com/meetme/plugins/jira/gerrit/data/dto/GerritPatchSet.java +++ b/src/main/java/com/meetme/plugins/jira/gerrit/data/dto/GerritPatchSet.java @@ -18,14 +18,14 @@ import java.util.List; import java.util.Map; +import com.sonymobile.tools.gerrit.gerritevents.dto.GerritEventKeys; +import com.sonymobile.tools.gerrit.gerritevents.dto.attr.PatchSet; import net.sf.json.JSONArray; import net.sf.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.sonyericsson.hudson.plugins.gerrit.gerritevents.dto.GerritEventKeys; -import com.sonyericsson.hudson.plugins.gerrit.gerritevents.dto.attr.PatchSet; public class GerritPatchSet extends PatchSet { private static final Logger log = LoggerFactory.getLogger(GerritPatchSet.class); @@ -47,7 +47,7 @@ public void fromJson(JSONObject json) { if (json.containsKey(GerritEventKeys.APPROVALS)) { JSONArray eventApprovals = json.getJSONArray(GerritEventKeys.APPROVALS); - approvals = new ArrayList(eventApprovals.size()); + approvals = new ArrayList<>(eventApprovals.size()); for (int i = 0; i < eventApprovals.size(); i++) { GerritApproval approval = new GerritApproval(eventApprovals.getJSONObject(i)); @@ -63,27 +63,21 @@ public List getApprovals() { } public Map> getApprovalsByLabel() { - Map> map = new HashMap>(); + Map> map = new HashMap<>(); List l; for (GerritApproval approval : approvals) { String type = approval.getType(); - - l = map.get(type); - - if (l == null) { - l = new ArrayList(); - map.put(type, l); - } - + l = map.computeIfAbsent(type, k -> new ArrayList<>()); l.add(approval); + map.put(type, l); } return map; } public List getApprovalsForLabel(String label) { - List filtered = new ArrayList(); + List filtered = new ArrayList<>(); if (approvals != null) { for (GerritApproval approval : approvals) { diff --git a/src/main/java/com/meetme/plugins/jira/gerrit/tabpanel/GerritEventKeys.java b/src/main/java/com/meetme/plugins/jira/gerrit/tabpanel/GerritEventKeys.java index 768c785..be390c6 100644 --- a/src/main/java/com/meetme/plugins/jira/gerrit/tabpanel/GerritEventKeys.java +++ b/src/main/java/com/meetme/plugins/jira/gerrit/tabpanel/GerritEventKeys.java @@ -14,8 +14,8 @@ package com.meetme.plugins.jira.gerrit.tabpanel; /** - * Extension of {@link com.sonyericsson.hudson.plugins.gerrit.gerritevents.dto.GerritEventKeys - * sonyericsson.GerritEventKeys} to provide additional missing keys. + * Extension of {@link com.sonymobile.tools.gerrit.gerritevents.dto.GerritEventKeys} + * to provide additional missing keys. * * @author Joe Hansche */ diff --git a/src/main/java/com/meetme/plugins/jira/gerrit/tabpanel/GerritReviewIssueAction.java b/src/main/java/com/meetme/plugins/jira/gerrit/tabpanel/GerritReviewIssueAction.java index 4c80ad4..8c85e3a 100644 --- a/src/main/java/com/meetme/plugins/jira/gerrit/tabpanel/GerritReviewIssueAction.java +++ b/src/main/java/com/meetme/plugins/jira/gerrit/tabpanel/GerritReviewIssueAction.java @@ -13,11 +13,12 @@ */ package com.meetme.plugins.jira.gerrit.tabpanel; -import com.atlassian.core.util.map.EasyMap; import com.atlassian.jira.plugin.issuetabpanel.AbstractIssueAction; import com.atlassian.jira.plugin.issuetabpanel.IssueAction; import com.atlassian.jira.plugin.issuetabpanel.IssueTabPanelModuleDescriptor; + import com.atlassian.jira.web.util.OutlookDate; +import com.google.common.collect.ImmutableMap; import com.meetme.plugins.jira.gerrit.data.dto.GerritApproval; import com.meetme.plugins.jira.gerrit.data.dto.GerritChange; @@ -41,9 +42,8 @@ public GerritReviewIssueAction(IssueTabPanelModuleDescriptor descriptor, GerritC } @Override - @SuppressWarnings("unchecked") - protected void populateVelocityParams(@SuppressWarnings("rawtypes") Map params) { - params.putAll(EasyMap.build("change", change, + protected void populateVelocityParams(Map params) { + params.putAll(ImmutableMap.of("change", change, "formatLastUpdated", formatLastUpdated(), "isoLastUpdated", isoFormatLastUpdated(), "baseurl", this.baseUrl)); diff --git a/src/main/java/com/meetme/plugins/jira/gerrit/tabpanel/GerritReviewsTabPanel.java b/src/main/java/com/meetme/plugins/jira/gerrit/tabpanel/GerritReviewsTabPanel.java index 1ba26c5..7187ebb 100644 --- a/src/main/java/com/meetme/plugins/jira/gerrit/tabpanel/GerritReviewsTabPanel.java +++ b/src/main/java/com/meetme/plugins/jira/gerrit/tabpanel/GerritReviewsTabPanel.java @@ -13,6 +13,8 @@ */ package com.meetme.plugins.jira.gerrit.tabpanel; +import com.atlassian.jira.bc.user.search.UserSearchService; +import com.atlassian.jira.component.ComponentAccessor; import com.atlassian.jira.issue.Issue; import com.atlassian.jira.issue.tabpanels.GenericMessageAction; import com.atlassian.jira.plugin.issuetabpanel.AbstractIssueTabPanel2; @@ -27,20 +29,24 @@ import com.atlassian.jira.web.util.OutlookDate; import com.atlassian.jira.web.util.OutlookDateManager; import com.atlassian.sal.api.ApplicationProperties; +import com.atlassian.sal.api.UrlMode; import com.atlassian.sal.api.message.I18nResolver; import com.meetme.plugins.jira.gerrit.data.GerritConfiguration; import com.meetme.plugins.jira.gerrit.data.IssueReviewsManager; import com.meetme.plugins.jira.gerrit.data.dto.GerritApproval; import com.meetme.plugins.jira.gerrit.data.dto.GerritChange; import com.meetme.plugins.jira.gerrit.data.dto.GerritPatchSet; -import com.sonyericsson.hudson.plugins.gerrit.gerritevents.GerritQueryException; +import com.sonymobile.tools.gerrit.gerritevents.GerritQueryException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; +import static org.apache.commons.collections.CollectionUtils.isEmpty; + /** * An {@link IssueTabPanel2 issue tab panel} for displaying all Gerrit code reviews related to this * issue. @@ -59,8 +65,8 @@ public class GerritReviewsTabPanel extends AbstractIssueTabPanel2 implements Iss //TODO: Update OutlookDateManager to DateFormatter public GerritReviewsTabPanel(UserManager userManager, OutlookDateManager dateTimeFormatterFactory, - ApplicationProperties applicationProperties, GerritConfiguration configuration, - IssueReviewsManager reviewsManager, I18nResolver i18n) { + ApplicationProperties applicationProperties, GerritConfiguration configuration, + IssueReviewsManager reviewsManager, I18nResolver i18n) { this.userManager = userManager; this.dateTimeFormatter = dateTimeFormatterFactory.getOutlookDate(null); this.applicationProperties = applicationProperties; @@ -75,7 +81,7 @@ public GetActionsReply getActions(GetActionsRequest request) { if (configuration.getSshHostname() == null || configuration.getSshUsername() == null || configuration.getSshPrivateKey() == null) { // Show not-configured error. - issueActions = new ArrayList(); + issueActions = new ArrayList<>(); issueActions.add(new GenericMessageAction("Configure Gerrit in Administration interface first.")); } else { // List of items we will be showing in the tab panel. @@ -89,11 +95,12 @@ public GetActionsReply getActions(GetActionsRequest request) { public ShowPanelReply showPanel(ShowPanelRequest arg0) { boolean isShowing = true; - if (!isConfigurationReady()) - { + if (!isConfigurationReady()) { + isShowing = false; + } + if (configuration.getUseGerritProjectWhitelist() && !configuration.isGerritProject(arg0.issue())) { isShowing = false; } - return ShowPanelReply.create(isShowing); } @@ -107,7 +114,7 @@ public ShowPanelReply showPanel(ShowPanelRequest arg0) { private List getActions(Issue issue) { log.debug("Getting actions for issue: {0}", issue.getKey()); - List issueActions = new ArrayList(); + List issueActions = new ArrayList<>(); List reviews; try { @@ -123,7 +130,7 @@ private List getActions(Issue issue) { } else { for (GerritChange change : reviews) { setUsersForChangeApprovals(change); - issueActions.add(new GerritReviewIssueAction(descriptor(), change, dateTimeFormatter, applicationProperties.getBaseUrl())); + issueActions.add(new GerritReviewIssueAction(descriptor(), change, dateTimeFormatter, applicationProperties.getBaseUrl(UrlMode.AUTO))); // issueActions.add(new GenericMessageAction("
" + obj.toString(4) + "
")); } } @@ -132,19 +139,15 @@ private List getActions(Issue issue) { } private ApplicationUser getUserByEmail(String email) { - ApplicationUser user = null; - - if (email != null) { - for (ApplicationUser iUser : userManager.getUsers()) { - if (email.equalsIgnoreCase(iUser.getEmailAddress())) - { - user = iUser; - break; - } - } + if (email == null || email.isEmpty()) { + return null; } - - return user; + final UserSearchService userSearchService = ComponentAccessor.getComponent(UserSearchService.class); + Iterator users = userSearchService.findUsersByEmail(email).iterator(); + if (users.hasNext()) { + return users.next(); + } + return null; } private boolean isConfigurationReady() { @@ -160,7 +163,7 @@ private void setUsersForChangeApprovals(GerritChange change) { if (approvals != null) { for (GerritApproval approval : change.getPatchSet().getApprovals()) { - String byEmail = approval.getByEmail(); + String byEmail = approval.getBy().getEmail(); approval.setUser(getUserByEmail(byEmail)); } } diff --git a/src/main/java/com/meetme/plugins/jira/gerrit/tabpanel/SubtaskReviewsTabPanel.java b/src/main/java/com/meetme/plugins/jira/gerrit/tabpanel/SubtaskReviewsTabPanel.java index daec05a..49232fe 100644 --- a/src/main/java/com/meetme/plugins/jira/gerrit/tabpanel/SubtaskReviewsTabPanel.java +++ b/src/main/java/com/meetme/plugins/jira/gerrit/tabpanel/SubtaskReviewsTabPanel.java @@ -28,7 +28,9 @@ import com.meetme.plugins.jira.gerrit.data.GerritConfiguration; import com.meetme.plugins.jira.gerrit.data.IssueReviewsManager; import com.meetme.plugins.jira.gerrit.data.dto.GerritChange; -import com.sonyericsson.hudson.plugins.gerrit.gerritevents.GerritQueryException; +import com.sonymobile.tools.gerrit.gerritevents.GerritQueryException; + +import static org.apache.commons.collections.CollectionUtils.isEmpty; public class SubtaskReviewsTabPanel extends AbstractIssueTabPanel2 implements IssueTabPanel2 { private final GerritConfiguration configuration; @@ -43,7 +45,7 @@ public SubtaskReviewsTabPanel(GerritConfiguration configuration, @Override public GetActionsReply getActions(GetActionsRequest request) { Collection subtasks = request.issue().getSubTaskObjects(); - List actions = new ArrayList(); + List actions = new ArrayList<>(); List changes; for (Issue subtask : subtasks) { @@ -66,8 +68,12 @@ public ShowPanelReply showPanel(ShowPanelRequest request) { if (isConfigurationReady()) { Collection subtasks = request.issue().getSubTaskObjects(); show = subtasks != null && subtasks.size() > 0; + if (configuration.getUseGerritProjectWhitelist() && !configuration.isGerritProject(request.issue())) { + show = false; + } } + return ShowPanelReply.create(show); } @@ -81,4 +87,5 @@ private boolean isConfigurationReady() { return configuration != null && configuration.getSshHostname() != null && configuration.getSshUsername() != null && configuration.getSshPrivateKey() != null && configuration.getSshPrivateKey().exists(); } + } diff --git a/src/main/java/com/meetme/plugins/jira/gerrit/webpanel/GerritReviewsIssueAgilePanel.java b/src/main/java/com/meetme/plugins/jira/gerrit/webpanel/GerritReviewsIssueAgilePanel.java index 8bea0d1..4e870a5 100644 --- a/src/main/java/com/meetme/plugins/jira/gerrit/webpanel/GerritReviewsIssueAgilePanel.java +++ b/src/main/java/com/meetme/plugins/jira/gerrit/webpanel/GerritReviewsIssueAgilePanel.java @@ -23,9 +23,9 @@ import com.atlassian.jira.user.ApplicationUser; import com.meetme.plugins.jira.gerrit.data.IssueReviewsManager; import com.meetme.plugins.jira.gerrit.data.dto.GerritChange; -import com.sonyericsson.hudson.plugins.gerrit.gerritevents.GerritQueryException; +import com.sonymobile.tools.gerrit.gerritevents.GerritQueryException; + -@SuppressWarnings("unchecked") public class GerritReviewsIssueAgilePanel extends AbstractJiraContextProvider { private static final String KEY_ISSUE = "issue"; private static final String KEY_CHANGES = "changes"; @@ -40,14 +40,13 @@ public GerritReviewsIssueAgilePanel(IssueReviewsManager reviewsManager) { @Override public Map getContextMap(ApplicationUser user, JiraHelper jiraHelper) { - HashMap contextMap = new HashMap(); - + HashMap contextMap = new HashMap<>(); Issue currentIssue = (Issue) jiraHelper.getContextParams().get(KEY_ISSUE); try { List changes = reviewsManager.getReviewsForIssue(currentIssue); contextMap.put(KEY_CHANGES, changes); - contextMap.put("atl.gh.issue.details.tab.count", Long.valueOf(changes.size())); + contextMap.put("atl.gh.issue.details.tab.count", changes.size()); } catch (GerritQueryException e) { contextMap.put(KEY_ERROR, e.getMessage()); } diff --git a/src/main/java/com/meetme/plugins/jira/gerrit/webpanel/GerritReviewsIssueLeftPanel.java b/src/main/java/com/meetme/plugins/jira/gerrit/webpanel/GerritReviewsIssueLeftPanel.java index 60aedf3..a19bf69 100644 --- a/src/main/java/com/meetme/plugins/jira/gerrit/webpanel/GerritReviewsIssueLeftPanel.java +++ b/src/main/java/com/meetme/plugins/jira/gerrit/webpanel/GerritReviewsIssueLeftPanel.java @@ -24,8 +24,8 @@ import com.atlassian.jira.plugin.webfragment.model.JiraHelper; import com.atlassian.jira.util.collect.MapBuilder; import com.atlassian.plugin.PluginParseException; -import com.sonyericsson.hudson.plugins.gerrit.gerritevents.GerritQueryException; +import com.sonymobile.tools.gerrit.gerritevents.GerritQueryException; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -95,7 +95,7 @@ public Map getContextMap(Map context) { } } - List changes = new ArrayList(); + List changes = new ArrayList<>(); try { if (IssueTypeOptionsProvider.wantsIssue(gerritIssueType) diff --git a/src/main/java/com/meetme/plugins/jira/gerrit/webpanel/GerritReviewsIssueSidePanel.java b/src/main/java/com/meetme/plugins/jira/gerrit/webpanel/GerritReviewsIssueSidePanel.java index 247cc6d..323b64f 100644 --- a/src/main/java/com/meetme/plugins/jira/gerrit/webpanel/GerritReviewsIssueSidePanel.java +++ b/src/main/java/com/meetme/plugins/jira/gerrit/webpanel/GerritReviewsIssueSidePanel.java @@ -23,9 +23,8 @@ import com.atlassian.jira.user.ApplicationUser; import com.meetme.plugins.jira.gerrit.data.IssueReviewsManager; import com.meetme.plugins.jira.gerrit.data.dto.GerritChange; -import com.sonyericsson.hudson.plugins.gerrit.gerritevents.GerritQueryException; +import com.sonymobile.tools.gerrit.gerritevents.GerritQueryException; -@SuppressWarnings("unchecked") public class GerritReviewsIssueSidePanel extends AbstractJiraContextProvider { private static final String KEY_ISSUE = "issue"; private static final String KEY_CHANGES = "changes"; @@ -40,8 +39,7 @@ public GerritReviewsIssueSidePanel(IssueReviewsManager reviewsManager) { @Override public Map getContextMap(ApplicationUser user, JiraHelper jiraHelper) { - HashMap contextMap = new HashMap(); - + HashMap contextMap = new HashMap<>(); Issue currentIssue = (Issue) jiraHelper.getContextParams().get(KEY_ISSUE); try { diff --git a/src/main/java/com/meetme/plugins/jira/gerrit/webpanel/IssueStatusOptionsProvider.java b/src/main/java/com/meetme/plugins/jira/gerrit/webpanel/IssueStatusOptionsProvider.java index 6602404..d642175 100644 --- a/src/main/java/com/meetme/plugins/jira/gerrit/webpanel/IssueStatusOptionsProvider.java +++ b/src/main/java/com/meetme/plugins/jira/gerrit/webpanel/IssueStatusOptionsProvider.java @@ -96,8 +96,8 @@ private String getStyleFor(String type, String expecting) { } static boolean isIssueOpen(Issue issue) { - log.debug("Checking if " + issue.getKey() + " is open: " + issue.getResolutionObject()); - return issue.getResolutionObject() == null; + log.debug("Checking if " + issue.getKey() + " is open: " + issue.getResolution()); + return issue.getResolution() == null; } static boolean wantsUnresolved(final String gerritIssueStatus) { diff --git a/src/main/java/com/meetme/plugins/jira/gerrit/webpanel/IssueTypeOptionsProvider.java b/src/main/java/com/meetme/plugins/jira/gerrit/webpanel/IssueTypeOptionsProvider.java index 3565c87..59aa1f1 100644 --- a/src/main/java/com/meetme/plugins/jira/gerrit/webpanel/IssueTypeOptionsProvider.java +++ b/src/main/java/com/meetme/plugins/jira/gerrit/webpanel/IssueTypeOptionsProvider.java @@ -107,11 +107,11 @@ private String getStyleFor(String type, String expecting) { return expecting.equals(type) ? "aui-list-checked aui-checked" : "aui-list-checked"; } - public static final boolean wantsSubtasks(final String gerritIssueType) { + public static boolean wantsSubtasks(final String gerritIssueType) { return SUBTASK_ONLY.equals(gerritIssueType) || ALL_ISSUES.equals(gerritIssueType); } - public static final boolean wantsIssue(final String gerritIssueType) { + public static boolean wantsIssue(final String gerritIssueType) { return ISSUE_ONLY.equals(gerritIssueType) || ALL_ISSUES.equals(gerritIssueType); } } diff --git a/src/main/java/com/meetme/plugins/jira/gerrit/webpanel/ShowReviewsWebPanelCondition.java b/src/main/java/com/meetme/plugins/jira/gerrit/webpanel/ShowReviewsWebPanelCondition.java index dc7a39b..097d556 100644 --- a/src/main/java/com/meetme/plugins/jira/gerrit/webpanel/ShowReviewsWebPanelCondition.java +++ b/src/main/java/com/meetme/plugins/jira/gerrit/webpanel/ShowReviewsWebPanelCondition.java @@ -4,7 +4,7 @@ import com.atlassian.plugin.web.Condition; import com.meetme.plugins.jira.gerrit.data.GerritConfiguration; import com.meetme.plugins.jira.gerrit.data.IssueReviewsManager; -import com.sonyericsson.hudson.plugins.gerrit.gerritevents.GerritQueryException; +import com.sonymobile.tools.gerrit.gerritevents.GerritQueryException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -25,7 +25,6 @@ public class ShowReviewsWebPanelCondition implements Condition { private final IssueReviewsManager issueReviewsManager; public ShowReviewsWebPanelCondition(IssueReviewsManager reviewsManager, GerritConfiguration configurationManager) { - issueReviewsManager = reviewsManager; gerritConfiguration = configurationManager; } @@ -65,11 +64,6 @@ public boolean shouldDisplay(Map map) { } private boolean isGerritProject(final Issue issue) { - - if (issue.getProjectId() == null) - return false; - - return ! isEmpty(gerritConfiguration.getIdsOfKnownGerritProjects()) && - gerritConfiguration.getIdsOfKnownGerritProjects().contains(issue.getProjectId().toString()); + return issue.getProjectId() != null && !isEmpty(gerritConfiguration.getIdsOfKnownGerritProjects()) && gerritConfiguration.getIdsOfKnownGerritProjects().contains(issue.getProjectId().toString()); } } \ No newline at end of file diff --git a/src/main/java/com/meetme/plugins/jira/gerrit/workflow/ApprovalScoreConditionFactoryImpl.java b/src/main/java/com/meetme/plugins/jira/gerrit/workflow/ApprovalScoreConditionFactoryImpl.java index 29c1ff4..0f97bcc 100644 --- a/src/main/java/com/meetme/plugins/jira/gerrit/workflow/ApprovalScoreConditionFactoryImpl.java +++ b/src/main/java/com/meetme/plugins/jira/gerrit/workflow/ApprovalScoreConditionFactoryImpl.java @@ -18,9 +18,9 @@ import java.util.List; import java.util.Map; -import com.atlassian.core.util.map.EasyMap; import com.atlassian.jira.plugin.workflow.AbstractWorkflowPluginFactory; import com.atlassian.jira.plugin.workflow.WorkflowPluginConditionFactory; +import com.google.common.collect.ImmutableMap; import com.meetme.plugins.jira.gerrit.data.dto.GerritApproval; import com.meetme.plugins.jira.gerrit.workflow.condition.ApprovalScore; import com.opensymphony.workflow.loader.AbstractDescriptor; @@ -44,7 +44,7 @@ public class ApprovalScoreConditionFactoryImpl extends AbstractWorkflowPluginFac return extractMultipleParams(conditionParams, ALL_PARAMS); } - return EasyMap.build(); + return ImmutableMap.of(); } @Override diff --git a/src/main/java/com/meetme/plugins/jira/gerrit/workflow/ApproveReviewFactoryImpl.java b/src/main/java/com/meetme/plugins/jira/gerrit/workflow/ApproveReviewFactoryImpl.java index d827da6..0ab9c1b 100644 --- a/src/main/java/com/meetme/plugins/jira/gerrit/workflow/ApproveReviewFactoryImpl.java +++ b/src/main/java/com/meetme/plugins/jira/gerrit/workflow/ApproveReviewFactoryImpl.java @@ -15,9 +15,9 @@ import java.util.Map; -import com.atlassian.core.util.map.EasyMap; import com.atlassian.jira.plugin.workflow.AbstractWorkflowPluginFactory; import com.atlassian.jira.plugin.workflow.WorkflowPluginFunctionFactory; +import com.google.common.collect.ImmutableMap; import com.meetme.plugins.jira.gerrit.workflow.function.ApprovalFunction; import com.opensymphony.workflow.loader.AbstractDescriptor; import com.opensymphony.workflow.loader.FunctionDescriptor; @@ -35,11 +35,11 @@ public class ApproveReviewFactoryImpl extends AbstractWorkflowPluginFactory impl @Override public Map getDescriptorParams(Map params) { if (params != null && params.containsKey(ApprovalFunction.KEY_CMD_ARGS)) { - return EasyMap.build(ApprovalFunction.KEY_CMD_ARGS, extractSingleParam(params, ApprovalFunction.KEY_CMD_ARGS)); + return ImmutableMap.of(ApprovalFunction.KEY_CMD_ARGS, extractSingleParam(params, ApprovalFunction.KEY_CMD_ARGS)); } // Create a 'hard coded' parameter - return EasyMap.build(ApprovalFunction.KEY_CMD_ARGS, ApprovalFunction.DEFAULT_CMD_ARGS); + return ImmutableMap.of(ApprovalFunction.KEY_CMD_ARGS, ApprovalFunction.DEFAULT_CMD_ARGS); } @Override diff --git a/src/main/java/com/meetme/plugins/jira/gerrit/workflow/NoOpenReviewsConditionFactoryImpl.java b/src/main/java/com/meetme/plugins/jira/gerrit/workflow/NoOpenReviewsConditionFactoryImpl.java index d168528..1e9a08b 100644 --- a/src/main/java/com/meetme/plugins/jira/gerrit/workflow/NoOpenReviewsConditionFactoryImpl.java +++ b/src/main/java/com/meetme/plugins/jira/gerrit/workflow/NoOpenReviewsConditionFactoryImpl.java @@ -15,9 +15,9 @@ import java.util.Map; -import com.atlassian.core.util.map.EasyMap; import com.atlassian.jira.plugin.workflow.AbstractWorkflowPluginFactory; import com.atlassian.jira.plugin.workflow.WorkflowPluginConditionFactory; +import com.google.common.collect.ImmutableMap; import com.meetme.plugins.jira.gerrit.workflow.condition.NoOpenReviews; import com.opensymphony.workflow.loader.AbstractDescriptor; import com.opensymphony.workflow.loader.ConditionDescriptor; @@ -29,10 +29,10 @@ public class NoOpenReviewsConditionFactoryImpl extends AbstractWorkflowPluginFac public Map getDescriptorParams(Map conditionParams) { if (conditionParams != null && conditionParams.containsKey(NoOpenReviews.KEY_REVERSED)) { - return EasyMap.build(NoOpenReviews.KEY_REVERSED, extractSingleParam(conditionParams, NoOpenReviews.KEY_REVERSED)); + return ImmutableMap.of(NoOpenReviews.KEY_REVERSED, extractSingleParam(conditionParams, NoOpenReviews.KEY_REVERSED)); } - return EasyMap.build(); + return ImmutableMap.of(); } @Override diff --git a/src/main/java/com/meetme/plugins/jira/gerrit/workflow/condition/ApprovalScore.java b/src/main/java/com/meetme/plugins/jira/gerrit/workflow/condition/ApprovalScore.java index db898df..8bd6401 100644 --- a/src/main/java/com/meetme/plugins/jira/gerrit/workflow/condition/ApprovalScore.java +++ b/src/main/java/com/meetme/plugins/jira/gerrit/workflow/condition/ApprovalScore.java @@ -14,14 +14,14 @@ package com.meetme.plugins.jira.gerrit.workflow.condition; import com.atlassian.jira.issue.Issue; +import com.atlassian.jira.workflow.WorkflowException; import com.atlassian.jira.workflow.condition.AbstractJiraCondition; import com.meetme.plugins.jira.gerrit.data.IssueReviewsManager; import com.meetme.plugins.jira.gerrit.data.dto.GerritApproval; import com.meetme.plugins.jira.gerrit.data.dto.GerritChange; import com.opensymphony.module.propertyset.PropertySet; -import com.opensymphony.workflow.WorkflowException; -import com.sonyericsson.hudson.plugins.gerrit.gerritevents.GerritQueryException; +import com.sonymobile.tools.gerrit.gerritevents.GerritQueryException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -147,12 +147,12 @@ private boolean compareScore(ComparisonOperator oper, int score, int target) { * * @author Joe Hansche */ - public static enum ComparisonOperator { + public enum ComparisonOperator { LESS_THAN("<"), LESS_OR_EQUAL("<="), EQUAL_TO("=="), GREATER_OR_EQUAL(">="), GREATER_THAN(">"); private final String display; - private ComparisonOperator(final String display) { + ComparisonOperator(final String display) { this.display = display; } diff --git a/src/main/java/com/meetme/plugins/jira/gerrit/workflow/condition/NoOpenReviews.java b/src/main/java/com/meetme/plugins/jira/gerrit/workflow/condition/NoOpenReviews.java index 8337882..e347875 100644 --- a/src/main/java/com/meetme/plugins/jira/gerrit/workflow/condition/NoOpenReviews.java +++ b/src/main/java/com/meetme/plugins/jira/gerrit/workflow/condition/NoOpenReviews.java @@ -14,12 +14,12 @@ package com.meetme.plugins.jira.gerrit.workflow.condition; import com.atlassian.jira.issue.Issue; +import com.atlassian.jira.workflow.WorkflowException; import com.atlassian.jira.workflow.condition.AbstractJiraCondition; import com.meetme.plugins.jira.gerrit.data.IssueReviewsManager; import com.meetme.plugins.jira.gerrit.data.dto.GerritChange; import com.opensymphony.module.propertyset.PropertySet; -import com.opensymphony.workflow.WorkflowException; -import com.sonyericsson.hudson.plugins.gerrit.gerritevents.GerritQueryException; +import com.sonymobile.tools.gerrit.gerritevents.GerritQueryException; import java.util.List; import java.util.Map; diff --git a/src/main/java/com/meetme/plugins/jira/gerrit/workflow/function/ApprovalFunction.java b/src/main/java/com/meetme/plugins/jira/gerrit/workflow/function/ApprovalFunction.java index 002f5c5..ca64448 100644 --- a/src/main/java/com/meetme/plugins/jira/gerrit/workflow/function/ApprovalFunction.java +++ b/src/main/java/com/meetme/plugins/jira/gerrit/workflow/function/ApprovalFunction.java @@ -13,19 +13,19 @@ */ package com.meetme.plugins.jira.gerrit.workflow.function; -import com.atlassian.core.user.preferences.Preferences; import com.atlassian.jira.issue.Issue; import com.atlassian.jira.user.ApplicationUser; +import com.atlassian.jira.user.preferences.ExtendedPreferences; import com.atlassian.jira.user.preferences.UserPreferencesManager; +import com.atlassian.jira.workflow.WorkflowException; import com.atlassian.jira.workflow.function.issue.AbstractJiraFunctionProvider; import com.meetme.plugins.jira.gerrit.data.GerritConfiguration; import com.meetme.plugins.jira.gerrit.data.IssueReviewsManager; import com.meetme.plugins.jira.gerrit.data.dto.GerritChange; import com.meetme.plugins.jira.gerrit.workflow.condition.ApprovalScore; import com.opensymphony.module.propertyset.PropertySet; -import com.opensymphony.workflow.WorkflowException; -import com.sonyericsson.hudson.plugins.gerrit.gerritevents.GerritQueryException; +import com.sonymobile.tools.gerrit.gerritevents.GerritQueryException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -66,14 +66,14 @@ public class ApprovalFunction extends AbstractJiraFunctionProvider { private final IssueReviewsManager reviewsManager; private final GerritConfiguration configuration; - private final UserPreferencesManager prefsManager; + private final UserPreferencesManager userPreferencesManager; public ApprovalFunction(GerritConfiguration configuration, IssueReviewsManager reviewsManager, UserPreferencesManager prefsManager) { super(); this.configuration = configuration; this.reviewsManager = reviewsManager; - this.prefsManager = prefsManager; + this.userPreferencesManager = prefsManager; } @Override @@ -85,7 +85,7 @@ public void execute(@SuppressWarnings("rawtypes") Map transientVars, @SuppressWa final Issue issue = getIssue(transientVars); final List issueReviews = getReviews(issue); - final Preferences prefs = getUserPrefs(transientVars, args); + final ExtendedPreferences prefs = getUserPrefs(transientVars, args); final String cmdArgs = (String) args.get(KEY_CMD_ARGS); boolean success = false; @@ -102,9 +102,9 @@ public void execute(@SuppressWarnings("rawtypes") Map transientVars, @SuppressWa } } - protected Preferences getUserPrefs(@SuppressWarnings("rawtypes") Map transientVars, @SuppressWarnings("rawtypes") Map args) { - final ApplicationUser user = getCaller(transientVars, args); - return prefsManager.getPreferences(user); + protected ExtendedPreferences getUserPrefs(@SuppressWarnings("rawtypes") Map transientVars, @SuppressWarnings("rawtypes") Map args) { + final ApplicationUser user = getCallerUser(transientVars, args); + return userPreferencesManager.getExtendedPreferences(user); } protected String getIssueKey(@SuppressWarnings("rawtypes") Map transientVars) { diff --git a/src/main/resources/atlassian-plugin.xml b/src/main/resources/atlassian-plugin.xml index 77030ca..19f12f6 100644 --- a/src/main/resources/atlassian-plugin.xml +++ b/src/main/resources/atlassian-plugin.xml @@ -36,7 +36,6 @@ - diff --git a/src/main/resources/i18n/admin.properties b/src/main/resources/i18n/admin.properties index 34a88e8..04addcd 100644 --- a/src/main/resources/i18n/admin.properties +++ b/src/main/resources/i18n/admin.properties @@ -25,6 +25,8 @@ gerrit.admin.sshKey.label=SSH Private Key gerrit.admin.sshKey.description=Example: id_rsa file gerrit.admin.sshKey.isOnFile=Private Key is already on file. Upload a new one to replace it. gerrit.admin.sshKey.missing=A private key is required! +gerrit.admin.sshTimeout.label=SSH Timeout +gerrit.admin.sshTimeout.description=Set 0 for no timeout or other value in milliseconds. gerrit.admin.search.label=Search Queries gerrit.admin.issueSearchQuery.label=Issue Search @@ -49,4 +51,6 @@ gerrit.admin.showEmptyPanel.description=If there are no matching Gerrit reviews gerrit.admin.project.whitelist=Gerrit Projects Whitelist gerrit.admin.project.whitelist.description=List of projects, that use gerrit. gerrit.admin.project.useWhiteList.label=Use Gerrit Project Whitelist -gerrit.admin.project.useWhiteList.description=If a list of projects, that use Gerrit, shall be maintained. \ No newline at end of file +gerrit.admin.project.useWhiteList.description=If a list of projects, that use Gerrit, shall be maintained. +gerrit.admin.cacheTimeout.label = Cache period +gerrit.admin.cacheTimeout.description = Number of milliseconds an item may stay in cache. Default: 30 seconds \ No newline at end of file diff --git a/src/main/resources/styles/gerrit-reviews-tabpanel.css b/src/main/resources/styles/gerrit-reviews-tabpanel.css index 6e1aa6e..88283fb 100644 --- a/src/main/resources/styles/gerrit-reviews-tabpanel.css +++ b/src/main/resources/styles/gerrit-reviews-tabpanel.css @@ -52,10 +52,7 @@ span.gerrit-review text-indent: -9999px; width: 16px; height: 16px; - background-color: transparent; - background-image: url(images/gerrit-icon16.png); - background-repeat: no-repeat; - background-position: 50% 50%; + background: transparent url(images/gerrit-icon16.png) no-repeat 50% 50%; } span.gerrit-open-reviews @@ -72,7 +69,7 @@ span.gerrit-no-reviews { white-space: nowrap; overflow: hidden; - text-overflow: none; + text-overflow: initial; width: 81%; text-align: left; } diff --git a/src/main/resources/templates/admin.vm b/src/main/resources/templates/admin.vm index e7afdf6..6651709 100644 --- a/src/main/resources/templates/admin.vm +++ b/src/main/resources/templates/admin.vm @@ -63,6 +63,14 @@
$i18n.getText("gerrit.admin.username.description")
+
+ + +
$i18n.getText("gerrit.admin.sshTimeout.description")
+