/* * Sonar, open source software quality management tool. * Copyright (C) 2009 SonarSource * mailto:contact AT sonarsource DOT com * * Sonar is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * Sonar is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with Sonar; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 */ package org.sonar.plugins.jira; import com.atlassian.jira.rpc.soap.client.JiraSoapService; import com.atlassian.jira.rpc.soap.client.RemoteFilter; import com.atlassian.jira.rpc.soap.client.RemoteIssue; import com.atlassian.jira.rpc.soap.client.RemotePriority; import org.apache.commons.configuration.Configuration; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.batch.Sensor; import org.sonar.api.batch.SensorContext; import org.sonar.api.measures.Measure; import org.sonar.api.measures.PropertiesBuilder; import org.sonar.api.resources.Project; import org.sonar.api.utils.SonarException; import org.sonar.plugins.jira.soap.JiraSoapSession; import java.net.URL; import java.rmi.RemoteException; import java.util.HashMap; import java.util.Map; public class JiraSensor implements Sensor { private static final Logger LOG = LoggerFactory.getLogger(JiraSensor.class); private String serverUrl; private String username; private String password; private String filterName; public void analyse(Project project, SensorContext context) { initParams(project); if (!isMandatoryParametersNotEmpty()) { LOG.warn("The server url, the filter name, the username and the password must not be empty."); return; } try { JiraSoapSession session = new JiraSoapSession(new URL(serverUrl + "/rpc/soap/jirasoapservice-v2")); session.connect(username, password); JiraSoapService service = session.getJiraSoapService(); String authToken = session.getAuthenticationToken(); analyze(context, service, authToken); session.disconnect(); } catch (Exception e) { LOG.error("Error accessing Jira web service, please verify the parameters", e); } } private void analyze(SensorContext context, JiraSoapService service, String authToken) throws RemoteException { // TODO use google-collections Map<String, String> priorities = new HashMap<String, String>(); for (RemotePriority priority : service.getPriorities(authToken)) { priorities.put(priority.getId(), priority.getName()); } RemoteFilter[] filters; try { filters = service.getFavouriteFilters(authToken); } catch (Exception e) { // for Jira prior to 3.13 filters = service.getSavedFilters(authToken); } RemoteFilter filter = null; for (RemoteFilter f : filters) { if (filterName.equals(f.getName())) { filter = f; } } if (filter == null) { throw new SonarException("Unable to find filter '" + filterName + "' in JIRA"); } RemoteIssue[] issues = service.getIssuesFromFilter(authToken, filter.getId()); Map<String, Integer> issuesByPriority = new HashMap<String, Integer>(); for (RemoteIssue issue : issues) { String priority = issue.getPriority(); if (!issuesByPriority.containsKey(priority)) { issuesByPriority.put(priority, 1); } else { issuesByPriority.put(priority, issuesByPriority.get(priority) + 1); } } double total = 0; PropertiesBuilder<String, Integer> distribution = new PropertiesBuilder<String, Integer>(); for (Map.Entry<String, Integer> entry : issuesByPriority.entrySet()) { total += entry.getValue(); distribution.add(priorities.get(entry.getKey()), entry.getValue()); } String url = serverUrl + "/secure/IssueNavigator.jspa?mode=hide&requestId=" + filter.getId(); saveMeasures(context, url, total, distribution.buildData()); } private void initParams(Project project) { Configuration configuration = project.getConfiguration(); serverUrl = configuration.getString(JiraPlugin.SERVER_URL_PROPERTY); username = configuration.getString(JiraPlugin.USERNAME_PROPERTY); password = configuration.getString(JiraPlugin.PASSWORD_PROPERTY); filterName = configuration.getString(JiraPlugin.FILTER_PROPERTY); } private boolean isMandatoryParametersNotEmpty() { return StringUtils.isNotEmpty(serverUrl) && StringUtils.isNotEmpty(filterName) && StringUtils.isNotEmpty(username) && StringUtils.isNotEmpty(password); } protected void saveMeasures(SensorContext context, String issueUrl, double totalPrioritiesCount, String priorityDistribution) { Measure issuesMeasure = new Measure(JiraMetrics.ISSUES, totalPrioritiesCount); issuesMeasure.setUrl(issueUrl); issuesMeasure.setData(priorityDistribution); context.saveMeasure(issuesMeasure); } public boolean shouldExecuteOnProject(Project project) { return project.isRoot(); } @Override public String toString() { return getClass().getSimpleName(); } }