]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6588 integrate issues to Compute Engine
authorSimon Brandhof <simon.brandhof@sonarsource.com>
Wed, 24 Jun 2015 14:41:13 +0000 (16:41 +0200)
committerSimon Brandhof <simon.brandhof@sonarsource.com>
Thu, 2 Jul 2015 14:08:07 +0000 (16:08 +0200)
90 files changed:
server/sonar-server/src/main/java/org/sonar/server/computation/batch/BatchReportReader.java
server/sonar-server/src/main/java/org/sonar/server/computation/container/ComputeEngineContainerImpl.java
server/sonar-server/src/main/java/org/sonar/server/computation/issue/BaseIssuesLoader.java
server/sonar-server/src/main/java/org/sonar/server/computation/issue/CountIssuesListener.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/issue/DebtAggregator.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/issue/DebtCalculator.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueAssigner.java
server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueCounter.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueLifecycle.java
server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueListener.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueListeners.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueVisitor.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueVisitors.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/issue/NewDebtAggregator.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/issue/NewDebtCalculator.java
server/sonar-server/src/main/java/org/sonar/server/computation/issue/RuleTagsCopier.java
server/sonar-server/src/main/java/org/sonar/server/computation/issue/TrackerBaseInputFactory.java
server/sonar-server/src/main/java/org/sonar/server/computation/issue/TrackerRawInputFactory.java
server/sonar-server/src/main/java/org/sonar/server/computation/measure/BatchMeasureToMeasure.java
server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureRepositoryImpl.java
server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputationSteps.java
server/sonar-server/src/main/java/org/sonar/server/computation/step/FeedDebtModelStep.java
server/sonar-server/src/main/java/org/sonar/server/computation/step/IntegrateIssuesStep.java
server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistIssuesStep.java
server/sonar-server/src/main/java/org/sonar/server/source/db/FileSourceDao.java
server/sonar-server/src/test/java/org/sonar/server/computation/debt/CharacteristicTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/debt/DebtModelHolderImplTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/issue/CountIssuesListenerTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/issue/NewDebtAggregatorTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/issue/NewDebtCalculatorTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/measure/BatchMeasureToMeasureTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureRepositoryImplTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/step/FeedDebtModelStepTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/step/FillMeasuresWithVariationsStepTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistIssuesStepTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistMeasuresStepTest.java
server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistIssuesStepTest/close_issue-result.xml
server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistIssuesStepTest/shared.xml
sonar-batch-protocol/src/main/gen-java/org/sonar/batch/protocol/output/BatchReport.java
sonar-batch-protocol/src/main/protobuf/batch_report.proto
sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchComponents.java
sonar-batch/src/main/java/org/sonar/batch/debt/DebtModelProvider.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/debt/IssueChangelogDebtCalculator.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/debt/NewDebtDecorator.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/issue/ModuleIssues.java
sonar-batch/src/main/java/org/sonar/batch/issue/tracking/LocalIssueTracking.java
sonar-batch/src/main/java/org/sonar/batch/report/IssuesPublisher.java
sonar-batch/src/main/java/org/sonar/batch/report/MeasuresPublisher.java
sonar-batch/src/main/java/org/sonar/batch/report/MetadataPublisher.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/rule/RulesProvider.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
sonar-batch/src/main/java/org/sonar/batch/scan/measure/MeasureCache.java
sonar-batch/src/main/java/org/sonar/batch/scan/measure/MeasureValueCoder.java
sonar-batch/src/test/java/org/sonar/batch/debt/DebtDecoratorTest.java [deleted file]
sonar-batch/src/test/java/org/sonar/batch/debt/DebtModelProviderTest.java [deleted file]
sonar-batch/src/test/java/org/sonar/batch/debt/IssueChangelogDebtCalculatorTest.java [deleted file]
sonar-batch/src/test/java/org/sonar/batch/debt/NewDebtDecoratorTest.java [deleted file]
sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java
sonar-batch/src/test/java/org/sonar/batch/report/IssuesPublisherTest.java
sonar-batch/src/test/java/org/sonar/batch/report/MeasuresPublisherTest.java
sonar-batch/src/test/java/org/sonar/batch/report/MetadataPublisherTest.java [new file with mode: 0644]
sonar-batch/src/test/java/org/sonar/batch/rule/RulesProviderTest.java [deleted file]
sonar-batch/src/test/java/org/sonar/batch/scan/measure/MeasureCacheTest.java
sonar-core/src/main/java/org/sonar/core/dashboard/ActiveDashboardDao.java
sonar-core/src/main/java/org/sonar/core/issue/db/ActionPlanDao.java
sonar-core/src/main/java/org/sonar/core/issue/db/IssueChangeDao.java
sonar-core/src/main/java/org/sonar/core/issue/db/IssueChangeMapper.java
sonar-core/src/main/java/org/sonar/core/issue/db/IssueDto.java
sonar-core/src/main/java/org/sonar/core/issue/db/IssueMapper.java
sonar-core/src/main/java/org/sonar/core/issue/tracking/LazyInput.java
sonar-core/src/main/java/org/sonar/core/issue/tracking/Tracker.java
sonar-core/src/main/java/org/sonar/core/issue/tracking/Tracking.java
sonar-core/src/main/java/org/sonar/core/issue/workflow/SetClosed.java
sonar-core/src/main/java/org/sonar/core/persistence/DaoComponent.java
sonar-core/src/main/java/org/sonar/core/technicaldebt/DefaultTechnicalDebtModel.java [deleted file]
sonar-core/src/main/resources/org/sonar/core/issue/db/IssueChangeMapper.xml
sonar-core/src/main/resources/org/sonar/core/issue/db/IssueMapper.xml
sonar-core/src/test/java/org/sonar/core/issue/db/IssueChangeDaoTest.java
sonar-core/src/test/java/org/sonar/core/issue/tracking/TrackerTest.java
sonar-core/src/test/java/org/sonar/core/issue/workflow/SetClosedTest.java
sonar-core/src/test/java/org/sonar/core/technicaldebt/DefaultTechnicalDebtModelTest.java [deleted file]
sonar-core/src/test/resources/org/sonar/core/issue/db/IssueChangeDaoTest/selectChangelogOfUnresolvedIssuesByComponent.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/issue/db/IssueChangeDaoTest/select_issue_changelog_by_module.xml [deleted file]
sonar-core/src/test/resources/org/sonar/core/issue/db/IssueChangeDaoTest/select_issue_changelog_by_module_are_sorted_by_creation_date.xml [deleted file]
sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/Rule.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/DefaultRule.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/NewRule.java
sonar-plugin-api/src/main/java/org/sonar/api/measures/Measure.java
sonar-plugin-api/src/main/java/org/sonar/api/technicaldebt/batch/TechnicalDebtModel.java [deleted file]
sonar-plugin-api/src/test/java/org/sonar/api/batch/rule/internal/RulesBuilderTest.java

index fbed4ffb945a2b2774b5112e182fc5c16292aca6..2568cb4ed9aa0d774281764558c98575a418d4f6 100644 (file)
@@ -45,7 +45,8 @@ public interface BatchReportReader {
   CloseableIterator<BatchReport.Coverage> readComponentCoverage(int fileRef);
 
   /**
-   * Reads file source line by line.
+   * Reads file source line by line. Throws an exception if the ref does not relate
+   * to a file
    */
   CloseableIterator<String> readFileSource(int fileRef);
 
index 4bd929e44e1833b3077d6acf8afae05de4eb500f..7bbd85c8748c8d75e60951deceb06fc6a50e8cea 100644 (file)
@@ -45,13 +45,15 @@ import org.sonar.server.computation.debt.DebtModelHolderImpl;
 import org.sonar.server.computation.event.EventRepositoryImpl;
 import org.sonar.server.computation.formula.CoreFormulaRepositoryImpl;
 import org.sonar.server.computation.issue.BaseIssuesLoader;
-import org.sonar.server.computation.issue.CountIssuesListener;
-import org.sonar.server.computation.issue.DebtCalculator;
+import org.sonar.server.computation.issue.IssueCounter;
+import org.sonar.server.computation.issue.DebtAggregator;
 import org.sonar.server.computation.issue.DefaultAssignee;
 import org.sonar.server.computation.issue.IssueAssigner;
 import org.sonar.server.computation.issue.IssueCache;
 import org.sonar.server.computation.issue.IssueLifecycle;
-import org.sonar.server.computation.issue.IssueListeners;
+import org.sonar.server.computation.issue.IssueVisitors;
+import org.sonar.server.computation.issue.NewDebtAggregator;
+import org.sonar.server.computation.issue.NewDebtCalculator;
 import org.sonar.server.computation.issue.RuleCache;
 import org.sonar.server.computation.issue.RuleCacheLoader;
 import org.sonar.server.computation.issue.RuleTagsCopier;
@@ -168,16 +170,21 @@ public class ComputeEngineContainerImpl extends ComponentContainer implements Co
       // issues
       ScmAccountToUserLoader.class,
       ScmAccountToUser.class,
-      IssueAssigner.class,
-      RuleTagsCopier.class,
       RuleCache.class,
       RuleCacheLoader.class,
       IssueCache.class,
       DefaultAssignee.class,
-      DebtCalculator.class,
-      IssueListeners.class,
+      IssueVisitors.class,
       IssueLifecycle.class,
-      CountIssuesListener.class,
+
+      // order is important, NewDebtAggregator is based on DebtAggregator (new debt requires debt)
+      DebtAggregator.class,
+      NewDebtCalculator.class,
+      NewDebtAggregator.class,
+      IssueAssigner.class,
+      RuleTagsCopier.class,
+      IssueCounter.class,
+
       UpdateConflictResolver.class,
       TrackerBaseInputFactory.class,
       TrackerRawInputFactory.class,
index 904ac1f1242c1ace425056a38cd248d7c116af77..216fe6db9b95cc575b1b00a8ea7a2c64caf1ab15 100644 (file)
  */
 package org.sonar.server.computation.issue;
 
+import com.google.common.base.Function;
 import com.google.common.collect.ImmutableMap;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import javax.annotation.Nonnull;
 import org.apache.ibatis.session.ResultContext;
 import org.apache.ibatis.session.ResultHandler;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.RuleStatus;
+import org.sonar.api.utils.log.Loggers;
 import org.sonar.core.issue.DefaultIssue;
 import org.sonar.core.issue.db.IssueDto;
 import org.sonar.core.issue.db.IssueMapper;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.core.persistence.MyBatis;
+import org.sonar.core.rule.RuleDto;
+import org.sonar.server.computation.batch.BatchReportReader;
 import org.sonar.server.computation.component.TreeRootHolder;
 import org.sonar.server.db.DbClient;
 
+import static com.google.common.collect.FluentIterable.from;
+
 /**
  * Loads all the project open issues from database, including manual issues.
+ *
  */
 public class BaseIssuesLoader {
 
+  private final Set<RuleKey> activeRuleKeys;
   private final TreeRootHolder treeRootHolder;
   private final DbClient dbClient;
   private final RuleCache ruleCache;
 
-  public BaseIssuesLoader(TreeRootHolder treeRootHolder, DbClient dbClient, RuleCache ruleCache) {
+  public BaseIssuesLoader(BatchReportReader reportReader, TreeRootHolder treeRootHolder,
+    DbClient dbClient, RuleCache ruleCache) {
+    this.activeRuleKeys = from(reportReader.readMetadata().getActiveRuleKeyList()).transform(ToRuleKey.INSTANCE).toSet();
     this.treeRootHolder = treeRootHolder;
     this.dbClient = dbClient;
     this.ruleCache = ruleCache;
@@ -54,11 +67,21 @@ public class BaseIssuesLoader {
     final List<DefaultIssue> result = new ArrayList<>();
     try {
       Map<String, String> params = ImmutableMap.of("componentUuid", componentUuid);
-      session.select(IssueMapper.class.getName() + ".selectOpenByComponentUuid", params, new ResultHandler() {
+      session.select(IssueMapper.class.getName() + ".selectNonClosedByComponentUuid", params, new ResultHandler() {
         @Override
         public void handleResult(ResultContext resultContext) {
           DefaultIssue issue = ((IssueDto) resultContext.getResultObject()).toDefaultIssue();
-          issue.setOnDisabledRule(ruleCache.getNullable(issue.ruleKey()) == null);
+
+          // TODO this field should be set outside this class
+          RuleDto rule = ruleCache.getNullable(issue.ruleKey());
+          if (rule == null || rule.getStatus() == RuleStatus.REMOVED || !isActive(issue.ruleKey())) {
+            issue.setOnDisabledRule(true);
+            // TODO to be improved, why setOnDisabledRule(true) is not enough ?
+            issue.setBeingClosed(true);
+          }
+          // FIXME
+          issue.setSelectedAt(System.currentTimeMillis());
+          Loggers.get(getClass()).info("Loaded from db: " + issue);
           result.add(issue);
         }
       });
@@ -68,6 +91,10 @@ public class BaseIssuesLoader {
     }
   }
 
+  private boolean isActive(RuleKey ruleKey) {
+    return ruleKey.isManual() || activeRuleKeys.contains(ruleKey);
+  }
+
   /**
    * Uuids of all the components that have open issues on this project.
    */
@@ -79,4 +106,13 @@ public class BaseIssuesLoader {
       MyBatis.closeQuietly(session);
     }
   }
+
+  private enum ToRuleKey implements Function<String, RuleKey> {
+    INSTANCE;
+    @Nonnull
+    @Override
+    public RuleKey apply(@Nonnull String input) {
+      return RuleKey.parse(input);
+    }
+  }
 }
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/CountIssuesListener.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/CountIssuesListener.java
deleted file mode 100644 (file)
index 1b49303..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.server.computation.issue;
-
-import com.google.common.collect.HashMultiset;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Multiset;
-import java.util.HashMap;
-import java.util.Map;
-import javax.annotation.Nullable;
-import org.sonar.api.issue.Issue;
-import org.sonar.core.issue.DefaultIssue;
-import org.sonar.core.issue.tracking.Tracking;
-import org.sonar.server.computation.component.Component;
-import org.sonar.server.computation.measure.Measure;
-import org.sonar.server.computation.measure.MeasureRepository;
-import org.sonar.server.computation.measure.MeasureVariations;
-import org.sonar.server.computation.metric.Metric;
-import org.sonar.server.computation.metric.MetricRepository;
-import org.sonar.server.computation.period.Period;
-import org.sonar.server.computation.period.PeriodsHolder;
-
-import static org.sonar.api.issue.Issue.STATUS_CONFIRMED;
-import static org.sonar.api.issue.Issue.STATUS_OPEN;
-import static org.sonar.api.issue.Issue.STATUS_REOPENED;
-import static org.sonar.api.measures.CoreMetrics.BLOCKER_VIOLATIONS_KEY;
-import static org.sonar.api.measures.CoreMetrics.CONFIRMED_ISSUES_KEY;
-import static org.sonar.api.measures.CoreMetrics.CRITICAL_VIOLATIONS_KEY;
-import static org.sonar.api.measures.CoreMetrics.FALSE_POSITIVE_ISSUES_KEY;
-import static org.sonar.api.measures.CoreMetrics.INFO_VIOLATIONS_KEY;
-import static org.sonar.api.measures.CoreMetrics.MAJOR_VIOLATIONS_KEY;
-import static org.sonar.api.measures.CoreMetrics.MINOR_VIOLATIONS_KEY;
-import static org.sonar.api.measures.CoreMetrics.NEW_BLOCKER_VIOLATIONS_KEY;
-import static org.sonar.api.measures.CoreMetrics.NEW_CRITICAL_VIOLATIONS_KEY;
-import static org.sonar.api.measures.CoreMetrics.NEW_INFO_VIOLATIONS_KEY;
-import static org.sonar.api.measures.CoreMetrics.NEW_MAJOR_VIOLATIONS_KEY;
-import static org.sonar.api.measures.CoreMetrics.NEW_MINOR_VIOLATIONS_KEY;
-import static org.sonar.api.measures.CoreMetrics.NEW_VIOLATIONS_KEY;
-import static org.sonar.api.measures.CoreMetrics.OPEN_ISSUES_KEY;
-import static org.sonar.api.measures.CoreMetrics.REOPENED_ISSUES_KEY;
-import static org.sonar.api.measures.CoreMetrics.VIOLATIONS_KEY;
-import static org.sonar.api.rule.Severity.BLOCKER;
-import static org.sonar.api.rule.Severity.CRITICAL;
-import static org.sonar.api.rule.Severity.INFO;
-import static org.sonar.api.rule.Severity.MAJOR;
-import static org.sonar.api.rule.Severity.MINOR;
-
-/**
- * For each component, computes the measures related to number of issues:
- * <ul>
- *   <li>unresolved issues</li>
- *   <li>false-positives</li>
- *   <li>open issues</li>
- *   <li>issues per status (open, reopen, confirmed)</li>
- *   <li>issues per severity (from info to blocker)</li>
- * </ul>
- * For each value, the variation on configured periods is also computed.
- */
-public class CountIssuesListener extends IssueListener {
-
-  private final static Map<String, String> SEVERITY_TO_METRIC_KEY = ImmutableMap.of(
-    BLOCKER, BLOCKER_VIOLATIONS_KEY,
-    CRITICAL, CRITICAL_VIOLATIONS_KEY,
-    MAJOR, MAJOR_VIOLATIONS_KEY,
-    MINOR, MINOR_VIOLATIONS_KEY,
-    INFO, INFO_VIOLATIONS_KEY
-    );
-
-  private final static Map<String, String> SEVERITY_TO_NEW_METRIC_KEY = ImmutableMap.of(
-    BLOCKER, NEW_BLOCKER_VIOLATIONS_KEY,
-    CRITICAL, NEW_CRITICAL_VIOLATIONS_KEY,
-    MAJOR, NEW_MAJOR_VIOLATIONS_KEY,
-    MINOR, NEW_MINOR_VIOLATIONS_KEY,
-    INFO, NEW_INFO_VIOLATIONS_KEY
-    );
-
-  private final PeriodsHolder periodsHolder;
-  private final MetricRepository metricRepository;
-  private final MeasureRepository measureRepository;
-
-  private final Map<Integer, Counters> countersByComponentRef = new HashMap<>();
-  private Counters currentCounters;
-
-  public CountIssuesListener(PeriodsHolder periodsHolder,
-    MetricRepository metricRepository, MeasureRepository measureRepository) {
-    this.periodsHolder = periodsHolder;
-    this.metricRepository = metricRepository;
-    this.measureRepository = measureRepository;
-  }
-
-  @Override
-  public void beforeComponent(Component component, Tracking tracking) {
-    // TODO optimization no need to instantiate counter if no open issues
-    currentCounters = new Counters();
-    countersByComponentRef.put(component.getRef(), currentCounters);
-
-    // aggregate children counters
-    for (Component child : component.getChildren()) {
-      // no need to keep the children in memory. They can be garbage-collected.
-      Counters childCounters = countersByComponentRef.remove(child.getRef());
-      currentCounters.add(childCounters);
-    }
-  }
-
-  @Override
-  public void onIssue(Component component, DefaultIssue issue) {
-    currentCounters.add(issue);
-    for (Period period : periodsHolder.getPeriods()) {
-      // Add one second to not take into account issues created during current analysis
-      if (issue.creationDate().getTime() >= period.getSnapshotDate() + 1000L) {
-        currentCounters.addOnPeriod(issue, period.getIndex());
-      }
-    }
-  }
-
-  @Override
-  public void afterComponent(Component component) {
-    addMeasuresByStatus(component);
-    addMeasuresBySeverity(component);
-    addMeasuresByPeriod(component);
-    currentCounters = null;
-  }
-
-  private void addMeasuresBySeverity(Component component) {
-    for (Map.Entry<String, String> entry : SEVERITY_TO_METRIC_KEY.entrySet()) {
-      String severity = entry.getKey();
-      String metricKey = entry.getValue();
-      addMeasure(component, metricKey, currentCounters.counter().severityBag.count(severity));
-    }
-  }
-
-  private void addMeasuresByStatus(Component component) {
-    addMeasure(component, VIOLATIONS_KEY, currentCounters.counter().unresolved);
-    addMeasure(component, OPEN_ISSUES_KEY, currentCounters.counter().open);
-    addMeasure(component, REOPENED_ISSUES_KEY, currentCounters.counter().reopened);
-    addMeasure(component, CONFIRMED_ISSUES_KEY, currentCounters.counter().confirmed);
-    addMeasure(component, FALSE_POSITIVE_ISSUES_KEY, currentCounters.counter().falsePositives);
-  }
-
-  private void addMeasure(Component component, String metricKey, int value) {
-    Metric metric = metricRepository.getByKey(metricKey);
-    measureRepository.add(component, metric, Measure.newMeasureBuilder().create(value));
-  }
-
-  private void addMeasuresByPeriod(Component component) {
-    if (!periodsHolder.getPeriods().isEmpty()) {
-      Double[] unresolvedVariations = new Double[PeriodsHolder.MAX_NUMBER_OF_PERIODS];
-      for (Period period : periodsHolder.getPeriods()) {
-        unresolvedVariations[period.getIndex() - 1] = new Double(currentCounters.counterForPeriod(period.getIndex()).unresolved);
-      }
-      measureRepository.add(component, metricRepository.getByKey(NEW_VIOLATIONS_KEY), Measure.newMeasureBuilder()
-        .setVariations(new MeasureVariations(unresolvedVariations))
-        .createNoValue());
-
-      for (Map.Entry<String, String> entry : SEVERITY_TO_NEW_METRIC_KEY.entrySet()) {
-        String severity = entry.getKey();
-        String metricKey = entry.getValue();
-        Double[] variations = new Double[PeriodsHolder.MAX_NUMBER_OF_PERIODS];
-        boolean set = false;
-        for (Period period : periodsHolder.getPeriods()) {
-          Multiset<String> bag = currentCounters.counterForPeriod(period.getIndex()).severityBag;
-          if (bag.contains(severity)) {
-            variations[period.getIndex() - 1] = new Double(bag.count(severity));
-            set = true;
-          }
-        }
-        if (set) {
-          Metric metric = metricRepository.getByKey(metricKey);
-          measureRepository.add(component, metric, Measure.newMeasureBuilder()
-            .setVariations(new MeasureVariations(variations))
-            .createNoValue());
-        }
-      }
-    }
-  }
-
-  /**
-   * Count issues by status, resolutions, rules and severities
-   */
-  private static class Counter {
-    private int unresolved = 0;
-    private int open = 0;
-    private int reopened = 0;
-    private int confirmed = 0;
-    private int falsePositives = 0;
-    private Multiset<String> severityBag = HashMultiset.create();
-
-    void add(Counter counter) {
-      unresolved += counter.unresolved;
-      open += counter.open;
-      reopened += counter.reopened;
-      confirmed += counter.confirmed;
-      falsePositives += counter.falsePositives;
-      severityBag.addAll(counter.severityBag);
-    }
-
-    void add(Issue issue) {
-      if (issue.resolution() == null) {
-        unresolved++;
-        severityBag.add(issue.severity());
-      } else if (Issue.RESOLUTION_FALSE_POSITIVE.equals(issue.resolution())) {
-        falsePositives++;
-      }
-      switch (issue.status()) {
-        case STATUS_OPEN:
-          open++;
-          break;
-        case STATUS_REOPENED:
-          reopened++;
-          break;
-        case STATUS_CONFIRMED:
-          confirmed++;
-          break;
-        default:
-          // Other statuses are ignored
-      }
-    }
-  }
-
-  /**
-   * List of {@link Counter} for regular value and periods.
-   */
-  private static class Counters {
-    private final Counter[] array = new Counter[1 + PeriodsHolder.MAX_NUMBER_OF_PERIODS];
-
-    Counters() {
-      array[0] = new Counter();
-      for (int i = 1; i <= PeriodsHolder.MAX_NUMBER_OF_PERIODS; i++) {
-        array[i] = new Counter();
-      }
-    }
-
-    void add(@Nullable Counters other) {
-      if (other != null) {
-        for (int i = 0; i < array.length; i++) {
-          array[i].add(other.array[i]);
-        }
-      }
-    }
-
-    void addOnPeriod(Issue issue, int periodIndex) {
-      array[periodIndex].add(issue);
-    }
-
-    void add(Issue issue) {
-      array[0].add(issue);
-    }
-
-    Counter counter() {
-      return array[0];
-    }
-
-    Counter counterForPeriod(int periodIndex) {
-      return array[periodIndex];
-    }
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/DebtAggregator.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/DebtAggregator.java
new file mode 100644 (file)
index 0000000..8bce132
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.computation.issue;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.tracking.Tracking;
+import org.sonar.core.rule.RuleDto;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.debt.Characteristic;
+import org.sonar.server.computation.debt.DebtModelHolder;
+import org.sonar.server.computation.measure.Measure;
+import org.sonar.server.computation.measure.MeasureRepository;
+import org.sonar.server.computation.metric.Metric;
+import org.sonar.server.computation.metric.MetricRepository;
+
+import static com.google.common.collect.Maps.newHashMap;
+
+public class DebtAggregator extends IssueVisitor {
+
+  private final RuleCache ruleCache;
+  private final DebtModelHolder debtModelHolder;
+  private final MetricRepository metricRepository;
+  private final MeasureRepository measureRepository;
+
+  private final Map<Integer, Debt> debtsByComponentRef = new HashMap<>();
+  private Debt currentDebt;
+
+  public DebtAggregator(RuleCache ruleCache, DebtModelHolder debtModelHolder,
+    MetricRepository metricRepository, MeasureRepository measureRepository) {
+    this.ruleCache = ruleCache;
+    this.debtModelHolder = debtModelHolder;
+    this.metricRepository = metricRepository;
+    this.measureRepository = measureRepository;
+  }
+
+  @Override
+  public void beforeComponent(Component component, Tracking tracking) {
+    this.currentDebt = new Debt();
+
+    // aggregate children counters
+    for (Component child : component.getChildren()) {
+      // no need to keep the children in memory. They can be garbage-collected.
+      Debt childDebt = debtsByComponentRef.remove(child.getRef());
+      if (childDebt != null) {
+        currentDebt.add(childDebt);
+      }
+    }
+  }
+
+  @Override
+  public void onIssue(Component component, DefaultIssue issue) {
+    if (issue.resolution() == null) {
+      currentDebt.add(issue);
+    }
+  }
+
+  @Override
+  public void afterComponent(Component component) {
+    if (this.currentDebt.minutes > 0L) {
+      Metric metric = metricRepository.getByKey(CoreMetrics.TECHNICAL_DEBT_KEY);
+
+      // total value
+      measureRepository.add(component, metric, Measure.newMeasureBuilder().create(this.currentDebt.minutes));
+
+      // distribution by rule
+      for (Map.Entry<Integer, Long> entry : currentDebt.minutesByRuleId.entrySet()) {
+        int ruleId = entry.getKey();
+        long ruleDebt = entry.getValue();
+        measureRepository.add(component, metric, Measure.newMeasureBuilder().forRule(ruleId).create(ruleDebt));
+      }
+
+      // distribution by characteristic
+      for (Map.Entry<Integer, Long> entry : currentDebt.minutesByCharacteristicId.entrySet()) {
+        int characteristicId = entry.getKey();
+        long characteristicDebt = entry.getValue();
+        measureRepository.add(component, metric, Measure.newMeasureBuilder().forCharacteristic(characteristicId).create(characteristicDebt));
+      }
+    }
+    this.currentDebt = null;
+  }
+
+  private class Debt {
+    private long minutes = 0L;
+    private final SumMap<Integer> minutesByRuleId = new SumMap<>();
+    private final SumMap<Integer> minutesByCharacteristicId = new SumMap<>();
+
+    void add(DefaultIssue issue) {
+      Long issueMinutes = issue.debtInMinutes();
+      if (issueMinutes != null && issueMinutes != 0L) {
+        this.minutes += issueMinutes;
+
+        RuleDto rule = ruleCache.get(issue.ruleKey());
+        this.minutesByRuleId.add(rule.getId(), issueMinutes);
+
+        Integer subCharacteristicId = rule.getSubCharacteristicId();
+        if (subCharacteristicId != null) {
+          Characteristic characteristic = debtModelHolder.getCharacteristicById(subCharacteristicId);
+          this.minutesByCharacteristicId.add(characteristic.getId(), issueMinutes);
+          Integer characteristicParentId = characteristic.getParentId();
+          if (characteristicParentId != null) {
+            this.minutesByCharacteristicId.add(characteristicParentId, issueMinutes);
+          }
+        }
+      }
+    }
+
+    public void add(Debt debt) {
+      this.minutes += debt.minutes;
+      this.minutesByRuleId.add(debt.minutesByRuleId);
+      this.minutesByCharacteristicId.add(debt.minutesByCharacteristicId);
+    }
+  }
+
+  private static class SumMap<E> {
+    private final Map<E, Long> sumByKeys = newHashMap();
+
+    void add(SumMap<E> other) {
+      for (Map.Entry<E, Long> entry : other.entrySet()) {
+        add(entry.getKey(), entry.getValue());
+      }
+    }
+
+    void add(@Nullable E key, Long value) {
+      if (key != null) {
+        Long currentValue = sumByKeys.get(key);
+        sumByKeys.put(key, currentValue != null ? (currentValue + value) : value);
+      }
+    }
+
+    @CheckForNull
+    Long get(E key) {
+      return sumByKeys.get(key);
+    }
+
+    Set<Map.Entry<E, Long>> entrySet() {
+      return sumByKeys.entrySet();
+    }
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/DebtCalculator.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/DebtCalculator.java
deleted file mode 100644 (file)
index b5ee6bb..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.server.computation.issue;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.core.issue.DefaultIssue;
-import org.sonar.core.issue.IssueUpdater;
-import org.sonar.core.issue.tracking.Tracking;
-import org.sonar.core.rule.RuleDto;
-import org.sonar.server.computation.component.Component;
-import org.sonar.server.computation.debt.Characteristic;
-import org.sonar.server.computation.debt.DebtModelHolder;
-import org.sonar.server.computation.measure.Measure;
-import org.sonar.server.computation.measure.MeasureRepository;
-import org.sonar.server.computation.metric.Metric;
-import org.sonar.server.computation.metric.MetricRepository;
-
-import static com.google.common.collect.Maps.newHashMap;
-
-public class DebtCalculator extends IssueListener {
-
-  private final IssueUpdater updater;
-  private final RuleCache ruleCache;
-  private final DebtModelHolder debtModelHolder;
-  private final MetricRepository metricRepository;
-  private final MeasureRepository measureRepository;
-
-  private final Map<Integer, Debt> debtsByComponentRef = new HashMap<>();
-  private Debt currentDebt;
-
-  public DebtCalculator(IssueUpdater updater, RuleCache ruleCache, DebtModelHolder debtModelHolder,
-    MetricRepository metricRepository, MeasureRepository measureRepository) {
-    this.updater = updater;
-    this.ruleCache = ruleCache;
-    this.debtModelHolder = debtModelHolder;
-    this.metricRepository = metricRepository;
-    this.measureRepository = measureRepository;
-  }
-
-  @Override
-  public void beforeComponent(Component component, Tracking tracking) {
-    this.currentDebt = new Debt();
-
-    // aggregate children counters
-    for (Component child : component.getChildren()) {
-      // no need to keep the children in memory. They can be garbage-collected.
-      Debt childDebt = debtsByComponentRef.remove(child.getRef());
-      currentDebt.add(childDebt);
-    }
-  }
-
-  @Override
-  public void onIssue(Component component, DefaultIssue issue) {
-    if (issue.resolution() == null) {
-      // TODO calculate debt according to rule remediation function. Currently done by batch.
-      currentDebt.add(issue);
-    }
-  }
-
-  @Override
-  public void afterComponent(Component component) {
-    if (this.currentDebt.minutes > 0L) {
-      Metric metric = metricRepository.getByKey(CoreMetrics.TECHNICAL_DEBT_KEY);
-
-      // total value
-      measureRepository.add(component, metric, Measure.newMeasureBuilder().create(this.currentDebt.minutes));
-
-      // distribution by rule
-      for (Map.Entry<Integer, Long> entry : currentDebt.minutesByRuleId.entrySet()) {
-        int ruleId = entry.getKey();
-        long ruleDebt = entry.getValue();
-        measureRepository.add(component, metric, Measure.newMeasureBuilder().forRule(ruleId).create(ruleDebt));
-      }
-
-      // distribution by characteristic
-      for (Map.Entry<Integer, Long> entry : currentDebt.minutesByCharacteristicId.entrySet()) {
-        int characteristicId = entry.getKey();
-        long characteristicDebt = entry.getValue();
-        measureRepository.add(component, metric, Measure.newMeasureBuilder().forCharacteristic(characteristicId).create(characteristicDebt));
-      }
-    }
-    this.currentDebt = null;
-  }
-
-  private class Debt {
-    private long minutes = 0L;
-    private final SumMap<Integer> minutesByRuleId = new SumMap<>();
-    private final SumMap<Integer> minutesByCharacteristicId = new SumMap<>();
-
-    void add(DefaultIssue issue) {
-      Long issueMinutes = issue.debtInMinutes();
-      if (issueMinutes != null && issueMinutes != 0L) {
-        this.minutes += issueMinutes;
-
-        RuleDto rule = ruleCache.get(issue.ruleKey());
-        this.minutesByRuleId.add(rule.getId(), issueMinutes);
-
-        Characteristic characteristic = debtModelHolder.getCharacteristicById(rule.getSubCharacteristicId());
-        this.minutesByCharacteristicId.add(characteristic.getId(), issueMinutes);
-        Integer characteristicParentId = characteristic.getParentId();
-        if (characteristicParentId != null) {
-          this.minutesByCharacteristicId.add(characteristicParentId, issueMinutes);
-        }
-      }
-    }
-
-    public void add(Debt debt) {
-      this.minutes += debt.minutes;
-      this.minutesByRuleId.add(debt.minutesByRuleId);
-      this.minutesByCharacteristicId.add(debt.minutesByCharacteristicId);
-    }
-  }
-
-  private static class SumMap<E> {
-    private final Map<E, Long> sumByKeys = newHashMap();
-
-    void add(SumMap<E> other) {
-      for (Map.Entry<E, Long> entry : other.entrySet()) {
-        add(entry.getKey(), entry.getValue());
-      }
-    }
-
-    void add(@Nullable E key, Long value) {
-      if (key != null) {
-        Long currentValue = sumByKeys.get(key);
-        sumByKeys.put(key, currentValue != null ? (currentValue + value) : value);
-      }
-    }
-
-    @CheckForNull
-    Long get(E key) {
-      return sumByKeys.get(key);
-    }
-
-    Set<Map.Entry<E, Long>> entrySet() {
-      return sumByKeys.entrySet();
-    }
-  }
-}
index 7d3087f0a076c8df64eb4f4e0ab36d1cc1cd1ac4..7f49d9831541c21778a008678af721463f0b8d29 100644 (file)
@@ -43,7 +43,7 @@ import org.sonar.server.source.index.SourceLineIndex;
  *   <li>the Elasticsearch index of source lines for non-modified files</li>
  * </ul>
  */
-public class IssueAssigner extends IssueListener {
+public class IssueAssigner extends IssueVisitor {
 
   private final SourceLineIndex sourceLineIndex;
   private final BatchReportReader reportReader;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueCounter.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueCounter.java
new file mode 100644 (file)
index 0000000..2e49500
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.computation.issue;
+
+import com.google.common.collect.HashMultiset;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Multiset;
+import java.util.HashMap;
+import java.util.Map;
+import javax.annotation.Nullable;
+import org.sonar.api.issue.Issue;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.tracking.Tracking;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.measure.Measure;
+import org.sonar.server.computation.measure.MeasureRepository;
+import org.sonar.server.computation.measure.MeasureVariations;
+import org.sonar.server.computation.metric.Metric;
+import org.sonar.server.computation.metric.MetricRepository;
+import org.sonar.server.computation.period.Period;
+import org.sonar.server.computation.period.PeriodsHolder;
+
+import static org.sonar.api.issue.Issue.STATUS_CONFIRMED;
+import static org.sonar.api.issue.Issue.STATUS_OPEN;
+import static org.sonar.api.issue.Issue.STATUS_REOPENED;
+import static org.sonar.api.measures.CoreMetrics.BLOCKER_VIOLATIONS_KEY;
+import static org.sonar.api.measures.CoreMetrics.CONFIRMED_ISSUES_KEY;
+import static org.sonar.api.measures.CoreMetrics.CRITICAL_VIOLATIONS_KEY;
+import static org.sonar.api.measures.CoreMetrics.FALSE_POSITIVE_ISSUES_KEY;
+import static org.sonar.api.measures.CoreMetrics.INFO_VIOLATIONS_KEY;
+import static org.sonar.api.measures.CoreMetrics.MAJOR_VIOLATIONS_KEY;
+import static org.sonar.api.measures.CoreMetrics.MINOR_VIOLATIONS_KEY;
+import static org.sonar.api.measures.CoreMetrics.NEW_BLOCKER_VIOLATIONS_KEY;
+import static org.sonar.api.measures.CoreMetrics.NEW_CRITICAL_VIOLATIONS_KEY;
+import static org.sonar.api.measures.CoreMetrics.NEW_INFO_VIOLATIONS_KEY;
+import static org.sonar.api.measures.CoreMetrics.NEW_MAJOR_VIOLATIONS_KEY;
+import static org.sonar.api.measures.CoreMetrics.NEW_MINOR_VIOLATIONS_KEY;
+import static org.sonar.api.measures.CoreMetrics.NEW_VIOLATIONS_KEY;
+import static org.sonar.api.measures.CoreMetrics.OPEN_ISSUES_KEY;
+import static org.sonar.api.measures.CoreMetrics.REOPENED_ISSUES_KEY;
+import static org.sonar.api.measures.CoreMetrics.VIOLATIONS_KEY;
+import static org.sonar.api.rule.Severity.BLOCKER;
+import static org.sonar.api.rule.Severity.CRITICAL;
+import static org.sonar.api.rule.Severity.INFO;
+import static org.sonar.api.rule.Severity.MAJOR;
+import static org.sonar.api.rule.Severity.MINOR;
+
+/**
+ * For each component, computes the measures related to number of issues:
+ * <ul>
+ *   <li>unresolved issues</li>
+ *   <li>false-positives</li>
+ *   <li>open issues</li>
+ *   <li>issues per status (open, reopen, confirmed)</li>
+ *   <li>issues per severity (from info to blocker)</li>
+ * </ul>
+ * For each value, the variation on configured periods is also computed.
+ */
+public class IssueCounter extends IssueVisitor {
+
+  private final static Map<String, String> SEVERITY_TO_METRIC_KEY = ImmutableMap.of(
+    BLOCKER, BLOCKER_VIOLATIONS_KEY,
+    CRITICAL, CRITICAL_VIOLATIONS_KEY,
+    MAJOR, MAJOR_VIOLATIONS_KEY,
+    MINOR, MINOR_VIOLATIONS_KEY,
+    INFO, INFO_VIOLATIONS_KEY
+    );
+
+  private final static Map<String, String> SEVERITY_TO_NEW_METRIC_KEY = ImmutableMap.of(
+    BLOCKER, NEW_BLOCKER_VIOLATIONS_KEY,
+    CRITICAL, NEW_CRITICAL_VIOLATIONS_KEY,
+    MAJOR, NEW_MAJOR_VIOLATIONS_KEY,
+    MINOR, NEW_MINOR_VIOLATIONS_KEY,
+    INFO, NEW_INFO_VIOLATIONS_KEY
+    );
+
+  private final PeriodsHolder periodsHolder;
+  private final MetricRepository metricRepository;
+  private final MeasureRepository measureRepository;
+
+  private final Map<Integer, Counters> countersByComponentRef = new HashMap<>();
+  private Counters currentCounters;
+
+  public IssueCounter(PeriodsHolder periodsHolder,
+                      MetricRepository metricRepository, MeasureRepository measureRepository) {
+    this.periodsHolder = periodsHolder;
+    this.metricRepository = metricRepository;
+    this.measureRepository = measureRepository;
+  }
+
+  @Override
+  public void beforeComponent(Component component, Tracking tracking) {
+    // TODO optimization no need to instantiate counter if no open issues
+    currentCounters = new Counters();
+    countersByComponentRef.put(component.getRef(), currentCounters);
+
+    // aggregate children counters
+    for (Component child : component.getChildren()) {
+      // no need to keep the children in memory. They can be garbage-collected.
+      Counters childCounters = countersByComponentRef.remove(child.getRef());
+      currentCounters.add(childCounters);
+    }
+  }
+
+  @Override
+  public void onIssue(Component component, DefaultIssue issue) {
+    currentCounters.add(issue);
+    for (Period period : periodsHolder.getPeriods()) {
+      // Add one second to not take into account issues created during current analysis
+      if (issue.creationDate().getTime() >= period.getSnapshotDate() + 1000L) {
+        currentCounters.addOnPeriod(issue, period.getIndex());
+      }
+    }
+  }
+
+  @Override
+  public void afterComponent(Component component) {
+    addMeasuresByStatus(component);
+    addMeasuresBySeverity(component);
+    addMeasuresByPeriod(component);
+    currentCounters = null;
+  }
+
+  private void addMeasuresBySeverity(Component component) {
+    for (Map.Entry<String, String> entry : SEVERITY_TO_METRIC_KEY.entrySet()) {
+      String severity = entry.getKey();
+      String metricKey = entry.getValue();
+      addMeasure(component, metricKey, currentCounters.counter().severityBag.count(severity));
+    }
+  }
+
+  private void addMeasuresByStatus(Component component) {
+    addMeasure(component, VIOLATIONS_KEY, currentCounters.counter().unresolved);
+    addMeasure(component, OPEN_ISSUES_KEY, currentCounters.counter().open);
+    addMeasure(component, REOPENED_ISSUES_KEY, currentCounters.counter().reopened);
+    addMeasure(component, CONFIRMED_ISSUES_KEY, currentCounters.counter().confirmed);
+    addMeasure(component, FALSE_POSITIVE_ISSUES_KEY, currentCounters.counter().falsePositives);
+  }
+
+  private void addMeasure(Component component, String metricKey, int value) {
+    Metric metric = metricRepository.getByKey(metricKey);
+    measureRepository.add(component, metric, Measure.newMeasureBuilder().create(value));
+  }
+
+  private void addMeasuresByPeriod(Component component) {
+    if (!periodsHolder.getPeriods().isEmpty()) {
+      Double[] unresolvedVariations = new Double[PeriodsHolder.MAX_NUMBER_OF_PERIODS];
+      for (Period period : periodsHolder.getPeriods()) {
+        unresolvedVariations[period.getIndex() - 1] = new Double(currentCounters.counterForPeriod(period.getIndex()).unresolved);
+      }
+      measureRepository.add(component, metricRepository.getByKey(NEW_VIOLATIONS_KEY), Measure.newMeasureBuilder()
+        .setVariations(new MeasureVariations(unresolvedVariations))
+        .createNoValue());
+
+      for (Map.Entry<String, String> entry : SEVERITY_TO_NEW_METRIC_KEY.entrySet()) {
+        String severity = entry.getKey();
+        String metricKey = entry.getValue();
+        Double[] variations = new Double[PeriodsHolder.MAX_NUMBER_OF_PERIODS];
+        boolean set = false;
+        for (Period period : periodsHolder.getPeriods()) {
+          Multiset<String> bag = currentCounters.counterForPeriod(period.getIndex()).severityBag;
+          if (bag.contains(severity)) {
+            variations[period.getIndex() - 1] = new Double(bag.count(severity));
+            set = true;
+          }
+        }
+        if (set) {
+          Metric metric = metricRepository.getByKey(metricKey);
+          measureRepository.add(component, metric, Measure.newMeasureBuilder()
+            .setVariations(new MeasureVariations(variations))
+            .createNoValue());
+        }
+      }
+    }
+  }
+
+  /**
+   * Count issues by status, resolutions, rules and severities
+   */
+  private static class Counter {
+    private int unresolved = 0;
+    private int open = 0;
+    private int reopened = 0;
+    private int confirmed = 0;
+    private int falsePositives = 0;
+    private Multiset<String> severityBag = HashMultiset.create();
+
+    void add(Counter counter) {
+      unresolved += counter.unresolved;
+      open += counter.open;
+      reopened += counter.reopened;
+      confirmed += counter.confirmed;
+      falsePositives += counter.falsePositives;
+      severityBag.addAll(counter.severityBag);
+    }
+
+    void add(Issue issue) {
+      if (issue.resolution() == null) {
+        unresolved++;
+        severityBag.add(issue.severity());
+      } else if (Issue.RESOLUTION_FALSE_POSITIVE.equals(issue.resolution())) {
+        falsePositives++;
+      }
+      switch (issue.status()) {
+        case STATUS_OPEN:
+          open++;
+          break;
+        case STATUS_REOPENED:
+          reopened++;
+          break;
+        case STATUS_CONFIRMED:
+          confirmed++;
+          break;
+        default:
+          // Other statuses are ignored
+      }
+    }
+  }
+
+  /**
+   * List of {@link Counter} for regular value and periods.
+   */
+  private static class Counters {
+    private final Counter[] array = new Counter[1 + PeriodsHolder.MAX_NUMBER_OF_PERIODS];
+
+    Counters() {
+      array[0] = new Counter();
+      for (int i = 1; i <= PeriodsHolder.MAX_NUMBER_OF_PERIODS; i++) {
+        array[i] = new Counter();
+      }
+    }
+
+    void add(@Nullable Counters other) {
+      if (other != null) {
+        for (int i = 0; i < array.length; i++) {
+          array[i].add(other.array[i]);
+        }
+      }
+    }
+
+    void addOnPeriod(Issue issue, int periodIndex) {
+      array[periodIndex].add(issue);
+    }
+
+    void add(Issue issue) {
+      array[0].add(issue);
+    }
+
+    Counter counter() {
+      return array[0];
+    }
+
+    Counter counterForPeriod(int periodIndex) {
+      return array[periodIndex];
+    }
+  }
+}
index 713e65306ffd5455d0e2ee5ff39af1f652a02e2a..10bd8af2edfc00981fd5b38843f7c812d9491aca 100644 (file)
@@ -73,6 +73,7 @@ public class IssueLifecycle {
     updater.setPastMessage(raw, base.getMessage(), changeContext);
     updater.setPastEffortToFix(raw, base.effortToFix(), changeContext);
     updater.setPastTechnicalDebt(raw, base.debt(), changeContext);
+    raw.setSelectedAt(base.selectedAt());
   }
 
   public void doAutomaticTransition(DefaultIssue issue) {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueListener.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueListener.java
deleted file mode 100644 (file)
index ebd3d4e..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.server.computation.issue;
-
-import org.sonar.core.issue.DefaultIssue;
-import org.sonar.core.issue.tracking.Tracking;
-import org.sonar.server.computation.component.Component;
-
-public abstract class IssueListener {
-
-  /**
-   * This method is called for each component before processing its issues.
-   * The component does not necessarily have issues.
-   */
-  public void beforeComponent(Component component, Tracking tracking) {
-
-  }
-
-  /**
-   * This method is called when initializing an open issue. At that time
-   * any information related to tracking step are not available (line, assignee,
-   * resolution, status, creation date, uuid, ...).
-   * <p/>
-   * The need for this method is for example to calculate the issue debt
-   * before merging with base issue
-   */
-  public void onOpenIssueInitialization(Component component, DefaultIssue issue) {
-
-  }
-
-  /**
-   * This method is called when tracking is done and issue is initialized. That means that the following fields
-   * are set: resolution, status, line, creation date, uuid and all the fields merged from base issues.
-   */
-  public void onIssue(Component component, DefaultIssue issue) {
-
-  }
-
-  public void afterComponent(Component component) {
-
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueListeners.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueListeners.java
deleted file mode 100644 (file)
index 7c92c0e..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.server.computation.issue;
-
-import org.sonar.core.issue.DefaultIssue;
-import org.sonar.core.issue.tracking.Tracking;
-import org.sonar.server.computation.component.Component;
-
-public class IssueListeners {
-
-  private final IssueListener[] listeners;
-
-  public IssueListeners(IssueListener[] listeners) {
-    this.listeners = listeners;
-  }
-
-  public void beforeComponent(Component component, Tracking tracking) {
-    for (IssueListener listener : listeners) {
-      listener.beforeComponent(component, tracking);
-    }
-  }
-
-  public void onOpenIssueInitialization(Component component, DefaultIssue issue) {
-    for (IssueListener listener : listeners) {
-      listener.onOpenIssueInitialization(component, issue);
-    }
-  }
-
-  public void onIssue(Component component, DefaultIssue issue) {
-    for (IssueListener listener : listeners) {
-      listener.onIssue(component, issue);
-    }
-  }
-
-  public void afterComponent(Component component) {
-    for (IssueListener listener : listeners) {
-      listener.afterComponent(component);
-    }
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueVisitor.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueVisitor.java
new file mode 100644 (file)
index 0000000..7385ff0
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.computation.issue;
+
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.tracking.Tracking;
+import org.sonar.server.computation.component.Component;
+
+public abstract class IssueVisitor {
+
+  /**
+   * This method is called for each component before processing its issues.
+   * The component does not necessarily have issues.
+   */
+  public void beforeComponent(Component component, Tracking tracking) {
+
+  }
+
+  /**
+   * This method is called when tracking is done and issue is initialized. That means that the following fields
+   * are set: resolution, status, line, creation date, uuid and all the fields merged from base issues.
+   */
+  public void onIssue(Component component, DefaultIssue issue) {
+
+  }
+
+  public void afterComponent(Component component) {
+
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueVisitors.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueVisitors.java
new file mode 100644 (file)
index 0000000..51ddee1
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.computation.issue;
+
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.tracking.Tracking;
+import org.sonar.server.computation.component.Component;
+
+public class IssueVisitors {
+
+  private final IssueVisitor[] visitors;
+
+  public IssueVisitors(IssueVisitor[] visitors) {
+    this.visitors = visitors;
+  }
+
+  public void beforeComponent(Component component, Tracking tracking) {
+    for (IssueVisitor visitor : visitors) {
+      visitor.beforeComponent(component, tracking);
+    }
+  }
+
+  public void onIssue(Component component, DefaultIssue issue) {
+    for (IssueVisitor visitor : visitors) {
+      visitor.onIssue(component, issue);
+    }
+  }
+
+  public void afterComponent(Component component) {
+    for (IssueVisitor visitor : visitors) {
+      visitor.afterComponent(component);
+    }
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/NewDebtAggregator.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/NewDebtAggregator.java
new file mode 100644 (file)
index 0000000..dd21225
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.computation.issue;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ListMultimap;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.db.IssueChangeDto;
+import org.sonar.core.issue.tracking.Tracking;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.measure.Measure;
+import org.sonar.server.computation.measure.MeasureRepository;
+import org.sonar.server.computation.measure.MeasureVariations;
+import org.sonar.server.computation.metric.Metric;
+import org.sonar.server.computation.metric.MetricRepository;
+import org.sonar.server.computation.period.Period;
+import org.sonar.server.computation.period.PeriodsHolder;
+import org.sonar.server.db.DbClient;
+
+public class NewDebtAggregator extends IssueVisitor {
+
+  private final NewDebtCalculator calculator;
+  private final PeriodsHolder periodsHolder;
+  private final DbClient dbClient;
+  private final MetricRepository metricRepository;
+  private final MeasureRepository measureRepository;
+
+  private ListMultimap<String, IssueChangeDto> changesByIssueUuid = ArrayListMultimap.create();
+  private Map<Integer, DebtSum> sumsByComponentRef = new HashMap<>();
+  private DebtSum currentSum = null;
+
+  public NewDebtAggregator(NewDebtCalculator calculator, PeriodsHolder periodsHolder, DbClient dbClient,
+    MetricRepository metricRepository, MeasureRepository measureRepository) {
+    this.calculator = calculator;
+    this.periodsHolder = periodsHolder;
+    this.dbClient = dbClient;
+    this.metricRepository = metricRepository;
+    this.measureRepository = measureRepository;
+  }
+
+  @Override
+  public void beforeComponent(Component component, Tracking tracking) {
+    currentSum = new DebtSum();
+    sumsByComponentRef.put(component.getRef(), currentSum);
+    List<IssueChangeDto> changes = dbClient.issueChangeDao().selectChangelogOfUnresolvedIssuesByComponent(component.getUuid());
+    for (IssueChangeDto change : changes) {
+      changesByIssueUuid.put(change.getIssueKey(), change);
+    }
+  }
+
+  @Override
+  public void onIssue(Component component, DefaultIssue issue) {
+    if (issue.debtInMinutes() != null && !periodsHolder.getPeriods().isEmpty()) {
+      List<IssueChangeDto> changelog = changesByIssueUuid.get(issue.key());
+      for (Period period : periodsHolder.getPeriods()) {
+        long newDebt = calculator.calculate(issue, changelog, period);
+        currentSum.add(period.getIndex(), newDebt);
+      }
+    }
+    for (Component child : component.getChildren()) {
+      DebtSum childSum = sumsByComponentRef.remove(child.getRef());
+      if (childSum != null) {
+        currentSum.add(childSum);
+      }
+    }
+  }
+
+  @Override
+  public void afterComponent(Component component) {
+    if (!currentSum.isEmpty) {
+      MeasureVariations variations = new MeasureVariations(currentSum.sums);
+      Metric metric = metricRepository.getByKey(CoreMetrics.NEW_TECHNICAL_DEBT_KEY);
+      measureRepository.add(component, metric, Measure.newMeasureBuilder().setVariations(variations).createNoValue());
+    }
+    changesByIssueUuid.clear();
+    currentSum = null;
+  }
+
+  private static class DebtSum {
+    private Double[] sums = new Double[PeriodsHolder.MAX_NUMBER_OF_PERIODS];
+    private boolean isEmpty = true;
+
+    void add(int periodIndex, long newDebt) {
+      double previous = Objects.firstNonNull(sums[periodIndex - 1], 0d);
+      sums[periodIndex - 1] = previous + newDebt;
+      isEmpty = false;
+    }
+
+    void add(DebtSum other) {
+      for (int i = 0; i < sums.length; i++) {
+        Double otherValue = other.sums[i];
+        if (otherValue != null) {
+          add(i + 1, otherValue.longValue());
+        }
+      }
+    }
+  }
+}
index b21ffd09de3d1da04fce7172e6c0c155bf96e075..6d7c85941c3f198e7b6fe13430967d27207701fc 100644 (file)
  */
 package org.sonar.server.computation.issue;
 
+import com.google.common.base.Function;
+import com.google.common.base.Objects;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Ordering;
+import java.util.Calendar;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.apache.commons.lang.time.DateUtils;
 import org.sonar.core.issue.DefaultIssue;
-import org.sonar.server.computation.component.Component;
+import org.sonar.core.issue.FieldDiffs;
+import org.sonar.core.issue.IssueUpdater;
+import org.sonar.core.issue.db.IssueChangeDto;
+import org.sonar.server.computation.period.Period;
 
-public class NewDebtCalculator extends IssueListener {
+import static com.google.common.collect.FluentIterable.from;
 
-  @Override
-  public void onIssue(Component component, DefaultIssue issue) {
-    // TODO
+/**
+ * Gets the issue debt that was introduced on a period. The algorithm
+ * is based on the issue changelog.
+ */
+public class NewDebtCalculator {
+
+  public long calculate(DefaultIssue issue, List<IssueChangeDto> debtChangelog, Period period) {
+    if (issue.creationDate().getTime() > period.getSnapshotDate() + 1000L) {
+      return Objects.firstNonNull(issue.debtInMinutes(), 0L);
+    }
+    return calculateFromChangelog(issue, debtChangelog, period.getSnapshotDate());
+  }
+
+  private long calculateFromChangelog(DefaultIssue issue, List<IssueChangeDto> debtChangelog, long periodDate) {
+    List<FieldDiffs> debtDiffs = from(debtChangelog).transform(ToFieldDiffs.INSTANCE).filter(HasDebtChange.INSTANCE).toSortedList(CHANGE_ORDERING);
+    long newDebt = issue.debtInMinutes().longValue();
+
+    for (Iterator<FieldDiffs> it = debtDiffs.iterator(); it.hasNext();) {
+      FieldDiffs diffs = it.next();
+      Date date = diffs.creationDate();
+      // TODO use longs
+      if (isBeforeOrEqual(date, new Date(periodDate))) {
+        // return new value from the change that is just before the period date
+        return subtract(newDebt, debtDiff(diffs).newValueLong());
+      }
+      if (!it.hasNext()) {
+        // return old value from the change that is just after the period date when there's no more element in changelog
+        return subtract(newDebt, debtDiff(diffs).oldValueLong());
+      }
+    }
+    // no changelog
+    return 0L;
+  }
+
+  /**
+   * SONAR-5059
+   */
+  @CheckForNull
+  private static long subtract(long newDebt, @Nullable Long with) {
+    if (with != null) {
+      return Math.min(0L, newDebt - with);
+    }
+    return newDebt;
   }
 
+  private static boolean isBeforeOrEqual(@Nullable Date changeDate, Date periodDate) {
+    return (changeDate != null) && (DateUtils.truncatedCompareTo(changeDate, periodDate, Calendar.SECOND) <= 0);
+  }
+
+  private static FieldDiffs.Diff debtDiff(FieldDiffs diffs) {
+    return diffs.diffs().get(IssueUpdater.TECHNICAL_DEBT);
+  }
+
+  /**
+   * Changelog have to be sorted from newest to oldest.
+   * Null date should be the first as this happen when technical debt has changed since previous analysis.
+   */
+  private static final Comparator<FieldDiffs> CHANGE_ORDERING = Ordering.natural().reverse().nullsFirst().onResultOf(new Function<FieldDiffs, Date>() {
+    @Override
+    public Date apply(@Nonnull FieldDiffs dto) {
+      return dto.creationDate();
+    }
+  });
+
+  private enum ToFieldDiffs implements Function<IssueChangeDto, FieldDiffs> {
+    INSTANCE;
+    @Override
+    public FieldDiffs apply(@Nonnull IssueChangeDto dto) {
+      FieldDiffs diffs = FieldDiffs.parse(dto.getChangeData());
+      diffs.setIssueKey(dto.getIssueKey());
+      Long date = dto.getIssueChangeCreationDate();
+      if (date != null) {
+        diffs.setCreationDate(new Date(date));
+      }
+      return diffs;
+    }
+  }
+
+  private enum HasDebtChange implements Predicate<FieldDiffs> {
+    INSTANCE;
+    @Override
+    public boolean apply(@Nonnull FieldDiffs diffs) {
+      return diffs.diffs().containsKey(IssueUpdater.TECHNICAL_DEBT);
+    }
+  }
 }
index 2d33d7898bf0c56203148fd26038386bfe5eb9f3..75530ff601d51f4189cb7d4b77467ec18a753663 100644 (file)
@@ -26,7 +26,7 @@ import org.sonar.server.computation.component.Component;
 
 import static com.google.common.collect.Sets.union;
 
-public class RuleTagsCopier extends IssueListener {
+public class RuleTagsCopier extends IssueVisitor {
 
   private final RuleCache ruleCache;
 
index e5117d3fe23f8b3246f48883c9ce3d159e25617b..8f5feb2573cff5fd5735f75a7803a494f3ae9435 100644 (file)
@@ -23,6 +23,7 @@ import java.util.List;
 import org.sonar.core.issue.DefaultIssue;
 import org.sonar.core.issue.tracking.Input;
 import org.sonar.core.issue.tracking.LazyInput;
+import org.sonar.core.issue.tracking.LineHashSequence;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.core.persistence.MyBatis;
 import org.sonar.server.computation.component.Component;
@@ -53,10 +54,11 @@ public class TrackerBaseInputFactory {
     }
 
     @Override
-    protected Iterable<String> loadSourceLines() {
+    protected LineHashSequence loadLineHashSequence() {
       DbSession session = dbClient.openSession(false);
       try {
-        return dbClient.fileSourceDao().selectLineHashes(session, component.getUuid());
+        List<String> hashes = dbClient.fileSourceDao().selectLineHashes(session, component.getUuid());
+        return new LineHashSequence(hashes);
       } finally {
         MyBatis.closeQuietly(session);
       }
index 036a0e5d74de1f39a5c67589009ea88a9455459e..e61e9a578bae38f728593169d8a3826151823896 100644 (file)
@@ -22,10 +22,12 @@ package org.sonar.server.computation.issue;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import org.sonar.api.issue.Issue;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.utils.Duration;
+import org.sonar.api.utils.log.Loggers;
 import org.sonar.batch.protocol.output.BatchReport;
 import org.sonar.core.issue.DefaultIssue;
 import org.sonar.core.issue.tracking.Input;
@@ -59,8 +61,14 @@ public class TrackerRawInputFactory {
     }
 
     @Override
-    protected Iterable<String> loadSourceLines() {
-      return Lists.newArrayList(reportReader.readFileSource(component.getRef()));
+    protected LineHashSequence loadLineHashSequence() {
+      Iterable<String> lines;
+      if (component.getType() == Component.Type.FILE) {
+        lines = Lists.newArrayList(reportReader.readFileSource(component.getRef()));
+      } else {
+        lines = Collections.emptyList();
+      }
+      return LineHashSequence.createForLines(lines);
     }
 
     @Override
@@ -73,6 +81,7 @@ public class TrackerRawInputFactory {
         for (BatchReport.Issue reportIssue : reportIssues) {
           DefaultIssue issue = toIssue(lineHashSeq, reportIssue);
           if (isValid(issue, lineHashSeq)) {
+            Loggers.get(getClass()).info("Loaded from report: " + issue);
             issues.add(issue);
           }
         }
@@ -83,10 +92,12 @@ public class TrackerRawInputFactory {
     private DefaultIssue toIssue(LineHashSequence lineHashSeq, BatchReport.Issue reportIssue) {
       DefaultIssue issue = new DefaultIssue();
       issue.setRuleKey(RuleKey.of(reportIssue.getRuleRepository(), reportIssue.getRuleKey()));
+      issue.setResolution(null);
       issue.setStatus(Issue.STATUS_OPEN);
       issue.setComponentUuid(component.getUuid());
       issue.setComponentKey(component.getKey());
       issue.setProjectUuid(treeRootHolder.getRoot().getUuid());
+      issue.setProjectKey(treeRootHolder.getRoot().getKey());
 
       if (reportIssue.hasLine()) {
         issue.setLine(reportIssue.getLine());
@@ -113,12 +124,14 @@ public class TrackerRawInputFactory {
   }
 
   private boolean isValid(DefaultIssue issue, LineHashSequence lineHashSeq) {
-    // TODO log debug when invalid ?
+    // TODO log debug when invalid ? Or throw exception ?
+
     if (ruleCache.getNullable(issue.ruleKey()) == null) {
       return false;
     }
     if (issue.getLine() != null && !lineHashSeq.hasLine(issue.getLine())) {
-      return false;
+      // FIXME
+      //return false;
     }
     return true;
   }
index bdaeae331865020b7e682273b3dd16b09e0a6d5a..41a4e49cb775398c847be4c1159f62b9f5bbd724 100644 (file)
@@ -22,20 +22,12 @@ package org.sonar.server.computation.measure;
 import com.google.common.base.Optional;
 import java.util.Objects;
 import javax.annotation.Nullable;
-import org.sonar.api.rule.RuleKey;
 import org.sonar.batch.protocol.output.BatchReport;
-import org.sonar.core.rule.RuleDto;
-import org.sonar.server.computation.issue.RuleCache;
 import org.sonar.server.computation.metric.Metric;
 
 import static com.google.common.base.Optional.of;
 
 public class BatchMeasureToMeasure {
-  private final RuleCache ruleCache;
-
-  public BatchMeasureToMeasure(RuleCache ruleCache) {
-    this.ruleCache = ruleCache;
-  }
 
   public Optional<Measure> toMeasure(@Nullable BatchReport.Measure batchMeasure, Metric metric) {
     Objects.requireNonNull(metric);
@@ -43,7 +35,7 @@ public class BatchMeasureToMeasure {
       return Optional.absent();
     }
 
-    Measure.NewMeasureBuilder builder = createBuilder(batchMeasure);
+    Measure.NewMeasureBuilder builder = Measure.newMeasureBuilder();
     String data = batchMeasure.hasStringValue() ? batchMeasure.getStringValue() : null;
     switch (metric.getType().getValueType()) {
       case INT:
@@ -65,20 +57,6 @@ public class BatchMeasureToMeasure {
     }
   }
 
-  private Measure.NewMeasureBuilder createBuilder(BatchReport.Measure batchMeasure) {
-    if (batchMeasure.hasCharactericId() && batchMeasure.hasRuleKey()) {
-      throw new IllegalArgumentException("Measure with both characteristicId and ruleKey are not supported");
-    }
-    if (batchMeasure.hasCharactericId()) {
-      return Measure.newMeasureBuilder().forCharacteristic(batchMeasure.getCharactericId());
-    }
-    if (batchMeasure.hasRuleKey()) {
-      RuleDto ruleDto = ruleCache.get(RuleKey.parse(batchMeasure.getRuleKey()));
-      return Measure.newMeasureBuilder().forRule(ruleDto.getId());
-    }
-    return Measure.newMeasureBuilder();
-  }
-
   private static Optional<Measure> toIntegerMeasure(Measure.NewMeasureBuilder builder, BatchReport.Measure batchMeasure, @Nullable String data) {
     if (!batchMeasure.hasIntValue()) {
       return toNoValueMeasure(builder, batchMeasure);
@@ -113,7 +91,7 @@ public class BatchMeasureToMeasure {
     }
     return of(setCommonProperties(builder, batchMeasure).create(batchMeasure.getStringValue()));
   }
-  
+
   private static Optional<Measure> toLevelMeasure(Measure.NewMeasureBuilder builder, BatchReport.Measure batchMeasure) {
     if (!batchMeasure.hasStringValue()) {
       return toNoValueMeasure(builder, batchMeasure);
@@ -130,14 +108,7 @@ public class BatchMeasureToMeasure {
   }
 
   private static Measure.NewMeasureBuilder setCommonProperties(Measure.NewMeasureBuilder builder, BatchReport.Measure batchMeasure) {
-    if (batchMeasure.hasAlertStatus()) {
-      Optional<Measure.Level> qualityGateStatus = Measure.Level.toLevel(batchMeasure.getAlertStatus());
-      if (qualityGateStatus.isPresent()) {
-        String text = batchMeasure.hasAlertText() ? batchMeasure.getAlertText() : null;
-        builder.setQualityGateStatus(new QualityGateStatus(qualityGateStatus.get(), text));
-      }
-    }
-    if (hasAnyVariation(batchMeasure))  {
+    if (hasAnyVariation(batchMeasure)) {
       builder.setVariations(createVariations(batchMeasure));
     }
     return builder;
@@ -145,20 +116,19 @@ public class BatchMeasureToMeasure {
 
   private static boolean hasAnyVariation(BatchReport.Measure batchMeasure) {
     return batchMeasure.hasVariationValue1()
-        || batchMeasure.hasVariationValue2()
-        || batchMeasure.hasVariationValue3()
-        || batchMeasure.hasVariationValue4()
-        || batchMeasure.hasVariationValue5();
+      || batchMeasure.hasVariationValue2()
+      || batchMeasure.hasVariationValue3()
+      || batchMeasure.hasVariationValue4()
+      || batchMeasure.hasVariationValue5();
   }
 
   private static MeasureVariations createVariations(BatchReport.Measure batchMeasure) {
     return new MeasureVariations(
-        batchMeasure.hasVariationValue1() ? batchMeasure.getVariationValue1() : null,
-        batchMeasure.hasVariationValue2() ? batchMeasure.getVariationValue2() : null,
-        batchMeasure.hasVariationValue3() ? batchMeasure.getVariationValue3() : null,
-        batchMeasure.hasVariationValue4() ? batchMeasure.getVariationValue4() : null,
-        batchMeasure.hasVariationValue5() ? batchMeasure.getVariationValue5() : null
-    );
+      batchMeasure.hasVariationValue1() ? batchMeasure.getVariationValue1() : null,
+      batchMeasure.hasVariationValue2() ? batchMeasure.getVariationValue2() : null,
+      batchMeasure.hasVariationValue3() ? batchMeasure.getVariationValue3() : null,
+      batchMeasure.hasVariationValue4() ? batchMeasure.getVariationValue4() : null,
+      batchMeasure.hasVariationValue5() ? batchMeasure.getVariationValue5() : null);
   }
 
 }
index 26a486c58bdf89d94fbfb6e82f4669c99d09c5cd..8cdb33bcfb51e7619db72901e279ffd6b2aa8c32 100644 (file)
@@ -36,7 +36,6 @@ import org.sonar.core.rule.RuleDto;
 import org.sonar.server.computation.batch.BatchReportReader;
 import org.sonar.server.computation.component.Component;
 import org.sonar.server.computation.debt.Characteristic;
-import org.sonar.server.computation.issue.RuleCache;
 import org.sonar.server.computation.metric.Metric;
 import org.sonar.server.computation.metric.MetricRepository;
 import org.sonar.server.db.DbClient;
@@ -55,10 +54,10 @@ public class MeasureRepositoryImpl implements MeasureRepository {
   private final Map<Integer, Map<MeasureKey, Measure>> measures = new HashMap<>();
 
   public MeasureRepositoryImpl(DbClient dbClient, BatchReportReader reportReader,
-    final MetricRepository metricRepository, final RuleCache ruleCache) {
+    MetricRepository metricRepository) {
     this.dbClient = dbClient;
     this.reportReader = reportReader;
-    this.batchMeasureToMeasure = new BatchMeasureToMeasure(ruleCache);
+    this.batchMeasureToMeasure = new BatchMeasureToMeasure();
     this.metricRepository = metricRepository;
   }
 
index 49643fa299a1f7ce5a9e56437ecddc9298de09e9..bc5d9633880851c4fc5fb215aea0f64edf1f38ff 100644 (file)
@@ -55,6 +55,7 @@ public class ComputationSteps {
       ComputeIssueMeasuresStep.class,
       CustomMeasuresCopyStep.class,
       ComputeFormulaMeasuresStep.class,      
+      CustomMeasuresCopyStep.class,
       SqaleMeasuresStep.class,
       NewCoverageMeasuresStep.class,
       NewCoverageAggregationStep.class,
index b03a1f9559e525186807cd018b348f56dfed2e4d..80e7899eb5eba40021e2bda411ebf3d956b44bb0 100644 (file)
@@ -22,8 +22,6 @@ package org.sonar.server.computation.step;
 
 import com.google.common.base.Function;
 import com.google.common.base.Predicate;
-import com.google.common.base.Predicates;
-import com.google.common.collect.FluentIterable;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
index fed2f288295bd5c535171d4cb706148ebda15cd7..f9c08506ed514fe842d22726b6e1227e73b99fd8 100644 (file)
@@ -23,6 +23,7 @@ import com.google.common.collect.Sets;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import org.sonar.api.utils.log.Loggers;
 import org.sonar.core.issue.DefaultIssue;
 import org.sonar.core.issue.tracking.Tracking;
 import org.sonar.server.computation.component.Component;
@@ -31,11 +32,11 @@ import org.sonar.server.computation.component.TreeRootHolder;
 import org.sonar.server.computation.issue.BaseIssuesLoader;
 import org.sonar.server.computation.issue.IssueCache;
 import org.sonar.server.computation.issue.IssueLifecycle;
-import org.sonar.server.computation.issue.IssueListeners;
+import org.sonar.server.computation.issue.IssueVisitors;
 import org.sonar.server.computation.issue.TrackerExecution;
 import org.sonar.server.util.cache.DiskCache;
 
-import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.POST_ORDER;
+import static org.sonar.server.computation.component.ComponentVisitor.Order.POST_ORDER;
 
 public class IntegrateIssuesStep implements ComputationStep {
 
@@ -44,17 +45,17 @@ public class IntegrateIssuesStep implements ComputationStep {
   private final IssueCache issueCache;
   private final BaseIssuesLoader baseIssuesLoader;
   private final IssueLifecycle issueLifecycle;
-  private final IssueListeners issueListeners;
+  private final IssueVisitors issueVisitors;
 
   public IntegrateIssuesStep(TreeRootHolder treeRootHolder, TrackerExecution tracker, IssueCache issueCache,
     BaseIssuesLoader baseIssuesLoader, IssueLifecycle issueLifecycle,
-    IssueListeners issueListeners) {
+    IssueVisitors issueVisitors) {
     this.treeRootHolder = treeRootHolder;
     this.tracker = tracker;
     this.issueCache = issueCache;
     this.baseIssuesLoader = baseIssuesLoader;
     this.issueLifecycle = issueLifecycle;
-    this.issueListeners = issueListeners;
+    this.issueVisitors = issueVisitors;
   }
 
   @Override
@@ -75,13 +76,15 @@ public class IntegrateIssuesStep implements ComputationStep {
 
   private void processIssues(Component component) {
     Tracking<DefaultIssue, DefaultIssue> tracking = tracker.track(component);
+    Loggers.get(getClass()).info("----- tracking ------");
+    Loggers.get(getClass()).info("" + tracking);
     DiskCache<DefaultIssue>.DiskAppender cacheAppender = issueCache.newAppender();
     try {
-      issueListeners.beforeComponent(component, tracking);
+      issueVisitors.beforeComponent(component, tracking);
       fillNewOpenIssues(component, tracking, cacheAppender);
       fillExistingOpenIssues(component, tracking, cacheAppender);
       closeUnmatchedBaseIssues(component, tracking, cacheAppender);
-      issueListeners.afterComponent(component);
+      issueVisitors.afterComponent(component);
     } finally {
       cacheAppender.close();
     }
@@ -89,42 +92,49 @@ public class IntegrateIssuesStep implements ComputationStep {
 
   private void fillNewOpenIssues(Component component, Tracking<DefaultIssue, DefaultIssue> tracking, DiskCache<DefaultIssue>.DiskAppender cacheAppender) {
     Set<DefaultIssue> issues = tracking.getUnmatchedRaws();
+    Loggers.get(getClass()).info("----- fillNewOpenIssues on " + component.getKey());
     for (DefaultIssue issue : issues) {
       issueLifecycle.initNewOpenIssue(issue);
-      issueListeners.onOpenIssueInitialization(component, issue);
+      Loggers.get(getClass()).info("new " + issue);
       process(component, issue, cacheAppender);
     }
+    Loggers.get(getClass()).info("----- /fillNewOpenIssues on " + component.getKey());
   }
 
   private void fillExistingOpenIssues(Component component, Tracking<DefaultIssue, DefaultIssue> tracking, DiskCache<DefaultIssue>.DiskAppender cacheAppender) {
+    Loggers.get(getClass()).info("----- fillExistingOpenIssues on " + component.getKey());
     for (Map.Entry<DefaultIssue, DefaultIssue> entry : tracking.getMatchedRaws().entrySet()) {
       DefaultIssue raw = entry.getKey();
       DefaultIssue base = entry.getValue();
-      issueListeners.onOpenIssueInitialization(component, raw);
       issueLifecycle.mergeExistingOpenIssue(raw, base);
+      Loggers.get(getClass()).info("merged " + raw);
       process(component, raw, cacheAppender);
     }
     for (Map.Entry<Integer, DefaultIssue> entry : tracking.getOpenManualIssuesByLine().entries()) {
       int line = entry.getKey();
       DefaultIssue manualIssue = entry.getValue();
       manualIssue.setLine(line == 0 ? null : line);
-      issueListeners.onOpenIssueInitialization(component, manualIssue);
+      Loggers.get(getClass()).info("kept manual " + manualIssue);
       process(component, manualIssue, cacheAppender);
     }
+    Loggers.get(getClass()).info("----- /fillExistingOpenIssues on " + component.getKey());
   }
 
   private void closeUnmatchedBaseIssues(Component component, Tracking<DefaultIssue, DefaultIssue> tracking, DiskCache<DefaultIssue>.DiskAppender cacheAppender) {
+    Loggers.get(getClass()).info("----- closeUnmatchedBaseIssues on " + component.getKey());
     for (DefaultIssue issue : tracking.getUnmatchedBases()) {
       // TODO should replace flag "beingClosed" by express call to transition "automaticClose"
       issue.setBeingClosed(true);
+      Loggers.get(getClass()).info("closing " + issue);
       // TODO manual issues -> was updater.setResolution(newIssue, Issue.RESOLUTION_REMOVED, changeContext);. Is it a problem ?
       process(component, issue, cacheAppender);
     }
+    Loggers.get(getClass()).info("----- /closeUnmatchedBaseIssues on " + component.getKey());
   }
 
   private void process(Component component, DefaultIssue issue, DiskCache<DefaultIssue>.DiskAppender cacheAppender) {
     issueLifecycle.doAutomaticTransition(issue);
-    issueListeners.onIssue(component, issue);
+    issueVisitors.onIssue(component, issue);
     cacheAppender.append(issue);
   }
 
@@ -135,8 +145,10 @@ public class IntegrateIssuesStep implements ComputationStep {
         List<DefaultIssue> issues = baseIssuesLoader.loadForComponentUuid(deletedComponentUuid);
         for (DefaultIssue issue : issues) {
           issue.setBeingClosed(true);
+          // FIXME should be renamed "setToRemovedStatus"
+          issue.setOnDisabledRule(true);
           issueLifecycle.doAutomaticTransition(issue);
-          // TODO execute listeners ? Component is currently missing.
+          // TODO execute visitors ? Component is currently missing.
           cacheAppender.append(issue);
         }
       }
index 539d5b6cbc73e37a740717862edece0cb46eb2f7..a5ac16a7477a41ac6d5a9608562b1c5d0ac40b80 100644 (file)
@@ -19,9 +19,9 @@
  */
 package org.sonar.server.computation.step;
 
-import org.sonar.api.issue.Issue;
 import org.sonar.api.issue.IssueComment;
 import org.sonar.api.utils.System2;
+import org.sonar.api.utils.log.Loggers;
 import org.sonar.core.issue.DefaultIssue;
 import org.sonar.core.issue.DefaultIssueComment;
 import org.sonar.core.issue.FieldDiffs;
@@ -67,22 +67,24 @@ public class PersistIssuesStep implements ComputationStep {
         boolean saved = false;
         if (issue.isNew()) {
           Integer ruleId = ruleCache.get(issue.ruleKey()).getId();
-          mapper.insert(IssueDto.toDtoForComputationInsert(issue, ruleId, system2.now()));
+          IssueDto dto = IssueDto.toDtoForComputationInsert(issue, ruleId, system2.now());
+          Loggers.get(getClass()).info("---- INSERT " + dto);
+          mapper.insert(dto);
           saved = true;
         } else if (issue.isChanged()) {
           IssueDto dto = IssueDto.toDtoForUpdate(issue, system2.now());
-          if (Issue.STATUS_CLOSED.equals(issue.status()) || issue.selectedAt() == null) {
-            // Issue is closed by scan or changed by end-user
-            mapper.update(dto);
-          } else {
-            int updateCount = mapper.updateIfBeforeSelectedDate(dto);
-            if (updateCount == 0) {
-              // End-user and scan changed the issue at the same time.
-              // See https://jira.sonarsource.com/browse/SONAR-4309
-              conflictResolver.resolve(issue, mapper);
-            }
+          Loggers.get(getClass()).info("---- UPDATE " + dto);
+          int updateCount = mapper.updateIfBeforeSelectedDate(dto);
+          if (updateCount == 0) {
+            Loggers.get(getClass()).info("---- CONFLICT: " + updateCount);
+            // End-user and scan changed the issue at the same time.
+            // See https://jira.sonarsource.com/browse/SONAR-4309
+            conflictResolver.resolve(issue, mapper);
           }
+
           saved = true;
+        } else {
+          Loggers.get(getClass()).info("---- UNCHANGED "  + issue);
         }
         if (saved) {
           insertChanges(changeMapper, issue);
index 4e78181f4c52982c6129aec6bf2897b346c020f9..c1d8f0e60027a78f43c4a5d106b27e176687303c 100644 (file)
@@ -27,6 +27,7 @@ import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
+import java.util.List;
 import javax.annotation.CheckForNull;
 import org.apache.commons.dbutils.DbUtils;
 import org.apache.commons.io.IOUtils;
@@ -69,7 +70,7 @@ public class FileSourceDao implements DaoComponent {
   }
 
   @CheckForNull
-  public Iterable<String> selectLineHashes(DbSession dbSession, String fileUuid) {
+  public List<String> selectLineHashes(DbSession dbSession, String fileUuid) {
     Connection connection = dbSession.getConnection();
     PreparedStatement pstmt = null;
     ResultSet rs = null;
@@ -79,7 +80,7 @@ public class FileSourceDao implements DaoComponent {
       pstmt.setString(2, Type.SOURCE);
       rs = pstmt.executeQuery();
       if (rs.next()) {
-        return END_OF_LINE_SPLITTER.split(rs.getString(1));
+        return END_OF_LINE_SPLITTER.splitToList(rs.getString(1));
       }
       return null;
     } catch (SQLException e) {
index 55a984af894ec6e2785fe3517b5a04f91d81971c..c1deba159212a1b38cd2d721d1972cc3a1606222 100644 (file)
@@ -41,7 +41,7 @@ public class CharacteristicTest {
 
   @Test
   public void test_to_string() throws Exception {
-    assertThat(new Characteristic(1, "PORTABILITY", null).toString()).isEqualTo("Characteristic{id=1, key='PORTABILITY'}");
+    assertThat(new Characteristic(1, "PORTABILITY", null).toString()).isEqualTo("Characteristic{id=1, key='PORTABILITY', parentId=null}");
   }
 
   @Test
index df3a0e6be993bfa3a1ea8674431b29d351fdfa1e..a9172d9842e9ba457ce1cbb049f16a800d05fd74 100644 (file)
@@ -1,3 +1,22 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
 ///*
 // * SonarQube, open source software quality management tool.
 // * Copyright (C) 2008-2014 SonarSource
index 56b65390a89506bae0de3b4c496b79fda0ae84d6..5a7fa451ba48f583449399760a0d146219ea239d 100644 (file)
@@ -107,15 +107,14 @@ public class CountIssuesListenerTest {
   Tracking tracking = mock(Tracking.class);
   MetricRepository metricRepository = mock(MetricRepository.class);
   MeasureRepository measureRepository;
-  RuleCache ruleCache = mock(RuleCache.class);
-  CountIssuesListener sut;
+  IssueCounter sut;
 
   @Before
   public void setUp() throws Exception {
     initMetrics();
-    measureRepository = new MeasureRepositoryImpl(null, reportReader, metricRepository, ruleCache);
+    measureRepository = new MeasureRepositoryImpl(null, reportReader, metricRepository);
 
-    sut = new CountIssuesListener(periodsHolder, metricRepository, measureRepository);
+    sut = new IssueCounter(periodsHolder, metricRepository, measureRepository);
   }
 
   @Test
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/issue/NewDebtAggregatorTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/issue/NewDebtAggregatorTest.java
new file mode 100644 (file)
index 0000000..17c4dc0
--- /dev/null
@@ -0,0 +1,367 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+//package org.sonar.server.computation.issue;
+//
+//import java.util.Date;
+//import org.apache.commons.lang.ObjectUtils;
+//import org.apache.commons.lang.time.DateUtils;
+//import org.junit.Before;
+//import org.junit.Test;
+//import org.mockito.ArgumentMatcher;
+//import org.mockito.Mock;
+//import org.sonar.api.CoreProperties;
+//import org.sonar.api.batch.DecoratorContext;
+//import org.sonar.api.component.ResourcePerspectives;
+//import org.sonar.api.config.Settings;
+//import org.sonar.api.issue.Issuable;
+//import org.sonar.api.issue.Issue;
+//import org.sonar.api.measures.CoreMetrics;
+//import org.sonar.api.measures.Measure;
+//import org.sonar.api.measures.Metric;
+//import org.sonar.api.resources.Resource;
+//import org.sonar.api.utils.Duration;
+//import org.sonar.core.issue.DefaultIssue;
+//import org.sonar.core.issue.FieldDiffs;
+//
+//import static com.google.common.collect.Lists.newArrayList;
+//import static org.assertj.core.api.Assertions.assertThat;
+//import static org.mockito.Matchers.argThat;
+//import static org.mockito.Mockito.mock;
+//import static org.mockito.Mockito.never;
+//import static org.mockito.Mockito.verify;
+//import static org.mockito.Mockito.when;
+//
+//public class NewDebtAggregatorTest {
+//  NewDebtDecorator decorator;
+//
+//  @Mock
+//  TimeMachineConfiguration timeMachineConfiguration;
+//
+//  @Mock
+//  Resource resource;
+//
+//  @Mock
+//  Issuable issuable;
+//
+//  @Mock
+//  DecoratorContext context;
+//
+//  Date rightNow;
+//  Date elevenDaysAgo;
+//  Date tenDaysAgo;
+//  Date nineDaysAgo;
+//  Date fiveDaysAgo;
+//  Date fourDaysAgo;
+//
+//  static final int HOURS_IN_DAY = 8;
+//
+//  static final Long ONE_DAY_IN_MINUTES = 1L * HOURS_IN_DAY * 60;
+//  static final Long TWO_DAYS_IN_MINUTES = 2L * HOURS_IN_DAY * 60;
+//  static final Long FIVE_DAYS_IN_MINUTES = 5L * HOURS_IN_DAY * 60;
+//
+//  @Before
+//  public void setup() {
+//    Settings settings = new Settings();
+//    settings.setProperty(CoreProperties.HOURS_IN_DAY, HOURS_IN_DAY);
+//
+//    ResourcePerspectives perspectives = mock(ResourcePerspectives.class);
+//    when(perspectives.as(Issuable.class, resource)).thenReturn(issuable);
+//
+//    rightNow = new Date();
+//    elevenDaysAgo = DateUtils.addDays(rightNow, -11);
+//    tenDaysAgo = DateUtils.addDays(rightNow, -10);
+//    nineDaysAgo = DateUtils.addDays(rightNow, -9);
+//    fiveDaysAgo = DateUtils.addDays(rightNow, -5);
+//    fourDaysAgo = DateUtils.addDays(rightNow, -4);
+//
+//    when(timeMachineConfiguration.periods()).thenReturn(newArrayList(new Period(1, fiveDaysAgo), new Period(2, tenDaysAgo)));
+//
+//    decorator = new NewDebtDecorator(perspectives, timeMachineConfiguration, new IssueChangelogDebtCalculator());
+//  }
+//
+//  @Test
+//  public void generates_metrics() {
+//    assertThat(decorator.generatesMetrics()).hasSize(1);
+//  }
+//
+//  @Test
+//  public void execute_on_project() {
+//    assertThat(decorator.shouldExecuteOnProject(null)).isTrue();
+//  }
+//
+//  @Test
+//  public void save_on_one_issue_with_one_new_changelog() {
+//    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(TWO_DAYS_IN_MINUTES)).setChanges(
+//      newArrayList(
+//        // changelog created at is null because it has just been created on the current analysis
+//        new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, TWO_DAYS_IN_MINUTES).setCreationDate(null)
+//      )
+//    );
+//    when(issuable.issues()).thenReturn(newArrayList(issue));
+//
+//    decorator.decorate(resource, context);
+//
+//    // remember : period1 is 5daysAgo, period2 is 10daysAgo
+//    verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 1.0 * ONE_DAY_IN_MINUTES, 1.0 * ONE_DAY_IN_MINUTES)));
+//  }
+//
+//  @Test
+//  public void save_on_one_issue_with_changelog() {
+//    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)).setChanges(
+//      newArrayList(
+//        new FieldDiffs().setDiff("technicalDebt", TWO_DAYS_IN_MINUTES, FIVE_DAYS_IN_MINUTES).setCreationDate(null),
+//        new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, TWO_DAYS_IN_MINUTES).setCreationDate(fourDaysAgo)
+//      )
+//    );
+//    when(issuable.issues()).thenReturn(newArrayList(issue));
+//
+//    decorator.decorate(resource, context);
+//
+//    // remember : period1 is 5daysAgo, period2 is 10daysAgo
+//    verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 4.0 * ONE_DAY_IN_MINUTES, 4.0 * ONE_DAY_IN_MINUTES)));
+//  }
+//
+//  @Test
+//  public void save_on_one_issue_with_changelog_only_in_the_past() {
+//    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(ONE_DAY_IN_MINUTES)).setChanges(
+//      newArrayList(
+//        // Change before all periods
+//        new FieldDiffs().setDiff("technicalDebt", null, ONE_DAY_IN_MINUTES).setCreationDate(elevenDaysAgo)
+//      )
+//    );
+//    when(issuable.issues()).thenReturn(newArrayList(issue));
+//
+//    decorator.decorate(resource, context);
+//
+//    // remember : period1 is 5daysAgo, period2 is 10daysAgo
+//    verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0, 0.0)));
+//  }
+//
+//  @Test
+//  public void save_on_one_issue_with_changelog_having_null_value() {
+//    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)).setChanges(
+//      newArrayList(
+//        new FieldDiffs().setDiff("technicalDebt", null, FIVE_DAYS_IN_MINUTES).setCreationDate(null),
+//        new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, null).setCreationDate(fourDaysAgo),
+//        new FieldDiffs().setDiff("technicalDebt", null, ONE_DAY_IN_MINUTES).setCreationDate(nineDaysAgo)
+//      )
+//    );
+//    when(issuable.issues()).thenReturn(newArrayList(issue));
+//
+//    decorator.decorate(resource, context);
+//
+//    // remember : period1 is 5daysAgo, period2 is 10daysAgo
+//    verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 4.0 * ONE_DAY_IN_MINUTES, 5.0 * ONE_DAY_IN_MINUTES)));
+//  }
+//
+//  @Test
+//  public void save_on_one_issue_with_changelog_and_periods_have_no_dates() {
+//    when(timeMachineConfiguration.periods()).thenReturn(newArrayList(new Period(1, null), new Period(2, null)));
+//
+//    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)).setChanges(
+//      newArrayList(
+//        new FieldDiffs().setDiff("technicalDebt", null, FIVE_DAYS_IN_MINUTES).setCreationDate(null),
+//        new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, null).setCreationDate(fourDaysAgo),
+//        new FieldDiffs().setDiff("technicalDebt", null, ONE_DAY_IN_MINUTES).setCreationDate(nineDaysAgo)
+//      )
+//    );
+//    when(issuable.issues()).thenReturn(newArrayList(issue));
+//
+//    decorator.decorate(resource, context);
+//
+//    // remember : period1 is 5daysAgo, period2 is 10daysAgo
+//    verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 5.0 * ONE_DAY_IN_MINUTES, 5.0 * ONE_DAY_IN_MINUTES)));
+//  }
+//
+//  @Test
+//  public void save_on_one_issue_with_changelog_having_not_only_technical_debt_changes() {
+//    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)).setChanges(
+//      newArrayList(
+//        new FieldDiffs()
+//          .setDiff("actionPlan", "1.0", "1.1").setCreationDate(fourDaysAgo)
+//          .setDiff("technicalDebt", ONE_DAY_IN_MINUTES, TWO_DAYS_IN_MINUTES).setCreationDate(fourDaysAgo)
+//      )
+//    );
+//    when(issuable.issues()).thenReturn(newArrayList(issue));
+//
+//    decorator.decorate(resource, context);
+//
+//    // remember : period1 is 5daysAgo, period2 is 10daysAgo
+//    verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 4.0 * ONE_DAY_IN_MINUTES, 4.0 * ONE_DAY_IN_MINUTES)));
+//  }
+//
+//  @Test
+//  public void save_on_issues_with_changelog() {
+//    Issue issue1 = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)).setChanges(
+//      newArrayList(
+//        new FieldDiffs().setDiff("technicalDebt", TWO_DAYS_IN_MINUTES, FIVE_DAYS_IN_MINUTES).setCreationDate(rightNow),
+//        new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, TWO_DAYS_IN_MINUTES).setCreationDate(fourDaysAgo),
+//        new FieldDiffs().setDiff("technicalDebt", null, ONE_DAY_IN_MINUTES).setCreationDate(nineDaysAgo)
+//      )
+//    );
+//    Issue issue2 = new DefaultIssue().setKey("B").setCreationDate(tenDaysAgo).setDebt(Duration.create(TWO_DAYS_IN_MINUTES)).setChanges(
+//      newArrayList(
+//        new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, TWO_DAYS_IN_MINUTES).setCreationDate(rightNow),
+//        new FieldDiffs().setDiff("technicalDebt", null, ONE_DAY_IN_MINUTES).setCreationDate(nineDaysAgo)
+//      )
+//    );
+//    when(issuable.issues()).thenReturn(newArrayList(issue1, issue2));
+//
+//    decorator.decorate(resource, context);
+//
+//    // remember : period1 is 5daysAgo, period2 is 10daysAgo
+//    verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 5.0 * ONE_DAY_IN_MINUTES, 7.0 * ONE_DAY_IN_MINUTES)));
+//  }
+//
+//  @Test
+//  public void save_on_one_issue_without_changelog() {
+//    when(issuable.issues()).thenReturn(newArrayList(
+//        (Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)))
+//    );
+//
+//    decorator.decorate(resource, context);
+//
+//    // remember : period1 is 5daysAgo, period2 is 10daysAgo
+//    verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0, 5.0 * ONE_DAY_IN_MINUTES)));
+//  }
+//
+//  @Test
+//  public void save_on_one_issue_without_technical_debt_and_without_changelog() {
+//    when(issuable.issues()).thenReturn(newArrayList(
+//        (Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setDebt(null))
+//    );
+//
+//    decorator.decorate(resource, context);
+//
+//    // remember : period1 is 5daysAgo, period2 is 10daysAgo
+//    verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0, 0.0)));
+//  }
+//
+//  @Test
+//  public void save_on_one_issue_without_changelog_and_periods_have_no_dates() {
+//    when(timeMachineConfiguration.periods()).thenReturn(newArrayList(new Period(1, null), new Period(2, null)));
+//
+//    when(issuable.issues()).thenReturn(newArrayList(
+//        (Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)))
+//    );
+//
+//    decorator.decorate(resource, context);
+//
+//    // remember : period1 is null, period2 is null
+//    verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 5.0 * ONE_DAY_IN_MINUTES, 5.0 * ONE_DAY_IN_MINUTES)));
+//  }
+//
+//  @Test
+//  public void save_on_issues_without_changelog() {
+//    when(issuable.issues()).thenReturn(newArrayList(
+//      (Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)),
+//      new DefaultIssue().setKey("B").setCreationDate(fiveDaysAgo).setDebt(Duration.create(TWO_DAYS_IN_MINUTES))
+//    ));
+//
+//    decorator.decorate(resource, context);
+//
+//    // remember : period1 is 5daysAgo, period2 is 10daysAgo
+//    verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0, 7.0 * ONE_DAY_IN_MINUTES)));
+//  }
+//
+//  @Test
+//  public void save_on_issues_with_changelog_and_issues_without_changelog() {
+//    // issue1 and issue2 have changelog
+//    Issue issue1 = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)).setChanges(
+//      newArrayList(
+//        new FieldDiffs().setDiff("technicalDebt", TWO_DAYS_IN_MINUTES, FIVE_DAYS_IN_MINUTES).setCreationDate(rightNow),
+//        new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, TWO_DAYS_IN_MINUTES).setCreationDate(fourDaysAgo),
+//        new FieldDiffs().setDiff("technicalDebt", null, ONE_DAY_IN_MINUTES).setCreationDate(nineDaysAgo)
+//      )
+//    );
+//    Issue issue2 = new DefaultIssue().setKey("B").setCreationDate(tenDaysAgo).setDebt(Duration.create(TWO_DAYS_IN_MINUTES)).setChanges(
+//      newArrayList(
+//        new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, TWO_DAYS_IN_MINUTES).setCreationDate(rightNow),
+//        new FieldDiffs().setDiff("technicalDebt", null, ONE_DAY_IN_MINUTES).setCreationDate(nineDaysAgo)
+//      )
+//    );
+//
+//    // issue3 and issue4 have no changelog
+//    Issue issue3 = new DefaultIssue().setKey("C").setCreationDate(nineDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES));
+//    Issue issue4 = new DefaultIssue().setKey("D").setCreationDate(fiveDaysAgo).setDebt(Duration.create(TWO_DAYS_IN_MINUTES));
+//    when(issuable.issues()).thenReturn(newArrayList(issue1, issue2, issue3, issue4));
+//
+//    decorator.decorate(resource, context);
+//
+//    // remember : period1 is 5daysAgo, period2 is 10daysAgo
+//    verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 5.0 * ONE_DAY_IN_MINUTES, 14.0 * ONE_DAY_IN_MINUTES)));
+//  }
+//
+//  @Test
+//  public void not_save_if_measure_already_computed() {
+//    when(context.getMeasure(CoreMetrics.NEW_TECHNICAL_DEBT)).thenReturn(new Measure());
+//    when(issuable.issues()).thenReturn(newArrayList(
+//      (Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)),
+//      new DefaultIssue().setKey("B").setCreationDate(fiveDaysAgo).setDebt(Duration.create(TWO_DAYS_IN_MINUTES))
+//    ));
+//
+//    decorator.decorate(resource, context);
+//
+//    verify(context, never()).saveMeasure(argThat(new IsMeasure(CoreMetrics.NEW_TECHNICAL_DEBT)));
+//  }
+//
+//  /**
+//   * SONAR-5059
+//   */
+//  @Test
+//  public void not_return_negative_debt() {
+//    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(ONE_DAY_IN_MINUTES)).setChanges(
+//      newArrayList(
+//        // changelog created at is null because it has just been created on the current analysis
+//        new FieldDiffs().setDiff("technicalDebt", TWO_DAYS_IN_MINUTES, ONE_DAY_IN_MINUTES).setCreationDate(null)
+//      )
+//    );
+//    when(issuable.issues()).thenReturn(newArrayList(issue));
+//
+//    decorator.decorate(resource, context);
+//
+//    // remember : period1 is 5daysAgo, period2 is 10daysAgo
+//    verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0, 0.0)));
+//  }
+//
+//
+//  class IsVariationMeasure extends ArgumentMatcher<Measure> {
+//    Metric metric = null;
+//    Double var1 = null;
+//    Double var2 = null;
+//
+//    public IsVariationMeasure(Metric metric, Double var1, Double var2) {
+//      this.metric = metric;
+//      this.var1 = var1;
+//      this.var2 = var2;
+//    }
+//
+//    public boolean matches(Object o) {
+//      if (!(o instanceof Measure)) {
+//        return false;
+//      }
+//      Measure m = (Measure) o;
+//      return ObjectUtils.equals(metric, m.getMetric()) &&
+//        ObjectUtils.equals(var1, m.getVariation1()) &&
+//        ObjectUtils.equals(var2, m.getVariation2());
+//    }
+//  }
+//
+//}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/issue/NewDebtCalculatorTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/issue/NewDebtCalculatorTest.java
new file mode 100644 (file)
index 0000000..bfbcb7a
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+//package org.sonar.server.computation.issue;
+//
+//import java.util.Date;
+//import org.apache.commons.lang.time.DateUtils;
+//import org.junit.Before;
+//import org.junit.Test;
+//import org.sonar.api.issue.Issue;
+//import org.sonar.api.utils.Duration;
+//import org.sonar.core.issue.DefaultIssue;
+//import org.sonar.core.issue.FieldDiffs;
+//
+//import static com.google.common.collect.Lists.newArrayList;
+//import static org.assertj.core.api.Assertions.assertThat;
+//
+//public class NewDebtCalculatorTest {
+//  private static final int HOURS_IN_DAY = 8;
+//
+//  IssueChangelogDebtCalculator issueChangelogDebtCalculator;
+//
+//  Date rightNow = new Date();
+//  Date elevenDaysAgo = DateUtils.addDays(rightNow, -11);
+//  Date tenDaysAgo = DateUtils.addDays(rightNow, -10);
+//  Date nineDaysAgo = DateUtils.addDays(rightNow, -9);
+//  Date fiveDaysAgo = DateUtils.addDays(rightNow, -5);
+//  Date fourDaysAgo = DateUtils.addDays(rightNow, -4);
+//
+//  long oneDay = 1 * HOURS_IN_DAY * 60 * 60L;
+//  long twoDays = 2 * HOURS_IN_DAY * 60 * 60L;
+//  long fiveDays = 5 * HOURS_IN_DAY * 60 * 60L;
+//
+//  Duration oneDayDebt = Duration.create(oneDay);
+//  Duration twoDaysDebt = Duration.create(twoDays);
+//  Duration fiveDaysDebt = Duration.create(fiveDays);
+//
+//  @Before
+//  public void setUp() {
+//    issueChangelogDebtCalculator = new IssueChangelogDebtCalculator();
+//  }
+//
+//  @Test
+//  public void calculate_new_technical_debt_with_one_diff_in_changelog() {
+//    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(twoDaysDebt).setChanges(
+//      newArrayList(
+//        // changelog created at is null because it has just been created on the current analysis
+//        new FieldDiffs().setDiff("technicalDebt", oneDay, twoDays).setCreationDate(null)
+//      )
+//    );
+//
+//    assertThat(issueChangelogDebtCalculator.calculateNewTechnicalDebt(issue, rightNow)).isEqualTo(oneDay);
+//    assertThat(issueChangelogDebtCalculator.calculateNewTechnicalDebt(issue, fiveDaysAgo)).isEqualTo(oneDay);
+//
+//    assertThat(issueChangelogDebtCalculator.calculateNewTechnicalDebt(issue, elevenDaysAgo)).isEqualTo(twoDays);
+//  }
+//
+//  @Test
+//  public void calculate_new_technical_debt_with_many_diffs_in_changelog() {
+//    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(fiveDaysDebt).setChanges(
+//      newArrayList(
+//        new FieldDiffs().setDiff("technicalDebt", twoDays, fiveDays).setCreationDate(null),
+//        new FieldDiffs().setDiff("technicalDebt", oneDay, twoDays).setCreationDate(fourDaysAgo)
+//      )
+//    );
+//
+//    assertThat(issueChangelogDebtCalculator.calculateNewTechnicalDebt(issue, rightNow)).isEqualTo(3 * oneDay);
+//    assertThat(issueChangelogDebtCalculator.calculateNewTechnicalDebt(issue, fiveDaysAgo)).isEqualTo(4 * oneDay);
+//    assertThat(issueChangelogDebtCalculator.calculateNewTechnicalDebt(issue, elevenDaysAgo)).isEqualTo(5 * oneDay);
+//  }
+//
+//  @Test
+//  public void changelog_can_be_in_wrong_order() {
+//    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(fiveDaysDebt).setChanges(
+//      newArrayList(
+//        // 3rd
+//        new FieldDiffs().setDiff("technicalDebt", null, oneDay).setCreationDate(nineDaysAgo),
+//        // 1st
+//        new FieldDiffs().setDiff("technicalDebt", twoDays, fiveDays).setCreationDate(rightNow),
+//        // 2nd
+//        new FieldDiffs().setDiff("technicalDebt", oneDay, twoDays).setCreationDate(fourDaysAgo)
+//      )
+//    );
+//
+//    assertThat(issueChangelogDebtCalculator.calculateNewTechnicalDebt(issue, fiveDaysAgo)).isEqualTo(4 * oneDay);
+//    assertThat(issueChangelogDebtCalculator.calculateNewTechnicalDebt(issue, elevenDaysAgo)).isEqualTo(5 * oneDay);
+//  }
+//
+//  @Test
+//  public void calculate_new_technical_debt_with_null_date() {
+//    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(twoDaysDebt).setChanges(
+//      newArrayList(
+//        new FieldDiffs().setDiff("technicalDebt", oneDay, twoDays).setCreationDate(null)
+//      )
+//    );
+//
+//    assertThat(issueChangelogDebtCalculator.calculateNewTechnicalDebt(issue, null)).isEqualTo(2 * oneDay);
+//  }
+//
+//  @Test
+//  public void calculate_new_technical_debt_when_new_debt_is_null() {
+//    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(null).setChanges(
+//      newArrayList(
+//        new FieldDiffs().setDiff("technicalDebt", oneDay, null).setCreationDate(null),
+//        new FieldDiffs().setDiff("technicalDebt", null, oneDay).setCreationDate(nineDaysAgo)
+//      )
+//    );
+//
+//    assertThat(issueChangelogDebtCalculator.calculateNewTechnicalDebt(issue, rightNow)).isNull();
+//  }
+//
+//  @Test
+//  public void calculate_new_technical_debt_on_issue_without_technical_debt_and_without_changelog() {
+//    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo);
+//
+//    assertThat(issueChangelogDebtCalculator.calculateNewTechnicalDebt(issue, rightNow)).isNull();
+//  }
+//
+//  @Test
+//  public void not_return_negative_debt() {
+//    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(oneDayDebt).setChanges(
+//      newArrayList(
+//        new FieldDiffs().setDiff("technicalDebt", twoDays, oneDay).setCreationDate(null)
+//      )
+//    );
+//
+//    assertThat(issueChangelogDebtCalculator.calculateNewTechnicalDebt(issue, rightNow)).isNull();
+//  }
+//
+//}
index fbf88dbdf0d578b44cf256d133b09f4055dc0864..c00155eb02f7e4628f2bc7cf440af76e3a8b98fc 100644 (file)
@@ -23,20 +23,14 @@ import com.google.common.base.Optional;
 import com.tngtech.java.junit.dataprovider.DataProvider;
 import com.tngtech.java.junit.dataprovider.DataProviderRunner;
 import com.tngtech.java.junit.dataprovider.UseDataProvider;
-import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.sonar.api.rule.RuleKey;
 import org.sonar.batch.protocol.output.BatchReport;
-import org.sonar.core.rule.RuleDto;
-import org.sonar.server.computation.issue.RuleCache;
 import org.sonar.server.computation.metric.Metric;
 import org.sonar.server.computation.metric.MetricImpl;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.guava.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
 
 @RunWith(DataProviderRunner.class)
 public class BatchMeasureToMeasureTest {
@@ -48,19 +42,9 @@ public class BatchMeasureToMeasureTest {
   private static final Metric SOME_LEVEL_METRIC = new MetricImpl(42, "level", "name", Metric.MetricType.LEVEL);
 
   private static final String SOME_DATA = "some_data man!";
-  private static final String SOME_ALERT_TEXT = "some alert text_be_careFul!";
   private static final BatchReport.Measure EMPTY_BATCH_MEASURE = BatchReport.Measure.newBuilder().build();
-  private static final RuleKey SOME_RULE_KEY = RuleKey.of("A", "B");
-  private static final int SOME_RULE_ID = 9513;
-  private static final RuleDto SOME_RULE = new RuleDto().setRuleKey(SOME_RULE_KEY.toString()).setId(SOME_RULE_ID);
 
-  private RuleCache ruleCache = mock(RuleCache.class);
-  private BatchMeasureToMeasure underTest = new BatchMeasureToMeasure(ruleCache);
-
-  @Before
-  public void setUp() throws Exception {
-    when(ruleCache.get(SOME_RULE_KEY)).thenReturn(SOME_RULE);
-  }
+  private BatchMeasureToMeasure underTest = new BatchMeasureToMeasure();
 
   @Test
   public void toMeasure_returns_absent_for_null_argument() {
@@ -77,25 +61,6 @@ public class BatchMeasureToMeasureTest {
     underTest.toMeasure(null, null);
   }
 
-  @Test(expected = IllegalArgumentException.class)
-  public void toMeasure_throws_IAE_if_batch_Measure_has_both_ruleKey_and_characteristicId() {
-    underTest.toMeasure(BatchReport.Measure.newBuilder().setRuleKey(SOME_RULE_KEY.toString()).setCharactericId(42).build(), SOME_STRING_METRIC);
-  }
-
-  @Test
-  public void toMeasure_maps_characteristicId_if_present() {
-    BatchReport.Measure batchMeasure = BatchReport.Measure.newBuilder().setCharactericId(42).build();
-
-    assertThat(underTest.toMeasure(batchMeasure, SOME_STRING_METRIC).get().getCharacteristicId()).isEqualTo(42);
-  }
-
-  @Test
-  public void toMeasure_maps_ruleKey_if_present() {
-    BatchReport.Measure batchMeasure = BatchReport.Measure.newBuilder().setRuleKey(SOME_RULE_KEY.toString()).build();
-
-    assertThat(underTest.toMeasure(batchMeasure, SOME_STRING_METRIC).get().getRuleId()).isEqualTo(SOME_RULE_ID);
-  }
-
   @Test
   public void toMeasure_returns_no_value_if_dto_has_no_string_value_for_LEVEL_Metric() {
     Optional<Measure> measure = underTest.toMeasure(EMPTY_BATCH_MEASURE, SOME_LEVEL_METRIC);
@@ -138,8 +103,6 @@ public class BatchMeasureToMeasureTest {
   public void toMeasure_for_LEVEL_Metric_maps_QualityGateStatus() {
     BatchReport.Measure batchMeasure = BatchReport.Measure.newBuilder()
       .setStringValue(Measure.Level.OK.name())
-      .setAlertStatus(Measure.Level.ERROR.name())
-      .setAlertText(SOME_ALERT_TEXT)
       .build();
 
     Optional<Measure> measure = underTest.toMeasure(batchMeasure, SOME_LEVEL_METRIC);
@@ -147,8 +110,6 @@ public class BatchMeasureToMeasureTest {
     assertThat(measure).isPresent();
     assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.LEVEL);
     assertThat(measure.get().getLevelValue()).isEqualTo(Measure.Level.OK);
-    assertThat(measure.get().getQualityGateStatus().getStatus()).isEqualTo(Measure.Level.ERROR);
-    assertThat(measure.get().getQualityGateStatus().getText()).isEqualTo(SOME_ALERT_TEXT);
   }
 
   @Test
@@ -182,7 +143,6 @@ public class BatchMeasureToMeasureTest {
     BatchReport.Measure batchMeasure = BatchReport.Measure.newBuilder()
       .setIntValue(10)
       .setStringValue(SOME_DATA)
-      .setAlertStatus(Measure.Level.OK.name()).setAlertText(SOME_ALERT_TEXT)
       .build();
 
     Optional<Measure> measure = underTest.toMeasure(batchMeasure, SOME_INT_METRIC);
@@ -191,8 +151,6 @@ public class BatchMeasureToMeasureTest {
     assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.INT);
     assertThat(measure.get().getIntValue()).isEqualTo(10);
     assertThat(measure.get().getData()).isEqualTo(SOME_DATA);
-    assertThat(measure.get().getQualityGateStatus().getStatus()).isEqualTo(Measure.Level.OK);
-    assertThat(measure.get().getQualityGateStatus().getText()).isEqualTo(SOME_ALERT_TEXT);
   }
 
   @Test
@@ -217,7 +175,6 @@ public class BatchMeasureToMeasureTest {
     BatchReport.Measure batchMeasure = BatchReport.Measure.newBuilder()
       .setLongValue(10l)
       .setStringValue(SOME_DATA)
-      .setAlertStatus(Measure.Level.OK.name()).setAlertText(SOME_ALERT_TEXT)
       .build();
 
     Optional<Measure> measure = underTest.toMeasure(batchMeasure, SOME_LONG_METRIC);
@@ -226,8 +183,6 @@ public class BatchMeasureToMeasureTest {
     assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.LONG);
     assertThat(measure.get().getLongValue()).isEqualTo(10);
     assertThat(measure.get().getData()).isEqualTo(SOME_DATA);
-    assertThat(measure.get().getQualityGateStatus().getStatus()).isEqualTo(Measure.Level.OK);
-    assertThat(measure.get().getQualityGateStatus().getText()).isEqualTo(SOME_ALERT_TEXT);
   }
 
   @Test
@@ -243,7 +198,6 @@ public class BatchMeasureToMeasureTest {
     BatchReport.Measure batchMeasure = BatchReport.Measure.newBuilder()
       .setDoubleValue(10.6395d)
       .setStringValue(SOME_DATA)
-      .setAlertStatus(Measure.Level.OK.name()).setAlertText(SOME_ALERT_TEXT)
       .build();
 
     Optional<Measure> measure = underTest.toMeasure(batchMeasure, SOME_DOUBLE_METRIC);
@@ -252,8 +206,6 @@ public class BatchMeasureToMeasureTest {
     assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.DOUBLE);
     assertThat(measure.get().getDoubleValue()).isEqualTo(10.6d);
     assertThat(measure.get().getData()).isEqualTo(SOME_DATA);
-    assertThat(measure.get().getQualityGateStatus().getStatus()).isEqualTo(Measure.Level.OK);
-    assertThat(measure.get().getQualityGateStatus().getText()).isEqualTo(SOME_ALERT_TEXT);
   }
 
   @Test
@@ -281,7 +233,7 @@ public class BatchMeasureToMeasureTest {
   @Test
   public void toMeasure_maps_data_and_alert_properties_in_dto_for_Boolean_metric() {
     BatchReport.Measure batchMeasure = BatchReport.Measure.newBuilder()
-      .setBooleanValue(true).setStringValue(SOME_DATA).setAlertStatus(Measure.Level.OK.name()).setAlertText(SOME_ALERT_TEXT).build();
+      .setBooleanValue(true).setStringValue(SOME_DATA).build();
 
     Optional<Measure> measure = underTest.toMeasure(batchMeasure, SOME_BOOLEAN_METRIC);
 
@@ -289,8 +241,6 @@ public class BatchMeasureToMeasureTest {
     assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.BOOLEAN);
     assertThat(measure.get().getBooleanValue()).isTrue();
     assertThat(measure.get().getData()).isEqualTo(SOME_DATA);
-    assertThat(measure.get().getQualityGateStatus().getStatus()).isEqualTo(Measure.Level.OK);
-    assertThat(measure.get().getQualityGateStatus().getText()).isEqualTo(SOME_ALERT_TEXT);
   }
 
   @Test
@@ -305,7 +255,6 @@ public class BatchMeasureToMeasureTest {
   public void toMeasure_maps_alert_properties_in_dto_for_String_Metric() {
     BatchReport.Measure batchMeasure = BatchReport.Measure.newBuilder()
       .setStringValue(SOME_DATA)
-      .setAlertStatus(Measure.Level.OK.name()).setAlertText(SOME_ALERT_TEXT)
       .build();
 
     Optional<Measure> measure = underTest.toMeasure(batchMeasure, SOME_STRING_METRIC);
@@ -314,8 +263,6 @@ public class BatchMeasureToMeasureTest {
     assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.STRING);
     assertThat(measure.get().getStringValue()).isEqualTo(SOME_DATA);
     assertThat(measure.get().getData()).isEqualTo(SOME_DATA);
-    assertThat(measure.get().getQualityGateStatus().getStatus()).isEqualTo(Measure.Level.OK);
-    assertThat(measure.get().getQualityGateStatus().getText()).isEqualTo(SOME_ALERT_TEXT);
   }
 
   @DataProvider
index 22f1a271827c2b243969a0981405fccbff87cfbd..67d0a10e685dee4ef94cc47a57b7e31c5bf54590 100644 (file)
@@ -49,7 +49,6 @@ import org.sonar.server.computation.batch.BatchReportReaderRule;
 import org.sonar.server.computation.component.Component;
 import org.sonar.server.computation.component.DumbComponent;
 import org.sonar.server.computation.debt.Characteristic;
-import org.sonar.server.computation.issue.RuleCache;
 import org.sonar.server.computation.metric.Metric;
 import org.sonar.server.computation.metric.MetricImpl;
 import org.sonar.server.computation.metric.MetricRepository;
@@ -93,12 +92,11 @@ public class MeasureRepositoryImplTest {
 
   private DbClient dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), new MeasureDao(), new SnapshotDao(), new MetricDao(), new ComponentDao());
   private MetricRepository metricRepository = mock(MetricRepository.class);
-  private RuleCache ruleCache = mock(RuleCache.class);
-  private MeasureRepositoryImpl underTest = new MeasureRepositoryImpl(dbClient, reportReader, metricRepository, ruleCache);
+  private MeasureRepositoryImpl underTest = new MeasureRepositoryImpl(dbClient, reportReader, metricRepository);
 
   private DbClient mockedDbClient = mock(DbClient.class);
   private BatchReportReader mockBatchReportReader = mock(BatchReportReader.class);
-  private MeasureRepositoryImpl underTestWithMock = new MeasureRepositoryImpl(mockedDbClient, mockBatchReportReader, metricRepository, ruleCache);
+  private MeasureRepositoryImpl underTestWithMock = new MeasureRepositoryImpl(mockedDbClient, mockBatchReportReader, metricRepository);
 
   @CheckForNull
   private DbSession dbSession;
@@ -227,7 +225,7 @@ public class MeasureRepositoryImplTest {
       @Nullable
       @Override
       public Object[] apply(Measure input) {
-        return new Measure[] { input };
+        return new Measure[] {input};
       }
     }).toArray(Object[].class);
   }
@@ -254,8 +252,8 @@ public class MeasureRepositoryImplTest {
         fail("An IllegalArgumentException should have been raised");
       } catch (IllegalArgumentException e) {
         assertThat(e).hasMessage(format(
-            "Measure's ValueType (%s) is not consistent with the Measure's ValueType (%s)",
-            measure.getValueType(), metricType.getValueType()));
+          "Measure's ValueType (%s) is not consistent with the Measure's ValueType (%s)",
+          measure.getValueType(), metricType.getValueType()));
       }
     }
   }
index 97ae6bf520e2b1b2d4a0b83589918145548ddfec..edf10791eb23a6784fd3dfcf5eae2a6467cfaaa4 100644 (file)
@@ -1,3 +1,22 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
 ///*
 // * SonarQube, open source software quality management tool.
 // * Copyright (C) 2008-2014 SonarSource
index 573b543f54192752cc94d8356c7d2a84ecd378dc..786fdcce13136ed9e469bae4f55f850a9ee72899 100644 (file)
@@ -35,9 +35,7 @@ import org.sonar.core.measure.db.MeasureDto;
 import org.sonar.core.metric.db.MetricDto;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.core.persistence.DbTester;
-import org.sonar.core.rule.RuleDto;
 import org.sonar.core.technicaldebt.db.CharacteristicDao;
-import org.sonar.core.technicaldebt.db.CharacteristicDto;
 import org.sonar.server.component.ComponentTesting;
 import org.sonar.server.component.db.ComponentDao;
 import org.sonar.server.component.db.SnapshotDao;
@@ -45,9 +43,6 @@ import org.sonar.server.computation.batch.BatchReportReaderRule;
 import org.sonar.server.computation.batch.TreeRootHolderRule;
 import org.sonar.server.computation.component.Component;
 import org.sonar.server.computation.component.DumbComponent;
-import org.sonar.server.computation.debt.Characteristic;
-import org.sonar.server.computation.issue.RuleCache;
-import org.sonar.server.computation.issue.RuleCacheLoader;
 import org.sonar.server.computation.measure.Measure;
 import org.sonar.server.computation.measure.MeasureRepository;
 import org.sonar.server.computation.measure.MeasureRepositoryImpl;
@@ -60,7 +55,6 @@ import org.sonar.server.computation.period.PeriodsHolderRule;
 import org.sonar.server.db.DbClient;
 import org.sonar.server.measure.persistence.MeasureDao;
 import org.sonar.server.metric.persistence.MetricDao;
-import org.sonar.server.rule.RuleTesting;
 import org.sonar.server.rule.db.RuleDao;
 import org.sonar.test.DbTests;
 
@@ -119,7 +113,7 @@ public class FillMeasuresWithVariationsStepTest {
 
     metricRepository = new MetricRepositoryImpl(dbClient);
     metricRepository.start();
-    measureRepository = new MeasureRepositoryImpl(dbClient, reportReader, metricRepository, new RuleCache(new RuleCacheLoader(dbClient)));
+    measureRepository = new MeasureRepositoryImpl(dbClient, reportReader, metricRepository);
 
     sut = new FillMeasuresWithVariationsStep(dbClient, treeRootHolder, periodsHolder, metricRepository, measureRepository);
   }
@@ -257,66 +251,6 @@ public class FillMeasuresWithVariationsStepTest {
     assertThat(measureRepository.getRawMeasure(PROJECT, toMetric(BUILD_BREAKER_METRIC)).get().getVariations().getVariation1()).isEqualTo(-1d);
   }
 
-  @Test
-  public void set_variation_on_rule_measure() throws Exception {
-    SnapshotDto period1ProjectSnapshot = createForProject(PROJECT_DTO);
-    dbClient.snapshotDao().insert(session, period1ProjectSnapshot);
-
-    RuleDto rule1 = RuleTesting.newXooX1();
-    RuleDto rule2 = RuleTesting.newXooX2();
-    dbClient.ruleDao().insert(session, rule1, rule2);
-
-    dbClient.measureDao().insert(session, newMeasureDto(ISSUES_METRIC.getId(), PROJECT_DTO.getId(), period1ProjectSnapshot.getId(), 60d));
-    dbClient.measureDao().insert(session, newMeasureDto(ISSUES_METRIC.getId(), PROJECT_DTO.getId(), period1ProjectSnapshot.getId(), 40d).setRuleId(rule1.getId()));
-    dbClient.measureDao().insert(session, newMeasureDto(ISSUES_METRIC.getId(), PROJECT_DTO.getId(), period1ProjectSnapshot.getId(), 20d).setRuleId(rule2.getId()));
-    session.commit();
-
-    periodsHolder.setPeriods(newPeriod(1, period1ProjectSnapshot));
-
-    treeRootHolder.setRoot(PROJECT);
-
-    measureRepository.add(PROJECT, toMetric(ISSUES_METRIC), Measure.newMeasureBuilder().create(80, null));
-    measureRepository.add(PROJECT, toMetric(ISSUES_METRIC), Measure.newMeasureBuilder().forRule(rule1.getId()).create(45, null));
-    measureRepository.add(PROJECT, toMetric(ISSUES_METRIC), Measure.newMeasureBuilder().forRule(rule2.getId()).create(35, null));
-
-    sut.execute();
-
-    assertThat(measureRepository.getRawMeasure(PROJECT, toMetric(ISSUES_METRIC)).get().getVariations().getVariation1()).isEqualTo(20d);
-    assertThat(measureRepository.getRawMeasure(PROJECT, toMetric(ISSUES_METRIC), rule1).get().getVariations().getVariation1()).isEqualTo(5d);
-    assertThat(measureRepository.getRawMeasure(PROJECT, toMetric(ISSUES_METRIC), rule2).get().getVariations().getVariation1()).isEqualTo(15d);
-  }
-
-  @Test
-  public void set_variation_on_characteristic_measure() throws Exception {
-    SnapshotDto period1ProjectSnapshot = createForProject(PROJECT_DTO);
-    dbClient.snapshotDao().insert(session, period1ProjectSnapshot);
-
-    CharacteristicDto char1 = new CharacteristicDto().setKey("PORTABILITY");
-    CharacteristicDto char2 = new CharacteristicDto().setKey("MAINTAINABILITY");
-    dbClient.debtCharacteristicDao().insert(session, char1, char2);
-
-    dbClient.measureDao().insert(session, newMeasureDto(ISSUES_METRIC.getId(), PROJECT_DTO.getId(), period1ProjectSnapshot.getId(), 60d));
-    dbClient.measureDao().insert(session, newMeasureDto(ISSUES_METRIC.getId(), PROJECT_DTO.getId(), period1ProjectSnapshot.getId(), 40d).setCharacteristicId(char1.getId()));
-    dbClient.measureDao().insert(session, newMeasureDto(ISSUES_METRIC.getId(), PROJECT_DTO.getId(), period1ProjectSnapshot.getId(), 20d).setCharacteristicId(char2.getId()));
-    session.commit();
-
-    periodsHolder.setPeriods(newPeriod(1, period1ProjectSnapshot));
-
-    treeRootHolder.setRoot(PROJECT);
-
-    measureRepository.add(PROJECT, toMetric(ISSUES_METRIC), Measure.newMeasureBuilder().create(80, null));
-    measureRepository.add(PROJECT, toMetric(ISSUES_METRIC), Measure.newMeasureBuilder().forCharacteristic(char1.getId()).create(45, null));
-    measureRepository.add(PROJECT, toMetric(ISSUES_METRIC), Measure.newMeasureBuilder().forCharacteristic(char2.getId()).create(35, null));
-
-    sut.execute();
-
-    assertThat(measureRepository.getRawMeasure(PROJECT, toMetric(ISSUES_METRIC)).get().getVariations().getVariation1()).isEqualTo(20d);
-    assertThat(measureRepository.getRawMeasure(PROJECT, toMetric(ISSUES_METRIC), new Characteristic(char1.getId(), char1.getKey(), null)).get().getVariations().getVariation1())
-      .isEqualTo(5d);
-    assertThat(measureRepository.getRawMeasure(PROJECT, toMetric(ISSUES_METRIC), new Characteristic(char2.getId(), char2.getKey(), null)).get().getVariations().getVariation1())
-      .isEqualTo(15d);
-  }
-
   @Test
   public void read_measure_from_batch() throws Exception {
     // Project
index e5592554a47fa53f5bc295bbf477f49d435491a8..ff4b22ba991b4b8078d8fc8428ee2b5bb79b9156 100644 (file)
@@ -48,6 +48,8 @@ import static org.mockito.Mockito.when;
 
 public class PersistIssuesStepTest extends BaseStepTest {
 
+  public static final long NOW = 1400000000000L;
+
   @Rule
   public TemporaryFolder temp = new TemporaryFolder();
 
@@ -77,7 +79,7 @@ public class PersistIssuesStepTest extends BaseStepTest {
 
     issueCache = new IssueCache(temp.newFile(), System2.INSTANCE);
     system2 = mock(System2.class);
-    when(system2.now()).thenReturn(1400000000000L);
+    when(system2.now()).thenReturn(NOW);
     step = new PersistIssuesStep(dbClient, system2, new UpdateConflictResolver(), new RuleCache(new RuleCacheLoader(dbClient)), issueCache);
   }
 
@@ -117,6 +119,7 @@ public class PersistIssuesStepTest extends BaseStepTest {
       .setSeverity(Severity.BLOCKER)
       .setStatus(Issue.STATUS_CLOSED)
       .setResolution(Issue.RESOLUTION_FIXED)
+      .setSelectedAt(NOW)
       .setNew(false)
       .setChanged(true)
       ).close();
index 296dda1d0188c9dc6aebcdfd2ca45442d18adae4..b99f981492ae96da0fcbf1d3c50bdaefdc6e0296 100644 (file)
@@ -57,6 +57,7 @@ import org.sonar.server.rule.RuleTesting;
 import org.sonar.server.rule.db.RuleDao;
 import org.sonar.test.DbTests;
 
+import static java.util.Arrays.asList;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.sonar.api.measures.CoreMetrics.DUPLICATIONS_DATA;
 import static org.sonar.api.measures.CoreMetrics.DUPLICATIONS_DATA_KEY;
@@ -151,11 +152,8 @@ public class PersistMeasuresStepTest extends BaseStepTest {
         .setVariationValue3(3.3d)
         .setVariationValue4(4.4d)
         .setVariationValue5(5.5d)
-        .setAlertStatus("WARN")
-        .setAlertText("Open issues > 0")
         .setDescription("measure-description")
         .setMetricKey(STRING_METRIC_KEY)
-        .setCharactericId(123456)
         .build()));
 
     reportReader.putMeasures(FILE_REF, Arrays.asList(
@@ -167,11 +165,8 @@ public class PersistMeasuresStepTest extends BaseStepTest {
         .setVariationValue3(3.3d)
         .setVariationValue4(4.4d)
         .setVariationValue5(5.5d)
-        .setAlertStatus("ERROR")
-        .setAlertText("Blocker issues variation > 0")
         .setDescription("measure-description")
         .setMetricKey(DOUBLE_METRIC_KEY)
-        .setRuleKey(RULE_KEY.toString())
         .build()));
 
     sut.execute();
@@ -192,10 +187,15 @@ public class PersistMeasuresStepTest extends BaseStepTest {
     dto = dtos.get(PROJECT_REF);
     assertThat(dto.get("snapshotId")).isEqualTo(4L);
     assertThat(dto.get("componentId")).isEqualTo(fileDto.getId());
+<<<<<<< HEAD
     assertThat(dto.get("metricId")).isEqualTo(2L);
     assertThat(dto.get("ruleId")).isEqualTo(rule.getId().longValue());
     assertThat(dto.get("characteristicId")).isNull();
     assertThat(dto.get("value")).isEqualTo(123.1d);
+=======
+    assertThat(dto.get("metricId")).isEqualTo(doubleMetric.getId().longValue());
+    assertThat(dto.get("value")).isEqualTo(123.123d);
+>>>>>>> SONAR-6588 integrate issues to Compute Engine
     assertThat(dto.get("severity")).isNull();
   }
 
index e15b08c3e25b5a2ea44a2121dcd60e2782d574e0..a4c029b46067e5a2b28fc1a84a93addf41edb8b2 100644 (file)
@@ -24,7 +24,7 @@
       issue_creation_date="[null]"
       issue_update_date="[null]"
       issue_close_date="[null]"
-      created_at="1100000000000"
+      created_at="1300000000000"
       updated_at="1400000000000"
       />
 
index 23f7ab20677b219c3c02986074a12e2fb9c97e12..3cee2f8e087f955fe5e9a06891afb154bc34c5b2 100644 (file)
@@ -36,8 +36,8 @@
       issue_creation_date="[null]"
       issue_update_date="[null]"
       issue_close_date="[null]"
-      created_at="1100000000000"
-      updated_at="1100000000000"
+      created_at="1300000000000"
+      updated_at="1300000000000"
       />
 
 </dataset>
index 5f02ff8f82ef2695fcdf7e7a26d71de8ddcf513e..21d7b857ca9b8be245a5f46c3a9085f7568a6291 100644 (file)
@@ -69,6 +69,49 @@ public final class BatchReport {
      * <code>optional int32 root_component_ref = 4;</code>
      */
     int getRootComponentRef();
+
+    /**
+     * <code>repeated string active_rule_key = 5;</code>
+     *
+     * <pre>
+     *Keys of the rules that were enabled in Quality profiles.
+     *A key is a string composed of the repository and the subKey, specific to the repository. Format is
+     *"{repository}:{subKey}", for instance "java:NullDereference".
+     * </pre>
+     */
+    com.google.protobuf.ProtocolStringList
+        getActiveRuleKeyList();
+    /**
+     * <code>repeated string active_rule_key = 5;</code>
+     *
+     * <pre>
+     *Keys of the rules that were enabled in Quality profiles.
+     *A key is a string composed of the repository and the subKey, specific to the repository. Format is
+     *"{repository}:{subKey}", for instance "java:NullDereference".
+     * </pre>
+     */
+    int getActiveRuleKeyCount();
+    /**
+     * <code>repeated string active_rule_key = 5;</code>
+     *
+     * <pre>
+     *Keys of the rules that were enabled in Quality profiles.
+     *A key is a string composed of the repository and the subKey, specific to the repository. Format is
+     *"{repository}:{subKey}", for instance "java:NullDereference".
+     * </pre>
+     */
+    java.lang.String getActiveRuleKey(int index);
+    /**
+     * <code>repeated string active_rule_key = 5;</code>
+     *
+     * <pre>
+     *Keys of the rules that were enabled in Quality profiles.
+     *A key is a string composed of the repository and the subKey, specific to the repository. Format is
+     *"{repository}:{subKey}", for instance "java:NullDereference".
+     * </pre>
+     */
+    com.google.protobuf.ByteString
+        getActiveRuleKeyBytes(int index);
   }
   /**
    * Protobuf type {@code Metadata}
@@ -144,6 +187,15 @@ public final class BatchReport {
               rootComponentRef_ = input.readInt32();
               break;
             }
+            case 42: {
+              com.google.protobuf.ByteString bs = input.readBytes();
+              if (!((mutable_bitField0_ & 0x00000010) == 0x00000010)) {
+                activeRuleKey_ = new com.google.protobuf.LazyStringArrayList();
+                mutable_bitField0_ |= 0x00000010;
+              }
+              activeRuleKey_.add(bs);
+              break;
+            }
           }
         }
       } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -152,6 +204,9 @@ public final class BatchReport {
         throw new com.google.protobuf.InvalidProtocolBufferException(
             e.getMessage()).setUnfinishedMessage(this);
       } finally {
+        if (((mutable_bitField0_ & 0x00000010) == 0x00000010)) {
+          activeRuleKey_ = activeRuleKey_.getUnmodifiableView();
+        }
         this.unknownFields = unknownFields.build();
         makeExtensionsImmutable();
       }
@@ -310,11 +365,65 @@ public final class BatchReport {
       return rootComponentRef_;
     }
 
+    public static final int ACTIVE_RULE_KEY_FIELD_NUMBER = 5;
+    private com.google.protobuf.LazyStringList activeRuleKey_;
+    /**
+     * <code>repeated string active_rule_key = 5;</code>
+     *
+     * <pre>
+     *Keys of the rules that were enabled in Quality profiles.
+     *A key is a string composed of the repository and the subKey, specific to the repository. Format is
+     *"{repository}:{subKey}", for instance "java:NullDereference".
+     * </pre>
+     */
+    public com.google.protobuf.ProtocolStringList
+        getActiveRuleKeyList() {
+      return activeRuleKey_;
+    }
+    /**
+     * <code>repeated string active_rule_key = 5;</code>
+     *
+     * <pre>
+     *Keys of the rules that were enabled in Quality profiles.
+     *A key is a string composed of the repository and the subKey, specific to the repository. Format is
+     *"{repository}:{subKey}", for instance "java:NullDereference".
+     * </pre>
+     */
+    public int getActiveRuleKeyCount() {
+      return activeRuleKey_.size();
+    }
+    /**
+     * <code>repeated string active_rule_key = 5;</code>
+     *
+     * <pre>
+     *Keys of the rules that were enabled in Quality profiles.
+     *A key is a string composed of the repository and the subKey, specific to the repository. Format is
+     *"{repository}:{subKey}", for instance "java:NullDereference".
+     * </pre>
+     */
+    public java.lang.String getActiveRuleKey(int index) {
+      return activeRuleKey_.get(index);
+    }
+    /**
+     * <code>repeated string active_rule_key = 5;</code>
+     *
+     * <pre>
+     *Keys of the rules that were enabled in Quality profiles.
+     *A key is a string composed of the repository and the subKey, specific to the repository. Format is
+     *"{repository}:{subKey}", for instance "java:NullDereference".
+     * </pre>
+     */
+    public com.google.protobuf.ByteString
+        getActiveRuleKeyBytes(int index) {
+      return activeRuleKey_.getByteString(index);
+    }
+
     private void initFields() {
       analysisDate_ = 0L;
       projectKey_ = "";
       branch_ = "";
       rootComponentRef_ = 0;
+      activeRuleKey_ = com.google.protobuf.LazyStringArrayList.EMPTY;
     }
     private byte memoizedIsInitialized = -1;
     public final boolean isInitialized() {
@@ -341,6 +450,9 @@ public final class BatchReport {
       if (((bitField0_ & 0x00000008) == 0x00000008)) {
         output.writeInt32(4, rootComponentRef_);
       }
+      for (int i = 0; i < activeRuleKey_.size(); i++) {
+        output.writeBytes(5, activeRuleKey_.getByteString(i));
+      }
       getUnknownFields().writeTo(output);
     }
 
@@ -366,6 +478,15 @@ public final class BatchReport {
         size += com.google.protobuf.CodedOutputStream
           .computeInt32Size(4, rootComponentRef_);
       }
+      {
+        int dataSize = 0;
+        for (int i = 0; i < activeRuleKey_.size(); i++) {
+          dataSize += com.google.protobuf.CodedOutputStream
+            .computeBytesSizeNoTag(activeRuleKey_.getByteString(i));
+        }
+        size += dataSize;
+        size += 1 * getActiveRuleKeyList().size();
+      }
       size += getUnknownFields().getSerializedSize();
       memoizedSerializedSize = size;
       return size;
@@ -491,6 +612,8 @@ public final class BatchReport {
         bitField0_ = (bitField0_ & ~0x00000004);
         rootComponentRef_ = 0;
         bitField0_ = (bitField0_ & ~0x00000008);
+        activeRuleKey_ = com.google.protobuf.LazyStringArrayList.EMPTY;
+        bitField0_ = (bitField0_ & ~0x00000010);
         return this;
       }
 
@@ -535,6 +658,11 @@ public final class BatchReport {
           to_bitField0_ |= 0x00000008;
         }
         result.rootComponentRef_ = rootComponentRef_;
+        if (((bitField0_ & 0x00000010) == 0x00000010)) {
+          activeRuleKey_ = activeRuleKey_.getUnmodifiableView();
+          bitField0_ = (bitField0_ & ~0x00000010);
+        }
+        result.activeRuleKey_ = activeRuleKey_;
         result.bitField0_ = to_bitField0_;
         onBuilt();
         return result;
@@ -567,6 +695,16 @@ public final class BatchReport {
         if (other.hasRootComponentRef()) {
           setRootComponentRef(other.getRootComponentRef());
         }
+        if (!other.activeRuleKey_.isEmpty()) {
+          if (activeRuleKey_.isEmpty()) {
+            activeRuleKey_ = other.activeRuleKey_;
+            bitField0_ = (bitField0_ & ~0x00000010);
+          } else {
+            ensureActiveRuleKeyIsMutable();
+            activeRuleKey_.addAll(other.activeRuleKey_);
+          }
+          onChanged();
+        }
         this.mergeUnknownFields(other.getUnknownFields());
         return this;
       }
@@ -834,6 +972,153 @@ public final class BatchReport {
         return this;
       }
 
+      private com.google.protobuf.LazyStringList activeRuleKey_ = com.google.protobuf.LazyStringArrayList.EMPTY;
+      private void ensureActiveRuleKeyIsMutable() {
+        if (!((bitField0_ & 0x00000010) == 0x00000010)) {
+          activeRuleKey_ = new com.google.protobuf.LazyStringArrayList(activeRuleKey_);
+          bitField0_ |= 0x00000010;
+         }
+      }
+      /**
+       * <code>repeated string active_rule_key = 5;</code>
+       *
+       * <pre>
+       *Keys of the rules that were enabled in Quality profiles.
+       *A key is a string composed of the repository and the subKey, specific to the repository. Format is
+       *"{repository}:{subKey}", for instance "java:NullDereference".
+       * </pre>
+       */
+      public com.google.protobuf.ProtocolStringList
+          getActiveRuleKeyList() {
+        return activeRuleKey_.getUnmodifiableView();
+      }
+      /**
+       * <code>repeated string active_rule_key = 5;</code>
+       *
+       * <pre>
+       *Keys of the rules that were enabled in Quality profiles.
+       *A key is a string composed of the repository and the subKey, specific to the repository. Format is
+       *"{repository}:{subKey}", for instance "java:NullDereference".
+       * </pre>
+       */
+      public int getActiveRuleKeyCount() {
+        return activeRuleKey_.size();
+      }
+      /**
+       * <code>repeated string active_rule_key = 5;</code>
+       *
+       * <pre>
+       *Keys of the rules that were enabled in Quality profiles.
+       *A key is a string composed of the repository and the subKey, specific to the repository. Format is
+       *"{repository}:{subKey}", for instance "java:NullDereference".
+       * </pre>
+       */
+      public java.lang.String getActiveRuleKey(int index) {
+        return activeRuleKey_.get(index);
+      }
+      /**
+       * <code>repeated string active_rule_key = 5;</code>
+       *
+       * <pre>
+       *Keys of the rules that were enabled in Quality profiles.
+       *A key is a string composed of the repository and the subKey, specific to the repository. Format is
+       *"{repository}:{subKey}", for instance "java:NullDereference".
+       * </pre>
+       */
+      public com.google.protobuf.ByteString
+          getActiveRuleKeyBytes(int index) {
+        return activeRuleKey_.getByteString(index);
+      }
+      /**
+       * <code>repeated string active_rule_key = 5;</code>
+       *
+       * <pre>
+       *Keys of the rules that were enabled in Quality profiles.
+       *A key is a string composed of the repository and the subKey, specific to the repository. Format is
+       *"{repository}:{subKey}", for instance "java:NullDereference".
+       * </pre>
+       */
+      public Builder setActiveRuleKey(
+          int index, java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  ensureActiveRuleKeyIsMutable();
+        activeRuleKey_.set(index, value);
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>repeated string active_rule_key = 5;</code>
+       *
+       * <pre>
+       *Keys of the rules that were enabled in Quality profiles.
+       *A key is a string composed of the repository and the subKey, specific to the repository. Format is
+       *"{repository}:{subKey}", for instance "java:NullDereference".
+       * </pre>
+       */
+      public Builder addActiveRuleKey(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  ensureActiveRuleKeyIsMutable();
+        activeRuleKey_.add(value);
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>repeated string active_rule_key = 5;</code>
+       *
+       * <pre>
+       *Keys of the rules that were enabled in Quality profiles.
+       *A key is a string composed of the repository and the subKey, specific to the repository. Format is
+       *"{repository}:{subKey}", for instance "java:NullDereference".
+       * </pre>
+       */
+      public Builder addAllActiveRuleKey(
+          java.lang.Iterable<java.lang.String> values) {
+        ensureActiveRuleKeyIsMutable();
+        com.google.protobuf.AbstractMessageLite.Builder.addAll(
+            values, activeRuleKey_);
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>repeated string active_rule_key = 5;</code>
+       *
+       * <pre>
+       *Keys of the rules that were enabled in Quality profiles.
+       *A key is a string composed of the repository and the subKey, specific to the repository. Format is
+       *"{repository}:{subKey}", for instance "java:NullDereference".
+       * </pre>
+       */
+      public Builder clearActiveRuleKey() {
+        activeRuleKey_ = com.google.protobuf.LazyStringArrayList.EMPTY;
+        bitField0_ = (bitField0_ & ~0x00000010);
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>repeated string active_rule_key = 5;</code>
+       *
+       * <pre>
+       *Keys of the rules that were enabled in Quality profiles.
+       *A key is a string composed of the repository and the subKey, specific to the repository. Format is
+       *"{repository}:{subKey}", for instance "java:NullDereference".
+       * </pre>
+       */
+      public Builder addActiveRuleKeyBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  ensureActiveRuleKeyIsMutable();
+        activeRuleKey_.add(value);
+        onChanged();
+        return this;
+      }
+
       // @@protoc_insertion_point(builder_scope:Metadata)
     }
 
@@ -3814,48 +4099,6 @@ public final class BatchReport {
     com.google.protobuf.ByteString
         getDescriptionBytes();
 
-    /**
-     * <code>optional string rule_key = 10;</code>
-     */
-    boolean hasRuleKey();
-    /**
-     * <code>optional string rule_key = 10;</code>
-     */
-    java.lang.String getRuleKey();
-    /**
-     * <code>optional string rule_key = 10;</code>
-     */
-    com.google.protobuf.ByteString
-        getRuleKeyBytes();
-
-    /**
-     * <code>optional string alert_status = 12;</code>
-     */
-    boolean hasAlertStatus();
-    /**
-     * <code>optional string alert_status = 12;</code>
-     */
-    java.lang.String getAlertStatus();
-    /**
-     * <code>optional string alert_status = 12;</code>
-     */
-    com.google.protobuf.ByteString
-        getAlertStatusBytes();
-
-    /**
-     * <code>optional string alert_text = 13;</code>
-     */
-    boolean hasAlertText();
-    /**
-     * <code>optional string alert_text = 13;</code>
-     */
-    java.lang.String getAlertText();
-    /**
-     * <code>optional string alert_text = 13;</code>
-     */
-    com.google.protobuf.ByteString
-        getAlertTextBytes();
-
     /**
      * <code>optional double variation_value_1 = 14;</code>
      */
@@ -3901,15 +4144,6 @@ public final class BatchReport {
      */
     double getVariationValue5();
 
-    /**
-     * <code>optional int32 characteric_id = 19;</code>
-     */
-    boolean hasCharactericId();
-    /**
-     * <code>optional int32 characteric_id = 19;</code>
-     */
-    int getCharactericId();
-
     /**
      * <code>optional int32 person_id = 20;</code>
      */
@@ -4020,56 +4254,33 @@ public final class BatchReport {
               description_ = bs;
               break;
             }
-            case 82: {
-              com.google.protobuf.ByteString bs = input.readBytes();
-              bitField0_ |= 0x00000100;
-              ruleKey_ = bs;
-              break;
-            }
-            case 98: {
-              com.google.protobuf.ByteString bs = input.readBytes();
-              bitField0_ |= 0x00000200;
-              alertStatus_ = bs;
-              break;
-            }
-            case 106: {
-              com.google.protobuf.ByteString bs = input.readBytes();
-              bitField0_ |= 0x00000400;
-              alertText_ = bs;
-              break;
-            }
             case 113: {
-              bitField0_ |= 0x00000800;
+              bitField0_ |= 0x00000100;
               variationValue1_ = input.readDouble();
               break;
             }
             case 121: {
-              bitField0_ |= 0x00001000;
+              bitField0_ |= 0x00000200;
               variationValue2_ = input.readDouble();
               break;
             }
             case 129: {
-              bitField0_ |= 0x00002000;
+              bitField0_ |= 0x00000400;
               variationValue3_ = input.readDouble();
               break;
             }
             case 137: {
-              bitField0_ |= 0x00004000;
+              bitField0_ |= 0x00000800;
               variationValue4_ = input.readDouble();
               break;
             }
             case 145: {
-              bitField0_ |= 0x00008000;
+              bitField0_ |= 0x00001000;
               variationValue5_ = input.readDouble();
               break;
             }
-            case 152: {
-              bitField0_ |= 0x00010000;
-              charactericId_ = input.readInt32();
-              break;
-            }
             case 160: {
-              bitField0_ |= 0x00020000;
+              bitField0_ |= 0x00002000;
               personId_ = input.readInt32();
               break;
             }
@@ -4334,157 +4545,31 @@ public final class BatchReport {
       }
     }
 
-    public static final int RULE_KEY_FIELD_NUMBER = 10;
-    private java.lang.Object ruleKey_;
+    public static final int VARIATION_VALUE_1_FIELD_NUMBER = 14;
+    private double variationValue1_;
     /**
-     * <code>optional string rule_key = 10;</code>
+     * <code>optional double variation_value_1 = 14;</code>
      */
-    public boolean hasRuleKey() {
+    public boolean hasVariationValue1() {
       return ((bitField0_ & 0x00000100) == 0x00000100);
     }
     /**
-     * <code>optional string rule_key = 10;</code>
-     */
-    public java.lang.String getRuleKey() {
-      java.lang.Object ref = ruleKey_;
-      if (ref instanceof java.lang.String) {
-        return (java.lang.String) ref;
-      } else {
-        com.google.protobuf.ByteString bs = 
-            (com.google.protobuf.ByteString) ref;
-        java.lang.String s = bs.toStringUtf8();
-        if (bs.isValidUtf8()) {
-          ruleKey_ = s;
-        }
-        return s;
-      }
-    }
-    /**
-     * <code>optional string rule_key = 10;</code>
+     * <code>optional double variation_value_1 = 14;</code>
      */
-    public com.google.protobuf.ByteString
-        getRuleKeyBytes() {
-      java.lang.Object ref = ruleKey_;
-      if (ref instanceof java.lang.String) {
-        com.google.protobuf.ByteString b = 
-            com.google.protobuf.ByteString.copyFromUtf8(
-                (java.lang.String) ref);
-        ruleKey_ = b;
-        return b;
-      } else {
-        return (com.google.protobuf.ByteString) ref;
-      }
+    public double getVariationValue1() {
+      return variationValue1_;
     }
 
-    public static final int ALERT_STATUS_FIELD_NUMBER = 12;
-    private java.lang.Object alertStatus_;
+    public static final int VARIATION_VALUE_2_FIELD_NUMBER = 15;
+    private double variationValue2_;
     /**
-     * <code>optional string alert_status = 12;</code>
+     * <code>optional double variation_value_2 = 15;</code>
      */
-    public boolean hasAlertStatus() {
+    public boolean hasVariationValue2() {
       return ((bitField0_ & 0x00000200) == 0x00000200);
     }
     /**
-     * <code>optional string alert_status = 12;</code>
-     */
-    public java.lang.String getAlertStatus() {
-      java.lang.Object ref = alertStatus_;
-      if (ref instanceof java.lang.String) {
-        return (java.lang.String) ref;
-      } else {
-        com.google.protobuf.ByteString bs = 
-            (com.google.protobuf.ByteString) ref;
-        java.lang.String s = bs.toStringUtf8();
-        if (bs.isValidUtf8()) {
-          alertStatus_ = s;
-        }
-        return s;
-      }
-    }
-    /**
-     * <code>optional string alert_status = 12;</code>
-     */
-    public com.google.protobuf.ByteString
-        getAlertStatusBytes() {
-      java.lang.Object ref = alertStatus_;
-      if (ref instanceof java.lang.String) {
-        com.google.protobuf.ByteString b = 
-            com.google.protobuf.ByteString.copyFromUtf8(
-                (java.lang.String) ref);
-        alertStatus_ = b;
-        return b;
-      } else {
-        return (com.google.protobuf.ByteString) ref;
-      }
-    }
-
-    public static final int ALERT_TEXT_FIELD_NUMBER = 13;
-    private java.lang.Object alertText_;
-    /**
-     * <code>optional string alert_text = 13;</code>
-     */
-    public boolean hasAlertText() {
-      return ((bitField0_ & 0x00000400) == 0x00000400);
-    }
-    /**
-     * <code>optional string alert_text = 13;</code>
-     */
-    public java.lang.String getAlertText() {
-      java.lang.Object ref = alertText_;
-      if (ref instanceof java.lang.String) {
-        return (java.lang.String) ref;
-      } else {
-        com.google.protobuf.ByteString bs = 
-            (com.google.protobuf.ByteString) ref;
-        java.lang.String s = bs.toStringUtf8();
-        if (bs.isValidUtf8()) {
-          alertText_ = s;
-        }
-        return s;
-      }
-    }
-    /**
-     * <code>optional string alert_text = 13;</code>
-     */
-    public com.google.protobuf.ByteString
-        getAlertTextBytes() {
-      java.lang.Object ref = alertText_;
-      if (ref instanceof java.lang.String) {
-        com.google.protobuf.ByteString b = 
-            com.google.protobuf.ByteString.copyFromUtf8(
-                (java.lang.String) ref);
-        alertText_ = b;
-        return b;
-      } else {
-        return (com.google.protobuf.ByteString) ref;
-      }
-    }
-
-    public static final int VARIATION_VALUE_1_FIELD_NUMBER = 14;
-    private double variationValue1_;
-    /**
-     * <code>optional double variation_value_1 = 14;</code>
-     */
-    public boolean hasVariationValue1() {
-      return ((bitField0_ & 0x00000800) == 0x00000800);
-    }
-    /**
-     * <code>optional double variation_value_1 = 14;</code>
-     */
-    public double getVariationValue1() {
-      return variationValue1_;
-    }
-
-    public static final int VARIATION_VALUE_2_FIELD_NUMBER = 15;
-    private double variationValue2_;
-    /**
-     * <code>optional double variation_value_2 = 15;</code>
-     */
-    public boolean hasVariationValue2() {
-      return ((bitField0_ & 0x00001000) == 0x00001000);
-    }
-    /**
-     * <code>optional double variation_value_2 = 15;</code>
+     * <code>optional double variation_value_2 = 15;</code>
      */
     public double getVariationValue2() {
       return variationValue2_;
@@ -4496,7 +4581,7 @@ public final class BatchReport {
      * <code>optional double variation_value_3 = 16;</code>
      */
     public boolean hasVariationValue3() {
-      return ((bitField0_ & 0x00002000) == 0x00002000);
+      return ((bitField0_ & 0x00000400) == 0x00000400);
     }
     /**
      * <code>optional double variation_value_3 = 16;</code>
@@ -4511,7 +4596,7 @@ public final class BatchReport {
      * <code>optional double variation_value_4 = 17;</code>
      */
     public boolean hasVariationValue4() {
-      return ((bitField0_ & 0x00004000) == 0x00004000);
+      return ((bitField0_ & 0x00000800) == 0x00000800);
     }
     /**
      * <code>optional double variation_value_4 = 17;</code>
@@ -4526,7 +4611,7 @@ public final class BatchReport {
      * <code>optional double variation_value_5 = 18;</code>
      */
     public boolean hasVariationValue5() {
-      return ((bitField0_ & 0x00008000) == 0x00008000);
+      return ((bitField0_ & 0x00001000) == 0x00001000);
     }
     /**
      * <code>optional double variation_value_5 = 18;</code>
@@ -4535,28 +4620,13 @@ public final class BatchReport {
       return variationValue5_;
     }
 
-    public static final int CHARACTERIC_ID_FIELD_NUMBER = 19;
-    private int charactericId_;
-    /**
-     * <code>optional int32 characteric_id = 19;</code>
-     */
-    public boolean hasCharactericId() {
-      return ((bitField0_ & 0x00010000) == 0x00010000);
-    }
-    /**
-     * <code>optional int32 characteric_id = 19;</code>
-     */
-    public int getCharactericId() {
-      return charactericId_;
-    }
-
     public static final int PERSON_ID_FIELD_NUMBER = 20;
     private int personId_;
     /**
      * <code>optional int32 person_id = 20;</code>
      */
     public boolean hasPersonId() {
-      return ((bitField0_ & 0x00020000) == 0x00020000);
+      return ((bitField0_ & 0x00002000) == 0x00002000);
     }
     /**
      * <code>optional int32 person_id = 20;</code>
@@ -4574,15 +4644,11 @@ public final class BatchReport {
       stringValue_ = "";
       metricKey_ = "";
       description_ = "";
-      ruleKey_ = "";
-      alertStatus_ = "";
-      alertText_ = "";
       variationValue1_ = 0D;
       variationValue2_ = 0D;
       variationValue3_ = 0D;
       variationValue4_ = 0D;
       variationValue5_ = 0D;
-      charactericId_ = 0;
       personId_ = 0;
     }
     private byte memoizedIsInitialized = -1;
@@ -4623,33 +4689,21 @@ public final class BatchReport {
         output.writeBytes(9, getDescriptionBytes());
       }
       if (((bitField0_ & 0x00000100) == 0x00000100)) {
-        output.writeBytes(10, getRuleKeyBytes());
-      }
-      if (((bitField0_ & 0x00000200) == 0x00000200)) {
-        output.writeBytes(12, getAlertStatusBytes());
-      }
-      if (((bitField0_ & 0x00000400) == 0x00000400)) {
-        output.writeBytes(13, getAlertTextBytes());
-      }
-      if (((bitField0_ & 0x00000800) == 0x00000800)) {
         output.writeDouble(14, variationValue1_);
       }
-      if (((bitField0_ & 0x00001000) == 0x00001000)) {
+      if (((bitField0_ & 0x00000200) == 0x00000200)) {
         output.writeDouble(15, variationValue2_);
       }
-      if (((bitField0_ & 0x00002000) == 0x00002000)) {
+      if (((bitField0_ & 0x00000400) == 0x00000400)) {
         output.writeDouble(16, variationValue3_);
       }
-      if (((bitField0_ & 0x00004000) == 0x00004000)) {
+      if (((bitField0_ & 0x00000800) == 0x00000800)) {
         output.writeDouble(17, variationValue4_);
       }
-      if (((bitField0_ & 0x00008000) == 0x00008000)) {
+      if (((bitField0_ & 0x00001000) == 0x00001000)) {
         output.writeDouble(18, variationValue5_);
       }
-      if (((bitField0_ & 0x00010000) == 0x00010000)) {
-        output.writeInt32(19, charactericId_);
-      }
-      if (((bitField0_ & 0x00020000) == 0x00020000)) {
+      if (((bitField0_ & 0x00002000) == 0x00002000)) {
         output.writeInt32(20, personId_);
       }
       getUnknownFields().writeTo(output);
@@ -4694,42 +4748,26 @@ public final class BatchReport {
           .computeBytesSize(9, getDescriptionBytes());
       }
       if (((bitField0_ & 0x00000100) == 0x00000100)) {
-        size += com.google.protobuf.CodedOutputStream
-          .computeBytesSize(10, getRuleKeyBytes());
-      }
-      if (((bitField0_ & 0x00000200) == 0x00000200)) {
-        size += com.google.protobuf.CodedOutputStream
-          .computeBytesSize(12, getAlertStatusBytes());
-      }
-      if (((bitField0_ & 0x00000400) == 0x00000400)) {
-        size += com.google.protobuf.CodedOutputStream
-          .computeBytesSize(13, getAlertTextBytes());
-      }
-      if (((bitField0_ & 0x00000800) == 0x00000800)) {
         size += com.google.protobuf.CodedOutputStream
           .computeDoubleSize(14, variationValue1_);
       }
-      if (((bitField0_ & 0x00001000) == 0x00001000)) {
+      if (((bitField0_ & 0x00000200) == 0x00000200)) {
         size += com.google.protobuf.CodedOutputStream
           .computeDoubleSize(15, variationValue2_);
       }
-      if (((bitField0_ & 0x00002000) == 0x00002000)) {
+      if (((bitField0_ & 0x00000400) == 0x00000400)) {
         size += com.google.protobuf.CodedOutputStream
           .computeDoubleSize(16, variationValue3_);
       }
-      if (((bitField0_ & 0x00004000) == 0x00004000)) {
+      if (((bitField0_ & 0x00000800) == 0x00000800)) {
         size += com.google.protobuf.CodedOutputStream
           .computeDoubleSize(17, variationValue4_);
       }
-      if (((bitField0_ & 0x00008000) == 0x00008000)) {
+      if (((bitField0_ & 0x00001000) == 0x00001000)) {
         size += com.google.protobuf.CodedOutputStream
           .computeDoubleSize(18, variationValue5_);
       }
-      if (((bitField0_ & 0x00010000) == 0x00010000)) {
-        size += com.google.protobuf.CodedOutputStream
-          .computeInt32Size(19, charactericId_);
-      }
-      if (((bitField0_ & 0x00020000) == 0x00020000)) {
+      if (((bitField0_ & 0x00002000) == 0x00002000)) {
         size += com.google.protobuf.CodedOutputStream
           .computeInt32Size(20, personId_);
       }
@@ -4866,26 +4904,18 @@ public final class BatchReport {
         bitField0_ = (bitField0_ & ~0x00000040);
         description_ = "";
         bitField0_ = (bitField0_ & ~0x00000080);
-        ruleKey_ = "";
-        bitField0_ = (bitField0_ & ~0x00000100);
-        alertStatus_ = "";
-        bitField0_ = (bitField0_ & ~0x00000200);
-        alertText_ = "";
-        bitField0_ = (bitField0_ & ~0x00000400);
         variationValue1_ = 0D;
-        bitField0_ = (bitField0_ & ~0x00000800);
+        bitField0_ = (bitField0_ & ~0x00000100);
         variationValue2_ = 0D;
-        bitField0_ = (bitField0_ & ~0x00001000);
+        bitField0_ = (bitField0_ & ~0x00000200);
         variationValue3_ = 0D;
-        bitField0_ = (bitField0_ & ~0x00002000);
+        bitField0_ = (bitField0_ & ~0x00000400);
         variationValue4_ = 0D;
-        bitField0_ = (bitField0_ & ~0x00004000);
+        bitField0_ = (bitField0_ & ~0x00000800);
         variationValue5_ = 0D;
-        bitField0_ = (bitField0_ & ~0x00008000);
-        charactericId_ = 0;
-        bitField0_ = (bitField0_ & ~0x00010000);
+        bitField0_ = (bitField0_ & ~0x00001000);
         personId_ = 0;
-        bitField0_ = (bitField0_ & ~0x00020000);
+        bitField0_ = (bitField0_ & ~0x00002000);
         return this;
       }
 
@@ -4949,42 +4979,26 @@ public final class BatchReport {
         if (((from_bitField0_ & 0x00000100) == 0x00000100)) {
           to_bitField0_ |= 0x00000100;
         }
-        result.ruleKey_ = ruleKey_;
+        result.variationValue1_ = variationValue1_;
         if (((from_bitField0_ & 0x00000200) == 0x00000200)) {
           to_bitField0_ |= 0x00000200;
         }
-        result.alertStatus_ = alertStatus_;
+        result.variationValue2_ = variationValue2_;
         if (((from_bitField0_ & 0x00000400) == 0x00000400)) {
           to_bitField0_ |= 0x00000400;
         }
-        result.alertText_ = alertText_;
+        result.variationValue3_ = variationValue3_;
         if (((from_bitField0_ & 0x00000800) == 0x00000800)) {
           to_bitField0_ |= 0x00000800;
         }
-        result.variationValue1_ = variationValue1_;
+        result.variationValue4_ = variationValue4_;
         if (((from_bitField0_ & 0x00001000) == 0x00001000)) {
           to_bitField0_ |= 0x00001000;
         }
-        result.variationValue2_ = variationValue2_;
+        result.variationValue5_ = variationValue5_;
         if (((from_bitField0_ & 0x00002000) == 0x00002000)) {
           to_bitField0_ |= 0x00002000;
         }
-        result.variationValue3_ = variationValue3_;
-        if (((from_bitField0_ & 0x00004000) == 0x00004000)) {
-          to_bitField0_ |= 0x00004000;
-        }
-        result.variationValue4_ = variationValue4_;
-        if (((from_bitField0_ & 0x00008000) == 0x00008000)) {
-          to_bitField0_ |= 0x00008000;
-        }
-        result.variationValue5_ = variationValue5_;
-        if (((from_bitField0_ & 0x00010000) == 0x00010000)) {
-          to_bitField0_ |= 0x00010000;
-        }
-        result.charactericId_ = charactericId_;
-        if (((from_bitField0_ & 0x00020000) == 0x00020000)) {
-          to_bitField0_ |= 0x00020000;
-        }
         result.personId_ = personId_;
         result.bitField0_ = to_bitField0_;
         onBuilt();
@@ -5032,21 +5046,6 @@ public final class BatchReport {
           description_ = other.description_;
           onChanged();
         }
-        if (other.hasRuleKey()) {
-          bitField0_ |= 0x00000100;
-          ruleKey_ = other.ruleKey_;
-          onChanged();
-        }
-        if (other.hasAlertStatus()) {
-          bitField0_ |= 0x00000200;
-          alertStatus_ = other.alertStatus_;
-          onChanged();
-        }
-        if (other.hasAlertText()) {
-          bitField0_ |= 0x00000400;
-          alertText_ = other.alertText_;
-          onChanged();
-        }
         if (other.hasVariationValue1()) {
           setVariationValue1(other.getVariationValue1());
         }
@@ -5062,9 +5061,6 @@ public final class BatchReport {
         if (other.hasVariationValue5()) {
           setVariationValue5(other.getVariationValue5());
         }
-        if (other.hasCharactericId()) {
-          setCharactericId(other.getCharactericId());
-        }
         if (other.hasPersonId()) {
           setPersonId(other.getPersonId());
         }
@@ -5526,240 +5522,12 @@ public final class BatchReport {
         return this;
       }
 
-      private java.lang.Object ruleKey_ = "";
-      /**
-       * <code>optional string rule_key = 10;</code>
-       */
-      public boolean hasRuleKey() {
-        return ((bitField0_ & 0x00000100) == 0x00000100);
-      }
-      /**
-       * <code>optional string rule_key = 10;</code>
-       */
-      public java.lang.String getRuleKey() {
-        java.lang.Object ref = ruleKey_;
-        if (!(ref instanceof java.lang.String)) {
-          com.google.protobuf.ByteString bs =
-              (com.google.protobuf.ByteString) ref;
-          java.lang.String s = bs.toStringUtf8();
-          if (bs.isValidUtf8()) {
-            ruleKey_ = s;
-          }
-          return s;
-        } else {
-          return (java.lang.String) ref;
-        }
-      }
-      /**
-       * <code>optional string rule_key = 10;</code>
-       */
-      public com.google.protobuf.ByteString
-          getRuleKeyBytes() {
-        java.lang.Object ref = ruleKey_;
-        if (ref instanceof String) {
-          com.google.protobuf.ByteString b = 
-              com.google.protobuf.ByteString.copyFromUtf8(
-                  (java.lang.String) ref);
-          ruleKey_ = b;
-          return b;
-        } else {
-          return (com.google.protobuf.ByteString) ref;
-        }
-      }
-      /**
-       * <code>optional string rule_key = 10;</code>
-       */
-      public Builder setRuleKey(
-          java.lang.String value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  bitField0_ |= 0x00000100;
-        ruleKey_ = value;
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>optional string rule_key = 10;</code>
-       */
-      public Builder clearRuleKey() {
-        bitField0_ = (bitField0_ & ~0x00000100);
-        ruleKey_ = getDefaultInstance().getRuleKey();
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>optional string rule_key = 10;</code>
-       */
-      public Builder setRuleKeyBytes(
-          com.google.protobuf.ByteString value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  bitField0_ |= 0x00000100;
-        ruleKey_ = value;
-        onChanged();
-        return this;
-      }
-
-      private java.lang.Object alertStatus_ = "";
-      /**
-       * <code>optional string alert_status = 12;</code>
-       */
-      public boolean hasAlertStatus() {
-        return ((bitField0_ & 0x00000200) == 0x00000200);
-      }
-      /**
-       * <code>optional string alert_status = 12;</code>
-       */
-      public java.lang.String getAlertStatus() {
-        java.lang.Object ref = alertStatus_;
-        if (!(ref instanceof java.lang.String)) {
-          com.google.protobuf.ByteString bs =
-              (com.google.protobuf.ByteString) ref;
-          java.lang.String s = bs.toStringUtf8();
-          if (bs.isValidUtf8()) {
-            alertStatus_ = s;
-          }
-          return s;
-        } else {
-          return (java.lang.String) ref;
-        }
-      }
-      /**
-       * <code>optional string alert_status = 12;</code>
-       */
-      public com.google.protobuf.ByteString
-          getAlertStatusBytes() {
-        java.lang.Object ref = alertStatus_;
-        if (ref instanceof String) {
-          com.google.protobuf.ByteString b = 
-              com.google.protobuf.ByteString.copyFromUtf8(
-                  (java.lang.String) ref);
-          alertStatus_ = b;
-          return b;
-        } else {
-          return (com.google.protobuf.ByteString) ref;
-        }
-      }
-      /**
-       * <code>optional string alert_status = 12;</code>
-       */
-      public Builder setAlertStatus(
-          java.lang.String value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  bitField0_ |= 0x00000200;
-        alertStatus_ = value;
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>optional string alert_status = 12;</code>
-       */
-      public Builder clearAlertStatus() {
-        bitField0_ = (bitField0_ & ~0x00000200);
-        alertStatus_ = getDefaultInstance().getAlertStatus();
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>optional string alert_status = 12;</code>
-       */
-      public Builder setAlertStatusBytes(
-          com.google.protobuf.ByteString value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  bitField0_ |= 0x00000200;
-        alertStatus_ = value;
-        onChanged();
-        return this;
-      }
-
-      private java.lang.Object alertText_ = "";
-      /**
-       * <code>optional string alert_text = 13;</code>
-       */
-      public boolean hasAlertText() {
-        return ((bitField0_ & 0x00000400) == 0x00000400);
-      }
-      /**
-       * <code>optional string alert_text = 13;</code>
-       */
-      public java.lang.String getAlertText() {
-        java.lang.Object ref = alertText_;
-        if (!(ref instanceof java.lang.String)) {
-          com.google.protobuf.ByteString bs =
-              (com.google.protobuf.ByteString) ref;
-          java.lang.String s = bs.toStringUtf8();
-          if (bs.isValidUtf8()) {
-            alertText_ = s;
-          }
-          return s;
-        } else {
-          return (java.lang.String) ref;
-        }
-      }
-      /**
-       * <code>optional string alert_text = 13;</code>
-       */
-      public com.google.protobuf.ByteString
-          getAlertTextBytes() {
-        java.lang.Object ref = alertText_;
-        if (ref instanceof String) {
-          com.google.protobuf.ByteString b = 
-              com.google.protobuf.ByteString.copyFromUtf8(
-                  (java.lang.String) ref);
-          alertText_ = b;
-          return b;
-        } else {
-          return (com.google.protobuf.ByteString) ref;
-        }
-      }
-      /**
-       * <code>optional string alert_text = 13;</code>
-       */
-      public Builder setAlertText(
-          java.lang.String value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  bitField0_ |= 0x00000400;
-        alertText_ = value;
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>optional string alert_text = 13;</code>
-       */
-      public Builder clearAlertText() {
-        bitField0_ = (bitField0_ & ~0x00000400);
-        alertText_ = getDefaultInstance().getAlertText();
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>optional string alert_text = 13;</code>
-       */
-      public Builder setAlertTextBytes(
-          com.google.protobuf.ByteString value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  bitField0_ |= 0x00000400;
-        alertText_ = value;
-        onChanged();
-        return this;
-      }
-
       private double variationValue1_ ;
       /**
        * <code>optional double variation_value_1 = 14;</code>
        */
       public boolean hasVariationValue1() {
-        return ((bitField0_ & 0x00000800) == 0x00000800);
+        return ((bitField0_ & 0x00000100) == 0x00000100);
       }
       /**
        * <code>optional double variation_value_1 = 14;</code>
@@ -5771,7 +5539,7 @@ public final class BatchReport {
        * <code>optional double variation_value_1 = 14;</code>
        */
       public Builder setVariationValue1(double value) {
-        bitField0_ |= 0x00000800;
+        bitField0_ |= 0x00000100;
         variationValue1_ = value;
         onChanged();
         return this;
@@ -5780,7 +5548,7 @@ public final class BatchReport {
        * <code>optional double variation_value_1 = 14;</code>
        */
       public Builder clearVariationValue1() {
-        bitField0_ = (bitField0_ & ~0x00000800);
+        bitField0_ = (bitField0_ & ~0x00000100);
         variationValue1_ = 0D;
         onChanged();
         return this;
@@ -5791,7 +5559,7 @@ public final class BatchReport {
        * <code>optional double variation_value_2 = 15;</code>
        */
       public boolean hasVariationValue2() {
-        return ((bitField0_ & 0x00001000) == 0x00001000);
+        return ((bitField0_ & 0x00000200) == 0x00000200);
       }
       /**
        * <code>optional double variation_value_2 = 15;</code>
@@ -5803,7 +5571,7 @@ public final class BatchReport {
        * <code>optional double variation_value_2 = 15;</code>
        */
       public Builder setVariationValue2(double value) {
-        bitField0_ |= 0x00001000;
+        bitField0_ |= 0x00000200;
         variationValue2_ = value;
         onChanged();
         return this;
@@ -5812,7 +5580,7 @@ public final class BatchReport {
        * <code>optional double variation_value_2 = 15;</code>
        */
       public Builder clearVariationValue2() {
-        bitField0_ = (bitField0_ & ~0x00001000);
+        bitField0_ = (bitField0_ & ~0x00000200);
         variationValue2_ = 0D;
         onChanged();
         return this;
@@ -5823,7 +5591,7 @@ public final class BatchReport {
        * <code>optional double variation_value_3 = 16;</code>
        */
       public boolean hasVariationValue3() {
-        return ((bitField0_ & 0x00002000) == 0x00002000);
+        return ((bitField0_ & 0x00000400) == 0x00000400);
       }
       /**
        * <code>optional double variation_value_3 = 16;</code>
@@ -5835,7 +5603,7 @@ public final class BatchReport {
        * <code>optional double variation_value_3 = 16;</code>
        */
       public Builder setVariationValue3(double value) {
-        bitField0_ |= 0x00002000;
+        bitField0_ |= 0x00000400;
         variationValue3_ = value;
         onChanged();
         return this;
@@ -5844,7 +5612,7 @@ public final class BatchReport {
        * <code>optional double variation_value_3 = 16;</code>
        */
       public Builder clearVariationValue3() {
-        bitField0_ = (bitField0_ & ~0x00002000);
+        bitField0_ = (bitField0_ & ~0x00000400);
         variationValue3_ = 0D;
         onChanged();
         return this;
@@ -5855,7 +5623,7 @@ public final class BatchReport {
        * <code>optional double variation_value_4 = 17;</code>
        */
       public boolean hasVariationValue4() {
-        return ((bitField0_ & 0x00004000) == 0x00004000);
+        return ((bitField0_ & 0x00000800) == 0x00000800);
       }
       /**
        * <code>optional double variation_value_4 = 17;</code>
@@ -5867,7 +5635,7 @@ public final class BatchReport {
        * <code>optional double variation_value_4 = 17;</code>
        */
       public Builder setVariationValue4(double value) {
-        bitField0_ |= 0x00004000;
+        bitField0_ |= 0x00000800;
         variationValue4_ = value;
         onChanged();
         return this;
@@ -5876,7 +5644,7 @@ public final class BatchReport {
        * <code>optional double variation_value_4 = 17;</code>
        */
       public Builder clearVariationValue4() {
-        bitField0_ = (bitField0_ & ~0x00004000);
+        bitField0_ = (bitField0_ & ~0x00000800);
         variationValue4_ = 0D;
         onChanged();
         return this;
@@ -5887,7 +5655,7 @@ public final class BatchReport {
        * <code>optional double variation_value_5 = 18;</code>
        */
       public boolean hasVariationValue5() {
-        return ((bitField0_ & 0x00008000) == 0x00008000);
+        return ((bitField0_ & 0x00001000) == 0x00001000);
       }
       /**
        * <code>optional double variation_value_5 = 18;</code>
@@ -5899,7 +5667,7 @@ public final class BatchReport {
        * <code>optional double variation_value_5 = 18;</code>
        */
       public Builder setVariationValue5(double value) {
-        bitField0_ |= 0x00008000;
+        bitField0_ |= 0x00001000;
         variationValue5_ = value;
         onChanged();
         return this;
@@ -5908,50 +5676,18 @@ public final class BatchReport {
        * <code>optional double variation_value_5 = 18;</code>
        */
       public Builder clearVariationValue5() {
-        bitField0_ = (bitField0_ & ~0x00008000);
+        bitField0_ = (bitField0_ & ~0x00001000);
         variationValue5_ = 0D;
         onChanged();
         return this;
       }
 
-      private int charactericId_ ;
-      /**
-       * <code>optional int32 characteric_id = 19;</code>
-       */
-      public boolean hasCharactericId() {
-        return ((bitField0_ & 0x00010000) == 0x00010000);
-      }
-      /**
-       * <code>optional int32 characteric_id = 19;</code>
-       */
-      public int getCharactericId() {
-        return charactericId_;
-      }
-      /**
-       * <code>optional int32 characteric_id = 19;</code>
-       */
-      public Builder setCharactericId(int value) {
-        bitField0_ |= 0x00010000;
-        charactericId_ = value;
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>optional int32 characteric_id = 19;</code>
-       */
-      public Builder clearCharactericId() {
-        bitField0_ = (bitField0_ & ~0x00010000);
-        charactericId_ = 0;
-        onChanged();
-        return this;
-      }
-
       private int personId_ ;
       /**
        * <code>optional int32 person_id = 20;</code>
        */
       public boolean hasPersonId() {
-        return ((bitField0_ & 0x00020000) == 0x00020000);
+        return ((bitField0_ & 0x00002000) == 0x00002000);
       }
       /**
        * <code>optional int32 person_id = 20;</code>
@@ -5963,7 +5699,7 @@ public final class BatchReport {
        * <code>optional int32 person_id = 20;</code>
        */
       public Builder setPersonId(int value) {
-        bitField0_ |= 0x00020000;
+        bitField0_ |= 0x00002000;
         personId_ = value;
         onChanged();
         return this;
@@ -5972,7 +5708,7 @@ public final class BatchReport {
        * <code>optional int32 person_id = 20;</code>
        */
       public Builder clearPersonId() {
-        bitField0_ = (bitField0_ & ~0x00020000);
+        bitField0_ = (bitField0_ & ~0x00002000);
         personId_ = 0;
         onChanged();
         return this;
@@ -19705,66 +19441,64 @@ public final class BatchReport {
       descriptor;
   static {
     java.lang.String[] descriptorData = {
-      "\n\022batch_report.proto\032\017constants.proto\"b\n" +
+      "\n\022batch_report.proto\032\017constants.proto\"{\n" +
       "\010Metadata\022\025\n\ranalysis_date\030\001 \001(\003\022\023\n\013proj" +
       "ect_key\030\002 \001(\t\022\016\n\006branch\030\003 \001(\t\022\032\n\022root_co" +
-      "mponent_ref\030\004 \001(\005\"?\n\rComponentLink\022 \n\004ty" +
-      "pe\030\001 \001(\0162\022.ComponentLinkType\022\014\n\004href\030\002 \001" +
-      "(\t\"\354\001\n\tComponent\022\013\n\003ref\030\001 \001(\005\022\014\n\004path\030\002 " +
-      "\001(\t\022\014\n\004name\030\003 \001(\t\022\034\n\004type\030\004 \001(\0162\016.Compon" +
-      "entType\022\017\n\007is_test\030\005 \001(\010\022\020\n\010language\030\006 \001" +
-      "(\t\022\025\n\tchild_ref\030\007 \003(\005B\002\020\001\022\034\n\004link\030\010 \003(\0132" +
-      "\016.ComponentLink\022\017\n\007version\030\t \001(\t\022\013\n\003key\030",
-      "\n \001(\t\022\r\n\005lines\030\013 \001(\005\022\023\n\013description\030\014 \001(" +
-      "\t\"\261\003\n\007Measure\022%\n\nvalue_type\030\001 \001(\0162\021.Meas" +
-      "ureValueType\022\025\n\rboolean_value\030\002 \001(\010\022\021\n\ti" +
-      "nt_value\030\003 \001(\005\022\022\n\nlong_value\030\004 \001(\003\022\024\n\014do" +
-      "uble_value\030\005 \001(\001\022\024\n\014string_value\030\006 \001(\t\022\022" +
-      "\n\nmetric_key\030\007 \001(\t\022\023\n\013description\030\t \001(\t\022" +
-      "\020\n\010rule_key\030\n \001(\t\022\024\n\014alert_status\030\014 \001(\t\022" +
-      "\022\n\nalert_text\030\r \001(\t\022\031\n\021variation_value_1" +
-      "\030\016 \001(\001\022\031\n\021variation_value_2\030\017 \001(\001\022\031\n\021var" +
-      "iation_value_3\030\020 \001(\001\022\031\n\021variation_value_",
-      "4\030\021 \001(\001\022\031\n\021variation_value_5\030\022 \001(\001\022\026\n\016ch" +
-      "aracteric_id\030\023 \001(\005\022\021\n\tperson_id\030\024 \001(\005\"<\n" +
-      "\010Measures\022\025\n\rcomponent_ref\030\001 \001(\005\022\031\n\007meas" +
-      "ure\030\002 \003(\0132\010.Measure\"\273\001\n\005Issue\022\027\n\017rule_re" +
-      "pository\030\001 \001(\t\022\020\n\010rule_key\030\002 \001(\t\022\014\n\004line" +
-      "\030\003 \001(\005\022\013\n\003msg\030\004 \001(\t\022\033\n\010severity\030\005 \001(\0162\t." +
-      "Severity\022\013\n\003tag\030\006 \003(\t\022\025\n\reffort_to_fix\030\007" +
-      " \001(\001\022\022\n\nattributes\030\010 \001(\t\022\027\n\017debt_in_minu" +
-      "tes\030\t \001(\003\"6\n\006Issues\022\025\n\rcomponent_ref\030\001 \001" +
-      "(\005\022\025\n\005issue\030\002 \003(\0132\006.Issue\"\254\001\n\nChangesets",
-      "\022\025\n\rcomponent_ref\030\001 \001(\005\022(\n\tchangeset\030\002 \003" +
-      "(\0132\025.Changesets.Changeset\022 \n\024changesetIn" +
-      "dexByLine\030\003 \003(\005B\002\020\001\032;\n\tChangeset\022\020\n\010revi" +
-      "sion\030\001 \001(\t\022\016\n\006author\030\002 \001(\t\022\014\n\004date\030\003 \001(\003" +
-      "\"R\n\tDuplicate\022\026\n\016other_file_ref\030\001 \001(\005\022\025\n" +
-      "\005range\030\002 \001(\0132\006.Range\022\026\n\016other_file_key\030\003" +
-      " \001(\t\"M\n\013Duplication\022\037\n\017origin_position\030\001" +
-      " \001(\0132\006.Range\022\035\n\tduplicate\030\002 \003(\0132\n.Duplic" +
-      "ate\"H\n\014Duplications\022\025\n\rcomponent_ref\030\001 \001" +
-      "(\005\022!\n\013duplication\030\002 \003(\0132\014.Duplication\"W\n",
-      "\005Range\022\022\n\nstart_line\030\001 \001(\005\022\020\n\010end_line\030\002" +
-      " \001(\005\022\024\n\014start_offset\030\003 \001(\005\022\022\n\nend_offset" +
-      "\030\004 \001(\005\"~\n\007Symbols\022\020\n\010file_ref\030\001 \001(\005\022\037\n\006s" +
-      "ymbol\030\002 \003(\0132\017.Symbols.Symbol\032@\n\006Symbol\022\033" +
-      "\n\013declaration\030\001 \001(\0132\006.Range\022\031\n\treference" +
-      "\030\002 \003(\0132\006.Range\"\260\001\n\010Coverage\022\014\n\004line\030\001 \001(" +
-      "\005\022\022\n\nconditions\030\002 \001(\005\022\017\n\007ut_hits\030\003 \001(\010\022\017" +
-      "\n\007it_hits\030\004 \001(\010\022\035\n\025ut_covered_conditions" +
-      "\030\005 \001(\005\022\035\n\025it_covered_conditions\030\006 \001(\005\022\"\n" +
-      "\032overall_covered_conditions\030\007 \001(\005\"L\n\022Syn",
-      "taxHighlighting\022\025\n\005range\030\001 \001(\0132\006.Range\022\037" +
-      "\n\004type\030\002 \001(\0162\021.HighlightingType\"j\n\004Test\022" +
-      "\014\n\004name\030\001 \001(\t\022\033\n\006status\030\002 \001(\0162\013.TestStat" +
-      "us\022\026\n\016duration_in_ms\030\003 \001(\003\022\022\n\nstacktrace" +
-      "\030\004 \001(\t\022\013\n\003msg\030\005 \001(\t\"\221\001\n\016CoverageDetail\022\021" +
-      "\n\ttest_name\030\001 \001(\t\0221\n\014covered_file\030\002 \003(\0132" +
-      "\033.CoverageDetail.CoveredFile\0329\n\013CoveredF" +
-      "ile\022\020\n\010file_ref\030\001 \001(\005\022\030\n\014covered_line\030\002 " +
-      "\003(\005B\002\020\001B#\n\037org.sonar.batch.protocol.outp" +
-      "utH\001"
+      "mponent_ref\030\004 \001(\005\022\027\n\017active_rule_key\030\005 \003" +
+      "(\t\"?\n\rComponentLink\022 \n\004type\030\001 \001(\0162\022.Comp" +
+      "onentLinkType\022\014\n\004href\030\002 \001(\t\"\354\001\n\tComponen" +
+      "t\022\013\n\003ref\030\001 \001(\005\022\014\n\004path\030\002 \001(\t\022\014\n\004name\030\003 \001" +
+      "(\t\022\034\n\004type\030\004 \001(\0162\016.ComponentType\022\017\n\007is_t" +
+      "est\030\005 \001(\010\022\020\n\010language\030\006 \001(\t\022\025\n\tchild_ref" +
+      "\030\007 \003(\005B\002\020\001\022\034\n\004link\030\010 \003(\0132\016.ComponentLink",
+      "\022\017\n\007version\030\t \001(\t\022\013\n\003key\030\n \001(\t\022\r\n\005lines\030" +
+      "\013 \001(\005\022\023\n\013description\030\014 \001(\t\"\335\002\n\007Measure\022%" +
+      "\n\nvalue_type\030\001 \001(\0162\021.MeasureValueType\022\025\n" +
+      "\rboolean_value\030\002 \001(\010\022\021\n\tint_value\030\003 \001(\005\022" +
+      "\022\n\nlong_value\030\004 \001(\003\022\024\n\014double_value\030\005 \001(" +
+      "\001\022\024\n\014string_value\030\006 \001(\t\022\022\n\nmetric_key\030\007 " +
+      "\001(\t\022\023\n\013description\030\t \001(\t\022\031\n\021variation_va" +
+      "lue_1\030\016 \001(\001\022\031\n\021variation_value_2\030\017 \001(\001\022\031" +
+      "\n\021variation_value_3\030\020 \001(\001\022\031\n\021variation_v" +
+      "alue_4\030\021 \001(\001\022\031\n\021variation_value_5\030\022 \001(\001\022",
+      "\021\n\tperson_id\030\024 \001(\005\"<\n\010Measures\022\025\n\rcompon" +
+      "ent_ref\030\001 \001(\005\022\031\n\007measure\030\002 \003(\0132\010.Measure" +
+      "\"\273\001\n\005Issue\022\027\n\017rule_repository\030\001 \001(\t\022\020\n\010r" +
+      "ule_key\030\002 \001(\t\022\014\n\004line\030\003 \001(\005\022\013\n\003msg\030\004 \001(\t" +
+      "\022\033\n\010severity\030\005 \001(\0162\t.Severity\022\013\n\003tag\030\006 \003" +
+      "(\t\022\025\n\reffort_to_fix\030\007 \001(\001\022\022\n\nattributes\030" +
+      "\010 \001(\t\022\027\n\017debt_in_minutes\030\t \001(\003\"6\n\006Issues" +
+      "\022\025\n\rcomponent_ref\030\001 \001(\005\022\025\n\005issue\030\002 \003(\0132\006" +
+      ".Issue\"\254\001\n\nChangesets\022\025\n\rcomponent_ref\030\001" +
+      " \001(\005\022(\n\tchangeset\030\002 \003(\0132\025.Changesets.Cha",
+      "ngeset\022 \n\024changesetIndexByLine\030\003 \003(\005B\002\020\001" +
+      "\032;\n\tChangeset\022\020\n\010revision\030\001 \001(\t\022\016\n\006autho" +
+      "r\030\002 \001(\t\022\014\n\004date\030\003 \001(\003\"R\n\tDuplicate\022\026\n\016ot" +
+      "her_file_ref\030\001 \001(\005\022\025\n\005range\030\002 \001(\0132\006.Rang" +
+      "e\022\026\n\016other_file_key\030\003 \001(\t\"M\n\013Duplication" +
+      "\022\037\n\017origin_position\030\001 \001(\0132\006.Range\022\035\n\tdup" +
+      "licate\030\002 \003(\0132\n.Duplicate\"H\n\014Duplications" +
+      "\022\025\n\rcomponent_ref\030\001 \001(\005\022!\n\013duplication\030\002" +
+      " \003(\0132\014.Duplication\"W\n\005Range\022\022\n\nstart_lin" +
+      "e\030\001 \001(\005\022\020\n\010end_line\030\002 \001(\005\022\024\n\014start_offse",
+      "t\030\003 \001(\005\022\022\n\nend_offset\030\004 \001(\005\"~\n\007Symbols\022\020" +
+      "\n\010file_ref\030\001 \001(\005\022\037\n\006symbol\030\002 \003(\0132\017.Symbo" +
+      "ls.Symbol\032@\n\006Symbol\022\033\n\013declaration\030\001 \001(\013" +
+      "2\006.Range\022\031\n\treference\030\002 \003(\0132\006.Range\"\260\001\n\010" +
+      "Coverage\022\014\n\004line\030\001 \001(\005\022\022\n\nconditions\030\002 \001" +
+      "(\005\022\017\n\007ut_hits\030\003 \001(\010\022\017\n\007it_hits\030\004 \001(\010\022\035\n\025" +
+      "ut_covered_conditions\030\005 \001(\005\022\035\n\025it_covere" +
+      "d_conditions\030\006 \001(\005\022\"\n\032overall_covered_co" +
+      "nditions\030\007 \001(\005\"L\n\022SyntaxHighlighting\022\025\n\005" +
+      "range\030\001 \001(\0132\006.Range\022\037\n\004type\030\002 \001(\0162\021.High",
+      "lightingType\"j\n\004Test\022\014\n\004name\030\001 \001(\t\022\033\n\006st" +
+      "atus\030\002 \001(\0162\013.TestStatus\022\026\n\016duration_in_m" +
+      "s\030\003 \001(\003\022\022\n\nstacktrace\030\004 \001(\t\022\013\n\003msg\030\005 \001(\t" +
+      "\"\221\001\n\016CoverageDetail\022\021\n\ttest_name\030\001 \001(\t\0221" +
+      "\n\014covered_file\030\002 \003(\0132\033.CoverageDetail.Co" +
+      "veredFile\0329\n\013CoveredFile\022\020\n\010file_ref\030\001 \001" +
+      "(\005\022\030\n\014covered_line\030\002 \003(\005B\002\020\001B#\n\037org.sona" +
+      "r.batch.protocol.outputH\001"
     };
     com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
         new com.google.protobuf.Descriptors.FileDescriptor.    InternalDescriptorAssigner() {
@@ -19784,7 +19518,7 @@ public final class BatchReport {
     internal_static_Metadata_fieldAccessorTable = new
       com.google.protobuf.GeneratedMessage.FieldAccessorTable(
         internal_static_Metadata_descriptor,
-        new java.lang.String[] { "AnalysisDate", "ProjectKey", "Branch", "RootComponentRef", });
+        new java.lang.String[] { "AnalysisDate", "ProjectKey", "Branch", "RootComponentRef", "ActiveRuleKey", });
     internal_static_ComponentLink_descriptor =
       getDescriptor().getMessageTypes().get(1);
     internal_static_ComponentLink_fieldAccessorTable = new
@@ -19802,7 +19536,7 @@ public final class BatchReport {
     internal_static_Measure_fieldAccessorTable = new
       com.google.protobuf.GeneratedMessage.FieldAccessorTable(
         internal_static_Measure_descriptor,
-        new java.lang.String[] { "ValueType", "BooleanValue", "IntValue", "LongValue", "DoubleValue", "StringValue", "MetricKey", "Description", "RuleKey", "AlertStatus", "AlertText", "VariationValue1", "VariationValue2", "VariationValue3", "VariationValue4", "VariationValue5", "CharactericId", "PersonId", });
+        new java.lang.String[] { "ValueType", "BooleanValue", "IntValue", "LongValue", "DoubleValue", "StringValue", "MetricKey", "Description", "VariationValue1", "VariationValue2", "VariationValue3", "VariationValue4", "VariationValue5", "PersonId", });
     internal_static_Measures_descriptor =
       getDescriptor().getMessageTypes().get(4);
     internal_static_Measures_fieldAccessorTable = new
index 0ecee214e9318cb1b99dce5f00788b5fbc451e11..361c0419fff471a334c8dcf61a76efe8c7236b43 100644 (file)
@@ -45,6 +45,13 @@ message Metadata {
   optional string project_key = 2;
   optional string branch = 3;
   optional int32 root_component_ref = 4;
+
+  /*
+    Keys of the rules that were enabled in Quality profiles.
+    A key is a string composed of the repository and the subKey, specific to the repository. Format is
+    "{repository}:{subKey}", for instance "java:NullDereference".
+  */
+  repeated string active_rule_key = 5;
 }
 
 message ComponentLink {
@@ -84,15 +91,11 @@ message Measure {
 
   // temporary fields during development of computation stack
   optional string description = 9;
-  optional string rule_key = 10;
-  optional string alert_status = 12;
-  optional string alert_text = 13;
   optional double variation_value_1 = 14;
   optional double variation_value_2 = 15;
   optional double variation_value_3 = 16;
   optional double variation_value_4 = 17;
   optional double variation_value_5 = 18;
-  optional int32 characteric_id = 19;
   optional int32 person_id = 20;
 }
 
index 58a2e630d3c851de716901ddde7be1ed11d75cc0..53b2f2c1bb10b264511a88ef0621fcf25c9d27e4 100644 (file)
@@ -37,8 +37,6 @@ import org.sonar.batch.compute.OverallCoverageDecorator;
 import org.sonar.batch.compute.OverallLineCoverageDecorator;
 import org.sonar.batch.compute.UnitTestDecorator;
 import org.sonar.batch.cpd.CpdComponents;
-import org.sonar.batch.debt.IssueChangelogDebtCalculator;
-import org.sonar.batch.debt.NewDebtDecorator;
 import org.sonar.batch.issue.tracking.IssueTracking;
 import org.sonar.batch.language.LanguageDistributionDecorator;
 import org.sonar.batch.scan.report.ConsoleReport;
@@ -83,10 +81,6 @@ public class BatchComponents {
       // language
       LanguageDistributionDecorator.class,
 
-      // Debt
-      IssueChangelogDebtCalculator.class,
-      NewDebtDecorator.class,
-
       // to be moved to compute engine
       UnitTestDecorator.class,
       LineCoverageDecorator.class,
diff --git a/sonar-batch/src/main/java/org/sonar/batch/debt/DebtModelProvider.java b/sonar-batch/src/main/java/org/sonar/batch/debt/DebtModelProvider.java
deleted file mode 100644 (file)
index dc95f8e..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-package org.sonar.batch.debt;
-
-import com.google.common.base.Predicate;
-import com.google.common.collect.Iterables;
-import java.util.List;
-import javax.annotation.Nullable;
-import org.picocontainer.injectors.ProviderAdapter;
-import org.sonar.api.batch.debt.DebtCharacteristic;
-import org.sonar.api.batch.debt.DebtModel;
-import org.sonar.api.batch.debt.internal.DefaultDebtCharacteristic;
-import org.sonar.api.batch.debt.internal.DefaultDebtModel;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.api.utils.log.Profiler;
-import org.sonar.core.technicaldebt.db.CharacteristicDao;
-import org.sonar.core.technicaldebt.db.CharacteristicDto;
-
-public class DebtModelProvider extends ProviderAdapter {
-
-  private DebtModel model;
-
-  public DebtModel provide(CharacteristicDao dao) {
-    if (model == null) {
-      Profiler profiler = Profiler.create(Loggers.get(getClass())).startInfo("Load technical debt model");
-      model = load(dao);
-      profiler.stopDebug();
-    }
-    return model;
-  }
-
-  private static DebtModel load(CharacteristicDao dao) {
-    DefaultDebtModel debtModel = new DefaultDebtModel();
-
-    List<CharacteristicDto> allCharacteristics = dao.selectEnabledCharacteristics();
-    for (CharacteristicDto dto : allCharacteristics) {
-      Integer parentId = dto.getParentId();
-      if (parentId == null) {
-        debtModel.addCharacteristic(toDebtCharacteristic(dto));
-      } else {
-        debtModel.addSubCharacteristic(toDebtCharacteristic(dto), characteristicById(parentId, allCharacteristics).getKey());
-      }
-    }
-    return debtModel;
-  }
-
-  private static CharacteristicDto characteristicById(final int id, List<CharacteristicDto> allCharacteristics) {
-    return Iterables.find(allCharacteristics, new Predicate<CharacteristicDto>() {
-      @Override
-      public boolean apply(@Nullable CharacteristicDto input) {
-        return input != null && id == input.getId();
-      }
-    });
-  }
-
-  private static DebtCharacteristic toDebtCharacteristic(CharacteristicDto characteristic) {
-    return new DefaultDebtCharacteristic()
-      .setId(characteristic.getId())
-      .setKey(characteristic.getKey())
-      .setName(characteristic.getName())
-      .setOrder(characteristic.getOrder())
-      .setParentId(characteristic.getParentId());
-  }
-
-}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/debt/IssueChangelogDebtCalculator.java b/sonar-batch/src/main/java/org/sonar/batch/debt/IssueChangelogDebtCalculator.java
deleted file mode 100644 (file)
index 5d34e8f..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-package org.sonar.batch.debt;
-
-import com.google.common.base.Function;
-import com.google.common.collect.Ordering;
-import java.util.Calendar;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import org.apache.commons.lang.time.DateUtils;
-import org.sonar.api.batch.BatchSide;
-import org.sonar.api.issue.Issue;
-import org.sonar.core.issue.DefaultIssue;
-import org.sonar.core.issue.FieldDiffs;
-import org.sonar.core.issue.IssueUpdater;
-
-import static com.google.common.collect.Lists.newArrayList;
-
-/**
- * Warning, before modifying this class, please do not forget that it's used by the Dev Cockpit plugin
- */
-@BatchSide
-public class IssueChangelogDebtCalculator {
-
-  @CheckForNull
-  public Long calculateNewTechnicalDebt(Issue issue, @Nullable Date periodDate) {
-    Long debt = ((DefaultIssue) issue).debtInMinutes();
-    Date periodDatePlusOneSecond = periodDate != null ? DateUtils.addSeconds(periodDate, 1) : null;
-    if (isAfter(issue.creationDate(), periodDatePlusOneSecond)) {
-      return debt;
-    } else {
-      return calculateNewTechnicalDebtValueFromChangelog(debt, issue, periodDate);
-    }
-  }
-
-  @CheckForNull
-  private Long calculateNewTechnicalDebtValueFromChangelog(@Nullable Long currentTechnicalDebtValue, Issue issue, Date periodDate) {
-    List<FieldDiffs> changelog = technicalDebtHistory(issue);
-    for (Iterator<FieldDiffs> iterator = changelog.iterator(); iterator.hasNext();) {
-      FieldDiffs diff = iterator.next();
-      Date date = diff.creationDate();
-      if (isLesserOrEqual(date, periodDate)) {
-        // return new value from the change that is just before the period date
-        return subtractNeverNegative(currentTechnicalDebtValue, newValue(diff));
-      }
-      if (!iterator.hasNext()) {
-        // return old value from the change that is just after the period date when there's no more element in changelog
-        return subtractNeverNegative(currentTechnicalDebtValue, oldValue(diff));
-      }
-    }
-    // Return null when no changelog
-    return null;
-  }
-
-  /**
-   * SONAR-5059
-   */
-  @CheckForNull
-  private static Long subtractNeverNegative(@Nullable Long value, @Nullable Long with) {
-    Long result = (value != null ? value : 0) - (with != null ? with : 0);
-    return result > 0 ? result : null;
-  }
-
-  private List<FieldDiffs> technicalDebtHistory(Issue issue) {
-    List<FieldDiffs> technicalDebtChangelog = changesOnField(((DefaultIssue) issue).changes());
-    if (!technicalDebtChangelog.isEmpty()) {
-      // Changelog have to be sorted from newest to oldest.
-      // Null date should be the first as this happen when technical debt has changed since previous analysis.
-      Ordering<FieldDiffs> ordering = Ordering.natural().reverse().nullsFirst().onResultOf(new Function<FieldDiffs, Date>() {
-        @Override
-        public Date apply(FieldDiffs diff) {
-          return diff.creationDate();
-        }
-      });
-      return ordering.immutableSortedCopy(technicalDebtChangelog);
-    }
-    return Collections.emptyList();
-  }
-
-  private static List<FieldDiffs> changesOnField(Collection<FieldDiffs> fieldDiffs) {
-    List<FieldDiffs> diffs = newArrayList();
-    for (FieldDiffs fieldDiff : fieldDiffs) {
-      if (fieldDiff.diffs().containsKey(IssueUpdater.TECHNICAL_DEBT)) {
-        diffs.add(fieldDiff);
-      }
-    }
-    return diffs;
-  }
-
-  @CheckForNull
-  private static Long newValue(FieldDiffs fieldDiffs) {
-    for (Map.Entry<String, FieldDiffs.Diff> entry : fieldDiffs.diffs().entrySet()) {
-      if (entry.getKey().equals(IssueUpdater.TECHNICAL_DEBT)) {
-        return entry.getValue().newValueLong();
-      }
-    }
-    return null;
-  }
-
-  @CheckForNull
-  private static Long oldValue(FieldDiffs fieldDiffs) {
-    for (Map.Entry<String, FieldDiffs.Diff> entry : fieldDiffs.diffs().entrySet()) {
-      if (entry.getKey().equals(IssueUpdater.TECHNICAL_DEBT)) {
-        return entry.getValue().oldValueLong();
-      }
-    }
-    return null;
-  }
-
-  private static boolean isAfter(@Nullable Date currentDate, @Nullable Date pastDate) {
-    return pastDate == null || (currentDate != null && DateUtils.truncatedCompareTo(currentDate, pastDate, Calendar.SECOND) > 0);
-  }
-
-  private static boolean isLesserOrEqual(@Nullable Date currentDate, @Nullable Date pastDate) {
-    return (currentDate != null) && (pastDate == null || (DateUtils.truncatedCompareTo(currentDate, pastDate, Calendar.SECOND) <= 0));
-  }
-
-}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/debt/NewDebtDecorator.java b/sonar-batch/src/main/java/org/sonar/batch/debt/NewDebtDecorator.java
deleted file mode 100644 (file)
index c334520..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-package org.sonar.batch.debt;
-
-import com.google.common.collect.ImmutableList;
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-import javax.annotation.Nullable;
-import org.sonar.api.batch.Decorator;
-import org.sonar.api.batch.DecoratorBarriers;
-import org.sonar.api.batch.DecoratorContext;
-import org.sonar.api.batch.DependedUpon;
-import org.sonar.api.batch.DependsUpon;
-import org.sonar.api.batch.RequiresDB;
-import org.sonar.api.component.ResourcePerspectives;
-import org.sonar.api.issue.Issuable;
-import org.sonar.api.issue.Issue;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.measures.Measure;
-import org.sonar.api.measures.MeasureUtils;
-import org.sonar.api.measures.Metric;
-import org.sonar.api.resources.Project;
-import org.sonar.api.resources.Resource;
-import org.sonar.batch.components.Period;
-import org.sonar.batch.components.TimeMachineConfiguration;
-
-import static com.google.common.collect.Lists.newArrayList;
-
-/**
- * Decorator that computes the technical debt metric
- */
-@RequiresDB
-@DependsUpon(DecoratorBarriers.ISSUES_TRACKED)
-public final class NewDebtDecorator implements Decorator {
-
-  private final ResourcePerspectives perspectives;
-  private final TimeMachineConfiguration timeMachineConfiguration;
-  private final IssueChangelogDebtCalculator issueChangelogDebtCalculator;
-
-  public NewDebtDecorator(ResourcePerspectives perspectives, TimeMachineConfiguration timeMachineConfiguration,
-    IssueChangelogDebtCalculator issueChangelogDebtCalculator) {
-    this.perspectives = perspectives;
-    this.timeMachineConfiguration = timeMachineConfiguration;
-    this.issueChangelogDebtCalculator = issueChangelogDebtCalculator;
-  }
-
-  @Override
-  public boolean shouldExecuteOnProject(Project project) {
-    return true;
-  }
-
-  @DependedUpon
-  public List<Metric> generatesMetrics() {
-    return ImmutableList.<Metric>of(
-      CoreMetrics.NEW_TECHNICAL_DEBT
-      );
-  }
-
-  @Override
-  public void decorate(Resource resource, DecoratorContext context) {
-    Issuable issuable = perspectives.as(Issuable.class, resource);
-    if (issuable != null && shouldSaveNewMetrics(context)) {
-      List<Issue> issues = newArrayList(issuable.issues());
-      saveMeasures(context, issues);
-    }
-  }
-
-  private void saveMeasures(DecoratorContext context, Collection<Issue> issues) {
-    Measure measure = new Measure(CoreMetrics.NEW_TECHNICAL_DEBT);
-    for (Period period : timeMachineConfiguration.periods()) {
-      Date periodDate = period.getDate();
-      double value = calculateNewTechnicalDebtValue(issues, periodDate);
-      Collection<Measure> children = context.getChildrenMeasures(measure.getMetric());
-      double sum = MeasureUtils.sumOnVariation(true, period.getIndex(), children) + value;
-      measure.setVariation(period.getIndex(), sum);
-    }
-    context.saveMeasure(measure);
-  }
-
-  private long calculateNewTechnicalDebtValue(Collection<Issue> issues, @Nullable Date periodDate) {
-    long result = 0;
-    for (Issue issue : issues) {
-      Long debt = issueChangelogDebtCalculator.calculateNewTechnicalDebt(issue, periodDate);
-      if (debt != null) {
-        result += debt;
-      }
-    }
-    return result;
-  }
-
-  private static boolean shouldSaveNewMetrics(DecoratorContext context) {
-    return context.getMeasure(CoreMetrics.NEW_TECHNICAL_DEBT) == null;
-  }
-
-}
index 23fa523df443fca9e2c7404cd263ff48e1609a72..2ff7190907b2ecccbdb44fa21a26f8b7112efc4d 100644 (file)
@@ -28,12 +28,12 @@ import org.sonar.api.batch.rule.ActiveRules;
 import org.sonar.api.batch.rule.Rule;
 import org.sonar.api.batch.rule.Rules;
 import org.sonar.api.batch.rule.internal.DefaultActiveRule;
-import org.sonar.core.issue.DefaultIssue;
 import org.sonar.api.resources.Project;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rules.Violation;
 import org.sonar.api.utils.Duration;
 import org.sonar.api.utils.MessageException;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.core.issue.DefaultIssueBuilder;
 
 /**
@@ -120,7 +120,7 @@ public class ModuleIssues {
     }
     if (rule != null) {
       DebtRemediationFunction function = rule.debtRemediationFunction();
-      if (rule.debtSubCharacteristic() != null && function != null) {
+      if (function != null) {
         issue.setDebt(calculateDebt(function, issue.effortToFix(), rule.key()));
       }
     }
index 733e41d26a1cb6b2feefae17e32f6d3fad293b96..729e4d7cff1b4334e2a50a12d4de13835b562aa5 100644 (file)
@@ -143,7 +143,7 @@ public class LocalIssueTracking {
       if (file == null) {
         throw new IllegalStateException("Resource " + component.resource() + " was not found in InputPath cache");
       }
-      sourceHashHolder = new SourceHashHolder((DefaultInputFile) file, lastLineHashes);
+      sourceHashHolder = new SourceHashHolder(file, lastLineHashes);
     }
     return sourceHashHolder;
   }
index 0377b3e08897475db8f29095b3244a2c6da0fe9a..9c56d2404afe9748d814a2a308f81081f8ea0082 100644 (file)
@@ -21,9 +21,6 @@ package org.sonar.batch.report;
 
 import com.google.common.base.Function;
 import com.google.common.collect.Iterables;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.batch.bootstrap.ProjectDefinition;
-import org.sonar.api.resources.Project;
 import org.sonar.api.utils.KeyValueFormat;
 import org.sonar.batch.index.BatchComponent;
 import org.sonar.batch.index.BatchComponentCache;
@@ -31,19 +28,17 @@ import org.sonar.batch.issue.IssueCache;
 import org.sonar.batch.protocol.Constants;
 import org.sonar.batch.protocol.output.BatchReport;
 import org.sonar.batch.protocol.output.BatchReportWriter;
-import org.sonar.batch.scan.ImmutableProjectReactor;
 import org.sonar.core.issue.DefaultIssue;
 
 public class IssuesPublisher implements ReportPublisherStep {
 
   private final BatchComponentCache componentCache;
   private final IssueCache issueCache;
-  private final ImmutableProjectReactor reactor;
 
-  public IssuesPublisher(ImmutableProjectReactor reactor, BatchComponentCache componentCache, IssueCache issueCache) {
-    this.reactor = reactor;
+  public IssuesPublisher(BatchComponentCache componentCache, IssueCache issueCache) {
     this.componentCache = componentCache;
     this.issueCache = issueCache;
+
   }
 
   @Override
@@ -60,23 +55,6 @@ public class IssuesPublisher implements ReportPublisherStep {
         }
       }));
     }
-
-    exportMetadata(writer);
-  }
-
-  private void exportMetadata(BatchReportWriter writer) {
-    ProjectDefinition root = reactor.getRoot();
-    BatchComponent rootProject = componentCache.getRoot();
-    BatchReport.Metadata.Builder builder = BatchReport.Metadata.newBuilder()
-      .setAnalysisDate(((Project) rootProject.resource()).getAnalysisDate().getTime())
-      // Here we want key without branch
-      .setProjectKey(root.getKey())
-      .setRootComponentRef(rootProject.batchId());
-    String branch = root.properties().get(CoreProperties.PROJECT_BRANCH_PROPERTY);
-    if (branch != null) {
-      builder.setBranch(branch);
-    }
-    writer.writeMetadata(builder.build());
   }
 
   private BatchReport.Issue toReportIssue(BatchReport.Issue.Builder builder, DefaultIssue issue) {
index 9aad7276659c75c35427cdaa21e71a90ca847516..8a8ae99436a9de88e1d59cd4ec267cea8a587764 100644 (file)
@@ -26,14 +26,10 @@ import com.google.common.collect.Iterables;
 import java.io.Serializable;
 import javax.annotation.Nullable;
 import org.sonar.api.measures.Measure;
-import org.sonar.api.measures.Metric.Level;
 import org.sonar.api.measures.Metric.ValueType;
 import org.sonar.api.measures.MetricFinder;
-import org.sonar.api.measures.RuleMeasure;
 import org.sonar.api.resources.Resource;
 import org.sonar.api.resources.ResourceUtils;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.technicaldebt.batch.Characteristic;
 import org.sonar.batch.index.BatchComponent;
 import org.sonar.batch.index.BatchComponentCache;
 import org.sonar.batch.protocol.Constants.MeasureValueType;
@@ -111,14 +107,6 @@ public class MeasuresPublisher implements ReportPublisherStep {
     if (description != null) {
       builder.setDescription(description);
     }
-    Level alertStatus = measure.getAlertStatus();
-    if (alertStatus != null) {
-      builder.setAlertStatus(alertStatus.toString());
-    }
-    String alertText = measure.getAlertText();
-    if (alertText != null) {
-      builder.setAlertText(alertText);
-    }
     Double variation1 = measure.getVariation1();
     if (variation1 != null) {
       builder.setVariationValue1(variation1);
@@ -139,10 +127,6 @@ public class MeasuresPublisher implements ReportPublisherStep {
     if (variation5 != null) {
       builder.setVariationValue5(variation5);
     }
-    Characteristic charac = measure.getCharacteristic();
-    if (charac != null) {
-      builder.setCharactericId(charac.id());
-    }
     Integer personId = measure.getPersonId();
     if (personId != null) {
       builder.setPersonId(personId);
diff --git a/sonar-batch/src/main/java/org/sonar/batch/report/MetadataPublisher.java b/sonar-batch/src/main/java/org/sonar/batch/report/MetadataPublisher.java
new file mode 100644 (file)
index 0000000..d5c4152
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.batch.report;
+
+import com.google.common.base.Function;
+import javax.annotation.Nonnull;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.batch.bootstrap.ProjectDefinition;
+import org.sonar.api.batch.rule.ActiveRule;
+import org.sonar.api.batch.rule.ActiveRules;
+import org.sonar.api.resources.Project;
+import org.sonar.batch.index.BatchComponent;
+import org.sonar.batch.index.BatchComponentCache;
+import org.sonar.batch.protocol.output.BatchReport;
+import org.sonar.batch.protocol.output.BatchReportWriter;
+import org.sonar.batch.scan.ImmutableProjectReactor;
+
+import static com.google.common.collect.FluentIterable.from;
+
+public class MetadataPublisher implements ReportPublisherStep {
+
+  private final BatchComponentCache componentCache;
+  private final ImmutableProjectReactor reactor;
+  private final ActiveRules activeRules;
+
+  public MetadataPublisher(BatchComponentCache componentCache, ImmutableProjectReactor reactor, ActiveRules activeRules) {
+    this.componentCache = componentCache;
+    this.reactor = reactor;
+    this.activeRules = activeRules;
+  }
+
+  @Override
+  public void publish(BatchReportWriter writer) {
+    ProjectDefinition root = reactor.getRoot();
+    BatchComponent rootProject = componentCache.getRoot();
+    BatchReport.Metadata.Builder builder = BatchReport.Metadata.newBuilder()
+      .setAnalysisDate(((Project) rootProject.resource()).getAnalysisDate().getTime())
+      // Here we want key without branch
+      .setProjectKey(root.getKey())
+      .setRootComponentRef(rootProject.batchId());
+    String branch = root.properties().get(CoreProperties.PROJECT_BRANCH_PROPERTY);
+    if (branch != null) {
+      builder.setBranch(branch);
+    }
+    builder.addAllActiveRuleKey(from(activeRules.findAll()).transform(ToRuleKey.INSTANCE));
+    writer.writeMetadata(builder.build());
+  }
+
+  private enum ToRuleKey implements Function<ActiveRule, String> {
+    INSTANCE;
+    @Nonnull
+    @Override
+    public String apply(@Nonnull ActiveRule input) {
+      return input.ruleKey().toString();
+    }
+  }
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/rule/RulesProvider.java b/sonar-batch/src/main/java/org/sonar/batch/rule/RulesProvider.java
deleted file mode 100644 (file)
index 9a8af6d..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-package org.sonar.batch.rule;
-
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.ListMultimap;
-import java.util.List;
-import javax.annotation.Nullable;
-import org.picocontainer.injectors.ProviderAdapter;
-import org.sonar.api.batch.debt.DebtCharacteristic;
-import org.sonar.api.batch.debt.DebtModel;
-import org.sonar.api.batch.debt.DebtRemediationFunction;
-import org.sonar.api.batch.debt.internal.DefaultDebtModel;
-import org.sonar.api.batch.rule.Rules;
-import org.sonar.api.batch.rule.internal.NewRule;
-import org.sonar.api.batch.rule.internal.RulesBuilder;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.utils.Durations;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.api.utils.log.Profiler;
-import org.sonar.core.rule.RuleDao;
-import org.sonar.core.rule.RuleDto;
-import org.sonar.core.rule.RuleParamDto;
-
-/**
- * Loads all enabled and non manual rules
- */
-public class RulesProvider extends ProviderAdapter {
-
-  private Rules singleton = null;
-
-  public Rules provide(RuleDao ruleDao, DebtModel debtModel, Durations durations) {
-    if (singleton == null) {
-      Profiler profiler = Profiler.create(Loggers.get(getClass())).startInfo("Load rules");
-      singleton = load(ruleDao, (DefaultDebtModel) debtModel, durations);
-      profiler.stopDebug();
-    }
-    return singleton;
-  }
-
-  private Rules load(RuleDao ruleDao, DefaultDebtModel debtModel, Durations durations) {
-    RulesBuilder rulesBuilder = new RulesBuilder();
-
-    List<RuleParamDto> ruleParamDtos = ruleDao.selectParameters();
-    ListMultimap<Integer, RuleParamDto> paramDtosByRuleId = ArrayListMultimap.create();
-    for (RuleParamDto dto : ruleParamDtos) {
-      paramDtosByRuleId.put(dto.getRuleId(), dto);
-    }
-    for (RuleDto ruleDto : ruleDao.selectEnablesAndNonManual()) {
-      RuleKey ruleKey = RuleKey.of(ruleDto.getRepositoryKey(), ruleDto.getRuleKey());
-      NewRule newRule = rulesBuilder.add(ruleKey)
-        .setId(ruleDto.getId())
-        .setName(ruleDto.getName())
-        .setSeverity(ruleDto.getSeverityString())
-        .setDescription(ruleDto.getDescription())
-        .setStatus(ruleDto.getStatus())
-        .setInternalKey(ruleDto.getConfigKey());
-
-      if (hasCharacteristic(ruleDto)) {
-        newRule.setDebtSubCharacteristic(effectiveCharacteristic(ruleDto, ruleKey, debtModel).key());
-        newRule.setDebtRemediationFunction(effectiveFunction(ruleDto, ruleKey, durations));
-      }
-
-      for (RuleParamDto ruleParamDto : paramDtosByRuleId.get(ruleDto.getId())) {
-        newRule.addParam(ruleParamDto.getName())
-          .setDescription(ruleParamDto.getDescription());
-      }
-    }
-    return rulesBuilder.build();
-  }
-
-  private static DebtCharacteristic effectiveCharacteristic(RuleDto ruleDto, RuleKey ruleKey, DefaultDebtModel debtModel) {
-    Integer subCharacteristicId = ruleDto.getSubCharacteristicId();
-    Integer defaultSubCharacteristicId = ruleDto.getDefaultSubCharacteristicId();
-    Integer effectiveSubCharacteristicId = subCharacteristicId != null ? subCharacteristicId : defaultSubCharacteristicId;
-    DebtCharacteristic subCharacteristic = debtModel.characteristicById(effectiveSubCharacteristicId);
-    if (subCharacteristic == null) {
-      throw new IllegalStateException(String.format("Sub characteristic id '%s' on rule '%s' has not been found", effectiveSubCharacteristicId, ruleKey));
-    }
-    return subCharacteristic;
-  }
-
-  private DebtRemediationFunction effectiveFunction(RuleDto ruleDto, RuleKey ruleKey, Durations durations) {
-    String function = ruleDto.getRemediationFunction();
-    String defaultFunction = ruleDto.getDefaultRemediationFunction();
-    if (function != null) {
-      return createDebtRemediationFunction(function, ruleDto.getRemediationCoefficient(), ruleDto.getRemediationOffset(), durations);
-    } else if (defaultFunction != null) {
-      return createDebtRemediationFunction(defaultFunction, ruleDto.getDefaultRemediationCoefficient(), ruleDto.getDefaultRemediationOffset(), durations);
-    } else {
-      throw new IllegalStateException(String.format("Remediation function should not be null on rule '%s'", ruleKey));
-    }
-  }
-
-  private DebtRemediationFunction createDebtRemediationFunction(String function, @Nullable String factor, @Nullable String offset, Durations durations) {
-    return DebtRemediationFunction.create(DebtRemediationFunction.Type.valueOf(function),
-      factor != null ? durations.decode(factor) : null,
-      offset != null ? durations.decode(offset) : null);
-  }
-
-  /**
-   * Return true is the characteristic has not been overridden and a default characteristic is existing or
-   * if the characteristic has been overridden but is not disabled
-   */
-  private static boolean hasCharacteristic(RuleDto ruleDto) {
-    Integer subCharacteristicId = ruleDto.getSubCharacteristicId();
-    return (subCharacteristicId == null && ruleDto.getDefaultSubCharacteristicId() != null) ||
-      (subCharacteristicId != null && !RuleDto.DISABLED_CHARACTERISTIC_ID.equals(subCharacteristicId));
-  }
-
-}
index 83f24753ef475bf744ccb4dd70b8c9e79158b523..53aa790b4a451332673b2e4bbc134d92aced47e8 100644 (file)
@@ -43,7 +43,6 @@ import org.sonar.batch.bootstrap.ExtensionUtils;
 import org.sonar.batch.bootstrap.MetricProvider;
 import org.sonar.batch.bootstrapper.EnvironmentInformation;
 import org.sonar.batch.components.PastMeasuresLoader;
-import org.sonar.batch.debt.DebtModelProvider;
 import org.sonar.batch.deprecated.components.DefaultResourceCreationLock;
 import org.sonar.batch.deprecated.components.PeriodsDefinition;
 import org.sonar.batch.duplication.DuplicationCache;
@@ -63,13 +62,13 @@ import org.sonar.batch.report.CoveragePublisher;
 import org.sonar.batch.report.DuplicationsPublisher;
 import org.sonar.batch.report.IssuesPublisher;
 import org.sonar.batch.report.MeasuresPublisher;
+import org.sonar.batch.report.MetadataPublisher;
 import org.sonar.batch.report.ReportPublisher;
 import org.sonar.batch.report.SourcePublisher;
 import org.sonar.batch.report.TestExecutionAndCoveragePublisher;
 import org.sonar.batch.repository.ProjectRepositoriesProvider;
 import org.sonar.batch.repository.language.DefaultLanguagesRepository;
 import org.sonar.batch.rule.ActiveRulesProvider;
-import org.sonar.batch.rule.RulesProvider;
 import org.sonar.batch.scan.filesystem.InputPathCache;
 import org.sonar.batch.scan.measure.DefaultMetricFinder;
 import org.sonar.batch.scan.measure.DeprecatedMetricFinder;
@@ -82,7 +81,6 @@ import org.sonar.core.issue.workflow.FunctionExecutor;
 import org.sonar.core.issue.workflow.IssueWorkflow;
 import org.sonar.core.permission.PermissionFacade;
 import org.sonar.core.platform.ComponentContainer;
-import org.sonar.core.technicaldebt.DefaultTechnicalDebtModel;
 
 public class ProjectScanContainer extends ComponentContainer {
 
@@ -159,10 +157,10 @@ public class ProjectScanContainer extends ComponentContainer {
       InputPathCache.class,
       PathResolver.class,
 
-    // rules
+      // rules
       new ActiveRulesProvider(),
 
-    // issues
+      // issues
       IssueUpdater.class,
       FunctionExecutor.class,
       IssueWorkflow.class,
@@ -171,31 +169,32 @@ public class ProjectScanContainer extends ComponentContainer {
       LocalIssueTracking.class,
       ServerIssueRepository.class,
 
-    // metrics
+      // metrics
       DefaultMetricFinder.class,
       DeprecatedMetricFinder.class,
 
-    // tests
+      // tests
       TestPlanBuilder.class,
       TestableBuilder.class,
 
-    // lang
+      // lang
       Languages.class,
       DefaultLanguagesRepository.class,
 
-    // Differential periods
+      // Differential periods
       PeriodsDefinition.class,
 
-    // Measures
+      // Measures
       MeasureCache.class,
 
-    // Duplications
+      // Duplications
       DuplicationCache.class,
 
-    ProjectSettings.class,
+      ProjectSettings.class,
 
-    // Report
+      // Report
       ReportPublisher.class,
+      MetadataPublisher.class,
       ComponentsPublisher.class,
       IssuesPublisher.class,
       MeasuresPublisher.class,
@@ -204,19 +203,11 @@ public class ProjectScanContainer extends ComponentContainer {
       SourcePublisher.class,
       TestExecutionAndCoveragePublisher.class,
 
-    ScanTaskObservers.class);
+      ScanTaskObservers.class);
   }
 
   private void addDataBaseComponents() {
-    add(
-      PastMeasuresLoader.class,
-
-    // Rules
-      new RulesProvider(),
-      new DebtModelProvider(),
-
-    // technical debt
-      DefaultTechnicalDebtModel.class);
+    add(PastMeasuresLoader.class);
   }
 
   private void addBatchExtensions() {
index 92ab22929565df78b43c9fff2b466c95cda2a309..2fd211534abd62d4c106769d6c6400b7f7368b7a 100644 (file)
@@ -23,10 +23,7 @@ import com.google.common.base.Preconditions;
 import org.sonar.api.batch.BatchSide;
 import org.sonar.api.batch.measure.MetricFinder;
 import org.sonar.api.measures.Measure;
-import org.sonar.api.measures.RuleMeasure;
 import org.sonar.api.resources.Resource;
-import org.sonar.api.technicaldebt.batch.Characteristic;
-import org.sonar.api.technicaldebt.batch.TechnicalDebtModel;
 import org.sonar.batch.index.Cache;
 import org.sonar.batch.index.Cache.Entry;
 import org.sonar.batch.index.Caches;
@@ -39,13 +36,8 @@ public class MeasureCache {
 
   private final Cache<Measure> cache;
 
-  public MeasureCache(Caches caches, MetricFinder metricFinder, TechnicalDebtModel techDebtModel) {
-    caches.registerValueCoder(Measure.class, new MeasureValueCoder(metricFinder, techDebtModel));
-    cache = caches.createCache("measures");
-  }
-
   public MeasureCache(Caches caches, MetricFinder metricFinder) {
-    caches.registerValueCoder(Measure.class, new MeasureValueCoder(metricFinder, null));
+    caches.registerValueCoder(Measure.class, new MeasureValueCoder(metricFinder));
     cache = caches.createCache("measures");
   }
 
@@ -88,19 +80,10 @@ public class MeasureCache {
       sb.append(m.getMetricKey());
     }
     sb.append("|");
-    Characteristic characteristic = m.getCharacteristic();
-    if (characteristic != null) {
-      sb.append(characteristic.key());
-    }
-    sb.append("|");
     Integer personId = m.getPersonId();
     if (personId != null) {
       sb.append(personId);
     }
-    if (m instanceof RuleMeasure) {
-      sb.append("|");
-      sb.append(((RuleMeasure) m).ruleKey());
-    }
     return sb.toString();
   }
 
index e7dae02780dc95baba06ac438c055d7ad7f4eb4b..e0fb8bb54a97eac8299df762593d608f26f61486 100644 (file)
@@ -22,24 +22,19 @@ package org.sonar.batch.scan.measure;
 import com.persistit.Value;
 import com.persistit.encoding.CoderContext;
 import com.persistit.encoding.ValueCoder;
+import javax.annotation.Nullable;
 import org.sonar.api.batch.measure.MetricFinder;
 import org.sonar.api.measures.Measure;
 import org.sonar.api.measures.Metric;
 import org.sonar.api.measures.PersistenceMode;
-import org.sonar.api.technicaldebt.batch.Characteristic;
 import org.sonar.api.technicaldebt.batch.Requirement;
-import org.sonar.api.technicaldebt.batch.TechnicalDebtModel;
-
-import javax.annotation.Nullable;
 
 class MeasureValueCoder implements ValueCoder {
 
   private final MetricFinder metricFinder;
-  private final TechnicalDebtModel techDebtModel;
 
-  public MeasureValueCoder(MetricFinder metricFinder, @Nullable TechnicalDebtModel techDebtModel) {
+  public MeasureValueCoder(MetricFinder metricFinder) {
     this.metricFinder = metricFinder;
-    this.techDebtModel = techDebtModel;
   }
 
   @Override
@@ -58,10 +53,6 @@ class MeasureValueCoder implements ValueCoder {
     value.put(m.getVariation4());
     value.put(m.getVariation5());
     putUTFOrNull(value, m.getUrl());
-    Characteristic characteristic = m.getCharacteristic();
-    value.put(characteristic != null ? characteristic.id() : null);
-    Requirement requirement = m.getRequirement();
-    value.put(requirement != null ? requirement.id() : null);
     Integer personId = m.getPersonId();
     value.put(personId != null ? personId.intValue() : null);
     PersistenceMode persistenceMode = m.getPersistenceMode();
@@ -97,8 +88,6 @@ class MeasureValueCoder implements ValueCoder {
     m.setVariation4(value.isNull(true) ? null : value.getDouble());
     m.setVariation5(value.isNull(true) ? null : value.getDouble());
     m.setUrl(value.getString());
-    m.setCharacteristic(value.isNull(true) ? null : techDebtModel.characteristicById(value.getInt()));
-    m.setRequirement(value.isNull(true) ? null : techDebtModel.requirementsById(value.getInt()));
     m.setPersonId(value.isNull(true) ? null : value.getInt());
     m.setPersistenceMode(value.isNull(true) ? null : PersistenceMode.valueOf(value.getString()));
     return m;
diff --git a/sonar-batch/src/test/java/org/sonar/batch/debt/DebtDecoratorTest.java b/sonar-batch/src/test/java/org/sonar/batch/debt/DebtDecoratorTest.java
deleted file mode 100644 (file)
index 4b96aba..0000000
+++ /dev/null
@@ -1,353 +0,0 @@
-///*
-// * SonarQube, open source software quality management tool.
-// * Copyright (C) 2008-2014 SonarSource
-// * mailto:contact AT sonarsource DOT com
-// *
-// * SonarQube 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.
-// *
-// * SonarQube 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 this program; if not, write to the Free Software Foundation,
-// * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-// */
-//
-//package org.sonar.batch.debt;
-//
-//import com.google.common.collect.Lists;
-//import org.apache.commons.lang.ObjectUtils;
-//import org.apache.commons.lang.builder.ToStringBuilder;
-//import org.apache.commons.lang.builder.ToStringStyle;
-//import org.hamcrest.Description;
-//import org.junit.Before;
-//import org.junit.Test;
-//import org.junit.runner.RunWith;
-//import org.mockito.ArgumentMatcher;
-//import org.mockito.Mock;
-//import org.mockito.runners.MockitoJUnitRunner;
-//import org.sonar.api.batch.DecoratorContext;
-//import org.sonar.api.batch.rule.Rules;
-//import org.sonar.api.batch.rule.internal.RulesBuilder;
-//import org.sonar.api.component.ResourcePerspectives;
-//import org.sonar.api.issue.Issuable;
-//import org.sonar.api.issue.Issue;
-//import org.sonar.core.issue.DefaultIssue;
-//import org.sonar.api.measures.CoreMetrics;
-//import org.sonar.api.measures.Measure;
-//import org.sonar.api.measures.MeasuresFilter;
-//import org.sonar.api.measures.Metric;
-//import org.sonar.api.measures.RuleMeasure;
-//import org.sonar.api.resources.File;
-//import org.sonar.api.resources.Project;
-//import org.sonar.api.resources.Resource;
-//import org.sonar.api.rule.RuleKey;
-//import org.sonar.api.rules.RuleFinder;
-//import org.sonar.api.technicaldebt.batch.Characteristic;
-//import org.sonar.api.technicaldebt.batch.TechnicalDebtModel;
-//import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
-//import org.sonar.api.test.IsMeasure;
-//import org.sonar.api.utils.Duration;
-//
-//import java.util.Collections;
-//
-//import static com.google.common.collect.Lists.newArrayList;
-//import static org.assertj.core.api.Assertions.assertThat;
-//import static org.mockito.Matchers.any;
-//import static org.mockito.Matchers.argThat;
-//import static org.mockito.Mockito.mock;
-//import static org.mockito.Mockito.never;
-//import static org.mockito.Mockito.times;
-//import static org.mockito.Mockito.verify;
-//import static org.mockito.Mockito.when;
-//
-//@RunWith(MockitoJUnitRunner.class)
-//public class DebtDecoratorTest {
-//
-//  static final int HOURS_IN_DAY = 8;
-//
-//  static final Long ONE_DAY_IN_MINUTES = 1L * HOURS_IN_DAY * 60;
-//
-//  @Mock
-//  DecoratorContext context;
-//
-//  @Mock
-//  Resource resource;
-//
-//  @Mock
-//  TechnicalDebtModel debtModel;
-//
-//  @Mock
-//  Issuable issuable;
-//
-//  @Mock
-//  ResourcePerspectives perspectives;
-//
-//  @Mock
-//  RuleFinder ruleFinder;
-//
-//  RuleKey ruleKey1 = RuleKey.of("repo1", "rule1");
-//  RuleKey ruleKey2 = RuleKey.of("repo2", "rule2");
-//  Rules rules;
-//
-//  DefaultCharacteristic efficiency = new DefaultCharacteristic().setKey("EFFICIENCY");
-//  DefaultCharacteristic memoryEfficiency = new DefaultCharacteristic().setKey("MEMORY_EFFICIENCY").setParent(efficiency);
-//
-//  DefaultCharacteristic reusability = new DefaultCharacteristic().setKey("REUSABILITY");
-//  DefaultCharacteristic modularity = new DefaultCharacteristic().setKey("MODULARITY").setParent(reusability);
-//
-//  DebtDecorator decorator;
-//
-//  @Before
-//  public void before() {
-//    when(perspectives.as(Issuable.class, resource)).thenReturn(issuable);
-//    RulesBuilder rulesBuilder = new RulesBuilder();
-//    rulesBuilder.add(ruleKey1).setName("rule1").setDebtSubCharacteristic("MEMORY_EFFICIENCY");
-//    rulesBuilder.add(ruleKey2).setName("rule2").setDebtSubCharacteristic("MODULARITY");
-//    rules = rulesBuilder.build();
-//
-//    when(ruleFinder.findByKey(ruleKey1)).thenReturn(org.sonar.api.rules.Rule.create(ruleKey1.repository(), ruleKey1.rule()));
-//    when(ruleFinder.findByKey(ruleKey2)).thenReturn(org.sonar.api.rules.Rule.create(ruleKey2.repository(), ruleKey2.rule()));
-//
-//    when(debtModel.characteristics()).thenReturn(newArrayList(efficiency, memoryEfficiency, reusability, modularity));
-//    when(debtModel.characteristicByKey("EFFICIENCY")).thenReturn(efficiency);
-//    when(debtModel.characteristicByKey("MEMORY_EFFICIENCY")).thenReturn(memoryEfficiency);
-//    when(debtModel.characteristicByKey("REUSABILITY")).thenReturn(reusability);
-//    when(debtModel.characteristicByKey("MODULARITY")).thenReturn(modularity);
-//
-//    decorator = new DebtDecorator(perspectives, debtModel, rules, ruleFinder);
-//  }
-//
-//  @Test
-//  public void generates_metrics() {
-//    assertThat(decorator.generatesMetrics()).hasSize(1);
-//  }
-//
-//  @Test
-//  public void execute_on_project() {
-//    assertThat(decorator.shouldExecuteOnProject(null)).isTrue();
-//  }
-//
-//  @Test
-//  public void not_save_if_measure_already_computed() {
-//    when(context.getMeasure(CoreMetrics.TECHNICAL_DEBT)).thenReturn(new Measure());
-//
-//    decorator.decorate(resource, context);
-//
-//    verify(context, never()).saveMeasure(argThat(new IsMeasure(CoreMetrics.TECHNICAL_DEBT)));
-//  }
-//
-//  @Test
-//  public void add_technical_debt_from_one_issue_and_no_parent() {
-//    Issue issue = createIssue("rule1", "repo1").setDebt(Duration.create(ONE_DAY_IN_MINUTES));
-//    when(issuable.issues()).thenReturn(newArrayList(issue));
-//
-//    decorator.decorate(resource, context);
-//
-//    verify(context).saveMeasure(CoreMetrics.TECHNICAL_DEBT, ONE_DAY_IN_MINUTES.doubleValue());
-//    verify(context).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.TECHNICAL_DEBT, ruleKey1, ONE_DAY_IN_MINUTES.doubleValue())));
-//  }
-//
-//  @Test
-//  public void add_technical_debt_from_one_issue_without_debt() {
-//    Issue issue = createIssue("rule1", "repo1").setDebt(null);
-//    when(issuable.issues()).thenReturn(newArrayList(issue));
-//
-//    decorator.decorate(resource, context);
-//
-//    verify(context).saveMeasure(CoreMetrics.TECHNICAL_DEBT, 0.0);
-//  }
-//
-//  @Test
-//  public void add_technical_debt_from_one_issue_and_propagate_to_parents() {
-//    Issue issue = createIssue("rule1", "repo1").setDebt(Duration.create(ONE_DAY_IN_MINUTES));
-//    when(issuable.issues()).thenReturn(newArrayList(issue));
-//
-//    decorator.decorate(resource, context);
-//
-//    verify(context).saveMeasure(CoreMetrics.TECHNICAL_DEBT, ONE_DAY_IN_MINUTES.doubleValue());
-//    verify(context).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.TECHNICAL_DEBT, ruleKey1, ONE_DAY_IN_MINUTES.doubleValue())));
-//    verify(context).saveMeasure(argThat(new IsCharacteristicMeasure(CoreMetrics.TECHNICAL_DEBT, efficiency, ONE_DAY_IN_MINUTES.doubleValue())));
-//    verify(context).saveMeasure(argThat(new IsCharacteristicMeasure(CoreMetrics.TECHNICAL_DEBT, memoryEfficiency, ONE_DAY_IN_MINUTES.doubleValue())));
-//  }
-//
-//  @Test
-//  public void add_technical_debt_from_issues() {
-//    Long technicalDebt1 = ONE_DAY_IN_MINUTES;
-//    Long technicalDebt2 = 2 * ONE_DAY_IN_MINUTES;
-//
-//    Issue issue1 = createIssue("rule1", "repo1").setDebt(Duration.create(technicalDebt1));
-//    Issue issue2 = createIssue("rule1", "repo1").setDebt(Duration.create(technicalDebt1));
-//    Issue issue3 = createIssue("rule2", "repo2").setDebt(Duration.create(technicalDebt2));
-//    Issue issue4 = createIssue("rule2", "repo2").setDebt(Duration.create(technicalDebt2));
-//    when(issuable.issues()).thenReturn(newArrayList(issue1, issue2, issue3, issue4));
-//
-//    decorator.decorate(resource, context);
-//
-//    verify(context).saveMeasure(CoreMetrics.TECHNICAL_DEBT, 6d * ONE_DAY_IN_MINUTES);
-//    verify(context).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.TECHNICAL_DEBT, ruleKey1, 2d * ONE_DAY_IN_MINUTES)));
-//    verify(context).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.TECHNICAL_DEBT, ruleKey2, 4d * ONE_DAY_IN_MINUTES)));
-//  }
-//
-//  @Test
-//  public void add_technical_debt_from_current_and_children_measures() {
-//    Issue issue1 = createIssue("rule1", "repo1").setDebt(Duration.create(ONE_DAY_IN_MINUTES));
-//    Issue issue2 = createIssue("rule1", "repo1").setDebt(Duration.create(ONE_DAY_IN_MINUTES));
-//    when(issuable.issues()).thenReturn(newArrayList(issue1, issue2));
-//
-//    when(context.getChildrenMeasures(any(MeasuresFilter.class))).thenReturn(Lists.<Measure>newArrayList(
-//      new RuleMeasure(CoreMetrics.TECHNICAL_DEBT,
-//        org.sonar.api.rules.Rule.create(ruleKey1.repository(), ruleKey1.rule()), null, null)
-//        .setValue(5d * ONE_DAY_IN_MINUTES)
-//      ));
-//    decorator.decorate(resource, context);
-//
-//    verify(context).saveMeasure(CoreMetrics.TECHNICAL_DEBT, 7d * ONE_DAY_IN_MINUTES);
-//    verify(context).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.TECHNICAL_DEBT, ruleKey1, 7d * ONE_DAY_IN_MINUTES)));
-//    verify(context).saveMeasure(argThat(new IsCharacteristicMeasure(CoreMetrics.TECHNICAL_DEBT, memoryEfficiency, 7d * ONE_DAY_IN_MINUTES)));
-//    verify(context).saveMeasure(argThat(new IsCharacteristicMeasure(CoreMetrics.TECHNICAL_DEBT, efficiency, 7d * ONE_DAY_IN_MINUTES)));
-//  }
-//
-//  @Test
-//  public void add_technical_debt_only_from_children_measures() {
-//    when(issuable.issues()).thenReturn(Collections.<Issue>emptyList());
-//
-//    when(context.getChildrenMeasures(any(MeasuresFilter.class))).thenReturn(Lists.<Measure>newArrayList(
-//      new RuleMeasure(CoreMetrics.TECHNICAL_DEBT,
-//        org.sonar.api.rules.Rule.create(ruleKey1.repository(), ruleKey1.rule())
-//        , null, null).setValue(5d * ONE_DAY_IN_MINUTES),
-//
-//      new RuleMeasure(CoreMetrics.TECHNICAL_DEBT,
-//        org.sonar.api.rules.Rule.create(ruleKey2.repository(), ruleKey2.rule())
-//        , null, null).setValue(10d * ONE_DAY_IN_MINUTES)
-//      ));
-//    decorator.decorate(resource, context);
-//
-//    verify(context).saveMeasure(CoreMetrics.TECHNICAL_DEBT, 15d * ONE_DAY_IN_MINUTES);
-//    verify(context).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.TECHNICAL_DEBT, ruleKey1, 5d * ONE_DAY_IN_MINUTES)));
-//    verify(context).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.TECHNICAL_DEBT, ruleKey2, 10d * ONE_DAY_IN_MINUTES)));
-//    verify(context).saveMeasure(argThat(new IsCharacteristicMeasure(CoreMetrics.TECHNICAL_DEBT, memoryEfficiency, 5d * ONE_DAY_IN_MINUTES)));
-//    verify(context).saveMeasure(argThat(new IsCharacteristicMeasure(CoreMetrics.TECHNICAL_DEBT, efficiency, 5d * ONE_DAY_IN_MINUTES)));
-//    verify(context).saveMeasure(argThat(new IsCharacteristicMeasure(CoreMetrics.TECHNICAL_DEBT, reusability, 10d * ONE_DAY_IN_MINUTES)));
-//    verify(context).saveMeasure(argThat(new IsCharacteristicMeasure(CoreMetrics.TECHNICAL_DEBT, modularity, 10d * ONE_DAY_IN_MINUTES)));
-//  }
-//
-//  @Test
-//  public void always_save_technical_debt_for_positive_values() {
-//    // for a project
-//    DecoratorContext context = mock(DecoratorContext.class);
-//    when(context.getResource()).thenReturn(new Project("foo"));
-//    decorator.saveCharacteristicMeasure(context, (Characteristic) null, 12.0, false);
-//    verify(context, times(1)).saveMeasure(new Measure(CoreMetrics.TECHNICAL_DEBT));
-//
-//    // or for a file
-//    context = mock(DecoratorContext.class);
-//    when(context.getResource()).thenReturn(File.create("foo"));
-//    decorator.saveCharacteristicMeasure(context, (Characteristic) null, 12.0, false);
-//    verify(context, times(1)).saveMeasure(new Measure(CoreMetrics.TECHNICAL_DEBT));
-//  }
-//
-//  @Test
-//  public void always_save_technical_debt_for_project_if_top_characteristic() {
-//    DecoratorContext context = mock(DecoratorContext.class);
-//    when(context.getResource()).thenReturn(new Project("foo"));
-//
-//    // this is a top characteristic
-//    DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic().setKey("root");
-//
-//    decorator.saveCharacteristicMeasure(context, rootCharacteristic, 0.0, true);
-//    verify(context, times(1)).saveMeasure(new Measure(CoreMetrics.TECHNICAL_DEBT).setCharacteristic(rootCharacteristic));
-//  }
-//
-//  /**
-//   * SQALE-147
-//   */
-//  @Test
-//  public void never_save_technical_debt_for_project_if_not_top_characteristic() {
-//    DecoratorContext context = mock(DecoratorContext.class);
-//    when(context.getResource()).thenReturn(new Project("foo"));
-//
-//    DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic().setKey("EFFICIENCY");
-//    DefaultCharacteristic characteristic = new DefaultCharacteristic().setKey("MEMORY_EFFICIENCY").setParent(rootCharacteristic);
-//
-//    decorator.saveCharacteristicMeasure(context, characteristic, 0.0, true);
-//    verify(context, never()).saveMeasure(any(Measure.class));
-//  }
-//
-//  @Test
-//  public void not_save_technical_debt_for_file_if_zero() {
-//    DecoratorContext context = mock(DecoratorContext.class);
-//    when(context.getResource()).thenReturn(File.create("foo"));
-//
-//    decorator.saveCharacteristicMeasure(context, null, 0.0, true);
-//    verify(context, never()).saveMeasure(new Measure(CoreMetrics.TECHNICAL_DEBT));
-//  }
-//
-//  private DefaultIssue createIssue(String ruleKey, String repositoryKey) {
-//    return new DefaultIssue().setRuleKey(RuleKey.of(repositoryKey, ruleKey));
-//  }
-//
-//  class IsCharacteristicMeasure extends ArgumentMatcher<Measure> {
-//    Metric metric = null;
-//    Characteristic characteristic = null;
-//    Double value = null;
-//
-//    public IsCharacteristicMeasure(Metric metric, Characteristic characteristic, Double value) {
-//      this.metric = metric;
-//      this.characteristic = characteristic;
-//      this.value = value;
-//    }
-//
-//    @Override
-//    public boolean matches(Object o) {
-//      if (!(o instanceof Measure)) {
-//        return false;
-//      }
-//      Measure m = (Measure) o;
-//      return ObjectUtils.equals(metric, m.getMetric()) &&
-//        ObjectUtils.equals(characteristic, m.getCharacteristic()) &&
-//        ObjectUtils.equals(value, m.getValue());
-//    }
-//
-//    @Override
-//    public void describeTo(Description description) {
-//      description.appendText(new StringBuilder()
-//        .append("value=").append(value).append(",")
-//        .append("characteristic=").append(characteristic.key()).append(",")
-//        .append("metric=").append(metric.getKey()).toString());
-//    }
-//  }
-//
-//  class IsRuleMeasure extends ArgumentMatcher<RuleMeasure> {
-//    Metric metric = null;
-//    RuleKey ruleKey = null;
-//    Double value = null;
-//
-//    public IsRuleMeasure(Metric metric, RuleKey ruleKey, Double value) {
-//      this.metric = metric;
-//      this.ruleKey = ruleKey;
-//      this.value = value;
-//    }
-//
-//    @Override
-//    public boolean matches(Object o) {
-//      if (!(o instanceof RuleMeasure)) {
-//        return false;
-//      }
-//      RuleMeasure m = (RuleMeasure) o;
-//      return ObjectUtils.equals(metric, m.getMetric()) &&
-//        ObjectUtils.equals(ruleKey, m.ruleKey()) &&
-//        ObjectUtils.equals(value, m.getValue());
-//    }
-//
-//    @Override
-//    public void describeTo(Description description) {
-//      description.appendText(ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE));
-//    }
-//  }
-//}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/debt/DebtModelProviderTest.java b/sonar-batch/src/test/java/org/sonar/batch/debt/DebtModelProviderTest.java
deleted file mode 100644 (file)
index 1d434d5..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-package org.sonar.batch.debt;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-import org.sonar.api.batch.debt.DebtCharacteristic;
-import org.sonar.api.batch.debt.DebtModel;
-import org.sonar.core.technicaldebt.db.CharacteristicDao;
-import org.sonar.core.technicaldebt.db.CharacteristicDto;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.when;
-
-@RunWith(MockitoJUnitRunner.class)
-public class DebtModelProviderTest {
-
-  @Mock
-  CharacteristicDao dao;
-
-  DebtModelProvider provider;
-
-  @Before
-  public void before() {
-    provider = new DebtModelProvider();
-  }
-
-  @Test
-  public void provide_model() {
-    CharacteristicDto rootCharacteristicDto = new CharacteristicDto()
-      .setId(1)
-      .setKey("MEMORY_EFFICIENCY")
-      .setName("Memory use")
-      .setOrder(1);
-
-    CharacteristicDto characteristicDto = new CharacteristicDto()
-      .setId(2)
-      .setKey("EFFICIENCY")
-      .setName("Efficiency")
-      .setParentId(1);
-
-    when(dao.selectEnabledCharacteristics()).thenReturn(newArrayList(rootCharacteristicDto, characteristicDto));
-
-    DebtModel result = provider.provide(dao);
-    assertThat(result.characteristics()).hasSize(1);
-
-    DebtCharacteristic characteristic = result.characteristicByKey("MEMORY_EFFICIENCY");
-    assertThat(characteristic.key()).isEqualTo("MEMORY_EFFICIENCY");
-    assertThat(characteristic.name()).isEqualTo("Memory use");
-    assertThat(characteristic.isSub()).isFalse();
-    assertThat(characteristic.order()).isEqualTo(1);
-
-    DebtCharacteristic subCharacteristic = result.characteristicByKey("EFFICIENCY");
-    assertThat(subCharacteristic.key()).isEqualTo("EFFICIENCY");
-    assertThat(subCharacteristic.name()).isEqualTo("Efficiency");
-    assertThat(subCharacteristic.isSub()).isTrue();
-    assertThat(subCharacteristic.order()).isNull();
-  }
-}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/debt/IssueChangelogDebtCalculatorTest.java b/sonar-batch/src/test/java/org/sonar/batch/debt/IssueChangelogDebtCalculatorTest.java
deleted file mode 100644 (file)
index fb2bf2e..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-package org.sonar.batch.debt;
-
-import org.apache.commons.lang.time.DateUtils;
-import org.junit.Before;
-import org.junit.Test;
-import org.sonar.api.issue.Issue;
-import org.sonar.core.issue.DefaultIssue;
-import org.sonar.core.issue.FieldDiffs;
-import org.sonar.api.utils.Duration;
-
-import java.util.Date;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class IssueChangelogDebtCalculatorTest {
-
-  private static final int HOURS_IN_DAY = 8;
-
-  IssueChangelogDebtCalculator issueChangelogDebtCalculator;
-
-  Date rightNow = new Date();
-  Date elevenDaysAgo = DateUtils.addDays(rightNow, -11);
-  Date tenDaysAgo = DateUtils.addDays(rightNow, -10);
-  Date nineDaysAgo = DateUtils.addDays(rightNow, -9);
-  Date fiveDaysAgo = DateUtils.addDays(rightNow, -5);
-  Date fourDaysAgo = DateUtils.addDays(rightNow, -4);
-
-  long oneDay = 1 * HOURS_IN_DAY * 60 * 60L;
-  long twoDays = 2 * HOURS_IN_DAY * 60 * 60L;
-  long fiveDays = 5 * HOURS_IN_DAY * 60 * 60L;
-
-  Duration oneDayDebt = Duration.create(oneDay);
-  Duration twoDaysDebt = Duration.create(twoDays);
-  Duration fiveDaysDebt = Duration.create(fiveDays);
-
-  @Before
-  public void setUp() {
-    issueChangelogDebtCalculator = new IssueChangelogDebtCalculator();
-  }
-
-  @Test
-  public void calculate_new_technical_debt_with_one_diff_in_changelog() {
-    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(twoDaysDebt).setChanges(
-      newArrayList(
-        // changelog created at is null because it has just been created on the current analysis
-        new FieldDiffs().setDiff("technicalDebt", oneDay, twoDays).setCreationDate(null)
-      )
-    );
-
-    assertThat(issueChangelogDebtCalculator.calculateNewTechnicalDebt(issue, rightNow)).isEqualTo(oneDay);
-    assertThat(issueChangelogDebtCalculator.calculateNewTechnicalDebt(issue, fiveDaysAgo)).isEqualTo(oneDay);
-
-    assertThat(issueChangelogDebtCalculator.calculateNewTechnicalDebt(issue, elevenDaysAgo)).isEqualTo(twoDays);
-  }
-
-  @Test
-  public void calculate_new_technical_debt_with_many_diffs_in_changelog() {
-    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(fiveDaysDebt).setChanges(
-      newArrayList(
-        new FieldDiffs().setDiff("technicalDebt", twoDays, fiveDays).setCreationDate(null),
-        new FieldDiffs().setDiff("technicalDebt", oneDay, twoDays).setCreationDate(fourDaysAgo)
-      )
-    );
-
-    assertThat(issueChangelogDebtCalculator.calculateNewTechnicalDebt(issue, rightNow)).isEqualTo(3 * oneDay);
-    assertThat(issueChangelogDebtCalculator.calculateNewTechnicalDebt(issue, fiveDaysAgo)).isEqualTo(4 * oneDay);
-    assertThat(issueChangelogDebtCalculator.calculateNewTechnicalDebt(issue, elevenDaysAgo)).isEqualTo(5 * oneDay);
-  }
-
-  @Test
-  public void changelog_can_be_in_wrong_order() {
-    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(fiveDaysDebt).setChanges(
-      newArrayList(
-        // 3rd
-        new FieldDiffs().setDiff("technicalDebt", null, oneDay).setCreationDate(nineDaysAgo),
-        // 1st
-        new FieldDiffs().setDiff("technicalDebt", twoDays, fiveDays).setCreationDate(rightNow),
-        // 2nd
-        new FieldDiffs().setDiff("technicalDebt", oneDay, twoDays).setCreationDate(fourDaysAgo)
-      )
-    );
-
-    assertThat(issueChangelogDebtCalculator.calculateNewTechnicalDebt(issue, fiveDaysAgo)).isEqualTo(4 * oneDay);
-    assertThat(issueChangelogDebtCalculator.calculateNewTechnicalDebt(issue, elevenDaysAgo)).isEqualTo(5 * oneDay);
-  }
-
-  @Test
-  public void calculate_new_technical_debt_with_null_date() {
-    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(twoDaysDebt).setChanges(
-      newArrayList(
-        new FieldDiffs().setDiff("technicalDebt", oneDay, twoDays).setCreationDate(null)
-      )
-    );
-
-    assertThat(issueChangelogDebtCalculator.calculateNewTechnicalDebt(issue, null)).isEqualTo(2 * oneDay);
-  }
-
-  @Test
-  public void calculate_new_technical_debt_when_new_debt_is_null() {
-    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(null).setChanges(
-      newArrayList(
-        new FieldDiffs().setDiff("technicalDebt", oneDay, null).setCreationDate(null),
-        new FieldDiffs().setDiff("technicalDebt", null, oneDay).setCreationDate(nineDaysAgo)
-      )
-    );
-
-    assertThat(issueChangelogDebtCalculator.calculateNewTechnicalDebt(issue, rightNow)).isNull();
-  }
-
-  @Test
-  public void calculate_new_technical_debt_on_issue_without_technical_debt_and_without_changelog() {
-    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo);
-
-    assertThat(issueChangelogDebtCalculator.calculateNewTechnicalDebt(issue, rightNow)).isNull();
-  }
-
-  @Test
-  public void not_return_negative_debt() {
-    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(oneDayDebt).setChanges(
-      newArrayList(
-        new FieldDiffs().setDiff("technicalDebt", twoDays, oneDay).setCreationDate(null)
-      )
-    );
-
-    assertThat(issueChangelogDebtCalculator.calculateNewTechnicalDebt(issue, rightNow)).isNull();
-  }
-
-}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/debt/NewDebtDecoratorTest.java b/sonar-batch/src/test/java/org/sonar/batch/debt/NewDebtDecoratorTest.java
deleted file mode 100644 (file)
index 8b00495..0000000
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-package org.sonar.batch.debt;
-
-import org.apache.commons.lang.ObjectUtils;
-import org.apache.commons.lang.time.DateUtils;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentMatcher;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.batch.DecoratorContext;
-import org.sonar.api.component.ResourcePerspectives;
-import org.sonar.api.config.Settings;
-import org.sonar.api.issue.Issuable;
-import org.sonar.api.issue.Issue;
-import org.sonar.core.issue.DefaultIssue;
-import org.sonar.core.issue.FieldDiffs;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.measures.Measure;
-import org.sonar.api.measures.Metric;
-import org.sonar.api.resources.Resource;
-import org.sonar.api.test.IsMeasure;
-import org.sonar.api.utils.Duration;
-import org.sonar.batch.components.Period;
-import org.sonar.batch.components.TimeMachineConfiguration;
-
-import java.util.Date;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-@RunWith(MockitoJUnitRunner.class)
-public class NewDebtDecoratorTest {
-
-  NewDebtDecorator decorator;
-
-  @Mock
-  TimeMachineConfiguration timeMachineConfiguration;
-
-  @Mock
-  Resource resource;
-
-  @Mock
-  Issuable issuable;
-
-  @Mock
-  DecoratorContext context;
-
-  Date rightNow;
-  Date elevenDaysAgo;
-  Date tenDaysAgo;
-  Date nineDaysAgo;
-  Date fiveDaysAgo;
-  Date fourDaysAgo;
-
-  static final int HOURS_IN_DAY = 8;
-
-  static final Long ONE_DAY_IN_MINUTES = 1L * HOURS_IN_DAY * 60;
-  static final Long TWO_DAYS_IN_MINUTES = 2L * HOURS_IN_DAY * 60;
-  static final Long FIVE_DAYS_IN_MINUTES = 5L * HOURS_IN_DAY * 60;
-
-  @Before
-  public void setup() {
-    Settings settings = new Settings();
-    settings.setProperty(CoreProperties.HOURS_IN_DAY, HOURS_IN_DAY);
-
-    ResourcePerspectives perspectives = mock(ResourcePerspectives.class);
-    when(perspectives.as(Issuable.class, resource)).thenReturn(issuable);
-
-    rightNow = new Date();
-    elevenDaysAgo = DateUtils.addDays(rightNow, -11);
-    tenDaysAgo = DateUtils.addDays(rightNow, -10);
-    nineDaysAgo = DateUtils.addDays(rightNow, -9);
-    fiveDaysAgo = DateUtils.addDays(rightNow, -5);
-    fourDaysAgo = DateUtils.addDays(rightNow, -4);
-
-    when(timeMachineConfiguration.periods()).thenReturn(newArrayList(new Period(1, fiveDaysAgo), new Period(2, tenDaysAgo)));
-
-    decorator = new NewDebtDecorator(perspectives, timeMachineConfiguration, new IssueChangelogDebtCalculator());
-  }
-
-  @Test
-  public void generates_metrics() {
-    assertThat(decorator.generatesMetrics()).hasSize(1);
-  }
-
-  @Test
-  public void execute_on_project() {
-    assertThat(decorator.shouldExecuteOnProject(null)).isTrue();
-  }
-
-  @Test
-  public void save_on_one_issue_with_one_new_changelog() {
-    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(TWO_DAYS_IN_MINUTES)).setChanges(
-      newArrayList(
-        // changelog created at is null because it has just been created on the current analysis
-        new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, TWO_DAYS_IN_MINUTES).setCreationDate(null)
-      )
-    );
-    when(issuable.issues()).thenReturn(newArrayList(issue));
-
-    decorator.decorate(resource, context);
-
-    // remember : period1 is 5daysAgo, period2 is 10daysAgo
-    verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 1.0 * ONE_DAY_IN_MINUTES, 1.0 * ONE_DAY_IN_MINUTES)));
-  }
-
-  @Test
-  public void save_on_one_issue_with_changelog() {
-    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)).setChanges(
-      newArrayList(
-        new FieldDiffs().setDiff("technicalDebt", TWO_DAYS_IN_MINUTES, FIVE_DAYS_IN_MINUTES).setCreationDate(null),
-        new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, TWO_DAYS_IN_MINUTES).setCreationDate(fourDaysAgo)
-      )
-    );
-    when(issuable.issues()).thenReturn(newArrayList(issue));
-
-    decorator.decorate(resource, context);
-
-    // remember : period1 is 5daysAgo, period2 is 10daysAgo
-    verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 4.0 * ONE_DAY_IN_MINUTES, 4.0 * ONE_DAY_IN_MINUTES)));
-  }
-
-  @Test
-  public void save_on_one_issue_with_changelog_only_in_the_past() {
-    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(ONE_DAY_IN_MINUTES)).setChanges(
-      newArrayList(
-        // Change before all periods
-        new FieldDiffs().setDiff("technicalDebt", null, ONE_DAY_IN_MINUTES).setCreationDate(elevenDaysAgo)
-      )
-    );
-    when(issuable.issues()).thenReturn(newArrayList(issue));
-
-    decorator.decorate(resource, context);
-
-    // remember : period1 is 5daysAgo, period2 is 10daysAgo
-    verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0, 0.0)));
-  }
-
-  @Test
-  public void save_on_one_issue_with_changelog_having_null_value() {
-    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)).setChanges(
-      newArrayList(
-        new FieldDiffs().setDiff("technicalDebt", null, FIVE_DAYS_IN_MINUTES).setCreationDate(null),
-        new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, null).setCreationDate(fourDaysAgo),
-        new FieldDiffs().setDiff("technicalDebt", null, ONE_DAY_IN_MINUTES).setCreationDate(nineDaysAgo)
-      )
-    );
-    when(issuable.issues()).thenReturn(newArrayList(issue));
-
-    decorator.decorate(resource, context);
-
-    // remember : period1 is 5daysAgo, period2 is 10daysAgo
-    verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 4.0 * ONE_DAY_IN_MINUTES, 5.0 * ONE_DAY_IN_MINUTES)));
-  }
-
-  @Test
-  public void save_on_one_issue_with_changelog_and_periods_have_no_dates() {
-    when(timeMachineConfiguration.periods()).thenReturn(newArrayList(new Period(1, null), new Period(2, null)));
-
-    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)).setChanges(
-      newArrayList(
-        new FieldDiffs().setDiff("technicalDebt", null, FIVE_DAYS_IN_MINUTES).setCreationDate(null),
-        new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, null).setCreationDate(fourDaysAgo),
-        new FieldDiffs().setDiff("technicalDebt", null, ONE_DAY_IN_MINUTES).setCreationDate(nineDaysAgo)
-      )
-    );
-    when(issuable.issues()).thenReturn(newArrayList(issue));
-
-    decorator.decorate(resource, context);
-
-    // remember : period1 is 5daysAgo, period2 is 10daysAgo
-    verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 5.0 * ONE_DAY_IN_MINUTES, 5.0 * ONE_DAY_IN_MINUTES)));
-  }
-
-  @Test
-  public void save_on_one_issue_with_changelog_having_not_only_technical_debt_changes() {
-    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)).setChanges(
-      newArrayList(
-        new FieldDiffs()
-          .setDiff("actionPlan", "1.0", "1.1").setCreationDate(fourDaysAgo)
-          .setDiff("technicalDebt", ONE_DAY_IN_MINUTES, TWO_DAYS_IN_MINUTES).setCreationDate(fourDaysAgo)
-      )
-    );
-    when(issuable.issues()).thenReturn(newArrayList(issue));
-
-    decorator.decorate(resource, context);
-
-    // remember : period1 is 5daysAgo, period2 is 10daysAgo
-    verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 4.0 * ONE_DAY_IN_MINUTES, 4.0 * ONE_DAY_IN_MINUTES)));
-  }
-
-  @Test
-  public void save_on_issues_with_changelog() {
-    Issue issue1 = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)).setChanges(
-      newArrayList(
-        new FieldDiffs().setDiff("technicalDebt", TWO_DAYS_IN_MINUTES, FIVE_DAYS_IN_MINUTES).setCreationDate(rightNow),
-        new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, TWO_DAYS_IN_MINUTES).setCreationDate(fourDaysAgo),
-        new FieldDiffs().setDiff("technicalDebt", null, ONE_DAY_IN_MINUTES).setCreationDate(nineDaysAgo)
-      )
-    );
-    Issue issue2 = new DefaultIssue().setKey("B").setCreationDate(tenDaysAgo).setDebt(Duration.create(TWO_DAYS_IN_MINUTES)).setChanges(
-      newArrayList(
-        new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, TWO_DAYS_IN_MINUTES).setCreationDate(rightNow),
-        new FieldDiffs().setDiff("technicalDebt", null, ONE_DAY_IN_MINUTES).setCreationDate(nineDaysAgo)
-      )
-    );
-    when(issuable.issues()).thenReturn(newArrayList(issue1, issue2));
-
-    decorator.decorate(resource, context);
-
-    // remember : period1 is 5daysAgo, period2 is 10daysAgo
-    verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 5.0 * ONE_DAY_IN_MINUTES, 7.0 * ONE_DAY_IN_MINUTES)));
-  }
-
-  @Test
-  public void save_on_one_issue_without_changelog() {
-    when(issuable.issues()).thenReturn(newArrayList(
-      (Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)))
-    );
-
-    decorator.decorate(resource, context);
-
-    // remember : period1 is 5daysAgo, period2 is 10daysAgo
-    verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0, 5.0 * ONE_DAY_IN_MINUTES)));
-  }
-
-  @Test
-  public void save_on_one_issue_without_technical_debt_and_without_changelog() {
-    when(issuable.issues()).thenReturn(newArrayList(
-      (Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setDebt(null))
-    );
-
-    decorator.decorate(resource, context);
-
-    // remember : period1 is 5daysAgo, period2 is 10daysAgo
-    verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0, 0.0)));
-  }
-
-  @Test
-  public void save_on_one_issue_without_changelog_and_periods_have_no_dates() {
-    when(timeMachineConfiguration.periods()).thenReturn(newArrayList(new Period(1, null), new Period(2, null)));
-
-    when(issuable.issues()).thenReturn(newArrayList(
-      (Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)))
-    );
-
-    decorator.decorate(resource, context);
-
-    // remember : period1 is null, period2 is null
-    verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 5.0 * ONE_DAY_IN_MINUTES, 5.0 * ONE_DAY_IN_MINUTES)));
-  }
-
-  @Test
-  public void save_on_issues_without_changelog() {
-    when(issuable.issues()).thenReturn(newArrayList(
-      (Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)),
-      new DefaultIssue().setKey("B").setCreationDate(fiveDaysAgo).setDebt(Duration.create(TWO_DAYS_IN_MINUTES))
-    ));
-
-    decorator.decorate(resource, context);
-
-    // remember : period1 is 5daysAgo, period2 is 10daysAgo
-    verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0, 7.0 * ONE_DAY_IN_MINUTES)));
-  }
-
-  @Test
-  public void save_on_issues_with_changelog_and_issues_without_changelog() {
-    // issue1 and issue2 have changelog
-    Issue issue1 = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)).setChanges(
-      newArrayList(
-        new FieldDiffs().setDiff("technicalDebt", TWO_DAYS_IN_MINUTES, FIVE_DAYS_IN_MINUTES).setCreationDate(rightNow),
-        new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, TWO_DAYS_IN_MINUTES).setCreationDate(fourDaysAgo),
-        new FieldDiffs().setDiff("technicalDebt", null, ONE_DAY_IN_MINUTES).setCreationDate(nineDaysAgo)
-      )
-    );
-    Issue issue2 = new DefaultIssue().setKey("B").setCreationDate(tenDaysAgo).setDebt(Duration.create(TWO_DAYS_IN_MINUTES)).setChanges(
-      newArrayList(
-        new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, TWO_DAYS_IN_MINUTES).setCreationDate(rightNow),
-        new FieldDiffs().setDiff("technicalDebt", null, ONE_DAY_IN_MINUTES).setCreationDate(nineDaysAgo)
-      )
-    );
-
-    // issue3 and issue4 have no changelog
-    Issue issue3 = new DefaultIssue().setKey("C").setCreationDate(nineDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES));
-    Issue issue4 = new DefaultIssue().setKey("D").setCreationDate(fiveDaysAgo).setDebt(Duration.create(TWO_DAYS_IN_MINUTES));
-    when(issuable.issues()).thenReturn(newArrayList(issue1, issue2, issue3, issue4));
-
-    decorator.decorate(resource, context);
-
-    // remember : period1 is 5daysAgo, period2 is 10daysAgo
-    verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 5.0 * ONE_DAY_IN_MINUTES, 14.0 * ONE_DAY_IN_MINUTES)));
-  }
-
-  @Test
-  public void not_save_if_measure_already_computed() {
-    when(context.getMeasure(CoreMetrics.NEW_TECHNICAL_DEBT)).thenReturn(new Measure());
-    when(issuable.issues()).thenReturn(newArrayList(
-      (Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)),
-      new DefaultIssue().setKey("B").setCreationDate(fiveDaysAgo).setDebt(Duration.create(TWO_DAYS_IN_MINUTES))
-    ));
-
-    decorator.decorate(resource, context);
-
-    verify(context, never()).saveMeasure(argThat(new IsMeasure(CoreMetrics.NEW_TECHNICAL_DEBT)));
-  }
-
-  /**
-   * SONAR-5059
-   */
-  @Test
-  public void not_return_negative_debt() {
-    Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(ONE_DAY_IN_MINUTES)).setChanges(
-      newArrayList(
-        // changelog created at is null because it has just been created on the current analysis
-        new FieldDiffs().setDiff("technicalDebt", TWO_DAYS_IN_MINUTES, ONE_DAY_IN_MINUTES).setCreationDate(null)
-      )
-    );
-    when(issuable.issues()).thenReturn(newArrayList(issue));
-
-    decorator.decorate(resource, context);
-
-    // remember : period1 is 5daysAgo, period2 is 10daysAgo
-    verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0, 0.0)));
-  }
-
-
-  class IsVariationMeasure extends ArgumentMatcher<Measure> {
-    Metric metric = null;
-    Double var1 = null;
-    Double var2 = null;
-
-    public IsVariationMeasure(Metric metric, Double var1, Double var2) {
-      this.metric = metric;
-      this.var1 = var1;
-      this.var2 = var2;
-    }
-
-    public boolean matches(Object o) {
-      if (!(o instanceof Measure)) {
-        return false;
-      }
-      Measure m = (Measure) o;
-      return ObjectUtils.equals(metric, m.getMetric()) &&
-        ObjectUtils.equals(var1, m.getVariation1()) &&
-        ObjectUtils.equals(var2, m.getVariation2());
-    }
-  }
-
-}
index f1157f16572901bc7d3c3ed4a274e9c5e3c96616..6f9961c681a14c2bdef56adf2a4823350cee2106 100644 (file)
@@ -253,7 +253,6 @@ public class ModuleIssuesTest {
   public void set_debt_with_linear_function() {
     ruleBuilder.add(SQUID_RULE_KEY)
       .setName(SQUID_RULE_NAME)
-      .setDebtSubCharacteristic("COMPILER_RELATED_PORTABILITY")
       .setDebtRemediationFunction(DebtRemediationFunction.createLinear(Duration.create(10L)));
     activeRulesBuilder.create(SQUID_RULE_KEY).setSeverity(Severity.INFO).activate();
     initModuleIssues();
@@ -279,7 +278,6 @@ public class ModuleIssuesTest {
   public void set_debt_with_linear_with_offset_function() {
     ruleBuilder.add(SQUID_RULE_KEY)
       .setName(SQUID_RULE_NAME)
-      .setDebtSubCharacteristic("COMPILER_RELATED_PORTABILITY")
       .setDebtRemediationFunction(DebtRemediationFunction.createLinearWithOffset(Duration.create(10L), Duration.create(25L)));
     activeRulesBuilder.create(SQUID_RULE_KEY).setSeverity(Severity.INFO).activate();
     initModuleIssues();
@@ -305,7 +303,6 @@ public class ModuleIssuesTest {
   public void set_debt_with_constant_issue_function() {
     ruleBuilder.add(SQUID_RULE_KEY)
       .setName(SQUID_RULE_NAME)
-      .setDebtSubCharacteristic("COMPILER_RELATED_PORTABILITY")
       .setDebtRemediationFunction(DebtRemediationFunction.createConstantPerIssue(Duration.create(10L)));
     activeRulesBuilder.create(SQUID_RULE_KEY).setSeverity(Severity.INFO).activate();
     initModuleIssues();
@@ -331,7 +328,6 @@ public class ModuleIssuesTest {
   public void fail_to_set_debt_with_constant_issue_function_when_effort_to_fix_is_set() {
     ruleBuilder.add(SQUID_RULE_KEY)
       .setName(SQUID_RULE_NAME)
-      .setDebtSubCharacteristic("COMPILER_RELATED_PORTABILITY")
       .setDebtRemediationFunction(DebtRemediationFunction.createConstantPerIssue(Duration.create(25L)));
     activeRulesBuilder.create(SQUID_RULE_KEY).setSeverity(Severity.INFO).activate();
     initModuleIssues();
index fbe835369f3035af44dcb0c6464b009b865453d8..bdcce1bd74f6b542f94182a9e26c4f7e7304198e 100644 (file)
@@ -27,7 +27,6 @@ import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
-import org.sonar.api.CoreProperties;
 import org.sonar.api.batch.bootstrap.ProjectDefinition;
 import org.sonar.api.database.model.Snapshot;
 import org.sonar.api.resources.Project;
@@ -35,10 +34,8 @@ import org.sonar.api.rule.RuleKey;
 import org.sonar.api.utils.Duration;
 import org.sonar.batch.index.BatchComponentCache;
 import org.sonar.batch.issue.IssueCache;
-import org.sonar.batch.protocol.output.BatchReport.Metadata;
 import org.sonar.batch.protocol.output.BatchReportReader;
 import org.sonar.batch.protocol.output.BatchReportWriter;
-import org.sonar.batch.scan.ImmutableProjectReactor;
 import org.sonar.core.issue.DefaultIssue;
 import org.sonar.core.issue.FieldDiffs;
 
@@ -52,29 +49,27 @@ public class IssuesPublisherTest {
   @Rule
   public TemporaryFolder temp = new TemporaryFolder();
 
-  private IssueCache issueCache;
-  private IssuesPublisher publisher;
+  IssueCache issueCache;
+  ProjectDefinition projectDef;
+  Project project;
 
-  private ProjectDefinition root;
-
-  private Project p;
+  IssuesPublisher underTest;
 
   @Before
   public void prepare() {
-    root = ProjectDefinition.create().setKey("foo");
-    p = new Project("foo").setAnalysisDate(new Date(1234567L));
+    projectDef = ProjectDefinition.create().setKey("foo");
+    project = new Project("foo").setAnalysisDate(new Date(1234567L));
     BatchComponentCache componentCache = new BatchComponentCache();
     org.sonar.api.resources.Resource sampleFile = org.sonar.api.resources.File.create("src/Foo.php").setEffectiveKey("foo:src/Foo.php");
-    componentCache.add(p, null).setSnapshot(new Snapshot().setId(2));
-    componentCache.add(sampleFile, p);
+    componentCache.add(project, null).setSnapshot(new Snapshot().setId(2));
+    componentCache.add(sampleFile, project);
     issueCache = mock(IssueCache.class);
     when(issueCache.byComponent(anyString())).thenReturn(Collections.<DefaultIssue>emptyList());
-    publisher = new IssuesPublisher(new ImmutableProjectReactor(root), componentCache, issueCache);
+    underTest = new IssuesPublisher(componentCache, issueCache);
   }
 
   @Test
-  public void publishIssuesAndMetadata() throws Exception {
-
+  public void write_issues() throws Exception {
     DefaultIssue issue1 = new DefaultIssue();
     issue1.setKey("uuid");
     issue1.setSeverity("MAJOR");
@@ -104,34 +99,11 @@ public class IssuesPublisherTest {
     File outputDir = temp.newFolder();
     BatchReportWriter writer = new BatchReportWriter(outputDir);
 
-    publisher.publish(writer);
+    underTest.publish(writer);
 
     BatchReportReader reader = new BatchReportReader(outputDir);
-    Metadata metadata = reader.readMetadata();
-    assertThat(metadata.getAnalysisDate()).isEqualTo(1234567L);
-    assertThat(metadata.getProjectKey()).isEqualTo("foo");
-
     assertThat(reader.readComponentIssues(1)).hasSize(0);
     assertThat(reader.readComponentIssues(2)).hasSize(2);
-
-  }
-
-  @Test
-  public void publishMetadataWithBranch() throws Exception {
-    root.properties().put(CoreProperties.PROJECT_BRANCH_PROPERTY, "myBranch");
-    p.setKey("foo:myBranch");
-    p.setEffectiveKey("foo:myBranch");
-
-    File outputDir = temp.newFolder();
-    BatchReportWriter writer = new BatchReportWriter(outputDir);
-
-    publisher.publish(writer);
-
-    BatchReportReader reader = new BatchReportReader(outputDir);
-    Metadata metadata = reader.readMetadata();
-    assertThat(metadata.getAnalysisDate()).isEqualTo(1234567L);
-    assertThat(metadata.getProjectKey()).isEqualTo("foo");
-    assertThat(metadata.getBranch()).isEqualTo("myBranch");
   }
 
 }
index 94204a3afbc6e4ed567bc29de5c0fa33d8fea9e1..c4faec31bce8faff9542932ead8f77cc0dcd8531 100644 (file)
@@ -37,12 +37,12 @@ import org.sonar.api.measures.Metric.ValueType;
 import org.sonar.api.measures.MetricFinder;
 import org.sonar.api.resources.Project;
 import org.sonar.api.resources.Resource;
-import org.sonar.api.technicaldebt.batch.Characteristic;
 import org.sonar.batch.index.BatchComponentCache;
 import org.sonar.batch.protocol.output.BatchReportReader;
 import org.sonar.batch.protocol.output.BatchReportWriter;
 import org.sonar.batch.scan.measure.MeasureCache;
 
+import static java.util.Arrays.asList;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.mock;
@@ -81,12 +81,8 @@ public class MeasuresPublisherTest {
 
   @Test
   public void publishMeasures() throws Exception {
-
     Measure measure1 = new Measure<>(CoreMetrics.COVERAGE)
       .setValue(2.0)
-      .setAlertStatus(Level.ERROR)
-      .setAlertText("Foo")
-      .setCharacteristic(mock(Characteristic.class))
       .setPersonId(2);
     // No value on new_xxx
     Measure measure2 = new Measure<>(CoreMetrics.NEW_BLOCKER_VIOLATIONS)
@@ -109,8 +105,7 @@ public class MeasuresPublisherTest {
     // String value
     Measure stringMeasure = new Measure<>(CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION)
       .setData("foo bar");
-
-    when(measureCache.byResource(sampleFile)).thenReturn(Arrays.asList(measure1, measure2, manual, rating, longMeasure, stringMeasure));
+    when(measureCache.byResource(sampleFile)).thenReturn(asList(measure1, measure2, manual, rating, longMeasure, stringMeasure));
 
     File outputDir = temp.newFolder();
     BatchReportWriter writer = new BatchReportWriter(outputDir);
@@ -121,10 +116,8 @@ public class MeasuresPublisherTest {
 
     assertThat(reader.readComponentMeasures(1)).hasSize(0);
     List<org.sonar.batch.protocol.output.BatchReport.Measure> componentMeasures = reader.readComponentMeasures(2);
-    assertThat(componentMeasures).hasSize(8);
+    assertThat(componentMeasures).hasSize(6);
     assertThat(componentMeasures.get(0).getDoubleValue()).isEqualTo(2.0);
-    assertThat(componentMeasures.get(0).getAlertStatus()).isEqualTo("ERROR");
-    assertThat(componentMeasures.get(0).getAlertText()).isEqualTo("Foo");
     assertThat(componentMeasures.get(0).getPersonId()).isEqualTo(2);
 
   }
diff --git a/sonar-batch/src/test/java/org/sonar/batch/report/MetadataPublisherTest.java b/sonar-batch/src/test/java/org/sonar/batch/report/MetadataPublisherTest.java
new file mode 100644 (file)
index 0000000..23f9860
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.batch.report;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.Date;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.batch.bootstrap.ProjectDefinition;
+import org.sonar.api.batch.rule.ActiveRules;
+import org.sonar.api.batch.rule.internal.DefaultActiveRules;
+import org.sonar.api.batch.rule.internal.NewActiveRule;
+import org.sonar.api.database.model.Snapshot;
+import org.sonar.api.resources.Project;
+import org.sonar.batch.index.BatchComponentCache;
+import org.sonar.batch.protocol.output.BatchReport;
+import org.sonar.batch.protocol.output.BatchReportReader;
+import org.sonar.batch.protocol.output.BatchReportWriter;
+import org.sonar.batch.scan.ImmutableProjectReactor;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class MetadataPublisherTest {
+
+  @Rule
+  public TemporaryFolder temp = new TemporaryFolder();
+
+  ActiveRules activeRules = new DefaultActiveRules(Collections.<NewActiveRule>emptyList());
+  ProjectDefinition projectDef;
+  Project project;
+
+  MetadataPublisher underTest;
+
+  @Before
+  public void prepare() {
+    projectDef = ProjectDefinition.create().setKey("foo");
+    project = new Project("foo").setAnalysisDate(new Date(1234567L));
+    BatchComponentCache componentCache = new BatchComponentCache();
+    org.sonar.api.resources.Resource sampleFile = org.sonar.api.resources.File.create("src/Foo.php").setEffectiveKey("foo:src/Foo.php");
+    componentCache.add(project, null).setSnapshot(new Snapshot().setId(2));
+    componentCache.add(sampleFile, project);
+    underTest = new MetadataPublisher(componentCache, new ImmutableProjectReactor(projectDef), activeRules);
+  }
+
+  @Test
+  public void write_metadata() throws Exception {
+
+    File outputDir = temp.newFolder();
+    BatchReportWriter writer = new BatchReportWriter(outputDir);
+
+    underTest.publish(writer);
+
+    BatchReportReader reader = new BatchReportReader(outputDir);
+    BatchReport.Metadata metadata = reader.readMetadata();
+    assertThat(metadata.getAnalysisDate()).isEqualTo(1234567L);
+    assertThat(metadata.getProjectKey()).isEqualTo("foo");
+
+  }
+
+  @Test
+  public void write_project_branch() throws Exception {
+    projectDef.properties().put(CoreProperties.PROJECT_BRANCH_PROPERTY, "myBranch");
+    project.setKey("foo:myBranch");
+    project.setEffectiveKey("foo:myBranch");
+
+    File outputDir = temp.newFolder();
+    BatchReportWriter writer = new BatchReportWriter(outputDir);
+
+    underTest.publish(writer);
+
+    BatchReportReader reader = new BatchReportReader(outputDir);
+    BatchReport.Metadata metadata = reader.readMetadata();
+    assertThat(metadata.getAnalysisDate()).isEqualTo(1234567L);
+    assertThat(metadata.getProjectKey()).isEqualTo("foo");
+    assertThat(metadata.getBranch()).isEqualTo("myBranch");
+  }
+
+}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/rule/RulesProviderTest.java b/sonar-batch/src/test/java/org/sonar/batch/rule/RulesProviderTest.java
deleted file mode 100644 (file)
index 79ba7df..0000000
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-package org.sonar.batch.rule;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-import org.sonar.api.batch.debt.DebtRemediationFunction;
-import org.sonar.api.batch.debt.internal.DefaultDebtCharacteristic;
-import org.sonar.api.batch.debt.internal.DefaultDebtModel;
-import org.sonar.api.batch.rule.Rule;
-import org.sonar.api.batch.rule.RuleParam;
-import org.sonar.api.batch.rule.Rules;
-import org.sonar.api.config.Settings;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.Severity;
-import org.sonar.api.utils.Duration;
-import org.sonar.api.utils.Durations;
-import org.sonar.core.persistence.AbstractDaoTestCase;
-import org.sonar.core.rule.RuleDao;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assert.fail;
-
-@RunWith(MockitoJUnitRunner.class)
-public class RulesProviderTest extends AbstractDaoTestCase {
-
-  @Mock
-  Durations durations;
-
-  RuleDao ruleDao;
-
-  DefaultDebtModel debtModel;
-
-  RulesProvider provider;
-
-  @Before
-  public void setUp() {
-    debtModel = new DefaultDebtModel()
-      .addCharacteristic(new DefaultDebtCharacteristic()
-        .setId(100)
-        .setKey("MEMORY_EFFICIENCY")
-        .setName("Memory use")
-        .setOrder(1))
-      .addCharacteristic(new DefaultDebtCharacteristic()
-        .setId(101)
-        .setKey("EFFICIENCY")
-        .setName("Efficiency")
-        .setParentId(100));
-    debtModel
-      .addCharacteristic(new DefaultDebtCharacteristic()
-        .setId(102)
-        .setKey("COMPILER_RELATED_PORTABILITY")
-        .setName("Compiler")
-        .setOrder(1))
-      .addCharacteristic(new DefaultDebtCharacteristic()
-        .setId(103)
-        .setKey("PORTABILITY")
-        .setName("Portability")
-        .setParentId(102));
-
-    durations = new Durations(new Settings().setProperty("sonar.technicalDebt.hoursInDay", 8), null);
-    ruleDao = new RuleDao(getMyBatis());
-
-    provider = new RulesProvider();
-  }
-
-  @Test
-  public void build_rules() {
-    setupData("shared");
-
-    Rules rules = provider.provide(ruleDao, debtModel, durations);
-
-    assertThat(rules.findAll()).hasSize(1);
-    assertThat(rules.findByRepository("checkstyle")).hasSize(1);
-    assertThat(rules.findByRepository("unknown")).isEmpty();
-
-    Rule rule = rules.find(RuleKey.of("checkstyle", "AvoidNull"));
-    assertThat(rule).isNotNull();
-    assertThat(rule.key()).isEqualTo(RuleKey.of("checkstyle", "AvoidNull"));
-    assertThat(rule.name()).isEqualTo("Avoid Null");
-    assertThat(rule.description()).isEqualTo("Should avoid NULL");
-    assertThat(rule.severity()).isEqualTo(Severity.MINOR);
-    assertThat(rule.internalKey()).isNull();
-    assertThat(rule.params()).hasSize(1);
-
-    RuleParam param = rule.param("myParameter");
-    assertThat(param).isNotNull();
-    assertThat(param.description()).isEqualTo("My Parameter");
-  }
-
-  @Test
-  public void build_rules_with_default_debt_definitions() {
-    setupData("build_rules_with_default_debt_definitions");
-
-    Rules rules = provider.provide(ruleDao, debtModel, durations);
-
-    Rule rule = rules.find(RuleKey.of("checkstyle", "AvoidNull"));
-    assertThat(rule.debtSubCharacteristic()).isEqualTo("EFFICIENCY");
-    assertThat(rule.debtRemediationFunction()).isEqualTo(DebtRemediationFunction.createLinearWithOffset(Duration.decode("5d", 8), Duration.decode("10h", 8)));
-  }
-
-  @Test
-  public void build_rules_with_overridden_debt_definitions() {
-    setupData("build_rules_with_overridden_debt_definitions");
-
-    Rules rules = provider.provide(ruleDao, debtModel, durations);
-
-    Rule rule = rules.find(RuleKey.of("checkstyle", "AvoidNull"));
-    assertThat(rule.debtSubCharacteristic()).isEqualTo("PORTABILITY");
-    assertThat(rule.debtRemediationFunction()).isEqualTo(DebtRemediationFunction.createLinear(Duration.decode("2h", 8)));
-  }
-
-  @Test
-  public void build_rules_with_default_and_overridden_debt_definitions() {
-    setupData("build_rules_with_default_and_overridden_debt_definitions");
-
-    Rules rules = provider.provide(ruleDao, debtModel, durations);
-
-    // As both default columns and user columns on debt are set, user debt columns should be used
-    Rule rule = rules.find(RuleKey.of("checkstyle", "AvoidNull"));
-    assertThat(rule.debtSubCharacteristic()).isEqualTo("PORTABILITY");
-    assertThat(rule.debtRemediationFunction()).isEqualTo(DebtRemediationFunction.createLinear(Duration.decode("2h", 8)));
-  }
-
-  @Test
-  public void build_rules_with_default_characteristic_and_overridden_function() {
-    setupData("build_rules_with_default_characteristic_and_overridden_function");
-
-    Rules rules = provider.provide(ruleDao, debtModel, durations);
-
-    // As both default columns and user columns on debt are set, user debt columns should be used
-    Rule rule = rules.find(RuleKey.of("checkstyle", "AvoidNull"));
-    assertThat(rule.debtSubCharacteristic()).isEqualTo("PORTABILITY");
-    assertThat(rule.debtRemediationFunction()).isEqualTo(DebtRemediationFunction.createLinear(Duration.decode("2h", 8)));
-  }
-
-  @Test
-  public void build_rules_with_overridden_characteristic_and_default_function() {
-    setupData("build_rules_with_overridden_characteristic_and_default_function");
-
-    Rules rules = provider.provide(ruleDao, debtModel, durations);
-
-    // As both default columns and user columns on debt are set, user debt columns should be used
-    Rule rule = rules.find(RuleKey.of("checkstyle", "AvoidNull"));
-    assertThat(rule.debtSubCharacteristic()).isEqualTo("PORTABILITY");
-    assertThat(rule.debtRemediationFunction()).isEqualTo(DebtRemediationFunction.createLinear(Duration.decode("2h", 8)));
-  }
-
-  @Test
-  public void build_rules_with_disable_characteristic() {
-    setupData("build_rules_with_disable_characteristic");
-
-    Rules rules = provider.provide(ruleDao, debtModel, durations);
-
-    Rule rule = rules.find(RuleKey.of("checkstyle", "AvoidNull"));
-    assertThat(rule.debtSubCharacteristic()).isNull();
-    assertThat(rule.debtRemediationFunction()).isNull();
-  }
-
-  @Test
-  public void build_rules_with_default_characteristic_and_disable_characteristic() {
-    setupData("build_rules_with_default_characteristic_and_disable_characteristic");
-
-    Rules rules = provider.provide(ruleDao, debtModel, durations);
-
-    Rule rule = rules.find(RuleKey.of("checkstyle", "AvoidNull"));
-    assertThat(rule.debtSubCharacteristic()).isNull();
-    assertThat(rule.debtRemediationFunction()).isNull();
-  }
-
-  @Test
-  public void fail_if_characteristic_not_found() {
-    setupData("fail_if_characteristic_not_found");
-
-    try {
-      provider.provide(ruleDao, debtModel, durations);
-      fail();
-    } catch (Exception e) {
-      assertThat(e).isInstanceOf(IllegalStateException.class).hasMessage("Sub characteristic id '999' on rule 'checkstyle:AvoidNull' has not been found");
-    }
-  }
-
-  @Test
-  public void fail_if_no_function() {
-    setupData("fail_if_no_function");
-
-    try {
-      provider.provide(ruleDao, debtModel, durations);
-      fail();
-    } catch (Exception e) {
-      assertThat(e).isInstanceOf(IllegalStateException.class).hasMessage("Remediation function should not be null on rule 'checkstyle:AvoidNull'");
-    }
-  }
-}
index 58dcf64ffdfc23a6b7f6ff1cfbab5442af194e17..505ee23191e54291916802344ff2bfb5f4125f82 100644 (file)
@@ -34,8 +34,6 @@ import org.sonar.api.resources.Directory;
 import org.sonar.api.resources.File;
 import org.sonar.api.resources.Project;
 import org.sonar.api.resources.Resource;
-import org.sonar.api.technicaldebt.batch.Characteristic;
-import org.sonar.api.technicaldebt.batch.Requirement;
 import org.sonar.batch.index.AbstractCachesTest;
 import org.sonar.batch.index.Cache.Entry;
 
@@ -64,7 +62,6 @@ public class MeasureCacheTest extends AbstractCachesTest {
     Project p = new Project("struts");
 
     assertThat(measureCache.entries()).hasSize(0);
-
     assertThat(measureCache.byResource(p)).hasSize(0);
 
     Measure m = new Measure(CoreMetrics.NCLOC, 1.0);
@@ -227,29 +224,14 @@ public class MeasureCacheTest extends AbstractCachesTest {
   public void test_measure_coder() throws Exception {
     Resource file1 = File.create("foo/bar/File1.txt").setEffectiveKey("struts:foo/bar/File1.txt");
 
-    Measure measure = new Measure(CoreMetrics.NCLOC, 1.786, 5);
-    measureCache.put(file1, measure);
-
-    Measure savedMeasure = measureCache.byResource(file1).iterator().next();
-
-    assertThat(EqualsBuilder.reflectionEquals(measure, savedMeasure)).isTrue();
-
-    measure = new Measure(CoreMetrics.NCLOC);
+    Measure measure = new Measure(CoreMetrics.NCLOC, 3.14);
     measure.setData("data");
     measure.setAlertStatus(Level.ERROR);
     measure.setAlertText("alert");
-    Characteristic c = mock(Characteristic.class);
-    when(c.id()).thenReturn(1);
-    when(techDebtModel.characteristicById(1)).thenReturn(c);
-    measure.setCharacteristic(c);
     measure.setDate(new Date());
     measure.setDescription("description");
     measure.setPersistenceMode(null);
     measure.setPersonId(3);
-    Requirement r = mock(Requirement.class);
-    when(r.id()).thenReturn(7);
-    when(techDebtModel.requirementsById(7)).thenReturn(r);
-    measure.setRequirement(r);
     measure.setUrl("http://foo");
     measure.setVariation1(11.0);
     measure.setVariation2(12.0);
@@ -258,7 +240,7 @@ public class MeasureCacheTest extends AbstractCachesTest {
     measure.setVariation5(15.0);
     measureCache.put(file1, measure);
 
-    savedMeasure = measureCache.byResource(file1).iterator().next();
+    Measure savedMeasure = measureCache.byResource(file1).iterator().next();
     assertThat(EqualsBuilder.reflectionEquals(measure, savedMeasure)).isTrue();
 
   }
index 7ac05f224f641aa7e59386fd92372619a73cde5a..cfacc608706bd9d0f729157fc813853ca6589810 100644 (file)
  */
 package org.sonar.core.dashboard;
 
+import java.util.List;
+import javax.annotation.Nullable;
 import org.apache.ibatis.session.SqlSession;
-import org.sonar.api.batch.BatchSide;
 import org.sonar.api.server.ServerSide;
 import org.sonar.core.persistence.DaoComponent;
 import org.sonar.core.persistence.MyBatis;
 
-import javax.annotation.Nullable;
-
-import java.util.List;
-
-@BatchSide
 @ServerSide
 public class ActiveDashboardDao implements DaoComponent {
 
index 774956178fe1603bd801219e0aef8833c0a60bf7..cc75c1e1a93ab8794033cf58be9862f47374e370 100644 (file)
 package org.sonar.core.issue.db;
 
 import com.google.common.collect.Lists;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
 import org.apache.ibatis.session.SqlSession;
-import org.sonar.api.batch.BatchSide;
 import org.sonar.api.server.ServerSide;
 import org.sonar.core.persistence.DaoComponent;
 import org.sonar.core.persistence.MyBatis;
 
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
 import static com.google.common.collect.Lists.newArrayList;
 
-/**
- * @since 3.6
- */
-@BatchSide
 @ServerSide
 public class ActionPlanDao implements DaoComponent {
 
index a400a04c9cd3eb3c66bbc037bc3ceaf01c03ff7c..3e7c21e8d2398408fde53f43b800d25886763e92 100644 (file)
 package org.sonar.core.issue.db;
 
 import com.google.common.collect.Lists;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
-import java.util.Map;
 import javax.annotation.CheckForNull;
-import org.apache.ibatis.session.ResultHandler;
-import org.sonar.api.batch.BatchSide;
+import org.sonar.api.server.ServerSide;
 import org.sonar.core.issue.DefaultIssueComment;
 import org.sonar.core.issue.FieldDiffs;
-import org.sonar.api.server.ServerSide;
 import org.sonar.core.persistence.DaoComponent;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.core.persistence.MyBatis;
 
 import static com.google.common.collect.Lists.newArrayList;
-import static com.google.common.collect.Maps.newHashMap;
+import static java.util.Arrays.asList;
 
-/**
- * @since 3.6
- */
-@BatchSide
 @ServerSide
 public class IssueChangeDao implements DaoComponent {
 
@@ -64,7 +56,7 @@ public class IssueChangeDao implements DaoComponent {
     DbSession session = mybatis.openSession(false);
     try {
       List<FieldDiffs> result = Lists.newArrayList();
-      for (IssueChangeDto dto : selectByIssuesAndType(session, Arrays.asList(issueKey), IssueChangeDto.TYPE_FIELD_CHANGE)) {
+      for (IssueChangeDto dto : selectByIssuesAndType(session, asList(issueKey), IssueChangeDto.TYPE_FIELD_CHANGE)) {
         result.add(dto.toFieldDiffs());
       }
       return result;
@@ -73,13 +65,11 @@ public class IssueChangeDao implements DaoComponent {
     }
   }
 
-  public void selectChangelogOnNonClosedIssuesByModuleAndType(long componentId, ResultHandler handler) {
+  public List<IssueChangeDto> selectChangelogOfUnresolvedIssuesByComponent(String componentUuid) {
     DbSession session = mybatis.openSession(false);
     try {
-      Map<String, Object> params = newHashMap();
-      params.put("componentId", componentId);
-      params.put("changeType", IssueChangeDto.TYPE_FIELD_CHANGE);
-      session.select("org.sonar.core.issue.db.IssueChangeMapper.selectChangelogOnNonClosedIssuesByModuleAndType", params, handler);
+      IssueChangeMapper mapper = session.getMapper(IssueChangeMapper.class);
+      return mapper.selectChangelogOfUnresolvedIssuesByComponent(componentUuid, IssueChangeDto.TYPE_FIELD_CHANGE);
 
     } finally {
       MyBatis.closeQuietly(session);
index cadf024cda41062d87bfdff41bdb6bf1b9b2ab11..732ddc5c75bf2fa2ca186b4bc0cefd0ef96d4844 100644 (file)
 
 package org.sonar.core.issue.db;
 
-import org.apache.ibatis.annotations.Param;
-
-import javax.annotation.CheckForNull;
-
 import java.util.List;
+import javax.annotation.CheckForNull;
+import org.apache.ibatis.annotations.Param;
 
-/**
- * @since 3.6
- */
 public interface IssueChangeMapper {
 
   void insert(IssueChangeDto dto);
@@ -38,13 +33,13 @@ public interface IssueChangeMapper {
   int update(IssueChangeDto change);
 
   @CheckForNull
-  IssueChangeDto selectByKeyAndType(@Param("key") String key,
-                                    @Param("changeType") String type);
+  IssueChangeDto selectByKeyAndType(@Param("key") String key, @Param("changeType") String type);
+
   /**
    * Issue changes by chronological date of creation
    */
   List<IssueChangeDto> selectByIssuesAndType(@Param("issueKeys") List<String> issueKeys,
-                                             @Param("changeType") String changeType);
+    @Param("changeType") String changeType);
 
-  List<IssueChangeDto> selectByIssue(String issueKey);
+  List<IssueChangeDto> selectChangelogOfUnresolvedIssuesByComponent(@Param("componentUuid") String componentUuid, @Param("changeType") String changeType);
 }
index 44baff06b8cb7c566dad931c7f0349adf1f5df1e..ec3b3b60cea8511f415749683edd68304b6f1356 100644 (file)
@@ -661,6 +661,7 @@ public final class IssueDto implements Serializable {
     issue.setEffortToFix(effortToFix);
     issue.setDebt(debt != null ? Duration.create(debt) : null);
     issue.setLine(line);
+    issue.setChecksum(checksum);
     issue.setSeverity(severity);
     issue.setReporter(reporter);
     issue.setAssignee(assignee);
index aba2531071ed47386604c94e328f5603e02ac102..a3a8f61c4908e5c53cd701acf46d11dece8017dc 100644 (file)
@@ -26,7 +26,7 @@ public interface IssueMapper {
 
   IssueDto selectByKey(String key);
 
-  List<IssueDto> selectOpenByComponentUuid(String componentUuid);
+  List<IssueDto> selectNonClosedByComponentUuid(String componentUuid);
 
   Set<String> selectComponentUuidsOfOpenIssuesForProjectUuid(String projectUuid);
 
index 0406c631f09a51666f46b95a0f0ac7cc783761a6..2a5dc580a81f02988ba7f62f628c94b788183675 100644 (file)
@@ -31,7 +31,7 @@ public abstract class LazyInput<ISSUE extends Trackable> implements Input<ISSUE>
   @Override
   public LineHashSequence getLineHashSequence() {
     if (lineHashSeq == null) {
-      lineHashSeq = LineHashSequence.createForLines(loadSourceLines());
+      lineHashSeq = loadLineHashSequence();
     }
     return lineHashSeq;
   }
@@ -52,7 +52,7 @@ public abstract class LazyInput<ISSUE extends Trackable> implements Input<ISSUE>
     return issues;
   }
 
-  protected abstract Iterable<String> loadSourceLines();
+  protected abstract LineHashSequence loadLineHashSequence();
 
   protected abstract List<ISSUE> loadIssues();
 }
index 8691757440cec2b000847dc2da51f8c42f27d620..5da2ca5da04440457379c5ae531bd5db6d4473f0 100644 (file)
@@ -27,7 +27,9 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Objects;
 import javax.annotation.Nonnull;
+import org.apache.commons.lang.StringUtils;
 import org.sonar.api.rule.RuleKey;
+import org.sonar.api.utils.log.Loggers;
 
 import static com.google.common.collect.FluentIterable.from;
 
@@ -43,7 +45,7 @@ public class Tracker<RAW extends Trackable, BASE extends Trackable> {
     detectCodeMoves(rawInput, baseInput, tracking);
 
     // 3. match issues with same rule, same message and same line hash
-    match(tracking, LineHashAndMessagekeyFactory.INSTANCE);
+    match(tracking, LineHashAndMessageKeyFactory.INSTANCE);
 
     // 4. match issues with same rule, same line and same message
     match(tracking, LineAndMessageKeyFactory.INSTANCE);
@@ -135,7 +137,7 @@ public class Tracker<RAW extends Trackable, BASE extends Trackable> {
     LineAndLineHashKey(Trackable trackable) {
       this.ruleKey = trackable.getRuleKey();
       this.line = trackable.getLine();
-      this.lineHash = trackable.getLineHash();
+      this.lineHash = StringUtils.defaultString(trackable.getLineHash(), "");
     }
 
     @Override
@@ -178,7 +180,7 @@ public class Tracker<RAW extends Trackable, BASE extends Trackable> {
     LineHashAndMessageKey(Trackable trackable) {
       this.ruleKey = trackable.getRuleKey();
       this.message = trackable.getMessage();
-      this.lineHash = trackable.getLineHash();
+      this.lineHash = StringUtils.defaultString(trackable.getLineHash(), "");
     }
 
     @Override
@@ -206,7 +208,7 @@ public class Tracker<RAW extends Trackable, BASE extends Trackable> {
     }
   }
 
-  private enum LineHashAndMessagekeyFactory implements SearchKeyFactory {
+  private enum LineHashAndMessageKeyFactory implements SearchKeyFactory {
     INSTANCE;
     @Override
     public SearchKey create(Trackable t) {
index 27f34ac3887cd198a83adde69c62fe764b6880c7..f2a5306e500677611298a3a68814f7c0aae98c04 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.core.issue.tracking;
 
+import com.google.common.base.Objects;
 import com.google.common.collect.ArrayListMultimap;
 import com.google.common.collect.Multimap;
 import java.util.Collection;
@@ -53,14 +54,7 @@ public class Tracking<RAW extends Trackable, BASE extends Trackable> {
   private final Multimap<Integer, BASE> openManualIssues = ArrayListMultimap.create();
 
   public Tracking(Input<RAW> rawInput, Input<BASE> baseInput) {
-    for (RAW raw : rawInput.getIssues()) {
-      // Extra verification if some plugins create issues on wrong lines
-      Integer rawLine = raw.getLine();
-      if (rawLine != null && !rawInput.getLineHashSequence().hasLine(rawLine)) {
-        throw new IllegalArgumentException("Issue line is not valid: " + raw);
-      }
-      this.unmatchedRaws.add(raw);
-    }
+    this.unmatchedRaws.addAll(rawInput.getIssues());
     this.unmatchedBases.addAll(baseInput.getIssues());
   }
 
@@ -90,15 +84,24 @@ public class Tracking<RAW extends Trackable, BASE extends Trackable> {
 
   void associateRawToBase(RAW raw, BASE base) {
     rawToBase.put(raw, base);
-    unmatchedBases.remove(base);
+    if (!unmatchedBases.remove(base)) {
+      throw new IllegalStateException(String.format("Fail to associate base issue %s to %s among %s", base, raw, this));
+    }
   }
 
   void markRawAsAssociated(RAW raw) {
-    unmatchedRaws.remove(raw);
+    if (!unmatchedRaws.remove(raw)) {
+      throw new IllegalStateException(String.format("Fail to mark issue as associated: %s among %s", raw, this));
+    }
   }
 
   void markRawsAsAssociated(Collection<RAW> c) {
-    unmatchedRaws.removeAll(c);
+    // important : do not use unmatchedRaws.removeAll(Collection) as it's buggy. See:
+    // http://stackoverflow.com/questions/19682542/why-identityhashmap-keyset-removeallkeys-does-not-use-identity-is-it-a-bug/19682543#19682543
+    // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6588783
+    for (RAW raw : c) {
+      markRawAsAssociated(raw);
+    }
   }
 
   boolean isComplete() {
@@ -113,4 +116,14 @@ public class Tracking<RAW extends Trackable, BASE extends Trackable> {
     openManualIssues.put(line, manualIssue);
     unmatchedBases.remove(manualIssue);
   }
+
+  @Override
+  public String toString() {
+    return Objects.toStringHelper(this)
+      .add("rawToBase", rawToBase)
+      .add("unmatchedRaws", unmatchedRaws)
+      .add("unmatchedBases", unmatchedBases)
+      .add("openManualIssues", openManualIssues)
+      .toString();
+  }
 }
index cee06ac4181833b48d01566140257878417f3b2a..49b874220e7db730d9822c757e9a87e86a846f60 100644 (file)
@@ -29,7 +29,7 @@ public enum SetClosed implements Function {
   public void execute(Context context) {
     DefaultIssue issue = (DefaultIssue) context.issue();
     if (!issue.isBeingClosed()) {
-      throw new IllegalStateException("Issue is still alive: " + issue);
+      throw new IllegalStateException("Issue is still open: " + issue);
     }
     if (issue.isOnDisabledRule()) {
       context.setResolution(Issue.RESOLUTION_REMOVED);
index da0a5f122244aa84293b54121ac5e2516bfd0b43..09849be20fb378b7efddee5577d8fb13cab33bf1 100644 (file)
@@ -19,8 +19,5 @@
  */
 package org.sonar.core.persistence;
 
-/**
- * @since 4.4
- */
 public interface DaoComponent {
 }
diff --git a/sonar-core/src/main/java/org/sonar/core/technicaldebt/DefaultTechnicalDebtModel.java b/sonar-core/src/main/java/org/sonar/core/technicaldebt/DefaultTechnicalDebtModel.java
deleted file mode 100644 (file)
index a7016a5..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-package org.sonar.core.technicaldebt;
-
-import com.google.common.base.Predicate;
-import com.google.common.collect.Iterables;
-import org.sonar.api.batch.RequiresDB;
-import org.sonar.api.batch.debt.DebtCharacteristic;
-import org.sonar.api.batch.debt.DebtModel;
-import org.sonar.api.batch.debt.internal.DefaultDebtCharacteristic;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.technicaldebt.batch.TechnicalDebtModel;
-import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
-import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
-
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
-import java.util.Collections;
-import java.util.List;
-
-import static com.google.common.collect.Lists.newArrayList;
-
-@RequiresDB
-public class DefaultTechnicalDebtModel implements TechnicalDebtModel {
-
-  private final DebtModel model;
-
-  public DefaultTechnicalDebtModel(DebtModel model) {
-    this.model = model;
-  }
-
-  public List<DefaultCharacteristic> rootCharacteristics() {
-    return newArrayList(Iterables.filter(characteristics(), new Predicate<DefaultCharacteristic>() {
-      @Override
-      public boolean apply(DefaultCharacteristic input) {
-        return input.isRoot();
-      }
-    }));
-  }
-
-  @Override
-  @CheckForNull
-  public DefaultCharacteristic characteristicByKey(final String key) {
-    return Iterables.find(characteristics(), new Predicate<DefaultCharacteristic>() {
-      @Override
-      public boolean apply(DefaultCharacteristic input) {
-        return input.key().equals(key);
-      }
-    }, null);
-  }
-
-  @Override
-  @CheckForNull
-  public DefaultCharacteristic characteristicById(final Integer id) {
-    return Iterables.find(characteristics(), new Predicate<DefaultCharacteristic>() {
-      @Override
-      public boolean apply(DefaultCharacteristic input) {
-        return input.id().equals(id);
-      }
-    }, null);
-  }
-
-  @Override
-  @CheckForNull
-  public DefaultRequirement requirementsByRule(final RuleKey ruleKey) {
-    return null;
-  }
-
-  @Override
-  @CheckForNull
-  public DefaultRequirement requirementsById(final Integer id) {
-    return null;
-  }
-
-  @Override
-  public List<DefaultCharacteristic> characteristics() {
-    List<DefaultCharacteristic> flatCharacteristics = newArrayList();
-    for (DebtCharacteristic characteristic : model.characteristics()) {
-      DefaultCharacteristic root = toDefaultCharacteristic((DefaultDebtCharacteristic) characteristic, null);
-      flatCharacteristics.add(root);
-      for (DebtCharacteristic subCharacteristic : model.subCharacteristics(characteristic.key())) {
-        flatCharacteristics.add(toDefaultCharacteristic((DefaultDebtCharacteristic) subCharacteristic, root));
-      }
-    }
-    return flatCharacteristics;
-  }
-
-  @Override
-  public List<DefaultRequirement> requirements() {
-    return Collections.emptyList();
-  }
-
-  public boolean isEmpty() {
-    return model.allCharacteristics().isEmpty();
-  }
-
-  private static DefaultCharacteristic toDefaultCharacteristic(DefaultDebtCharacteristic debtCharacteristic, @Nullable DefaultCharacteristic parentCharacteristic) {
-    return new DefaultCharacteristic()
-      .setId(debtCharacteristic.id())
-      .setKey(debtCharacteristic.key())
-      .setName(debtCharacteristic.name())
-      .setOrder(debtCharacteristic.order())
-      .setParent(parentCharacteristic)
-      .setRoot(parentCharacteristic)
-      .setCreatedAt(debtCharacteristic.createdAt())
-      .setUpdatedAt(debtCharacteristic.updatedAt());
-  }
-
-}
index 47d0bc96d717f57fed5bd942e328fe797f8b36b1..e810f1dc33c8d14322c7a640a2f7f5a383c9d641 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8" ?>
 
-<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mappei.dtd">
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 
 <mapper namespace="org.sonar.core.issue.db.IssueChangeMapper">
 
     order by c.created_at
   </select>
 
-  <select id="selectChangelogOnNonClosedIssuesByModuleAndType" parameterType="map" resultType="IssueChange">
-    select
-    <include refid="issueChangeColumns"/>
-    from issue_changes c
-    inner join issues i on i.kee = c.issue_key
-    inner join (select p.id, p.uuid, p.kee from projects p where (p.root_id=#{componentId} and p.qualifier &lt;&gt; 'BRC') or
-    (p.id=#{componentId})) p on p.uuid=i.component_uuid
-    <where>
-      and c.change_type=#{changeType}
-      and i.status &lt;&gt; 'CLOSED'
-    </where>
-    order by c.issue_change_creation_date asc
-  </select>
-
   <select id="selectByKeyAndType" parameterType="map" resultType="IssueChange">
     select
     <include refid="issueChangeColumns"/>
     where c.issue_key=#{id}
     order by created_at asc
   </select>
+
+  <select id="selectChangelogOfUnresolvedIssuesByComponent" parameterType="map" resultType="IssueChange">
+    select
+    <include refid="issueChangeColumns"/>
+    from issue_changes c
+    inner join issues i on i.kee = c.issue_key
+    where i.component_uuid=#{componentUuid}
+    and c.change_type=#{changeType}
+    and i.resolution is null
+  </select>
 </mapper>
 
index 50eb94db4d34ecf7da4f7c3fea528e26a43c5608..a6511b063296ee1c9641148aa081ae69f71e4012 100644 (file)
     where i.kee=#{kee}
   </select>
 
-  <select id="selectOpenByComponentUuid" parameterType="String" resultType="Issue">
+  <select id="selectNonClosedByComponentUuid" parameterType="String" resultType="Issue">
     select
-    i.id,
-    i.kee as kee,
-    i.rule_id as ruleId,
-    i.action_plan_key as actionPlanKey,
-    i.severity as severity,
-    i.manual_severity as manualSeverity,
-    i.message as message,
-    i.line as line,
-    i.effort_to_fix as effortToFix,
-    i.technical_debt as debt,
-    i.status as status,
-    i.resolution as resolution,
-    i.checksum as checksum,
-    i.reporter as reporter,
-    i.assignee as assignee,
-    i.author_login as authorLogin,
-    i.tags as tagsString,
-    i.issue_attributes as issueAttributes,
-    i.issue_creation_date as issueCreationTime,
-    i.issue_update_date as issueUpdateTime,
-    i.issue_close_date as issueCloseTime,
-    i.created_at as createdAt,
-    i.updated_at as updatedAt,
-    r.plugin_rule_key as ruleKey,
-    i.component_uuid as componentUuid,
-    i.project_uuid as projectUuid
+    <include refid="issueColumns"/>
     from issues i
     inner join rules r on r.id=i.rule_id
+    inner join projects p on p.uuid=i.component_uuid
+    inner join projects root on root.uuid=i.project_uuid
     where
     i.component_uuid=#{componentUuid} and
     i.status &lt;&gt; 'CLOSED'
index 411048b421e5cb4175803ec972c5c27e2e6c57ef..2d379cfee6cb6f5d42263bdd5ca9e6afa57b5358 100644 (file)
  */
 package org.sonar.core.issue.db;
 
-import org.apache.ibatis.executor.result.DefaultResultHandler;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.sonar.api.utils.DateUtils;
 import org.sonar.core.issue.DefaultIssueComment;
 import org.sonar.core.issue.FieldDiffs;
-import org.sonar.api.utils.DateUtils;
 import org.sonar.core.persistence.AbstractDaoTestCase;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.core.persistence.MyBatis;
 
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
 import static com.google.common.collect.Lists.newArrayList;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
@@ -115,45 +113,11 @@ public class IssueChangeDaoTest extends AbstractDaoTestCase {
   }
 
   @Test
-  public void select_issue_changelog_by_module() {
-    setupData("select_issue_changelog_by_module");
-
-    // 400 is a non-root module, we should find 2 + 1 changelog from classes and one on itself
-    DefaultResultHandler handler = new DefaultResultHandler();
-    dao.selectChangelogOnNonClosedIssuesByModuleAndType(400, handler);
-    assertThat(handler.getResultList()).hasSize(4);
-
-    IssueChangeDto issueChangeDto = (IssueChangeDto) handler.getResultList().get(0);
-    assertThat(issueChangeDto.getId()).isNotNull();
-    assertThat(issueChangeDto.getKey()).isNotNull();
-    assertThat(issueChangeDto.getIssueKey()).isNotNull();
-    assertThat(issueChangeDto.getUserLogin()).isNotNull();
-    assertThat(issueChangeDto.getChangeType()).isNotNull();
-    assertThat(issueChangeDto.getChangeData()).isNotNull();
-    assertThat(issueChangeDto.getCreatedAt()).isNotNull();
-    assertThat(issueChangeDto.getUpdatedAt()).isNotNull();
-
-    for (Object changeDtoObject : handler.getResultList()) {
-      IssueChangeDto changeDto = (IssueChangeDto) changeDtoObject;
-      assertThat(changeDto.getChangeType()).isEqualTo(IssueChangeDto.TYPE_FIELD_CHANGE);
-    }
+  public void selectChangelogOfUnresolvedIssuesByComponent() {
+    setupData("selectChangelogOfUnresolvedIssuesByComponent");
 
-    // 399 is the root module, we should only find 1 changelog on itself
-    handler = new DefaultResultHandler();
-    dao.selectChangelogOnNonClosedIssuesByModuleAndType(399, handler);
-    assertThat(handler.getResultList()).hasSize(1);
-  }
-
-  @Test
-  public void select_issue_changelog_by_module_should_be_sorted_by_creation_date() {
-    setupData("select_issue_changelog_by_module_are_sorted_by_creation_date");
-
-    DefaultResultHandler handler = new DefaultResultHandler();
-    dao.selectChangelogOnNonClosedIssuesByModuleAndType(399, handler);
-    assertThat(handler.getResultList()).hasSize(3);
-    assertThat(((IssueChangeDto) handler.getResultList().get(0)).getId()).isEqualTo(1001);
-    assertThat(((IssueChangeDto) handler.getResultList().get(1)).getId()).isEqualTo(1002);
-    assertThat(((IssueChangeDto) handler.getResultList().get(2)).getId()).isEqualTo(1000);
+    List<IssueChangeDto> dtos = dao.selectChangelogOfUnresolvedIssuesByComponent("FILE_1");
+    assertThat(dtos).extracting("id").containsExactly(100L);
   }
 
   @Test
index 37391225a8468db964d789dfd41fb8708ce5608b..a9fe647095e205692d4bfa6debd55fa9630b2bb8 100644 (file)
@@ -196,13 +196,13 @@ public class TrackerTest {
   }
 
   @Test
-  public void fail_if_raw_line_does_not_exist() throws Exception {
+  public void do_not_fail_if_raw_line_does_not_exist() throws Exception {
     FakeInput baseInput = new FakeInput();
     FakeInput rawInput = new FakeInput("H1").addIssue(new Issue(200, "H200", RULE_SYSTEM_PRINT, "msg"));
 
-    thrown.expect(IllegalArgumentException.class);
-    thrown.expectMessage("Issue line is not valid");
-    tracker.track(rawInput, baseInput);
+    Tracking<Issue, Issue> tracking = tracker.track(rawInput, baseInput);
+
+    assertThat(tracking.getUnmatchedRaws()).hasSize(1);
   }
 
   /**
@@ -406,7 +406,7 @@ public class TrackerTest {
     private final List<Issue> issues = new ArrayList<>();
     private final List<String> lineHashes;
 
-    public FakeInput(String... lineHashes) {
+    FakeInput(String... lineHashes) {
       this.lineHashes = asList(lineHashes);
     }
 
@@ -418,7 +418,7 @@ public class TrackerTest {
       return new FakeInput(hashes);
     }
 
-    public Issue createIssueOnLine(int line, RuleKey ruleKey, String message) {
+    Issue createIssueOnLine(int line, RuleKey ruleKey, String message) {
       Issue issue = new Issue(line, lineHashes.get(line - 1), ruleKey, message);
       issues.add(issue);
       return issue;
@@ -427,13 +427,13 @@ public class TrackerTest {
     /**
      * No line (line 0)
      */
-    public Issue createIssue(RuleKey ruleKey, String message) {
+    Issue createIssue(RuleKey ruleKey, String message) {
       Issue issue = new Issue(null, "", ruleKey, message);
       issues.add(issue);
       return issue;
     }
 
-    public FakeInput addIssue(Issue issue) {
+    FakeInput addIssue(Issue issue) {
       this.issues.add(issue);
       return this;
     }
index 84e46786292d0a9be78f77e1bd4d70077de90706..3418cd9d1d3c2743788d3cdb96e6f6e008b11d0d 100644 (file)
@@ -56,7 +56,7 @@ public class SetClosedTest {
       INSTANCE.execute(context);
       fail();
     } catch (IllegalStateException e) {
-      assertThat(e.getMessage()).contains("Issue is still alive");
+      assertThat(e.getMessage()).contains("Issue is still open");
       verify(context, never()).setResolution(anyString());
     }
   }
diff --git a/sonar-core/src/test/java/org/sonar/core/technicaldebt/DefaultTechnicalDebtModelTest.java b/sonar-core/src/test/java/org/sonar/core/technicaldebt/DefaultTechnicalDebtModelTest.java
deleted file mode 100644 (file)
index 3ea3a31..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-package org.sonar.core.technicaldebt;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.sonar.api.batch.debt.internal.DefaultDebtCharacteristic;
-import org.sonar.api.batch.debt.internal.DefaultDebtModel;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class DefaultTechnicalDebtModelTest {
-
-  private DefaultTechnicalDebtModel sqaleModel;
-
-  @Before
-  public void setUp() {
-    DefaultDebtModel debtModel = new DefaultDebtModel();
-    debtModel.addCharacteristic(
-      new DefaultDebtCharacteristic().setId(1)
-        .setKey("MEMORY_EFFICIENCY")
-        .setName("Memory use")
-        .setOrder(1)
-    );
-    debtModel.addSubCharacteristic(
-      new DefaultDebtCharacteristic().setId(2)
-        .setKey("EFFICIENCY")
-        .setName("Efficiency")
-        .setParentId(1),
-      "MEMORY_EFFICIENCY"
-    );
-    sqaleModel = new DefaultTechnicalDebtModel(debtModel);
-  }
-
-  @Test
-  public void get_characteristics() {
-    assertThat(sqaleModel.rootCharacteristics()).hasSize(1);
-
-    DefaultCharacteristic resultRootCharacteristic = sqaleModel.rootCharacteristics().get(0);
-    assertThat(resultRootCharacteristic.id()).isEqualTo(1);
-    assertThat(resultRootCharacteristic.key()).isEqualTo("MEMORY_EFFICIENCY");
-    assertThat(resultRootCharacteristic.name()).isEqualTo("Memory use");
-    assertThat(resultRootCharacteristic.order()).isEqualTo(1);
-    assertThat(resultRootCharacteristic.children()).hasSize(1);
-    assertThat(resultRootCharacteristic.parent()).isNull();
-    assertThat(resultRootCharacteristic.root()).isNull();
-  }
-
-  @Test
-  public void get_characteristic_by_key() {
-    assertThat(sqaleModel.characteristicByKey("MEMORY_EFFICIENCY")).isNotNull();
-    assertThat(sqaleModel.characteristicByKey("EFFICIENCY")).isNotNull();
-    assertThat(sqaleModel.characteristicByKey("EFFICIENCY").parent()).isNotNull();
-
-    assertThat(sqaleModel.characteristicByKey("UNKNOWN")).isNull();
-  }
-
-  @Test
-  public void characteristic_by_id() {
-    assertThat(sqaleModel.characteristicById(1)).isNotNull();
-    assertThat(sqaleModel.characteristicById(2)).isNotNull();
-    assertThat(sqaleModel.characteristicById(123)).isNull();
-  }
-
-  @Test
-  public void get_requirement_by_rule_key_always_return_null() {
-    assertThat(sqaleModel.requirementsByRule(RuleKey.of("checkstyle", "Regexp"))).isNull();
-  }
-
-  @Test
-  public void get_requirement_by_id_always_return_null() {
-    assertThat(sqaleModel.requirementsById(1)).isNull();
-  }
-
-  @Test
-  public void get_requirements_always_return_empty_list() {
-    assertThat(sqaleModel.requirements()).isEmpty();
-  }
-
-}
diff --git a/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueChangeDaoTest/selectChangelogOfUnresolvedIssuesByComponent.xml b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueChangeDaoTest/selectChangelogOfUnresolvedIssuesByComponent.xml
new file mode 100644 (file)
index 0000000..966f7c3
--- /dev/null
@@ -0,0 +1,144 @@
+<dataset>
+
+  <!-- Unresolved -->
+  <issues
+      id="1"
+      kee="UNRESOLVED_ON_FILE_1"
+      component_uuid="FILE_1"
+      project_uuid="PROJECT_1"
+      resolution="[null]"
+      status="OPEN"
+      rule_id="500"
+      severity="BLOCKER"
+      manual_severity="[false]"
+      message="[null]"
+      line="200"
+      effort_to_fix="[null]"
+      checksum="[null]"
+      reporter="user"
+      assignee="user"
+      author_login="[null]"
+      issue_attributes="[null]"
+      issue_creation_date="1366063200000"
+      issue_update_date="1366063200000"
+      issue_close_date="1366063200000"
+      created_at="1400000000000"
+      updated_at="[null]"
+      />
+
+  <!-- diff -->
+  <issue_changes
+      id="100"
+      kee="100"
+      issue_key="UNRESOLVED_ON_FILE_1"
+      user_login="arthur"
+      change_type="diff"
+      change_data="severity=MAJOR|BLOCKER"
+      created_at="1410213600000"
+      updated_at="1410213600000"
+      issue_change_creation_date="1410213600000"
+      />
+
+    <!-- comment -->
+  <issue_changes
+      id="102"
+      kee="102"
+      issue_key="UNRESOLVED_ON_FILE_1"
+      user_login="arthur"
+      change_type="comment"
+      change_data="recent comment"
+      created_at="1410213600000"
+      updated_at="1410213600000"
+      issue_change_creation_date="[null]"
+      />
+
+  <!-- Resolved: to be ignored -->
+  <issues
+      id="2"
+      kee="RESOLVED_ON_FILE_1"
+      component_uuid="FILE_1"
+      project_uuid="PROJECT_1"
+      resolution="FIXED"
+      status="RESOLVED"
+      rule_id="501"
+      severity="MAJOR"
+      manual_severity="[false]"
+      message="[null]"
+      line="120"
+      effort_to_fix="[null]"
+      checksum="[null]"
+      reporter="[null]"
+      assignee="user"
+      author_login="[null]"
+      issue_attributes="[null]"
+      issue_creation_date="1366063200000"
+      issue_update_date="1366063200000"
+      issue_close_date="1366063200000"
+      created_at="1400000000000"
+      updated_at="[null]"
+      />
+
+  <issue_changes
+      id="103"
+      kee="103"
+      issue_key="RESOLVED_ON_FILE_1"
+      user_login="arthur"
+      change_type="diff"
+      change_data="severity=MAJOR|BLOCKER"
+      created_at="1410213600000"
+      updated_at="1410213600000"
+      issue_change_creation_date="1410213600000"
+      />
+
+  <!-- Unresolved on other file -->
+    <issues
+      id="3"
+      kee="UNRESOLVED_ON_FILE_2"
+      component_uuid="FILE_2"
+      project_uuid="PROJECT_1"
+      resolution="[null]"
+      status="OPEN"
+      rule_id="500"
+      severity="BLOCKER"
+      manual_severity="[false]"
+      message="[null]"
+      line="200"
+      effort_to_fix="[null]"
+      checksum="[null]"
+      reporter="user"
+      assignee="user"
+      author_login="[null]"
+      issue_attributes="[null]"
+      issue_creation_date="1366063200000"
+      issue_update_date="1366063200000"
+      issue_close_date="1366063200000"
+      created_at="1400000000000"
+      updated_at="[null]"
+      />
+
+    <!-- diff -->
+    <issue_changes
+      id="104"
+      kee="104"
+      issue_key="UNRESOLVED_ON_FILE_2"
+      user_login="arthur"
+      change_type="diff"
+      change_data="severity=MAJOR|BLOCKER"
+      created_at="1410213600000"
+      updated_at="1410213600000"
+      issue_change_creation_date="1410213600000"
+      />
+
+    <!-- comment -->
+    <issue_changes
+      id="105"
+      kee="105"
+      issue_key="UNRESOLVED_ON_FILE_2"
+      user_login="arthur"
+      change_type="comment"
+      change_data="recent comment"
+      created_at="1410213600000"
+      updated_at="1410213600000"
+      issue_change_creation_date="[null]"
+      />
+</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueChangeDaoTest/select_issue_changelog_by_module.xml b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueChangeDaoTest/select_issue_changelog_by_module.xml
deleted file mode 100644 (file)
index fd4ee9c..0000000
+++ /dev/null
@@ -1,222 +0,0 @@
-<dataset>
-
-  <projects id="399" uuid="uuid-399" kee="struts" root_id="[null]" project_uuid="[null]" qualifier="TRK" scope="PRJ" />
-  <projects id="400" uuid="uuid-400" kee="struts-core" root_id="399" project_uuid="uuid-399" qualifier="BRC" scope="PRJ" />
-  <projects id="401" uuid="uuid-401" kee="Action.java" root_id="400" project_uuid="uuid-400" qualifier="CLA" scope="PRJ" />
-  <projects id="402" uuid="uuid-402" kee="Filter.java" root_id="400" project_uuid="uuid-400" qualifier="CLA" scope="PRJ" />
-
-  <!-- Open Issue on a file -->
-  <issues
-      id="100"
-      kee="100"
-      component_uuid="uuid-401"
-      project_uuid="uuid-399"
-      rule_id="500"
-      severity="BLOCKER"
-      manual_severity="[false]"
-      message="[null]"
-      line="200"
-      effort_to_fix="[null]"
-      status="OPEN"
-      resolution="[null]"
-      checksum="[null]"
-      reporter="user"
-      assignee="user"
-      author_login="[null]"
-      issue_attributes="[null]"
-      issue_creation_date="1366063200000"
-      issue_update_date="1366063200000"
-      issue_close_date="1366063200000"
-      created_at="1400000000000"
-      updated_at="[null]"
-      />
-
-  <issue_changes
-      id="100"
-      kee="100"
-      issue_key="100"
-      user_login="arthur"
-      change_type="diff"
-      change_data="severity=MAJOR|BLOCKER"
-      created_at="1410213600000"
-      updated_at="1410213600000"
-      issue_change_creation_date="1410213600000"
-      />
-
-  <issue_changes
-      id="1000"
-      kee="1000"
-      issue_key="100"
-      user_login="arthur"
-      change_type="diff"
-      change_data="actionPlan=1.0|1.1"
-      created_at="1410213600000"
-      updated_at="1410213600000"
-      issue_change_creation_date="1410213600000"
-      />
-
-  <issue_changes
-      id="1001"
-      kee="1001"
-      issue_key="100"
-      user_login="arthur"
-      change_type="comment"
-      change_data="recent comment"
-      created_at="1410213600000"
-      updated_at="1410213600000"
-      issue_change_creation_date="[null]"
-      />
-
-  <!-- Open Issue on a file -->
-  <issues
-      id="101"
-      kee="101"
-      component_uuid="uuid-402"
-      project_uuid="uuid-399"
-      rule_id="501"
-      severity="MAJOR"
-      manual_severity="[false]"
-      message="[null]"
-      line="120"
-      effort_to_fix="[null]"
-      status="OPEN"
-      resolution="[null]"
-      checksum="[null]"
-      reporter="[null]"
-      assignee="user"
-      author_login="[null]"
-      issue_attributes="[null]"
-      issue_creation_date="1366063200000"
-      issue_update_date="1366063200000"
-      issue_close_date="1366063200000"
-      created_at="1400000000000"
-      updated_at="[null]"
-      />
-
-  <issue_changes
-      id="101"
-      kee="101"
-      issue_key="101"
-      user_login="arthur"
-      change_type="diff"
-      change_data="severity=MAJOR|BLOCKER"
-      created_at="1410213600000"
-      updated_at="1410213600000"
-      issue_change_creation_date="1410213600000"
-      />
-
-  <!-- Closed Issue on a file -->
-  <issues
-      id="102"
-      kee="102"
-      component_uuid="uuid-402"
-      project_uuid="uuid-399"
-      rule_id="501"
-      severity="MAJOR"
-      manual_severity="[false]"
-      message="[null]"
-      line="120"
-      effort_to_fix="[null]"
-      status="CLOSED"
-      resolution="FIXED"
-      checksum="[null]"
-      reporter="[null]"
-      assignee="user"
-      author_login="[null]"
-      issue_attributes="[null]"
-      issue_creation_date="1366063200000"
-      issue_update_date="1366063200000"
-      issue_close_date="1366063200000"
-      created_at="1400000000000"
-      updated_at="[null]"
-      />
-
-  <issue_changes
-      id="102"
-      kee="102"
-      issue_key="102"
-      user_login="arthur"
-      change_type="diff"
-      change_data="severity=MAJOR|BLOCKER"
-      created_at="1410213600000"
-      updated_at="1410213600000"
-      issue_change_creation_date="1410213600000"
-      />
-
-  <!-- Open Issue on a sub module -->
-  <issues
-      id="103"
-      kee="103"
-      component_uuid="uuid-400"
-      project_uuid="uuid-399"
-      rule_id="501"
-      severity="MAJOR"
-      manual_severity="[false]"
-      message="[null]"
-      line="[null]"
-      effort_to_fix="[null]"
-      status="OPEN"
-      resolution="[null]"
-      checksum="[null]"
-      reporter="[null]"
-      assignee="user"
-      author_login="[null]"
-      issue_attributes="[null]"
-      issue_creation_date="1366063200000"
-      issue_update_date="1366063200000"
-      issue_close_date="1366063200000"
-      created_at="1400000000000"
-      updated_at="[null]"
-      />
-
-  <issue_changes
-      id="103"
-      kee="103"
-      issue_key="103"
-      user_login="arthur"
-      change_type="diff"
-      change_data="severity=MAJOR|BLOCKER"
-      created_at="1410213600000"
-      updated_at="1410213600000"
-      issue_change_creation_date="1410213600000"
-      />
-
-  <!-- Open Issue on a root module -->
-  <issues
-      id="104"
-      kee="104"
-      component_uuid="uuid-399"
-      project_uuid="uuid-399"
-      rule_id="501"
-      severity="MAJOR"
-      manual_severity="[false]"
-      message="[null]"
-      line="[null]"
-      effort_to_fix="[null]"
-      status="OPEN"
-      resolution="[null]"
-      checksum="[null]"
-      reporter="[null]"
-      assignee="user"
-      author_login="[null]"
-      issue_attributes="[null]"
-      issue_creation_date="1366063200000"
-      issue_update_date="1366063200000"
-      issue_close_date="1366063200000"
-      created_at="1400000000000"
-      updated_at="[null]"
-      />
-
-  <issue_changes
-      id="104"
-      kee="104"
-      issue_key="104"
-      user_login="arthur"
-      change_type="diff"
-      change_data="severity=MAJOR|BLOCKER"
-      created_at="1410213600000"
-      updated_at="1410213600000"
-      issue_change_creation_date="1410213600000"
-      />
-
-</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueChangeDaoTest/select_issue_changelog_by_module_are_sorted_by_creation_date.xml b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueChangeDaoTest/select_issue_changelog_by_module_are_sorted_by_creation_date.xml
deleted file mode 100644 (file)
index b019869..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-<dataset>
-
-  <projects id="399" uuid="uuid-399" kee="struts" root_id="[null]" project_uuid="[null]" qualifier="TRK" scope="PRJ" />
-
-  <!-- Open Issue on a root module -->
-  <issues
-      id="104"
-      kee="104"
-      component_uuid="uuid-399"
-      project_uuid="uuid-399"
-      rule_id="501"
-      severity="MAJOR"
-      manual_severity="[false]"
-      message="[null]"
-      line="[null]"
-      effort_to_fix="[null]"
-      status="OPEN"
-      resolution="[null]"
-      checksum="[null]"
-      reporter="[null]"
-      assignee="user"
-      author_login="[null]"
-      issue_attributes="[null]"
-      issue_creation_date="1366063200000"
-      issue_update_date="1366063200000"
-      issue_close_date="1366063200000"
-      created_at="1400000000000"
-      updated_at="[null]"
-      />
-
-  <issue_changes
-      id="1000"
-      kee="1000"
-      issue_key="104"
-      user_login="arthur"
-      change_type="diff"
-      change_data="severity=MAJOR|BLOCKER"
-      created_at="1410386400000"
-      updated_at="1410386400000"
-      issue_change_creation_date="1410386400000"
-      />
-
-  <issue_changes
-      id="1001"
-      kee="1001"
-      issue_key="104"
-      user_login="arthur"
-      change_type="diff"
-      change_data="severity=MAJOR|BLOCKER"
-      created_at="1410213600000"
-      updated_at="1410213600000"
-      issue_change_creation_date="1410213600000"
-      />
-
-  <issue_changes
-      id="1002"
-      kee="1002"
-      issue_key="104"
-      user_login="arthur"
-      change_type="diff"
-      change_data="actionPlan=1.0|1.1"
-      created_at="1410300000000"
-      updated_at="1410300000000"
-      issue_change_creation_date="1410300000000"
-      />
-
-</dataset>
index d0a6cec8a44bfeb45cc3aa3c514310080c6b4c51..0866cb8b203ffa2d79dc2376eccb75f5a6381ab8 100644 (file)
  */
 package org.sonar.api.batch.rule;
 
+import java.util.Collection;
+import javax.annotation.CheckForNull;
 import org.sonar.api.batch.debt.DebtRemediationFunction;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rule.RuleStatus;
 
-import javax.annotation.CheckForNull;
-import java.util.Collection;
-
 /**
  * @since 4.2
  */
@@ -50,14 +49,6 @@ public interface Rule {
 
   RuleStatus status();
 
-  /**
-   * Sub characteristic key.
-   *
-   * @since 4.3
-   */
-  @CheckForNull
-  String debtSubCharacteristic();
-
   /**
    * Remediation function : can by Linear (with a coefficient), Linear with offset (with a coefficient and an offset) or Constant per issue (with an offset)
    *
index 4493449e62f711e20a696b7a5362c095aaea2436..097694e146cf76494cee990c69ef65ff362114a2 100644 (file)
@@ -41,7 +41,6 @@ public class DefaultRule implements Rule {
   private final String severity;
   private final String description;
   private final String internalKey;
-  private final String debtSubCharacteristic;
   private final RuleStatus status;
   private final DebtRemediationFunction debtRemediationFunction;
   private final Map<String, RuleParam> params;
@@ -54,7 +53,6 @@ public class DefaultRule implements Rule {
     this.description = newRule.description;
     this.internalKey = newRule.internalKey;
     this.status = newRule.status;
-    this.debtSubCharacteristic = newRule.debtSubCharacteristic;
     this.debtRemediationFunction = newRule.debtRemediationFunction;
 
     ImmutableMap.Builder<String, RuleParam> builder = ImmutableMap.builder();
@@ -99,11 +97,6 @@ public class DefaultRule implements Rule {
     return status;
   }
 
-  @Override
-  public String debtSubCharacteristic() {
-    return debtSubCharacteristic;
-  }
-
   @Override
   public DebtRemediationFunction debtRemediationFunction() {
     return debtRemediationFunction;
index 3572315f4724e71992801a9b2f413c7b4f509191..2e174b2b2ae1d85eb274d089e72bb0c5fae95e63 100644 (file)
@@ -41,7 +41,6 @@ public class NewRule {
   String description;
   String severity = DEFAULT_SEVERITY;
   String internalKey;
-  String debtSubCharacteristic;
   DebtRemediationFunction debtRemediationFunction;
   RuleStatus status = RuleStatus.defaultStatus();
   Map<String, NewRuleParam> params = new HashMap<>();
@@ -80,11 +79,6 @@ public class NewRule {
     return this;
   }
 
-  public NewRule setDebtSubCharacteristic(@Nullable String c) {
-    this.debtSubCharacteristic = c;
-    return this;
-  }
-
   public NewRule setDebtRemediationFunction(@Nullable DebtRemediationFunction f) {
     this.debtRemediationFunction = f;
     return this;
index b5f423c257e4210fd1ec793a4097abd70c66edde..391cc49eb9965840fdd153f2412cdca3fae1a9d7 100644 (file)
 package org.sonar.api.measures;
 
 import com.google.common.annotations.Beta;
-import org.apache.commons.lang.builder.ReflectionToStringBuilder;
-import org.apache.commons.lang.math.NumberUtils;
-import org.sonar.api.technicaldebt.batch.Characteristic;
-import org.sonar.api.technicaldebt.batch.Requirement;
-
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
 import java.io.Serializable;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.util.Date;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.apache.commons.lang.builder.ReflectionToStringBuilder;
+import org.apache.commons.lang.math.NumberUtils;
+import org.sonar.api.technicaldebt.batch.Characteristic;
+import org.sonar.api.technicaldebt.batch.Requirement;
 
 /**
  * A class to handle measures.
@@ -62,8 +60,6 @@ public class Measure<G extends Serializable> implements Serializable {
   protected Double variation4;
   protected Double variation5;
   protected String url;
-  protected Characteristic characteristic;
-  protected Requirement requirement;
   protected Integer personId;
   protected PersistenceMode persistenceMode = PersistenceMode.FULL;
   private boolean fromCore;
@@ -631,14 +627,13 @@ public class Measure<G extends Serializable> implements Serializable {
    */
   @CheckForNull
   public final Characteristic getCharacteristic() {
-    return characteristic;
+    return null;
   }
 
   /**
    * @since 4.1
    */
   public final Measure<G> setCharacteristic(@Nullable Characteristic characteristic) {
-    this.characteristic = characteristic;
     return this;
   }
 
@@ -649,7 +644,7 @@ public class Measure<G extends Serializable> implements Serializable {
   @Deprecated
   @CheckForNull
   public final Requirement getRequirement() {
-    return requirement;
+    return null;
   }
 
   /**
@@ -658,7 +653,6 @@ public class Measure<G extends Serializable> implements Serializable {
    */
   @Deprecated
   public final Measure<G> setRequirement(@Nullable Requirement requirement) {
-    this.requirement = requirement;
     return this;
   }
 
@@ -737,16 +731,12 @@ public class Measure<G extends Serializable> implements Serializable {
     if (metricKey != null ? !metricKey.equals(measure.metricKey) : (measure.metricKey != null)) {
       return false;
     }
-    if (characteristic != null ? !characteristic.equals(measure.characteristic) : (measure.characteristic != null)) {
-      return false;
-    }
     return !(personId != null ? !personId.equals(measure.personId) : (measure.personId != null));
   }
 
   @Override
   public int hashCode() {
     int result = metricKey != null ? metricKey.hashCode() : 0;
-    result = 31 * result + (characteristic != null ? characteristic.hashCode() : 0);
     result = 31 * result + (personId != null ? personId.hashCode() : 0);
     return result;
   }
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/technicaldebt/batch/TechnicalDebtModel.java b/sonar-plugin-api/src/main/java/org/sonar/api/technicaldebt/batch/TechnicalDebtModel.java
deleted file mode 100644 (file)
index 39f551d..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-package org.sonar.api.technicaldebt.batch;
-
-import org.sonar.api.batch.BatchSide;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
-
-import javax.annotation.CheckForNull;
-
-import java.util.List;
-
-/**
- * @since 4.1
- * @deprecated since 4.3
- */
-@Deprecated
-@BatchSide
-public interface TechnicalDebtModel {
-
-  @CheckForNull
-  Characteristic characteristicById(Integer id);
-
-  @CheckForNull
-  Characteristic characteristicByKey(String key);
-
-  /**
-   * @deprecated since 4.3. Always return null
-   */
-  @CheckForNull
-  @Deprecated
-  Requirement requirementsByRule(RuleKey ruleKey);
-
-  /**
-   * @deprecated since 4.3. Always return null
-   */
-  @CheckForNull
-  @Deprecated
-  Requirement requirementsById(Integer id);
-
-  /**
-   * @deprecated since 4.3. Always return empty list
-   */
-  @Deprecated
-  List<? extends Requirement> requirements();
-
-  /**
-   * @since 4.3
-   */
-  List<DefaultCharacteristic> characteristics();
-
-}
index a64550d7b09721a771e8e7d7acbd9947bb795b8b..3c5270f699630f2f63a9877b95764bb9f296cd81 100644 (file)
@@ -51,7 +51,6 @@ public class RulesBuilderTest {
     newSquid1.setInternalKey("foo=bar");
     newSquid1.setSeverity(Severity.CRITICAL);
     newSquid1.setStatus(RuleStatus.BETA);
-    newSquid1.setDebtSubCharacteristic("COMPILER");
     newSquid1.setDebtRemediationFunction(DebtRemediationFunction.create(DebtRemediationFunction.Type.LINEAR_OFFSET, Duration.create(10), Duration.create(60)));
     newSquid1.addParam("min");
     newSquid1.addParam("max").setDescription("Maximum");
@@ -74,11 +73,9 @@ public class RulesBuilderTest {
     assertThat(squid1.internalKey()).isEqualTo("foo=bar");
     assertThat(squid1.status()).isEqualTo(RuleStatus.BETA);
     assertThat(squid1.severity()).isEqualTo(Severity.CRITICAL);
-    assertThat(squid1.debtSubCharacteristic()).isEqualTo("COMPILER");
     assertThat(squid1.debtRemediationFunction().type()).isEqualTo(DebtRemediationFunction.Type.LINEAR_OFFSET);
     assertThat(squid1.debtRemediationFunction().coefficient()).isEqualTo(Duration.create(10));
     assertThat(squid1.debtRemediationFunction().offset()).isEqualTo(Duration.create(60));
-    assertThat(squid1.debtSubCharacteristic()).isEqualTo("COMPILER");
     assertThat(squid1.params()).hasSize(2);
     assertThat(squid1.param("min").key()).isEqualTo("min");
     assertThat(squid1.param("min").description()).isNull();
@@ -92,7 +89,6 @@ public class RulesBuilderTest {
     assertThat(squid2.internalKey()).isNull();
     assertThat(squid2.status()).isEqualTo(RuleStatus.defaultStatus());
     assertThat(squid2.severity()).isEqualTo(Severity.defaultSeverity());
-    assertThat(squid2.debtSubCharacteristic()).isNull();
     assertThat(squid2.debtRemediationFunction()).isNull();
     assertThat(squid2.params()).isEmpty();
   }