/* * 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.technicaldebt; import com.google.common.collect.Lists; import org.apache.commons.configuration.Configuration; import org.sonar.api.batch.Decorator; import org.sonar.api.batch.DecoratorContext; import org.sonar.api.batch.DependedUpon; import org.sonar.api.batch.DependsUpon; import org.sonar.api.measures.Metric; import org.sonar.api.measures.PropertiesBuilder; import org.sonar.api.resources.Project; import org.sonar.api.resources.Resource; import org.sonar.plugins.technicaldebt.axis.*; import java.util.Arrays; import java.util.List; /** * {@inheritDoc} */ public final class TechnicalDebtDecorator implements Decorator { private List<AxisDebtCalculator> axisList; private Configuration configuration; /** * {@inheritDoc} */ public TechnicalDebtDecorator(Configuration configuration, Project project) { this.configuration = configuration; axisList = Arrays.asList( new CommentDebtCalculator(configuration), new ComplexityDebtCalculator(configuration, project), new CoverageDebtCalculator(configuration), new DuplicationDebtCalculator(configuration), new ViolationsDebtCalculator(configuration), new DesignDebtCalculator(configuration) ); } /** * {@inheritDoc} */ public boolean shouldExecuteOnProject(Project project) { return true; } @DependsUpon public List<Metric> dependsOnMetrics() { List<Metric> list = Lists.newLinkedList(); for (AxisDebtCalculator axis : axisList) { list.addAll(axis.dependsOn()); } return list; } @DependedUpon public List<Metric> generatesMetrics() { return Arrays.asList( TechnicalDebtMetrics.TECHNICAL_DEBT, TechnicalDebtMetrics.TECHNICAL_DEBT_DAYS, TechnicalDebtMetrics.TECHNICAL_DEBT_RATIO, TechnicalDebtMetrics.TECHNICAL_DEBT_REPARTITION); } /** * {@inheritDoc} */ public void decorate(Resource resource, DecoratorContext context) { double sonarDebt = 0.0; double denominatorDensity = 0.0; PropertiesBuilder<String, Double> techDebtRepartition = new PropertiesBuilder<String, Double>(TechnicalDebtMetrics.TECHNICAL_DEBT_REPARTITION); // We calculate the total absolute debt and total maximum debt for (AxisDebtCalculator axis : axisList) { sonarDebt += axis.calculateAbsoluteDebt(context); denominatorDensity += axis.calculateTotalPossibleDebt(context); } // Then we calculate the % of each axis for this debt for (AxisDebtCalculator axis : axisList) { addToRepartition(techDebtRepartition, axis.getName(), axis.calculateAbsoluteDebt(context) / sonarDebt * 100); } double dailyRate = configuration.getDouble(TechnicalDebtPlugin.DAILY_RATE, TechnicalDebtPlugin.DAILY_RATE_DEFVAL); saveMeasure(context, TechnicalDebtMetrics.TECHNICAL_DEBT, sonarDebt * dailyRate); saveMeasure(context, TechnicalDebtMetrics.TECHNICAL_DEBT_DAYS, sonarDebt); if (denominatorDensity != 0.0) { saveMeasure(context, TechnicalDebtMetrics.TECHNICAL_DEBT_RATIO, sonarDebt / denominatorDensity * 100); } context.saveMeasure(techDebtRepartition.build()); } private void saveMeasure(DecoratorContext decoratorContext, Metric metric, double measure) { if (measure * 10 > 5) { decoratorContext.saveMeasure(metric, measure); } } private void addToRepartition(PropertiesBuilder<String, Double> techDebtRepartition, String key, double value) { if (value > 0d) { // Math.floor is important to avoid getting very long doubles... see SONAR-859 techDebtRepartition.add(key, Math.floor(value * 100.0) / 100); } } }