]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6623 extract issue tracking algorithm from batch
authorSimon Brandhof <simon.brandhof@sonarsource.com>
Wed, 3 Jun 2015 08:31:16 +0000 (10:31 +0200)
committerSimon Brandhof <simon.brandhof@sonarsource.com>
Thu, 2 Jul 2015 14:06:08 +0000 (16:06 +0200)
210 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/batch/BatchReportReaderImpl.java
server/sonar-server/src/main/java/org/sonar/server/computation/component/ComponentVisitor.java
server/sonar-server/src/main/java/org/sonar/server/computation/component/ProjectSettingsRepository.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 [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/issue/DebtCalculator.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/issue/DefaultAssignee.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/issue/IntegrateIssuesStep.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueAssigner.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueCache.java
server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueComputation.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueLifecycle.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueListener.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueListeners.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/issue/NewDebtCalculator.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/issue/RuleTagsCopier.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/issue/ScmAccountCache.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/issue/ScmAccountCacheLoader.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/issue/ScmAccountToUser.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/issue/ScmAccountToUserLoader.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/issue/SourceLinesCache.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/issue/TrackerBaseInputFactory.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/issue/TrackerExecution.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/issue/TrackerRawInputFactory.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputationSteps.java
server/sonar-server/src/main/java/org/sonar/server/computation/step/ParseReportStep.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistIssuesStep.java
server/sonar-server/src/main/java/org/sonar/server/computation/step/SendIssueNotificationsStep.java
server/sonar-server/src/main/java/org/sonar/server/issue/AbstractChangeTagsAction.java
server/sonar-server/src/main/java/org/sonar/server/issue/Action.java
server/sonar-server/src/main/java/org/sonar/server/issue/ActionService.java
server/sonar-server/src/main/java/org/sonar/server/issue/AssignAction.java
server/sonar-server/src/main/java/org/sonar/server/issue/CommentAction.java
server/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java
server/sonar-server/src/main/java/org/sonar/server/issue/IssueBulkChangeService.java
server/sonar-server/src/main/java/org/sonar/server/issue/IssueChangelog.java
server/sonar-server/src/main/java/org/sonar/server/issue/IssueChangelogFormatter.java
server/sonar-server/src/main/java/org/sonar/server/issue/IssueChangelogService.java
server/sonar-server/src/main/java/org/sonar/server/issue/IssueCommentService.java
server/sonar-server/src/main/java/org/sonar/server/issue/IssueService.java
server/sonar-server/src/main/java/org/sonar/server/issue/PlanAction.java
server/sonar-server/src/main/java/org/sonar/server/issue/ServerIssueStorage.java
server/sonar-server/src/main/java/org/sonar/server/issue/SetSeverityAction.java
server/sonar-server/src/main/java/org/sonar/server/issue/TransitionAction.java
server/sonar-server/src/main/java/org/sonar/server/issue/actionplan/ActionPlanService.java
server/sonar-server/src/main/java/org/sonar/server/issue/db/IssueDao.java
server/sonar-server/src/main/java/org/sonar/server/issue/notification/IssueChangeNotification.java
server/sonar-server/src/main/java/org/sonar/server/issue/ws/IssueJsonWriter.java
server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java
server/sonar-server/src/main/java/org/sonar/server/issue/ws/ShowAction.java
server/sonar-server/src/main/java/org/sonar/server/source/db/FileSourceDao.java
server/sonar-server/src/test/java/org/sonar/server/computation/batch/BatchReportReaderImplTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/batch/BatchReportReaderRule.java
server/sonar-server/src/test/java/org/sonar/server/computation/issue/IssueComputationTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/issue/ScmAccountCacheLoaderTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/issue/ScmAccountToUserLoaderTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/issue/SourceAuthorsHolderTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/issue/SourceLinesCacheTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/step/ParseReportStepTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistIssuesStepTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/step/SendIssueNotificationsStepTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/ActionServiceTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/AddTagsActionTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/AssignActionTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/CommentActionTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/InternalRubyIssueServiceTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/IssueChangelogFormatterTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/IssueChangelogServiceTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/IssueCommentServiceMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/IssueCommentServiceTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/PlanActionTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/RemoveTagsActionTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/ServerIssueStorageTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/SetSeverityActionTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/TransitionActionTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/actionplan/ActionPlanServiceTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/notification/IssueChangeNotificationTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/notification/NewIssuesNotificationTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/notification/NewIssuesStatisticsTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/ws/IssueActionsWriterTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/ws/ShowActionTest.java
sonar-batch-protocol/src/main/gen-java/org/sonar/batch/protocol/output/BatchReport.java
sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/BatchReportReader.java
sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/BatchReportWriter.java
sonar-batch-protocol/src/main/protobuf/batch_report.proto
sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/BatchReportReaderTest.java
sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/BatchReportWriterTest.java
sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchComponents.java
sonar-batch/src/main/java/org/sonar/batch/debt/DebtDecorator.java
sonar-batch/src/main/java/org/sonar/batch/debt/IssueChangelogDebtCalculator.java
sonar-batch/src/main/java/org/sonar/batch/index/ScanPersister.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/issue/DefaultIssuable.java
sonar-batch/src/main/java/org/sonar/batch/issue/DefaultProjectIssues.java
sonar-batch/src/main/java/org/sonar/batch/issue/IssueCache.java
sonar-batch/src/main/java/org/sonar/batch/issue/IssueFilters.java
sonar-batch/src/main/java/org/sonar/batch/issue/ModuleIssues.java
sonar-batch/src/main/java/org/sonar/batch/issue/tracking/InitialOpenIssuesSensor.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/issue/tracking/InitialOpenIssuesStack.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/issue/tracking/IssueHandlers.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/issue/tracking/IssueTracking.java
sonar-batch/src/main/java/org/sonar/batch/issue/tracking/IssueTrackingDecorator.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/issue/tracking/IssueTrackingResult.java
sonar-batch/src/main/java/org/sonar/batch/issue/tracking/LocalIssueTracking.java
sonar-batch/src/main/java/org/sonar/batch/mediumtest/TaskResult.java
sonar-batch/src/main/java/org/sonar/batch/phases/PersisterExecutionEvent.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/phases/PersistersExecutor.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/phases/PersistersPhaseEvent.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/phases/PhaseExecutor.java
sonar-batch/src/main/java/org/sonar/batch/phases/event/PersisterExecutionHandler.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/phases/event/PersistersPhaseHandler.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/phases/event/package-info.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/postjob/DefaultPostJobContext.java
sonar-batch/src/main/java/org/sonar/batch/profiling/PhasesSumUpTimeProfiler.java
sonar-batch/src/main/java/org/sonar/batch/report/IssuesPublisher.java
sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java
sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
sonar-batch/src/main/java/org/sonar/batch/scan/report/ConsoleReport.java
sonar-batch/src/main/java/org/sonar/batch/scan/report/IssuesReportBuilder.java
sonar-batch/src/main/java/org/sonar/batch/scan/report/JSONReport.java
sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorStorage.java
sonar-batch/src/test/java/org/sonar/batch/debt/DebtDecoratorTest.java
sonar-batch/src/test/java/org/sonar/batch/debt/IssueChangelogDebtCalculatorTest.java
sonar-batch/src/test/java/org/sonar/batch/debt/NewDebtDecoratorTest.java
sonar-batch/src/test/java/org/sonar/batch/issue/DefaultIssuableTest.java
sonar-batch/src/test/java/org/sonar/batch/issue/DefaultProjectIssuesTest.java
sonar-batch/src/test/java/org/sonar/batch/issue/IssueCacheTest.java
sonar-batch/src/test/java/org/sonar/batch/issue/IssueFiltersTest.java
sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java
sonar-batch/src/test/java/org/sonar/batch/issue/tracking/InitialOpenIssuesSensorTest.java [deleted file]
sonar-batch/src/test/java/org/sonar/batch/issue/tracking/InitialOpenIssuesStackTest.java [deleted file]
sonar-batch/src/test/java/org/sonar/batch/issue/tracking/IssueHandlersTest.java [deleted file]
sonar-batch/src/test/java/org/sonar/batch/issue/tracking/IssueTrackingDecoratorTest.java [deleted file]
sonar-batch/src/test/java/org/sonar/batch/issue/tracking/IssueTrackingTest.java
sonar-batch/src/test/java/org/sonar/batch/postjob/DefaultPostJobContextTest.java
sonar-batch/src/test/java/org/sonar/batch/profiling/PhasesSumUpTimeProfilerTest.java
sonar-batch/src/test/java/org/sonar/batch/report/IssuesPublisherTest.java
sonar-batch/src/test/java/org/sonar/batch/scan/report/ConsoleReportTest.java
sonar-batch/src/test/java/org/sonar/batch/scan/report/JSONReportTest.java
sonar-batch/src/test/java/org/sonar/batch/sensor/DefaultSensorStorageTest.java
sonar-core/src/main/java/org/sonar/core/issue/DefaultIssue.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/issue/DefaultIssueBuilder.java
sonar-core/src/main/java/org/sonar/core/issue/DefaultIssueComment.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/issue/FieldDiffs.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/issue/IssueChangeContext.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/issue/IssueUpdater.java
sonar-core/src/main/java/org/sonar/core/issue/db/IssueChangeDao.java
sonar-core/src/main/java/org/sonar/core/issue/db/IssueChangeDto.java
sonar-core/src/main/java/org/sonar/core/issue/db/IssueDao.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/db/IssueStorage.java
sonar-core/src/main/java/org/sonar/core/issue/db/UpdateConflictResolver.java
sonar-core/src/main/java/org/sonar/core/issue/tracking/BlockHashSequence.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/issue/tracking/BlockRecognizer.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/issue/tracking/Input.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/issue/tracking/LazyInput.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/issue/tracking/LineHashSequence.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/issue/tracking/Trackable.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/issue/tracking/Tracker.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/issue/tracking/Tracking.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/issue/tracking/package-info.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/issue/workflow/FunctionExecutor.java
sonar-core/src/main/java/org/sonar/core/issue/workflow/IsBeingClosed.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/issue/workflow/IsEndOfLife.java [deleted file]
sonar-core/src/main/java/org/sonar/core/issue/workflow/IsManual.java
sonar-core/src/main/java/org/sonar/core/issue/workflow/IssueWorkflow.java
sonar-core/src/main/java/org/sonar/core/issue/workflow/SetAssignee.java [deleted file]
sonar-core/src/main/java/org/sonar/core/issue/workflow/SetCloseDate.java
sonar-core/src/main/java/org/sonar/core/issue/workflow/SetClosed.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/issue/workflow/SetEndOfLife.java [deleted file]
sonar-core/src/main/java/org/sonar/core/issue/workflow/UnsetAssignee.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/issue/workflow/UnsetLine.java [new file with mode: 0644]
sonar-core/src/main/resources/org/sonar/core/issue/db/IssueMapper.xml
sonar-core/src/test/java/org/sonar/core/issue/DefaultIssueBuilderTest.java
sonar-core/src/test/java/org/sonar/core/issue/IssueChangeContextTest.java
sonar-core/src/test/java/org/sonar/core/issue/IssueUpdaterTest.java
sonar-core/src/test/java/org/sonar/core/issue/db/IssueChangeDaoTest.java
sonar-core/src/test/java/org/sonar/core/issue/db/IssueChangeDtoTest.java
sonar-core/src/test/java/org/sonar/core/issue/db/IssueDaoTest.java
sonar-core/src/test/java/org/sonar/core/issue/db/IssueDtoTest.java
sonar-core/src/test/java/org/sonar/core/issue/db/IssueStorageTest.java
sonar-core/src/test/java/org/sonar/core/issue/db/UpdateConflictResolverTest.java
sonar-core/src/test/java/org/sonar/core/issue/tracking/BlockHashSequenceTest.java [new file with mode: 0644]
sonar-core/src/test/java/org/sonar/core/issue/tracking/BlockRecognizerTest.java [new file with mode: 0644]
sonar-core/src/test/java/org/sonar/core/issue/tracking/TrackerTest.java [new file with mode: 0644]
sonar-core/src/test/java/org/sonar/core/issue/workflow/IsBeingClosedTest.java [new file with mode: 0644]
sonar-core/src/test/java/org/sonar/core/issue/workflow/IsEndOfLifeTest.java [deleted file]
sonar-core/src/test/java/org/sonar/core/issue/workflow/IsManualTest.java
sonar-core/src/test/java/org/sonar/core/issue/workflow/IssueWorkflowTest.java
sonar-core/src/test/java/org/sonar/core/issue/workflow/SetAssigneeTest.java [deleted file]
sonar-core/src/test/java/org/sonar/core/issue/workflow/SetClosedTest.java [new file with mode: 0644]
sonar-core/src/test/java/org/sonar/core/issue/workflow/SetEndOfLifeTest.java [deleted file]
sonar-core/src/test/java/org/sonar/core/issue/workflow/TransitionTest.java
sonar-core/src/test/java/org/sonar/core/issue/workflow/UnsetAssigneeTest.java [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_by_key.xml [deleted file]
sonar-plugin-api/src/main/java/org/sonar/api/issue/Issue.java
sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/DefaultIssue.java [deleted file]
sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/DefaultIssueComment.java [deleted file]
sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/FieldDiffs.java [deleted file]
sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/IssueChangeContext.java [deleted file]
sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/package-info.java [deleted file]
sonar-plugin-api/src/test/java/org/sonar/api/issue/action/ActionTest.java
sonar-plugin-api/src/test/java/org/sonar/api/issue/condition/HasIssuePropertyConditionTest.java
sonar-plugin-api/src/test/java/org/sonar/api/issue/condition/HasResolutionTest.java
sonar-plugin-api/src/test/java/org/sonar/api/issue/condition/HasStatusTest.java
sonar-plugin-api/src/test/java/org/sonar/api/issue/condition/IsUnResolvedTest.java
sonar-plugin-api/src/test/java/org/sonar/api/issue/condition/NotConditionTest.java
sonar-plugin-api/src/test/java/org/sonar/api/issue/internal/DefaultIssueTest.java
sonar-plugin-api/src/test/java/org/sonar/api/issue/internal/FieldDiffsTest.java

index dc57d0aa6ae5e53f629f7c6ef140fcdd2b64b4bd..fbed4ffb945a2b2774b5112e182fc5c16292aca6 100644 (file)
@@ -36,8 +36,6 @@ public interface BatchReportReader {
 
   List<BatchReport.Issue> readComponentIssues(int componentRef);
 
-  BatchReport.Issues readDeletedComponentIssues(int deletedComponentRef);
-
   List<BatchReport.Duplication> readComponentDuplications(int componentRef);
 
   List<BatchReport.Symbols.Symbol> readComponentSymbols(int componentRef);
index c48e0289b1ab81b09d129399fbd36d78d05dd32f..8f1f476e2ec0ed4deddba047890175aa585b3390 100644 (file)
@@ -73,11 +73,6 @@ public class BatchReportReaderImpl implements BatchReportReader {
     return delegate.readComponentIssues(componentRef);
   }
 
-  @Override
-  public BatchReport.Issues readDeletedComponentIssues(int deletedComponentRef) {
-    return delegate.readDeletedComponentIssues(deletedComponentRef);
-  }
-
   @Override
   public List<BatchReport.Duplication> readComponentDuplications(int componentRef) {
     return delegate.readComponentDuplications(componentRef);
index 5804e0b2b553b562c02ac90a7e0ae46c5d0f24ec..4039933865c92af676e1addcbfc3930fd717550f 100644 (file)
@@ -23,6 +23,16 @@ public interface ComponentVisitor {
   void visit(Component tree);
 
   enum Order {
-    PRE_ORDER, POST_ORDER
+    /**
+     * Each component is visited BEFORE its children. Top-down traversal of
+     * tree of components.
+     */
+    PRE_ORDER,
+
+    /**
+     * Each component is visited AFTER its children. Bottom-up traversal of
+     * tree of components.
+     */
+    POST_ORDER
   }
 }
index 467049c0e00e4ebf659094979ec9cd85f7b329e3..2a12477b8de8b237204444908a0cf7aaeae93f84 100644 (file)
@@ -26,7 +26,7 @@ import org.sonar.server.properties.ProjectSettingsFactory;
 /**
  * Lazy loading of project settings.
  *
- * Should be refactored to be able to load settings from any components.
+ * TODO Should be refactored to be able to load settings from any components.
  */
 public class ProjectSettingsRepository {
 
index b22ec16e2ffb1df7c092fd680ab1a846dc9a777f..f4c31846f1f3fee169a702fdb652fbffc4f7399b 100644 (file)
@@ -31,6 +31,7 @@ import org.sonar.api.utils.log.Loggers;
 import org.sonar.api.utils.log.Profiler;
 import org.sonar.core.component.Module;
 import org.sonar.core.issue.db.UpdateConflictResolver;
+import org.sonar.core.issue.tracking.Tracker;
 import org.sonar.core.platform.ComponentContainer;
 import org.sonar.server.computation.ComputationService;
 import org.sonar.server.computation.ReportQueue;
@@ -43,13 +44,21 @@ import org.sonar.server.computation.component.TreeRootHolderImpl;
 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.DebtCalculator;
+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.IssueComputation;
+import org.sonar.server.computation.issue.IssueLifecycle;
+import org.sonar.server.computation.issue.IssueListeners;
 import org.sonar.server.computation.issue.RuleCache;
 import org.sonar.server.computation.issue.RuleCacheLoader;
-import org.sonar.server.computation.issue.ScmAccountCache;
-import org.sonar.server.computation.issue.ScmAccountCacheLoader;
-import org.sonar.server.computation.issue.SourceLinesCache;
+import org.sonar.server.computation.issue.RuleTagsCopier;
+import org.sonar.server.computation.issue.ScmAccountToUser;
+import org.sonar.server.computation.issue.ScmAccountToUserLoader;
+import org.sonar.server.computation.issue.TrackerBaseInputFactory;
+import org.sonar.server.computation.issue.TrackerExecution;
+import org.sonar.server.computation.issue.TrackerRawInputFactory;
 import org.sonar.server.computation.language.LanguageRepositoryImpl;
 import org.sonar.server.computation.measure.MeasureRepositoryImpl;
 import org.sonar.server.computation.measure.newcoverage.NewCoverageMetricKeysModule;
@@ -156,14 +165,23 @@ public class ComputeEngineContainerImpl extends ComponentContainer implements Co
       NewCoverageMetricKeysModule.class,
 
       // issues
-      ScmAccountCacheLoader.class,
-      ScmAccountCache.class,
-      SourceLinesCache.class,
-      IssueComputation.class,
+      ScmAccountToUserLoader.class,
+      ScmAccountToUser.class,
+      IssueAssigner.class,
+      RuleTagsCopier.class,
       RuleCache.class,
       RuleCacheLoader.class,
       IssueCache.class,
+      DefaultAssignee.class,
+      DebtCalculator.class,
+      IssueListeners.class,
+      IssueLifecycle.class,
       UpdateConflictResolver.class,
+      TrackerBaseInputFactory.class,
+      TrackerRawInputFactory.class,
+      Tracker.class,
+      TrackerExecution.class,
+      BaseIssuesLoader.class,
 
       // views
       ViewIndex.class,
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/BaseIssuesLoader.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/BaseIssuesLoader.java
new file mode 100644 (file)
index 0000000..904ac1f
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * 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.ImmutableMap;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.ibatis.session.ResultContext;
+import org.apache.ibatis.session.ResultHandler;
+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.server.computation.component.TreeRootHolder;
+import org.sonar.server.db.DbClient;
+
+/**
+ * Loads all the project open issues from database, including manual issues.
+ */
+public class BaseIssuesLoader {
+
+  private final TreeRootHolder treeRootHolder;
+  private final DbClient dbClient;
+  private final RuleCache ruleCache;
+
+  public BaseIssuesLoader(TreeRootHolder treeRootHolder, DbClient dbClient, RuleCache ruleCache) {
+    this.treeRootHolder = treeRootHolder;
+    this.dbClient = dbClient;
+    this.ruleCache = ruleCache;
+  }
+
+  public List<DefaultIssue> loadForComponentUuid(String componentUuid) {
+    DbSession session = dbClient.openSession(false);
+    final List<DefaultIssue> result = new ArrayList<>();
+    try {
+      Map<String, String> params = ImmutableMap.of("componentUuid", componentUuid);
+      session.select(IssueMapper.class.getName() + ".selectOpenByComponentUuid", params, new ResultHandler() {
+        @Override
+        public void handleResult(ResultContext resultContext) {
+          DefaultIssue issue = ((IssueDto) resultContext.getResultObject()).toDefaultIssue();
+          issue.setOnDisabledRule(ruleCache.getNullable(issue.ruleKey()) == null);
+          result.add(issue);
+        }
+      });
+      return result;
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  /**
+   * Uuids of all the components that have open issues on this project.
+   */
+  public Set<String> loadComponentUuids() {
+    DbSession session = dbClient.openSession(false);
+    try {
+      return dbClient.issueDao().selectComponentUuidsOfOpenIssuesForProjectUuid(session, treeRootHolder.getRoot().getUuid());
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+}
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
new file mode 100644 (file)
index 0000000..8dbd6aa
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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.server.computation.component.Component;
+
+public class DebtCalculator extends IssueListener {
+
+  @Override
+  public void beforeIssue(Component component, DefaultIssue issue) {
+    if (issue.resolution() == null) {
+      // TODO
+    }
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/DefaultAssignee.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/DefaultAssignee.java
new file mode 100644 (file)
index 0000000..466575e
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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.Strings;
+import javax.annotation.CheckForNull;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.server.computation.component.ProjectSettingsRepository;
+import org.sonar.server.computation.component.TreeRootHolder;
+import org.sonar.server.user.index.UserDoc;
+import org.sonar.server.user.index.UserIndex;
+
+/**
+ * The user who is optionally declared as being the assignee
+ * of all the issues which SCM author is not associated with any SonarQube user.
+ */
+public class DefaultAssignee {
+
+  private static final Logger LOG = Loggers.get(DefaultAssignee.class);
+
+  private final TreeRootHolder treeRootHolder;
+  private final UserIndex userIndex;
+  private final ProjectSettingsRepository settings;
+
+  private boolean loaded = false;
+  private String login = null;
+
+  public DefaultAssignee(TreeRootHolder treeRootHolder, UserIndex userIndex, ProjectSettingsRepository settings) {
+    this.treeRootHolder = treeRootHolder;
+    this.userIndex = userIndex;
+    this.settings = settings;
+  }
+
+  @CheckForNull
+  public String getLogin() {
+    if (!loaded) {
+      String configuredLogin = settings.getProjectSettings(treeRootHolder.getRoot().getKey()).getString(CoreProperties.DEFAULT_ISSUE_ASSIGNEE);
+      if (!Strings.isNullOrEmpty(configuredLogin) && isValidLogin(configuredLogin)) {
+        this.login = configuredLogin;
+      }
+      loaded = true;
+    }
+    return login;
+  }
+
+  private boolean isValidLogin(String s) {
+    UserDoc user = userIndex.getNullableByLogin(s);
+    if (user == null) {
+      LOG.info("the {} property was set with an unknown login: {}", CoreProperties.DEFAULT_ISSUE_ASSIGNEE, s);
+      return false;
+    }
+    return true;
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IntegrateIssuesStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IntegrateIssuesStep.java
new file mode 100644 (file)
index 0000000..da507bb
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * 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.Sets;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+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.component.DepthTraversalTypeAwareVisitor;
+import org.sonar.server.computation.component.TreeRootHolder;
+import org.sonar.server.computation.step.ComputationStep;
+import org.sonar.server.util.cache.DiskCache;
+
+import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.POST_ORDER;
+
+public class IntegrateIssuesStep implements ComputationStep {
+
+  private final TreeRootHolder treeRootHolder;
+  private final TrackerExecution tracker;
+  private final IssueCache issueCache;
+  private final BaseIssuesLoader baseIssuesLoader;
+  private final IssueLifecycle issueLifecycle;
+  private final IssueListeners issueListeners;
+
+  public IntegrateIssuesStep(TreeRootHolder treeRootHolder, TrackerExecution tracker, IssueCache issueCache,
+    BaseIssuesLoader baseIssuesLoader, IssueLifecycle issueLifecycle,
+    IssueListeners issueListeners) {
+    this.treeRootHolder = treeRootHolder;
+    this.tracker = tracker;
+    this.issueCache = issueCache;
+    this.baseIssuesLoader = baseIssuesLoader;
+    this.issueLifecycle = issueLifecycle;
+    this.issueListeners = issueListeners;
+  }
+
+  @Override
+  public void execute() {
+    // all the components that had issues before this analysis
+    final Set<String> unprocessedComponentUuids = Sets.newHashSet(baseIssuesLoader.loadComponentUuids());
+
+    new DepthTraversalTypeAwareVisitor(Component.Type.FILE, POST_ORDER) {
+      @Override
+      public void visitAny(Component component) {
+        processIssues(component);
+        unprocessedComponentUuids.remove(component.getUuid());
+      }
+    }.visit(treeRootHolder.getRoot());
+
+    closeIssuesForDeletedComponentUuids(unprocessedComponentUuids);
+  }
+
+  private void processIssues(Component component) {
+    Tracking<DefaultIssue, DefaultIssue> tracking = tracker.track(component);
+    DiskCache<DefaultIssue>.DiskAppender cacheAppender = issueCache.newAppender();
+    try {
+      issueListeners.beforeComponent(component, tracking);
+      fillNewOpenIssues(component, tracking, cacheAppender);
+      fillExistingOpenIssues(component, tracking, cacheAppender);
+      closeUnmatchedBaseIssues(component, tracking, cacheAppender);
+      issueListeners.afterComponent(component);
+    } finally {
+      cacheAppender.close();
+    }
+  }
+
+  private void fillNewOpenIssues(Component component, Tracking<DefaultIssue, DefaultIssue> tracking, DiskCache<DefaultIssue>.DiskAppender cacheAppender) {
+    Set<DefaultIssue> issues = tracking.getUnmatchedRaws();
+    for (DefaultIssue issue : issues) {
+      issueLifecycle.initNewOpenIssue(issue);
+      issueListeners.beforeIssue(component, issue);
+      process(component, issue, cacheAppender);
+    }
+  }
+
+  private void fillExistingOpenIssues(Component component, Tracking<DefaultIssue, DefaultIssue> tracking, DiskCache<DefaultIssue>.DiskAppender cacheAppender) {
+    for (Map.Entry<DefaultIssue, DefaultIssue> entry : tracking.getMatchedRaws().entrySet()) {
+      DefaultIssue raw = entry.getKey();
+      DefaultIssue base = entry.getValue();
+      issueListeners.beforeIssue(component, raw);
+      issueLifecycle.mergeExistingOpenIssue(raw, base);
+      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.beforeIssue(component, manualIssue);
+      process(component, manualIssue, cacheAppender);
+    }
+  }
+
+  private void closeUnmatchedBaseIssues(Component component, Tracking<DefaultIssue, DefaultIssue> tracking, DiskCache<DefaultIssue>.DiskAppender cacheAppender) {
+    for (DefaultIssue issue : tracking.getUnmatchedBases()) {
+      // TODO should replace flag "beingClosed" by express call to transition "automaticClose"
+      issue.setBeingClosed(true);
+      // TODO manual issues -> was updater.setResolution(newIssue, Issue.RESOLUTION_REMOVED, changeContext);. Is it a problem ?
+      process(component, issue, cacheAppender);
+    }
+  }
+
+  private void process(Component component, DefaultIssue issue, DiskCache<DefaultIssue>.DiskAppender cacheAppender) {
+    issueLifecycle.doAutomaticTransition(issue);
+    issueListeners.onIssue(component, issue);
+    cacheAppender.append(issue);
+  }
+
+  private void closeIssuesForDeletedComponentUuids(Set<String> deletedComponentUuids) {
+    DiskCache<DefaultIssue>.DiskAppender cacheAppender = issueCache.newAppender();
+    try {
+      for (String deletedComponentUuid : deletedComponentUuids) {
+        List<DefaultIssue> issues = baseIssuesLoader.loadForComponentUuid(deletedComponentUuid);
+        for (DefaultIssue issue : issues) {
+          issue.setBeingClosed(true);
+          issueLifecycle.doAutomaticTransition(issue);
+          // TODO execute listeners ? Component is currently missing.
+          cacheAppender.append(issue);
+        }
+      }
+    } finally {
+      cacheAppender.close();
+    }
+  }
+
+  @Override
+  public String getDescription() {
+    return "Integrate issues";
+  }
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueAssigner.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueAssigner.java
new file mode 100644 (file)
index 0000000..7d3087f
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * 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 java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.batch.protocol.output.BatchReport;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.tracking.Tracking;
+import org.sonar.server.computation.batch.BatchReportReader;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.source.index.SourceLineDoc;
+import org.sonar.server.source.index.SourceLineIndex;
+
+/**
+ * Detect the SCM author and SQ assignee.
+ * <p/>
+ * It relies on:
+ * <ul>
+ *   <li>the SCM information sent in the report for modified files</li>
+ *   <li>the Elasticsearch index of source lines for non-modified files</li>
+ * </ul>
+ */
+public class IssueAssigner extends IssueListener {
+
+  private final SourceLineIndex sourceLineIndex;
+  private final BatchReportReader reportReader;
+  private final DefaultAssignee defaultAssigne;
+  private final ScmAccountToUser scmAccountToUser;
+
+  private long lastCommitDate = 0L;
+  private String lastCommitAuthor = null;
+  private BatchReport.Changesets scmChangesets = null;
+
+  public IssueAssigner(SourceLineIndex sourceLineIndex, BatchReportReader reportReader,
+    ScmAccountToUser scmAccountToUser, DefaultAssignee defaultAssigne) {
+    this.sourceLineIndex = sourceLineIndex;
+    this.reportReader = reportReader;
+    this.scmAccountToUser = scmAccountToUser;
+    this.defaultAssigne = defaultAssigne;
+  }
+
+  @Override
+  public void beforeComponent(Component component, Tracking tracking) {
+    // optimization - do not load data if there are no new issues
+    if (!tracking.getUnmatchedRaws().isEmpty()) {
+      scmChangesets = loadScmChangesetsFromReport(component);
+      if (scmChangesets == null) {
+        scmChangesets = loadScmChangesetsFromIndex(component);
+      }
+      computeLastCommitDateAndAuthor();
+    }
+  }
+
+  @Override
+  public void onIssue(Component component, DefaultIssue issue) {
+    if (issue.isNew()) {
+      String scmAuthor = guessScmAuthor(issue.line());
+      issue.setAuthorLogin(scmAuthor);
+      if (scmAuthor != null) {
+        String assigneeLogin = scmAccountToUser.getNullable(scmAuthor);
+        if (assigneeLogin == null) {
+          issue.setAssignee(defaultAssigne.getLogin());
+        } else {
+          issue.setAssignee(assigneeLogin);
+        }
+      }
+    }
+  }
+
+  @Override
+  public void afterComponent(Component component) {
+    lastCommitDate = 0L;
+    lastCommitAuthor = null;
+    scmChangesets = null;
+  }
+
+  /**
+   * Get the SCM login of the last committer on the line. When line is zero,
+   * then get the last committer on the file.
+   */
+  @CheckForNull
+  private String guessScmAuthor(@Nullable Integer line) {
+    String author = null;
+    if (line != null && line <= scmChangesets.getChangesetIndexByLineCount()) {
+      BatchReport.Changesets.Changeset changeset = scmChangesets.getChangeset(scmChangesets.getChangesetIndexByLine(line - 1));
+      author = changeset.hasAuthor() ? changeset.getAuthor() : null;
+    }
+    return StringUtils.defaultIfEmpty(author, lastCommitAuthor);
+  }
+
+  private BatchReport.Changesets loadScmChangesetsFromReport(Component component) {
+    return reportReader.readChangesets(component.getRef());
+  }
+
+  private BatchReport.Changesets loadScmChangesetsFromIndex(Component component) {
+    List<SourceLineDoc> lines = sourceLineIndex.getLines(component.getUuid());
+    Map<String, BatchReport.Changesets.Changeset> changesetByRevision = new HashMap<>();
+    BatchReport.Changesets.Builder scmBuilder = BatchReport.Changesets.newBuilder()
+      .setComponentRef(component.getRef());
+    for (SourceLineDoc sourceLine : lines) {
+      String scmRevision = sourceLine.scmRevision();
+      if (scmRevision == null || changesetByRevision.get(scmRevision) == null) {
+        BatchReport.Changesets.Changeset.Builder changeSetBuilder = BatchReport.Changesets.Changeset.newBuilder();
+        String scmAuthor = sourceLine.scmAuthor();
+        if (scmAuthor != null) {
+          changeSetBuilder.setAuthor(scmAuthor);
+        }
+        Date scmDate = sourceLine.scmDate();
+        if (scmDate != null) {
+          changeSetBuilder.setDate(scmDate.getTime());
+        }
+        if (scmRevision != null) {
+          changeSetBuilder.setRevision(scmRevision);
+        }
+
+        BatchReport.Changesets.Changeset changeset = changeSetBuilder.build();
+        scmBuilder.addChangeset(changeset);
+        scmBuilder.addChangesetIndexByLine(scmBuilder.getChangesetCount() - 1);
+        if (scmRevision != null) {
+          changesetByRevision.put(scmRevision, changeset);
+        }
+      } else {
+        scmBuilder.addChangesetIndexByLine(scmBuilder.getChangesetList().indexOf(changesetByRevision.get(scmRevision)));
+      }
+    }
+    return scmBuilder.build();
+  }
+
+  private void computeLastCommitDateAndAuthor() {
+    for (BatchReport.Changesets.Changeset changeset : scmChangesets.getChangesetList()) {
+      if (changeset.hasAuthor() && changeset.hasDate() && changeset.getDate() > lastCommitDate) {
+        lastCommitDate = changeset.getDate();
+        lastCommitAuthor = changeset.getAuthor();
+      }
+    }
+  }
+}
index 50fab5b12b344ec9d032086c7b37b4007f43e4b2..af1dc395b594468d6aeb01f9a5e96dee98ee20d0 100644 (file)
  */
 package org.sonar.server.computation.issue;
 
-import org.sonar.api.issue.internal.DefaultIssue;
+import java.io.File;
+import java.io.IOException;
 import org.sonar.api.utils.System2;
 import org.sonar.api.utils.TempFolder;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.server.util.cache.DiskCache;
 
-import java.io.File;
-import java.io.IOException;
-
 /**
  * Cache of all the issues involved in the analysis. Their state is as it will be
  * persisted in database (after issue tracking, auto-assignment, ...)
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueComputation.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueComputation.java
deleted file mode 100644 (file)
index 76079a6..0000000
+++ /dev/null
@@ -1,166 +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.base.Strings;
-import com.google.common.collect.Sets;
-import java.util.Date;
-import javax.annotation.Nullable;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.FieldDiffs;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.utils.Duration;
-import org.sonar.api.utils.KeyValueFormat;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.batch.protocol.output.BatchReport;
-import org.sonar.core.rule.RuleDto;
-import org.sonar.server.computation.batch.BatchReportReader;
-import org.sonar.server.computation.component.ProjectSettingsRepository;
-import org.sonar.server.user.index.UserDoc;
-import org.sonar.server.user.index.UserIndex;
-import org.sonar.server.util.cache.DiskCache;
-
-public class IssueComputation {
-
-  private static final Logger LOG = Loggers.get(IssueComputation.class);
-
-  private final RuleCache ruleCache;
-  private final ScmAccountCache scmAccountCache;
-  private final SourceLinesCache linesCache;
-  private final DiskCache<DefaultIssue>.DiskAppender diskIssuesAppender;
-  private final UserIndex userIndex;
-  private final ProjectSettingsRepository projectSettingsRepository;
-  private final BatchReportReader reportReader;
-  private boolean hasAssigneeBeenComputed = false;
-  private String defaultAssignee = null;
-
-  public IssueComputation(RuleCache ruleCache, SourceLinesCache linesCache, ScmAccountCache scmAccountCache,
-    IssueCache issueCache, UserIndex userIndex, ProjectSettingsRepository projectSettingsRepository, BatchReportReader reportReader) {
-    this.ruleCache = ruleCache;
-    this.linesCache = linesCache;
-    this.scmAccountCache = scmAccountCache;
-    this.userIndex = userIndex;
-    this.reportReader = reportReader;
-    this.projectSettingsRepository = projectSettingsRepository;
-    this.diskIssuesAppender = issueCache.newAppender();
-  }
-
-  public void processComponentIssues(Iterable<BatchReport.Issue> issues, String componentUuid, @Nullable Integer componentReportRef,
-    String projectKey, String projectUuid) {
-    linesCache.init(componentUuid, componentReportRef, reportReader);
-    computeDefaultAssignee(projectSettingsRepository.getProjectSettings(projectKey).getString(CoreProperties.DEFAULT_ISSUE_ASSIGNEE));
-    for (BatchReport.Issue reportIssue : issues) {
-      DefaultIssue issue = toDefaultIssue(componentUuid, reportIssue, projectKey, projectUuid);
-      if (issue.isNew()) {
-        guessAuthor(issue);
-        autoAssign(issue, defaultAssignee);
-        copyRuleTags(issue);
-      }
-      diskIssuesAppender.append(issue);
-    }
-    linesCache.clear();
-  }
-
-  private DefaultIssue toDefaultIssue(String componentUuid, BatchReport.Issue issue, String projectKey, String projectUuid) {
-    DefaultIssue target = new DefaultIssue();
-    target.setKey(issue.getUuid());
-    target.setComponentUuid(componentUuid);
-    target.setRuleKey(RuleKey.of(issue.getRuleRepository(), issue.getRuleKey()));
-    target.setSeverity(issue.getSeverity().name());
-    target.setManualSeverity(issue.getManualSeverity());
-    target.setMessage(issue.hasMsg() ? issue.getMsg() : null);
-    target.setLine(issue.hasLine() ? issue.getLine() : null);
-    target.setProjectUuid(projectUuid);
-    target.setProjectKey(projectKey);
-    target.setEffortToFix(issue.hasEffortToFix() ? issue.getEffortToFix() : null);
-    target.setDebt(issue.hasDebtInMinutes() ? Duration.create(issue.getDebtInMinutes()) : null);
-    if (issue.hasDiffFields()) {
-      FieldDiffs fieldDiffs = FieldDiffs.parse(issue.getDiffFields());
-      fieldDiffs.setCreationDate(new Date(reportReader.readMetadata().getAnalysisDate()));
-      target.setCurrentChange(fieldDiffs);
-    }
-    target.setStatus(issue.getStatus());
-    target.setTags(issue.getTagList());
-    target.setResolution(issue.hasResolution() ? issue.getResolution() : null);
-    target.setReporter(issue.hasReporter() ? issue.getReporter() : null);
-    target.setAssignee(issue.hasAssignee() ? issue.getAssignee() : null);
-    target.setChecksum(issue.hasChecksum() ? issue.getChecksum() : null);
-    target.setAttributes(issue.hasAttributes() ? KeyValueFormat.parse(issue.getAttributes()) : null);
-    target.setAuthorLogin(issue.hasAuthorLogin() ? issue.getAuthorLogin() : null);
-    target.setActionPlanKey(issue.hasActionPlanKey() ? issue.getActionPlanKey() : null);
-    target.setCreationDate(issue.hasCreationDate() ? new Date(issue.getCreationDate()) : null);
-    target.setUpdateDate(issue.hasUpdateDate() ? new Date(issue.getUpdateDate()) : null);
-    target.setCloseDate(issue.hasCloseDate() ? new Date(issue.getCloseDate()) : null);
-    target.setChanged(issue.getIsChanged());
-    target.setNew(issue.getIsNew());
-    target.setSelectedAt(issue.hasSelectedAt() ? issue.getSelectedAt() : null);
-    target.setSendNotifications(issue.getMustSendNotification());
-    return target;
-  }
-
-  public void afterReportProcessing() {
-    diskIssuesAppender.close();
-  }
-
-  private void guessAuthor(DefaultIssue issue) {
-    // issue.authorLogin() can be not-null when old developer cockpit plugin (or other plugin)
-    // is still installed and executed during analysis
-    if (issue.authorLogin() == null) {
-      issue.setAuthorLogin(linesCache.lineAuthor(issue.line()));
-    }
-  }
-
-  private void autoAssign(DefaultIssue issue, @Nullable String defaultAssignee) {
-    // issue.assignee() can be not-null if the issue-assign-plugin is
-    // still installed and executed during analysis
-    if (issue.assignee() == null) {
-      String scmAccount = issue.authorLogin();
-      if (scmAccount != null) {
-        issue.setAssignee(scmAccountCache.getNullable(scmAccount));
-      }
-      if (issue.assignee() == null && defaultAssignee != null) {
-        issue.setAssignee(defaultAssignee);
-      }
-    }
-  }
-
-  private void copyRuleTags(DefaultIssue issue) {
-    RuleDto rule = ruleCache.get(issue.ruleKey());
-    issue.setTags(Sets.union(rule.getTags(), rule.getSystemTags()));
-  }
-
-  private void computeDefaultAssignee(@Nullable String login) {
-    if (hasAssigneeBeenComputed) {
-      return;
-    }
-
-    hasAssigneeBeenComputed = true;
-    if (!Strings.isNullOrEmpty(login)) {
-      UserDoc user = userIndex.getNullableByLogin(login);
-      if (user == null) {
-        LOG.info("the {} property was set with an unknown login: {}", CoreProperties.DEFAULT_ISSUE_ASSIGNEE, login);
-      } else {
-        defaultAssignee = login;
-      }
-    }
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueLifecycle.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueLifecycle.java
new file mode 100644 (file)
index 0000000..713e653
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * 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.sonar.api.issue.Issue;
+import org.sonar.api.utils.internal.Uuids;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.IssueChangeContext;
+import org.sonar.core.issue.IssueUpdater;
+import org.sonar.core.issue.workflow.IssueWorkflow;
+import org.sonar.server.computation.batch.BatchReportReader;
+
+public class IssueLifecycle {
+
+  private final IssueWorkflow workflow;
+  private final IssueChangeContext changeContext;
+  private final IssueUpdater updater;
+
+  public IssueLifecycle(BatchReportReader reportReader, IssueWorkflow workflow, IssueUpdater updater) {
+    this.workflow = workflow;
+    this.updater = updater;
+    this.changeContext = IssueChangeContext.createScan(new Date(reportReader.readMetadata().getAnalysisDate()));
+  }
+
+  public void initNewOpenIssue(DefaultIssue issue) {
+    issue.setKey(Uuids.create());
+    issue.setCreationDate(changeContext.date());
+    issue.setUpdateDate(changeContext.date());
+    issue.setStatus(Issue.STATUS_OPEN);
+  }
+
+  public void mergeExistingOpenIssue(DefaultIssue raw, DefaultIssue base) {
+    raw.setNew(false);
+    raw.setKey(base.key());
+    raw.setCreationDate(base.creationDate());
+    raw.setUpdateDate(base.updateDate());
+    raw.setCloseDate(base.closeDate());
+    raw.setActionPlanKey(base.actionPlanKey());
+    raw.setResolution(base.resolution());
+    raw.setStatus(base.status());
+    raw.setAssignee(base.assignee());
+    raw.setAuthorLogin(base.authorLogin());
+    raw.setTags(base.tags());
+    if (base.manualSeverity()) {
+      raw.setManualSeverity(true);
+      raw.setSeverity(base.severity());
+    } else {
+      updater.setPastSeverity(raw, base.severity(), changeContext);
+    }
+
+    // TODO attributes + changelog
+
+    // fields coming from raw
+    updater.setPastLine(raw, base.getLine());
+    updater.setPastMessage(raw, base.getMessage(), changeContext);
+    updater.setPastEffortToFix(raw, base.effortToFix(), changeContext);
+    updater.setPastTechnicalDebt(raw, base.debt(), changeContext);
+  }
+
+  public void doAutomaticTransition(DefaultIssue issue) {
+    workflow.doAutomaticTransition(issue, changeContext);
+  }
+}
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
new file mode 100644 (file)
index 0000000..8ad0371
--- /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 IssueListener {
+
+  public void beforeComponent(Component component, Tracking tracking) {
+
+  }
+
+  public void beforeIssue(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
new file mode 100644 (file)
index 0000000..9da6c8d
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * 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 beforeIssue(Component component, DefaultIssue issue) {
+    for (IssueListener listener : listeners) {
+      listener.beforeIssue(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/NewDebtCalculator.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/NewDebtCalculator.java
new file mode 100644 (file)
index 0000000..b21ffd0
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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.server.computation.component.Component;
+
+public class NewDebtCalculator extends IssueListener {
+
+  @Override
+  public void onIssue(Component component, DefaultIssue issue) {
+    // TODO
+  }
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/RuleTagsCopier.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/RuleTagsCopier.java
new file mode 100644 (file)
index 0000000..2d33d78
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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.Set;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.rule.RuleDto;
+import org.sonar.server.computation.component.Component;
+
+import static com.google.common.collect.Sets.union;
+
+public class RuleTagsCopier extends IssueListener {
+
+  private final RuleCache ruleCache;
+
+  public RuleTagsCopier(RuleCache ruleCache) {
+    this.ruleCache = ruleCache;
+  }
+
+  @Override
+  public void onIssue(Component component, DefaultIssue issue) {
+    if (issue.isNew()) {
+      // analyzer can provide some tags. They must be merged with rule tags
+      RuleDto rule = ruleCache.get(issue.ruleKey());
+      Set<String> ruleTags = union(rule.getTags(), rule.getSystemTags());
+      issue.setTags(union(issue.tags(), ruleTags));
+    }
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/ScmAccountCache.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/ScmAccountCache.java
deleted file mode 100644 (file)
index 1170c2d..0000000
+++ /dev/null
@@ -1,31 +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.server.util.cache.MemoryCache;
-
-/**
- * Cache of dictionary {SCM account -> SQ user login}
- */
-public class ScmAccountCache extends MemoryCache<String,String> {
-  public ScmAccountCache(ScmAccountCacheLoader loader) {
-    super(loader);
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/ScmAccountCacheLoader.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/ScmAccountCacheLoader.java
deleted file mode 100644 (file)
index 2d51c5b..0000000
+++ /dev/null
@@ -1,78 +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.annotations.VisibleForTesting;
-import com.google.common.base.Function;
-import com.google.common.base.Joiner;
-import com.google.common.collect.Collections2;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.server.user.index.UserDoc;
-import org.sonar.server.user.index.UserIndex;
-import org.sonar.server.util.cache.CacheLoader;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Loads the association between a SCM account and a SQ user
- */
-public class ScmAccountCacheLoader implements CacheLoader<String, String> {
-
-  private final Logger log;
-  private final UserIndex index;
-
-  public ScmAccountCacheLoader(UserIndex index) {
-    this(index, Loggers.get(ScmAccountCacheLoader.class));
-  }
-
-  @VisibleForTesting
-  ScmAccountCacheLoader(UserIndex index, Logger log) {
-    this.log = log;
-    this.index = index;
-  }
-
-  @Override
-  public String load(String scmAccount) {
-    List<UserDoc> users = index.getAtMostThreeActiveUsersForScmAccount(scmAccount);
-    if (users.size() == 1) {
-      return users.get(0).login();
-    }
-    if (!users.isEmpty()) {
-      // multiple users are associated to the same SCM account, for example
-      // the same email
-      Collection<String> logins = Collections2.transform(users, new Function<UserDoc, String>() {
-        @Override
-        public String apply(UserDoc input) {
-          return input.login();
-        }
-      });
-      log.warn(String.format("Multiple users share the SCM account '%s': %s", scmAccount, Joiner.on(", ").join(logins)));
-    }
-    return null;
-  }
-
-  @Override
-  public Map<String, String> loadAll(Collection<? extends String> scmAccounts) {
-    throw new UnsupportedOperationException("Loading by multiple scm accounts is not supported yet");
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/ScmAccountToUser.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/ScmAccountToUser.java
new file mode 100644 (file)
index 0000000..53babcf
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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.server.util.cache.MemoryCache;
+
+/**
+ * Cache of dictionary {SCM account -> SQ user login}. Kept in memory
+ * during the execution of Compute Engine.
+ */
+public class ScmAccountToUser extends MemoryCache<String,String> {
+  public ScmAccountToUser(ScmAccountToUserLoader loader) {
+    super(loader);
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/ScmAccountToUserLoader.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/ScmAccountToUserLoader.java
new file mode 100644 (file)
index 0000000..c103597
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.collect.Collections2;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.server.user.index.UserDoc;
+import org.sonar.server.user.index.UserIndex;
+import org.sonar.server.util.cache.CacheLoader;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Loads the association between a SCM account and a SQ user
+ */
+public class ScmAccountToUserLoader implements CacheLoader<String, String> {
+
+  private final Logger log;
+  private final UserIndex index;
+
+  public ScmAccountToUserLoader(UserIndex index) {
+    this(index, Loggers.get(ScmAccountToUserLoader.class));
+  }
+
+  @VisibleForTesting
+  ScmAccountToUserLoader(UserIndex index, Logger log) {
+    this.log = log;
+    this.index = index;
+  }
+
+  @Override
+  public String load(String scmAccount) {
+    List<UserDoc> users = index.getAtMostThreeActiveUsersForScmAccount(scmAccount);
+    if (users.size() == 1) {
+      return users.get(0).login();
+    }
+    if (!users.isEmpty()) {
+      // multiple users are associated to the same SCM account, for example
+      // the same email
+      Collection<String> logins = Collections2.transform(users, new Function<UserDoc, String>() {
+        @Override
+        public String apply(UserDoc input) {
+          return input.login();
+        }
+      });
+      log.warn(String.format("Multiple users share the SCM account '%s': %s", scmAccount, Joiner.on(", ").join(logins)));
+    }
+    return null;
+  }
+
+  @Override
+  public Map<String, String> loadAll(Collection<? extends String> scmAccounts) {
+    throw new UnsupportedOperationException("Loading by multiple scm accounts is not supported yet");
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/SourceLinesCache.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/SourceLinesCache.java
deleted file mode 100644 (file)
index f8654fe..0000000
+++ /dev/null
@@ -1,172 +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.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.batch.protocol.output.BatchReport;
-import org.sonar.batch.protocol.output.BatchReport.Changesets.Changeset;
-import org.sonar.batch.protocol.output.BatchReport.Changesets.Changeset.Builder;
-import org.sonar.server.computation.batch.BatchReportReader;
-import org.sonar.server.source.index.SourceLineDoc;
-import org.sonar.server.source.index.SourceLineIndex;
-
-/**
- * Cache of the lines of the currently processed file. Only a <strong>single</strong> file
- * is kept in memory at a time. Data is loaded <strong>on demand</strong> (to avoid non necessary
- * loading).<br />
- * It relies on:
- * <ul>
- *   <li>the SCM information sent in the report for modified files</li>
- *   <li>the source line index for non-modified files</li>
- * </ul>
- *
- */
-public class SourceLinesCache {
-
-  private final SourceLineIndex index;
-  private BatchReportReader reportReader;
-
-  private boolean loaded = false;
-  private BatchReport.Changesets scm;
-  private String currentFileUuid;
-  private Integer currentFileReportRef;
-
-  private long lastCommitDate = 0L;
-  private String lastCommitAuthor = null;
-
-  public SourceLinesCache(SourceLineIndex index) {
-    this.index = index;
-  }
-
-  /**
-   * Marks the currently processed component
-   */
-  void init(String fileUuid, @Nullable Integer fileReportRef, BatchReportReader reportReader) {
-    this.loaded = false;
-    this.currentFileUuid = fileUuid;
-    this.currentFileReportRef = fileReportRef;
-    this.lastCommitDate = 0L;
-    this.lastCommitAuthor = null;
-    this.reportReader = reportReader;
-    clear();
-  }
-
-  /**
-   * Last committer of the line, can be null.
-   */
-  @CheckForNull
-  public String lineAuthor(@Nullable Integer lineNumber) {
-    loadIfNeeded();
-
-    if (lineNumber == null) {
-      // issue on file, approximately estimate that author is the last committer on the file
-      return lastCommitAuthor;
-    }
-    String author = null;
-    if (lineNumber <= scm.getChangesetIndexByLineCount()) {
-      BatchReport.Changesets.Changeset changeset = scm.getChangeset(scm.getChangesetIndexByLine(lineNumber - 1));
-      author = changeset.hasAuthor() ? changeset.getAuthor() : null;
-    }
-
-    return StringUtils.defaultIfEmpty(author, lastCommitAuthor);
-  }
-
-  private void loadIfNeeded() {
-    checkState();
-
-    if (!loaded) {
-      scm = loadScmFromReport();
-      loaded = scm != null;
-    }
-
-    if (!loaded) {
-      scm = loadLinesFromIndexAndBuildScm();
-      loaded = true;
-    }
-
-    computeLastCommitDateAndAuthor();
-  }
-
-  private BatchReport.Changesets loadScmFromReport() {
-    return reportReader.readChangesets(currentFileReportRef);
-  }
-
-  private BatchReport.Changesets loadLinesFromIndexAndBuildScm() {
-    List<SourceLineDoc> lines = index.getLines(currentFileUuid);
-    Map<String, BatchReport.Changesets.Changeset> changesetByRevision = new HashMap<>();
-    BatchReport.Changesets.Builder scmBuilder = BatchReport.Changesets.newBuilder()
-      .setComponentRef(currentFileReportRef);
-    for (SourceLineDoc sourceLine : lines) {
-      String scmRevision = sourceLine.scmRevision();
-      if (scmRevision == null || changesetByRevision.get(scmRevision) == null) {
-        Builder changeSetBuilder = BatchReport.Changesets.Changeset.newBuilder();
-        String scmAuthor = sourceLine.scmAuthor();
-        if (scmAuthor != null) {
-          changeSetBuilder.setAuthor(scmAuthor);
-        }
-        Date scmDate = sourceLine.scmDate();
-        if (scmDate != null) {
-          changeSetBuilder.setDate(scmDate.getTime());
-        }
-        if (scmRevision != null) {
-          changeSetBuilder.setRevision(scmRevision);
-        }
-
-        Changeset changeset = changeSetBuilder.build();
-        scmBuilder.addChangeset(changeset);
-        scmBuilder.addChangesetIndexByLine(scmBuilder.getChangesetCount() - 1);
-        if (scmRevision != null) {
-          changesetByRevision.put(scmRevision, changeset);
-        }
-      } else {
-        scmBuilder.addChangesetIndexByLine(scmBuilder.getChangesetList().indexOf(changesetByRevision.get(scmRevision)));
-      }
-    }
-    return scmBuilder.build();
-  }
-
-  private void computeLastCommitDateAndAuthor() {
-    for (BatchReport.Changesets.Changeset changeset : scm.getChangesetList()) {
-      if (changeset.hasAuthor() && changeset.hasDate() && changeset.getDate() > lastCommitDate) {
-        lastCommitDate = changeset.getDate();
-        lastCommitAuthor = changeset.getAuthor();
-      }
-    }
-  }
-
-  private void checkState() {
-    if (currentFileReportRef == null) {
-      throw new IllegalStateException("Report component reference must not be null to use the cache");
-    }
-  }
-
-  /**
-   * Makes cache eligible to GC
-   */
-  public void clear() {
-    scm = null;
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/TrackerBaseInputFactory.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/TrackerBaseInputFactory.java
new file mode 100644 (file)
index 0000000..e5117d3
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * 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.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.persistence.DbSession;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.db.DbClient;
+
+/**
+ * Factory of {@link Input} of base data for issue tracking. Data are lazy-loaded.
+ */
+public class TrackerBaseInputFactory {
+
+  private final BaseIssuesLoader baseIssuesLoader;
+  private final DbClient dbClient;
+
+  public TrackerBaseInputFactory(BaseIssuesLoader baseIssuesLoader, DbClient dbClient) {
+    this.baseIssuesLoader = baseIssuesLoader;
+    this.dbClient = dbClient;
+  }
+
+  public Input<DefaultIssue> create(Component component) {
+    return new BaseLazyInput(component);
+  }
+
+  private class BaseLazyInput extends LazyInput<DefaultIssue> {
+    private final Component component;
+
+    private BaseLazyInput(Component component) {
+      this.component = component;
+    }
+
+    @Override
+    protected Iterable<String> loadSourceLines() {
+      DbSession session = dbClient.openSession(false);
+      try {
+        return dbClient.fileSourceDao().selectLineHashes(session, component.getUuid());
+      } finally {
+        MyBatis.closeQuietly(session);
+      }
+    }
+
+    @Override
+    protected List<DefaultIssue> loadIssues() {
+      return baseIssuesLoader.loadForComponentUuid(component.getUuid());
+    }
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/TrackerExecution.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/TrackerExecution.java
new file mode 100644 (file)
index 0000000..86e0f7c
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * 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.Tracker;
+import org.sonar.core.issue.tracking.Tracking;
+import org.sonar.server.computation.component.Component;
+
+public class TrackerExecution {
+
+  private final TrackerBaseInputFactory baseInputFactory;
+  private final TrackerRawInputFactory rawInputFactory;
+  private final Tracker<DefaultIssue, DefaultIssue> tracker;
+
+  public TrackerExecution(TrackerBaseInputFactory baseInputFactory, TrackerRawInputFactory rawInputFactory,
+    Tracker<DefaultIssue, DefaultIssue> tracker) {
+    this.baseInputFactory = baseInputFactory;
+    this.rawInputFactory = rawInputFactory;
+    this.tracker = tracker;
+  }
+
+  public Tracking<DefaultIssue, DefaultIssue> track(Component component) {
+    return tracker.track(rawInputFactory.create(component), baseInputFactory.create(component));
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/TrackerRawInputFactory.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/TrackerRawInputFactory.java
new file mode 100644 (file)
index 0000000..036a0e5
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * 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.Lists;
+import com.google.common.collect.Sets;
+import java.util.ArrayList;
+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.batch.protocol.output.BatchReport;
+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.server.computation.batch.BatchReportReader;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.component.TreeRootHolder;
+
+public class TrackerRawInputFactory {
+
+  private final TreeRootHolder treeRootHolder;
+  private final BatchReportReader reportReader;
+  private final RuleCache ruleCache;
+
+  public TrackerRawInputFactory(TreeRootHolder treeRootHolder, BatchReportReader reportReader, RuleCache ruleCache) {
+    this.treeRootHolder = treeRootHolder;
+    this.reportReader = reportReader;
+    this.ruleCache = ruleCache;
+  }
+
+  public Input<DefaultIssue> create(Component component) {
+    return new RawLazyInput(component);
+  }
+
+  private class RawLazyInput extends LazyInput<DefaultIssue> {
+    private final Component component;
+
+    private RawLazyInput(Component component) {
+      this.component = component;
+    }
+
+    @Override
+    protected Iterable<String> loadSourceLines() {
+      return Lists.newArrayList(reportReader.readFileSource(component.getRef()));
+    }
+
+    @Override
+    protected List<DefaultIssue> loadIssues() {
+      List<BatchReport.Issue> reportIssues = reportReader.readComponentIssues(component.getRef());
+      List<DefaultIssue> issues = new ArrayList<>();
+      if (!reportIssues.isEmpty()) {
+        // optimization - do not load line hashes if there are no issues
+        LineHashSequence lineHashSeq = getLineHashSequence();
+        for (BatchReport.Issue reportIssue : reportIssues) {
+          DefaultIssue issue = toIssue(lineHashSeq, reportIssue);
+          if (isValid(issue, lineHashSeq)) {
+            issues.add(issue);
+          }
+        }
+      }
+      return issues;
+    }
+
+    private DefaultIssue toIssue(LineHashSequence lineHashSeq, BatchReport.Issue reportIssue) {
+      DefaultIssue issue = new DefaultIssue();
+      issue.setRuleKey(RuleKey.of(reportIssue.getRuleRepository(), reportIssue.getRuleKey()));
+      issue.setStatus(Issue.STATUS_OPEN);
+      issue.setComponentUuid(component.getUuid());
+      issue.setComponentKey(component.getKey());
+      issue.setProjectUuid(treeRootHolder.getRoot().getUuid());
+
+      if (reportIssue.hasLine()) {
+        issue.setLine(reportIssue.getLine());
+        issue.setChecksum(lineHashSeq.getHashForLine(reportIssue.getLine()));
+      } else {
+        issue.setChecksum("");
+      }
+      if (reportIssue.hasMsg()) {
+        issue.setMessage(reportIssue.getMsg());
+      }
+      if (reportIssue.hasSeverity()) {
+        issue.setSeverity(reportIssue.getSeverity().name());
+      }
+      if (reportIssue.hasEffortToFix()) {
+        issue.setEffortToFix(reportIssue.getEffortToFix());
+      }
+      if (reportIssue.hasDebtInMinutes()) {
+        issue.setDebt(Duration.create(reportIssue.getDebtInMinutes()));
+      }
+      issue.setTags(Sets.newHashSet(reportIssue.getTagList()));
+      // TODO issue attributes
+      return issue;
+    }
+  }
+
+  private boolean isValid(DefaultIssue issue, LineHashSequence lineHashSeq) {
+    // TODO log debug when invalid ?
+    if (ruleCache.getNullable(issue.ruleKey()) == null) {
+      return false;
+    }
+    if (issue.getLine() != null && !lineHashSeq.hasLine(issue.getLine())) {
+      return false;
+    }
+    return true;
+  }
+}
index f22c71b0d5b87071e38bc91a55c7d2663b0dcb12..003d8de45b2e1bb0ba9694cf7e2c1b87c7b9c3e1 100644 (file)
@@ -24,6 +24,7 @@ import com.google.common.collect.Iterables;
 import java.util.Arrays;
 import java.util.List;
 import org.sonar.server.computation.container.ComputeEngineContainer;
+import org.sonar.server.computation.issue.IntegrateIssuesStep;
 
 /**
  * Ordered list of steps to be executed
@@ -46,10 +47,8 @@ public class ComputationSteps {
 
       FeedDebtModelStep.class,
 
-      // Read report
-      ParseReportStep.class,
-
       // load project related stuffs
+      IntegrateIssuesStep.class,
       QualityGateLoadingStep.class,
       FeedPeriodsStep.class,
 
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/ParseReportStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/ParseReportStep.java
deleted file mode 100644 (file)
index 8170712..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.server.computation.step;
-
-import java.util.List;
-import org.sonar.batch.protocol.output.BatchReport;
-import org.sonar.server.computation.batch.BatchReportReader;
-import org.sonar.server.computation.component.Component;
-import org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor;
-import org.sonar.server.computation.component.TreeRootHolder;
-import org.sonar.server.computation.issue.IssueComputation;
-
-public class ParseReportStep implements ComputationStep {
-
-  private final IssueComputation issueComputation;
-  private final BatchReportReader reportReader;
-  private final TreeRootHolder treeRootHolder;
-
-  public ParseReportStep(IssueComputation issueComputation, BatchReportReader reportReader, TreeRootHolder treeRootHolder) {
-    this.issueComputation = issueComputation;
-    this.reportReader = reportReader;
-    this.treeRootHolder = treeRootHolder;
-  }
-
-  @Override
-  public void execute() {
-    IssueDepthTraversalTypeAwareVisitor visitor = new IssueDepthTraversalTypeAwareVisitor();
-    visitor.visit(treeRootHolder.getRoot());
-    processDeletedComponents(visitor);
-    issueComputation.afterReportProcessing();
-  }
-
-  private void processDeletedComponents(IssueDepthTraversalTypeAwareVisitor visitor) {
-    int deletedComponentsCount = reportReader.readMetadata().getDeletedComponentsCount();
-    for (int componentRef = 1; componentRef <= deletedComponentsCount; componentRef++) {
-      BatchReport.Issues issues = reportReader.readDeletedComponentIssues(componentRef);
-      issueComputation.processComponentIssues(issues.getIssueList(), issues.getComponentUuid(), null, visitor.projectKey, visitor.projectUuid);
-    }
-  }
-
-  @Override
-  public String getDescription() {
-    return "Digest analysis report";
-  }
-
-  private class IssueDepthTraversalTypeAwareVisitor extends DepthTraversalTypeAwareVisitor {
-    private String projectKey;
-    private String projectUuid;
-
-    public IssueDepthTraversalTypeAwareVisitor() {
-      super(Component.Type.FILE, Order.PRE_ORDER);
-    }
-
-    @Override
-    public void visitProject(Component tree) {
-      projectKey = tree.getKey();
-      projectUuid = tree.getUuid();
-      executeForComponent(tree);
-    }
-
-    @Override
-    public void visitModule(Component module) {
-      executeForComponent(module);
-    }
-
-    @Override
-    public void visitDirectory(Component directory) {
-      executeForComponent(directory);
-    }
-
-    @Override
-    public void visitFile(Component file) {
-      executeForComponent(file);
-    }
-
-    private void executeForComponent(Component component) {
-      int componentRef = component.getRef();
-      List<BatchReport.Issue> issues = reportReader.readComponentIssues(componentRef);
-      issueComputation.processComponentIssues(issues, component.getUuid(), componentRef, projectKey, projectUuid);
-    }
-  }
-}
index df107b009c2cb3aa60d3bc93bf0a63ee16666526..539d5b6cbc73e37a740717862edece0cb46eb2f7 100644 (file)
@@ -21,10 +21,10 @@ package org.sonar.server.computation.step;
 
 import org.sonar.api.issue.Issue;
 import org.sonar.api.issue.IssueComment;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.DefaultIssueComment;
-import org.sonar.api.issue.internal.FieldDiffs;
 import org.sonar.api.utils.System2;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.DefaultIssueComment;
+import org.sonar.core.issue.FieldDiffs;
 import org.sonar.core.issue.db.IssueChangeDto;
 import org.sonar.core.issue.db.IssueChangeMapper;
 import org.sonar.core.issue.db.IssueDto;
index 5129e8a4959b763f843adf6c8cabc84be0543782..2c8aa110430b3cd44ccab76191573d4c12120c1f 100644 (file)
@@ -23,7 +23,7 @@ import com.google.common.collect.ImmutableSet;
 import java.util.Date;
 import java.util.Map;
 import java.util.Set;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.server.computation.batch.BatchReportReader;
 import org.sonar.server.computation.component.Component;
 import org.sonar.server.computation.component.TreeRootHolder;
index aa1542a659d870a4f48f62c44b5dea16d9b7ec58..73475e26ed84778fdae63e185804855251ae6538 100644 (file)
@@ -26,7 +26,7 @@ import com.google.common.collect.Sets;
 import org.sonar.api.server.ServerSide;
 import org.sonar.api.issue.Issue;
 import org.sonar.api.issue.condition.IsUnResolved;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.api.server.rule.RuleTagFormat;
 import org.sonar.core.issue.IssueUpdater;
 import org.sonar.server.user.UserSession;
index 40f6d03988b2f19e05e555c1ec26d55862aa11ea..57c4c21fd7631028145e27e68d4ca6a62a9f67bc 100644 (file)
@@ -26,7 +26,7 @@ import com.google.common.collect.ImmutableList;
 import org.sonar.api.server.ServerSide;
 import org.sonar.api.issue.Issue;
 import org.sonar.api.issue.condition.Condition;
-import org.sonar.api.issue.internal.IssueChangeContext;
+import org.sonar.core.issue.IssueChangeContext;
 import org.sonar.server.user.UserSession;
 
 import java.util.Collection;
index b5660789cad01ac8bcdedc1f1b0211a695ef0ca1..f24fa6159dae826004657e878a0ed28cfeabc4c0 100644 (file)
@@ -31,8 +31,8 @@ import org.sonar.api.issue.Issue;
 import org.sonar.api.issue.action.Action;
 import org.sonar.api.issue.action.Actions;
 import org.sonar.api.issue.action.Function;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.IssueChangeContext;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.IssueChangeContext;
 import org.sonar.core.issue.IssueUpdater;
 import org.sonar.core.issue.db.IssueStorage;
 import org.sonar.core.persistence.DbSession;
index 0c15344639ac36a22ec044fca2e17948f13cfc31..41e8b91708c6aa3f7acb4ea62a7ca649a6c0716e 100644 (file)
@@ -24,7 +24,7 @@ import com.google.common.base.Strings;
 import org.sonar.api.server.ServerSide;
 import org.sonar.api.issue.Issue;
 import org.sonar.api.issue.condition.IsUnResolved;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.api.user.User;
 import org.sonar.api.user.UserFinder;
 import org.sonar.core.issue.IssueUpdater;
index 83356b5a1c105722908cfd5fd5789fbd68fb1ff7..d37a746aff9691b827f4b6391321008ba2498075 100644 (file)
@@ -24,7 +24,7 @@ import com.google.common.base.Strings;
 import java.util.Collection;
 import java.util.Map;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.api.server.ServerSide;
 import org.sonar.core.issue.IssueUpdater;
 import org.sonar.server.user.UserSession;
index 9f01f119669613e9793325cab63d8c41aebcf73e..fc42a79853995bad1192eab69f827ce239e50859 100644 (file)
@@ -45,9 +45,9 @@ import org.sonar.api.issue.ActionPlan;
 import org.sonar.api.issue.Issue;
 import org.sonar.api.issue.IssueComment;
 import org.sonar.api.issue.action.Action;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.DefaultIssueComment;
-import org.sonar.api.issue.internal.FieldDiffs;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.DefaultIssueComment;
+import org.sonar.core.issue.FieldDiffs;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.server.ServerSide;
 import org.sonar.api.user.User;
index 53c4539b16f82805a10e75e4ff6a67cb642aae89..65ba2386cf45f00ef188ae0b56648c529581f555 100644 (file)
@@ -35,8 +35,8 @@ import java.util.Set;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.IssueChangeContext;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.IssueChangeContext;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rules.Rule;
 import org.sonar.api.utils.log.Logger;
index cd08901008399eba629d763b6dd494608b67d852..3d8ee6d3b669cafa0f1633860d1fe072a8421e9d 100644 (file)
@@ -20,7 +20,7 @@
 package org.sonar.server.issue;
 
 import com.google.common.collect.Maps;
-import org.sonar.api.issue.internal.FieldDiffs;
+import org.sonar.core.issue.FieldDiffs;
 import org.sonar.api.user.User;
 
 import javax.annotation.CheckForNull;
index aebc35d85299b37d64b6489e8ac5561397f63a58..0dc55507993f4a007266111906917a16f8f67b33 100644 (file)
@@ -25,7 +25,7 @@ import java.util.Locale;
 import java.util.Map;
 import org.sonar.api.server.ServerSide;
 import org.sonar.api.i18n.I18n;
-import org.sonar.api.issue.internal.FieldDiffs;
+import org.sonar.core.issue.FieldDiffs;
 import org.sonar.api.utils.Duration;
 import org.sonar.api.utils.Durations;
 import org.sonar.core.issue.IssueUpdater;
index 62c85672fd52305cf03bc7a8a3fc5ed6618b20bc..2009dfb10b837657c81a686865df6bfbe706802f 100644 (file)
@@ -23,7 +23,7 @@ import java.util.Collection;
 import java.util.List;
 import org.sonar.api.server.ServerSide;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.FieldDiffs;
+import org.sonar.core.issue.FieldDiffs;
 import org.sonar.api.user.User;
 import org.sonar.api.user.UserFinder;
 import org.sonar.core.issue.db.IssueChangeDao;
index 4a1bb7c307dadd0d9c9866284d7e477974eb98fb..8b1da808880be92727ef1466487f516a9c489c67 100644 (file)
@@ -24,9 +24,9 @@ import com.google.common.base.Strings;
 import org.apache.commons.lang.StringUtils;
 import org.sonar.api.server.ServerSide;
 import org.sonar.api.issue.IssueComment;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.DefaultIssueComment;
-import org.sonar.api.issue.internal.IssueChangeContext;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.DefaultIssueComment;
+import org.sonar.core.issue.IssueChangeContext;
 import org.sonar.api.utils.System2;
 import org.sonar.core.issue.IssueUpdater;
 import org.sonar.core.issue.db.IssueChangeDto;
index 0f342ce585acde8d0513f9152f563a4b8bd290c4..35e97cf20dac9cafcf2b45822d69f0eb93933b0e 100644 (file)
@@ -24,8 +24,8 @@ import com.google.common.base.Strings;
 import org.apache.commons.lang.StringUtils;
 import org.sonar.api.issue.ActionPlan;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.IssueChangeContext;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.IssueChangeContext;
 import org.sonar.server.notification.NotificationManager;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rule.Severity;
index 690dca8de779340ae0506a95c2d0464f1b1563fb..bf2993a12e27f0f960509d26b75de03da7cb3c53 100644 (file)
@@ -25,7 +25,7 @@ import org.sonar.api.server.ServerSide;
 import org.sonar.api.issue.ActionPlan;
 import org.sonar.api.issue.Issue;
 import org.sonar.api.issue.condition.IsUnResolved;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.core.issue.IssueUpdater;
 import org.sonar.server.issue.actionplan.ActionPlanService;
 import org.sonar.server.user.UserSession;
index eabaeb440895cbf395b0878437a1e06d81fa0145..74c9aedce067c021bd9df0b44084532a02bf7b16 100644 (file)
@@ -20,7 +20,7 @@
 package org.sonar.server.issue;
 
 import org.sonar.api.server.ServerSide;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.api.rules.RuleFinder;
 import org.sonar.core.component.ComponentDto;
 import org.sonar.core.issue.db.IssueDto;
index 174f943f7cd0d2838d6fd349a68d2e4c807eb4c5..6c75b9c1f0154366a261fe52c990ee1ab4ab739b 100644 (file)
@@ -26,7 +26,7 @@ import java.util.Map;
 import org.sonar.api.issue.Issue;
 import org.sonar.api.issue.condition.Condition;
 import org.sonar.api.issue.condition.IsUnResolved;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.api.server.ServerSide;
 import org.sonar.api.web.UserRole;
 import org.sonar.core.issue.IssueUpdater;
index 6683c79382dee88a59cb0ee91e38942fc12c4851..1f4c4b283ed675b7b275c8715a8c90a57e4abdcf 100644 (file)
@@ -27,7 +27,7 @@ import java.util.Collection;
 import java.util.Map;
 import org.apache.commons.lang.StringUtils;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.api.server.ServerSide;
 import org.sonar.core.issue.workflow.IssueWorkflow;
 import org.sonar.core.issue.workflow.Transition;
index 7d9b925975328733c5b8c15f75362a81ff30f4df..a2dc02852a2c4e3a5aeb8e438914bd5c1c967c26 100644 (file)
@@ -28,8 +28,8 @@ import java.util.Date;
 import java.util.List;
 import javax.annotation.CheckForNull;
 import org.sonar.api.issue.ActionPlan;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.IssueChangeContext;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.IssueChangeContext;
 import org.sonar.api.server.ServerSide;
 import org.sonar.api.web.UserRole;
 import org.sonar.core.issue.ActionPlanDeadlineComparator;
index 958135fb50d91894a78db4e550d15dcd5a25655d..348e9464d6a6f682ac148b7f74a2a8f92912a3e7 100644 (file)
@@ -19,7 +19,9 @@
  */
 package org.sonar.server.issue.db;
 
-import org.apache.ibatis.session.ResultHandler;
+import java.util.List;
+import java.util.Set;
+import javax.annotation.CheckForNull;
 import org.sonar.core.issue.db.IssueDto;
 import org.sonar.core.issue.db.IssueMapper;
 import org.sonar.core.persistence.DaoComponent;
@@ -27,9 +29,6 @@ import org.sonar.core.persistence.DbSession;
 import org.sonar.core.persistence.MyBatis;
 import org.sonar.server.exceptions.NotFoundException;
 
-import javax.annotation.CheckForNull;
-import java.util.List;
-
 public class IssueDao extends org.sonar.core.issue.db.IssueDao implements DaoComponent {
 
   public IssueDao(MyBatis mybatis) {
@@ -57,12 +56,8 @@ public class IssueDao extends org.sonar.core.issue.db.IssueDao implements DaoCom
     return mapper(session).selectByKeys(keys);
   }
 
-  public void selectNonClosedIssuesByModuleUuid(DbSession session, String moduleUuid, ResultHandler handler) {
-    session.select("org.sonar.core.issue.db.IssueMapper.selectNonClosedIssuesByModuleUuid", moduleUuid, handler);
-  }
-
-  public void selectNonClosedIssuesByProjectUuid(DbSession session, String projectUuid, ResultHandler handler) {
-    session.select("org.sonar.core.issue.db.IssueMapper.selectNonClosedIssuesByProjectUuid", projectUuid, handler);
+  public Set<String> selectComponentUuidsOfOpenIssuesForProjectUuid(DbSession session, String projectUuid) {
+    return mapper(session).selectComponentUuidsOfOpenIssuesForProjectUuid(projectUuid);
   }
 
   public void insert(DbSession session, IssueDto dto) {
index 15b0d435f66a0f6e8acd9521a30b4895984dd9b3..91e0ae311b17819c3bf39ed57ed4fe320cc0e738 100644 (file)
@@ -21,8 +21,8 @@ package org.sonar.server.issue.notification;
 
 import com.google.common.base.Strings;
 import org.sonar.api.component.Component;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.FieldDiffs;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.FieldDiffs;
 import org.sonar.api.notifications.Notification;
 
 import javax.annotation.CheckForNull;
index 8e6da6672afb8d4a8b763674fcccccab1cf111bf..11c94a2cce0c82681aefe370034a2823e34262e8 100644 (file)
@@ -35,13 +35,13 @@ import javax.annotation.Nullable;
 import org.sonar.api.issue.ActionPlan;
 import org.sonar.api.issue.Issue;
 import org.sonar.api.issue.IssueComment;
-import org.sonar.api.issue.internal.DefaultIssueComment;
 import org.sonar.api.user.User;
 import org.sonar.api.utils.DateUtils;
 import org.sonar.api.utils.Duration;
 import org.sonar.api.utils.Durations;
 import org.sonar.api.utils.text.JsonWriter;
 import org.sonar.core.component.ComponentDto;
+import org.sonar.core.issue.DefaultIssueComment;
 import org.sonar.markdown.Markdown;
 import org.sonar.server.user.UserSession;
 import org.sonar.server.ws.JsonWriterUtils;
index 13860cdbaba35ca90458a238d1f9516685cb9379..fa78cb3f86a6a288035d4b5bb4d274e6d385bda6 100644 (file)
@@ -38,7 +38,6 @@ import org.apache.commons.lang.BooleanUtils;
 import org.sonar.api.i18n.I18n;
 import org.sonar.api.issue.ActionPlan;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssueComment;
 import org.sonar.api.resources.Language;
 import org.sonar.api.resources.Languages;
 import org.sonar.api.rule.RuleKey;
@@ -52,6 +51,7 @@ import org.sonar.api.user.UserFinder;
 import org.sonar.api.utils.DateUtils;
 import org.sonar.api.utils.text.JsonWriter;
 import org.sonar.core.component.ComponentDto;
+import org.sonar.core.issue.DefaultIssueComment;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.server.component.ws.ComponentJsonWriter;
 import org.sonar.server.db.DbClient;
index 7ab69a45769a8fedced569eabe5ad43b2988c76e..aa13668a4b6cc36af3d33fcc7431ee967a724a8e 100644 (file)
@@ -29,8 +29,8 @@ import org.sonar.api.i18n.I18n;
 import org.sonar.api.issue.ActionPlan;
 import org.sonar.api.issue.Issue;
 import org.sonar.api.issue.IssueComment;
-import org.sonar.api.issue.internal.DefaultIssueComment;
-import org.sonar.api.issue.internal.FieldDiffs;
+import org.sonar.core.issue.DefaultIssueComment;
+import org.sonar.core.issue.FieldDiffs;
 import org.sonar.api.server.debt.DebtCharacteristic;
 import org.sonar.api.server.debt.internal.DefaultDebtCharacteristic;
 import org.sonar.api.server.ws.Request;
index e17ae11c323b3a6d49127808e9a74d3e09f44a99..4e78181f4c52982c6129aec6bf2897b346c020f9 100644 (file)
@@ -21,6 +21,7 @@
 package org.sonar.server.source.db;
 
 import com.google.common.base.Function;
+import com.google.common.base.Splitter;
 import java.io.Reader;
 import java.sql.Connection;
 import java.sql.PreparedStatement;
@@ -40,6 +41,7 @@ import org.sonar.core.source.db.FileSourceMapper;
 @ServerSide
 public class FileSourceDao implements DaoComponent {
 
+  private static final Splitter END_OF_LINE_SPLITTER = Splitter.on('\n');
   private final MyBatis mybatis;
 
   public FileSourceDao(MyBatis myBatis) {
@@ -66,6 +68,27 @@ public class FileSourceDao implements DaoComponent {
     }
   }
 
+  @CheckForNull
+  public Iterable<String> selectLineHashes(DbSession dbSession, String fileUuid) {
+    Connection connection = dbSession.getConnection();
+    PreparedStatement pstmt = null;
+    ResultSet rs = null;
+    try {
+      pstmt = connection.prepareStatement("SELECT line_hashes FROM file_sources WHERE file_uuid=? AND data_type=?");
+      pstmt.setString(1, fileUuid);
+      pstmt.setString(2, Type.SOURCE);
+      rs = pstmt.executeQuery();
+      if (rs.next()) {
+        return END_OF_LINE_SPLITTER.split(rs.getString(1));
+      }
+      return null;
+    } catch (SQLException e) {
+      throw new IllegalStateException("Fail to read FILE_SOURCES.LINE_HASHES of file " + fileUuid, e);
+    } finally {
+      DbUtils.closeQuietly(connection, pstmt, rs);
+    }
+  }
+
   public <T> void readLineHashesStream(DbSession dbSession, String fileUuid, Function<Reader, T> function) {
     Connection connection = dbSession.getConnection();
     PreparedStatement pstmt = null;
index 8286bcfc9fdf240e130ab658a0be60d906b8540e..f09ed4bf395f9cd790c98f952b0d2a1496a369ab 100644 (file)
@@ -42,7 +42,7 @@ public class BatchReportReaderImplTest {
   private static final BatchReport.Measure MEASURE = BatchReport.Measure.newBuilder().build();
   private static final BatchReport.Component COMPONENT = BatchReport.Component.newBuilder().setRef(COMPONENT_REF).build();
   private static final BatchReport.Issue ISSUE = BatchReport.Issue.newBuilder().build();
-  private static final BatchReport.Issues ISSUES = BatchReport.Issues.newBuilder().setComponentRef(COMPONENT_REF).setComponentUuid(COMPONENT_UUID).addIssue(ISSUE).build();
+  private static final BatchReport.Issues ISSUES = BatchReport.Issues.newBuilder().setComponentRef(COMPONENT_REF).addIssue(ISSUE).build();
   private static final BatchReport.Duplication DUPLICATION = BatchReport.Duplication.newBuilder().build();
   private static final BatchReport.Symbols.Symbol SYMBOL = BatchReport.Symbols.Symbol.newBuilder().build();
   private static final BatchReport.SyntaxHighlighting SYNTAX_HIGHLIGHTING_1 = BatchReport.SyntaxHighlighting.newBuilder().build();
@@ -166,25 +166,6 @@ public class BatchReportReaderImplTest {
     assertThat(underTest.readComponentIssues(COMPONENT_REF)).isNotSameAs(underTest.readComponentIssues(COMPONENT_REF));
   }
 
-  @Test(expected = IllegalStateException.class)
-  public void readDeletedComponentIssues_throws_ISE_if_file_does_not_exist() {
-    underTest.readDeletedComponentIssues(COMPONENT_REF);
-  }
-
-  @Test
-  public void verify_readDeletedComponentIssues_returns_Issues() {
-    writer.writeDeletedComponentIssues(COMPONENT_REF, COMPONENT_UUID, of(ISSUE));
-
-    assertThat(underTest.readDeletedComponentIssues(COMPONENT_REF)).isEqualTo(ISSUES);
-  }
-
-  @Test
-  public void readDeletedComponentIssues_it_not_cached() {
-    writer.writeDeletedComponentIssues(COMPONENT_REF, COMPONENT_UUID, of(ISSUE));
-
-    assertThat(underTest.readDeletedComponentIssues(COMPONENT_REF)).isNotSameAs(underTest.readDeletedComponentIssues(COMPONENT_REF));
-  }
-
   @Test
   public void readComponentDuplications_returns_empty_list_if_file_does_not_exist() {
     assertThat(underTest.readComponentDuplications(COMPONENT_REF)).isEmpty();
index 6a6baba1ed7129800e10a89d32d2d493aece59c5..77a62c5610fc5ad5e3d1a37b7873c3a8b3bc628f 100644 (file)
@@ -39,7 +39,6 @@ public class BatchReportReaderRule implements TestRule, BatchReportReader {
   private Map<Integer, BatchReport.Changesets> changesets = new HashMap<>();
   private Map<Integer, BatchReport.Component> components = new HashMap<>();
   private Map<Integer, List<BatchReport.Issue>> issues = new HashMap<>();
-  private Map<Integer, BatchReport.Issues> deletedIssues = new HashMap<>();
   private Map<Integer, List<BatchReport.Duplication>> duplications = new HashMap<>();
   private Map<Integer, List<BatchReport.Symbols.Symbol>> symbols = new HashMap<>();
   private Map<Integer, List<BatchReport.SyntaxHighlighting>> syntaxHighlightings = new HashMap<>();
@@ -55,8 +54,7 @@ public class BatchReportReaderRule implements TestRule, BatchReportReader {
       public void evaluate() throws Throwable {
         try {
           statement.evaluate();
-        }
-        finally {
+        } finally {
           clear();
         }
       }
@@ -69,7 +67,6 @@ public class BatchReportReaderRule implements TestRule, BatchReportReader {
     this.changesets.clear();
     this.components.clear();
     this.issues.clear();
-    this.deletedIssues.clear();
     this.duplications.clear();
     this.symbols.clear();
     this.syntaxHighlightings.clear();
@@ -132,19 +129,6 @@ public class BatchReportReaderRule implements TestRule, BatchReportReader {
     this.issues.put(componentRef, issue);
   }
 
-  @Override
-  public BatchReport.Issues readDeletedComponentIssues(int deletedComponentRef) {
-    BatchReport.Issues issues = this.deletedIssues.get(deletedComponentRef);
-    if (issues == null) {
-      throw new IllegalStateException("Unable to issues for deleted component #" + deletedComponentRef);
-    }
-    return issues;
-  }
-
-  public void putDeletedIssues(int componentRef, BatchReport.Issues issues) {
-    this.deletedIssues.put(componentRef, issues);
-  }
-
   @Override
   public List<BatchReport.Duplication> readComponentDuplications(int componentRef) {
     return nonNull(this.duplications.get(componentRef));
index e84f86884136d3dc4804adeaf683ccce51aeca17..f07db4e1b6d5ef14444356ff5da3881f72b56bc8 100644 (file)
  * 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.ImmutableSet;
-import com.google.common.collect.Iterators;
-import java.io.IOException;
-import java.util.Arrays;
-import org.junit.After;
-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.config.Settings;
-import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.utils.System2;
-import org.sonar.api.utils.log.LogTester;
-import org.sonar.batch.protocol.output.BatchReport;
-import org.sonar.core.rule.RuleDto;
-import org.sonar.server.computation.batch.BatchReportReaderRule;
-import org.sonar.server.computation.component.ProjectSettingsRepository;
-import org.sonar.server.user.index.UserDoc;
-import org.sonar.server.user.index.UserIndex;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-public class IssueComputationTest {
-
-  private static final RuleKey RULE_KEY = RuleKey.of("squid", "R1");
-  private static final String PROJECT_KEY = "PROJECT_KEY";
-
-  @Rule
-  public TemporaryFolder temp = new TemporaryFolder();
-  @Rule
-  public LogTester logTester = new LogTester();
-  @Rule
-  public BatchReportReaderRule reportReader = new BatchReportReaderRule();
-
-  IssueComputation sut;
-
-  // inputs
-  RuleCache ruleCache = mock(RuleCache.class);
-  SourceLinesCache lineCache = mock(SourceLinesCache.class);
-  ScmAccountCache scmAccountCache = mock(ScmAccountCache.class);
-  RuleDto rule = new RuleDto().setRepositoryKey(RULE_KEY.repository()).setRuleKey(RULE_KEY.rule());
-  BatchReport.Issue.Builder inputIssue = BatchReport.Issue.newBuilder()
-    .setUuid("ISSUE_A")
-    .setRuleRepository(RULE_KEY.repository())
-    .setRuleKey(RULE_KEY.rule())
-    .setStatus(Issue.STATUS_OPEN);
-  Settings projectSettings;
-  ProjectSettingsRepository projectSettingsRepository = mock(ProjectSettingsRepository.class);
-  UserIndex userIndex = mock(UserIndex.class);
-
-  // output
-  IssueCache outputIssues;
-
-  @Before
-  public void setUp() throws IOException {
-    when(ruleCache.get(RULE_KEY)).thenReturn(rule);
-    outputIssues = new IssueCache(temp.newFile(), System2.INSTANCE);
-    projectSettings = new Settings();
-    when(projectSettingsRepository.getProjectSettings(PROJECT_KEY)).thenReturn(projectSettings);
-    sut = new IssueComputation(ruleCache, lineCache, scmAccountCache, outputIssues, userIndex, projectSettingsRepository, reportReader);
-  }
-
-  @After
-  public void after() {
-    sut.afterReportProcessing();
-  }
-
-  @Test
-  public void store_issues_on_disk() {
-    process();
-
-    assertThat(Iterators.getOnlyElement(outputIssues.traverse()).key()).isEqualTo("ISSUE_A");
-  }
-
-  @Test
-  public void copy_rule_tags_on_new_issues() {
-    inputIssue.setIsNew(true);
-    rule.setTags(ImmutableSet.of("bug", "performance"));
-    rule.setSystemTags(ImmutableSet.of("blocker"));
-
-    process();
-
-    assertThat(Iterators.getOnlyElement(outputIssues.traverse()).tags()).containsOnly("blocker", "bug", "performance");
-  }
-
-  @Test
-  public void do_not_copy_rule_tags_on_existing_issues() {
-    inputIssue.setIsNew(false);
-    rule.setTags(ImmutableSet.of("bug", "performance"));
-    rule.setSystemTags(ImmutableSet.of("blocker"));
-
-    process();
-
-    assertThat(Iterators.getOnlyElement(outputIssues.traverse()).tags()).isEmpty();
-  }
-
-  @Test
-  public void guess_author_of_new_issues() {
-    inputIssue.setIsNew(true);
-    inputIssue.setLine(3);
-    when(lineCache.lineAuthor(3)).thenReturn("charlie");
-
-    process();
-
-    assertThat(Iterators.getOnlyElement(outputIssues.traverse()).authorLogin()).isEqualTo("charlie");
-  }
-
-  @Test
-  public void do_not_fail_if_missing_author_for_new_issues() {
-    inputIssue.setIsNew(true);
-    inputIssue.setLine(3);
-    when(lineCache.lineAuthor(3)).thenReturn(null);
-
-    process();
-
-    assertThat(Iterators.getOnlyElement(outputIssues.traverse()).authorLogin()).isNull();
-  }
-
-  @Test
-  public void do_not_guess_author_of_existing_issues() {
-    inputIssue.setIsNew(false);
-    inputIssue.setLine(3);
-    when(lineCache.lineAuthor(3)).thenReturn("charlie");
-
-    process();
-
-    assertThat(Iterators.getOnlyElement(outputIssues.traverse()).authorLogin()).isNull();
-  }
-
-  @Test
-  public void auto_assign_new_issues() {
-    inputIssue.setIsNew(true);
-    inputIssue.setAuthorLogin("charlie");
-    when(scmAccountCache.getNullable("charlie")).thenReturn("char.lie");
-
-    process();
-
-    assertThat(Iterators.getOnlyElement(outputIssues.traverse()).assignee()).isEqualTo("char.lie");
-  }
-
-  @Test
-  public void do_not_auto_assign_existing_issues() {
-    inputIssue.setIsNew(false);
-    inputIssue.setAuthorLogin("charlie");
-    when(scmAccountCache.getNullable("charlie")).thenReturn("char.lie");
-
-    process();
-
-    assertThat(Iterators.getOnlyElement(outputIssues.traverse()).assignee()).isNull();
-  }
-
-  @Test
-  public void do_not_override_author_and_assignee_set_by_old_batch_plugins() {
-    inputIssue.setIsNew(true);
-
-    // these fields were provided during project analysis, for instance
-    // by developer cockpit or issue-assign plugins
-    inputIssue.setAuthorLogin("charlie");
-    inputIssue.setAssignee("cabu");
-
-    process();
-
-    // keep the values, without trying to update them
-    DefaultIssue cachedIssue = Iterators.getOnlyElement(outputIssues.traverse());
-    assertThat(cachedIssue.assignee()).isEqualTo("cabu");
-    assertThat(cachedIssue.authorLogin()).isEqualTo("charlie");
-    verifyZeroInteractions(scmAccountCache);
-  }
-
-  @Test
-  public void assign_default_assignee_when_available() {
-    inputIssue.setIsNew(true);
-    String wolinski = "wolinski";
-    projectSettings.setProperty(CoreProperties.DEFAULT_ISSUE_ASSIGNEE, wolinski);
-    when(userIndex.getNullableByLogin(wolinski)).thenReturn(new UserDoc());
-
-    process();
-
-    assertThat(Iterators.getOnlyElement(outputIssues.traverse()).assignee()).isEqualTo(wolinski);
-    assertThat(logTester.logs()).doesNotContain(String.format("the %s property was set with an unknown login: %s", CoreProperties.DEFAULT_ISSUE_ASSIGNEE, wolinski));
-  }
-
-  @Test
-  public void do_not_assign_default_assignee_when_not_found_in_index() {
-    inputIssue.setIsNew(true);
-    String wolinski = "wolinski";
-    projectSettings.setProperty(CoreProperties.DEFAULT_ISSUE_ASSIGNEE, wolinski);
-    when(userIndex.getNullableByLogin(wolinski)).thenReturn(null);
-
-    process();
-
-    assertThat(Iterators.getOnlyElement(outputIssues.traverse()).assignee()).isNull();
-    assertThat(logTester.logs()).contains(String.format("the %s property was set with an unknown login: %s", CoreProperties.DEFAULT_ISSUE_ASSIGNEE, wolinski));
-  }
-
-  private void process() {
-    sut.processComponentIssues(Arrays.asList(inputIssue.build()), "FILE_A", 1, PROJECT_KEY, "PROJECT_UUID");
-  }
-}
+///*
+// * 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.ImmutableSet;
+//import com.google.common.collect.Iterators;
+//import java.io.IOException;
+//import java.util.Arrays;
+//import org.junit.After;
+//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.config.Settings;
+//import org.sonar.api.issue.Issue;
+//import org.sonar.core.issue.DefaultIssue;
+//import org.sonar.api.rule.RuleKey;
+//import org.sonar.api.utils.System2;
+//import org.sonar.api.utils.log.LogTester;
+//import org.sonar.batch.protocol.output.BatchReport;
+//import org.sonar.core.rule.RuleDto;
+//import org.sonar.server.computation.batch.BatchReportReaderRule;
+//import org.sonar.server.computation.component.ProjectSettingsRepository;
+//import org.sonar.server.user.index.UserDoc;
+//import org.sonar.server.user.index.UserIndex;
+//
+//import static org.assertj.core.api.Assertions.assertThat;
+//import static org.mockito.Mockito.mock;
+//import static org.mockito.Mockito.verifyZeroInteractions;
+//import static org.mockito.Mockito.when;
+//
+//public class IssueComputationTest {
+//
+//  private static final RuleKey RULE_KEY = RuleKey.of("squid", "R1");
+//  private static final String PROJECT_KEY = "PROJECT_KEY";
+//
+//  @Rule
+//  public TemporaryFolder temp = new TemporaryFolder();
+//  @Rule
+//  public LogTester logTester = new LogTester();
+//  @Rule
+//  public BatchReportReaderRule reportReader = new BatchReportReaderRule();
+//
+//  IssueComputation sut;
+//
+//  // inputs
+//  RuleCache ruleCache = mock(RuleCache.class);
+//  SourceAuthorsHolder lineCache = mock(SourceAuthorsHolder.class);
+//  ScmAccountToUser scmAccountToUser = mock(ScmAccountToUser.class);
+//  RuleDto rule = new RuleDto().setRepositoryKey(RULE_KEY.repository()).setRuleKey(RULE_KEY.rule());
+//  BatchReport.Issue.Builder inputIssue = BatchReport.Issue.newBuilder()
+//    .setUuid("ISSUE_A")
+//    .setRuleRepository(RULE_KEY.repository())
+//    .setRuleKey(RULE_KEY.rule())
+//    .setStatus(Issue.STATUS_OPEN);
+//  Settings projectSettings;
+//  ProjectSettingsRepository projectSettingsRepository = mock(ProjectSettingsRepository.class);
+//  UserIndex userIndex = mock(UserIndex.class);
+//
+//  // output
+//  DeprecatedIssueCache outputIssues;
+//
+//  @Before
+//  public void setUp() throws IOException {
+//    when(ruleCache.get(RULE_KEY)).thenReturn(rule);
+//    outputIssues = new DeprecatedIssueCache(temp.newFile(), System2.INSTANCE);
+//    projectSettings = new Settings();
+//    when(projectSettingsRepository.getProjectSettings(PROJECT_KEY)).thenReturn(projectSettings);
+//    sut = new IssueComputation(ruleCache, lineCache, scmAccountToUser, outputIssues, userIndex, projectSettingsRepository, reportReader);
+//  }
+//
+//  @After
+//  public void after() {
+//    sut.afterReportProcessing();
+//  }
+//
+//  @Test
+//  public void store_issues_on_disk() {
+//    process();
+//
+//    assertThat(Iterators.getOnlyElement(outputIssues.traverse()).key()).isEqualTo("ISSUE_A");
+//  }
+//
+//  @Test
+//  public void copy_rule_tags_on_new_issues() {
+//    inputIssue.setIsNew(true);
+//    rule.setTags(ImmutableSet.of("bug", "performance"));
+//    rule.setSystemTags(ImmutableSet.of("blocker"));
+//
+//    process();
+//
+//    assertThat(Iterators.getOnlyElement(outputIssues.traverse()).tags()).containsOnly("blocker", "bug", "performance");
+//  }
+//
+//  @Test
+//  public void do_not_copy_rule_tags_on_existing_issues() {
+//    inputIssue.setIsNew(false);
+//    rule.setTags(ImmutableSet.of("bug", "performance"));
+//    rule.setSystemTags(ImmutableSet.of("blocker"));
+//
+//    process();
+//
+//    assertThat(Iterators.getOnlyElement(outputIssues.traverse()).tags()).isEmpty();
+//  }
+//
+//  @Test
+//  public void guess_author_of_new_issues() {
+//    inputIssue.setIsNew(true);
+//    inputIssue.setLine(3);
+//    when(lineCache.lineAuthor(3)).thenReturn("charlie");
+//
+//    process();
+//
+//    assertThat(Iterators.getOnlyElement(outputIssues.traverse()).authorLogin()).isEqualTo("charlie");
+//  }
+//
+//  @Test
+//  public void do_not_fail_if_missing_author_for_new_issues() {
+//    inputIssue.setIsNew(true);
+//    inputIssue.setLine(3);
+//    when(lineCache.lineAuthor(3)).thenReturn(null);
+//
+//    process();
+//
+//    assertThat(Iterators.getOnlyElement(outputIssues.traverse()).authorLogin()).isNull();
+//  }
+//
+//  @Test
+//  public void do_not_guess_author_of_existing_issues() {
+//    inputIssue.setIsNew(false);
+//    inputIssue.setLine(3);
+//    when(lineCache.lineAuthor(3)).thenReturn("charlie");
+//
+//    process();
+//
+//    assertThat(Iterators.getOnlyElement(outputIssues.traverse()).authorLogin()).isNull();
+//  }
+//
+//  @Test
+//  public void auto_assign_new_issues() {
+//    inputIssue.setIsNew(true);
+//    inputIssue.setAuthorLogin("charlie");
+//    when(scmAccountToUser.getNullable("charlie")).thenReturn("char.lie");
+//
+//    process();
+//
+//    assertThat(Iterators.getOnlyElement(outputIssues.traverse()).assignee()).isEqualTo("char.lie");
+//  }
+//
+//  @Test
+//  public void do_not_auto_assign_existing_issues() {
+//    inputIssue.setIsNew(false);
+//    inputIssue.setAuthorLogin("charlie");
+//    when(scmAccountToUser.getNullable("charlie")).thenReturn("char.lie");
+//
+//    process();
+//
+//    assertThat(Iterators.getOnlyElement(outputIssues.traverse()).assignee()).isNull();
+//  }
+//
+//  @Test
+//  public void do_not_override_author_and_assignee_set_by_old_batch_plugins() {
+//    inputIssue.setIsNew(true);
+//
+//    // these fields were provided during project analysis, for instance
+//    // by developer cockpit or issue-assign plugins
+//    inputIssue.setAuthorLogin("charlie");
+//    inputIssue.setAssignee("cabu");
+//
+//    process();
+//
+//    // keep the values, without trying to update them
+//    DefaultIssue cachedIssue = Iterators.getOnlyElement(outputIssues.traverse());
+//    assertThat(cachedIssue.assignee()).isEqualTo("cabu");
+//    assertThat(cachedIssue.authorLogin()).isEqualTo("charlie");
+//    verifyZeroInteractions(scmAccountToUser);
+//  }
+//
+//  @Test
+//  public void assign_default_assignee_when_available() {
+//    inputIssue.setIsNew(true);
+//    String wolinski = "wolinski";
+//    projectSettings.setProperty(CoreProperties.DEFAULT_ISSUE_ASSIGNEE, wolinski);
+//    when(userIndex.getNullableByLogin(wolinski)).thenReturn(new UserDoc());
+//
+//    process();
+//
+//    assertThat(Iterators.getOnlyElement(outputIssues.traverse()).assignee()).isEqualTo(wolinski);
+//    assertThat(logTester.logs()).doesNotContain(String.format("the %s property was set with an unknown login: %s", CoreProperties.DEFAULT_ISSUE_ASSIGNEE, wolinski));
+//  }
+//
+//  @Test
+//  public void do_not_assign_default_assignee_when_not_found_in_index() {
+//    inputIssue.setIsNew(true);
+//    String wolinski = "wolinski";
+//    projectSettings.setProperty(CoreProperties.DEFAULT_ISSUE_ASSIGNEE, wolinski);
+//    when(userIndex.getNullableByLogin(wolinski)).thenReturn(null);
+//
+//    process();
+//
+//    assertThat(Iterators.getOnlyElement(outputIssues.traverse()).assignee()).isNull();
+//    assertThat(logTester.logs()).contains(String.format("the %s property was set with an unknown login: %s", CoreProperties.DEFAULT_ISSUE_ASSIGNEE, wolinski));
+//  }
+//
+//  private void process() {
+//    sut.processComponentIssues(Arrays.asList(inputIssue.build()), "FILE_A", 1, PROJECT_KEY, "PROJECT_UUID");
+//  }
+//}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/issue/ScmAccountCacheLoaderTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/issue/ScmAccountCacheLoaderTest.java
deleted file mode 100644 (file)
index 6f0fd8a..0000000
+++ /dev/null
@@ -1,79 +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.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Test;
-import org.sonar.api.config.Settings;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.server.es.EsTester;
-import org.sonar.server.user.index.UserIndex;
-import org.sonar.server.user.index.UserIndexDefinition;
-
-import java.util.Collections;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-public class ScmAccountCacheLoaderTest {
-
-  @ClassRule
-  public static EsTester esTester = new EsTester().addDefinitions(new UserIndexDefinition(new Settings()));
-
-  @Before
-  public void setUp() {
-    esTester.truncateIndices();
-  }
-
-  @Test
-  public void load_login_for_scm_account() throws Exception {
-    esTester.putDocuments("users", "user", getClass(), "charlie.json");
-    UserIndex index = new UserIndex(esTester.client());
-    ScmAccountCacheLoader loader = new ScmAccountCacheLoader(index);
-
-    assertThat(loader.load("missing")).isNull();
-    assertThat(loader.load("jesuis@charlie.com")).isEqualTo("charlie");
-  }
-
-  @Test
-  public void warn_if_multiple_users_share_same_scm_account() throws Exception {
-    esTester.putDocuments("users", "user", getClass(), "charlie.json", "charlie_conflict.json");
-    UserIndex index = new UserIndex(esTester.client());
-    Logger log = mock(Logger.class);
-    ScmAccountCacheLoader loader = new ScmAccountCacheLoader(index, log);
-
-    assertThat(loader.load("charlie")).isNull();
-    verify(log).warn("Multiple users share the SCM account 'charlie': charlie, another.charlie");
-  }
-
-  @Test
-  public void load_by_multiple_scm_accounts_is_not_supported_yet() {
-    UserIndex index = new UserIndex(esTester.client());
-    ScmAccountCacheLoader loader = new ScmAccountCacheLoader(index);
-    try {
-      loader.loadAll(Collections.<String>emptyList());
-      fail();
-    } catch (UnsupportedOperationException ignored) {
-    }
-  }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/issue/ScmAccountToUserLoaderTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/issue/ScmAccountToUserLoaderTest.java
new file mode 100644 (file)
index 0000000..a25df3a
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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.Collections;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.sonar.api.config.Settings;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.server.es.EsTester;
+import org.sonar.server.user.index.UserIndex;
+import org.sonar.server.user.index.UserIndexDefinition;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+public class ScmAccountToUserLoaderTest {
+
+  @ClassRule
+  public static EsTester esTester = new EsTester().addDefinitions(new UserIndexDefinition(new Settings()));
+
+  @Before
+  public void setUp() {
+    esTester.truncateIndices();
+  }
+
+  @Test
+  public void load_login_for_scm_account() throws Exception {
+    esTester.putDocuments("users", "user", getClass(), "charlie.json");
+    UserIndex index = new UserIndex(esTester.client());
+    ScmAccountToUserLoader loader = new ScmAccountToUserLoader(index);
+
+    assertThat(loader.load("missing")).isNull();
+    assertThat(loader.load("jesuis@charlie.com")).isEqualTo("charlie");
+  }
+
+  @Test
+  public void warn_if_multiple_users_share_same_scm_account() throws Exception {
+    esTester.putDocuments("users", "user", getClass(), "charlie.json", "charlie_conflict.json");
+    UserIndex index = new UserIndex(esTester.client());
+    Logger log = mock(Logger.class);
+    ScmAccountToUserLoader loader = new ScmAccountToUserLoader(index, log);
+
+    assertThat(loader.load("charlie")).isNull();
+    verify(log).warn("Multiple users share the SCM account 'charlie': charlie, another.charlie");
+  }
+
+  @Test
+  public void load_by_multiple_scm_accounts_is_not_supported_yet() {
+    UserIndex index = new UserIndex(esTester.client());
+    ScmAccountToUserLoader loader = new ScmAccountToUserLoader(index);
+    try {
+      loader.loadAll(Collections.<String>emptyList());
+      fail();
+    } catch (UnsupportedOperationException ignored) {
+    }
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/issue/SourceAuthorsHolderTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/issue/SourceAuthorsHolderTest.java
new file mode 100644 (file)
index 0000000..ccfcddd
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * 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
+// * 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.junit.Before;
+//import org.junit.ClassRule;
+//import org.junit.Rule;
+//import org.junit.Test;
+//import org.junit.experimental.categories.Category;
+//import org.sonar.api.config.Settings;
+//import org.sonar.batch.protocol.output.BatchReport;
+//import org.sonar.server.computation.batch.BatchReportReaderRule;
+//import org.sonar.server.es.EsTester;
+//import org.sonar.server.source.index.SourceLineDoc;
+//import org.sonar.server.source.index.SourceLineIndex;
+//import org.sonar.server.source.index.SourceLineIndexDefinition;
+//import org.sonar.test.DbTests;
+//
+//import static org.assertj.core.api.Assertions.assertThat;
+//
+//@Category(DbTests.class)
+//public class SourceAuthorsHolderTest {
+//
+//  @ClassRule
+//  public static EsTester esTester = new EsTester().addDefinitions(new SourceLineIndexDefinition(new Settings()));
+//  @Rule
+//  public BatchReportReaderRule reportReader = new BatchReportReaderRule();
+//
+//  SourceAuthorsHolder sut;
+//
+//  @Before
+//  public void setUp() throws Exception {
+//    esTester.truncateIndices();
+//    sut = new SourceAuthorsHolder(new SourceLineIndex(esTester.client()), reportReader);
+//  }
+//
+//  @Test
+//  public void line_author_from_report() {
+//    reportReader.putChangesets(BatchReport.Changesets.newBuilder()
+//      .setComponentRef(123_456_789)
+//      .addChangeset(newChangeset("charb", "123-456-789", 123_456_789L))
+//      .addChangeset(newChangeset("wolinski", "987-654-321", 987_654_321L))
+//      .addChangesetIndexByLine(0)
+//      .addChangesetIndexByLine(0)
+//      .addChangesetIndexByLine(1)
+//      .build());
+//
+//    sut.init("ANY_UUID", 123_456_789, reportReader);
+//
+//    assertThat(sut.lineAuthor(1)).isEqualTo("charb");
+//    assertThat(sut.lineAuthor(2)).isEqualTo("charb");
+//    assertThat(sut.lineAuthor(3)).isEqualTo("wolinski");
+//    // compute last author
+//    assertThat(sut.lineAuthor(4)).isEqualTo("wolinski");
+//    assertThat(sut.lineAuthor(null)).isEqualTo("wolinski");
+//  }
+//
+//  @Test
+//  public void line_author_from_index() throws Exception {
+//    esTester.putDocuments(SourceLineIndexDefinition.INDEX, SourceLineIndexDefinition.TYPE,
+//      newSourceLine("cabu", "123-456-789", 123_456_789, 1),
+//      newSourceLine("cabu", "123-456-789", 123_456_789, 2),
+//      newSourceLine("cabu", "123-123-789", 123_456_789, 3),
+//      newSourceLine("wolinski", "987-654-321", 987_654_321, 4),
+//      newSourceLine("cabu", "123-456-789", 123_456_789, 5)
+//      );
+//
+//    sut.init("DEFAULT_UUID", 123, reportReader);
+//
+//    assertThat(sut.lineAuthor(1)).isEqualTo("cabu");
+//    assertThat(sut.lineAuthor(2)).isEqualTo("cabu");
+//    assertThat(sut.lineAuthor(3)).isEqualTo("cabu");
+//    assertThat(sut.lineAuthor(4)).isEqualTo("wolinski");
+//    assertThat(sut.lineAuthor(5)).isEqualTo("cabu");
+//    assertThat(sut.lineAuthor(6)).isEqualTo("wolinski");
+//  }
+//
+//  @Test(expected = IllegalStateException.class)
+//  public void fail_when_component_ref_is_not_filled() {
+//    sut.init("ANY_UUID", null, reportReader);
+//    sut.lineAuthor(0);
+//  }
+//
+//  private BatchReport.Changesets.Changeset.Builder newChangeset(String author, String revision, long date) {
+//    return BatchReport.Changesets.Changeset.newBuilder()
+//      .setAuthor(author)
+//      .setRevision(revision)
+//      .setDate(date);
+//  }
+//
+//  private SourceLineDoc newSourceLine(String author, String revision, long date, int lineNumber) {
+//    return new SourceLineDoc()
+//      .setScmAuthor(author)
+//      .setScmRevision(revision)
+//      .setScmDate(new Date(date))
+//      .setLine(lineNumber)
+//      .setProjectUuid("PROJECT_UUID")
+//      .setFileUuid("DEFAULT_UUID");
+//  }
+//}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/issue/SourceLinesCacheTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/issue/SourceLinesCacheTest.java
deleted file mode 100644 (file)
index 4638933..0000000
+++ /dev/null
@@ -1,118 +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.Date;
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.sonar.api.config.Settings;
-import org.sonar.batch.protocol.output.BatchReport;
-import org.sonar.server.computation.batch.BatchReportReaderRule;
-import org.sonar.server.es.EsTester;
-import org.sonar.server.source.index.SourceLineDoc;
-import org.sonar.server.source.index.SourceLineIndex;
-import org.sonar.server.source.index.SourceLineIndexDefinition;
-import org.sonar.test.DbTests;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-@Category(DbTests.class)
-public class SourceLinesCacheTest {
-
-  @ClassRule
-  public static EsTester esTester = new EsTester().addDefinitions(new SourceLineIndexDefinition(new Settings()));
-  @Rule
-  public BatchReportReaderRule reportReader = new BatchReportReaderRule();
-
-  SourceLinesCache sut;
-
-  @Before
-  public void setUp() throws Exception {
-    esTester.truncateIndices();
-    sut = new SourceLinesCache(new SourceLineIndex(esTester.client()));
-  }
-
-  @Test
-  public void line_author_from_report() {
-    reportReader.putChangesets(BatchReport.Changesets.newBuilder()
-      .setComponentRef(123_456_789)
-      .addChangeset(newChangeset("charb", "123-456-789", 123_456_789L))
-      .addChangeset(newChangeset("wolinski", "987-654-321", 987_654_321L))
-      .addChangesetIndexByLine(0)
-      .addChangesetIndexByLine(0)
-      .addChangesetIndexByLine(1)
-      .build());
-
-    sut.init("ANY_UUID", 123_456_789, reportReader);
-
-    assertThat(sut.lineAuthor(1)).isEqualTo("charb");
-    assertThat(sut.lineAuthor(2)).isEqualTo("charb");
-    assertThat(sut.lineAuthor(3)).isEqualTo("wolinski");
-    // compute last author
-    assertThat(sut.lineAuthor(4)).isEqualTo("wolinski");
-    assertThat(sut.lineAuthor(null)).isEqualTo("wolinski");
-  }
-
-  @Test
-  public void line_author_from_index() throws Exception {
-    esTester.putDocuments(SourceLineIndexDefinition.INDEX, SourceLineIndexDefinition.TYPE,
-      newSourceLine("cabu", "123-456-789", 123_456_789, 1),
-      newSourceLine("cabu", "123-456-789", 123_456_789, 2),
-      newSourceLine("cabu", "123-123-789", 123_456_789, 3),
-      newSourceLine("wolinski", "987-654-321", 987_654_321, 4),
-      newSourceLine("cabu", "123-456-789", 123_456_789, 5)
-      );
-
-    sut.init("DEFAULT_UUID", 123, reportReader);
-
-    assertThat(sut.lineAuthor(1)).isEqualTo("cabu");
-    assertThat(sut.lineAuthor(2)).isEqualTo("cabu");
-    assertThat(sut.lineAuthor(3)).isEqualTo("cabu");
-    assertThat(sut.lineAuthor(4)).isEqualTo("wolinski");
-    assertThat(sut.lineAuthor(5)).isEqualTo("cabu");
-    assertThat(sut.lineAuthor(6)).isEqualTo("wolinski");
-  }
-
-  @Test(expected = IllegalStateException.class)
-  public void fail_when_component_ref_is_not_filled() {
-    sut.init("ANY_UUID", null, reportReader);
-    sut.lineAuthor(0);
-  }
-
-  private BatchReport.Changesets.Changeset.Builder newChangeset(String author, String revision, long date) {
-    return BatchReport.Changesets.Changeset.newBuilder()
-      .setAuthor(author)
-      .setRevision(revision)
-      .setDate(date);
-  }
-
-  private SourceLineDoc newSourceLine(String author, String revision, long date, int lineNumber) {
-    return new SourceLineDoc()
-      .setScmAuthor(author)
-      .setScmRevision(revision)
-      .setScmDate(new Date(date))
-      .setLine(lineNumber)
-      .setProjectUuid("PROJECT_UUID")
-      .setFileUuid("DEFAULT_UUID");
-  }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ParseReportStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ParseReportStepTest.java
deleted file mode 100644 (file)
index c134485..0000000
+++ /dev/null
@@ -1,122 +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.step;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import org.junit.ClassRule;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.batch.protocol.Constants;
-import org.sonar.batch.protocol.output.BatchReport;
-import org.sonar.core.persistence.DbTester;
-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.issue.IssueComputation;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-public class ParseReportStepTest extends BaseStepTest {
-
-  private static final String PROJECT_KEY = "PROJECT_KEY";
-
-  private static final List<BatchReport.Issue> ISSUES_ON_DELETED_COMPONENT = Arrays.asList(BatchReport.Issue.newBuilder()
-    .setUuid("DELETED_ISSUE_UUID")
-    .build());
-
-  @Rule
-  public TemporaryFolder temp = new TemporaryFolder();
-  @Rule
-  public BatchReportReaderRule reportReader = new BatchReportReaderRule();
-  @Rule
-  public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
-
-  @ClassRule
-  public static DbTester dbTester = new DbTester();
-
-  IssueComputation issueComputation = mock(IssueComputation.class);
-  ParseReportStep sut = new ParseReportStep(issueComputation, reportReader, treeRootHolder);
-
-  @Test
-  public void extract_report_from_db_and_browse_components() throws Exception {
-    DumbComponent root = DumbComponent.builder(Component.Type.PROJECT, 1).setUuid("PROJECT_UUID").setKey(PROJECT_KEY).addChildren(
-      DumbComponent.builder(Component.Type.FILE, 2).setUuid("FILE1_UUID").setKey("PROJECT_KEY:file1").build(),
-      DumbComponent.builder(Component.Type.FILE, 3).setUuid("FILE2_UUID").setKey("PROJECT_KEY:file2").build())
-      .build();
-
-    generateReport();
-
-    treeRootHolder.setRoot(root);
-
-    sut.execute();
-
-    assertThat(reportReader.readMetadata().getRootComponentRef()).isEqualTo(1);
-    assertThat(reportReader.readMetadata().getDeletedComponentsCount()).isEqualTo(1);
-
-    // verify that all components are processed (currently only for issues)
-    verify(issueComputation).processComponentIssues(Collections.<BatchReport.Issue>emptyList(), "PROJECT_UUID", 1, PROJECT_KEY, "PROJECT_UUID");
-    verify(issueComputation).processComponentIssues(Collections.<BatchReport.Issue>emptyList(), "FILE1_UUID", 2, PROJECT_KEY, "PROJECT_UUID");
-    verify(issueComputation).processComponentIssues(Collections.<BatchReport.Issue>emptyList(), "FILE2_UUID", 3, PROJECT_KEY, "PROJECT_UUID");
-    verify(issueComputation).processComponentIssues(ISSUES_ON_DELETED_COMPONENT, "DELETED_UUID", null, PROJECT_KEY, "PROJECT_UUID");
-    verify(issueComputation).afterReportProcessing();
-  }
-
-  private void generateReport() throws IOException {
-    // project and 2 files
-    reportReader.setMetadata(BatchReport.Metadata.newBuilder()
-      .setRootComponentRef(1)
-      .setDeletedComponentsCount(1)
-      .build());
-
-    reportReader.putComponent(BatchReport.Component.newBuilder()
-      .setRef(1)
-      .setType(Constants.ComponentType.PROJECT)
-      .addChildRef(2)
-      .addChildRef(3)
-      .build());
-    reportReader.putComponent(BatchReport.Component.newBuilder()
-      .setRef(2)
-      .setType(Constants.ComponentType.FILE)
-      .build());
-    reportReader.putComponent(BatchReport.Component.newBuilder()
-      .setRef(3)
-      .setType(Constants.ComponentType.FILE)
-      .build());
-
-    // deleted components
-    BatchReport.Issues.Builder issuesBuilder = BatchReport.Issues.newBuilder();
-    issuesBuilder.setComponentRef(1);
-    issuesBuilder.setComponentUuid("DELETED_UUID");
-    issuesBuilder.addAllIssue(ISSUES_ON_DELETED_COMPONENT);
-    reportReader.putDeletedIssues(1, issuesBuilder.build());
-  }
-
-  @Override
-  protected ComputationStep step() {
-    return sut;
-  }
-}
index f50bc0e2cd9a05d28127762f5fa75a923e7a67e8..e5592554a47fa53f5bc295bbf477f49d435491a8 100644 (file)
@@ -27,12 +27,12 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.DefaultIssueComment;
-import org.sonar.api.issue.internal.FieldDiffs;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rule.Severity;
 import org.sonar.api.utils.System2;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.DefaultIssueComment;
+import org.sonar.core.issue.FieldDiffs;
 import org.sonar.core.issue.db.UpdateConflictResolver;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.core.persistence.DbTester;
index cbca0035cb0c83129a3547bcd1fa02cd9634aedd..e79b559ed79fa75f6073dad9643ab9d2e1e38d94 100644 (file)
@@ -25,7 +25,7 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
 import org.mockito.Mockito;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.api.notifications.Notification;
 import org.sonar.api.rule.Severity;
 import org.sonar.api.utils.System2;
index 29f8b0d496d8ccde7c77cbe4ad6014d24b8e54fd..1738484d0c83bbdbc3f6c4d24b8220c77561fb60 100644 (file)
@@ -28,8 +28,8 @@ import org.sonar.api.issue.Issue;
 import org.sonar.api.issue.action.Actions;
 import org.sonar.api.issue.action.Function;
 import org.sonar.api.issue.condition.Condition;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.IssueChangeContext;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.IssueChangeContext;
 import org.sonar.core.component.ComponentDto;
 import org.sonar.core.issue.IssueUpdater;
 import org.sonar.core.issue.db.IssueDto;
index d525662371cb2109d13ded44165d3bc49d2adc7a..326a7fbb2e9c1cce49c9df36eadd3206c4f3ab39 100644 (file)
@@ -26,8 +26,8 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.mockito.Matchers;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.IssueChangeContext;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.IssueChangeContext;
 import org.sonar.core.issue.IssueUpdater;
 
 import java.util.Collection;
index cec5baa96cef351acf6ce3684e4e20adbb3553db..cd5bba96b08ca7fa56667ba05f4bdae0fc711cd0 100644 (file)
@@ -25,8 +25,8 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.IssueChangeContext;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.IssueChangeContext;
 import org.sonar.api.user.User;
 import org.sonar.api.user.UserFinder;
 import org.sonar.core.issue.IssueUpdater;
index 9453a822e98fc400ba4dfa1689a312f93c9075a7..09ad3c81e849610eda5247583fdda1412317cdc9 100644 (file)
@@ -25,8 +25,8 @@ import java.util.Map;
 import org.junit.Before;
 import org.junit.Test;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.IssueChangeContext;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.IssueChangeContext;
 import org.sonar.core.issue.IssueUpdater;
 import org.sonar.server.tester.AnonymousMockUserSession;
 
index 93d9c9d36965b506caeb17ccdbef32976dce2b23..392c7182df1d7ca9084c0a5e968f31fd00e12511 100644 (file)
@@ -33,8 +33,8 @@ import org.mockito.ArgumentCaptor;
 import org.sonar.api.issue.ActionPlan;
 import org.sonar.api.issue.Issue;
 import org.sonar.api.issue.action.Action;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.FieldDiffs;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.FieldDiffs;
 import org.sonar.api.user.User;
 import org.sonar.api.web.UserRole;
 import org.sonar.core.issue.DefaultActionPlan;
index fbdec1239255f0160dd0a47640199bb69dcc7a15..d678470bcbebf6c1f97089561e8fbd075d289792 100644 (file)
@@ -28,7 +28,7 @@ import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.runners.MockitoJUnitRunner;
 import org.sonar.api.i18n.I18n;
-import org.sonar.api.issue.internal.FieldDiffs;
+import org.sonar.core.issue.FieldDiffs;
 import org.sonar.api.utils.Duration;
 import org.sonar.api.utils.Durations;
 import org.sonar.server.tester.UserSessionRule;
index 7723f024513b78170b3683cab4fe2c2afb52afef..f06bea4e57b8091bbba191ac07330edbb0596d72 100644 (file)
@@ -27,8 +27,8 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.runners.MockitoJUnitRunner;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.FieldDiffs;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.FieldDiffs;
 import org.sonar.api.user.User;
 import org.sonar.api.user.UserFinder;
 import org.sonar.core.issue.db.IssueChangeDao;
index a343a0394126a1e34cc344b647817d55f7c90cc2..d0bdd68ea9d7cb28f433c70149791ba276daec28 100644 (file)
@@ -27,7 +27,7 @@ import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssueComment;
+import org.sonar.core.issue.DefaultIssueComment;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rule.RuleStatus;
 import org.sonar.api.security.DefaultGroups;
index c4921fddb2a9a876d8462d7d8f1044214e8f2ab5..51d64252b1f88561cd5e86402e5ac796e269d21f 100644 (file)
@@ -28,9 +28,9 @@ import org.junit.rules.ExpectedException;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.runners.MockitoJUnitRunner;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.DefaultIssueComment;
-import org.sonar.api.issue.internal.IssueChangeContext;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.DefaultIssueComment;
+import org.sonar.core.issue.IssueChangeContext;
 import org.sonar.core.issue.IssueUpdater;
 import org.sonar.core.issue.db.IssueChangeDao;
 import org.sonar.core.issue.db.IssueChangeDto;
index 9da70d4d60636c052c600485cd4fd138b5d520dc..f47fe9ceb9dea699a5088594f9afddd7e9440a93 100644 (file)
@@ -26,8 +26,8 @@ import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.sonar.api.issue.ActionPlan;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.IssueChangeContext;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.IssueChangeContext;
 import org.sonar.core.issue.DefaultActionPlan;
 import org.sonar.core.issue.IssueUpdater;
 import org.sonar.server.issue.actionplan.ActionPlanService;
index 7280f972a34340df46d487a8fe6c43b72c53fa4a..1c966c06cb64f3ad46063c0ceb2cbe50bb6c5a3f 100644 (file)
@@ -26,8 +26,8 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.mockito.Matchers;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.IssueChangeContext;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.IssueChangeContext;
 import org.sonar.core.issue.IssueUpdater;
 
 import java.util.Collection;
index a6ea52cbaf3ca1a389dc08c6ca1e5d0681d10570..e295b3c965f18412c1265057a55f75624bf64d5f 100644 (file)
@@ -23,9 +23,9 @@ package org.sonar.server.issue;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.DefaultIssueComment;
-import org.sonar.api.issue.internal.IssueChangeContext;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.DefaultIssueComment;
+import org.sonar.core.issue.IssueChangeContext;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rules.Rule;
 import org.sonar.api.rules.RuleFinder;
index 093e41fa9c1ce8d63946eef4620849828371904d..07de711cfc3e977d20ab46d234fcaf570a2846da 100644 (file)
@@ -26,8 +26,8 @@ import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.IssueChangeContext;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.IssueChangeContext;
 import org.sonar.api.web.UserRole;
 import org.sonar.core.issue.IssueUpdater;
 import org.sonar.server.tester.UserSessionRule;
index 86945151adeb7091a24dce7354d734bca6f857a1..99c17905fb7df88cd52ccae8d20b7ed00f928bbf 100644 (file)
@@ -26,8 +26,8 @@ import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.IssueChangeContext;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.IssueChangeContext;
 import org.sonar.core.issue.workflow.IssueWorkflow;
 import org.sonar.core.issue.workflow.Transition;
 import org.sonar.server.tester.UserSessionRule;
index 4d17c6e4667c4d5b476de2a0c0078faad99629af..500f85a8348a4dd6fa41531a796b715c57b946e5 100644 (file)
@@ -28,8 +28,8 @@ import org.mockito.Mock;
 import org.mockito.runners.MockitoJUnitRunner;
 import org.sonar.api.issue.ActionPlan;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.IssueChangeContext;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.IssueChangeContext;
 import org.sonar.api.web.UserRole;
 import org.sonar.core.issue.ActionPlanStats;
 import org.sonar.core.issue.DefaultActionPlan;
index acd550864724e5247e04c98e301e2bbcd248927f..49a57b9db6d6c233a56a36b6ab16b08e4f71102c 100644 (file)
@@ -20,8 +20,8 @@
 package org.sonar.server.issue.notification;
 
 import org.junit.Test;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.FieldDiffs;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.FieldDiffs;
 import org.sonar.core.component.ComponentDto;
 
 import static org.assertj.core.api.Assertions.assertThat;
index 63c35a2bdeb7238811143d6509c0f98024facf8e..61e2e63bf0b863d86f2b0a15b3c414ce96291655 100644 (file)
@@ -24,7 +24,7 @@ import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
 import org.junit.Test;
 import org.mockito.Mockito;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rule.Severity;
 import org.sonar.api.utils.DateUtils;
index 215297d17edb71a0dc49120edf4e16ccc980e4f8..08f6851849b1e0d3c4e975aeee6d2426343570f6 100644 (file)
@@ -22,7 +22,7 @@ package org.sonar.server.issue.notification;
 
 import com.google.common.collect.Lists;
 import org.junit.Test;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rule.Severity;
 import org.sonar.api.utils.Duration;
index 34aab044a418bdb3acb91cea3157df8c638fddd3..d80a54701541df64f084bff5a6cd55e8a3d468ac 100644 (file)
@@ -29,7 +29,7 @@ import org.mockito.Mock;
 import org.mockito.runners.MockitoJUnitRunner;
 import org.sonar.api.issue.Issue;
 import org.sonar.api.issue.action.Action;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.utils.text.JsonWriter;
 import org.sonar.api.web.UserRole;
index 61e7a76811027f6f2b754b773d16d8c2b33a932f..5d1268abc7328f2ea6eb586587c1725760325342 100644 (file)
@@ -31,9 +31,9 @@ import org.mockito.Mock;
 import org.mockito.runners.MockitoJUnitRunner;
 import org.sonar.api.i18n.I18n;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.DefaultIssueComment;
-import org.sonar.api.issue.internal.FieldDiffs;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.DefaultIssueComment;
+import org.sonar.core.issue.FieldDiffs;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.server.debt.internal.DefaultDebtCharacteristic;
 import org.sonar.api.user.User;
index a238e9ef2fd416a7256a4165fffe9233e61a19aa..5f02ff8f82ef2695fcdf7e7a26d71de8ddcf513e 100644 (file)
@@ -69,23 +69,6 @@ public final class BatchReport {
      * <code>optional int32 root_component_ref = 4;</code>
      */
     int getRootComponentRef();
-
-    /**
-     * <code>optional int32 deleted_components_count = 5;</code>
-     *
-     * <pre>
-     * temporary fields used during development of computation stack
-     * </pre>
-     */
-    boolean hasDeletedComponentsCount();
-    /**
-     * <code>optional int32 deleted_components_count = 5;</code>
-     *
-     * <pre>
-     * temporary fields used during development of computation stack
-     * </pre>
-     */
-    int getDeletedComponentsCount();
   }
   /**
    * Protobuf type {@code Metadata}
@@ -161,11 +144,6 @@ public final class BatchReport {
               rootComponentRef_ = input.readInt32();
               break;
             }
-            case 40: {
-              bitField0_ |= 0x00000010;
-              deletedComponentsCount_ = input.readInt32();
-              break;
-            }
           }
         }
       } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -332,35 +310,11 @@ public final class BatchReport {
       return rootComponentRef_;
     }
 
-    public static final int DELETED_COMPONENTS_COUNT_FIELD_NUMBER = 5;
-    private int deletedComponentsCount_;
-    /**
-     * <code>optional int32 deleted_components_count = 5;</code>
-     *
-     * <pre>
-     * temporary fields used during development of computation stack
-     * </pre>
-     */
-    public boolean hasDeletedComponentsCount() {
-      return ((bitField0_ & 0x00000010) == 0x00000010);
-    }
-    /**
-     * <code>optional int32 deleted_components_count = 5;</code>
-     *
-     * <pre>
-     * temporary fields used during development of computation stack
-     * </pre>
-     */
-    public int getDeletedComponentsCount() {
-      return deletedComponentsCount_;
-    }
-
     private void initFields() {
       analysisDate_ = 0L;
       projectKey_ = "";
       branch_ = "";
       rootComponentRef_ = 0;
-      deletedComponentsCount_ = 0;
     }
     private byte memoizedIsInitialized = -1;
     public final boolean isInitialized() {
@@ -387,9 +341,6 @@ public final class BatchReport {
       if (((bitField0_ & 0x00000008) == 0x00000008)) {
         output.writeInt32(4, rootComponentRef_);
       }
-      if (((bitField0_ & 0x00000010) == 0x00000010)) {
-        output.writeInt32(5, deletedComponentsCount_);
-      }
       getUnknownFields().writeTo(output);
     }
 
@@ -415,10 +366,6 @@ public final class BatchReport {
         size += com.google.protobuf.CodedOutputStream
           .computeInt32Size(4, rootComponentRef_);
       }
-      if (((bitField0_ & 0x00000010) == 0x00000010)) {
-        size += com.google.protobuf.CodedOutputStream
-          .computeInt32Size(5, deletedComponentsCount_);
-      }
       size += getUnknownFields().getSerializedSize();
       memoizedSerializedSize = size;
       return size;
@@ -544,8 +491,6 @@ public final class BatchReport {
         bitField0_ = (bitField0_ & ~0x00000004);
         rootComponentRef_ = 0;
         bitField0_ = (bitField0_ & ~0x00000008);
-        deletedComponentsCount_ = 0;
-        bitField0_ = (bitField0_ & ~0x00000010);
         return this;
       }
 
@@ -590,10 +535,6 @@ public final class BatchReport {
           to_bitField0_ |= 0x00000008;
         }
         result.rootComponentRef_ = rootComponentRef_;
-        if (((from_bitField0_ & 0x00000010) == 0x00000010)) {
-          to_bitField0_ |= 0x00000010;
-        }
-        result.deletedComponentsCount_ = deletedComponentsCount_;
         result.bitField0_ = to_bitField0_;
         onBuilt();
         return result;
@@ -626,9 +567,6 @@ public final class BatchReport {
         if (other.hasRootComponentRef()) {
           setRootComponentRef(other.getRootComponentRef());
         }
-        if (other.hasDeletedComponentsCount()) {
-          setDeletedComponentsCount(other.getDeletedComponentsCount());
-        }
         this.mergeUnknownFields(other.getUnknownFields());
         return this;
       }
@@ -896,54 +834,6 @@ public final class BatchReport {
         return this;
       }
 
-      private int deletedComponentsCount_ ;
-      /**
-       * <code>optional int32 deleted_components_count = 5;</code>
-       *
-       * <pre>
-       * temporary fields used during development of computation stack
-       * </pre>
-       */
-      public boolean hasDeletedComponentsCount() {
-        return ((bitField0_ & 0x00000010) == 0x00000010);
-      }
-      /**
-       * <code>optional int32 deleted_components_count = 5;</code>
-       *
-       * <pre>
-       * temporary fields used during development of computation stack
-       * </pre>
-       */
-      public int getDeletedComponentsCount() {
-        return deletedComponentsCount_;
-      }
-      /**
-       * <code>optional int32 deleted_components_count = 5;</code>
-       *
-       * <pre>
-       * temporary fields used during development of computation stack
-       * </pre>
-       */
-      public Builder setDeletedComponentsCount(int value) {
-        bitField0_ |= 0x00000010;
-        deletedComponentsCount_ = value;
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>optional int32 deleted_components_count = 5;</code>
-       *
-       * <pre>
-       * temporary fields used during development of computation stack
-       * </pre>
-       */
-      public Builder clearDeletedComponentsCount() {
-        bitField0_ = (bitField0_ & ~0x00000010);
-        deletedComponentsCount_ = 0;
-        onChanged();
-        return this;
-      }
-
       // @@protoc_insertion_point(builder_scope:Metadata)
     }
 
@@ -6941,241 +6831,43 @@ public final class BatchReport {
 
     /**
      * <code>optional double effort_to_fix = 7;</code>
-     *
-     * <pre>
-     * temporary fields during development of computation stack
-     * </pre>
      */
     boolean hasEffortToFix();
     /**
      * <code>optional double effort_to_fix = 7;</code>
-     *
-     * <pre>
-     * temporary fields during development of computation stack
-     * </pre>
      */
     double getEffortToFix();
 
     /**
-     * <code>optional bool is_new = 8;</code>
-     */
-    boolean hasIsNew();
-    /**
-     * <code>optional bool is_new = 8;</code>
-     */
-    boolean getIsNew();
-
-    /**
-     * <code>optional string uuid = 9;</code>
-     */
-    boolean hasUuid();
-    /**
-     * <code>optional string uuid = 9;</code>
-     */
-    java.lang.String getUuid();
-    /**
-     * <code>optional string uuid = 9;</code>
-     */
-    com.google.protobuf.ByteString
-        getUuidBytes();
-
-    /**
-     * <code>optional int64 debt_in_minutes = 10;</code>
-     */
-    boolean hasDebtInMinutes();
-    /**
-     * <code>optional int64 debt_in_minutes = 10;</code>
-     */
-    long getDebtInMinutes();
-
-    /**
-     * <code>optional string resolution = 11;</code>
-     */
-    boolean hasResolution();
-    /**
-     * <code>optional string resolution = 11;</code>
-     */
-    java.lang.String getResolution();
-    /**
-     * <code>optional string resolution = 11;</code>
-     */
-    com.google.protobuf.ByteString
-        getResolutionBytes();
-
-    /**
-     * <code>optional string status = 12;</code>
-     */
-    boolean hasStatus();
-    /**
-     * <code>optional string status = 12;</code>
-     */
-    java.lang.String getStatus();
-    /**
-     * <code>optional string status = 12;</code>
-     */
-    com.google.protobuf.ByteString
-        getStatusBytes();
-
-    /**
-     * <code>optional string checksum = 13;</code>
-     */
-    boolean hasChecksum();
-    /**
-     * <code>optional string checksum = 13;</code>
-     */
-    java.lang.String getChecksum();
-    /**
-     * <code>optional string checksum = 13;</code>
-     */
-    com.google.protobuf.ByteString
-        getChecksumBytes();
-
-    /**
-     * <code>optional bool manual_severity = 14;</code>
-     */
-    boolean hasManualSeverity();
-    /**
-     * <code>optional bool manual_severity = 14;</code>
-     */
-    boolean getManualSeverity();
-
-    /**
-     * <code>optional string reporter = 15;</code>
-     */
-    boolean hasReporter();
-    /**
-     * <code>optional string reporter = 15;</code>
-     */
-    java.lang.String getReporter();
-    /**
-     * <code>optional string reporter = 15;</code>
-     */
-    com.google.protobuf.ByteString
-        getReporterBytes();
-
-    /**
-     * <code>optional string assignee = 16;</code>
-     */
-    boolean hasAssignee();
-    /**
-     * <code>optional string assignee = 16;</code>
-     */
-    java.lang.String getAssignee();
-    /**
-     * <code>optional string assignee = 16;</code>
-     */
-    com.google.protobuf.ByteString
-        getAssigneeBytes();
-
-    /**
-     * <code>optional string action_plan_key = 17;</code>
-     */
-    boolean hasActionPlanKey();
-    /**
-     * <code>optional string action_plan_key = 17;</code>
-     */
-    java.lang.String getActionPlanKey();
-    /**
-     * <code>optional string action_plan_key = 17;</code>
-     */
-    com.google.protobuf.ByteString
-        getActionPlanKeyBytes();
-
-    /**
-     * <code>optional string attributes = 18;</code>
+     * <code>optional string attributes = 8;</code>
      */
     boolean hasAttributes();
     /**
-     * <code>optional string attributes = 18;</code>
+     * <code>optional string attributes = 8;</code>
      */
     java.lang.String getAttributes();
     /**
-     * <code>optional string attributes = 18;</code>
+     * <code>optional string attributes = 8;</code>
      */
     com.google.protobuf.ByteString
         getAttributesBytes();
 
     /**
-     * <code>optional string author_login = 19;</code>
-     */
-    boolean hasAuthorLogin();
-    /**
-     * <code>optional string author_login = 19;</code>
-     */
-    java.lang.String getAuthorLogin();
-    /**
-     * <code>optional string author_login = 19;</code>
-     */
-    com.google.protobuf.ByteString
-        getAuthorLoginBytes();
-
-    /**
-     * <code>optional int64 creation_date = 20;</code>
-     */
-    boolean hasCreationDate();
-    /**
-     * <code>optional int64 creation_date = 20;</code>
-     */
-    long getCreationDate();
-
-    /**
-     * <code>optional int64 close_date = 21;</code>
-     */
-    boolean hasCloseDate();
-    /**
-     * <code>optional int64 close_date = 21;</code>
-     */
-    long getCloseDate();
-
-    /**
-     * <code>optional int64 update_date = 22;</code>
-     */
-    boolean hasUpdateDate();
-    /**
-     * <code>optional int64 update_date = 22;</code>
-     */
-    long getUpdateDate();
-
-    /**
-     * <code>optional int64 selected_at = 23;</code>
-     */
-    boolean hasSelectedAt();
-    /**
-     * <code>optional int64 selected_at = 23;</code>
-     */
-    long getSelectedAt();
-
-    /**
-     * <code>optional string diff_fields = 24;</code>
-     */
-    boolean hasDiffFields();
-    /**
-     * <code>optional string diff_fields = 24;</code>
-     */
-    java.lang.String getDiffFields();
-    /**
-     * <code>optional string diff_fields = 24;</code>
-     */
-    com.google.protobuf.ByteString
-        getDiffFieldsBytes();
-
-    /**
-     * <code>optional bool is_changed = 25;</code>
-     */
-    boolean hasIsChanged();
-    /**
-     * <code>optional bool is_changed = 25;</code>
-     */
-    boolean getIsChanged();
-
-    /**
-     * <code>optional bool must_send_notification = 26;</code>
+     * <code>optional int64 debt_in_minutes = 9;</code>
+     *
+     * <pre>
+     * TODO should it be moved to compute engine?
+     * </pre>
      */
-    boolean hasMustSendNotification();
+    boolean hasDebtInMinutes();
     /**
-     * <code>optional bool must_send_notification = 26;</code>
+     * <code>optional int64 debt_in_minutes = 9;</code>
+     *
+     * <pre>
+     * TODO should it be moved to compute engine?
+     * </pre>
      */
-    boolean getMustSendNotification();
+    long getDebtInMinutes();
   }
   /**
    * Protobuf type {@code Issue}
@@ -7277,111 +6969,17 @@ public final class BatchReport {
               effortToFix_ = input.readDouble();
               break;
             }
-            case 64: {
+            case 66: {
+              com.google.protobuf.ByteString bs = input.readBytes();
               bitField0_ |= 0x00000040;
-              isNew_ = input.readBool();
+              attributes_ = bs;
               break;
             }
-            case 74: {
-              com.google.protobuf.ByteString bs = input.readBytes();
+            case 72: {
               bitField0_ |= 0x00000080;
-              uuid_ = bs;
-              break;
-            }
-            case 80: {
-              bitField0_ |= 0x00000100;
               debtInMinutes_ = input.readInt64();
               break;
             }
-            case 90: {
-              com.google.protobuf.ByteString bs = input.readBytes();
-              bitField0_ |= 0x00000200;
-              resolution_ = bs;
-              break;
-            }
-            case 98: {
-              com.google.protobuf.ByteString bs = input.readBytes();
-              bitField0_ |= 0x00000400;
-              status_ = bs;
-              break;
-            }
-            case 106: {
-              com.google.protobuf.ByteString bs = input.readBytes();
-              bitField0_ |= 0x00000800;
-              checksum_ = bs;
-              break;
-            }
-            case 112: {
-              bitField0_ |= 0x00001000;
-              manualSeverity_ = input.readBool();
-              break;
-            }
-            case 122: {
-              com.google.protobuf.ByteString bs = input.readBytes();
-              bitField0_ |= 0x00002000;
-              reporter_ = bs;
-              break;
-            }
-            case 130: {
-              com.google.protobuf.ByteString bs = input.readBytes();
-              bitField0_ |= 0x00004000;
-              assignee_ = bs;
-              break;
-            }
-            case 138: {
-              com.google.protobuf.ByteString bs = input.readBytes();
-              bitField0_ |= 0x00008000;
-              actionPlanKey_ = bs;
-              break;
-            }
-            case 146: {
-              com.google.protobuf.ByteString bs = input.readBytes();
-              bitField0_ |= 0x00010000;
-              attributes_ = bs;
-              break;
-            }
-            case 154: {
-              com.google.protobuf.ByteString bs = input.readBytes();
-              bitField0_ |= 0x00020000;
-              authorLogin_ = bs;
-              break;
-            }
-            case 160: {
-              bitField0_ |= 0x00040000;
-              creationDate_ = input.readInt64();
-              break;
-            }
-            case 168: {
-              bitField0_ |= 0x00080000;
-              closeDate_ = input.readInt64();
-              break;
-            }
-            case 176: {
-              bitField0_ |= 0x00100000;
-              updateDate_ = input.readInt64();
-              break;
-            }
-            case 184: {
-              bitField0_ |= 0x00200000;
-              selectedAt_ = input.readInt64();
-              break;
-            }
-            case 194: {
-              com.google.protobuf.ByteString bs = input.readBytes();
-              bitField0_ |= 0x00400000;
-              diffFields_ = bs;
-              break;
-            }
-            case 200: {
-              bitField0_ |= 0x00800000;
-              isChanged_ = input.readBool();
-              break;
-            }
-            case 208: {
-              bitField0_ |= 0x01000000;
-              mustSendNotification_ = input.readBool();
-              break;
-            }
           }
         }
       } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -7614,53 +7212,30 @@ public final class BatchReport {
     private double effortToFix_;
     /**
      * <code>optional double effort_to_fix = 7;</code>
-     *
-     * <pre>
-     * temporary fields during development of computation stack
-     * </pre>
      */
     public boolean hasEffortToFix() {
       return ((bitField0_ & 0x00000020) == 0x00000020);
     }
     /**
      * <code>optional double effort_to_fix = 7;</code>
-     *
-     * <pre>
-     * temporary fields during development of computation stack
-     * </pre>
      */
     public double getEffortToFix() {
       return effortToFix_;
     }
 
-    public static final int IS_NEW_FIELD_NUMBER = 8;
-    private boolean isNew_;
+    public static final int ATTRIBUTES_FIELD_NUMBER = 8;
+    private java.lang.Object attributes_;
     /**
-     * <code>optional bool is_new = 8;</code>
+     * <code>optional string attributes = 8;</code>
      */
-    public boolean hasIsNew() {
+    public boolean hasAttributes() {
       return ((bitField0_ & 0x00000040) == 0x00000040);
     }
     /**
-     * <code>optional bool is_new = 8;</code>
-     */
-    public boolean getIsNew() {
-      return isNew_;
-    }
-
-    public static final int UUID_FIELD_NUMBER = 9;
-    private java.lang.Object uuid_;
-    /**
-     * <code>optional string uuid = 9;</code>
-     */
-    public boolean hasUuid() {
-      return ((bitField0_ & 0x00000080) == 0x00000080);
-    }
-    /**
-     * <code>optional string uuid = 9;</code>
+     * <code>optional string attributes = 8;</code>
      */
-    public java.lang.String getUuid() {
-      java.lang.Object ref = uuid_;
+    public java.lang.String getAttributes() {
+      java.lang.Object ref = attributes_;
       if (ref instanceof java.lang.String) {
         return (java.lang.String) ref;
       } else {
@@ -7668,2073 +7243,455 @@ public final class BatchReport {
             (com.google.protobuf.ByteString) ref;
         java.lang.String s = bs.toStringUtf8();
         if (bs.isValidUtf8()) {
-          uuid_ = s;
+          attributes_ = s;
         }
         return s;
       }
     }
     /**
-     * <code>optional string uuid = 9;</code>
+     * <code>optional string attributes = 8;</code>
      */
     public com.google.protobuf.ByteString
-        getUuidBytes() {
-      java.lang.Object ref = uuid_;
+        getAttributesBytes() {
+      java.lang.Object ref = attributes_;
       if (ref instanceof java.lang.String) {
         com.google.protobuf.ByteString b = 
             com.google.protobuf.ByteString.copyFromUtf8(
                 (java.lang.String) ref);
-        uuid_ = b;
+        attributes_ = b;
         return b;
       } else {
         return (com.google.protobuf.ByteString) ref;
       }
     }
 
-    public static final int DEBT_IN_MINUTES_FIELD_NUMBER = 10;
+    public static final int DEBT_IN_MINUTES_FIELD_NUMBER = 9;
     private long debtInMinutes_;
     /**
-     * <code>optional int64 debt_in_minutes = 10;</code>
+     * <code>optional int64 debt_in_minutes = 9;</code>
+     *
+     * <pre>
+     * TODO should it be moved to compute engine?
+     * </pre>
      */
     public boolean hasDebtInMinutes() {
-      return ((bitField0_ & 0x00000100) == 0x00000100);
+      return ((bitField0_ & 0x00000080) == 0x00000080);
     }
     /**
-     * <code>optional int64 debt_in_minutes = 10;</code>
+     * <code>optional int64 debt_in_minutes = 9;</code>
+     *
+     * <pre>
+     * TODO should it be moved to compute engine?
+     * </pre>
      */
     public long getDebtInMinutes() {
       return debtInMinutes_;
     }
 
-    public static final int RESOLUTION_FIELD_NUMBER = 11;
-    private java.lang.Object resolution_;
-    /**
-     * <code>optional string resolution = 11;</code>
-     */
-    public boolean hasResolution() {
-      return ((bitField0_ & 0x00000200) == 0x00000200);
-    }
-    /**
-     * <code>optional string resolution = 11;</code>
-     */
-    public java.lang.String getResolution() {
-      java.lang.Object ref = resolution_;
-      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()) {
-          resolution_ = s;
-        }
-        return s;
-      }
-    }
-    /**
-     * <code>optional string resolution = 11;</code>
-     */
-    public com.google.protobuf.ByteString
-        getResolutionBytes() {
-      java.lang.Object ref = resolution_;
-      if (ref instanceof java.lang.String) {
-        com.google.protobuf.ByteString b = 
-            com.google.protobuf.ByteString.copyFromUtf8(
-                (java.lang.String) ref);
-        resolution_ = b;
-        return b;
-      } else {
-        return (com.google.protobuf.ByteString) ref;
-      }
+    private void initFields() {
+      ruleRepository_ = "";
+      ruleKey_ = "";
+      line_ = 0;
+      msg_ = "";
+      severity_ = org.sonar.batch.protocol.Constants.Severity.INFO;
+      tag_ = com.google.protobuf.LazyStringArrayList.EMPTY;
+      effortToFix_ = 0D;
+      attributes_ = "";
+      debtInMinutes_ = 0L;
     }
+    private byte memoizedIsInitialized = -1;
+    public final boolean isInitialized() {
+      byte isInitialized = memoizedIsInitialized;
+      if (isInitialized == 1) return true;
+      if (isInitialized == 0) return false;
 
-    public static final int STATUS_FIELD_NUMBER = 12;
-    private java.lang.Object status_;
-    /**
-     * <code>optional string status = 12;</code>
-     */
-    public boolean hasStatus() {
-      return ((bitField0_ & 0x00000400) == 0x00000400);
+      memoizedIsInitialized = 1;
+      return true;
     }
-    /**
-     * <code>optional string status = 12;</code>
-     */
-    public java.lang.String getStatus() {
-      java.lang.Object ref = status_;
-      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()) {
-          status_ = s;
-        }
-        return s;
+
+    public void writeTo(com.google.protobuf.CodedOutputStream output)
+                        throws java.io.IOException {
+      getSerializedSize();
+      if (((bitField0_ & 0x00000001) == 0x00000001)) {
+        output.writeBytes(1, getRuleRepositoryBytes());
       }
-    }
-    /**
-     * <code>optional string status = 12;</code>
-     */
-    public com.google.protobuf.ByteString
-        getStatusBytes() {
-      java.lang.Object ref = status_;
-      if (ref instanceof java.lang.String) {
-        com.google.protobuf.ByteString b = 
-            com.google.protobuf.ByteString.copyFromUtf8(
-                (java.lang.String) ref);
-        status_ = b;
-        return b;
-      } else {
-        return (com.google.protobuf.ByteString) ref;
+      if (((bitField0_ & 0x00000002) == 0x00000002)) {
+        output.writeBytes(2, getRuleKeyBytes());
       }
-    }
-
-    public static final int CHECKSUM_FIELD_NUMBER = 13;
-    private java.lang.Object checksum_;
-    /**
-     * <code>optional string checksum = 13;</code>
-     */
-    public boolean hasChecksum() {
-      return ((bitField0_ & 0x00000800) == 0x00000800);
-    }
-    /**
-     * <code>optional string checksum = 13;</code>
-     */
-    public java.lang.String getChecksum() {
-      java.lang.Object ref = checksum_;
-      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()) {
-          checksum_ = s;
-        }
-        return s;
+      if (((bitField0_ & 0x00000004) == 0x00000004)) {
+        output.writeInt32(3, line_);
       }
-    }
-    /**
-     * <code>optional string checksum = 13;</code>
-     */
-    public com.google.protobuf.ByteString
-        getChecksumBytes() {
-      java.lang.Object ref = checksum_;
-      if (ref instanceof java.lang.String) {
-        com.google.protobuf.ByteString b = 
-            com.google.protobuf.ByteString.copyFromUtf8(
-                (java.lang.String) ref);
-        checksum_ = b;
-        return b;
-      } else {
-        return (com.google.protobuf.ByteString) ref;
+      if (((bitField0_ & 0x00000008) == 0x00000008)) {
+        output.writeBytes(4, getMsgBytes());
+      }
+      if (((bitField0_ & 0x00000010) == 0x00000010)) {
+        output.writeEnum(5, severity_.getNumber());
+      }
+      for (int i = 0; i < tag_.size(); i++) {
+        output.writeBytes(6, tag_.getByteString(i));
+      }
+      if (((bitField0_ & 0x00000020) == 0x00000020)) {
+        output.writeDouble(7, effortToFix_);
       }
+      if (((bitField0_ & 0x00000040) == 0x00000040)) {
+        output.writeBytes(8, getAttributesBytes());
+      }
+      if (((bitField0_ & 0x00000080) == 0x00000080)) {
+        output.writeInt64(9, debtInMinutes_);
+      }
+      getUnknownFields().writeTo(output);
     }
 
-    public static final int MANUAL_SEVERITY_FIELD_NUMBER = 14;
-    private boolean manualSeverity_;
-    /**
-     * <code>optional bool manual_severity = 14;</code>
-     */
-    public boolean hasManualSeverity() {
-      return ((bitField0_ & 0x00001000) == 0x00001000);
-    }
-    /**
-     * <code>optional bool manual_severity = 14;</code>
-     */
-    public boolean getManualSeverity() {
-      return manualSeverity_;
-    }
+    private int memoizedSerializedSize = -1;
+    public int getSerializedSize() {
+      int size = memoizedSerializedSize;
+      if (size != -1) return size;
 
-    public static final int REPORTER_FIELD_NUMBER = 15;
-    private java.lang.Object reporter_;
-    /**
-     * <code>optional string reporter = 15;</code>
-     */
-    public boolean hasReporter() {
-      return ((bitField0_ & 0x00002000) == 0x00002000);
-    }
-    /**
-     * <code>optional string reporter = 15;</code>
-     */
-    public java.lang.String getReporter() {
-      java.lang.Object ref = reporter_;
-      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()) {
-          reporter_ = s;
+      size = 0;
+      if (((bitField0_ & 0x00000001) == 0x00000001)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(1, getRuleRepositoryBytes());
+      }
+      if (((bitField0_ & 0x00000002) == 0x00000002)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(2, getRuleKeyBytes());
+      }
+      if (((bitField0_ & 0x00000004) == 0x00000004)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeInt32Size(3, line_);
+      }
+      if (((bitField0_ & 0x00000008) == 0x00000008)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(4, getMsgBytes());
+      }
+      if (((bitField0_ & 0x00000010) == 0x00000010)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeEnumSize(5, severity_.getNumber());
+      }
+      {
+        int dataSize = 0;
+        for (int i = 0; i < tag_.size(); i++) {
+          dataSize += com.google.protobuf.CodedOutputStream
+            .computeBytesSizeNoTag(tag_.getByteString(i));
         }
-        return s;
+        size += dataSize;
+        size += 1 * getTagList().size();
       }
-    }
-    /**
-     * <code>optional string reporter = 15;</code>
-     */
-    public com.google.protobuf.ByteString
-        getReporterBytes() {
-      java.lang.Object ref = reporter_;
-      if (ref instanceof java.lang.String) {
-        com.google.protobuf.ByteString b = 
-            com.google.protobuf.ByteString.copyFromUtf8(
-                (java.lang.String) ref);
-        reporter_ = b;
-        return b;
-      } else {
-        return (com.google.protobuf.ByteString) ref;
+      if (((bitField0_ & 0x00000020) == 0x00000020)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeDoubleSize(7, effortToFix_);
       }
+      if (((bitField0_ & 0x00000040) == 0x00000040)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(8, getAttributesBytes());
+      }
+      if (((bitField0_ & 0x00000080) == 0x00000080)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeInt64Size(9, debtInMinutes_);
+      }
+      size += getUnknownFields().getSerializedSize();
+      memoizedSerializedSize = size;
+      return size;
     }
 
-    public static final int ASSIGNEE_FIELD_NUMBER = 16;
-    private java.lang.Object assignee_;
-    /**
-     * <code>optional string assignee = 16;</code>
-     */
-    public boolean hasAssignee() {
-      return ((bitField0_ & 0x00004000) == 0x00004000);
-    }
-    /**
-     * <code>optional string assignee = 16;</code>
-     */
-    public java.lang.String getAssignee() {
-      java.lang.Object ref = assignee_;
-      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()) {
-          assignee_ = s;
-        }
-        return s;
-      }
-    }
-    /**
-     * <code>optional string assignee = 16;</code>
-     */
-    public com.google.protobuf.ByteString
-        getAssigneeBytes() {
-      java.lang.Object ref = assignee_;
-      if (ref instanceof java.lang.String) {
-        com.google.protobuf.ByteString b = 
-            com.google.protobuf.ByteString.copyFromUtf8(
-                (java.lang.String) ref);
-        assignee_ = b;
-        return b;
-      } else {
-        return (com.google.protobuf.ByteString) ref;
-      }
+    private static final long serialVersionUID = 0L;
+    @java.lang.Override
+    protected java.lang.Object writeReplace()
+        throws java.io.ObjectStreamException {
+      return super.writeReplace();
     }
 
-    public static final int ACTION_PLAN_KEY_FIELD_NUMBER = 17;
-    private java.lang.Object actionPlanKey_;
-    /**
-     * <code>optional string action_plan_key = 17;</code>
-     */
-    public boolean hasActionPlanKey() {
-      return ((bitField0_ & 0x00008000) == 0x00008000);
-    }
-    /**
-     * <code>optional string action_plan_key = 17;</code>
-     */
-    public java.lang.String getActionPlanKey() {
-      java.lang.Object ref = actionPlanKey_;
-      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()) {
-          actionPlanKey_ = s;
-        }
-        return s;
-      }
+    public static org.sonar.batch.protocol.output.BatchReport.Issue parseFrom(
+        com.google.protobuf.ByteString data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
     }
-    /**
-     * <code>optional string action_plan_key = 17;</code>
-     */
-    public com.google.protobuf.ByteString
-        getActionPlanKeyBytes() {
-      java.lang.Object ref = actionPlanKey_;
-      if (ref instanceof java.lang.String) {
-        com.google.protobuf.ByteString b = 
-            com.google.protobuf.ByteString.copyFromUtf8(
-                (java.lang.String) ref);
-        actionPlanKey_ = b;
-        return b;
-      } else {
-        return (com.google.protobuf.ByteString) ref;
-      }
+    public static org.sonar.batch.protocol.output.BatchReport.Issue parseFrom(
+        com.google.protobuf.ByteString data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
     }
-
-    public static final int ATTRIBUTES_FIELD_NUMBER = 18;
-    private java.lang.Object attributes_;
-    /**
-     * <code>optional string attributes = 18;</code>
-     */
-    public boolean hasAttributes() {
-      return ((bitField0_ & 0x00010000) == 0x00010000);
+    public static org.sonar.batch.protocol.output.BatchReport.Issue parseFrom(byte[] data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
     }
-    /**
-     * <code>optional string attributes = 18;</code>
-     */
-    public java.lang.String getAttributes() {
-      java.lang.Object ref = attributes_;
-      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()) {
-          attributes_ = s;
-        }
-        return s;
-      }
+    public static org.sonar.batch.protocol.output.BatchReport.Issue parseFrom(
+        byte[] data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
     }
-    /**
-     * <code>optional string attributes = 18;</code>
-     */
-    public com.google.protobuf.ByteString
-        getAttributesBytes() {
-      java.lang.Object ref = attributes_;
-      if (ref instanceof java.lang.String) {
-        com.google.protobuf.ByteString b = 
-            com.google.protobuf.ByteString.copyFromUtf8(
-                (java.lang.String) ref);
-        attributes_ = b;
-        return b;
-      } else {
-        return (com.google.protobuf.ByteString) ref;
-      }
+    public static org.sonar.batch.protocol.output.BatchReport.Issue parseFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input);
     }
-
-    public static final int AUTHOR_LOGIN_FIELD_NUMBER = 19;
-    private java.lang.Object authorLogin_;
-    /**
-     * <code>optional string author_login = 19;</code>
-     */
-    public boolean hasAuthorLogin() {
-      return ((bitField0_ & 0x00020000) == 0x00020000);
+    public static org.sonar.batch.protocol.output.BatchReport.Issue parseFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input, extensionRegistry);
     }
-    /**
-     * <code>optional string author_login = 19;</code>
-     */
-    public java.lang.String getAuthorLogin() {
-      java.lang.Object ref = authorLogin_;
-      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()) {
-          authorLogin_ = s;
-        }
-        return s;
-      }
+    public static org.sonar.batch.protocol.output.BatchReport.Issue parseDelimitedFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return PARSER.parseDelimitedFrom(input);
     }
-    /**
-     * <code>optional string author_login = 19;</code>
-     */
-    public com.google.protobuf.ByteString
-        getAuthorLoginBytes() {
-      java.lang.Object ref = authorLogin_;
-      if (ref instanceof java.lang.String) {
-        com.google.protobuf.ByteString b = 
-            com.google.protobuf.ByteString.copyFromUtf8(
-                (java.lang.String) ref);
-        authorLogin_ = b;
-        return b;
-      } else {
-        return (com.google.protobuf.ByteString) ref;
-      }
+    public static org.sonar.batch.protocol.output.BatchReport.Issue parseDelimitedFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseDelimitedFrom(input, extensionRegistry);
     }
-
-    public static final int CREATION_DATE_FIELD_NUMBER = 20;
-    private long creationDate_;
-    /**
-     * <code>optional int64 creation_date = 20;</code>
-     */
-    public boolean hasCreationDate() {
-      return ((bitField0_ & 0x00040000) == 0x00040000);
+    public static org.sonar.batch.protocol.output.BatchReport.Issue parseFrom(
+        com.google.protobuf.CodedInputStream input)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input);
     }
-    /**
-     * <code>optional int64 creation_date = 20;</code>
-     */
-    public long getCreationDate() {
-      return creationDate_;
+    public static org.sonar.batch.protocol.output.BatchReport.Issue parseFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input, extensionRegistry);
     }
 
-    public static final int CLOSE_DATE_FIELD_NUMBER = 21;
-    private long closeDate_;
-    /**
-     * <code>optional int64 close_date = 21;</code>
-     */
-    public boolean hasCloseDate() {
-      return ((bitField0_ & 0x00080000) == 0x00080000);
-    }
-    /**
-     * <code>optional int64 close_date = 21;</code>
-     */
-    public long getCloseDate() {
-      return closeDate_;
+    public static Builder newBuilder() { return Builder.create(); }
+    public Builder newBuilderForType() { return newBuilder(); }
+    public static Builder newBuilder(org.sonar.batch.protocol.output.BatchReport.Issue prototype) {
+      return newBuilder().mergeFrom(prototype);
     }
+    public Builder toBuilder() { return newBuilder(this); }
 
-    public static final int UPDATE_DATE_FIELD_NUMBER = 22;
-    private long updateDate_;
-    /**
-     * <code>optional int64 update_date = 22;</code>
-     */
-    public boolean hasUpdateDate() {
-      return ((bitField0_ & 0x00100000) == 0x00100000);
+    @java.lang.Override
+    protected Builder newBuilderForType(
+        com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+      Builder builder = new Builder(parent);
+      return builder;
     }
     /**
-     * <code>optional int64 update_date = 22;</code>
+     * Protobuf type {@code Issue}
      */
-    public long getUpdateDate() {
-      return updateDate_;
-    }
+    public static final class Builder extends
+        com.google.protobuf.GeneratedMessage.Builder<Builder> implements
+        // @@protoc_insertion_point(builder_implements:Issue)
+        org.sonar.batch.protocol.output.BatchReport.IssueOrBuilder {
+      public static final com.google.protobuf.Descriptors.Descriptor
+          getDescriptor() {
+        return org.sonar.batch.protocol.output.BatchReport.internal_static_Issue_descriptor;
+      }
 
-    public static final int SELECTED_AT_FIELD_NUMBER = 23;
-    private long selectedAt_;
-    /**
-     * <code>optional int64 selected_at = 23;</code>
-     */
-    public boolean hasSelectedAt() {
-      return ((bitField0_ & 0x00200000) == 0x00200000);
-    }
-    /**
-     * <code>optional int64 selected_at = 23;</code>
-     */
-    public long getSelectedAt() {
-      return selectedAt_;
-    }
+      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+          internalGetFieldAccessorTable() {
+        return org.sonar.batch.protocol.output.BatchReport.internal_static_Issue_fieldAccessorTable
+            .ensureFieldAccessorsInitialized(
+                org.sonar.batch.protocol.output.BatchReport.Issue.class, org.sonar.batch.protocol.output.BatchReport.Issue.Builder.class);
+      }
 
-    public static final int DIFF_FIELDS_FIELD_NUMBER = 24;
-    private java.lang.Object diffFields_;
-    /**
-     * <code>optional string diff_fields = 24;</code>
-     */
-    public boolean hasDiffFields() {
-      return ((bitField0_ & 0x00400000) == 0x00400000);
-    }
-    /**
-     * <code>optional string diff_fields = 24;</code>
-     */
-    public java.lang.String getDiffFields() {
-      java.lang.Object ref = diffFields_;
-      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()) {
-          diffFields_ = s;
+      // Construct using org.sonar.batch.protocol.output.BatchReport.Issue.newBuilder()
+      private Builder() {
+        maybeForceBuilderInitialization();
+      }
+
+      private Builder(
+          com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+        super(parent);
+        maybeForceBuilderInitialization();
+      }
+      private void maybeForceBuilderInitialization() {
+        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
         }
-        return s;
       }
-    }
-    /**
-     * <code>optional string diff_fields = 24;</code>
-     */
-    public com.google.protobuf.ByteString
-        getDiffFieldsBytes() {
-      java.lang.Object ref = diffFields_;
-      if (ref instanceof java.lang.String) {
-        com.google.protobuf.ByteString b = 
-            com.google.protobuf.ByteString.copyFromUtf8(
-                (java.lang.String) ref);
-        diffFields_ = b;
-        return b;
-      } else {
-        return (com.google.protobuf.ByteString) ref;
+      private static Builder create() {
+        return new Builder();
       }
-    }
-
-    public static final int IS_CHANGED_FIELD_NUMBER = 25;
-    private boolean isChanged_;
-    /**
-     * <code>optional bool is_changed = 25;</code>
-     */
-    public boolean hasIsChanged() {
-      return ((bitField0_ & 0x00800000) == 0x00800000);
-    }
-    /**
-     * <code>optional bool is_changed = 25;</code>
-     */
-    public boolean getIsChanged() {
-      return isChanged_;
-    }
-
-    public static final int MUST_SEND_NOTIFICATION_FIELD_NUMBER = 26;
-    private boolean mustSendNotification_;
-    /**
-     * <code>optional bool must_send_notification = 26;</code>
-     */
-    public boolean hasMustSendNotification() {
-      return ((bitField0_ & 0x01000000) == 0x01000000);
-    }
-    /**
-     * <code>optional bool must_send_notification = 26;</code>
-     */
-    public boolean getMustSendNotification() {
-      return mustSendNotification_;
-    }
 
-    private void initFields() {
-      ruleRepository_ = "";
-      ruleKey_ = "";
-      line_ = 0;
-      msg_ = "";
-      severity_ = org.sonar.batch.protocol.Constants.Severity.INFO;
-      tag_ = com.google.protobuf.LazyStringArrayList.EMPTY;
-      effortToFix_ = 0D;
-      isNew_ = false;
-      uuid_ = "";
-      debtInMinutes_ = 0L;
-      resolution_ = "";
-      status_ = "";
-      checksum_ = "";
-      manualSeverity_ = false;
-      reporter_ = "";
-      assignee_ = "";
-      actionPlanKey_ = "";
-      attributes_ = "";
-      authorLogin_ = "";
-      creationDate_ = 0L;
-      closeDate_ = 0L;
-      updateDate_ = 0L;
-      selectedAt_ = 0L;
-      diffFields_ = "";
-      isChanged_ = false;
-      mustSendNotification_ = false;
-    }
-    private byte memoizedIsInitialized = -1;
-    public final boolean isInitialized() {
-      byte isInitialized = memoizedIsInitialized;
-      if (isInitialized == 1) return true;
-      if (isInitialized == 0) return false;
-
-      memoizedIsInitialized = 1;
-      return true;
-    }
-
-    public void writeTo(com.google.protobuf.CodedOutputStream output)
-                        throws java.io.IOException {
-      getSerializedSize();
-      if (((bitField0_ & 0x00000001) == 0x00000001)) {
-        output.writeBytes(1, getRuleRepositoryBytes());
-      }
-      if (((bitField0_ & 0x00000002) == 0x00000002)) {
-        output.writeBytes(2, getRuleKeyBytes());
-      }
-      if (((bitField0_ & 0x00000004) == 0x00000004)) {
-        output.writeInt32(3, line_);
-      }
-      if (((bitField0_ & 0x00000008) == 0x00000008)) {
-        output.writeBytes(4, getMsgBytes());
-      }
-      if (((bitField0_ & 0x00000010) == 0x00000010)) {
-        output.writeEnum(5, severity_.getNumber());
-      }
-      for (int i = 0; i < tag_.size(); i++) {
-        output.writeBytes(6, tag_.getByteString(i));
-      }
-      if (((bitField0_ & 0x00000020) == 0x00000020)) {
-        output.writeDouble(7, effortToFix_);
-      }
-      if (((bitField0_ & 0x00000040) == 0x00000040)) {
-        output.writeBool(8, isNew_);
-      }
-      if (((bitField0_ & 0x00000080) == 0x00000080)) {
-        output.writeBytes(9, getUuidBytes());
-      }
-      if (((bitField0_ & 0x00000100) == 0x00000100)) {
-        output.writeInt64(10, debtInMinutes_);
-      }
-      if (((bitField0_ & 0x00000200) == 0x00000200)) {
-        output.writeBytes(11, getResolutionBytes());
-      }
-      if (((bitField0_ & 0x00000400) == 0x00000400)) {
-        output.writeBytes(12, getStatusBytes());
-      }
-      if (((bitField0_ & 0x00000800) == 0x00000800)) {
-        output.writeBytes(13, getChecksumBytes());
-      }
-      if (((bitField0_ & 0x00001000) == 0x00001000)) {
-        output.writeBool(14, manualSeverity_);
-      }
-      if (((bitField0_ & 0x00002000) == 0x00002000)) {
-        output.writeBytes(15, getReporterBytes());
-      }
-      if (((bitField0_ & 0x00004000) == 0x00004000)) {
-        output.writeBytes(16, getAssigneeBytes());
-      }
-      if (((bitField0_ & 0x00008000) == 0x00008000)) {
-        output.writeBytes(17, getActionPlanKeyBytes());
-      }
-      if (((bitField0_ & 0x00010000) == 0x00010000)) {
-        output.writeBytes(18, getAttributesBytes());
-      }
-      if (((bitField0_ & 0x00020000) == 0x00020000)) {
-        output.writeBytes(19, getAuthorLoginBytes());
-      }
-      if (((bitField0_ & 0x00040000) == 0x00040000)) {
-        output.writeInt64(20, creationDate_);
-      }
-      if (((bitField0_ & 0x00080000) == 0x00080000)) {
-        output.writeInt64(21, closeDate_);
-      }
-      if (((bitField0_ & 0x00100000) == 0x00100000)) {
-        output.writeInt64(22, updateDate_);
-      }
-      if (((bitField0_ & 0x00200000) == 0x00200000)) {
-        output.writeInt64(23, selectedAt_);
-      }
-      if (((bitField0_ & 0x00400000) == 0x00400000)) {
-        output.writeBytes(24, getDiffFieldsBytes());
-      }
-      if (((bitField0_ & 0x00800000) == 0x00800000)) {
-        output.writeBool(25, isChanged_);
-      }
-      if (((bitField0_ & 0x01000000) == 0x01000000)) {
-        output.writeBool(26, mustSendNotification_);
-      }
-      getUnknownFields().writeTo(output);
-    }
-
-    private int memoizedSerializedSize = -1;
-    public int getSerializedSize() {
-      int size = memoizedSerializedSize;
-      if (size != -1) return size;
-
-      size = 0;
-      if (((bitField0_ & 0x00000001) == 0x00000001)) {
-        size += com.google.protobuf.CodedOutputStream
-          .computeBytesSize(1, getRuleRepositoryBytes());
-      }
-      if (((bitField0_ & 0x00000002) == 0x00000002)) {
-        size += com.google.protobuf.CodedOutputStream
-          .computeBytesSize(2, getRuleKeyBytes());
-      }
-      if (((bitField0_ & 0x00000004) == 0x00000004)) {
-        size += com.google.protobuf.CodedOutputStream
-          .computeInt32Size(3, line_);
-      }
-      if (((bitField0_ & 0x00000008) == 0x00000008)) {
-        size += com.google.protobuf.CodedOutputStream
-          .computeBytesSize(4, getMsgBytes());
-      }
-      if (((bitField0_ & 0x00000010) == 0x00000010)) {
-        size += com.google.protobuf.CodedOutputStream
-          .computeEnumSize(5, severity_.getNumber());
-      }
-      {
-        int dataSize = 0;
-        for (int i = 0; i < tag_.size(); i++) {
-          dataSize += com.google.protobuf.CodedOutputStream
-            .computeBytesSizeNoTag(tag_.getByteString(i));
-        }
-        size += dataSize;
-        size += 1 * getTagList().size();
-      }
-      if (((bitField0_ & 0x00000020) == 0x00000020)) {
-        size += com.google.protobuf.CodedOutputStream
-          .computeDoubleSize(7, effortToFix_);
-      }
-      if (((bitField0_ & 0x00000040) == 0x00000040)) {
-        size += com.google.protobuf.CodedOutputStream
-          .computeBoolSize(8, isNew_);
-      }
-      if (((bitField0_ & 0x00000080) == 0x00000080)) {
-        size += com.google.protobuf.CodedOutputStream
-          .computeBytesSize(9, getUuidBytes());
-      }
-      if (((bitField0_ & 0x00000100) == 0x00000100)) {
-        size += com.google.protobuf.CodedOutputStream
-          .computeInt64Size(10, debtInMinutes_);
-      }
-      if (((bitField0_ & 0x00000200) == 0x00000200)) {
-        size += com.google.protobuf.CodedOutputStream
-          .computeBytesSize(11, getResolutionBytes());
-      }
-      if (((bitField0_ & 0x00000400) == 0x00000400)) {
-        size += com.google.protobuf.CodedOutputStream
-          .computeBytesSize(12, getStatusBytes());
-      }
-      if (((bitField0_ & 0x00000800) == 0x00000800)) {
-        size += com.google.protobuf.CodedOutputStream
-          .computeBytesSize(13, getChecksumBytes());
-      }
-      if (((bitField0_ & 0x00001000) == 0x00001000)) {
-        size += com.google.protobuf.CodedOutputStream
-          .computeBoolSize(14, manualSeverity_);
-      }
-      if (((bitField0_ & 0x00002000) == 0x00002000)) {
-        size += com.google.protobuf.CodedOutputStream
-          .computeBytesSize(15, getReporterBytes());
-      }
-      if (((bitField0_ & 0x00004000) == 0x00004000)) {
-        size += com.google.protobuf.CodedOutputStream
-          .computeBytesSize(16, getAssigneeBytes());
-      }
-      if (((bitField0_ & 0x00008000) == 0x00008000)) {
-        size += com.google.protobuf.CodedOutputStream
-          .computeBytesSize(17, getActionPlanKeyBytes());
-      }
-      if (((bitField0_ & 0x00010000) == 0x00010000)) {
-        size += com.google.protobuf.CodedOutputStream
-          .computeBytesSize(18, getAttributesBytes());
-      }
-      if (((bitField0_ & 0x00020000) == 0x00020000)) {
-        size += com.google.protobuf.CodedOutputStream
-          .computeBytesSize(19, getAuthorLoginBytes());
-      }
-      if (((bitField0_ & 0x00040000) == 0x00040000)) {
-        size += com.google.protobuf.CodedOutputStream
-          .computeInt64Size(20, creationDate_);
-      }
-      if (((bitField0_ & 0x00080000) == 0x00080000)) {
-        size += com.google.protobuf.CodedOutputStream
-          .computeInt64Size(21, closeDate_);
-      }
-      if (((bitField0_ & 0x00100000) == 0x00100000)) {
-        size += com.google.protobuf.CodedOutputStream
-          .computeInt64Size(22, updateDate_);
-      }
-      if (((bitField0_ & 0x00200000) == 0x00200000)) {
-        size += com.google.protobuf.CodedOutputStream
-          .computeInt64Size(23, selectedAt_);
-      }
-      if (((bitField0_ & 0x00400000) == 0x00400000)) {
-        size += com.google.protobuf.CodedOutputStream
-          .computeBytesSize(24, getDiffFieldsBytes());
-      }
-      if (((bitField0_ & 0x00800000) == 0x00800000)) {
-        size += com.google.protobuf.CodedOutputStream
-          .computeBoolSize(25, isChanged_);
-      }
-      if (((bitField0_ & 0x01000000) == 0x01000000)) {
-        size += com.google.protobuf.CodedOutputStream
-          .computeBoolSize(26, mustSendNotification_);
-      }
-      size += getUnknownFields().getSerializedSize();
-      memoizedSerializedSize = size;
-      return size;
-    }
-
-    private static final long serialVersionUID = 0L;
-    @java.lang.Override
-    protected java.lang.Object writeReplace()
-        throws java.io.ObjectStreamException {
-      return super.writeReplace();
-    }
-
-    public static org.sonar.batch.protocol.output.BatchReport.Issue parseFrom(
-        com.google.protobuf.ByteString data)
-        throws com.google.protobuf.InvalidProtocolBufferException {
-      return PARSER.parseFrom(data);
-    }
-    public static org.sonar.batch.protocol.output.BatchReport.Issue parseFrom(
-        com.google.protobuf.ByteString data,
-        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
-        throws com.google.protobuf.InvalidProtocolBufferException {
-      return PARSER.parseFrom(data, extensionRegistry);
-    }
-    public static org.sonar.batch.protocol.output.BatchReport.Issue parseFrom(byte[] data)
-        throws com.google.protobuf.InvalidProtocolBufferException {
-      return PARSER.parseFrom(data);
-    }
-    public static org.sonar.batch.protocol.output.BatchReport.Issue parseFrom(
-        byte[] data,
-        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
-        throws com.google.protobuf.InvalidProtocolBufferException {
-      return PARSER.parseFrom(data, extensionRegistry);
-    }
-    public static org.sonar.batch.protocol.output.BatchReport.Issue parseFrom(java.io.InputStream input)
-        throws java.io.IOException {
-      return PARSER.parseFrom(input);
-    }
-    public static org.sonar.batch.protocol.output.BatchReport.Issue parseFrom(
-        java.io.InputStream input,
-        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
-        throws java.io.IOException {
-      return PARSER.parseFrom(input, extensionRegistry);
-    }
-    public static org.sonar.batch.protocol.output.BatchReport.Issue parseDelimitedFrom(java.io.InputStream input)
-        throws java.io.IOException {
-      return PARSER.parseDelimitedFrom(input);
-    }
-    public static org.sonar.batch.protocol.output.BatchReport.Issue parseDelimitedFrom(
-        java.io.InputStream input,
-        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
-        throws java.io.IOException {
-      return PARSER.parseDelimitedFrom(input, extensionRegistry);
-    }
-    public static org.sonar.batch.protocol.output.BatchReport.Issue parseFrom(
-        com.google.protobuf.CodedInputStream input)
-        throws java.io.IOException {
-      return PARSER.parseFrom(input);
-    }
-    public static org.sonar.batch.protocol.output.BatchReport.Issue parseFrom(
-        com.google.protobuf.CodedInputStream input,
-        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
-        throws java.io.IOException {
-      return PARSER.parseFrom(input, extensionRegistry);
-    }
-
-    public static Builder newBuilder() { return Builder.create(); }
-    public Builder newBuilderForType() { return newBuilder(); }
-    public static Builder newBuilder(org.sonar.batch.protocol.output.BatchReport.Issue prototype) {
-      return newBuilder().mergeFrom(prototype);
-    }
-    public Builder toBuilder() { return newBuilder(this); }
-
-    @java.lang.Override
-    protected Builder newBuilderForType(
-        com.google.protobuf.GeneratedMessage.BuilderParent parent) {
-      Builder builder = new Builder(parent);
-      return builder;
-    }
-    /**
-     * Protobuf type {@code Issue}
-     */
-    public static final class Builder extends
-        com.google.protobuf.GeneratedMessage.Builder<Builder> implements
-        // @@protoc_insertion_point(builder_implements:Issue)
-        org.sonar.batch.protocol.output.BatchReport.IssueOrBuilder {
-      public static final com.google.protobuf.Descriptors.Descriptor
-          getDescriptor() {
-        return org.sonar.batch.protocol.output.BatchReport.internal_static_Issue_descriptor;
-      }
-
-      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
-          internalGetFieldAccessorTable() {
-        return org.sonar.batch.protocol.output.BatchReport.internal_static_Issue_fieldAccessorTable
-            .ensureFieldAccessorsInitialized(
-                org.sonar.batch.protocol.output.BatchReport.Issue.class, org.sonar.batch.protocol.output.BatchReport.Issue.Builder.class);
-      }
-
-      // Construct using org.sonar.batch.protocol.output.BatchReport.Issue.newBuilder()
-      private Builder() {
-        maybeForceBuilderInitialization();
-      }
-
-      private Builder(
-          com.google.protobuf.GeneratedMessage.BuilderParent parent) {
-        super(parent);
-        maybeForceBuilderInitialization();
-      }
-      private void maybeForceBuilderInitialization() {
-        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
-        }
-      }
-      private static Builder create() {
-        return new Builder();
-      }
-
-      public Builder clear() {
-        super.clear();
-        ruleRepository_ = "";
-        bitField0_ = (bitField0_ & ~0x00000001);
-        ruleKey_ = "";
-        bitField0_ = (bitField0_ & ~0x00000002);
-        line_ = 0;
-        bitField0_ = (bitField0_ & ~0x00000004);
-        msg_ = "";
-        bitField0_ = (bitField0_ & ~0x00000008);
-        severity_ = org.sonar.batch.protocol.Constants.Severity.INFO;
-        bitField0_ = (bitField0_ & ~0x00000010);
-        tag_ = com.google.protobuf.LazyStringArrayList.EMPTY;
-        bitField0_ = (bitField0_ & ~0x00000020);
-        effortToFix_ = 0D;
-        bitField0_ = (bitField0_ & ~0x00000040);
-        isNew_ = false;
-        bitField0_ = (bitField0_ & ~0x00000080);
-        uuid_ = "";
-        bitField0_ = (bitField0_ & ~0x00000100);
-        debtInMinutes_ = 0L;
-        bitField0_ = (bitField0_ & ~0x00000200);
-        resolution_ = "";
-        bitField0_ = (bitField0_ & ~0x00000400);
-        status_ = "";
-        bitField0_ = (bitField0_ & ~0x00000800);
-        checksum_ = "";
-        bitField0_ = (bitField0_ & ~0x00001000);
-        manualSeverity_ = false;
-        bitField0_ = (bitField0_ & ~0x00002000);
-        reporter_ = "";
-        bitField0_ = (bitField0_ & ~0x00004000);
-        assignee_ = "";
-        bitField0_ = (bitField0_ & ~0x00008000);
-        actionPlanKey_ = "";
-        bitField0_ = (bitField0_ & ~0x00010000);
-        attributes_ = "";
-        bitField0_ = (bitField0_ & ~0x00020000);
-        authorLogin_ = "";
-        bitField0_ = (bitField0_ & ~0x00040000);
-        creationDate_ = 0L;
-        bitField0_ = (bitField0_ & ~0x00080000);
-        closeDate_ = 0L;
-        bitField0_ = (bitField0_ & ~0x00100000);
-        updateDate_ = 0L;
-        bitField0_ = (bitField0_ & ~0x00200000);
-        selectedAt_ = 0L;
-        bitField0_ = (bitField0_ & ~0x00400000);
-        diffFields_ = "";
-        bitField0_ = (bitField0_ & ~0x00800000);
-        isChanged_ = false;
-        bitField0_ = (bitField0_ & ~0x01000000);
-        mustSendNotification_ = false;
-        bitField0_ = (bitField0_ & ~0x02000000);
-        return this;
-      }
-
-      public Builder clone() {
-        return create().mergeFrom(buildPartial());
-      }
-
-      public com.google.protobuf.Descriptors.Descriptor
-          getDescriptorForType() {
-        return org.sonar.batch.protocol.output.BatchReport.internal_static_Issue_descriptor;
-      }
-
-      public org.sonar.batch.protocol.output.BatchReport.Issue getDefaultInstanceForType() {
-        return org.sonar.batch.protocol.output.BatchReport.Issue.getDefaultInstance();
-      }
-
-      public org.sonar.batch.protocol.output.BatchReport.Issue build() {
-        org.sonar.batch.protocol.output.BatchReport.Issue result = buildPartial();
-        if (!result.isInitialized()) {
-          throw newUninitializedMessageException(result);
-        }
-        return result;
-      }
-
-      public org.sonar.batch.protocol.output.BatchReport.Issue buildPartial() {
-        org.sonar.batch.protocol.output.BatchReport.Issue result = new org.sonar.batch.protocol.output.BatchReport.Issue(this);
-        int from_bitField0_ = bitField0_;
-        int to_bitField0_ = 0;
-        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
-          to_bitField0_ |= 0x00000001;
-        }
-        result.ruleRepository_ = ruleRepository_;
-        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
-          to_bitField0_ |= 0x00000002;
-        }
-        result.ruleKey_ = ruleKey_;
-        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
-          to_bitField0_ |= 0x00000004;
-        }
-        result.line_ = line_;
-        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {
-          to_bitField0_ |= 0x00000008;
-        }
-        result.msg_ = msg_;
-        if (((from_bitField0_ & 0x00000010) == 0x00000010)) {
-          to_bitField0_ |= 0x00000010;
-        }
-        result.severity_ = severity_;
-        if (((bitField0_ & 0x00000020) == 0x00000020)) {
-          tag_ = tag_.getUnmodifiableView();
-          bitField0_ = (bitField0_ & ~0x00000020);
-        }
-        result.tag_ = tag_;
-        if (((from_bitField0_ & 0x00000040) == 0x00000040)) {
-          to_bitField0_ |= 0x00000020;
-        }
-        result.effortToFix_ = effortToFix_;
-        if (((from_bitField0_ & 0x00000080) == 0x00000080)) {
-          to_bitField0_ |= 0x00000040;
-        }
-        result.isNew_ = isNew_;
-        if (((from_bitField0_ & 0x00000100) == 0x00000100)) {
-          to_bitField0_ |= 0x00000080;
-        }
-        result.uuid_ = uuid_;
-        if (((from_bitField0_ & 0x00000200) == 0x00000200)) {
-          to_bitField0_ |= 0x00000100;
-        }
-        result.debtInMinutes_ = debtInMinutes_;
-        if (((from_bitField0_ & 0x00000400) == 0x00000400)) {
-          to_bitField0_ |= 0x00000200;
-        }
-        result.resolution_ = resolution_;
-        if (((from_bitField0_ & 0x00000800) == 0x00000800)) {
-          to_bitField0_ |= 0x00000400;
-        }
-        result.status_ = status_;
-        if (((from_bitField0_ & 0x00001000) == 0x00001000)) {
-          to_bitField0_ |= 0x00000800;
-        }
-        result.checksum_ = checksum_;
-        if (((from_bitField0_ & 0x00002000) == 0x00002000)) {
-          to_bitField0_ |= 0x00001000;
-        }
-        result.manualSeverity_ = manualSeverity_;
-        if (((from_bitField0_ & 0x00004000) == 0x00004000)) {
-          to_bitField0_ |= 0x00002000;
-        }
-        result.reporter_ = reporter_;
-        if (((from_bitField0_ & 0x00008000) == 0x00008000)) {
-          to_bitField0_ |= 0x00004000;
-        }
-        result.assignee_ = assignee_;
-        if (((from_bitField0_ & 0x00010000) == 0x00010000)) {
-          to_bitField0_ |= 0x00008000;
-        }
-        result.actionPlanKey_ = actionPlanKey_;
-        if (((from_bitField0_ & 0x00020000) == 0x00020000)) {
-          to_bitField0_ |= 0x00010000;
-        }
-        result.attributes_ = attributes_;
-        if (((from_bitField0_ & 0x00040000) == 0x00040000)) {
-          to_bitField0_ |= 0x00020000;
-        }
-        result.authorLogin_ = authorLogin_;
-        if (((from_bitField0_ & 0x00080000) == 0x00080000)) {
-          to_bitField0_ |= 0x00040000;
-        }
-        result.creationDate_ = creationDate_;
-        if (((from_bitField0_ & 0x00100000) == 0x00100000)) {
-          to_bitField0_ |= 0x00080000;
-        }
-        result.closeDate_ = closeDate_;
-        if (((from_bitField0_ & 0x00200000) == 0x00200000)) {
-          to_bitField0_ |= 0x00100000;
-        }
-        result.updateDate_ = updateDate_;
-        if (((from_bitField0_ & 0x00400000) == 0x00400000)) {
-          to_bitField0_ |= 0x00200000;
-        }
-        result.selectedAt_ = selectedAt_;
-        if (((from_bitField0_ & 0x00800000) == 0x00800000)) {
-          to_bitField0_ |= 0x00400000;
-        }
-        result.diffFields_ = diffFields_;
-        if (((from_bitField0_ & 0x01000000) == 0x01000000)) {
-          to_bitField0_ |= 0x00800000;
-        }
-        result.isChanged_ = isChanged_;
-        if (((from_bitField0_ & 0x02000000) == 0x02000000)) {
-          to_bitField0_ |= 0x01000000;
-        }
-        result.mustSendNotification_ = mustSendNotification_;
-        result.bitField0_ = to_bitField0_;
-        onBuilt();
-        return result;
-      }
-
-      public Builder mergeFrom(com.google.protobuf.Message other) {
-        if (other instanceof org.sonar.batch.protocol.output.BatchReport.Issue) {
-          return mergeFrom((org.sonar.batch.protocol.output.BatchReport.Issue)other);
-        } else {
-          super.mergeFrom(other);
-          return this;
-        }
-      }
-
-      public Builder mergeFrom(org.sonar.batch.protocol.output.BatchReport.Issue other) {
-        if (other == org.sonar.batch.protocol.output.BatchReport.Issue.getDefaultInstance()) return this;
-        if (other.hasRuleRepository()) {
-          bitField0_ |= 0x00000001;
-          ruleRepository_ = other.ruleRepository_;
-          onChanged();
-        }
-        if (other.hasRuleKey()) {
-          bitField0_ |= 0x00000002;
-          ruleKey_ = other.ruleKey_;
-          onChanged();
-        }
-        if (other.hasLine()) {
-          setLine(other.getLine());
-        }
-        if (other.hasMsg()) {
-          bitField0_ |= 0x00000008;
-          msg_ = other.msg_;
-          onChanged();
-        }
-        if (other.hasSeverity()) {
-          setSeverity(other.getSeverity());
-        }
-        if (!other.tag_.isEmpty()) {
-          if (tag_.isEmpty()) {
-            tag_ = other.tag_;
-            bitField0_ = (bitField0_ & ~0x00000020);
-          } else {
-            ensureTagIsMutable();
-            tag_.addAll(other.tag_);
-          }
-          onChanged();
-        }
-        if (other.hasEffortToFix()) {
-          setEffortToFix(other.getEffortToFix());
-        }
-        if (other.hasIsNew()) {
-          setIsNew(other.getIsNew());
-        }
-        if (other.hasUuid()) {
-          bitField0_ |= 0x00000100;
-          uuid_ = other.uuid_;
-          onChanged();
-        }
-        if (other.hasDebtInMinutes()) {
-          setDebtInMinutes(other.getDebtInMinutes());
-        }
-        if (other.hasResolution()) {
-          bitField0_ |= 0x00000400;
-          resolution_ = other.resolution_;
-          onChanged();
-        }
-        if (other.hasStatus()) {
-          bitField0_ |= 0x00000800;
-          status_ = other.status_;
-          onChanged();
-        }
-        if (other.hasChecksum()) {
-          bitField0_ |= 0x00001000;
-          checksum_ = other.checksum_;
-          onChanged();
-        }
-        if (other.hasManualSeverity()) {
-          setManualSeverity(other.getManualSeverity());
-        }
-        if (other.hasReporter()) {
-          bitField0_ |= 0x00004000;
-          reporter_ = other.reporter_;
-          onChanged();
-        }
-        if (other.hasAssignee()) {
-          bitField0_ |= 0x00008000;
-          assignee_ = other.assignee_;
-          onChanged();
-        }
-        if (other.hasActionPlanKey()) {
-          bitField0_ |= 0x00010000;
-          actionPlanKey_ = other.actionPlanKey_;
-          onChanged();
-        }
-        if (other.hasAttributes()) {
-          bitField0_ |= 0x00020000;
-          attributes_ = other.attributes_;
-          onChanged();
-        }
-        if (other.hasAuthorLogin()) {
-          bitField0_ |= 0x00040000;
-          authorLogin_ = other.authorLogin_;
-          onChanged();
-        }
-        if (other.hasCreationDate()) {
-          setCreationDate(other.getCreationDate());
-        }
-        if (other.hasCloseDate()) {
-          setCloseDate(other.getCloseDate());
-        }
-        if (other.hasUpdateDate()) {
-          setUpdateDate(other.getUpdateDate());
-        }
-        if (other.hasSelectedAt()) {
-          setSelectedAt(other.getSelectedAt());
-        }
-        if (other.hasDiffFields()) {
-          bitField0_ |= 0x00800000;
-          diffFields_ = other.diffFields_;
-          onChanged();
-        }
-        if (other.hasIsChanged()) {
-          setIsChanged(other.getIsChanged());
-        }
-        if (other.hasMustSendNotification()) {
-          setMustSendNotification(other.getMustSendNotification());
-        }
-        this.mergeUnknownFields(other.getUnknownFields());
-        return this;
-      }
-
-      public final boolean isInitialized() {
-        return true;
-      }
-
-      public Builder mergeFrom(
-          com.google.protobuf.CodedInputStream input,
-          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
-          throws java.io.IOException {
-        org.sonar.batch.protocol.output.BatchReport.Issue parsedMessage = null;
-        try {
-          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
-        } catch (com.google.protobuf.InvalidProtocolBufferException e) {
-          parsedMessage = (org.sonar.batch.protocol.output.BatchReport.Issue) e.getUnfinishedMessage();
-          throw e;
-        } finally {
-          if (parsedMessage != null) {
-            mergeFrom(parsedMessage);
-          }
-        }
-        return this;
-      }
-      private int bitField0_;
-
-      private java.lang.Object ruleRepository_ = "";
-      /**
-       * <code>optional string rule_repository = 1;</code>
-       */
-      public boolean hasRuleRepository() {
-        return ((bitField0_ & 0x00000001) == 0x00000001);
-      }
-      /**
-       * <code>optional string rule_repository = 1;</code>
-       */
-      public java.lang.String getRuleRepository() {
-        java.lang.Object ref = ruleRepository_;
-        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()) {
-            ruleRepository_ = s;
-          }
-          return s;
-        } else {
-          return (java.lang.String) ref;
-        }
-      }
-      /**
-       * <code>optional string rule_repository = 1;</code>
-       */
-      public com.google.protobuf.ByteString
-          getRuleRepositoryBytes() {
-        java.lang.Object ref = ruleRepository_;
-        if (ref instanceof String) {
-          com.google.protobuf.ByteString b = 
-              com.google.protobuf.ByteString.copyFromUtf8(
-                  (java.lang.String) ref);
-          ruleRepository_ = b;
-          return b;
-        } else {
-          return (com.google.protobuf.ByteString) ref;
-        }
-      }
-      /**
-       * <code>optional string rule_repository = 1;</code>
-       */
-      public Builder setRuleRepository(
-          java.lang.String value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  bitField0_ |= 0x00000001;
-        ruleRepository_ = value;
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>optional string rule_repository = 1;</code>
-       */
-      public Builder clearRuleRepository() {
-        bitField0_ = (bitField0_ & ~0x00000001);
-        ruleRepository_ = getDefaultInstance().getRuleRepository();
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>optional string rule_repository = 1;</code>
-       */
-      public Builder setRuleRepositoryBytes(
-          com.google.protobuf.ByteString value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  bitField0_ |= 0x00000001;
-        ruleRepository_ = value;
-        onChanged();
-        return this;
-      }
-
-      private java.lang.Object ruleKey_ = "";
-      /**
-       * <code>optional string rule_key = 2;</code>
-       */
-      public boolean hasRuleKey() {
-        return ((bitField0_ & 0x00000002) == 0x00000002);
-      }
-      /**
-       * <code>optional string rule_key = 2;</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 = 2;</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 = 2;</code>
-       */
-      public Builder setRuleKey(
-          java.lang.String value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  bitField0_ |= 0x00000002;
-        ruleKey_ = value;
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>optional string rule_key = 2;</code>
-       */
-      public Builder clearRuleKey() {
-        bitField0_ = (bitField0_ & ~0x00000002);
-        ruleKey_ = getDefaultInstance().getRuleKey();
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>optional string rule_key = 2;</code>
-       */
-      public Builder setRuleKeyBytes(
-          com.google.protobuf.ByteString value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  bitField0_ |= 0x00000002;
-        ruleKey_ = value;
-        onChanged();
-        return this;
-      }
-
-      private int line_ ;
-      /**
-       * <code>optional int32 line = 3;</code>
-       */
-      public boolean hasLine() {
-        return ((bitField0_ & 0x00000004) == 0x00000004);
-      }
-      /**
-       * <code>optional int32 line = 3;</code>
-       */
-      public int getLine() {
-        return line_;
-      }
-      /**
-       * <code>optional int32 line = 3;</code>
-       */
-      public Builder setLine(int value) {
-        bitField0_ |= 0x00000004;
-        line_ = value;
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>optional int32 line = 3;</code>
-       */
-      public Builder clearLine() {
-        bitField0_ = (bitField0_ & ~0x00000004);
-        line_ = 0;
-        onChanged();
-        return this;
-      }
-
-      private java.lang.Object msg_ = "";
-      /**
-       * <code>optional string msg = 4;</code>
-       */
-      public boolean hasMsg() {
-        return ((bitField0_ & 0x00000008) == 0x00000008);
-      }
-      /**
-       * <code>optional string msg = 4;</code>
-       */
-      public java.lang.String getMsg() {
-        java.lang.Object ref = msg_;
-        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()) {
-            msg_ = s;
-          }
-          return s;
-        } else {
-          return (java.lang.String) ref;
-        }
-      }
-      /**
-       * <code>optional string msg = 4;</code>
-       */
-      public com.google.protobuf.ByteString
-          getMsgBytes() {
-        java.lang.Object ref = msg_;
-        if (ref instanceof String) {
-          com.google.protobuf.ByteString b = 
-              com.google.protobuf.ByteString.copyFromUtf8(
-                  (java.lang.String) ref);
-          msg_ = b;
-          return b;
-        } else {
-          return (com.google.protobuf.ByteString) ref;
-        }
-      }
-      /**
-       * <code>optional string msg = 4;</code>
-       */
-      public Builder setMsg(
-          java.lang.String value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  bitField0_ |= 0x00000008;
-        msg_ = value;
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>optional string msg = 4;</code>
-       */
-      public Builder clearMsg() {
-        bitField0_ = (bitField0_ & ~0x00000008);
-        msg_ = getDefaultInstance().getMsg();
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>optional string msg = 4;</code>
-       */
-      public Builder setMsgBytes(
-          com.google.protobuf.ByteString value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  bitField0_ |= 0x00000008;
-        msg_ = value;
-        onChanged();
-        return this;
-      }
-
-      private org.sonar.batch.protocol.Constants.Severity severity_ = org.sonar.batch.protocol.Constants.Severity.INFO;
-      /**
-       * <code>optional .Severity severity = 5;</code>
-       */
-      public boolean hasSeverity() {
-        return ((bitField0_ & 0x00000010) == 0x00000010);
-      }
-      /**
-       * <code>optional .Severity severity = 5;</code>
-       */
-      public org.sonar.batch.protocol.Constants.Severity getSeverity() {
-        return severity_;
-      }
-      /**
-       * <code>optional .Severity severity = 5;</code>
-       */
-      public Builder setSeverity(org.sonar.batch.protocol.Constants.Severity value) {
-        if (value == null) {
-          throw new NullPointerException();
-        }
-        bitField0_ |= 0x00000010;
-        severity_ = value;
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>optional .Severity severity = 5;</code>
-       */
-      public Builder clearSeverity() {
-        bitField0_ = (bitField0_ & ~0x00000010);
-        severity_ = org.sonar.batch.protocol.Constants.Severity.INFO;
-        onChanged();
-        return this;
-      }
-
-      private com.google.protobuf.LazyStringList tag_ = com.google.protobuf.LazyStringArrayList.EMPTY;
-      private void ensureTagIsMutable() {
-        if (!((bitField0_ & 0x00000020) == 0x00000020)) {
-          tag_ = new com.google.protobuf.LazyStringArrayList(tag_);
-          bitField0_ |= 0x00000020;
-         }
-      }
-      /**
-       * <code>repeated string tag = 6;</code>
-       */
-      public com.google.protobuf.ProtocolStringList
-          getTagList() {
-        return tag_.getUnmodifiableView();
-      }
-      /**
-       * <code>repeated string tag = 6;</code>
-       */
-      public int getTagCount() {
-        return tag_.size();
-      }
-      /**
-       * <code>repeated string tag = 6;</code>
-       */
-      public java.lang.String getTag(int index) {
-        return tag_.get(index);
-      }
-      /**
-       * <code>repeated string tag = 6;</code>
-       */
-      public com.google.protobuf.ByteString
-          getTagBytes(int index) {
-        return tag_.getByteString(index);
-      }
-      /**
-       * <code>repeated string tag = 6;</code>
-       */
-      public Builder setTag(
-          int index, java.lang.String value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  ensureTagIsMutable();
-        tag_.set(index, value);
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>repeated string tag = 6;</code>
-       */
-      public Builder addTag(
-          java.lang.String value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  ensureTagIsMutable();
-        tag_.add(value);
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>repeated string tag = 6;</code>
-       */
-      public Builder addAllTag(
-          java.lang.Iterable<java.lang.String> values) {
-        ensureTagIsMutable();
-        com.google.protobuf.AbstractMessageLite.Builder.addAll(
-            values, tag_);
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>repeated string tag = 6;</code>
-       */
-      public Builder clearTag() {
-        tag_ = com.google.protobuf.LazyStringArrayList.EMPTY;
-        bitField0_ = (bitField0_ & ~0x00000020);
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>repeated string tag = 6;</code>
-       */
-      public Builder addTagBytes(
-          com.google.protobuf.ByteString value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  ensureTagIsMutable();
-        tag_.add(value);
-        onChanged();
-        return this;
-      }
-
-      private double effortToFix_ ;
-      /**
-       * <code>optional double effort_to_fix = 7;</code>
-       *
-       * <pre>
-       * temporary fields during development of computation stack
-       * </pre>
-       */
-      public boolean hasEffortToFix() {
-        return ((bitField0_ & 0x00000040) == 0x00000040);
-      }
-      /**
-       * <code>optional double effort_to_fix = 7;</code>
-       *
-       * <pre>
-       * temporary fields during development of computation stack
-       * </pre>
-       */
-      public double getEffortToFix() {
-        return effortToFix_;
-      }
-      /**
-       * <code>optional double effort_to_fix = 7;</code>
-       *
-       * <pre>
-       * temporary fields during development of computation stack
-       * </pre>
-       */
-      public Builder setEffortToFix(double value) {
-        bitField0_ |= 0x00000040;
-        effortToFix_ = value;
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>optional double effort_to_fix = 7;</code>
-       *
-       * <pre>
-       * temporary fields during development of computation stack
-       * </pre>
-       */
-      public Builder clearEffortToFix() {
-        bitField0_ = (bitField0_ & ~0x00000040);
-        effortToFix_ = 0D;
-        onChanged();
-        return this;
-      }
-
-      private boolean isNew_ ;
-      /**
-       * <code>optional bool is_new = 8;</code>
-       */
-      public boolean hasIsNew() {
-        return ((bitField0_ & 0x00000080) == 0x00000080);
-      }
-      /**
-       * <code>optional bool is_new = 8;</code>
-       */
-      public boolean getIsNew() {
-        return isNew_;
-      }
-      /**
-       * <code>optional bool is_new = 8;</code>
-       */
-      public Builder setIsNew(boolean value) {
-        bitField0_ |= 0x00000080;
-        isNew_ = value;
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>optional bool is_new = 8;</code>
-       */
-      public Builder clearIsNew() {
-        bitField0_ = (bitField0_ & ~0x00000080);
-        isNew_ = false;
-        onChanged();
-        return this;
-      }
-
-      private java.lang.Object uuid_ = "";
-      /**
-       * <code>optional string uuid = 9;</code>
-       */
-      public boolean hasUuid() {
-        return ((bitField0_ & 0x00000100) == 0x00000100);
-      }
-      /**
-       * <code>optional string uuid = 9;</code>
-       */
-      public java.lang.String getUuid() {
-        java.lang.Object ref = uuid_;
-        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()) {
-            uuid_ = s;
-          }
-          return s;
-        } else {
-          return (java.lang.String) ref;
-        }
-      }
-      /**
-       * <code>optional string uuid = 9;</code>
-       */
-      public com.google.protobuf.ByteString
-          getUuidBytes() {
-        java.lang.Object ref = uuid_;
-        if (ref instanceof String) {
-          com.google.protobuf.ByteString b = 
-              com.google.protobuf.ByteString.copyFromUtf8(
-                  (java.lang.String) ref);
-          uuid_ = b;
-          return b;
-        } else {
-          return (com.google.protobuf.ByteString) ref;
-        }
-      }
-      /**
-       * <code>optional string uuid = 9;</code>
-       */
-      public Builder setUuid(
-          java.lang.String value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  bitField0_ |= 0x00000100;
-        uuid_ = value;
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>optional string uuid = 9;</code>
-       */
-      public Builder clearUuid() {
-        bitField0_ = (bitField0_ & ~0x00000100);
-        uuid_ = getDefaultInstance().getUuid();
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>optional string uuid = 9;</code>
-       */
-      public Builder setUuidBytes(
-          com.google.protobuf.ByteString value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  bitField0_ |= 0x00000100;
-        uuid_ = value;
-        onChanged();
-        return this;
-      }
-
-      private long debtInMinutes_ ;
-      /**
-       * <code>optional int64 debt_in_minutes = 10;</code>
-       */
-      public boolean hasDebtInMinutes() {
-        return ((bitField0_ & 0x00000200) == 0x00000200);
-      }
-      /**
-       * <code>optional int64 debt_in_minutes = 10;</code>
-       */
-      public long getDebtInMinutes() {
-        return debtInMinutes_;
-      }
-      /**
-       * <code>optional int64 debt_in_minutes = 10;</code>
-       */
-      public Builder setDebtInMinutes(long value) {
-        bitField0_ |= 0x00000200;
-        debtInMinutes_ = value;
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>optional int64 debt_in_minutes = 10;</code>
-       */
-      public Builder clearDebtInMinutes() {
-        bitField0_ = (bitField0_ & ~0x00000200);
-        debtInMinutes_ = 0L;
-        onChanged();
-        return this;
-      }
-
-      private java.lang.Object resolution_ = "";
-      /**
-       * <code>optional string resolution = 11;</code>
-       */
-      public boolean hasResolution() {
-        return ((bitField0_ & 0x00000400) == 0x00000400);
-      }
-      /**
-       * <code>optional string resolution = 11;</code>
-       */
-      public java.lang.String getResolution() {
-        java.lang.Object ref = resolution_;
-        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()) {
-            resolution_ = s;
-          }
-          return s;
-        } else {
-          return (java.lang.String) ref;
-        }
-      }
-      /**
-       * <code>optional string resolution = 11;</code>
-       */
-      public com.google.protobuf.ByteString
-          getResolutionBytes() {
-        java.lang.Object ref = resolution_;
-        if (ref instanceof String) {
-          com.google.protobuf.ByteString b = 
-              com.google.protobuf.ByteString.copyFromUtf8(
-                  (java.lang.String) ref);
-          resolution_ = b;
-          return b;
-        } else {
-          return (com.google.protobuf.ByteString) ref;
-        }
-      }
-      /**
-       * <code>optional string resolution = 11;</code>
-       */
-      public Builder setResolution(
-          java.lang.String value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  bitField0_ |= 0x00000400;
-        resolution_ = value;
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>optional string resolution = 11;</code>
-       */
-      public Builder clearResolution() {
-        bitField0_ = (bitField0_ & ~0x00000400);
-        resolution_ = getDefaultInstance().getResolution();
-        onChanged();
+      public Builder clear() {
+        super.clear();
+        ruleRepository_ = "";
+        bitField0_ = (bitField0_ & ~0x00000001);
+        ruleKey_ = "";
+        bitField0_ = (bitField0_ & ~0x00000002);
+        line_ = 0;
+        bitField0_ = (bitField0_ & ~0x00000004);
+        msg_ = "";
+        bitField0_ = (bitField0_ & ~0x00000008);
+        severity_ = org.sonar.batch.protocol.Constants.Severity.INFO;
+        bitField0_ = (bitField0_ & ~0x00000010);
+        tag_ = com.google.protobuf.LazyStringArrayList.EMPTY;
+        bitField0_ = (bitField0_ & ~0x00000020);
+        effortToFix_ = 0D;
+        bitField0_ = (bitField0_ & ~0x00000040);
+        attributes_ = "";
+        bitField0_ = (bitField0_ & ~0x00000080);
+        debtInMinutes_ = 0L;
+        bitField0_ = (bitField0_ & ~0x00000100);
         return this;
       }
-      /**
-       * <code>optional string resolution = 11;</code>
-       */
-      public Builder setResolutionBytes(
-          com.google.protobuf.ByteString value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  bitField0_ |= 0x00000400;
-        resolution_ = value;
-        onChanged();
-        return this;
+
+      public Builder clone() {
+        return create().mergeFrom(buildPartial());
       }
 
-      private java.lang.Object status_ = "";
-      /**
-       * <code>optional string status = 12;</code>
-       */
-      public boolean hasStatus() {
-        return ((bitField0_ & 0x00000800) == 0x00000800);
+      public com.google.protobuf.Descriptors.Descriptor
+          getDescriptorForType() {
+        return org.sonar.batch.protocol.output.BatchReport.internal_static_Issue_descriptor;
       }
-      /**
-       * <code>optional string status = 12;</code>
-       */
-      public java.lang.String getStatus() {
-        java.lang.Object ref = status_;
-        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()) {
-            status_ = s;
-          }
-          return s;
-        } else {
-          return (java.lang.String) ref;
-        }
+
+      public org.sonar.batch.protocol.output.BatchReport.Issue getDefaultInstanceForType() {
+        return org.sonar.batch.protocol.output.BatchReport.Issue.getDefaultInstance();
       }
-      /**
-       * <code>optional string status = 12;</code>
-       */
-      public com.google.protobuf.ByteString
-          getStatusBytes() {
-        java.lang.Object ref = status_;
-        if (ref instanceof String) {
-          com.google.protobuf.ByteString b = 
-              com.google.protobuf.ByteString.copyFromUtf8(
-                  (java.lang.String) ref);
-          status_ = b;
-          return b;
-        } else {
-          return (com.google.protobuf.ByteString) ref;
+
+      public org.sonar.batch.protocol.output.BatchReport.Issue build() {
+        org.sonar.batch.protocol.output.BatchReport.Issue result = buildPartial();
+        if (!result.isInitialized()) {
+          throw newUninitializedMessageException(result);
         }
-      }
-      /**
-       * <code>optional string status = 12;</code>
-       */
-      public Builder setStatus(
-          java.lang.String value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  bitField0_ |= 0x00000800;
-        status_ = value;
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>optional string status = 12;</code>
-       */
-      public Builder clearStatus() {
-        bitField0_ = (bitField0_ & ~0x00000800);
-        status_ = getDefaultInstance().getStatus();
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>optional string status = 12;</code>
-       */
-      public Builder setStatusBytes(
-          com.google.protobuf.ByteString value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  bitField0_ |= 0x00000800;
-        status_ = value;
-        onChanged();
-        return this;
+        return result;
       }
 
-      private java.lang.Object checksum_ = "";
-      /**
-       * <code>optional string checksum = 13;</code>
-       */
-      public boolean hasChecksum() {
-        return ((bitField0_ & 0x00001000) == 0x00001000);
-      }
-      /**
-       * <code>optional string checksum = 13;</code>
-       */
-      public java.lang.String getChecksum() {
-        java.lang.Object ref = checksum_;
-        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()) {
-            checksum_ = s;
-          }
-          return s;
-        } else {
-          return (java.lang.String) ref;
+      public org.sonar.batch.protocol.output.BatchReport.Issue buildPartial() {
+        org.sonar.batch.protocol.output.BatchReport.Issue result = new org.sonar.batch.protocol.output.BatchReport.Issue(this);
+        int from_bitField0_ = bitField0_;
+        int to_bitField0_ = 0;
+        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
+          to_bitField0_ |= 0x00000001;
+        }
+        result.ruleRepository_ = ruleRepository_;
+        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
+          to_bitField0_ |= 0x00000002;
+        }
+        result.ruleKey_ = ruleKey_;
+        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
+          to_bitField0_ |= 0x00000004;
+        }
+        result.line_ = line_;
+        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {
+          to_bitField0_ |= 0x00000008;
+        }
+        result.msg_ = msg_;
+        if (((from_bitField0_ & 0x00000010) == 0x00000010)) {
+          to_bitField0_ |= 0x00000010;
+        }
+        result.severity_ = severity_;
+        if (((bitField0_ & 0x00000020) == 0x00000020)) {
+          tag_ = tag_.getUnmodifiableView();
+          bitField0_ = (bitField0_ & ~0x00000020);
+        }
+        result.tag_ = tag_;
+        if (((from_bitField0_ & 0x00000040) == 0x00000040)) {
+          to_bitField0_ |= 0x00000020;
+        }
+        result.effortToFix_ = effortToFix_;
+        if (((from_bitField0_ & 0x00000080) == 0x00000080)) {
+          to_bitField0_ |= 0x00000040;
+        }
+        result.attributes_ = attributes_;
+        if (((from_bitField0_ & 0x00000100) == 0x00000100)) {
+          to_bitField0_ |= 0x00000080;
         }
+        result.debtInMinutes_ = debtInMinutes_;
+        result.bitField0_ = to_bitField0_;
+        onBuilt();
+        return result;
       }
-      /**
-       * <code>optional string checksum = 13;</code>
-       */
-      public com.google.protobuf.ByteString
-          getChecksumBytes() {
-        java.lang.Object ref = checksum_;
-        if (ref instanceof String) {
-          com.google.protobuf.ByteString b = 
-              com.google.protobuf.ByteString.copyFromUtf8(
-                  (java.lang.String) ref);
-          checksum_ = b;
-          return b;
+
+      public Builder mergeFrom(com.google.protobuf.Message other) {
+        if (other instanceof org.sonar.batch.protocol.output.BatchReport.Issue) {
+          return mergeFrom((org.sonar.batch.protocol.output.BatchReport.Issue)other);
         } else {
-          return (com.google.protobuf.ByteString) ref;
+          super.mergeFrom(other);
+          return this;
         }
       }
-      /**
-       * <code>optional string checksum = 13;</code>
-       */
-      public Builder setChecksum(
-          java.lang.String value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  bitField0_ |= 0x00001000;
-        checksum_ = value;
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>optional string checksum = 13;</code>
-       */
-      public Builder clearChecksum() {
-        bitField0_ = (bitField0_ & ~0x00001000);
-        checksum_ = getDefaultInstance().getChecksum();
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>optional string checksum = 13;</code>
-       */
-      public Builder setChecksumBytes(
-          com.google.protobuf.ByteString value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  bitField0_ |= 0x00001000;
-        checksum_ = value;
-        onChanged();
-        return this;
-      }
 
-      private boolean manualSeverity_ ;
-      /**
-       * <code>optional bool manual_severity = 14;</code>
-       */
-      public boolean hasManualSeverity() {
-        return ((bitField0_ & 0x00002000) == 0x00002000);
-      }
-      /**
-       * <code>optional bool manual_severity = 14;</code>
-       */
-      public boolean getManualSeverity() {
-        return manualSeverity_;
-      }
-      /**
-       * <code>optional bool manual_severity = 14;</code>
-       */
-      public Builder setManualSeverity(boolean value) {
-        bitField0_ |= 0x00002000;
-        manualSeverity_ = value;
-        onChanged();
+      public Builder mergeFrom(org.sonar.batch.protocol.output.BatchReport.Issue other) {
+        if (other == org.sonar.batch.protocol.output.BatchReport.Issue.getDefaultInstance()) return this;
+        if (other.hasRuleRepository()) {
+          bitField0_ |= 0x00000001;
+          ruleRepository_ = other.ruleRepository_;
+          onChanged();
+        }
+        if (other.hasRuleKey()) {
+          bitField0_ |= 0x00000002;
+          ruleKey_ = other.ruleKey_;
+          onChanged();
+        }
+        if (other.hasLine()) {
+          setLine(other.getLine());
+        }
+        if (other.hasMsg()) {
+          bitField0_ |= 0x00000008;
+          msg_ = other.msg_;
+          onChanged();
+        }
+        if (other.hasSeverity()) {
+          setSeverity(other.getSeverity());
+        }
+        if (!other.tag_.isEmpty()) {
+          if (tag_.isEmpty()) {
+            tag_ = other.tag_;
+            bitField0_ = (bitField0_ & ~0x00000020);
+          } else {
+            ensureTagIsMutable();
+            tag_.addAll(other.tag_);
+          }
+          onChanged();
+        }
+        if (other.hasEffortToFix()) {
+          setEffortToFix(other.getEffortToFix());
+        }
+        if (other.hasAttributes()) {
+          bitField0_ |= 0x00000080;
+          attributes_ = other.attributes_;
+          onChanged();
+        }
+        if (other.hasDebtInMinutes()) {
+          setDebtInMinutes(other.getDebtInMinutes());
+        }
+        this.mergeUnknownFields(other.getUnknownFields());
         return this;
       }
-      /**
-       * <code>optional bool manual_severity = 14;</code>
-       */
-      public Builder clearManualSeverity() {
-        bitField0_ = (bitField0_ & ~0x00002000);
-        manualSeverity_ = false;
-        onChanged();
+
+      public final boolean isInitialized() {
+        return true;
+      }
+
+      public Builder mergeFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws java.io.IOException {
+        org.sonar.batch.protocol.output.BatchReport.Issue parsedMessage = null;
+        try {
+          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+        } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+          parsedMessage = (org.sonar.batch.protocol.output.BatchReport.Issue) e.getUnfinishedMessage();
+          throw e;
+        } finally {
+          if (parsedMessage != null) {
+            mergeFrom(parsedMessage);
+          }
+        }
         return this;
       }
+      private int bitField0_;
 
-      private java.lang.Object reporter_ = "";
+      private java.lang.Object ruleRepository_ = "";
       /**
-       * <code>optional string reporter = 15;</code>
+       * <code>optional string rule_repository = 1;</code>
        */
-      public boolean hasReporter() {
-        return ((bitField0_ & 0x00004000) == 0x00004000);
+      public boolean hasRuleRepository() {
+        return ((bitField0_ & 0x00000001) == 0x00000001);
       }
       /**
-       * <code>optional string reporter = 15;</code>
+       * <code>optional string rule_repository = 1;</code>
        */
-      public java.lang.String getReporter() {
-        java.lang.Object ref = reporter_;
+      public java.lang.String getRuleRepository() {
+        java.lang.Object ref = ruleRepository_;
         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()) {
-            reporter_ = s;
+            ruleRepository_ = s;
           }
           return s;
         } else {
@@ -9742,75 +7699,75 @@ public final class BatchReport {
         }
       }
       /**
-       * <code>optional string reporter = 15;</code>
+       * <code>optional string rule_repository = 1;</code>
        */
       public com.google.protobuf.ByteString
-          getReporterBytes() {
-        java.lang.Object ref = reporter_;
+          getRuleRepositoryBytes() {
+        java.lang.Object ref = ruleRepository_;
         if (ref instanceof String) {
           com.google.protobuf.ByteString b = 
               com.google.protobuf.ByteString.copyFromUtf8(
                   (java.lang.String) ref);
-          reporter_ = b;
+          ruleRepository_ = b;
           return b;
         } else {
           return (com.google.protobuf.ByteString) ref;
         }
       }
       /**
-       * <code>optional string reporter = 15;</code>
+       * <code>optional string rule_repository = 1;</code>
        */
-      public Builder setReporter(
+      public Builder setRuleRepository(
           java.lang.String value) {
         if (value == null) {
     throw new NullPointerException();
   }
-  bitField0_ |= 0x00004000;
-        reporter_ = value;
+  bitField0_ |= 0x00000001;
+        ruleRepository_ = value;
         onChanged();
         return this;
       }
       /**
-       * <code>optional string reporter = 15;</code>
+       * <code>optional string rule_repository = 1;</code>
        */
-      public Builder clearReporter() {
-        bitField0_ = (bitField0_ & ~0x00004000);
-        reporter_ = getDefaultInstance().getReporter();
+      public Builder clearRuleRepository() {
+        bitField0_ = (bitField0_ & ~0x00000001);
+        ruleRepository_ = getDefaultInstance().getRuleRepository();
         onChanged();
         return this;
       }
       /**
-       * <code>optional string reporter = 15;</code>
+       * <code>optional string rule_repository = 1;</code>
        */
-      public Builder setReporterBytes(
+      public Builder setRuleRepositoryBytes(
           com.google.protobuf.ByteString value) {
         if (value == null) {
     throw new NullPointerException();
   }
-  bitField0_ |= 0x00004000;
-        reporter_ = value;
+  bitField0_ |= 0x00000001;
+        ruleRepository_ = value;
         onChanged();
         return this;
       }
 
-      private java.lang.Object assignee_ = "";
+      private java.lang.Object ruleKey_ = "";
       /**
-       * <code>optional string assignee = 16;</code>
+       * <code>optional string rule_key = 2;</code>
        */
-      public boolean hasAssignee() {
-        return ((bitField0_ & 0x00008000) == 0x00008000);
+      public boolean hasRuleKey() {
+        return ((bitField0_ & 0x00000002) == 0x00000002);
       }
       /**
-       * <code>optional string assignee = 16;</code>
+       * <code>optional string rule_key = 2;</code>
        */
-      public java.lang.String getAssignee() {
-        java.lang.Object ref = assignee_;
+      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()) {
-            assignee_ = s;
+            ruleKey_ = s;
           }
           return s;
         } else {
@@ -9818,151 +7775,107 @@ public final class BatchReport {
         }
       }
       /**
-       * <code>optional string assignee = 16;</code>
+       * <code>optional string rule_key = 2;</code>
        */
       public com.google.protobuf.ByteString
-          getAssigneeBytes() {
-        java.lang.Object ref = assignee_;
+          getRuleKeyBytes() {
+        java.lang.Object ref = ruleKey_;
         if (ref instanceof String) {
           com.google.protobuf.ByteString b = 
               com.google.protobuf.ByteString.copyFromUtf8(
                   (java.lang.String) ref);
-          assignee_ = b;
+          ruleKey_ = b;
           return b;
         } else {
           return (com.google.protobuf.ByteString) ref;
         }
       }
       /**
-       * <code>optional string assignee = 16;</code>
+       * <code>optional string rule_key = 2;</code>
        */
-      public Builder setAssignee(
+      public Builder setRuleKey(
           java.lang.String value) {
         if (value == null) {
     throw new NullPointerException();
   }
-  bitField0_ |= 0x00008000;
-        assignee_ = value;
+  bitField0_ |= 0x00000002;
+        ruleKey_ = value;
         onChanged();
         return this;
       }
       /**
-       * <code>optional string assignee = 16;</code>
+       * <code>optional string rule_key = 2;</code>
        */
-      public Builder clearAssignee() {
-        bitField0_ = (bitField0_ & ~0x00008000);
-        assignee_ = getDefaultInstance().getAssignee();
+      public Builder clearRuleKey() {
+        bitField0_ = (bitField0_ & ~0x00000002);
+        ruleKey_ = getDefaultInstance().getRuleKey();
         onChanged();
         return this;
       }
       /**
-       * <code>optional string assignee = 16;</code>
+       * <code>optional string rule_key = 2;</code>
        */
-      public Builder setAssigneeBytes(
+      public Builder setRuleKeyBytes(
           com.google.protobuf.ByteString value) {
         if (value == null) {
     throw new NullPointerException();
   }
-  bitField0_ |= 0x00008000;
-        assignee_ = value;
+  bitField0_ |= 0x00000002;
+        ruleKey_ = value;
         onChanged();
         return this;
       }
 
-      private java.lang.Object actionPlanKey_ = "";
-      /**
-       * <code>optional string action_plan_key = 17;</code>
-       */
-      public boolean hasActionPlanKey() {
-        return ((bitField0_ & 0x00010000) == 0x00010000);
-      }
-      /**
-       * <code>optional string action_plan_key = 17;</code>
-       */
-      public java.lang.String getActionPlanKey() {
-        java.lang.Object ref = actionPlanKey_;
-        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()) {
-            actionPlanKey_ = s;
-          }
-          return s;
-        } else {
-          return (java.lang.String) ref;
-        }
-      }
+      private int line_ ;
       /**
-       * <code>optional string action_plan_key = 17;</code>
+       * <code>optional int32 line = 3;</code>
        */
-      public com.google.protobuf.ByteString
-          getActionPlanKeyBytes() {
-        java.lang.Object ref = actionPlanKey_;
-        if (ref instanceof String) {
-          com.google.protobuf.ByteString b = 
-              com.google.protobuf.ByteString.copyFromUtf8(
-                  (java.lang.String) ref);
-          actionPlanKey_ = b;
-          return b;
-        } else {
-          return (com.google.protobuf.ByteString) ref;
-        }
+      public boolean hasLine() {
+        return ((bitField0_ & 0x00000004) == 0x00000004);
       }
       /**
-       * <code>optional string action_plan_key = 17;</code>
+       * <code>optional int32 line = 3;</code>
        */
-      public Builder setActionPlanKey(
-          java.lang.String value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  bitField0_ |= 0x00010000;
-        actionPlanKey_ = value;
-        onChanged();
-        return this;
+      public int getLine() {
+        return line_;
       }
       /**
-       * <code>optional string action_plan_key = 17;</code>
+       * <code>optional int32 line = 3;</code>
        */
-      public Builder clearActionPlanKey() {
-        bitField0_ = (bitField0_ & ~0x00010000);
-        actionPlanKey_ = getDefaultInstance().getActionPlanKey();
+      public Builder setLine(int value) {
+        bitField0_ |= 0x00000004;
+        line_ = value;
         onChanged();
         return this;
       }
       /**
-       * <code>optional string action_plan_key = 17;</code>
+       * <code>optional int32 line = 3;</code>
        */
-      public Builder setActionPlanKeyBytes(
-          com.google.protobuf.ByteString value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  bitField0_ |= 0x00010000;
-        actionPlanKey_ = value;
+      public Builder clearLine() {
+        bitField0_ = (bitField0_ & ~0x00000004);
+        line_ = 0;
         onChanged();
         return this;
       }
 
-      private java.lang.Object attributes_ = "";
+      private java.lang.Object msg_ = "";
       /**
-       * <code>optional string attributes = 18;</code>
+       * <code>optional string msg = 4;</code>
        */
-      public boolean hasAttributes() {
-        return ((bitField0_ & 0x00020000) == 0x00020000);
+      public boolean hasMsg() {
+        return ((bitField0_ & 0x00000008) == 0x00000008);
       }
       /**
-       * <code>optional string attributes = 18;</code>
+       * <code>optional string msg = 4;</code>
        */
-      public java.lang.String getAttributes() {
-        java.lang.Object ref = attributes_;
+      public java.lang.String getMsg() {
+        java.lang.Object ref = msg_;
         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()) {
-            attributes_ = s;
+            msg_ = s;
           }
           return s;
         } else {
@@ -9970,279 +7883,235 @@ public final class BatchReport {
         }
       }
       /**
-       * <code>optional string attributes = 18;</code>
+       * <code>optional string msg = 4;</code>
        */
       public com.google.protobuf.ByteString
-          getAttributesBytes() {
-        java.lang.Object ref = attributes_;
+          getMsgBytes() {
+        java.lang.Object ref = msg_;
         if (ref instanceof String) {
           com.google.protobuf.ByteString b = 
               com.google.protobuf.ByteString.copyFromUtf8(
                   (java.lang.String) ref);
-          attributes_ = b;
+          msg_ = b;
           return b;
         } else {
           return (com.google.protobuf.ByteString) ref;
         }
       }
       /**
-       * <code>optional string attributes = 18;</code>
+       * <code>optional string msg = 4;</code>
        */
-      public Builder setAttributes(
+      public Builder setMsg(
           java.lang.String value) {
         if (value == null) {
     throw new NullPointerException();
   }
-  bitField0_ |= 0x00020000;
-        attributes_ = value;
+  bitField0_ |= 0x00000008;
+        msg_ = value;
         onChanged();
         return this;
       }
       /**
-       * <code>optional string attributes = 18;</code>
+       * <code>optional string msg = 4;</code>
        */
-      public Builder clearAttributes() {
-        bitField0_ = (bitField0_ & ~0x00020000);
-        attributes_ = getDefaultInstance().getAttributes();
+      public Builder clearMsg() {
+        bitField0_ = (bitField0_ & ~0x00000008);
+        msg_ = getDefaultInstance().getMsg();
         onChanged();
         return this;
       }
       /**
-       * <code>optional string attributes = 18;</code>
+       * <code>optional string msg = 4;</code>
        */
-      public Builder setAttributesBytes(
+      public Builder setMsgBytes(
           com.google.protobuf.ByteString value) {
         if (value == null) {
     throw new NullPointerException();
   }
-  bitField0_ |= 0x00020000;
-        attributes_ = value;
+  bitField0_ |= 0x00000008;
+        msg_ = value;
         onChanged();
         return this;
       }
 
-      private java.lang.Object authorLogin_ = "";
-      /**
-       * <code>optional string author_login = 19;</code>
-       */
-      public boolean hasAuthorLogin() {
-        return ((bitField0_ & 0x00040000) == 0x00040000);
-      }
+      private org.sonar.batch.protocol.Constants.Severity severity_ = org.sonar.batch.protocol.Constants.Severity.INFO;
       /**
-       * <code>optional string author_login = 19;</code>
+       * <code>optional .Severity severity = 5;</code>
        */
-      public java.lang.String getAuthorLogin() {
-        java.lang.Object ref = authorLogin_;
-        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()) {
-            authorLogin_ = s;
-          }
-          return s;
-        } else {
-          return (java.lang.String) ref;
-        }
+      public boolean hasSeverity() {
+        return ((bitField0_ & 0x00000010) == 0x00000010);
       }
       /**
-       * <code>optional string author_login = 19;</code>
+       * <code>optional .Severity severity = 5;</code>
        */
-      public com.google.protobuf.ByteString
-          getAuthorLoginBytes() {
-        java.lang.Object ref = authorLogin_;
-        if (ref instanceof String) {
-          com.google.protobuf.ByteString b = 
-              com.google.protobuf.ByteString.copyFromUtf8(
-                  (java.lang.String) ref);
-          authorLogin_ = b;
-          return b;
-        } else {
-          return (com.google.protobuf.ByteString) ref;
-        }
+      public org.sonar.batch.protocol.Constants.Severity getSeverity() {
+        return severity_;
       }
       /**
-       * <code>optional string author_login = 19;</code>
+       * <code>optional .Severity severity = 5;</code>
        */
-      public Builder setAuthorLogin(
-          java.lang.String value) {
+      public Builder setSeverity(org.sonar.batch.protocol.Constants.Severity value) {
         if (value == null) {
-    throw new NullPointerException();
-  }
-  bitField0_ |= 0x00040000;
-        authorLogin_ = value;
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>optional string author_login = 19;</code>
-       */
-      public Builder clearAuthorLogin() {
-        bitField0_ = (bitField0_ & ~0x00040000);
-        authorLogin_ = getDefaultInstance().getAuthorLogin();
+          throw new NullPointerException();
+        }
+        bitField0_ |= 0x00000010;
+        severity_ = value;
         onChanged();
         return this;
       }
       /**
-       * <code>optional string author_login = 19;</code>
+       * <code>optional .Severity severity = 5;</code>
        */
-      public Builder setAuthorLoginBytes(
-          com.google.protobuf.ByteString value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  bitField0_ |= 0x00040000;
-        authorLogin_ = value;
+      public Builder clearSeverity() {
+        bitField0_ = (bitField0_ & ~0x00000010);
+        severity_ = org.sonar.batch.protocol.Constants.Severity.INFO;
         onChanged();
         return this;
       }
 
-      private long creationDate_ ;
-      /**
-       * <code>optional int64 creation_date = 20;</code>
-       */
-      public boolean hasCreationDate() {
-        return ((bitField0_ & 0x00080000) == 0x00080000);
-      }
-      /**
-       * <code>optional int64 creation_date = 20;</code>
-       */
-      public long getCreationDate() {
-        return creationDate_;
+      private com.google.protobuf.LazyStringList tag_ = com.google.protobuf.LazyStringArrayList.EMPTY;
+      private void ensureTagIsMutable() {
+        if (!((bitField0_ & 0x00000020) == 0x00000020)) {
+          tag_ = new com.google.protobuf.LazyStringArrayList(tag_);
+          bitField0_ |= 0x00000020;
+         }
       }
       /**
-       * <code>optional int64 creation_date = 20;</code>
+       * <code>repeated string tag = 6;</code>
        */
-      public Builder setCreationDate(long value) {
-        bitField0_ |= 0x00080000;
-        creationDate_ = value;
-        onChanged();
-        return this;
+      public com.google.protobuf.ProtocolStringList
+          getTagList() {
+        return tag_.getUnmodifiableView();
       }
       /**
-       * <code>optional int64 creation_date = 20;</code>
+       * <code>repeated string tag = 6;</code>
        */
-      public Builder clearCreationDate() {
-        bitField0_ = (bitField0_ & ~0x00080000);
-        creationDate_ = 0L;
-        onChanged();
-        return this;
+      public int getTagCount() {
+        return tag_.size();
       }
-
-      private long closeDate_ ;
       /**
-       * <code>optional int64 close_date = 21;</code>
+       * <code>repeated string tag = 6;</code>
        */
-      public boolean hasCloseDate() {
-        return ((bitField0_ & 0x00100000) == 0x00100000);
+      public java.lang.String getTag(int index) {
+        return tag_.get(index);
       }
       /**
-       * <code>optional int64 close_date = 21;</code>
+       * <code>repeated string tag = 6;</code>
        */
-      public long getCloseDate() {
-        return closeDate_;
+      public com.google.protobuf.ByteString
+          getTagBytes(int index) {
+        return tag_.getByteString(index);
       }
       /**
-       * <code>optional int64 close_date = 21;</code>
+       * <code>repeated string tag = 6;</code>
        */
-      public Builder setCloseDate(long value) {
-        bitField0_ |= 0x00100000;
-        closeDate_ = value;
+      public Builder setTag(
+          int index, java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  ensureTagIsMutable();
+        tag_.set(index, value);
         onChanged();
         return this;
       }
       /**
-       * <code>optional int64 close_date = 21;</code>
+       * <code>repeated string tag = 6;</code>
        */
-      public Builder clearCloseDate() {
-        bitField0_ = (bitField0_ & ~0x00100000);
-        closeDate_ = 0L;
+      public Builder addTag(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  ensureTagIsMutable();
+        tag_.add(value);
         onChanged();
         return this;
       }
-
-      private long updateDate_ ;
-      /**
-       * <code>optional int64 update_date = 22;</code>
-       */
-      public boolean hasUpdateDate() {
-        return ((bitField0_ & 0x00200000) == 0x00200000);
-      }
       /**
-       * <code>optional int64 update_date = 22;</code>
+       * <code>repeated string tag = 6;</code>
        */
-      public long getUpdateDate() {
-        return updateDate_;
+      public Builder addAllTag(
+          java.lang.Iterable<java.lang.String> values) {
+        ensureTagIsMutable();
+        com.google.protobuf.AbstractMessageLite.Builder.addAll(
+            values, tag_);
+        onChanged();
+        return this;
       }
       /**
-       * <code>optional int64 update_date = 22;</code>
+       * <code>repeated string tag = 6;</code>
        */
-      public Builder setUpdateDate(long value) {
-        bitField0_ |= 0x00200000;
-        updateDate_ = value;
+      public Builder clearTag() {
+        tag_ = com.google.protobuf.LazyStringArrayList.EMPTY;
+        bitField0_ = (bitField0_ & ~0x00000020);
         onChanged();
         return this;
       }
       /**
-       * <code>optional int64 update_date = 22;</code>
+       * <code>repeated string tag = 6;</code>
        */
-      public Builder clearUpdateDate() {
-        bitField0_ = (bitField0_ & ~0x00200000);
-        updateDate_ = 0L;
+      public Builder addTagBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  ensureTagIsMutable();
+        tag_.add(value);
         onChanged();
         return this;
       }
 
-      private long selectedAt_ ;
+      private double effortToFix_ ;
       /**
-       * <code>optional int64 selected_at = 23;</code>
+       * <code>optional double effort_to_fix = 7;</code>
        */
-      public boolean hasSelectedAt() {
-        return ((bitField0_ & 0x00400000) == 0x00400000);
+      public boolean hasEffortToFix() {
+        return ((bitField0_ & 0x00000040) == 0x00000040);
       }
       /**
-       * <code>optional int64 selected_at = 23;</code>
+       * <code>optional double effort_to_fix = 7;</code>
        */
-      public long getSelectedAt() {
-        return selectedAt_;
+      public double getEffortToFix() {
+        return effortToFix_;
       }
       /**
-       * <code>optional int64 selected_at = 23;</code>
+       * <code>optional double effort_to_fix = 7;</code>
        */
-      public Builder setSelectedAt(long value) {
-        bitField0_ |= 0x00400000;
-        selectedAt_ = value;
+      public Builder setEffortToFix(double value) {
+        bitField0_ |= 0x00000040;
+        effortToFix_ = value;
         onChanged();
         return this;
       }
       /**
-       * <code>optional int64 selected_at = 23;</code>
+       * <code>optional double effort_to_fix = 7;</code>
        */
-      public Builder clearSelectedAt() {
-        bitField0_ = (bitField0_ & ~0x00400000);
-        selectedAt_ = 0L;
+      public Builder clearEffortToFix() {
+        bitField0_ = (bitField0_ & ~0x00000040);
+        effortToFix_ = 0D;
         onChanged();
         return this;
       }
 
-      private java.lang.Object diffFields_ = "";
+      private java.lang.Object attributes_ = "";
       /**
-       * <code>optional string diff_fields = 24;</code>
+       * <code>optional string attributes = 8;</code>
        */
-      public boolean hasDiffFields() {
-        return ((bitField0_ & 0x00800000) == 0x00800000);
+      public boolean hasAttributes() {
+        return ((bitField0_ & 0x00000080) == 0x00000080);
       }
       /**
-       * <code>optional string diff_fields = 24;</code>
+       * <code>optional string attributes = 8;</code>
        */
-      public java.lang.String getDiffFields() {
-        java.lang.Object ref = diffFields_;
+      public java.lang.String getAttributes() {
+        java.lang.Object ref = attributes_;
         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()) {
-            diffFields_ = s;
+            attributes_ = s;
           }
           return s;
         } else {
@@ -10250,117 +8119,101 @@ public final class BatchReport {
         }
       }
       /**
-       * <code>optional string diff_fields = 24;</code>
+       * <code>optional string attributes = 8;</code>
        */
       public com.google.protobuf.ByteString
-          getDiffFieldsBytes() {
-        java.lang.Object ref = diffFields_;
+          getAttributesBytes() {
+        java.lang.Object ref = attributes_;
         if (ref instanceof String) {
           com.google.protobuf.ByteString b = 
               com.google.protobuf.ByteString.copyFromUtf8(
                   (java.lang.String) ref);
-          diffFields_ = b;
+          attributes_ = b;
           return b;
         } else {
           return (com.google.protobuf.ByteString) ref;
         }
       }
       /**
-       * <code>optional string diff_fields = 24;</code>
+       * <code>optional string attributes = 8;</code>
        */
-      public Builder setDiffFields(
+      public Builder setAttributes(
           java.lang.String value) {
         if (value == null) {
     throw new NullPointerException();
   }
-  bitField0_ |= 0x00800000;
-        diffFields_ = value;
+  bitField0_ |= 0x00000080;
+        attributes_ = value;
         onChanged();
         return this;
       }
       /**
-       * <code>optional string diff_fields = 24;</code>
+       * <code>optional string attributes = 8;</code>
        */
-      public Builder clearDiffFields() {
-        bitField0_ = (bitField0_ & ~0x00800000);
-        diffFields_ = getDefaultInstance().getDiffFields();
+      public Builder clearAttributes() {
+        bitField0_ = (bitField0_ & ~0x00000080);
+        attributes_ = getDefaultInstance().getAttributes();
         onChanged();
         return this;
       }
       /**
-       * <code>optional string diff_fields = 24;</code>
+       * <code>optional string attributes = 8;</code>
        */
-      public Builder setDiffFieldsBytes(
+      public Builder setAttributesBytes(
           com.google.protobuf.ByteString value) {
         if (value == null) {
     throw new NullPointerException();
   }
-  bitField0_ |= 0x00800000;
-        diffFields_ = value;
-        onChanged();
-        return this;
-      }
-
-      private boolean isChanged_ ;
-      /**
-       * <code>optional bool is_changed = 25;</code>
-       */
-      public boolean hasIsChanged() {
-        return ((bitField0_ & 0x01000000) == 0x01000000);
-      }
-      /**
-       * <code>optional bool is_changed = 25;</code>
-       */
-      public boolean getIsChanged() {
-        return isChanged_;
-      }
-      /**
-       * <code>optional bool is_changed = 25;</code>
-       */
-      public Builder setIsChanged(boolean value) {
-        bitField0_ |= 0x01000000;
-        isChanged_ = value;
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>optional bool is_changed = 25;</code>
-       */
-      public Builder clearIsChanged() {
-        bitField0_ = (bitField0_ & ~0x01000000);
-        isChanged_ = false;
+  bitField0_ |= 0x00000080;
+        attributes_ = value;
         onChanged();
         return this;
       }
 
-      private boolean mustSendNotification_ ;
+      private long debtInMinutes_ ;
       /**
-       * <code>optional bool must_send_notification = 26;</code>
+       * <code>optional int64 debt_in_minutes = 9;</code>
+       *
+       * <pre>
+       * TODO should it be moved to compute engine?
+       * </pre>
        */
-      public boolean hasMustSendNotification() {
-        return ((bitField0_ & 0x02000000) == 0x02000000);
+      public boolean hasDebtInMinutes() {
+        return ((bitField0_ & 0x00000100) == 0x00000100);
       }
       /**
-       * <code>optional bool must_send_notification = 26;</code>
+       * <code>optional int64 debt_in_minutes = 9;</code>
+       *
+       * <pre>
+       * TODO should it be moved to compute engine?
+       * </pre>
        */
-      public boolean getMustSendNotification() {
-        return mustSendNotification_;
+      public long getDebtInMinutes() {
+        return debtInMinutes_;
       }
       /**
-       * <code>optional bool must_send_notification = 26;</code>
+       * <code>optional int64 debt_in_minutes = 9;</code>
+       *
+       * <pre>
+       * TODO should it be moved to compute engine?
+       * </pre>
        */
-      public Builder setMustSendNotification(boolean value) {
-        bitField0_ |= 0x02000000;
-        mustSendNotification_ = value;
+      public Builder setDebtInMinutes(long value) {
+        bitField0_ |= 0x00000100;
+        debtInMinutes_ = value;
         onChanged();
         return this;
       }
       /**
-       * <code>optional bool must_send_notification = 26;</code>
+       * <code>optional int64 debt_in_minutes = 9;</code>
+       *
+       * <pre>
+       * TODO should it be moved to compute engine?
+       * </pre>
        */
-      public Builder clearMustSendNotification() {
-        bitField0_ = (bitField0_ & ~0x02000000);
-        mustSendNotification_ = false;
+      public Builder clearDebtInMinutes() {
+        bitField0_ = (bitField0_ & ~0x00000100);
+        debtInMinutes_ = 0L;
         onChanged();
         return this;
       }
@@ -10412,32 +8265,6 @@ public final class BatchReport {
      */
     org.sonar.batch.protocol.output.BatchReport.IssueOrBuilder getIssueOrBuilder(
         int index);
-
-    /**
-     * <code>optional string component_uuid = 3;</code>
-     *
-     * <pre>
-     * Temporary field for issues on deleted components
-     * </pre>
-     */
-    boolean hasComponentUuid();
-    /**
-     * <code>optional string component_uuid = 3;</code>
-     *
-     * <pre>
-     * Temporary field for issues on deleted components
-     * </pre>
-     */
-    java.lang.String getComponentUuid();
-    /**
-     * <code>optional string component_uuid = 3;</code>
-     *
-     * <pre>
-     * Temporary field for issues on deleted components
-     * </pre>
-     */
-    com.google.protobuf.ByteString
-        getComponentUuidBytes();
   }
   /**
    * Protobuf type {@code Issues}
@@ -10504,12 +8331,6 @@ public final class BatchReport {
               issue_.add(input.readMessage(org.sonar.batch.protocol.output.BatchReport.Issue.PARSER, extensionRegistry));
               break;
             }
-            case 26: {
-              com.google.protobuf.ByteString bs = input.readBytes();
-              bitField0_ |= 0x00000002;
-              componentUuid_ = bs;
-              break;
-            }
           }
         }
       } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -10603,64 +8424,9 @@ public final class BatchReport {
       return issue_.get(index);
     }
 
-    public static final int COMPONENT_UUID_FIELD_NUMBER = 3;
-    private java.lang.Object componentUuid_;
-    /**
-     * <code>optional string component_uuid = 3;</code>
-     *
-     * <pre>
-     * Temporary field for issues on deleted components
-     * </pre>
-     */
-    public boolean hasComponentUuid() {
-      return ((bitField0_ & 0x00000002) == 0x00000002);
-    }
-    /**
-     * <code>optional string component_uuid = 3;</code>
-     *
-     * <pre>
-     * Temporary field for issues on deleted components
-     * </pre>
-     */
-    public java.lang.String getComponentUuid() {
-      java.lang.Object ref = componentUuid_;
-      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()) {
-          componentUuid_ = s;
-        }
-        return s;
-      }
-    }
-    /**
-     * <code>optional string component_uuid = 3;</code>
-     *
-     * <pre>
-     * Temporary field for issues on deleted components
-     * </pre>
-     */
-    public com.google.protobuf.ByteString
-        getComponentUuidBytes() {
-      java.lang.Object ref = componentUuid_;
-      if (ref instanceof java.lang.String) {
-        com.google.protobuf.ByteString b = 
-            com.google.protobuf.ByteString.copyFromUtf8(
-                (java.lang.String) ref);
-        componentUuid_ = b;
-        return b;
-      } else {
-        return (com.google.protobuf.ByteString) ref;
-      }
-    }
-
     private void initFields() {
       componentRef_ = 0;
       issue_ = java.util.Collections.emptyList();
-      componentUuid_ = "";
     }
     private byte memoizedIsInitialized = -1;
     public final boolean isInitialized() {
@@ -10681,9 +8447,6 @@ public final class BatchReport {
       for (int i = 0; i < issue_.size(); i++) {
         output.writeMessage(2, issue_.get(i));
       }
-      if (((bitField0_ & 0x00000002) == 0x00000002)) {
-        output.writeBytes(3, getComponentUuidBytes());
-      }
       getUnknownFields().writeTo(output);
     }
 
@@ -10701,10 +8464,6 @@ public final class BatchReport {
         size += com.google.protobuf.CodedOutputStream
           .computeMessageSize(2, issue_.get(i));
       }
-      if (((bitField0_ & 0x00000002) == 0x00000002)) {
-        size += com.google.protobuf.CodedOutputStream
-          .computeBytesSize(3, getComponentUuidBytes());
-      }
       size += getUnknownFields().getSerializedSize();
       memoizedSerializedSize = size;
       return size;
@@ -10831,8 +8590,6 @@ public final class BatchReport {
         } else {
           issueBuilder_.clear();
         }
-        componentUuid_ = "";
-        bitField0_ = (bitField0_ & ~0x00000004);
         return this;
       }
 
@@ -10874,10 +8631,6 @@ public final class BatchReport {
         } else {
           result.issue_ = issueBuilder_.build();
         }
-        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
-          to_bitField0_ |= 0x00000002;
-        }
-        result.componentUuid_ = componentUuid_;
         result.bitField0_ = to_bitField0_;
         onBuilt();
         return result;
@@ -10923,11 +8676,6 @@ public final class BatchReport {
             }
           }
         }
-        if (other.hasComponentUuid()) {
-          bitField0_ |= 0x00000004;
-          componentUuid_ = other.componentUuid_;
-          onChanged();
-        }
         this.mergeUnknownFields(other.getUnknownFields());
         return this;
       }
@@ -11227,106 +8975,6 @@ public final class BatchReport {
         return issueBuilder_;
       }
 
-      private java.lang.Object componentUuid_ = "";
-      /**
-       * <code>optional string component_uuid = 3;</code>
-       *
-       * <pre>
-       * Temporary field for issues on deleted components
-       * </pre>
-       */
-      public boolean hasComponentUuid() {
-        return ((bitField0_ & 0x00000004) == 0x00000004);
-      }
-      /**
-       * <code>optional string component_uuid = 3;</code>
-       *
-       * <pre>
-       * Temporary field for issues on deleted components
-       * </pre>
-       */
-      public java.lang.String getComponentUuid() {
-        java.lang.Object ref = componentUuid_;
-        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()) {
-            componentUuid_ = s;
-          }
-          return s;
-        } else {
-          return (java.lang.String) ref;
-        }
-      }
-      /**
-       * <code>optional string component_uuid = 3;</code>
-       *
-       * <pre>
-       * Temporary field for issues on deleted components
-       * </pre>
-       */
-      public com.google.protobuf.ByteString
-          getComponentUuidBytes() {
-        java.lang.Object ref = componentUuid_;
-        if (ref instanceof String) {
-          com.google.protobuf.ByteString b = 
-              com.google.protobuf.ByteString.copyFromUtf8(
-                  (java.lang.String) ref);
-          componentUuid_ = b;
-          return b;
-        } else {
-          return (com.google.protobuf.ByteString) ref;
-        }
-      }
-      /**
-       * <code>optional string component_uuid = 3;</code>
-       *
-       * <pre>
-       * Temporary field for issues on deleted components
-       * </pre>
-       */
-      public Builder setComponentUuid(
-          java.lang.String value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  bitField0_ |= 0x00000004;
-        componentUuid_ = value;
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>optional string component_uuid = 3;</code>
-       *
-       * <pre>
-       * Temporary field for issues on deleted components
-       * </pre>
-       */
-      public Builder clearComponentUuid() {
-        bitField0_ = (bitField0_ & ~0x00000004);
-        componentUuid_ = getDefaultInstance().getComponentUuid();
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>optional string component_uuid = 3;</code>
-       *
-       * <pre>
-       * Temporary field for issues on deleted components
-       * </pre>
-       */
-      public Builder setComponentUuidBytes(
-          com.google.protobuf.ByteString value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  bitField0_ |= 0x00000004;
-        componentUuid_ = value;
-        onChanged();
-        return this;
-      }
-
       // @@protoc_insertion_point(builder_scope:Issues)
     }
 
@@ -22057,76 +19705,66 @@ public final class BatchReport {
       descriptor;
   static {
     java.lang.String[] descriptorData = {
-      "\n\022batch_report.proto\032\017constants.proto\"\204\001" +
-      "\n\010Metadata\022\025\n\ranalysis_date\030\001 \001(\003\022\023\n\013pro" +
-      "ject_key\030\002 \001(\t\022\016\n\006branch\030\003 \001(\t\022\032\n\022root_c" +
-      "omponent_ref\030\004 \001(\005\022 \n\030deleted_components" +
-      "_count\030\005 \001(\005\"?\n\rComponentLink\022 \n\004type\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.ComponentTy" +
-      "pe\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.Com",
-      "ponentLink\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.MeasureVa" +
-      "lueType\022\025\n\rboolean_value\030\002 \001(\010\022\021\n\tint_va" +
-      "lue\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\nmet" +
-      "ric_key\030\007 \001(\t\022\023\n\013description\030\t \001(\t\022\020\n\010ru" +
-      "le_key\030\n \001(\t\022\024\n\014alert_status\030\014 \001(\t\022\022\n\nal" +
-      "ert_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\021variatio",
-      "n_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\016charact" +
-      "eric_id\030\023 \001(\005\022\021\n\tperson_id\030\024 \001(\005\"<\n\010Meas" +
-      "ures\022\025\n\rcomponent_ref\030\001 \001(\005\022\031\n\007measure\030\002" +
-      " \003(\0132\010.Measure\"\231\004\n\005Issue\022\027\n\017rule_reposit" +
-      "ory\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.Sever" +
-      "ity\022\013\n\003tag\030\006 \003(\t\022\025\n\reffort_to_fix\030\007 \001(\001\022" +
-      "\016\n\006is_new\030\010 \001(\010\022\014\n\004uuid\030\t \001(\t\022\027\n\017debt_in" +
-      "_minutes\030\n \001(\003\022\022\n\nresolution\030\013 \001(\t\022\016\n\006st",
-      "atus\030\014 \001(\t\022\020\n\010checksum\030\r \001(\t\022\027\n\017manual_s" +
-      "everity\030\016 \001(\010\022\020\n\010reporter\030\017 \001(\t\022\020\n\010assig" +
-      "nee\030\020 \001(\t\022\027\n\017action_plan_key\030\021 \001(\t\022\022\n\nat" +
-      "tributes\030\022 \001(\t\022\024\n\014author_login\030\023 \001(\t\022\025\n\r" +
-      "creation_date\030\024 \001(\003\022\022\n\nclose_date\030\025 \001(\003\022" +
-      "\023\n\013update_date\030\026 \001(\003\022\023\n\013selected_at\030\027 \001(" +
-      "\003\022\023\n\013diff_fields\030\030 \001(\t\022\022\n\nis_changed\030\031 \001" +
-      "(\010\022\036\n\026must_send_notification\030\032 \001(\010\"N\n\006Is" +
-      "sues\022\025\n\rcomponent_ref\030\001 \001(\005\022\025\n\005issue\030\002 \003" +
-      "(\0132\006.Issue\022\026\n\016component_uuid\030\003 \001(\t\"\254\001\n\nC",
-      "hangesets\022\025\n\rcomponent_ref\030\001 \001(\005\022(\n\tchan" +
-      "geset\030\002 \003(\0132\025.Changesets.Changeset\022 \n\024ch" +
-      "angesetIndexByLine\030\003 \003(\005B\002\020\001\032;\n\tChangese" +
-      "t\022\020\n\010revision\030\001 \001(\t\022\016\n\006author\030\002 \001(\t\022\014\n\004d" +
-      "ate\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_f" +
-      "ile_key\030\003 \001(\t\"M\n\013Duplication\022\037\n\017origin_p" +
-      "osition\030\001 \001(\0132\006.Range\022\035\n\tduplicate\030\002 \003(\013" +
-      "2\n.Duplicate\"H\n\014Duplications\022\025\n\rcomponen" +
-      "t_ref\030\001 \001(\005\022!\n\013duplication\030\002 \003(\0132\014.Dupli",
-      "cation\"W\n\005Range\022\022\n\nstart_line\030\001 \001(\005\022\020\n\010e" +
-      "nd_line\030\002 \001(\005\022\024\n\014start_offset\030\003 \001(\005\022\022\n\ne" +
-      "nd_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.Symbols.Symbol\032@\n" +
-      "\006Symbol\022\033\n\013declaration\030\001 \001(\0132\006.Range\022\031\n\t" +
-      "reference\030\002 \003(\0132\006.Range\"\260\001\n\010Coverage\022\014\n\004" +
-      "line\030\001 \001(\005\022\022\n\nconditions\030\002 \001(\005\022\017\n\007ut_hit" +
-      "s\030\003 \001(\010\022\017\n\007it_hits\030\004 \001(\010\022\035\n\025ut_covered_c" +
-      "onditions\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\022SyntaxHighlighting\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" +
-      ".TestStatus\022\026\n\016duration_in_ms\030\003 \001(\003\022\022\n\ns" +
-      "tacktrace\030\004 \001(\t\022\013\n\003msg\030\005 \001(\t\"\221\001\n\016Coverag" +
-      "eDetail\022\021\n\ttest_name\030\001 \001(\t\0221\n\014covered_fi" +
-      "le\030\002 \003(\0132\033.CoverageDetail.CoveredFile\0329\n" +
-      "\013CoveredFile\022\020\n\010file_ref\030\001 \001(\005\022\030\n\014covere" +
-      "d_line\030\002 \003(\005B\002\020\001B#\n\037org.sonar.batch.prot" +
-      "ocol.outputH\001"
+      "\n\022batch_report.proto\032\017constants.proto\"b\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"
     };
     com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
         new com.google.protobuf.Descriptors.FileDescriptor.    InternalDescriptorAssigner() {
@@ -22146,7 +19784,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", "DeletedComponentsCount", });
+        new java.lang.String[] { "AnalysisDate", "ProjectKey", "Branch", "RootComponentRef", });
     internal_static_ComponentLink_descriptor =
       getDescriptor().getMessageTypes().get(1);
     internal_static_ComponentLink_fieldAccessorTable = new
@@ -22176,13 +19814,13 @@ public final class BatchReport {
     internal_static_Issue_fieldAccessorTable = new
       com.google.protobuf.GeneratedMessage.FieldAccessorTable(
         internal_static_Issue_descriptor,
-        new java.lang.String[] { "RuleRepository", "RuleKey", "Line", "Msg", "Severity", "Tag", "EffortToFix", "IsNew", "Uuid", "DebtInMinutes", "Resolution", "Status", "Checksum", "ManualSeverity", "Reporter", "Assignee", "ActionPlanKey", "Attributes", "AuthorLogin", "CreationDate", "CloseDate", "UpdateDate", "SelectedAt", "DiffFields", "IsChanged", "MustSendNotification", });
+        new java.lang.String[] { "RuleRepository", "RuleKey", "Line", "Msg", "Severity", "Tag", "EffortToFix", "Attributes", "DebtInMinutes", });
     internal_static_Issues_descriptor =
       getDescriptor().getMessageTypes().get(6);
     internal_static_Issues_fieldAccessorTable = new
       com.google.protobuf.GeneratedMessage.FieldAccessorTable(
         internal_static_Issues_descriptor,
-        new java.lang.String[] { "ComponentRef", "Issue", "ComponentUuid", });
+        new java.lang.String[] { "ComponentRef", "Issue", });
     internal_static_Changesets_descriptor =
       getDescriptor().getMessageTypes().get(7);
     internal_static_Changesets_fieldAccessorTable = new
index 14455532309ffda5cdc7ef1bb373234ca9d42963..fe310bafadfde763679ec9c1ef7a71fa23de2290 100644 (file)
@@ -79,15 +79,6 @@ public class BatchReportReader {
     return Collections.emptyList();
   }
 
-  public Issues readDeletedComponentIssues(int deletedComponentRef) {
-    File file = fileStructure.fileFor(FileStructure.Domain.ISSUES_ON_DELETED, deletedComponentRef);
-    if (!doesFileExists(file)) {
-      throw new IllegalStateException("Unable to find report for deleted component #" + deletedComponentRef);
-    }
-    // all the issues are loaded in memory
-    return ProtobufUtil.readFile(file, Issues.PARSER);
-  }
-
   public List<BatchReport.Duplication> readComponentDuplications(int componentRef) {
     File file = fileStructure.fileFor(FileStructure.Domain.DUPLICATIONS, componentRef);
     if (doesFileExists(file)) {
index 1a771af3b41d1579654f0cbe7a0ea0d5cead3540..b9be0da6170c4d370790d8919691cb221308c26b 100644 (file)
@@ -80,20 +80,6 @@ public class BatchReportWriter {
     return file;
   }
 
-  /**
-   * Issues on components which have been deleted are stored in another location.
-   * Temporary hack, waiting for computation stack
-   */
-  public File writeDeletedComponentIssues(int componentRef, String componentUuid, Iterable<BatchReport.Issue> issues) {
-    BatchReport.Issues.Builder issuesBuilder = BatchReport.Issues.newBuilder();
-    issuesBuilder.setComponentRef(componentRef);
-    issuesBuilder.setComponentUuid(componentUuid);
-    issuesBuilder.addAllIssue(issues);
-    File file = fileStructure.fileFor(FileStructure.Domain.ISSUES_ON_DELETED, componentRef);
-    ProtobufUtil.writeToFile(issuesBuilder.build(), file);
-    return file;
-  }
-
   public File writeComponentDuplications(int componentRef, Iterable<BatchReport.Duplication> duplications) {
     BatchReport.Duplications.Builder builder = BatchReport.Duplications.newBuilder();
     builder.setComponentRef(componentRef);
index 52d6cd732d5dccbba479973ba7f7aabffbbad130..0ecee214e9318cb1b99dce5f00788b5fbc451e11 100644 (file)
@@ -45,9 +45,6 @@ message Metadata {
   optional string project_key = 2;
   optional string branch = 3;
   optional int32 root_component_ref = 4;
-
-  // temporary fields used during development of computation stack
-  optional int32 deleted_components_count = 5;
 }
 
 message ComponentLink {
@@ -111,36 +108,16 @@ message Issue {
   optional string msg = 4;
   optional Severity severity = 5;
   repeated string tag = 6;
-
-  // temporary fields during development of computation stack
   optional double effort_to_fix = 7;
-  optional bool is_new = 8;
-  optional string uuid = 9;
-  optional int64 debt_in_minutes = 10;
-  optional string resolution = 11;
-  optional string status = 12;
-  optional string checksum = 13;
-  optional bool manual_severity = 14;
-  optional string reporter = 15;
-  optional string assignee = 16;
-  optional string action_plan_key = 17;
-  optional string attributes = 18;
-  optional string author_login = 19;
-  optional int64 creation_date = 20;
-  optional int64 close_date = 21;
-  optional int64 update_date = 22;
-  optional int64 selected_at = 23;
-  optional string diff_fields = 24;
-  optional bool is_changed = 25;
-  optional bool must_send_notification = 26;
+  optional string attributes = 8;
+
+  // TODO should it be moved to compute engine?
+  optional int64 debt_in_minutes = 9;
 }
 
 message Issues {
   optional int32 component_ref = 1;
   repeated Issue issue = 2;
-
-  // Temporary field for issues on deleted components
-  optional string component_uuid = 3;
 }
 
 message Changesets {
index 2738f54208824364785550909774783b44687da2..805cda4dc4a9745d3be0d045db379a892bbd6aea 100644 (file)
@@ -56,14 +56,12 @@ public class BatchReportReaderTest {
     BatchReport.Metadata.Builder metadata = BatchReport.Metadata.newBuilder()
       .setAnalysisDate(15000000L)
       .setProjectKey("PROJECT_A")
-      .setRootComponentRef(1)
-      .setDeletedComponentsCount(10);
+      .setRootComponentRef(1);
     writer.writeMetadata(metadata.build());
 
     BatchReport.Metadata readMetadata = sut.readMetadata();
     assertThat(readMetadata.getAnalysisDate()).isEqualTo(15000000L);
     assertThat(readMetadata.getProjectKey()).isEqualTo("PROJECT_A");
-    assertThat(readMetadata.getDeletedComponentsCount()).isEqualTo(10);
     assertThat(readMetadata.getRootComponentRef()).isEqualTo(1);
   }
 
@@ -92,23 +90,12 @@ public class BatchReportReaderTest {
   public void read_issues() {
     BatchReportWriter writer = new BatchReportWriter(dir);
     BatchReport.Issue issue = BatchReport.Issue.newBuilder()
-      .setUuid("ISSUE_A")
       .setLine(50)
       .build();
     writer.writeComponentIssues(1, Arrays.asList(issue));
-    writer.writeDeletedComponentIssues(1, "compUuid", Arrays.asList(issue));
 
     assertThat(sut.readComponentIssues(1)).hasSize(1);
     assertThat(sut.readComponentIssues(200)).isEmpty();
-
-    BatchReport.Issues deletedComponentIssues = sut.readDeletedComponentIssues(1);
-    assertThat(deletedComponentIssues.getComponentUuid()).isEqualTo("compUuid");
-    assertThat(deletedComponentIssues.getIssueList()).hasSize(1);
-  }
-
-  @Test(expected = IllegalStateException.class)
-  public void fail_if_missing_file_on_deleted_component() {
-    sut.readDeletedComponentIssues(UNKNOWN_COMPONENT_REF);
   }
 
   @Test
index 46d8749259c73d939e93909f00fe8553fd7a9c5d..cf33a8f6d8f8ef57e7d170c342cf91f799c2aef9 100644 (file)
@@ -101,7 +101,6 @@ public class BatchReportWriterTest {
 
     // write data
     BatchReport.Issue issue = BatchReport.Issue.newBuilder()
-      .setUuid("ISSUE_A")
       .setLine(50)
       .setMsg("the message")
       .build();
@@ -113,30 +112,6 @@ public class BatchReportWriterTest {
     assertThat(file).exists().isFile();
     BatchReport.Issues read = ProtobufUtil.readFile(file, BatchReport.Issues.PARSER);
     assertThat(read.getComponentRef()).isEqualTo(1);
-    assertThat(read.hasComponentUuid()).isFalse();
-    assertThat(read.getIssueCount()).isEqualTo(1);
-  }
-
-  @Test
-  public void write_issues_of_deleted_component() {
-    // no data yet
-    assertThat(sut.hasComponentData(FileStructure.Domain.ISSUES_ON_DELETED, 1)).isFalse();
-
-    // write data
-    BatchReport.Issue issue = BatchReport.Issue.newBuilder()
-      .setUuid("ISSUE_A")
-      .setLine(50)
-      .setMsg("the message")
-      .build();
-
-    sut.writeDeletedComponentIssues(1, "componentUuid", Arrays.asList(issue));
-
-    assertThat(sut.hasComponentData(FileStructure.Domain.ISSUES_ON_DELETED, 1)).isTrue();
-    File file = sut.getFileStructure().fileFor(FileStructure.Domain.ISSUES_ON_DELETED, 1);
-    assertThat(file).exists().isFile();
-    BatchReport.Issues read = ProtobufUtil.readFile(file, BatchReport.Issues.PARSER);
-    assertThat(read.getComponentRef()).isEqualTo(1);
-    assertThat(read.getComponentUuid()).isEqualTo("componentUuid");
     assertThat(read.getIssueCount()).isEqualTo(1);
   }
 
index d40e1c223f771d473ae694446564174ba33b38f5..879ae9afb824803ffb63c9cbace44af45cd6b253 100644 (file)
@@ -40,10 +40,7 @@ import org.sonar.batch.cpd.CpdComponents;
 import org.sonar.batch.debt.DebtDecorator;
 import org.sonar.batch.debt.IssueChangelogDebtCalculator;
 import org.sonar.batch.debt.NewDebtDecorator;
-import org.sonar.batch.issue.tracking.InitialOpenIssuesSensor;
-import org.sonar.batch.issue.tracking.IssueHandlers;
 import org.sonar.batch.issue.tracking.IssueTracking;
-import org.sonar.batch.issue.tracking.IssueTrackingDecorator;
 import org.sonar.batch.language.LanguageDistributionDecorator;
 import org.sonar.batch.scan.report.ConsoleReport;
 import org.sonar.batch.scan.report.HtmlReport;
@@ -92,11 +89,6 @@ public class BatchComponents {
       DebtDecorator.class,
       NewDebtDecorator.class,
 
-      // Issue tracking
-      IssueTrackingDecorator.class,
-      IssueHandlers.class,
-      InitialOpenIssuesSensor.class,
-
       // to be moved to compute engine
       UnitTestDecorator.class,
       LineCoverageDecorator.class,
index 5ddb7e459498812c369d22bcdff0754585bf373f..b339ead086a171c5a9b875bd522544734c670b69 100644 (file)
@@ -38,7 +38,7 @@ import org.sonar.api.batch.rule.Rules;
 import org.sonar.api.component.ResourcePerspectives;
 import org.sonar.api.issue.Issuable;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.api.measures.CoreMetrics;
 import org.sonar.api.measures.Measure;
 import org.sonar.api.measures.MeasuresFilters;
index fb882a7a0eb9bc94eecb37cfdc2b0166ee695517..5d34e8f89defee1cfe5a1387be3b8c81c087b39d 100644 (file)
@@ -34,8 +34,8 @@ 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.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.FieldDiffs;
+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;
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/ScanPersister.java b/sonar-batch/src/main/java/org/sonar/batch/index/ScanPersister.java
deleted file mode 100644 (file)
index 88b749e..0000000
+++ /dev/null
@@ -1,29 +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.index;
-
-import org.sonar.api.batch.BatchSide;
-
-@BatchSide
-public interface ScanPersister {
-
-  void persist();
-
-}
index 89561865d63a0281522e69b764eb3b76b9cb1555..9dd268a8d2231639f27288da35926163e4ba1479 100644 (file)
@@ -23,7 +23,7 @@ import com.google.common.collect.Lists;
 import java.util.List;
 import org.sonar.api.issue.Issuable;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.api.resources.Project;
 import org.sonar.batch.index.BatchComponent;
 import org.sonar.core.issue.DefaultIssueBuilder;
index 1cc682c0e34962c6adb0f82476323cf6a865717a..ed9de9a5defa0eecdacd8174c3c9f1645c91598a 100644 (file)
@@ -23,7 +23,7 @@ import com.google.common.base.Predicate;
 import com.google.common.collect.Iterables;
 import org.sonar.api.issue.Issue;
 import org.sonar.api.issue.ProjectIssues;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 
 import javax.annotation.Nullable;
 
index dc5daaaafb47807370c9a4bdf2ecca18ee3a642e..52a29fb74831b81d26beb9a37c66e4382e4c007a 100644 (file)
@@ -20,7 +20,7 @@
 package org.sonar.batch.issue;
 
 import org.sonar.api.batch.BatchSide;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.batch.index.Cache;
 import org.sonar.batch.index.Caches;
 
index 0e623246b50cc649187ef22211768449194012b9..70bd4d54d5bf897fd370caa8051398aa3bcd20cf 100644 (file)
@@ -21,7 +21,7 @@ package org.sonar.batch.issue;
 
 import org.sonar.api.batch.BatchSide;
 import org.sonar.api.issue.batch.IssueFilter;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 
 @BatchSide
 public class IssueFilters {
index 2586d4f898ad1e066e8e555aa5b907bdda718408..23fa523df443fca9e2c7404cd263ff48e1609a72 100644 (file)
@@ -28,7 +28,7 @@ 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.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.api.resources.Project;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rules.Violation;
diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/tracking/InitialOpenIssuesSensor.java b/sonar-batch/src/main/java/org/sonar/batch/issue/tracking/InitialOpenIssuesSensor.java
deleted file mode 100644 (file)
index ef39e6b..0000000
+++ /dev/null
@@ -1,93 +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.issue.tracking;
-
-import java.util.Calendar;
-import java.util.Date;
-import org.apache.commons.lang.time.DateUtils;
-import org.apache.ibatis.session.ResultContext;
-import org.apache.ibatis.session.ResultHandler;
-import org.sonar.api.batch.RequiresDB;
-import org.sonar.api.batch.Sensor;
-import org.sonar.api.batch.SensorContext;
-import org.sonar.api.resources.Project;
-import org.sonar.core.issue.db.IssueChangeDao;
-import org.sonar.core.issue.db.IssueChangeDto;
-import org.sonar.core.issue.db.IssueDao;
-import org.sonar.core.issue.db.IssueDto;
-import org.sonar.core.resource.ResourceDao;
-import org.sonar.core.resource.ResourceDto;
-import org.sonar.core.resource.ResourceQuery;
-
-/**
- * Load all the issues referenced during the previous scan.
- */
-@RequiresDB
-public class InitialOpenIssuesSensor implements Sensor {
-
-  private final InitialOpenIssuesStack initialOpenIssuesStack;
-  private final IssueDao issueDao;
-  private final IssueChangeDao issueChangeDao;
-  private final ResourceDao resourceDao;
-
-  public InitialOpenIssuesSensor(InitialOpenIssuesStack initialOpenIssuesStack, IssueDao issueDao, IssueChangeDao issueChangeDao, ResourceDao resourceDao) {
-    this.initialOpenIssuesStack = initialOpenIssuesStack;
-    this.issueDao = issueDao;
-    this.issueChangeDao = issueChangeDao;
-    this.resourceDao = resourceDao;
-  }
-
-  @Override
-  public boolean shouldExecuteOnProject(Project project) {
-    return true;
-  }
-
-  @Override
-  public void analyse(Project project, SensorContext context) {
-    ResourceDto module = resourceDao.getResource(ResourceQuery.create().setKey(project.getEffectiveKey()));
-    if (module != null) {
-      long moduleId = module.getId();
-      // Adding one second is a hack for resolving conflicts with concurrent user
-      // changes during issue persistence
-      final Date now = DateUtils.addSeconds(DateUtils.truncate(new Date(), Calendar.MILLISECOND), 1);
-      issueDao.selectNonClosedIssuesByModule(moduleId, new ResultHandler() {
-        @Override
-        public void handleResult(ResultContext rc) {
-          IssueDto dto = (IssueDto) rc.getResultObject();
-          dto.setSelectedAt(now.getTime());
-          initialOpenIssuesStack.addIssue(dto);
-        }
-      });
-
-      issueChangeDao.selectChangelogOnNonClosedIssuesByModuleAndType(moduleId, new ResultHandler() {
-        @Override
-        public void handleResult(ResultContext rc) {
-          IssueChangeDto dto = (IssueChangeDto) rc.getResultObject();
-          initialOpenIssuesStack.addChangelog(dto);
-        }
-      });
-    }
-  }
-
-  @Override
-  public String toString() {
-    return getClass().getSimpleName();
-  }
-}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/tracking/InitialOpenIssuesStack.java b/sonar-batch/src/main/java/org/sonar/batch/issue/tracking/InitialOpenIssuesStack.java
deleted file mode 100644 (file)
index ea7b9fb..0000000
+++ /dev/null
@@ -1,86 +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.issue.tracking;
-
-import org.sonar.api.batch.BatchSide;
-import org.sonar.api.batch.InstantiationStrategy;
-import org.sonar.batch.index.Cache;
-import org.sonar.batch.index.Caches;
-import org.sonar.core.issue.db.IssueChangeDto;
-import org.sonar.core.issue.db.IssueDto;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-import static com.google.common.collect.Lists.newArrayList;
-
-@BatchSide
-@InstantiationStrategy(InstantiationStrategy.PER_BATCH)
-public class InitialOpenIssuesStack {
-
-  private final Cache<IssueDto> issuesCache;
-  private final Cache<ArrayList<IssueChangeDto>> issuesChangelogCache;
-
-  public InitialOpenIssuesStack(Caches caches) {
-    issuesCache = caches.createCache("last-open-issues");
-    issuesChangelogCache = caches.createCache("issues-changelog");
-  }
-
-  public InitialOpenIssuesStack addIssue(IssueDto issueDto) {
-    issuesCache.put(issueDto.getComponentKey(), issueDto.getKee(), issueDto);
-    return this;
-  }
-
-  public List<ServerIssue> selectAndRemoveIssues(String componentKey) {
-    Iterable<IssueDto> issues = issuesCache.values(componentKey);
-    List<ServerIssue> result = newArrayList();
-    for (IssueDto issue : issues) {
-      result.add(new ServerIssueFromDb(issue));
-    }
-    issuesCache.clear(componentKey);
-    return result;
-  }
-
-  public Iterable<IssueDto> selectAllIssues() {
-    return issuesCache.values();
-  }
-
-  public InitialOpenIssuesStack addChangelog(IssueChangeDto issueChangeDto) {
-    List<IssueChangeDto> changeDtos = issuesChangelogCache.get(issueChangeDto.getIssueKey());
-    if (changeDtos == null) {
-      changeDtos = newArrayList();
-    }
-    changeDtos.add(issueChangeDto);
-    issuesChangelogCache.put(issueChangeDto.getIssueKey(), newArrayList(changeDtos));
-    return this;
-  }
-
-  public List<IssueChangeDto> selectChangelog(String issueKey) {
-    List<IssueChangeDto> changeDtos = issuesChangelogCache.get(issueKey);
-    return changeDtos != null ? changeDtos : Collections.<IssueChangeDto>emptyList();
-  }
-
-  public void clear() {
-    issuesCache.clear();
-    issuesChangelogCache.clear();
-  }
-}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/tracking/IssueHandlers.java b/sonar-batch/src/main/java/org/sonar/batch/issue/tracking/IssueHandlers.java
deleted file mode 100644 (file)
index c7ef0dd..0000000
+++ /dev/null
@@ -1,141 +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.issue.tracking;
-
-import org.sonar.api.batch.BatchSide;
-import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.IssueHandler;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.IssueChangeContext;
-import org.sonar.api.user.User;
-import org.sonar.core.issue.IssueUpdater;
-import org.sonar.core.user.DefaultUser;
-
-import javax.annotation.Nullable;
-
-@BatchSide
-public class IssueHandlers {
-  private final IssueHandler[] handlers;
-  private final DefaultContext context;
-
-  public IssueHandlers(IssueUpdater updater, IssueHandler[] handlers) {
-    this.handlers = handlers;
-    this.context = new DefaultContext(updater);
-  }
-
-  public IssueHandlers(IssueUpdater updater) {
-    this(updater, new IssueHandler[0]);
-  }
-
-  public void execute(DefaultIssue issue, IssueChangeContext changeContext) {
-    context.reset(issue, changeContext);
-    for (IssueHandler handler : handlers) {
-      handler.onIssue(context);
-    }
-  }
-
-  static class DefaultContext implements IssueHandler.Context {
-    private final IssueUpdater updater;
-    private DefaultIssue issue;
-    private IssueChangeContext changeContext;
-
-    private DefaultContext(IssueUpdater updater) {
-      this.updater = updater;
-    }
-
-    private void reset(DefaultIssue i, IssueChangeContext changeContext) {
-      this.issue = i;
-      this.changeContext = changeContext;
-    }
-
-    @Override
-    public Issue issue() {
-      return issue;
-    }
-
-    @Override
-    public boolean isNew() {
-      return issue.isNew();
-    }
-
-    @Override
-    public boolean isEndOfLife() {
-      return issue.isEndOfLife();
-    }
-
-    @Override
-    public IssueHandler.Context setLine(@Nullable Integer line) {
-      updater.setLine(issue, line);
-      return this;
-    }
-
-    @Override
-    public IssueHandler.Context setMessage(@Nullable String s) {
-      updater.setMessage(issue, s, changeContext);
-      return this;
-    }
-
-    @Override
-    public IssueHandler.Context setSeverity(String severity) {
-      updater.setSeverity(issue, severity, changeContext);
-      return this;
-    }
-
-    @Override
-    public IssueHandler.Context setAuthorLogin(@Nullable String login) {
-      updater.setAuthorLogin(issue, login, changeContext);
-      return this;
-    }
-
-    @Override
-    public IssueHandler.Context setEffortToFix(@Nullable Double d) {
-      updater.setEffortToFix(issue, d, changeContext);
-      return this;
-    }
-
-    @Override
-    public IssueHandler.Context setAttribute(String key, @Nullable String value) {
-      throw new UnsupportedOperationException("TODO");
-    }
-
-    @Override
-    public IssueHandler.Context assign(@Nullable String assignee) {
-      User user = null;
-      if (assignee != null) {
-        user = new DefaultUser().setLogin(assignee).setName(assignee);
-      }
-      updater.assign(issue, user, changeContext);
-      return this;
-    }
-
-    @Override
-    public IssueHandler.Context assign(@Nullable User user) {
-      updater.assign(issue, user, changeContext);
-      return this;
-    }
-
-    @Override
-    public IssueHandler.Context addComment(String text) {
-      updater.addComment(issue, text, changeContext);
-      return this;
-    }
-  }
-
-}
index bd339571e51f9afb983940715180a45b0e13ada0..ee08935732038e9fa07fb9b30c1fc045c8025374 100644 (file)
@@ -29,7 +29,7 @@ import com.google.common.collect.Maps;
 import com.google.common.collect.Multimap;
 import org.sonar.api.batch.BatchSide;
 import org.sonar.api.batch.InstantiationStrategy;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 
 import javax.annotation.Nullable;
 
diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/tracking/IssueTrackingDecorator.java b/sonar-batch/src/main/java/org/sonar/batch/issue/tracking/IssueTrackingDecorator.java
deleted file mode 100644 (file)
index 7c05341..0000000
+++ /dev/null
@@ -1,279 +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.issue.tracking;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Strings;
-import com.google.common.collect.Lists;
-import org.apache.commons.lang.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-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.batch.fs.InputFile;
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.component.ResourcePerspectives;
-import org.sonar.api.issue.Issuable;
-import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.IssueChangeContext;
-import org.sonar.api.profiles.RulesProfile;
-import org.sonar.api.resources.File;
-import org.sonar.api.resources.Project;
-import org.sonar.api.resources.Resource;
-import org.sonar.api.resources.ResourceUtils;
-import org.sonar.api.rules.ActiveRule;
-import org.sonar.api.rules.Rule;
-import org.sonar.api.rules.RuleFinder;
-import org.sonar.api.utils.Duration;
-import org.sonar.api.utils.KeyValueFormat;
-import org.sonar.batch.issue.IssueCache;
-import org.sonar.batch.scan.filesystem.InputPathCache;
-import org.sonar.core.issue.IssueUpdater;
-import org.sonar.core.issue.db.IssueChangeDto;
-import org.sonar.core.issue.db.IssueDto;
-import org.sonar.core.issue.workflow.IssueWorkflow;
-
-import java.util.Collection;
-
-@DependsUpon(DecoratorBarriers.ISSUES_ADDED)
-@DependedUpon(DecoratorBarriers.ISSUES_TRACKED)
-@RequiresDB
-public class IssueTrackingDecorator implements Decorator {
-
-  private static final Logger LOG = LoggerFactory.getLogger(IssueTrackingDecorator.class);
-
-  private final IssueCache issueCache;
-  private final InitialOpenIssuesStack initialOpenIssues;
-  private final IssueTracking tracking;
-  private final ServerLineHashesLoader lastLineHashes;
-  private final IssueHandlers handlers;
-  private final IssueWorkflow workflow;
-  private final IssueUpdater updater;
-  private final IssueChangeContext changeContext;
-  private final ResourcePerspectives perspectives;
-  private final RulesProfile rulesProfile;
-  private final RuleFinder ruleFinder;
-  private final InputPathCache inputPathCache;
-  private final Project project;
-
-  public IssueTrackingDecorator(IssueCache issueCache, InitialOpenIssuesStack initialOpenIssues, IssueTracking tracking,
-    ServerLineHashesLoader lastLineHashes,
-    IssueHandlers handlers, IssueWorkflow workflow,
-    IssueUpdater updater,
-    Project project,
-    ResourcePerspectives perspectives,
-    RulesProfile rulesProfile,
-    RuleFinder ruleFinder, InputPathCache inputPathCache) {
-    this.issueCache = issueCache;
-    this.initialOpenIssues = initialOpenIssues;
-    this.tracking = tracking;
-    this.lastLineHashes = lastLineHashes;
-    this.handlers = handlers;
-    this.workflow = workflow;
-    this.updater = updater;
-    this.project = project;
-    this.inputPathCache = inputPathCache;
-    this.changeContext = IssueChangeContext.createScan(project.getAnalysisDate());
-    this.perspectives = perspectives;
-    this.rulesProfile = rulesProfile;
-    this.ruleFinder = ruleFinder;
-  }
-
-  @Override
-  public boolean shouldExecuteOnProject(Project project) {
-    return true;
-  }
-
-  @Override
-  public void decorate(Resource resource, DecoratorContext context) {
-    Issuable issuable = perspectives.as(Issuable.class, resource);
-    if (issuable != null) {
-      doDecorate(resource);
-    }
-  }
-
-  @VisibleForTesting
-  void doDecorate(Resource resource) {
-    Collection<DefaultIssue> issues = Lists.newArrayList();
-    for (Issue issue : issueCache.byComponent(resource.getEffectiveKey())) {
-      issues.add((DefaultIssue) issue);
-    }
-    issueCache.clear(resource.getEffectiveKey());
-    // issues = all the issues created by rule engines during this module scan and not excluded by filters
-
-    // all the issues that are not closed in db before starting this module scan, including manual issues
-    Collection<ServerIssue> dbOpenIssues = initialOpenIssues.selectAndRemoveIssues(resource.getEffectiveKey());
-
-    SourceHashHolder sourceHashHolder = null;
-    if (ResourceUtils.isFile(resource)) {
-      File sonarFile = (File) resource;
-      InputFile file = inputPathCache.getFile(project.getEffectiveKey(), sonarFile.getPath());
-      if (file == null) {
-        throw new IllegalStateException("File " + resource + " was not found in InputPath cache");
-      }
-      sourceHashHolder = new SourceHashHolder((DefaultInputFile) file, lastLineHashes);
-    }
-
-    IssueTrackingResult trackingResult = tracking.track(sourceHashHolder, dbOpenIssues, issues);
-
-    // unmatched = issues that have been resolved + issues on disabled/removed rules + manual issues
-    addUnmatched(trackingResult.unmatched(), sourceHashHolder, issues);
-
-    mergeMatched(trackingResult);
-
-    if (ResourceUtils.isProject(resource)) {
-      // issues that relate to deleted components
-      addIssuesOnDeletedComponents(issues);
-    }
-
-    for (DefaultIssue issue : issues) {
-      workflow.doAutomaticTransition(issue, changeContext);
-      handlers.execute(issue, changeContext);
-      issueCache.put(issue);
-    }
-  }
-
-  @VisibleForTesting
-  protected void mergeMatched(IssueTrackingResult result) {
-    for (DefaultIssue issue : result.matched()) {
-      IssueDto ref = ((ServerIssueFromDb) result.matching(issue)).getDto();
-
-      // invariant fields
-      issue.setKey(ref.getKee());
-      issue.setCreationDate(ref.getIssueCreationDate());
-      issue.setUpdateDate(ref.getIssueUpdateDate());
-      issue.setCloseDate(ref.getIssueCloseDate());
-
-      // non-persisted fields
-      issue.setNew(false);
-      issue.setEndOfLife(false);
-      issue.setOnDisabledRule(false);
-      issue.setSelectedAt(ref.getSelectedAt());
-
-      // fields to update with old values
-      issue.setActionPlanKey(ref.getActionPlanKey());
-      issue.setResolution(ref.getResolution());
-      issue.setStatus(ref.getStatus());
-      issue.setAssignee(ref.getAssignee());
-      issue.setAuthorLogin(ref.getAuthorLogin());
-      issue.setTags(ref.getTags());
-
-      if (ref.getIssueAttributes() != null) {
-        issue.setAttributes(KeyValueFormat.parse(ref.getIssueAttributes()));
-      }
-
-      // populate existing changelog
-      Collection<IssueChangeDto> issueChangeDtos = initialOpenIssues.selectChangelog(issue.key());
-      for (IssueChangeDto issueChangeDto : issueChangeDtos) {
-        issue.addChange(issueChangeDto.toFieldDiffs());
-      }
-
-      // fields to update with current values
-      if (ref.isManualSeverity()) {
-        issue.setManualSeverity(true);
-        issue.setSeverity(ref.getSeverity());
-      } else {
-        updater.setPastSeverity(issue, ref.getSeverity(), changeContext);
-      }
-      updater.setPastLine(issue, ref.getLine());
-      updater.setPastMessage(issue, ref.getMessage(), changeContext);
-      updater.setPastEffortToFix(issue, ref.getEffortToFix(), changeContext);
-      Long debtInMinutes = ref.getDebt();
-      Duration previousTechnicalDebt = debtInMinutes != null ? Duration.create(debtInMinutes) : null;
-      updater.setPastTechnicalDebt(issue, previousTechnicalDebt, changeContext);
-      updater.setPastProject(issue, ref.getProjectKey(), changeContext);
-    }
-  }
-
-  private void addUnmatched(Collection<ServerIssue> unmatchedIssues, SourceHashHolder sourceHashHolder, Collection<DefaultIssue> issues) {
-    for (ServerIssue unmatchedIssue : unmatchedIssues) {
-      IssueDto unmatchedDto = ((ServerIssueFromDb) unmatchedIssue).getDto();
-      DefaultIssue unmatched = unmatchedDto.toDefaultIssue();
-      if (StringUtils.isNotBlank(unmatchedDto.getReporter()) && !Issue.STATUS_CLOSED.equals(unmatchedDto.getStatus())) {
-        relocateManualIssue(unmatched, unmatchedDto, sourceHashHolder);
-      }
-      updateUnmatchedIssue(unmatched, false /* manual issues can be kept open */);
-      issues.add(unmatched);
-    }
-  }
-
-  private void addIssuesOnDeletedComponents(Collection<DefaultIssue> issues) {
-    for (IssueDto deadDto : initialOpenIssues.selectAllIssues()) {
-      DefaultIssue dead = deadDto.toDefaultIssue();
-      updateUnmatchedIssue(dead, true);
-      issues.add(dead);
-    }
-    initialOpenIssues.clear();
-  }
-
-  private void updateUnmatchedIssue(DefaultIssue issue, boolean forceEndOfLife) {
-    issue.setNew(false);
-
-    boolean manualIssue = !Strings.isNullOrEmpty(issue.reporter());
-    Rule rule = ruleFinder.findByKey(issue.ruleKey());
-    if (manualIssue) {
-      // Manual rules are not declared in Quality profiles, so no need to check ActiveRule
-      boolean isRemovedRule = rule == null || Rule.STATUS_REMOVED.equals(rule.getStatus());
-      issue.setEndOfLife(forceEndOfLife || isRemovedRule);
-      issue.setOnDisabledRule(isRemovedRule);
-    } else {
-      ActiveRule activeRule = rulesProfile.getActiveRule(issue.ruleKey().repository(), issue.ruleKey().rule());
-      issue.setEndOfLife(true);
-      issue.setOnDisabledRule(activeRule == null || rule == null || Rule.STATUS_REMOVED.equals(rule.getStatus()));
-    }
-  }
-
-  private void relocateManualIssue(DefaultIssue newIssue, IssueDto oldIssue, SourceHashHolder sourceHashHolder) {
-    LOG.debug("Trying to relocate manual issue {}", oldIssue.getKee());
-
-    Integer previousLine = oldIssue.getLine();
-    if (previousLine == null) {
-      LOG.debug("Cannot relocate issue at resource level");
-      return;
-    }
-
-    Collection<Integer> newLinesWithSameHash = sourceHashHolder.getNewLinesMatching(previousLine);
-    LOG.debug("Found the following lines with same hash: {}", newLinesWithSameHash);
-    if (newLinesWithSameHash.isEmpty()) {
-      if (previousLine > sourceHashHolder.getHashedSource().length()) {
-        LOG.debug("Old issue line {} is out of new source, closing and removing line number", previousLine);
-        newIssue.setLine(null);
-        updater.setStatus(newIssue, Issue.STATUS_CLOSED, changeContext);
-        updater.setResolution(newIssue, Issue.RESOLUTION_REMOVED, changeContext);
-        updater.setPastLine(newIssue, previousLine);
-        updater.setPastMessage(newIssue, oldIssue.getMessage(), changeContext);
-        updater.setPastEffortToFix(newIssue, oldIssue.getEffortToFix(), changeContext);
-      }
-    } else if (newLinesWithSameHash.size() == 1) {
-      Integer newLine = newLinesWithSameHash.iterator().next();
-      LOG.debug("Relocating issue to line {}", newLine);
-
-      newIssue.setLine(newLine);
-      updater.setPastLine(newIssue, previousLine);
-      updater.setPastMessage(newIssue, oldIssue.getMessage(), changeContext);
-      updater.setPastEffortToFix(newIssue, oldIssue.getEffortToFix(), changeContext);
-    }
-  }
-}
index 8fe3549e66b1b2a88e99fc5c664e9f933c422566..e04cdc240b433b6ac032e092035e59614d8427c0 100644 (file)
@@ -23,7 +23,7 @@ import com.google.common.collect.HashMultimap;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Multimap;
 import org.apache.commons.lang.StringUtils;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.api.rule.RuleKey;
 
 import javax.annotation.Nullable;
index a946c9f7dea3d08802dc8f0f1cc566bcb9f99e12..733e41d26a1cb6b2feefae17e32f6d3fad293b96 100644 (file)
@@ -29,8 +29,8 @@ import org.sonar.api.batch.fs.internal.DefaultInputFile;
 import org.sonar.api.batch.rule.ActiveRule;
 import org.sonar.api.batch.rule.ActiveRules;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.IssueChangeContext;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.IssueChangeContext;
 import org.sonar.api.resources.Project;
 import org.sonar.api.resources.ResourceUtils;
 import org.sonar.api.rule.RuleKey;
@@ -166,7 +166,7 @@ public class LocalIssueTracking {
 
       // non-persisted fields
       issue.setNew(false);
-      issue.setEndOfLife(false);
+      issue.setBeingClosed(false);
       issue.setOnDisabledRule(false);
 
       // fields to update with old values
@@ -226,9 +226,9 @@ public class LocalIssueTracking {
     boolean manualIssue = issue.ruleKey().isManual();
     boolean isRemovedRule = activeRule == null;
     if (manualIssue) {
-      issue.setEndOfLife(forceEndOfLife || isRemovedRule);
+      issue.setBeingClosed(forceEndOfLife || isRemovedRule);
     } else {
-      issue.setEndOfLife(true);
+      issue.setBeingClosed(true);
     }
     issue.setOnDisabledRule(isRemovedRule);
   }
index 55502e9ba781d66909bcd78369a87ce37aac8dbe..9b6ece676b1b9c0657aabc52c32497e3ada485de 100644 (file)
@@ -37,7 +37,7 @@ import org.sonar.api.batch.sensor.duplication.Duplication;
 import org.sonar.api.batch.sensor.highlighting.TypeOfText;
 import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.api.measures.Measure;
 import org.sonar.batch.duplication.DuplicationCache;
 import org.sonar.batch.index.Cache.Entry;
diff --git a/sonar-batch/src/main/java/org/sonar/batch/phases/PersisterExecutionEvent.java b/sonar-batch/src/main/java/org/sonar/batch/phases/PersisterExecutionEvent.java
deleted file mode 100644 (file)
index cb65745..0000000
+++ /dev/null
@@ -1,50 +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.phases;
-
-import org.sonar.batch.index.ScanPersister;
-import org.sonar.batch.phases.event.PersisterExecutionHandler;
-
-class PersisterExecutionEvent extends AbstractPhaseEvent<PersisterExecutionHandler>
-  implements PersisterExecutionHandler.PersisterExecutionEvent {
-
-  private final ScanPersister persister;
-
-  PersisterExecutionEvent(ScanPersister persister, boolean start) {
-    super(start);
-    this.persister = persister;
-  }
-
-  @Override
-  public ScanPersister getPersister() {
-    return persister;
-  }
-
-  @Override
-  public void dispatch(PersisterExecutionHandler handler) {
-    handler.onPersisterExecution(this);
-  }
-
-  @Override
-  public Class getType() {
-    return PersisterExecutionHandler.class;
-  }
-
-}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/phases/PersistersExecutor.java b/sonar-batch/src/main/java/org/sonar/batch/phases/PersistersExecutor.java
deleted file mode 100644 (file)
index 8e114b6..0000000
+++ /dev/null
@@ -1,65 +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.phases;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.batch.BatchSide;
-import org.sonar.batch.bootstrap.DefaultAnalysisMode;
-import org.sonar.batch.events.EventBus;
-import org.sonar.batch.index.ScanPersister;
-
-import java.util.Arrays;
-
-@BatchSide
-public class PersistersExecutor {
-
-  private static final Logger LOG = LoggerFactory.getLogger(PersistersExecutor.class);
-
-  private final ScanPersister[] persisters;
-  private final DefaultAnalysisMode analysisMode;
-  private final EventBus eventBus;
-
-  public PersistersExecutor(DefaultAnalysisMode analysisMode, EventBus eventBus, ScanPersister[] persisters) {
-    this.analysisMode = analysisMode;
-    this.eventBus = eventBus;
-    this.persisters = persisters;
-  }
-
-  public PersistersExecutor(DefaultAnalysisMode analysisMode, EventBus eventBus) {
-    this(analysisMode, eventBus, new ScanPersister[0]);
-  }
-
-  public void execute() {
-    if (analysisMode.isDb()) {
-      LOG.info("Store results in database");
-      eventBus.fireEvent(new PersistersPhaseEvent(Arrays.asList(persisters), true));
-      for (ScanPersister persister : persisters) {
-        LOG.debug("Execute {}", persister.getClass().getName());
-        eventBus.fireEvent(new PersisterExecutionEvent(persister, true));
-        persister.persist();
-        eventBus.fireEvent(new PersisterExecutionEvent(persister, false));
-      }
-
-      eventBus.fireEvent(new PersistersPhaseEvent(Arrays.asList(persisters), false));
-    }
-  }
-
-}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/phases/PersistersPhaseEvent.java b/sonar-batch/src/main/java/org/sonar/batch/phases/PersistersPhaseEvent.java
deleted file mode 100644 (file)
index ad43c00..0000000
+++ /dev/null
@@ -1,52 +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.phases;
-
-import org.sonar.batch.index.ScanPersister;
-import org.sonar.batch.phases.event.PersistersPhaseHandler;
-
-import java.util.List;
-
-class PersistersPhaseEvent extends AbstractPhaseEvent<PersistersPhaseHandler>
-  implements PersistersPhaseHandler.PersistersPhaseEvent {
-
-  private final List<ScanPersister> persisters;
-
-  PersistersPhaseEvent(List<ScanPersister> persisters, boolean start) {
-    super(start);
-    this.persisters = persisters;
-  }
-
-  @Override
-  public List<ScanPersister> getPersisters() {
-    return persisters;
-  }
-
-  @Override
-  protected void dispatch(PersistersPhaseHandler handler) {
-    handler.onPersistersPhase(this);
-  }
-
-  @Override
-  protected Class getType() {
-    return PersistersPhaseHandler.class;
-  }
-
-}
index af07cf80cb036c24611ea91811bd8b8f88b0f173..3a616e62465f170a14b2a93bbda9f60db8cf5958 100644 (file)
@@ -44,7 +44,6 @@ public final class PhaseExecutor {
   private final SensorContext sensorContext;
   private final DefaultIndex index;
   private final ProjectInitializer pi;
-  private final PersistersExecutor persistersExecutor;
   private final FileSystemLogger fsLogger;
   private final DefaultModuleFileSystem fs;
   private final QProfileVerifier profileVerifier;
@@ -57,7 +56,7 @@ public final class PhaseExecutor {
     InitializersExecutor initializersExecutor, PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor,
     SensorContext sensorContext, DefaultIndex index,
     EventBus eventBus, ReportPublisher reportPublisher, ProjectInitializer pi,
-    PersistersExecutor persistersExecutor, FileSystemLogger fsLogger, IssuesReports jsonReport, DefaultModuleFileSystem fs, QProfileVerifier profileVerifier,
+    FileSystemLogger fsLogger, IssuesReports jsonReport, DefaultModuleFileSystem fs, QProfileVerifier profileVerifier,
     IssueExclusionsLoader issueExclusionsLoader, DefaultAnalysisMode analysisMode, LocalIssueTracking localIssueTracking) {
     this.decoratorsExecutor = decoratorsExecutor;
     this.postJobsExecutor = postJobsExecutor;
@@ -68,7 +67,6 @@ public final class PhaseExecutor {
     this.eventBus = eventBus;
     this.reportPublisher = reportPublisher;
     this.pi = pi;
-    this.persistersExecutor = persistersExecutor;
     this.fsLogger = fsLogger;
     this.issuesReport = jsonReport;
     this.fs = fs;
@@ -106,16 +104,11 @@ public final class PhaseExecutor {
         localIssueTracking();
       }
       issuesReport();
-
-      if (!analysisMode.isPreview()) {
-        persistersExecutor.execute();
-      }
-
       publishReportJob();
       postJobsExecutor.execute(sensorContext);
     }
     cleanMemory();
-    eventBus.fireEvent(new ProjectAnalysisEvent(module, false));
+      eventBus.fireEvent(new ProjectAnalysisEvent(module, false));
   }
 
   private void publishReportJob() {
diff --git a/sonar-batch/src/main/java/org/sonar/batch/phases/event/PersisterExecutionHandler.java b/sonar-batch/src/main/java/org/sonar/batch/phases/event/PersisterExecutionHandler.java
deleted file mode 100644 (file)
index 7df8dae..0000000
+++ /dev/null
@@ -1,45 +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.phases.event;
-
-import org.sonar.api.batch.events.EventHandler;
-import org.sonar.batch.index.ScanPersister;
-
-public interface PersisterExecutionHandler extends EventHandler {
-
-  /**
-   * This interface is not intended to be implemented by clients.
-   */
-  interface PersisterExecutionEvent {
-
-    ScanPersister getPersister();
-
-    boolean isStart();
-
-    boolean isEnd();
-
-  }
-
-  /**
-   * Called before and after execution of {@link ScanPersister}.
-   */
-  void onPersisterExecution(PersisterExecutionEvent event);
-
-}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/phases/event/PersistersPhaseHandler.java b/sonar-batch/src/main/java/org/sonar/batch/phases/event/PersistersPhaseHandler.java
deleted file mode 100644 (file)
index 087755b..0000000
+++ /dev/null
@@ -1,50 +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.phases.event;
-
-import org.sonar.api.batch.events.EventHandler;
-import org.sonar.batch.index.ScanPersister;
-
-import java.util.List;
-
-public interface PersistersPhaseHandler extends EventHandler {
-
-  /**
-   * This interface is not intended to be implemented by clients.
-   */
-  interface PersistersPhaseEvent {
-
-    /**
-     * @return list of Persisters in the order of execution
-     */
-    List<ScanPersister> getPersisters();
-
-    boolean isStart();
-
-    boolean isEnd();
-
-  }
-
-  /**
-   * Called before and after execution of all {@link ScanPersister}s.
-   */
-  void onPersistersPhase(PersistersPhaseEvent event);
-
-}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/phases/event/package-info.java b/sonar-batch/src/main/java/org/sonar/batch/phases/event/package-info.java
deleted file mode 100644 (file)
index 6aefbe5..0000000
+++ /dev/null
@@ -1,23 +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.
- */
-@ParametersAreNonnullByDefault
-package org.sonar.batch.phases.event;
-
-import javax.annotation.ParametersAreNonnullByDefault;
index 6f46c012ce98a738fbc4d23635e2661b25d1d4c5..7b1edddabecbbb60234254bcc6e41fa2bf2f49dd 100644 (file)
@@ -28,7 +28,7 @@ import org.sonar.api.batch.postjob.PostJobContext;
 import org.sonar.api.batch.postjob.issue.Issue;
 import org.sonar.api.batch.rule.Severity;
 import org.sonar.api.config.Settings;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.batch.index.BatchComponent;
 import org.sonar.batch.index.BatchComponentCache;
index 97e5c09dcdb37c9af0a77e610bc63908fc13f33e..1da5585e76293d262da4512d09c8c903fbbd4634 100644 (file)
@@ -48,16 +48,13 @@ import org.sonar.api.utils.System2;
 import org.sonar.api.utils.TimeUtils;
 import org.sonar.batch.bootstrap.BootstrapProperties;
 import org.sonar.batch.events.BatchStepHandler;
-import org.sonar.batch.phases.event.PersisterExecutionHandler;
-import org.sonar.batch.phases.event.PersistersPhaseHandler;
 import org.sonar.batch.util.BatchUtils;
 
 import static org.sonar.batch.profiling.AbstractTimeProfiling.sortByDescendingTotalTime;
 import static org.sonar.batch.profiling.AbstractTimeProfiling.truncate;
 
 public class PhasesSumUpTimeProfiler implements ProjectAnalysisHandler, SensorExecutionHandler, DecoratorExecutionHandler, PostJobExecutionHandler, DecoratorsPhaseHandler,
-  SensorsPhaseHandler, PostJobsPhaseHandler, InitializersPhaseHandler, InitializerExecutionHandler, BatchStepHandler, PersistersPhaseHandler,
-  PersisterExecutionHandler {
+  SensorsPhaseHandler, PostJobsPhaseHandler, InitializersPhaseHandler, InitializerExecutionHandler, BatchStepHandler {
 
   static final Logger LOG = LoggerFactory.getLogger(PhasesSumUpTimeProfiler.class);
   private static final int TEXT_RIGHT_PAD = 60;
@@ -174,25 +171,6 @@ public class PhasesSumUpTimeProfiler implements ProjectAnalysisHandler, SensorEx
     }
   }
 
-  @Override
-  public void onPersistersPhase(PersistersPhaseEvent event) {
-    if (event.isStart()) {
-      currentModuleProfiling.addPhaseProfiling(Phase.PERSISTER);
-    } else {
-      currentModuleProfiling.getProfilingPerPhase(Phase.PERSISTER).stop();
-    }
-  }
-
-  @Override
-  public void onPersisterExecution(PersisterExecutionEvent event) {
-    PhaseProfiling profiling = currentModuleProfiling.getProfilingPerPhase(Phase.PERSISTER);
-    if (event.isStart()) {
-      profiling.newItemProfiling(event.getPersister());
-    } else {
-      profiling.getProfilingPerItem(event.getPersister()).stop();
-    }
-  }
-
   @Override
   public void onDecoratorExecution(DecoratorExecutionEvent event) {
     PhaseProfiling profiling = currentModuleProfiling.getProfilingPerPhase(Phase.DECORATOR);
index 08be39df95394bd86728d8f4a2f31d8f47a64758..0377b3e08897475db8f29095b3244a2c6da0fe9a 100644 (file)
@@ -21,14 +21,8 @@ package org.sonar.batch.report;
 
 import com.google.common.base.Function;
 import com.google.common.collect.Iterables;
-import java.util.Collection;
-import java.util.Date;
-import java.util.Iterator;
-import javax.annotation.Nullable;
 import org.sonar.api.CoreProperties;
 import org.sonar.api.batch.bootstrap.ProjectDefinition;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.FieldDiffs;
 import org.sonar.api.resources.Project;
 import org.sonar.api.utils.KeyValueFormat;
 import org.sonar.batch.index.BatchComponent;
@@ -38,6 +32,7 @@ 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 {
 
@@ -53,7 +48,6 @@ public class IssuesPublisher implements ReportPublisherStep {
 
   @Override
   public void publish(BatchReportWriter writer) {
-    Collection<Object> deletedComponentKeys = issueCache.componentKeys();
     for (BatchComponent resource : componentCache.all()) {
       String componentKey = resource.resource().getEffectiveKey();
       Iterable<DefaultIssue> issues = issueCache.byComponent(componentKey);
@@ -65,23 +59,19 @@ public class IssuesPublisher implements ReportPublisherStep {
           return toReportIssue(builder, input);
         }
       }));
-      deletedComponentKeys.remove(componentKey);
     }
 
-    int count = exportIssuesOfDeletedComponents(deletedComponentKeys, writer);
-
-    exportMetadata(writer, count);
+    exportMetadata(writer);
   }
 
-  private void exportMetadata(BatchReportWriter writer, int count) {
+  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())
-      .setDeletedComponentsCount(count);
+      .setRootComponentRef(rootProject.batchId());
     String branch = root.properties().get(CoreProperties.PROJECT_BRANCH_PROPERTY);
     if (branch != null) {
       builder.setBranch(branch);
@@ -89,39 +79,14 @@ public class IssuesPublisher implements ReportPublisherStep {
     writer.writeMetadata(builder.build());
   }
 
-  private int exportIssuesOfDeletedComponents(Collection<Object> deletedComponentKeys, BatchReportWriter writer) {
-    int deletedComponentCount = 0;
-    for (Object componentKey : deletedComponentKeys) {
-      deletedComponentCount++;
-      Iterable<DefaultIssue> issues = issueCache.byComponent(componentKey.toString());
-      Iterator<DefaultIssue> iterator = issues.iterator();
-      if (iterator.hasNext()) {
-        String componentUuid = iterator.next().componentUuid();
-        writer.writeDeletedComponentIssues(deletedComponentCount, componentUuid, Iterables.transform(issues, new Function<DefaultIssue, BatchReport.Issue>() {
-          private BatchReport.Issue.Builder builder = BatchReport.Issue.newBuilder();
-
-          @Override
-          public BatchReport.Issue apply(DefaultIssue input) {
-            return toReportIssue(builder, input);
-          }
-        }));
-      }
-    }
-    return deletedComponentCount;
-  }
-
   private BatchReport.Issue toReportIssue(BatchReport.Issue.Builder builder, DefaultIssue issue) {
     builder.clear();
     // non-null fields
-    builder.setUuid(issue.key());
-    builder.setIsNew(issue.isNew());
     builder.setSeverity(Constants.Severity.valueOf(issue.severity()));
     builder.setRuleRepository(issue.ruleKey().repository());
     builder.setRuleKey(issue.ruleKey().rule());
     builder.setAttributes(KeyValueFormat.format(issue.attributes()));
     builder.addAllTag(issue.tags());
-    builder.setMustSendNotification(issue.mustSendNotifications());
-    builder.setIsChanged(issue.isChanged());
 
     // nullable fields
     Integer line = issue.line();
@@ -136,65 +101,12 @@ public class IssuesPublisher implements ReportPublisherStep {
     if (effortToFix != null) {
       builder.setEffortToFix(effortToFix);
     }
-
     Long debtInMinutes = issue.debtInMinutes();
     if (debtInMinutes != null) {
       builder.setDebtInMinutes(debtInMinutes);
     }
-    String resolution = issue.resolution();
-    if (resolution != null) {
-      builder.setResolution(resolution);
-    }
-    String status = issue.status();
-    if (status != null) {
-      builder.setStatus(status);
-    }
-    String checksum = issue.checksum();
-    if (checksum != null) {
-      builder.setChecksum(checksum);
-    }
-    builder.setManualSeverity(issue.manualSeverity());
-    String reporter = issue.reporter();
-    if (reporter != null) {
-      builder.setReporter(reporter);
-    }
-    String assignee = issue.assignee();
-    if (assignee != null) {
-      builder.setAssignee(assignee);
-    }
-    String actionPlanKey = issue.actionPlanKey();
-    if (actionPlanKey != null) {
-      builder.setActionPlanKey(actionPlanKey);
-    }
-    String authorLogin = issue.authorLogin();
-    if (authorLogin != null) {
-      builder.setAuthorLogin(authorLogin);
-    }
-    String diff = diffsToString(issue.currentChange());
-    if (diff != null) {
-      builder.setDiffFields(diff);
-    }
-    Date creationDate = issue.creationDate();
-    if (creationDate != null) {
-      builder.setCreationDate(creationDate.getTime());
-    }
-    Long selectedAt = issue.selectedAt();
-    if (selectedAt != null) {
-      builder.setSelectedAt(selectedAt);
-    }
-    Date closeDate = issue.closeDate();
-    if (closeDate != null) {
-      builder.setCloseDate(closeDate.getTime());
-    }
-    Date updateDate = issue.updateDate();
-    if (updateDate != null) {
-      builder.setUpdateDate(updateDate.getTime());
-    }
-    return builder.build();
-  }
 
-  private String diffsToString(@Nullable FieldDiffs diffs) {
-    return diffs != null ? diffs.toString() : null;
+    return builder.build();
   }
 
 }
index 4d4fb03fff9bc136859cb64266458a76adecf3a0..c4524dca799967abbbd1172f98e57976abd7c1c9 100644 (file)
@@ -50,7 +50,6 @@ import org.sonar.batch.issue.ignore.scanner.IssueExclusionsLoader;
 import org.sonar.batch.issue.ignore.scanner.IssueExclusionsRegexpScanner;
 import org.sonar.batch.phases.DecoratorsExecutor;
 import org.sonar.batch.phases.InitializersExecutor;
-import org.sonar.batch.phases.PersistersExecutor;
 import org.sonar.batch.phases.PhaseExecutor;
 import org.sonar.batch.phases.PostJobsExecutor;
 import org.sonar.batch.phases.ProjectInitializer;
@@ -120,7 +119,6 @@ public class ModuleScanContainer extends ComponentContainer {
       PostJobsExecutor.class,
       DecoratorsExecutor.class,
       SensorsExecutor.class,
-      PersistersExecutor.class,
       InitializersExecutor.class,
       ProjectInitializer.class,
       moduleDefinition.getContainerExtensions(),
index 1c3e864170dfcdd52363f38a3ea1ed596017e299..83f24753ef475bf744ccb4dd70b8c9e79158b523 100644 (file)
@@ -53,7 +53,6 @@ import org.sonar.batch.index.Caches;
 import org.sonar.batch.index.DefaultIndex;
 import org.sonar.batch.issue.DefaultProjectIssues;
 import org.sonar.batch.issue.IssueCache;
-import org.sonar.batch.issue.tracking.InitialOpenIssuesStack;
 import org.sonar.batch.issue.tracking.LocalIssueTracking;
 import org.sonar.batch.issue.tracking.ServerIssueRepository;
 import org.sonar.batch.mediumtest.ScanTaskObservers;
@@ -217,10 +216,7 @@ public class ProjectScanContainer extends ComponentContainer {
       new DebtModelProvider(),
 
     // technical debt
-      DefaultTechnicalDebtModel.class,
-
-    // Issue tracking
-      InitialOpenIssuesStack.class);
+      DefaultTechnicalDebtModel.class);
   }
 
   private void addBatchExtensions() {
index e23e8a816e34685c1d162f86c1314b611b25f041..2634fdd9af978d93ce4cef87166a8dc994acabdb 100644 (file)
@@ -25,7 +25,7 @@ import org.sonar.api.Properties;
 import org.sonar.api.Property;
 import org.sonar.api.PropertyType;
 import org.sonar.api.config.Settings;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.api.rule.Severity;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
index 72c48f9bb7a704868df6e52f313cdd95d2994066..43e423e7fa7fc640b73a28a57e05053f91264cba 100644 (file)
@@ -23,7 +23,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.sonar.api.batch.BatchSide;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.api.resources.Project;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rules.Rule;
index e2959d9352d3e36963da372cc0bf06a5a6b1772c..b13b5468d67db40069976f09570ea39b590e66ef 100644 (file)
@@ -34,7 +34,7 @@ import org.sonar.api.batch.fs.internal.DefaultInputFile;
 import org.sonar.api.batch.rule.ActiveRules;
 import org.sonar.api.batch.rule.internal.DefaultActiveRule;
 import org.sonar.api.config.Settings;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.api.platform.Server;
 import org.sonar.api.resources.Project;
 import org.sonar.api.rule.RuleKey;
index 0277408cbe46035047f13dedb0f160ed49185d47..4ddfe03452e0724bf822f91c1d8d2bd638c48d87 100644 (file)
@@ -42,7 +42,7 @@ import org.sonar.api.batch.sensor.issue.Issue;
 import org.sonar.api.batch.sensor.measure.Measure;
 import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure;
 import org.sonar.api.config.Settings;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.api.measures.Formula;
 import org.sonar.api.measures.Metric;
 import org.sonar.api.measures.PersistenceMode;
index 5ce426696d5eb11d7850fb1df57d564e08d6f69e..94a58c79b0dff8cde379f03ff0f4f56ca516c983 100644 (file)
@@ -37,7 +37,7 @@ 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.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.api.measures.CoreMetrics;
 import org.sonar.api.measures.Measure;
 import org.sonar.api.measures.MeasuresFilter;
index 952075dec78a40876000f2dbba0d332871d0e41a..fb2bf2e90f56af792cdc5ae817034949d2576ac9 100644 (file)
@@ -24,8 +24,8 @@ 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.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.FieldDiffs;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.FieldDiffs;
 import org.sonar.api.utils.Duration;
 
 import java.util.Date;
index 8de52b074c213857ecccd61d667d934ece29f7b8..8b00495711bc6c718739e9720733aac232565d33 100644 (file)
@@ -34,8 +34,8 @@ 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.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.FieldDiffs;
+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;
index 42843ddd8ecc6c7948afd326e67fa92a0c56e162..7f50a767efe8670e244642c6c4e38256a5b2bb9a 100644 (file)
@@ -23,7 +23,7 @@ import java.util.Arrays;
 import java.util.List;
 import org.junit.Test;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.api.resources.Project;
 import org.sonar.batch.index.BatchComponent;
 
index b46e3551a6da56eb38998f9238c97e6b8cfb358e..99c6d5f710017c5c68e73e617d8355147208687b 100644 (file)
@@ -22,7 +22,7 @@ package org.sonar.batch.issue;
 import com.google.common.collect.Lists;
 import org.junit.Test;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rule.Severity;
 
index 25fefe6f13d653a0a98a22bb05ecfdd6ddf46ec6..18e90aff802c50751af56b265187c59b9acc3090 100644 (file)
@@ -26,7 +26,7 @@ import com.google.common.collect.Collections2;
 import com.google.common.collect.ImmutableList;
 import org.junit.Test;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.api.rule.Severity;
 
 import javax.annotation.Nullable;
index 46aea62325c282ee8d1b1f5098b6a0d36648fbea..b99aefe9bb857506c255742642024e225d9a7573 100644 (file)
@@ -21,7 +21,7 @@ package org.sonar.batch.issue;
 
 import org.junit.Test;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Matchers.any;
index 2577ba98a4179bb918220aab57b7050b7632fce7..f1157f16572901bc7d3c3ed4a274e9c5e3c96616 100644 (file)
@@ -29,7 +29,7 @@ import org.mockito.runners.MockitoJUnitRunner;
 import org.sonar.api.batch.debt.DebtRemediationFunction;
 import org.sonar.api.batch.rule.internal.ActiveRulesBuilder;
 import org.sonar.api.batch.rule.internal.RulesBuilder;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.api.resources.File;
 import org.sonar.api.resources.Project;
 import org.sonar.api.resources.Resource;
diff --git a/sonar-batch/src/test/java/org/sonar/batch/issue/tracking/InitialOpenIssuesSensorTest.java b/sonar-batch/src/test/java/org/sonar/batch/issue/tracking/InitialOpenIssuesSensorTest.java
deleted file mode 100644 (file)
index 1b4a6ad..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.issue.tracking;
-
-import org.apache.ibatis.session.ResultHandler;
-import org.junit.Test;
-import org.sonar.api.resources.Project;
-import org.sonar.core.issue.db.IssueChangeDao;
-import org.sonar.core.issue.db.IssueDao;
-import org.sonar.core.resource.ResourceDao;
-import org.sonar.core.resource.ResourceDto;
-import org.sonar.core.resource.ResourceQuery;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-public class InitialOpenIssuesSensorTest {
-
-  InitialOpenIssuesStack stack = mock(InitialOpenIssuesStack.class);
-  IssueDao issueDao = mock(IssueDao.class);
-  IssueChangeDao issueChangeDao = mock(IssueChangeDao.class);
-  ResourceDao resourceDao = mock(ResourceDao.class);
-
-  InitialOpenIssuesSensor sensor = new InitialOpenIssuesSensor(stack, issueDao, issueChangeDao, resourceDao);
-
-  @Test
-  public void should_select_module_open_issues() {
-    when(resourceDao.getResource(any(ResourceQuery.class))).thenReturn(new ResourceDto().setId(1L));
-
-    sensor.analyse(new Project("key"), null);
-
-    verify(issueDao).selectNonClosedIssuesByModule(eq(1L), any(ResultHandler.class));
-  }
-
-  @Test
-  public void should_select_module_open_issues_changelog() {
-    when(resourceDao.getResource(any(ResourceQuery.class))).thenReturn(new ResourceDto().setId(1L));
-
-    sensor.analyse(new Project("key"), null);
-
-    verify(issueChangeDao).selectChangelogOnNonClosedIssuesByModuleAndType(eq(1L), any(ResultHandler.class));
-  }
-
-  @Test
-  public void nothing_to_on_new_component() {
-    when(resourceDao.getResource(any(ResourceQuery.class))).thenReturn(null);
-
-    sensor.analyse(new Project("key"), null);
-
-    verifyZeroInteractions(issueDao);
-    verifyZeroInteractions(issueChangeDao);
-  }
-
-  @Test
-  public void test_toString() throws Exception {
-    assertThat(sensor.toString()).isEqualTo("InitialOpenIssuesSensor");
-
-  }
-}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/issue/tracking/InitialOpenIssuesStackTest.java b/sonar-batch/src/test/java/org/sonar/batch/issue/tracking/InitialOpenIssuesStackTest.java
deleted file mode 100644 (file)
index c6f42f1..0000000
+++ /dev/null
@@ -1,120 +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.issue.tracking;
-
-import org.sonar.batch.index.AbstractCachesTest;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.sonar.core.issue.db.IssueChangeDto;
-import org.sonar.core.issue.db.IssueDto;
-
-import java.util.List;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class InitialOpenIssuesStackTest extends AbstractCachesTest {
-
-  InitialOpenIssuesStack stack;
-
-  @Before
-  public void before() {
-    stack = new InitialOpenIssuesStack(caches);
-  }
-
-  @After
-  public void after() {
-    caches.stop();
-  }
-
-  @Test
-  public void get_and_remove_issues() {
-    IssueDto issueDto = new IssueDto().setComponentKey("org.struts.Action").setKee("ISSUE-1");
-    stack.addIssue(issueDto);
-
-    List<ServerIssue> issueDtos = stack.selectAndRemoveIssues("org.struts.Action");
-    assertThat(issueDtos).hasSize(1);
-    assertThat(issueDtos.get(0).key()).isEqualTo("ISSUE-1");
-
-    assertThat(stack.selectAllIssues()).isEmpty();
-  }
-
-  @Test
-  public void get_and_remove_with_many_issues_on_same_resource() {
-    stack.addIssue(new IssueDto().setComponentKey("org.struts.Action").setKee("ISSUE-1"));
-    stack.addIssue(new IssueDto().setComponentKey("org.struts.Action").setKee("ISSUE-2"));
-
-    List<ServerIssue> issueDtos = stack.selectAndRemoveIssues("org.struts.Action");
-    assertThat(issueDtos).hasSize(2);
-
-    assertThat(stack.selectAllIssues()).isEmpty();
-  }
-
-  @Test
-  public void get_and_remove_do_nothing_if_resource_not_found() {
-    stack.addIssue(new IssueDto().setComponentKey("org.struts.Action").setKee("ISSUE-1"));
-
-    List<ServerIssue> issueDtos = stack.selectAndRemoveIssues("Other");
-    assertThat(issueDtos).hasSize(0);
-
-    assertThat(stack.selectAllIssues()).hasSize(1);
-  }
-
-  @Test
-  public void select_changelog() {
-    stack.addChangelog(new IssueChangeDto().setKey("CHANGE-1").setIssueKey("ISSUE-1"));
-    stack.addChangelog(new IssueChangeDto().setKey("CHANGE-2").setIssueKey("ISSUE-1"));
-
-    List<IssueChangeDto> issueChangeDtos = stack.selectChangelog("ISSUE-1");
-    assertThat(issueChangeDtos).hasSize(2);
-    assertThat(issueChangeDtos.get(0).getKey()).isEqualTo("CHANGE-1");
-    assertThat(issueChangeDtos.get(1).getKey()).isEqualTo("CHANGE-2");
-  }
-
-  @Test
-  public void return_empty_changelog() {
-    assertThat(stack.selectChangelog("ISSUE-1")).isEmpty();
-  }
-
-  @Test
-  public void clear_issues() {
-    stack.addIssue(new IssueDto().setComponentKey("org.struts.Action").setKee("ISSUE-1"));
-
-    assertThat(stack.selectAllIssues()).hasSize(1);
-
-    // issues are not removed
-    assertThat(stack.selectAllIssues()).hasSize(1);
-
-    stack.clear();
-    assertThat(stack.selectAllIssues()).isEmpty();
-  }
-
-  @Test
-  public void clear_issues_changelog() {
-    stack.addChangelog(new IssueChangeDto().setKey("CHANGE-1").setIssueKey("ISSUE-1"));
-
-    assertThat(stack.selectChangelog("ISSUE-1")).hasSize(1);
-
-    stack.clear();
-    assertThat(stack.selectChangelog("ISSUE-1")).isEmpty();
-  }
-}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/issue/tracking/IssueHandlersTest.java b/sonar-batch/src/test/java/org/sonar/batch/issue/tracking/IssueHandlersTest.java
deleted file mode 100644 (file)
index fe81ee2..0000000
+++ /dev/null
@@ -1,62 +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.issue.tracking;
-
-import org.junit.Test;
-import org.mockito.ArgumentMatcher;
-import org.sonar.api.issue.IssueHandler;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.IssueChangeContext;
-import org.sonar.core.issue.IssueUpdater;
-
-import java.util.Date;
-
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-
-public class IssueHandlersTest {
-  @Test
-  public void should_execute_handlers() {
-    IssueHandler h1 = mock(IssueHandler.class);
-    IssueHandler h2 = mock(IssueHandler.class);
-    IssueUpdater updater = mock(IssueUpdater.class);
-
-    IssueHandlers handlers = new IssueHandlers(updater, new IssueHandler[]{h1, h2});
-    final DefaultIssue issue = new DefaultIssue();
-    handlers.execute(issue, IssueChangeContext.createScan(new Date()));
-
-    verify(h1).onIssue(argThat(new ArgumentMatcher<IssueHandler.Context>() {
-      @Override
-      public boolean matches(Object o) {
-        return ((IssueHandler.Context) o).issue() == issue;
-      }
-    }));
-  }
-
-  @Test
-  public void test_no_handlers() {
-    IssueUpdater updater = mock(IssueUpdater.class);
-    IssueHandlers handlers = new IssueHandlers(updater);
-    handlers.execute(new DefaultIssue(), IssueChangeContext.createScan(new Date()));
-    verifyZeroInteractions(updater);
-  }
-}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/issue/tracking/IssueTrackingDecoratorTest.java b/sonar-batch/src/test/java/org/sonar/batch/issue/tracking/IssueTrackingDecoratorTest.java
deleted file mode 100644 (file)
index d09c790..0000000
+++ /dev/null
@@ -1,584 +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.issue.tracking;
-
-import org.apache.commons.codec.digest.DigestUtils;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.lang.StringUtils;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.mockito.ArgumentCaptor;
-import org.mockito.ArgumentMatcher;
-import org.sonar.api.batch.DecoratorContext;
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.component.ResourcePerspectives;
-import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.IssueChangeContext;
-import org.sonar.api.profiles.RulesProfile;
-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.Rule;
-import org.sonar.api.rules.RuleFinder;
-import org.sonar.api.utils.Duration;
-import org.sonar.api.utils.System2;
-import org.sonar.batch.issue.IssueCache;
-import org.sonar.batch.scan.filesystem.InputPathCache;
-import org.sonar.core.issue.IssueUpdater;
-import org.sonar.core.issue.db.IssueChangeDto;
-import org.sonar.core.issue.db.IssueDto;
-import org.sonar.core.issue.workflow.IssueWorkflow;
-import org.sonar.java.api.JavaClass;
-
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.Collection;
-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.Matchers.any;
-import static org.mockito.Matchers.anyCollection;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.isA;
-import static org.mockito.Mockito.RETURNS_MOCKS;
-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.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-public class IssueTrackingDecoratorTest {
-
-  @org.junit.Rule
-  public TemporaryFolder temp = new TemporaryFolder();
-
-  IssueTrackingDecorator decorator;
-  IssueCache issueCache = mock(IssueCache.class, RETURNS_MOCKS);
-  InitialOpenIssuesStack initialOpenIssues = mock(InitialOpenIssuesStack.class);
-  IssueTracking tracking = mock(IssueTracking.class, RETURNS_MOCKS);
-  ServerLineHashesLoader lastSnapshots = mock(ServerLineHashesLoader.class);
-  IssueHandlers handlers = mock(IssueHandlers.class);
-  IssueWorkflow workflow = mock(IssueWorkflow.class);
-  IssueUpdater updater = mock(IssueUpdater.class);
-  ResourcePerspectives perspectives = mock(ResourcePerspectives.class);
-  RulesProfile profile = mock(RulesProfile.class);
-  RuleFinder ruleFinder = mock(RuleFinder.class);
-  InputPathCache inputPathCache = mock(InputPathCache.class);
-
-  @Before
-  public void init() {
-    decorator = new IssueTrackingDecorator(
-      issueCache,
-      initialOpenIssues,
-      tracking,
-      lastSnapshots,
-      handlers,
-      workflow,
-      updater,
-      new Project("foo"),
-      perspectives,
-      profile,
-      ruleFinder,
-      inputPathCache);
-  }
-
-  @Test
-  public void should_execute_on_project() {
-    Project project = mock(Project.class);
-    assertThat(decorator.shouldExecuteOnProject(project)).isTrue();
-  }
-
-  @Test
-  public void should_not_be_executed_on_classes_not_methods() {
-    DecoratorContext context = mock(DecoratorContext.class);
-    decorator.decorate(JavaClass.create("org.foo.Bar"), context);
-    verifyZeroInteractions(context, issueCache, tracking, handlers, workflow);
-  }
-
-  @Test
-  public void should_process_open_issues() {
-    Resource file = File.create("Action.java").setEffectiveKey("struts:Action.java").setId(123);
-    final DefaultIssue issue = new DefaultIssue();
-
-    // INPUT : one issue, no open issues during previous scan, no filtering
-    when(issueCache.byComponent("struts:Action.java")).thenReturn(Arrays.asList(issue));
-    List<ServerIssue> dbIssues = Collections.emptyList();
-    when(initialOpenIssues.selectAndRemoveIssues("struts:Action.java")).thenReturn(dbIssues);
-    when(inputPathCache.getFile("foo", "Action.java")).thenReturn(mock(DefaultInputFile.class));
-    decorator.doDecorate(file);
-
-    // Apply filters, track, apply transitions, notify extensions then update cache
-    verify(tracking).track(isA(SourceHashHolder.class), eq(dbIssues), argThat(new ArgumentMatcher<Collection<DefaultIssue>>() {
-      @Override
-      public boolean matches(Object o) {
-        List<DefaultIssue> issues = (List<DefaultIssue>) o;
-        return issues.size() == 1 && issues.get(0) == issue;
-      }
-    }));
-    verify(workflow).doAutomaticTransition(eq(issue), any(IssueChangeContext.class));
-    verify(handlers).execute(eq(issue), any(IssueChangeContext.class));
-    verify(issueCache).put(issue);
-  }
-
-  @Test
-  public void should_register_unmatched_issues_as_end_of_life() {
-    // "Unmatched" issues existed in previous scan but not in current one -> they have to be closed
-    Resource file = File.create("Action.java").setEffectiveKey("struts:Action.java").setId(123);
-
-    // INPUT : one issue existing during previous scan
-    ServerIssue unmatchedIssue = new ServerIssueFromDb(new IssueDto().setKee("ABCDE").setResolution(null).setStatus("OPEN").setRuleKey("squid", "AvoidCycle"));
-
-    IssueTrackingResult trackingResult = new IssueTrackingResult();
-    trackingResult.addUnmatched(unmatchedIssue);
-
-    when(tracking.track(isA(SourceHashHolder.class), anyCollection(), anyCollection())).thenReturn(trackingResult);
-    when(inputPathCache.getFile("foo", "Action.java")).thenReturn(mock(DefaultInputFile.class));
-
-    decorator.doDecorate(file);
-
-    verify(workflow, times(1)).doAutomaticTransition(any(DefaultIssue.class), any(IssueChangeContext.class));
-    verify(handlers, times(1)).execute(any(DefaultIssue.class), any(IssueChangeContext.class));
-
-    ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class);
-    verify(issueCache).put(argument.capture());
-
-    DefaultIssue issue = argument.getValue();
-    assertThat(issue.key()).isEqualTo("ABCDE");
-    assertThat(issue.isNew()).isFalse();
-    assertThat(issue.isEndOfLife()).isTrue();
-  }
-
-  @Test
-  public void manual_issues_should_be_moved_if_matching_line_found() throws Exception {
-    // INPUT : one issue existing during previous scan
-    ServerIssue unmatchedIssue = new ServerIssueFromDb(new IssueDto().setKee("ABCDE").setReporter("freddy").setLine(6).setStatus("OPEN").setRuleKey("manual", "Performance"));
-    when(ruleFinder.findByKey(RuleKey.of("manual", "Performance"))).thenReturn(new Rule("manual", "Performance"));
-
-    IssueTrackingResult trackingResult = new IssueTrackingResult();
-    trackingResult.addUnmatched(unmatchedIssue);
-
-    String originalSource = "public interface Action {\n"
-      + "   void method1();\n"
-      + "   void method2();\n"
-      + "   void method3();\n"
-      + "   void method4();\n"
-      + "   void method5();\n" // Original issue here
-      + "}";
-    String newSource = "public interface Action {\n"
-      + "   void method5();\n" // New issue here
-      + "   void method1();\n"
-      + "   void method2();\n"
-      + "   void method3();\n"
-      + "   void method4();\n"
-      + "}";
-    Resource file = mockHashes(originalSource, newSource);
-
-    when(tracking.track(isA(SourceHashHolder.class), anyCollection(), anyCollection())).thenReturn(trackingResult);
-
-    decorator.doDecorate(file);
-
-    verify(workflow, times(1)).doAutomaticTransition(any(DefaultIssue.class), any(IssueChangeContext.class));
-    verify(handlers, times(1)).execute(any(DefaultIssue.class), any(IssueChangeContext.class));
-
-    ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class);
-    verify(issueCache).put(argument.capture());
-
-    DefaultIssue issue = argument.getValue();
-    assertThat(issue.line()).isEqualTo(2);
-    assertThat(issue.key()).isEqualTo("ABCDE");
-    assertThat(issue.isNew()).isFalse();
-    assertThat(issue.isEndOfLife()).isFalse();
-    assertThat(issue.isOnDisabledRule()).isFalse();
-  }
-
-  private Resource mockHashes(String originalSource, String newSource) throws IOException {
-    DefaultInputFile inputFile = mock(DefaultInputFile.class);
-    java.io.File f = temp.newFile();
-    when(inputFile.path()).thenReturn(f.toPath());
-    when(inputFile.file()).thenReturn(f);
-    when(inputFile.charset()).thenReturn(StandardCharsets.UTF_8);
-    when(inputFile.lines()).thenReturn(StringUtils.countMatches(newSource, "\n") + 1);
-    FileUtils.write(f, newSource, StandardCharsets.UTF_8);
-    when(inputFile.key()).thenReturn("foo:Action.java");
-    when(inputPathCache.getFile("foo", "Action.java")).thenReturn(inputFile);
-    when(lastSnapshots.getLineHashes("foo:Action.java")).thenReturn(computeHexHashes(originalSource));
-    Resource file = File.create("Action.java");
-    return file;
-  }
-
-  @Test
-  public void manual_issues_should_be_untouched_if_already_closed() throws Exception {
-
-    // INPUT : one issue existing during previous scan
-    ServerIssue unmatchedIssue = new ServerIssueFromDb(new IssueDto().setKee("ABCDE").setReporter("freddy").setLine(1).setStatus("CLOSED").setRuleKey("manual", "Performance"));
-    when(ruleFinder.findByKey(RuleKey.of("manual", "Performance"))).thenReturn(new Rule("manual", "Performance"));
-
-    IssueTrackingResult trackingResult = new IssueTrackingResult();
-    trackingResult.addUnmatched(unmatchedIssue);
-
-    String originalSource = "public interface Action {}";
-    Resource file = mockHashes(originalSource, originalSource);
-
-    when(tracking.track(isA(SourceHashHolder.class), anyCollection(), anyCollection())).thenReturn(trackingResult);
-
-    decorator.doDecorate(file);
-
-    verify(workflow, times(1)).doAutomaticTransition(any(DefaultIssue.class), any(IssueChangeContext.class));
-    verify(handlers, times(1)).execute(any(DefaultIssue.class), any(IssueChangeContext.class));
-
-    ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class);
-    verify(issueCache).put(argument.capture());
-
-    DefaultIssue issue = argument.getValue();
-    assertThat(issue.line()).isEqualTo(1);
-    assertThat(issue.key()).isEqualTo("ABCDE");
-    assertThat(issue.isNew()).isFalse();
-    assertThat(issue.isEndOfLife()).isFalse();
-    assertThat(issue.isOnDisabledRule()).isFalse();
-    assertThat(issue.status()).isEqualTo("CLOSED");
-  }
-
-  @Test
-  public void manual_issues_should_be_untouched_if_line_is_null() throws Exception {
-
-    // INPUT : one issue existing during previous scan
-    ServerIssue unmatchedIssue = new ServerIssueFromDb(new IssueDto().setKee("ABCDE").setReporter("freddy").setLine(null).setStatus("OPEN").setRuleKey("manual", "Performance"));
-    when(ruleFinder.findByKey(RuleKey.of("manual", "Performance"))).thenReturn(new Rule("manual", "Performance"));
-
-    IssueTrackingResult trackingResult = new IssueTrackingResult();
-    trackingResult.addUnmatched(unmatchedIssue);
-
-    String originalSource = "public interface Action {}";
-    Resource file = mockHashes(originalSource, originalSource);
-
-    when(tracking.track(isA(SourceHashHolder.class), anyCollection(), anyCollection())).thenReturn(trackingResult);
-
-    decorator.doDecorate(file);
-
-    verify(workflow, times(1)).doAutomaticTransition(any(DefaultIssue.class), any(IssueChangeContext.class));
-    verify(handlers, times(1)).execute(any(DefaultIssue.class), any(IssueChangeContext.class));
-
-    ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class);
-    verify(issueCache).put(argument.capture());
-
-    DefaultIssue issue = argument.getValue();
-    assertThat(issue.line()).isEqualTo(null);
-    assertThat(issue.key()).isEqualTo("ABCDE");
-    assertThat(issue.isNew()).isFalse();
-    assertThat(issue.isEndOfLife()).isFalse();
-    assertThat(issue.isOnDisabledRule()).isFalse();
-    assertThat(issue.status()).isEqualTo("OPEN");
-  }
-
-  @Test
-  public void manual_issues_should_be_kept_if_matching_line_not_found() throws Exception {
-    // "Unmatched" issues existed in previous scan but not in current one -> they have to be closed
-
-    // INPUT : one issue existing during previous scan
-    final int issueOnLine = 6;
-    ServerIssue unmatchedIssue = new ServerIssueFromDb(new IssueDto().setKee("ABCDE").setReporter("freddy").setLine(issueOnLine).setStatus("OPEN")
-      .setRuleKey("manual", "Performance"));
-    when(ruleFinder.findByKey(RuleKey.of("manual", "Performance"))).thenReturn(new Rule("manual", "Performance"));
-
-    IssueTrackingResult trackingResult = new IssueTrackingResult();
-    trackingResult.addUnmatched(unmatchedIssue);
-
-    String originalSource = "public interface Action {\n"
-      + "   void method1();\n"
-      + "   void method2();\n"
-      + "   void method3();\n"
-      + "   void method4();\n"
-      + "   void method5();\n" // Original issue here
-      + "}";
-    String newSource = "public interface Action {\n"
-      + "   void method1();\n"
-      + "   void method2();\n"
-      + "   void method3();\n"
-      + "   void method4();\n"
-      + "   void method6();\n" // Poof, no method5 anymore
-      + "}";
-
-    Resource file = mockHashes(originalSource, newSource);
-
-    when(tracking.track(isA(SourceHashHolder.class), anyCollection(), anyCollection())).thenReturn(trackingResult);
-
-    decorator.doDecorate(file);
-
-    verify(workflow, times(1)).doAutomaticTransition(any(DefaultIssue.class), any(IssueChangeContext.class));
-    verify(handlers, times(1)).execute(any(DefaultIssue.class), any(IssueChangeContext.class));
-
-    ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class);
-    verify(issueCache).put(argument.capture());
-
-    DefaultIssue issue = argument.getValue();
-    assertThat(issue.line()).isEqualTo(issueOnLine);
-    assertThat(issue.key()).isEqualTo("ABCDE");
-    assertThat(issue.isNew()).isFalse();
-    assertThat(issue.isEndOfLife()).isFalse();
-    assertThat(issue.isOnDisabledRule()).isFalse();
-  }
-
-  @Test
-  public void manual_issues_should_be_kept_if_multiple_matching_lines_found() throws Exception {
-    // "Unmatched" issues existed in previous scan but not in current one -> they have to be closed
-
-    // INPUT : one issue existing during previous scan
-    final int issueOnLine = 3;
-    ServerIssue unmatchedIssue = new ServerIssueFromDb(new IssueDto().setKee("ABCDE").setReporter("freddy").setLine(issueOnLine).setStatus("OPEN")
-      .setRuleKey("manual", "Performance"));
-    when(ruleFinder.findByKey(RuleKey.of("manual", "Performance"))).thenReturn(new Rule("manual", "Performance"));
-
-    IssueTrackingResult trackingResult = new IssueTrackingResult();
-    trackingResult.addUnmatched(unmatchedIssue);
-
-    String originalSource = "public class Action {\n"
-      + "   void method1() {\n"
-      + "     notify();\n" // initial issue
-      + "   }\n"
-      + "}";
-    String newSource = "public class Action {\n"
-      + "   \n"
-      + "   void method1() {\n" // new issue will appear here
-      + "     notify();\n"
-      + "   }\n"
-      + "   void method2() {\n"
-      + "     notify();\n"
-      + "   }\n"
-      + "}";
-    Resource file = mockHashes(originalSource, newSource);
-
-    when(tracking.track(isA(SourceHashHolder.class), anyCollection(), anyCollection())).thenReturn(trackingResult);
-
-    decorator.doDecorate(file);
-
-    verify(workflow, times(1)).doAutomaticTransition(any(DefaultIssue.class), any(IssueChangeContext.class));
-    verify(handlers, times(1)).execute(any(DefaultIssue.class), any(IssueChangeContext.class));
-
-    ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class);
-    verify(issueCache).put(argument.capture());
-
-    DefaultIssue issue = argument.getValue();
-    assertThat(issue.line()).isEqualTo(issueOnLine);
-    assertThat(issue.key()).isEqualTo("ABCDE");
-    assertThat(issue.isNew()).isFalse();
-    assertThat(issue.isEndOfLife()).isFalse();
-    assertThat(issue.isOnDisabledRule()).isFalse();
-  }
-
-  @Test
-  public void manual_issues_should_be_closed_if_manual_rule_is_removed() throws Exception {
-    // "Unmatched" issues existed in previous scan but not in current one -> they have to be closed
-
-    // INPUT : one issue existing during previous scan
-    ServerIssue unmatchedIssue = new ServerIssueFromDb(new IssueDto().setKee("ABCDE").setReporter("freddy").setLine(1).setStatus("OPEN").setRuleKey("manual", "Performance"));
-    when(ruleFinder.findByKey(RuleKey.of("manual", "Performance"))).thenReturn(new Rule("manual", "Performance").setStatus(Rule.STATUS_REMOVED));
-
-    IssueTrackingResult trackingResult = new IssueTrackingResult();
-    trackingResult.addUnmatched(unmatchedIssue);
-
-    String source = "public interface Action {}";
-    Resource file = mockHashes(source, source);
-
-    when(tracking.track(isA(SourceHashHolder.class), anyCollection(), anyCollection())).thenReturn(trackingResult);
-
-    decorator.doDecorate(file);
-
-    verify(workflow, times(1)).doAutomaticTransition(any(DefaultIssue.class), any(IssueChangeContext.class));
-    verify(handlers, times(1)).execute(any(DefaultIssue.class), any(IssueChangeContext.class));
-
-    ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class);
-    verify(issueCache).put(argument.capture());
-
-    DefaultIssue issue = argument.getValue();
-    assertThat(issue.key()).isEqualTo("ABCDE");
-    assertThat(issue.isNew()).isFalse();
-    assertThat(issue.isEndOfLife()).isTrue();
-    assertThat(issue.isOnDisabledRule()).isTrue();
-  }
-
-  @Test
-  public void manual_issues_should_be_closed_if_manual_rule_is_not_found() throws Exception {
-    // "Unmatched" issues existed in previous scan but not in current one -> they have to be closed
-
-    // INPUT : one issue existing during previous scan
-    ServerIssue unmatchedIssue = new ServerIssueFromDb(new IssueDto().setKee("ABCDE").setReporter("freddy").setLine(1).setStatus("OPEN").setRuleKey("manual", "Performance"));
-    when(ruleFinder.findByKey(RuleKey.of("manual", "Performance"))).thenReturn(null);
-
-    IssueTrackingResult trackingResult = new IssueTrackingResult();
-    trackingResult.addUnmatched(unmatchedIssue);
-
-    String source = "public interface Action {}";
-    Resource file = mockHashes(source, source);
-
-    when(tracking.track(isA(SourceHashHolder.class), anyCollection(), anyCollection())).thenReturn(trackingResult);
-
-    decorator.doDecorate(file);
-
-    verify(workflow, times(1)).doAutomaticTransition(any(DefaultIssue.class), any(IssueChangeContext.class));
-    verify(handlers, times(1)).execute(any(DefaultIssue.class), any(IssueChangeContext.class));
-
-    ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class);
-    verify(issueCache).put(argument.capture());
-
-    DefaultIssue issue = argument.getValue();
-    assertThat(issue.key()).isEqualTo("ABCDE");
-    assertThat(issue.isNew()).isFalse();
-    assertThat(issue.isEndOfLife()).isTrue();
-    assertThat(issue.isOnDisabledRule()).isTrue();
-  }
-
-  @Test
-  public void manual_issues_should_be_closed_if_new_source_is_shorter() throws Exception {
-    // "Unmatched" issues existed in previous scan but not in current one -> they have to be closed
-
-    // INPUT : one issue existing during previous scan
-    ServerIssue unmatchedIssue = new ServerIssueFromDb(new IssueDto().setKee("ABCDE").setReporter("freddy").setLine(6).setStatus("OPEN").setRuleKey("manual", "Performance"));
-    when(ruleFinder.findByKey(RuleKey.of("manual", "Performance"))).thenReturn(null);
-
-    IssueTrackingResult trackingResult = new IssueTrackingResult();
-    trackingResult.addUnmatched(unmatchedIssue);
-
-    String originalSource = "public interface Action {\n"
-      + "   void method1();\n"
-      + "   void method2();\n"
-      + "   void method3();\n"
-      + "   void method4();\n"
-      + "   void method5();\n"
-      + "}";
-    String newSource = "public interface Action {\n"
-      + "   void method1();\n"
-      + "   void method2();\n"
-      + "}";
-    Resource file = mockHashes(originalSource, newSource);
-
-    when(tracking.track(isA(SourceHashHolder.class), anyCollection(), anyCollection())).thenReturn(trackingResult);
-
-    decorator.doDecorate(file);
-
-    verify(workflow, times(1)).doAutomaticTransition(any(DefaultIssue.class), any(IssueChangeContext.class));
-    verify(handlers, times(1)).execute(any(DefaultIssue.class), any(IssueChangeContext.class));
-
-    ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class);
-    verify(issueCache).put(argument.capture());
-
-    DefaultIssue issue = argument.getValue();
-    verify(updater).setResolution(eq(issue), eq(Issue.RESOLUTION_REMOVED), any(IssueChangeContext.class));
-    verify(updater).setStatus(eq(issue), eq(Issue.STATUS_CLOSED), any(IssueChangeContext.class));
-
-    assertThat(issue.key()).isEqualTo("ABCDE");
-    assertThat(issue.isNew()).isFalse();
-    assertThat(issue.isEndOfLife()).isTrue();
-    assertThat(issue.isOnDisabledRule()).isTrue();
-  }
-
-  @Test
-  public void should_register_issues_on_deleted_components() {
-    Project project = new Project("struts");
-    DefaultIssue openIssue = new DefaultIssue();
-    when(issueCache.byComponent("struts")).thenReturn(Arrays.asList(openIssue));
-    IssueDto deadIssue = new IssueDto().setKee("ABCDE").setResolution(null).setStatus("OPEN").setRuleKey("squid", "AvoidCycle");
-    when(initialOpenIssues.selectAllIssues()).thenReturn(Arrays.asList(deadIssue));
-
-    decorator.doDecorate(project);
-
-    // the dead issue must be closed -> apply automatic transition, notify handlers and add to cache
-    verify(workflow, times(2)).doAutomaticTransition(any(DefaultIssue.class), any(IssueChangeContext.class));
-    verify(handlers, times(2)).execute(any(DefaultIssue.class), any(IssueChangeContext.class));
-    verify(issueCache, times(2)).put(any(DefaultIssue.class));
-
-    verify(issueCache).put(argThat(new ArgumentMatcher<DefaultIssue>() {
-      @Override
-      public boolean matches(Object o) {
-        DefaultIssue dead = (DefaultIssue) o;
-        return "ABCDE".equals(dead.key()) && !dead.isNew() && dead.isEndOfLife();
-      }
-    }));
-  }
-
-  @Test
-  public void merge_matched_issue() {
-    ServerIssue previousIssue = new ServerIssueFromDb(new IssueDto().setKee("ABCDE").setResolution(null).setStatus("OPEN").setRuleKey("squid", "AvoidCycle")
-      .setLine(10).setSeverity("MAJOR").setMessage("Message").setEffortToFix(1.5).setDebt(1L).setProjectKey("sample"));
-    DefaultIssue issue = new DefaultIssue();
-
-    IssueTrackingResult trackingResult = mock(IssueTrackingResult.class);
-    when(trackingResult.matched()).thenReturn(newArrayList(issue));
-    when(trackingResult.matching(eq(issue))).thenReturn(previousIssue);
-    decorator.mergeMatched(trackingResult);
-
-    verify(updater).setPastSeverity(eq(issue), eq("MAJOR"), any(IssueChangeContext.class));
-    verify(updater).setPastLine(eq(issue), eq(10));
-    verify(updater).setPastMessage(eq(issue), eq("Message"), any(IssueChangeContext.class));
-    verify(updater).setPastEffortToFix(eq(issue), eq(1.5), any(IssueChangeContext.class));
-    verify(updater).setPastTechnicalDebt(eq(issue), eq(Duration.create(1L)), any(IssueChangeContext.class));
-    verify(updater).setPastProject(eq(issue), eq("sample"), any(IssueChangeContext.class));
-  }
-
-  @Test
-  public void merge_matched_issue_on_manual_severity() {
-    ServerIssue previousIssue = new ServerIssueFromDb(new IssueDto().setKee("ABCDE").setResolution(null).setStatus("OPEN").setRuleKey("squid", "AvoidCycle")
-      .setLine(10).setManualSeverity(true).setSeverity("MAJOR").setMessage("Message").setEffortToFix(1.5).setDebt(1L));
-    DefaultIssue issue = new DefaultIssue();
-
-    IssueTrackingResult trackingResult = mock(IssueTrackingResult.class);
-    when(trackingResult.matched()).thenReturn(newArrayList(issue));
-    when(trackingResult.matching(eq(issue))).thenReturn(previousIssue);
-    decorator.mergeMatched(trackingResult);
-
-    assertThat(issue.manualSeverity()).isTrue();
-    assertThat(issue.severity()).isEqualTo("MAJOR");
-    verify(updater, never()).setPastSeverity(eq(issue), anyString(), any(IssueChangeContext.class));
-  }
-
-  @Test
-  public void merge_issue_changelog_with_previous_changelog() {
-    when(initialOpenIssues.selectChangelog("ABCDE")).thenReturn(newArrayList(new IssueChangeDto().setIssueKey("ABCD").setCreatedAt(System2.INSTANCE.now())));
-
-    ServerIssue previousIssue = new ServerIssueFromDb(new IssueDto().setKee("ABCDE").setResolution(null).setStatus("OPEN").setRuleKey("squid", "AvoidCycle")
-      .setLine(10).setMessage("Message").setEffortToFix(1.5).setDebt(1L).setCreatedAt(System2.INSTANCE.now()));
-    DefaultIssue issue = new DefaultIssue();
-
-    IssueTrackingResult trackingResult = mock(IssueTrackingResult.class);
-    when(trackingResult.matched()).thenReturn(newArrayList(issue));
-    when(trackingResult.matching(eq(issue))).thenReturn(previousIssue);
-    decorator.mergeMatched(trackingResult);
-
-    assertThat(issue.changes()).hasSize(1);
-  }
-
-  private String[] computeHexHashes(String source) {
-    String[] lines = source.split("\n");
-    String[] hashes = new String[lines.length];
-    for (int i = 0; i < lines.length; i++) {
-      hashes[i] = DigestUtils.md5Hex(lines[i].replaceAll("[\t ]", ""));
-    }
-    return hashes;
-  }
-
-}
index 062c539b457bda487aa8b008d4f281e900ebcd43..ae678c34bd32cd5192d18ffdd1910ad21d487e7c 100644 (file)
@@ -32,7 +32,7 @@ import org.junit.rules.ExpectedException;
 import org.junit.rules.TemporaryFolder;
 import org.sonar.api.batch.fs.internal.DefaultInputFile;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.api.resources.Project;
 import org.sonar.api.resources.Resource;
 import org.sonar.api.rule.RuleKey;
index 5db240ddeb50bd1bbbb967d8c864d774c5f16482..081dcb968b58b52487c7e3f665eebed020eb7a6e 100644 (file)
@@ -26,7 +26,7 @@ import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.postjob.issue.Issue;
 import org.sonar.api.batch.rule.Severity;
 import org.sonar.api.config.Settings;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.api.resources.File;
 import org.sonar.batch.index.BatchComponentCache;
 import org.sonar.batch.issue.IssueCache;
index 0aa11588a8c1db7102f1b152e8808a1eb1d5625c..1ff8b82c9c42bf1a9cbe17f53bb59c5a7bba43dc 100644 (file)
 package org.sonar.batch.profiling;
 
 import com.google.common.collect.Maps;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -48,14 +52,6 @@ import org.sonar.api.resources.Resource;
 import org.sonar.api.utils.System2;
 import org.sonar.batch.bootstrap.BootstrapProperties;
 import org.sonar.batch.events.BatchStepEvent;
-import org.sonar.batch.index.ScanPersister;
-import org.sonar.batch.phases.event.PersisterExecutionHandler;
-import org.sonar.batch.phases.event.PersistersPhaseHandler;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.spy;
@@ -88,7 +84,6 @@ public class PhasesSumUpTimeProfilerTest {
     assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.INIT).getProfilingPerItem(new FakeInitializer()).totalTime()).isEqualTo(7L);
     assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.SENSOR).getProfilingPerItem(new FakeSensor()).totalTime()).isEqualTo(10L);
     assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.DECORATOR).getProfilingPerItem(new FakeDecorator1()).totalTime()).isEqualTo(20L);
-    assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.PERSISTER).getProfilingPerItem(new FakeScanPersister()).totalTime()).isEqualTo(40L);
     assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.POSTJOB).getProfilingPerItem(new FakePostJob()).totalTime()).isEqualTo(30L);
     assertThat(profiler.currentModuleProfiling.getProfilingPerBatchStep("Free memory").totalTime()).isEqualTo(9L);
 
@@ -109,14 +104,12 @@ public class PhasesSumUpTimeProfilerTest {
     assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.SENSOR).getProfilingPerItem(new FakeSensor()).totalTime()).isEqualTo(10L);
     assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.DECORATOR).getProfilingPerItem(new FakeDecorator1()).totalTime()).isEqualTo(20L);
     assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.DECORATOR).getProfilingPerItem(new FakeDecorator2()).totalTime()).isEqualTo(10L);
-    assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.PERSISTER).getProfilingPerItem(new FakeScanPersister()).totalTime()).isEqualTo(40L);
     assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.POSTJOB).getProfilingPerItem(new FakePostJob()).totalTime()).isEqualTo(30L);
 
     assertThat(profiler.totalProfiling.getProfilingPerPhase(Phase.INIT).getProfilingPerItem(new FakeInitializer()).totalTime()).isEqualTo(21L);
     assertThat(profiler.totalProfiling.getProfilingPerPhase(Phase.SENSOR).getProfilingPerItem(new FakeSensor()).totalTime()).isEqualTo(30L);
     assertThat(profiler.totalProfiling.getProfilingPerPhase(Phase.DECORATOR).getProfilingPerItem(new FakeDecorator1()).totalTime()).isEqualTo(60L);
     assertThat(profiler.totalProfiling.getProfilingPerPhase(Phase.DECORATOR).getProfilingPerItem(new FakeDecorator2()).totalTime()).isEqualTo(30L);
-    assertThat(profiler.totalProfiling.getProfilingPerPhase(Phase.PERSISTER).getProfilingPerItem(new FakeScanPersister()).totalTime()).isEqualTo(120L);
     assertThat(profiler.totalProfiling.getProfilingPerPhase(Phase.POSTJOB).getProfilingPerItem(new FakePostJob()).totalTime()).isEqualTo(90L);
   }
 
@@ -164,7 +157,6 @@ public class PhasesSumUpTimeProfilerTest {
     initializerPhase(profiler);
     sensorPhase(profiler);
     decoratorPhase(profiler);
-    persistersPhase(profiler);
     postJobPhase(profiler);
     batchStep(profiler);
     // End of moduleA
@@ -234,19 +226,6 @@ public class PhasesSumUpTimeProfilerTest {
     profiler.onSensorsPhase(sensorsEvent(false));
   }
 
-  private void persistersPhase(PhasesSumUpTimeProfiler profiler) {
-    ScanPersister persister = new FakeScanPersister();
-    // Start of persister phase
-    profiler.onPersistersPhase(persistersEvent(true));
-    // Start of a ScanPersister
-    profiler.onPersisterExecution(persisterEvent(persister, true));
-    clock.sleep(40);
-    // End of a ScanPersister
-    profiler.onPersisterExecution(persisterEvent(persister, false));
-    // End of persister phase
-    profiler.onPersistersPhase(persistersEvent(false));
-  }
-
   private void postJobPhase(PhasesSumUpTimeProfiler profiler) {
     PostJob postJob = new FakePostJob();
     // Start of sensor phase
@@ -340,26 +319,6 @@ public class PhasesSumUpTimeProfilerTest {
     };
   }
 
-  private PersisterExecutionHandler.PersisterExecutionEvent persisterEvent(final ScanPersister persister, final boolean start) {
-    return new PersisterExecutionHandler.PersisterExecutionEvent() {
-
-      @Override
-      public boolean isStart() {
-        return start;
-      }
-
-      @Override
-      public boolean isEnd() {
-        return !start;
-      }
-
-      @Override
-      public ScanPersister getPersister() {
-        return persister;
-      }
-    };
-  }
-
   private SensorsPhaseEvent sensorsEvent(final boolean start) {
     return new SensorsPhaseHandler.SensorsPhaseEvent() {
 
@@ -420,26 +379,6 @@ public class PhasesSumUpTimeProfilerTest {
     };
   }
 
-  private PersistersPhaseHandler.PersistersPhaseEvent persistersEvent(final boolean start) {
-    return new PersistersPhaseHandler.PersistersPhaseEvent() {
-
-      @Override
-      public boolean isStart() {
-        return start;
-      }
-
-      @Override
-      public boolean isEnd() {
-        return !start;
-      }
-
-      @Override
-      public List<ScanPersister> getPersisters() {
-        return null;
-      }
-    };
-  }
-
   private DecoratorsPhaseHandler.DecoratorsPhaseEvent decoratorsEvent(final boolean start) {
     return new DecoratorsPhaseHandler.DecoratorsPhaseEvent() {
 
@@ -528,10 +467,4 @@ public class PhasesSumUpTimeProfilerTest {
     public void executeOn(Project project, SensorContext context) {
     }
   }
-
-  public class FakeScanPersister implements ScanPersister {
-    @Override
-    public void persist() {
-    }
-  }
 }
index 8e49ddb719f467a689143d6508049c9e62b5eff0..fbe835369f3035af44dcb0c6464b009b865453d8 100644 (file)
@@ -30,8 +30,6 @@ 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.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.FieldDiffs;
 import org.sonar.api.resources.Project;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.utils.Duration;
@@ -41,6 +39,8 @@ 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;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Matchers.anyString;
@@ -110,7 +110,6 @@ public class IssuesPublisherTest {
     Metadata metadata = reader.readMetadata();
     assertThat(metadata.getAnalysisDate()).isEqualTo(1234567L);
     assertThat(metadata.getProjectKey()).isEqualTo("foo");
-    assertThat(metadata.getDeletedComponentsCount()).isEqualTo(0);
 
     assertThat(reader.readComponentIssues(1)).hasSize(0);
     assertThat(reader.readComponentIssues(2)).hasSize(2);
@@ -118,7 +117,7 @@ public class IssuesPublisherTest {
   }
 
   @Test
-  public void publishMatadataWithBranch() throws Exception {
+  public void publishMetadataWithBranch() throws Exception {
     root.properties().put(CoreProperties.PROJECT_BRANCH_PROPERTY, "myBranch");
     p.setKey("foo:myBranch");
     p.setEffectiveKey("foo:myBranch");
@@ -133,56 +132,6 @@ public class IssuesPublisherTest {
     assertThat(metadata.getAnalysisDate()).isEqualTo(1234567L);
     assertThat(metadata.getProjectKey()).isEqualTo("foo");
     assertThat(metadata.getBranch()).isEqualTo("myBranch");
-    assertThat(metadata.getDeletedComponentsCount()).isEqualTo(0);
   }
 
-  @Test
-  public void publishIssuesOfDeletedComponents() throws Exception {
-
-    DefaultIssue issue1 = new DefaultIssue();
-    issue1.setKey("uuid");
-    issue1.setComponentUuid("deletedUuid");
-    issue1.setSeverity("MAJOR");
-    issue1.setRuleKey(RuleKey.of("repo", "rule"));
-    DefaultIssue issue2 = new DefaultIssue();
-    issue2.setKey("uuid2");
-    issue2.setComponentUuid("deletedUuid");
-    issue2.setSeverity("MAJOR");
-    issue2.setRuleKey(RuleKey.of("repo", "rule"));
-    issue2.setLine(2);
-    issue2.setMessage("msg");
-    issue2.setEffortToFix(2d);
-    issue2.setDebt(Duration.create(2));
-    issue2.setResolution("FIXED");
-    issue2.setStatus("RESOLVED");
-    issue2.setChecksum("checksum");
-    issue2.setReporter("reporter");
-    issue2.setAssignee("assignee");
-    issue2.setActionPlanKey("action");
-    issue2.setAuthorLogin("author");
-    issue2.setCurrentChange(new FieldDiffs().setUserLogin("foo"));
-    issue2.setCreationDate(new Date());
-    issue2.setUpdateDate(new Date());
-    issue2.setCloseDate(new Date());
-    issue2.setSelectedAt(1234L);
-
-    when(issueCache.byComponent("foo:deleted.php")).thenReturn(Arrays.asList(issue1, issue2));
-
-    when(issueCache.componentKeys()).thenReturn(Arrays.<Object>asList("foo:deleted.php"));
-
-    File outputDir = temp.newFolder();
-    BatchReportWriter writer = new BatchReportWriter(outputDir);
-
-    publisher.publish(writer);
-
-    BatchReportReader reader = new BatchReportReader(outputDir);
-    Metadata metadata = reader.readMetadata();
-    assertThat(metadata.getDeletedComponentsCount()).isEqualTo(1);
-
-    assertThat(reader.readComponentIssues(1)).hasSize(0);
-    assertThat(reader.readComponentIssues(2)).hasSize(0);
-    assertThat(reader.readDeletedComponentIssues(1).getComponentUuid()).isEqualTo("deletedUuid");
-    assertThat(reader.readDeletedComponentIssues(1).getIssueList()).hasSize(2);
-
-  }
 }
index f5a1482e608942dac190d1d488cf14a0ba28e747..fc3355952c02e2ea229406b12117878677a0ae66 100644 (file)
@@ -25,7 +25,7 @@ import org.junit.Test;
 import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.fs.internal.DefaultInputFile;
 import org.sonar.api.config.Settings;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.api.rule.Severity;
 import org.sonar.api.utils.log.LogTester;
 import org.sonar.batch.issue.IssueCache;
index 0a346666ad5eb9117f98815f7274cbf905fc78bb..afc0d4c39aa900bc9cfac7ceb0f2429c4d9b50b6 100644 (file)
@@ -33,7 +33,7 @@ import org.sonar.api.batch.rule.ActiveRules;
 import org.sonar.api.batch.rule.internal.ActiveRulesBuilder;
 import org.sonar.api.config.Settings;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.api.platform.Server;
 import org.sonar.api.resources.Project;
 import org.sonar.api.resources.Resource;
index d62fd760616468447ce8d3c520624cc52d691a6d..69b176538a1bc8510b096521f0e40f11873746bb 100644 (file)
@@ -144,7 +144,7 @@ public class DefaultSensorStorageTest {
   public void shouldAddIssueOnFile() {
     InputFile file = new DefaultInputFile("foo", "src/Foo.php").setLines(4);
 
-    ArgumentCaptor<org.sonar.api.issue.internal.DefaultIssue> argumentCaptor = ArgumentCaptor.forClass(org.sonar.api.issue.internal.DefaultIssue.class);
+    ArgumentCaptor<org.sonar.core.issue.DefaultIssue> argumentCaptor = ArgumentCaptor.forClass(org.sonar.core.issue.DefaultIssue.class);
 
     sensorStorage.store(new DefaultIssue()
       .onFile(file)
@@ -155,7 +155,7 @@ public class DefaultSensorStorageTest {
 
     verify(moduleIssues).initAndAddIssue(argumentCaptor.capture());
 
-    org.sonar.api.issue.internal.DefaultIssue issue = argumentCaptor.getValue();
+    org.sonar.core.issue.DefaultIssue issue = argumentCaptor.getValue();
     assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("foo", "bar"));
     assertThat(issue.message()).isEqualTo("Foo");
     assertThat(issue.line()).isEqualTo(3);
@@ -167,7 +167,7 @@ public class DefaultSensorStorageTest {
   public void shouldAddIssueOnDirectory() {
     InputDir dir = new DefaultInputDir("foo", "src");
 
-    ArgumentCaptor<org.sonar.api.issue.internal.DefaultIssue> argumentCaptor = ArgumentCaptor.forClass(org.sonar.api.issue.internal.DefaultIssue.class);
+    ArgumentCaptor<org.sonar.core.issue.DefaultIssue> argumentCaptor = ArgumentCaptor.forClass(org.sonar.core.issue.DefaultIssue.class);
 
     sensorStorage.store(new DefaultIssue()
       .onDir(dir)
@@ -177,7 +177,7 @@ public class DefaultSensorStorageTest {
 
     verify(moduleIssues).initAndAddIssue(argumentCaptor.capture());
 
-    org.sonar.api.issue.internal.DefaultIssue issue = argumentCaptor.getValue();
+    org.sonar.core.issue.DefaultIssue issue = argumentCaptor.getValue();
     assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("foo", "bar"));
     assertThat(issue.message()).isEqualTo("Foo");
     assertThat(issue.line()).isNull();
@@ -187,7 +187,7 @@ public class DefaultSensorStorageTest {
 
   @Test
   public void shouldAddIssueOnProject() {
-    ArgumentCaptor<org.sonar.api.issue.internal.DefaultIssue> argumentCaptor = ArgumentCaptor.forClass(org.sonar.api.issue.internal.DefaultIssue.class);
+    ArgumentCaptor<org.sonar.core.issue.DefaultIssue> argumentCaptor = ArgumentCaptor.forClass(org.sonar.core.issue.DefaultIssue.class);
 
     sensorStorage.store(new DefaultIssue()
       .onProject()
@@ -198,7 +198,7 @@ public class DefaultSensorStorageTest {
 
     verify(moduleIssues).initAndAddIssue(argumentCaptor.capture());
 
-    org.sonar.api.issue.internal.DefaultIssue issue = argumentCaptor.getValue();
+    org.sonar.core.issue.DefaultIssue issue = argumentCaptor.getValue();
     assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("foo", "bar"));
     assertThat(issue.message()).isEqualTo("Foo");
     assertThat(issue.line()).isNull();
diff --git a/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssue.java b/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssue.java
new file mode 100644 (file)
index 0000000..9439aad
--- /dev/null
@@ -0,0 +1,613 @@
+/*
+ * 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.issue;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.builder.ToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+import org.apache.commons.lang.time.DateUtils;
+import org.sonar.api.issue.Issue;
+import org.sonar.api.issue.IssueComment;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.Severity;
+import org.sonar.api.utils.Duration;
+import org.sonar.core.issue.tracking.Trackable;
+
+/**
+ * PLUGINS MUST NOT BE USED THIS CLASS, EXCEPT FOR UNIT TESTING.
+ *
+ * @since 3.6
+ */
+public class DefaultIssue implements Issue, Trackable {
+
+  private String key;
+
+  private String componentUuid;
+  private String componentKey;
+
+  private String moduleUuid;
+  private String moduleUuidPath;
+
+  private String projectUuid;
+  private String projectKey;
+
+  private RuleKey ruleKey;
+  private String language;
+  private String severity;
+  private boolean manualSeverity = false;
+  private String message;
+  private Integer line;
+  private Double effortToFix;
+  private Duration debt;
+  private String status;
+  private String resolution;
+  private String reporter;
+  private String assignee;
+  private String checksum;
+  private Map<String, String> attributes = null;
+  private String authorLogin = null;
+  private String actionPlanKey;
+  private List<IssueComment> comments = null;
+  private Set<String> tags = null;
+
+  // FUNCTIONAL DATES
+  private Date creationDate;
+  private Date updateDate;
+  private Date closeDate;
+
+  // FOLLOWING FIELDS ARE AVAILABLE ONLY DURING SCAN
+
+  // Current changes
+  private FieldDiffs currentChange = null;
+
+  // all changes
+  private List<FieldDiffs> changes = null;
+
+  // true if the the issue did not exist in the previous scan.
+  private boolean isNew = true;
+
+  // True if the the issue did exist in the previous scan but not in the current one. That means
+  // that this issue should be closed.
+  private boolean beingClosed = false;
+
+  private boolean onDisabledRule = false;
+
+  // true if some fields have been changed since the previous scan
+  private boolean isChanged = false;
+
+  // true if notifications have to be sent
+  private boolean sendNotifications = false;
+
+  // Date when issue was loaded from db (only when isNew=false)
+  private Long selectedAt;
+
+  @Override
+  public String key() {
+    return key;
+  }
+
+  public DefaultIssue setKey(String key) {
+    this.key = key;
+    return this;
+  }
+
+  /**
+   * Can be null on Views or Devs
+   */
+  @Override
+  @CheckForNull
+  public String componentUuid() {
+    return componentUuid;
+  }
+
+  public DefaultIssue setComponentUuid(@CheckForNull String componentUuid) {
+    this.componentUuid = componentUuid;
+    return this;
+  }
+
+  @Override
+  public String componentKey() {
+    return componentKey;
+  }
+
+  public DefaultIssue setComponentKey(String s) {
+    this.componentKey = s;
+    return this;
+  }
+
+  @CheckForNull
+  public String moduleUuid() {
+    return moduleUuid;
+  }
+
+  public DefaultIssue setModuleUuid(@Nullable String moduleUuid) {
+    this.moduleUuid = moduleUuid;
+    return this;
+  }
+
+  @CheckForNull
+  public String moduleUuidPath() {
+    return moduleUuidPath;
+  }
+
+  public DefaultIssue setModuleUuidPath(@Nullable String moduleUuidPath) {
+    this.moduleUuidPath = moduleUuidPath;
+    return this;
+  }
+
+  /**
+   * Can be null on Views or Devs
+   */
+  @Override
+  @CheckForNull
+  public String projectUuid() {
+    return projectUuid;
+  }
+
+  public DefaultIssue setProjectUuid(@Nullable String projectUuid) {
+    this.projectUuid = projectUuid;
+    return this;
+  }
+
+  @Override
+  public String projectKey() {
+    return projectKey;
+  }
+
+  public DefaultIssue setProjectKey(String projectKey) {
+    this.projectKey = projectKey;
+    return this;
+  }
+
+  @Override
+  public RuleKey ruleKey() {
+    return ruleKey;
+  }
+
+  public DefaultIssue setRuleKey(RuleKey k) {
+    this.ruleKey = k;
+    return this;
+  }
+
+  @Override
+  public String language() {
+    return language;
+  }
+
+  public DefaultIssue setLanguage(String l) {
+    this.language = l;
+    return this;
+  }
+
+  @Override
+  public String severity() {
+    return severity;
+  }
+
+  public DefaultIssue setSeverity(@Nullable String s) {
+    Preconditions.checkArgument(s == null || Severity.ALL.contains(s), "Not a valid severity: " + s);
+    this.severity = s;
+    return this;
+  }
+
+  public boolean manualSeverity() {
+    return manualSeverity;
+  }
+
+  public DefaultIssue setManualSeverity(boolean b) {
+    this.manualSeverity = b;
+    return this;
+  }
+
+  @Override
+  @CheckForNull
+  public String message() {
+    return message;
+  }
+
+  public DefaultIssue setMessage(@Nullable String s) {
+    this.message = StringUtils.abbreviate(StringUtils.trim(s), MESSAGE_MAX_SIZE);
+    return this;
+  }
+
+  @Override
+  @CheckForNull
+  public Integer line() {
+    return line;
+  }
+
+  public DefaultIssue setLine(@Nullable Integer l) {
+    Preconditions.checkArgument(l == null || l > 0, "Line must be null or greater than zero (got " + l + ")");
+    this.line = l;
+    return this;
+  }
+
+  @Override
+  @CheckForNull
+  public Double effortToFix() {
+    return effortToFix;
+  }
+
+  public DefaultIssue setEffortToFix(@Nullable Double d) {
+    Preconditions.checkArgument(d == null || d >= 0, "Effort to fix must be greater than or equal 0 (got " + d + ")");
+    this.effortToFix = d;
+    return this;
+  }
+
+  /**
+   * Elapsed time to fix the issue
+   */
+  @Override
+  @CheckForNull
+  public Duration debt() {
+    return debt;
+  }
+
+  @CheckForNull
+  public Long debtInMinutes() {
+    return debt != null ? debt.toMinutes() : null;
+  }
+
+  public DefaultIssue setDebt(@Nullable Duration t) {
+    this.debt = t;
+    return this;
+  }
+
+  @Override
+  public String status() {
+    return status;
+  }
+
+  public DefaultIssue setStatus(String s) {
+    Preconditions.checkArgument(!Strings.isNullOrEmpty(s), "Status must be set");
+    this.status = s;
+    return this;
+  }
+
+  @Override
+  @CheckForNull
+  public String resolution() {
+    return resolution;
+  }
+
+  public DefaultIssue setResolution(@Nullable String s) {
+    this.resolution = s;
+    return this;
+  }
+
+  @Override
+  @CheckForNull
+  public String reporter() {
+    return reporter;
+  }
+
+  public DefaultIssue setReporter(@Nullable String s) {
+    this.reporter = s;
+    return this;
+  }
+
+  @Override
+  @CheckForNull
+  public String assignee() {
+    return assignee;
+  }
+
+  public DefaultIssue setAssignee(@Nullable String s) {
+    this.assignee = s;
+    return this;
+  }
+
+  @Override
+  public Date creationDate() {
+    return creationDate;
+  }
+
+  public DefaultIssue setCreationDate(Date d) {
+    // d is not marked as Nullable but we still allow null parameter for unit testing.
+    this.creationDate = (d != null ? DateUtils.truncate(d, Calendar.SECOND) : null);
+    return this;
+  }
+
+  @Override
+  @CheckForNull
+  public Date updateDate() {
+    return updateDate;
+  }
+
+  public DefaultIssue setUpdateDate(@Nullable Date d) {
+    this.updateDate = (d != null ? DateUtils.truncate(d, Calendar.SECOND) : null);
+    return this;
+  }
+
+  @Override
+  @CheckForNull
+  public Date closeDate() {
+    return closeDate;
+  }
+
+  public DefaultIssue setCloseDate(@Nullable Date d) {
+    this.closeDate = (d != null ? DateUtils.truncate(d, Calendar.SECOND) : null);
+    return this;
+  }
+
+  @CheckForNull
+  public String checksum() {
+    return checksum;
+  }
+
+  public DefaultIssue setChecksum(@Nullable String s) {
+    this.checksum = s;
+    return this;
+  }
+
+  @Override
+  public boolean isNew() {
+    return isNew;
+  }
+
+  public DefaultIssue setNew(boolean b) {
+    isNew = b;
+    return this;
+  }
+
+  /**
+   * True when one of the following conditions is true :
+   * <ul>
+   * <li>the related component has been deleted or renamed</li>
+   * <li>the rule has been deleted (eg. on plugin uninstall)</li>
+   * <li>the rule has been disabled in the Quality profile</li>
+   * </ul>
+   */
+  public boolean isBeingClosed() {
+    return beingClosed;
+  }
+
+  public DefaultIssue setBeingClosed(boolean b) {
+    beingClosed = b;
+    return this;
+  }
+
+  public boolean isOnDisabledRule() {
+    return onDisabledRule;
+  }
+
+  public DefaultIssue setOnDisabledRule(boolean b) {
+    onDisabledRule = b;
+    return this;
+  }
+
+  public boolean isChanged() {
+    return isChanged;
+  }
+
+  public DefaultIssue setChanged(boolean b) {
+    isChanged = b;
+    return this;
+  }
+
+  public boolean mustSendNotifications() {
+    return sendNotifications;
+  }
+
+  public DefaultIssue setSendNotifications(boolean b) {
+    sendNotifications = b;
+    return this;
+  }
+
+  @Override
+  @CheckForNull
+  public String attribute(String key) {
+    return attributes == null ? null : attributes.get(key);
+  }
+
+  public DefaultIssue setAttribute(String key, @Nullable String value) {
+    if (attributes == null) {
+      attributes = Maps.newHashMap();
+    }
+    if (value == null) {
+      attributes.remove(key);
+    } else {
+      attributes.put(key, value);
+    }
+    return this;
+  }
+
+  @Override
+  public Map<String, String> attributes() {
+    return attributes == null ? Collections.<String, String>emptyMap() : ImmutableMap.copyOf(attributes);
+  }
+
+  public DefaultIssue setAttributes(@Nullable Map<String, String> map) {
+    if (map != null) {
+      if (attributes == null) {
+        attributes = Maps.newHashMap();
+      }
+      attributes.putAll(map);
+    }
+    return this;
+  }
+
+  @Override
+  @CheckForNull
+  public String authorLogin() {
+    return authorLogin;
+  }
+
+  public DefaultIssue setAuthorLogin(@Nullable String s) {
+    this.authorLogin = s;
+    return this;
+  }
+
+  @Override
+  @CheckForNull
+  public String actionPlanKey() {
+    return actionPlanKey;
+  }
+
+  public DefaultIssue setActionPlanKey(@Nullable String actionPlanKey) {
+    this.actionPlanKey = actionPlanKey;
+    return this;
+  }
+
+  public DefaultIssue setFieldChange(IssueChangeContext context, String field, @Nullable Serializable oldValue, @Nullable Serializable newValue) {
+    if (!Objects.equal(oldValue, newValue)) {
+      if (currentChange == null) {
+        currentChange = new FieldDiffs();
+        currentChange.setUserLogin(context.login());
+        currentChange.setCreationDate(context.date());
+      }
+      currentChange.setDiff(field, oldValue, newValue);
+    }
+    addChange(currentChange);
+    return this;
+  }
+
+  public DefaultIssue setCurrentChange(FieldDiffs currentChange) {
+    this.currentChange = currentChange;
+    addChange(currentChange);
+    return this;
+  }
+
+  @CheckForNull
+  public FieldDiffs currentChange() {
+    return currentChange;
+  }
+
+  public DefaultIssue addChange(FieldDiffs change) {
+    if (changes == null) {
+      changes = new ArrayList<>();
+    }
+    changes.add(change);
+    return this;
+  }
+
+  public DefaultIssue setChanges(List<FieldDiffs> changes) {
+    this.changes = changes;
+    return this;
+  }
+
+  public List<FieldDiffs> changes() {
+    if (changes == null) {
+      return Collections.emptyList();
+    }
+    return ImmutableList.copyOf(changes);
+  }
+
+  public DefaultIssue addComment(DefaultIssueComment comment) {
+    if (comments == null) {
+      comments = new ArrayList<>();
+    }
+    comments.add(comment);
+    return this;
+  }
+
+  @Override
+  public List<IssueComment> comments() {
+    if (comments == null) {
+      return Collections.emptyList();
+    }
+    return ImmutableList.copyOf(comments);
+  }
+
+  @CheckForNull
+  public Long selectedAt() {
+    return selectedAt;
+  }
+
+  public DefaultIssue setSelectedAt(@Nullable Long d) {
+    this.selectedAt = d;
+    return this;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+    DefaultIssue that = (DefaultIssue) o;
+    return !(key != null ? !key.equals(that.key) : (that.key != null));
+  }
+
+  @Override
+  public int hashCode() {
+    return key != null ? key.hashCode() : 0;
+  }
+
+  @Override
+  public String toString() {
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
+  }
+
+  @Override
+  public Set<String> tags() {
+    if (tags == null) {
+      return ImmutableSet.of();
+    } else {
+      return ImmutableSet.copyOf(tags);
+    }
+  }
+
+  public DefaultIssue setTags(Collection<String> tags) {
+    this.tags = new LinkedHashSet<>(tags);
+    return this;
+  }
+
+  @Override
+  public Integer getLine() {
+    return line;
+  }
+
+  @Override
+  public String getMessage() {
+    return message;
+  }
+
+  @Override
+  public String getLineHash() {
+    return checksum;
+  }
+
+  @Override
+  public RuleKey getRuleKey() {
+    return ruleKey;
+  }
+}
index 3c39b5daddefc4097cf5145091e8d006f58feae6..962a45919161fa43ec015b71b8daefeef25f08ed 100644 (file)
@@ -23,7 +23,6 @@ import com.google.common.base.Preconditions;
 import com.google.common.collect.Maps;
 import org.sonar.api.issue.Issuable;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.utils.internal.Uuids;
 
@@ -132,7 +131,7 @@ public class DefaultIssueBuilder implements Issuable.IssueBuilder {
     issue.setStatus(Issue.STATUS_OPEN);
     issue.setCloseDate(null);
     issue.setNew(true);
-    issue.setEndOfLife(false);
+    issue.setBeingClosed(false);
     issue.setOnDisabledRule(false);
     return issue;
   }
diff --git a/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssueComment.java b/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssueComment.java
new file mode 100644 (file)
index 0000000..3a5b23b
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * 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.issue;
+
+import org.sonar.api.issue.IssueComment;
+import org.sonar.api.utils.internal.Uuids;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * PLUGINS MUST NOT BE USED THIS CLASS, EXCEPT FOR UNIT TESTING.
+ *
+ * @since 3.6
+ */
+public class DefaultIssueComment implements Serializable, IssueComment {
+
+  private String issueKey;
+  private String userLogin;
+  private Date createdAt;
+  private Date updatedAt;
+  private String key;
+  private String markdownText;
+  private boolean isNew;
+
+  public static DefaultIssueComment create(String issueKey, @Nullable String login, String markdownText) {
+    DefaultIssueComment comment = new DefaultIssueComment();
+    comment.setIssueKey(issueKey);
+    comment.setKey(Uuids.create());
+    Date now = new Date();
+    comment.setUserLogin(login);
+    comment.setMarkdownText(markdownText);
+    comment.setCreatedAt(now).setUpdatedAt(now);
+    comment.setNew(true);
+    return comment;
+  }
+
+  @Override
+  public String markdownText() {
+    return markdownText;
+  }
+
+  public DefaultIssueComment setMarkdownText(String s) {
+    this.markdownText = s;
+    return this;
+  }
+
+  @Override
+  public String issueKey() {
+    return issueKey;
+  }
+
+  public DefaultIssueComment setIssueKey(String s) {
+    this.issueKey = s;
+    return this;
+  }
+
+  @Override
+  public String key() {
+    return key;
+  }
+
+  public DefaultIssueComment setKey(String key) {
+    this.key = key;
+    return this;
+  }
+
+  /**
+   * The user who created the comment. Null if it was automatically generated during project scan.
+   */
+  @Override
+  @CheckForNull
+  public String userLogin() {
+    return userLogin;
+  }
+
+  public DefaultIssueComment setUserLogin(@Nullable String userLogin) {
+    this.userLogin = userLogin;
+    return this;
+  }
+
+  @Override
+  public Date createdAt() {
+    return createdAt;
+  }
+
+  public DefaultIssueComment setCreatedAt(Date createdAt) {
+    this.createdAt = createdAt;
+    return this;
+  }
+
+  @Override
+  public Date updatedAt() {
+    return updatedAt;
+  }
+
+  public DefaultIssueComment setUpdatedAt(@Nullable Date updatedAt) {
+    this.updatedAt = updatedAt;
+    return this;
+  }
+
+  public boolean isNew() {
+    return isNew;
+  }
+
+  public DefaultIssueComment setNew(boolean b) {
+    isNew = b;
+    return this;
+  }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/issue/FieldDiffs.java b/sonar-core/src/main/java/org/sonar/core/issue/FieldDiffs.java
new file mode 100644 (file)
index 0000000..d162056
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * 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.issue;
+
+import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
+import com.google.common.collect.Maps;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Map;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+/**
+ * PLUGINS MUST NOT USE THIS CLASS, EXCEPT FOR UNIT TESTING.
+ *
+ * @since 3.6
+ */
+public class FieldDiffs implements Serializable {
+
+  public static final Splitter FIELDS_SPLITTER = Splitter.on(',').omitEmptyStrings();
+
+  private String issueKey;
+  private String userLogin;
+  private Date creationDate;
+
+  private final Map<String, Diff> diffs = Maps.newLinkedHashMap();
+
+  public Map<String, Diff> diffs() {
+    return diffs;
+  }
+
+  public Diff get(String field) {
+    return diffs.get(field);
+  }
+
+  @CheckForNull
+  public String userLogin() {
+    return userLogin;
+  }
+
+  public FieldDiffs setUserLogin(@Nullable String s) {
+    this.userLogin = s;
+    return this;
+  }
+
+  public Date creationDate() {
+    return creationDate;
+  }
+
+  public FieldDiffs setCreationDate(Date creationDate) {
+    this.creationDate = creationDate;
+    return this;
+  }
+
+  public String issueKey() {
+    return issueKey;
+  }
+
+  public FieldDiffs setIssueKey(String issueKey) {
+    this.issueKey = issueKey;
+    return this;
+  }
+
+  @SuppressWarnings("unchecked")
+  public FieldDiffs setDiff(String field, @Nullable Serializable oldValue, @Nullable Serializable newValue) {
+    Diff diff = diffs.get(field);
+    if (diff == null) {
+      diff = new Diff(oldValue, newValue);
+      diffs.put(field, diff);
+    } else {
+      diff.setNewValue(newValue);
+    }
+    return this;
+  }
+
+  @Override
+  public String toString() {
+    StringBuilder sb = new StringBuilder();
+    boolean notFirst = false;
+    for (Map.Entry<String, Diff> entry : diffs.entrySet()) {
+      if (notFirst) {
+        sb.append(',');
+      } else {
+        notFirst = true;
+      }
+      sb.append(entry.getKey());
+      sb.append('=');
+      sb.append(entry.getValue().toString());
+    }
+    return sb.toString();
+  }
+
+  public static FieldDiffs parse(@Nullable String s) {
+    FieldDiffs diffs = new FieldDiffs();
+    if (!Strings.isNullOrEmpty(s)) {
+      Iterable<String> fields = FIELDS_SPLITTER.split(s);
+      for (String field : fields) {
+        String[] keyValues = field.split("=");
+        if (keyValues.length == 2) {
+          String[] values = keyValues[1].split("\\|");
+          String oldValue = "";
+          String newValue = "";
+          if(values.length == 1) {
+            newValue = Strings.nullToEmpty(values[0]);
+          } else if(values.length == 2) {
+            oldValue = Strings.nullToEmpty(values[0]);
+            newValue = Strings.nullToEmpty(values[1]);
+          }
+          diffs.setDiff(keyValues[0], oldValue, newValue);
+        } else {
+          diffs.setDiff(keyValues[0], "", "");
+        }
+      }
+    }
+    return diffs;
+  }
+
+  public static class Diff<T extends Serializable> implements Serializable {
+    private T oldValue;
+    private T newValue;
+
+    public Diff(@Nullable T oldValue, @Nullable T newValue) {
+      this.oldValue = oldValue;
+      this.newValue = newValue;
+    }
+
+    @CheckForNull
+    public T oldValue() {
+      return oldValue;
+    }
+
+    @CheckForNull
+    public Long oldValueLong() {
+      return toLong(oldValue);
+    }
+
+    @CheckForNull
+    public T newValue() {
+      return newValue;
+    }
+
+    @CheckForNull
+    public Long newValueLong() {
+      return toLong(newValue);
+    }
+
+    void setNewValue(T t) {
+      this.newValue = t;
+    }
+
+    @CheckForNull
+    private static Long toLong(@Nullable Serializable value) {
+      if (value != null && !"".equals(value)) {
+        try {
+          return Long.valueOf((String) value);
+        } catch (ClassCastException e) {
+          return (Long) value;
+        }
+      }
+      return null;
+    }
+
+    @Override
+    public String toString() {
+      //TODO escape , and | characters
+      StringBuilder sb = new StringBuilder();
+      if(newValue != null) {
+        if(oldValue != null) {
+          sb.append(oldValue.toString());
+          sb.append('|');
+        }
+        sb.append(newValue.toString());
+      }
+      return sb.toString();
+    }
+  }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/issue/IssueChangeContext.java b/sonar-core/src/main/java/org/sonar/core/issue/IssueChangeContext.java
new file mode 100644 (file)
index 0000000..1df5bd5
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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.issue;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * PLUGINS MUST NOT BE USED THIS CLASS, EXCEPT FOR UNIT TESTING.
+ *
+ * @since 3.6
+ */
+public class IssueChangeContext implements Serializable {
+
+  private final String login;
+  private final Date date;
+  private final boolean scan;
+
+  private IssueChangeContext(@Nullable String login, Date date, boolean scan) {
+    this.login = login;
+    this.date = date;
+    this.scan = scan;
+  }
+
+  @CheckForNull
+  public String login() {
+    return login;
+  }
+
+  public Date date() {
+    return date;
+  }
+
+  public boolean scan() {
+    return scan;
+  }
+
+  public static IssueChangeContext createScan(Date date) {
+    return new IssueChangeContext(null, date, true);
+  }
+
+  public static IssueChangeContext createUser(Date date, @Nullable String login) {
+    return new IssueChangeContext(login, date, false);
+  }
+}
index e91e7bbdbb4c50203916d597a290cc3d55ab9318..cb3bb6079aa2dcee617881432896c86c279d4361 100644 (file)
@@ -30,9 +30,6 @@ import org.apache.commons.lang.time.DateUtils;
 import org.sonar.api.batch.BatchSide;
 import org.sonar.api.server.ServerSide;
 import org.sonar.api.issue.ActionPlan;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.DefaultIssueComment;
-import org.sonar.api.issue.internal.IssueChangeContext;
 import org.sonar.api.server.rule.RuleTagFormat;
 import org.sonar.api.user.User;
 import org.sonar.api.utils.Duration;
index 1155e70c62db3f9e3965bf8ce2eac22745d99e21..a400a04c9cd3eb3c66bbc037bc3ceaf01c03ff7c 100644 (file)
@@ -29,8 +29,8 @@ import java.util.Map;
 import javax.annotation.CheckForNull;
 import org.apache.ibatis.session.ResultHandler;
 import org.sonar.api.batch.BatchSide;
-import org.sonar.api.issue.internal.DefaultIssueComment;
-import org.sonar.api.issue.internal.FieldDiffs;
+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;
index 18b731018f1d92579abb9fe2c2819bdfbbd948fc..0d79cd47ca4498accce23b06baeeb300a52440eb 100644 (file)
@@ -21,8 +21,8 @@ package org.sonar.core.issue.db;
 
 import org.apache.commons.lang.builder.ToStringBuilder;
 import org.apache.commons.lang.builder.ToStringStyle;
-import org.sonar.api.issue.internal.DefaultIssueComment;
-import org.sonar.api.issue.internal.FieldDiffs;
+import org.sonar.core.issue.DefaultIssueComment;
+import org.sonar.core.issue.FieldDiffs;
 import org.sonar.api.utils.System2;
 
 import javax.annotation.CheckForNull;
index 1a0208b7756f7ae4cf8fefc31d03e8bb3fd85b9b..c4e2e516cf28dcd586d74da78f0f9590cea8f081 100644 (file)
@@ -20,7 +20,6 @@
 
 package org.sonar.core.issue.db;
 
-import javax.annotation.CheckForNull;
 import org.apache.ibatis.session.ResultHandler;
 import org.apache.ibatis.session.SqlSession;
 import org.sonar.api.batch.BatchSide;
@@ -41,16 +40,6 @@ public class IssueDao {
     this.mybatis = mybatis;
   }
 
-  @CheckForNull
-  public IssueDto selectByKey(String key) {
-    DbSession session = mybatis.openSession(false);
-    try {
-      return mapper(session).selectByKey(key);
-    } finally {
-      MyBatis.closeQuietly(session);
-    }
-  }
-
   public void selectNonClosedIssuesByModule(long componentId, ResultHandler handler) {
     SqlSession session = mybatis.openSession(false);
     try {
index 9b726f4b4e3a90f9ee242fbf3a92f2224f626154..44baff06b8cb7c566dad931c7f0349adf1f5df1e 100644 (file)
@@ -24,9 +24,10 @@ import com.google.common.base.Objects;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Splitter;
 import com.google.common.collect.ImmutableSet;
+import java.util.Set;
 import org.apache.commons.lang.builder.ToStringBuilder;
 import org.apache.commons.lang.builder.ToStringStyle;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.api.resources.Project;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.utils.Duration;
@@ -624,7 +625,7 @@ public final class IssueDto implements Serializable {
     return this;
   }
 
-  public Collection<String> getTags() {
+  public Set<String> getTags() {
     return ImmutableSet.copyOf(TAGS_SPLITTER.split(tags == null ? "" : tags));
   }
 
index 569fa6594496bc3dce31c8c06c94337b55e85a43..aba2531071ed47386604c94e328f5603e02ac102 100644 (file)
 package org.sonar.core.issue.db;
 
 import java.util.List;
+import java.util.Set;
 
 public interface IssueMapper {
 
   IssueDto selectByKey(String key);
 
+  List<IssueDto> selectOpenByComponentUuid(String componentUuid);
+
+  Set<String> selectComponentUuidsOfOpenIssuesForProjectUuid(String projectUuid);
+
   List<IssueDto> selectByKeys(List<String> keys);
 
   List<IssueDto> selectByActionPlan(String actionPlan);
@@ -34,5 +39,4 @@ public interface IssueMapper {
   int update(IssueDto issue);
 
   int updateIfBeforeSelectedDate(IssueDto issue);
-
 }
index c4533c9bf0d077b05ccab88aab9f0e4205b18241..fb443d7cc9e60de7eb86632ac28e1e8e4545e754 100644 (file)
@@ -21,9 +21,9 @@ package org.sonar.core.issue.db;
 
 import org.sonar.api.issue.Issue;
 import org.sonar.api.issue.IssueComment;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.DefaultIssueComment;
-import org.sonar.api.issue.internal.FieldDiffs;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.DefaultIssueComment;
+import org.sonar.core.issue.FieldDiffs;
 import org.sonar.api.rules.Rule;
 import org.sonar.api.rules.RuleFinder;
 import org.sonar.core.persistence.BatchSession;
index 4fbd892d499e2a33fa7a3c83c6d47aa2fff94ad6..7c6b48a160343a60856d6763fbe49fec6207bf33 100644 (file)
 package org.sonar.core.issue.db;
 
 import com.google.common.annotations.VisibleForTesting;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.core.issue.DefaultIssue;
 
 /**
  * Support concurrent modifications on issues made by analysis and users at the same time
  * See https://jira.sonarsource.com/browse/SONAR-4309
+ *
+ * TODO move to compute engine
  */
 public class UpdateConflictResolver {
 
-  private static final Logger LOG = LoggerFactory.getLogger(IssueStorage.class);
+  private static final Logger LOG = Loggers.get(UpdateConflictResolver.class);
 
   public void resolve(DefaultIssue issue, IssueMapper mapper) {
     LOG.debug("Resolve conflict on issue " + issue.key());
diff --git a/sonar-core/src/main/java/org/sonar/core/issue/tracking/BlockHashSequence.java b/sonar-core/src/main/java/org/sonar/core/issue/tracking/BlockHashSequence.java
new file mode 100644 (file)
index 0000000..7a4d386
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * 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.issue.tracking;
+
+import java.util.List;
+
+public class BlockHashSequence {
+
+  public static final int DEFAULT_HALF_BLOCK_SIZE = 5;
+  /**
+   * Hashes of blocks around lines. Line 1 is at index 0.
+   */
+  private final int[] blockHashes;
+
+  BlockHashSequence(LineHashSequence lineHashSequence, int halfBlockSize) {
+    this.blockHashes = new int[lineHashSequence.length()];
+
+    BlockHashFactory blockHashFactory = new BlockHashFactory(lineHashSequence.getHashes(), halfBlockSize);
+    for (int line = 1; line <= lineHashSequence.length(); line++) {
+      blockHashes[line - 1] = blockHashFactory.getHash();
+      if (line - halfBlockSize > 0) {
+        blockHashFactory.remove(lineHashSequence.getHashForLine(line - halfBlockSize).hashCode());
+      }
+      if (line + 1 + halfBlockSize <= lineHashSequence.length()) {
+        blockHashFactory.add(lineHashSequence.getHashForLine(line + 1 + halfBlockSize).hashCode());
+      } else {
+        blockHashFactory.add(0);
+      }
+    }
+  }
+
+  public static BlockHashSequence create(LineHashSequence lineHashSequence) {
+    return new BlockHashSequence(lineHashSequence, DEFAULT_HALF_BLOCK_SIZE);
+  }
+
+  /**
+   * Hash of block around line. Line must be in range of valid lines. It starts with 1.
+   */
+  public int getBlockHashForLine(int line) {
+    return blockHashes[line - 1];
+  }
+
+  private static class BlockHashFactory {
+    private static final int PRIME_BASE = 31;
+
+    private final int power;
+    private int hash = 0;
+
+    public BlockHashFactory(List<String> hashes, int halfBlockSize) {
+      int pow = 1;
+      for (int i = 0; i < halfBlockSize * 2; i++) {
+        pow = pow * PRIME_BASE;
+      }
+      this.power = pow;
+      for (int i = 1; i <= Math.min(hashes.size(), halfBlockSize + 1); i++) {
+        add(hashes.get(i - 1).hashCode());
+      }
+    }
+
+    public void add(int value) {
+      hash = hash * PRIME_BASE + value;
+    }
+
+    public void remove(int value) {
+      hash = hash - power * value;
+    }
+
+    public int getHash() {
+      return hash;
+    }
+
+  }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/issue/tracking/BlockRecognizer.java b/sonar-core/src/main/java/org/sonar/core/issue/tracking/BlockRecognizer.java
new file mode 100644 (file)
index 0000000..d436181
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * 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.issue.tracking;
+
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Multimap;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+class BlockRecognizer<RAW extends Trackable, BASE extends Trackable> {
+
+  /**
+   * If base source code is available, then detect code moves through block hashes.
+   * Only the issues associated to a line can be matched here.
+   */
+  void match(Input<RAW> rawInput, Input<BASE> baseInput, Tracking<RAW, BASE> tracking) {
+    BlockHashSequence baseHashSequence = baseInput.getBlockHashSequence();
+    BlockHashSequence rawHashSequence = rawInput.getBlockHashSequence();
+
+    Multimap<Integer, RAW> rawsByLine = groupByLine(tracking.getUnmatchedRaws());
+    Multimap<Integer, BASE> basesByLine = groupByLine(tracking.getUnmatchedBases());
+    Map<Integer, HashOccurrence> map = new HashMap<>();
+
+    for (Integer line : basesByLine.keySet()) {
+      int hash = baseHashSequence.getBlockHashForLine(line);
+      HashOccurrence hashOccurrence = map.get(hash);
+      if (hashOccurrence == null) {
+        // first occurrence in base
+        hashOccurrence = new HashOccurrence();
+        hashOccurrence.baseLine = line;
+        hashOccurrence.baseCount = 1;
+        map.put(hash, hashOccurrence);
+      } else {
+        hashOccurrence.baseCount++;
+      }
+    }
+
+    for (Integer line : rawsByLine.keySet()) {
+      int hash = rawHashSequence.getBlockHashForLine(line);
+      HashOccurrence hashOccurrence = map.get(hash);
+      if (hashOccurrence != null) {
+        hashOccurrence.rawLine = line;
+        hashOccurrence.rawCount++;
+      }
+    }
+
+    for (HashOccurrence hashOccurrence : map.values()) {
+      if (hashOccurrence.baseCount == 1 && hashOccurrence.rawCount == 1) {
+        // Guaranteed that baseLine has been moved to rawLine, so we can map all issues on baseLine to all issues on rawLine
+        map(rawsByLine.get(hashOccurrence.rawLine), basesByLine.get(hashOccurrence.baseLine), tracking);
+        basesByLine.removeAll(hashOccurrence.baseLine);
+        rawsByLine.removeAll(hashOccurrence.rawLine);
+      }
+    }
+
+    // Check if remaining number of lines exceeds threshold
+    if (basesByLine.keySet().size() * rawsByLine.keySet().size() < 250000) {
+      List<LinePair> possibleLinePairs = Lists.newArrayList();
+      for (Integer baseLine : basesByLine.keySet()) {
+        for (Integer rawLine : rawsByLine.keySet()) {
+          int weight = lengthOfMaximalBlock(baseInput.getLineHashSequence(), baseLine, rawInput.getLineHashSequence(), rawLine);
+          possibleLinePairs.add(new LinePair(baseLine, rawLine, weight));
+        }
+      }
+      Collections.sort(possibleLinePairs, LinePairComparator.INSTANCE);
+      for (LinePair linePair : possibleLinePairs) {
+        // High probability that baseLine has been moved to rawLine, so we can map all Issues on baseLine to all Issues on rawLine
+        map(rawsByLine.get(linePair.rawLine), basesByLine.get(linePair.baseLine), tracking);
+      }
+    }
+  }
+
+  /**
+   * @param startLineA number of line from first version of text (numbering starts from 1)
+   * @param startLineB number of line from second version of text (numbering starts from 1)
+   */
+  static int lengthOfMaximalBlock(LineHashSequence hashesA, int startLineA, LineHashSequence hashesB, int startLineB) {
+    if (!hashesA.getHashForLine(startLineA).equals(hashesB.getHashForLine(startLineB))) {
+      return 0;
+    }
+    int length = 0;
+    int ai = startLineA;
+    int bi = startLineB;
+    while (ai <= hashesA.length() && bi <= hashesB.length() && hashesA.getHashForLine(ai).equals(hashesB.getHashForLine(bi))) {
+      ai++;
+      bi++;
+      length++;
+    }
+    ai = startLineA;
+    bi = startLineB;
+    while (ai > 0 && bi > 0 && hashesA.getHashForLine(ai).equals(hashesB.getHashForLine(bi))) {
+      ai--;
+      bi--;
+      length++;
+    }
+    // Note that position (startA, startB) was counted twice
+    return length - 1;
+  }
+
+  private void map(Collection<RAW> raws, Collection<BASE> bases, Tracking<RAW, BASE> result) {
+    for (RAW raw : raws) {
+      for (BASE base : bases) {
+        if (result.containsUnmatchedBase(base) && base.getRuleKey().equals(raw.getRuleKey())) {
+          result.associateRawToBase(raw, base);
+          result.markRawAsAssociated(raw);
+          break;
+        }
+      }
+    }
+  }
+
+  private static <T extends Trackable> Multimap<Integer, T> groupByLine(Collection<T> trackables) {
+    Multimap<Integer, T> result = LinkedHashMultimap.create();
+    for (T trackable : trackables) {
+      Integer line = trackable.getLine();
+      if (line != null) {
+        result.put(line, trackable);
+      }
+    }
+    return result;
+  }
+
+  private static class LinePair {
+    int baseLine;
+    int rawLine;
+    int weight;
+
+    public LinePair(int baseLine, int rawLine, int weight) {
+      this.baseLine = baseLine;
+      this.rawLine = rawLine;
+      this.weight = weight;
+    }
+  }
+
+  private static class HashOccurrence {
+    int baseLine;
+    int rawLine;
+    int baseCount;
+    int rawCount;
+  }
+
+  private enum LinePairComparator implements Comparator<LinePair> {
+    INSTANCE;
+
+    @Override
+    public int compare(LinePair o1, LinePair o2) {
+      int weightDiff = o2.weight - o1.weight;
+      if (weightDiff != 0) {
+        return weightDiff;
+      } else {
+        return Math.abs(o1.baseLine - o1.rawLine) - Math.abs(o2.baseLine - o2.rawLine);
+      }
+    }
+  }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/issue/tracking/Input.java b/sonar-core/src/main/java/org/sonar/core/issue/tracking/Input.java
new file mode 100644 (file)
index 0000000..b0681c6
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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.issue.tracking;
+
+import java.util.Collection;
+
+public interface Input<ISSUE extends Trackable> {
+
+  LineHashSequence getLineHashSequence();
+  BlockHashSequence getBlockHashSequence();
+  Collection<ISSUE> getIssues();
+
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/issue/tracking/LazyInput.java b/sonar-core/src/main/java/org/sonar/core/issue/tracking/LazyInput.java
new file mode 100644 (file)
index 0000000..0406c63
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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.issue.tracking;
+
+import java.util.Collection;
+import java.util.List;
+
+public abstract class LazyInput<ISSUE extends Trackable> implements Input<ISSUE> {
+
+  private List<ISSUE> issues;
+  private LineHashSequence lineHashSeq;
+  private BlockHashSequence blockHashSeq;
+
+  @Override
+  public LineHashSequence getLineHashSequence() {
+    if (lineHashSeq == null) {
+      lineHashSeq = LineHashSequence.createForLines(loadSourceLines());
+    }
+    return lineHashSeq;
+  }
+
+  @Override
+  public BlockHashSequence getBlockHashSequence() {
+    if (blockHashSeq == null) {
+      blockHashSeq = BlockHashSequence.create(getLineHashSequence());
+    }
+    return blockHashSeq;
+  }
+
+  @Override
+  public Collection<ISSUE> getIssues() {
+    if (issues == null) {
+      issues = loadIssues();
+    }
+    return issues;
+  }
+
+  protected abstract Iterable<String> loadSourceLines();
+
+  protected abstract List<ISSUE> loadIssues();
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/issue/tracking/LineHashSequence.java b/sonar-core/src/main/java/org/sonar/core/issue/tracking/LineHashSequence.java
new file mode 100644 (file)
index 0000000..b6be6b7
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * 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.issue.tracking;
+
+import com.google.common.base.Strings;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.Nullable;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * Sequence of hash of lines for a given file
+ */
+public class LineHashSequence {
+
+  private static final int[] EMPTY_INTS = new int[0];
+
+  /**
+   * Hashes of lines. Line 1 is at index 0. No null elements.
+   */
+  private final List<String> hashes;
+  private final Map<String, int[]> linesByHash;
+
+  public LineHashSequence(List<String> hashes) {
+    this.hashes = hashes;
+    this.linesByHash = new HashMap<>(hashes.size());
+    for (int line = 1; line <= hashes.size(); line++) {
+      String hash = hashes.get(line - 1);
+      int[] lines = linesByHash.get(hash);
+      linesByHash.put(hash, appendLineTo(line, lines));
+    }
+  }
+
+  /**
+   * Number of lines
+   */
+  public int length() {
+    return hashes.size();
+  }
+
+  /**
+   * Checks if the line, starting with 1, is defined.
+   */
+  public boolean hasLine(int line) {
+    return 0 < line && line <= hashes.size();
+  }
+
+  /**
+   * The lines, starting with 1, that matches the given hash.
+   */
+  public int[] getLinesForHash(String hash) {
+    int[] lines = linesByHash.get(hash);
+    return lines == null ? EMPTY_INTS : lines;
+  }
+
+  /**
+   * Hash of the given line, which starts with 1. Return empty string
+   * is the line does not exist.
+   */
+  public String getHashForLine(int line) {
+    if (line > 0 && line <= hashes.size()) {
+      return Strings.nullToEmpty(hashes.get(line - 1));
+    }
+    return "";
+  }
+
+  List<String> getHashes() {
+    return hashes;
+  }
+
+  private static int[] appendLineTo(int line, @Nullable int[] to) {
+    int[] result;
+    if (to == null) {
+      result = new int[] {line};
+    } else {
+      result = new int[to.length + 1];
+      System.arraycopy(to, 0, result, 0, to.length);
+      result[result.length - 1] = line;
+    }
+    return result;
+  }
+
+  public static LineHashSequence createForLines(Iterable<String> lines) {
+    List<String> hashes = new ArrayList<>();
+    for (String line : lines) {
+      hashes.add(hash(line));
+    }
+    return new LineHashSequence(hashes);
+  }
+
+  // FIXME duplicates ComputeFileSourceData
+  private static String hash(String line) {
+    String reducedLine = StringUtils.replaceChars(line, "\t ", "");
+    if (reducedLine.isEmpty()) {
+      return "";
+    }
+    return DigestUtils.md5Hex(reducedLine);
+  }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/issue/tracking/Trackable.java b/sonar-core/src/main/java/org/sonar/core/issue/tracking/Trackable.java
new file mode 100644 (file)
index 0000000..c6e5512
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * 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.issue.tracking;
+
+import javax.annotation.CheckForNull;
+import org.sonar.api.rule.RuleKey;
+
+public interface Trackable {
+
+  /**
+   * The line index, starting with 1. Null means that
+   * issue does not relate to a line (file issue for example).
+   */
+  @CheckForNull
+  Integer getLine();
+
+  String getMessage();
+
+  @CheckForNull
+  String getLineHash();
+
+  RuleKey getRuleKey();
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/issue/tracking/Tracker.java b/sonar-core/src/main/java/org/sonar/core/issue/tracking/Tracker.java
new file mode 100644 (file)
index 0000000..8691757
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * 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.issue.tracking;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Strings;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Objects;
+import javax.annotation.Nonnull;
+import org.sonar.api.rule.RuleKey;
+
+import static com.google.common.collect.FluentIterable.from;
+
+public class Tracker<RAW extends Trackable, BASE extends Trackable> {
+
+  public Tracking<RAW, BASE> track(Input<RAW> rawInput, Input<BASE> baseInput) {
+    Tracking<RAW, BASE> tracking = new Tracking<>(rawInput, baseInput);
+
+    // 1. match issues with same rule, same line and same line hash, but not necessarily with same message
+    match(tracking, LineAndLineHashKeyFactory.INSTANCE);
+
+    // 2. detect code moves by comparing blocks of codes
+    detectCodeMoves(rawInput, baseInput, tracking);
+
+    // 3. match issues with same rule, same message and same line hash
+    match(tracking, LineHashAndMessagekeyFactory.INSTANCE);
+
+    // 4. match issues with same rule, same line and same message
+    match(tracking, LineAndMessageKeyFactory.INSTANCE);
+
+    // 5. match issues with same rule and same line hash but different line and different message.
+    // See SONAR-2812
+    match(tracking, LineHashKeyFactory.INSTANCE);
+
+    // TODO what about issues on line 0 ?
+    relocateManualIssues(rawInput, tracking);
+
+    return tracking;
+  }
+
+  private void detectCodeMoves(Input<RAW> rawInput, Input<BASE> baseInput, Tracking<RAW, BASE> tracking) {
+    if (!tracking.isComplete()) {
+      new BlockRecognizer<RAW, BASE>().match(rawInput, baseInput, tracking);
+    }
+  }
+
+  private void match(Tracking<RAW, BASE> tracking, SearchKeyFactory factory) {
+    if (tracking.isComplete()) {
+      return;
+    }
+
+    Multimap<SearchKey, BASE> baseSearch = ArrayListMultimap.create();
+    for (BASE base : tracking.getUnmatchedBases()) {
+      baseSearch.put(factory.create(base), base);
+    }
+
+    Collection<RAW> trackedRaws = new ArrayList<>();
+    for (RAW raw : tracking.getUnmatchedRaws()) {
+      SearchKey rawKey = factory.create(raw);
+      Collection<BASE> bases = baseSearch.get(rawKey);
+      if (!bases.isEmpty()) {
+        // TODO taking the first one. Could be improved if there are more than 2 issues on the same line.
+        // Message could be checked to take the best one.
+        BASE match = bases.iterator().next();
+        tracking.associateRawToBase(raw, match);
+        baseSearch.remove(rawKey, match);
+        trackedRaws.add(raw);
+      }
+    }
+    tracking.markRawsAsAssociated(trackedRaws);
+  }
+
+  private void relocateManualIssues(Input<RAW> rawInput, Tracking<RAW, BASE> tracking) {
+    Iterable<BASE> manualIssues = from(tracking.getUnmatchedBases()).filter(IsManual.INSTANCE);
+    for (BASE base : manualIssues) {
+      if (base.getLine() == null) {
+        // no need to relocate. Location is unchanged.
+        tracking.associateManualIssueToLine(base, 0);
+      } else {
+        String lineHash = base.getLineHash();
+        if (!Strings.isNullOrEmpty(lineHash)) {
+          int[] rawLines = rawInput.getLineHashSequence().getLinesForHash(lineHash);
+          if (rawLines.length == 1) {
+            tracking.associateManualIssueToLine(base, rawLines[0]);
+          } else if (rawLines.length == 0 && base.getLine() <= rawInput.getLineHashSequence().length()) {
+            // still valid (???). We didn't manage to correctly detect code move, so the
+            // issue is kept at the same location, even if code changes
+            tracking.associateManualIssueToLine(base, base.getLine());
+          }
+        }
+      }
+    }
+  }
+
+  private enum IsManual implements Predicate<Trackable> {
+    INSTANCE;
+    @Override
+    public boolean apply(Trackable input) {
+      return input.getRuleKey().isManual();
+    }
+  }
+
+  private interface SearchKey {
+  }
+
+  private interface SearchKeyFactory {
+    SearchKey create(Trackable trackable);
+  }
+
+  private static class LineAndLineHashKey implements SearchKey {
+    private final RuleKey ruleKey;
+    private final String lineHash;
+    private final Integer line;
+
+    LineAndLineHashKey(Trackable trackable) {
+      this.ruleKey = trackable.getRuleKey();
+      this.line = trackable.getLine();
+      this.lineHash = trackable.getLineHash();
+    }
+
+    @Override
+    public boolean equals(@Nonnull Object o) {
+      if (this == o) {
+        return true;
+      }
+      LineAndLineHashKey that = (LineAndLineHashKey) o;
+      // start with most discriminant field
+      if (!Objects.equals(line, that.line)) {
+        return false;
+      }
+      if (!lineHash.equals(that.lineHash)) {
+        return false;
+      }
+      return ruleKey.equals(that.ruleKey);
+    }
+
+    @Override
+    public int hashCode() {
+      int result = ruleKey.hashCode();
+      result = 31 * result + lineHash.hashCode();
+      result = 31 * result + (line != null ? line.hashCode() : 0);
+      return result;
+    }
+  }
+
+  private enum LineAndLineHashKeyFactory implements SearchKeyFactory {
+    INSTANCE;
+    @Override
+    public SearchKey create(Trackable t) {
+      return new LineAndLineHashKey(t);
+    }
+  }
+
+  private static class LineHashAndMessageKey implements SearchKey {
+    private final RuleKey ruleKey;
+    private final String message, lineHash;
+
+    LineHashAndMessageKey(Trackable trackable) {
+      this.ruleKey = trackable.getRuleKey();
+      this.message = trackable.getMessage();
+      this.lineHash = trackable.getLineHash();
+    }
+
+    @Override
+    public boolean equals(@Nonnull Object o) {
+      if (this == o) {
+        return true;
+      }
+      LineHashAndMessageKey that = (LineHashAndMessageKey) o;
+      // start with most discriminant field
+      if (!lineHash.equals(that.lineHash)) {
+        return false;
+      }
+      if (!message.equals(that.message)) {
+        return false;
+      }
+      return ruleKey.equals(that.ruleKey);
+    }
+
+    @Override
+    public int hashCode() {
+      int result = ruleKey.hashCode();
+      result = 31 * result + message.hashCode();
+      result = 31 * result + lineHash.hashCode();
+      return result;
+    }
+  }
+
+  private enum LineHashAndMessagekeyFactory implements SearchKeyFactory {
+    INSTANCE;
+    @Override
+    public SearchKey create(Trackable t) {
+      return new LineHashAndMessageKey(t);
+    }
+  }
+
+  private static class LineAndMessageKey implements SearchKey {
+    private final RuleKey ruleKey;
+    private final String message;
+    private final Integer line;
+
+    LineAndMessageKey(Trackable trackable) {
+      this.ruleKey = trackable.getRuleKey();
+      this.message = trackable.getMessage();
+      this.line = trackable.getLine();
+    }
+
+    @Override
+    public boolean equals(@Nonnull Object o) {
+      if (this == o) {
+        return true;
+      }
+      LineAndMessageKey that = (LineAndMessageKey) o;
+      // start with most discriminant field
+      if (!Objects.equals(line, that.line)) {
+        return false;
+      }
+      if (!message.equals(that.message)) {
+        return false;
+      }
+      return ruleKey.equals(that.ruleKey);
+    }
+
+    @Override
+    public int hashCode() {
+      int result = ruleKey.hashCode();
+      result = 31 * result + message.hashCode();
+      result = 31 * result + (line != null ? line.hashCode() : 0);
+      return result;
+    }
+  }
+
+  private enum LineAndMessageKeyFactory implements SearchKeyFactory {
+    INSTANCE;
+    @Override
+    public SearchKey create(Trackable t) {
+      return new LineAndMessageKey(t);
+    }
+  }
+
+  private static class LineHashKey implements SearchKey {
+    private final RuleKey ruleKey;
+    private final String lineHash;
+
+    LineHashKey(Trackable trackable) {
+      this.ruleKey = trackable.getRuleKey();
+      this.lineHash = trackable.getLineHash();
+    }
+
+    @Override
+    public boolean equals(@Nonnull Object o) {
+      if (this == o) {
+        return true;
+      }
+      LineAndLineHashKey that = (LineAndLineHashKey) o;
+      // start with most discriminant field
+      if (!lineHash.equals(that.lineHash)) {
+        return false;
+      }
+      return ruleKey.equals(that.ruleKey);
+    }
+
+    @Override
+    public int hashCode() {
+      int result = ruleKey.hashCode();
+      result = 31 * result + lineHash.hashCode();
+      return result;
+    }
+  }
+
+  private enum LineHashKeyFactory implements SearchKeyFactory {
+    INSTANCE;
+    @Override
+    public SearchKey create(Trackable t) {
+      return new LineHashKey(t);
+    }
+  }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/issue/tracking/Tracking.java b/sonar-core/src/main/java/org/sonar/core/issue/tracking/Tracking.java
new file mode 100644 (file)
index 0000000..27f34ac
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * 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.issue.tracking;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.IdentityHashMap;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.CheckForNull;
+
+public class Tracking<RAW extends Trackable, BASE extends Trackable> {
+
+  /**
+   * Tracked issues -> a raw issue is associated to a base issue
+   */
+  private final IdentityHashMap<RAW, BASE> rawToBase = new IdentityHashMap<>();
+
+  /**
+   * The raw issues that are not associated to a base issue.
+   */
+  private final Set<RAW> unmatchedRaws = Collections.newSetFromMap(new IdentityHashMap<RAW, Boolean>());
+
+  /**
+   * IdentityHashSet of the base issues that are not associated to a raw issue.
+   */
+  private final Set<BASE> unmatchedBases = Collections.newSetFromMap(new IdentityHashMap<BASE, Boolean>());
+
+  /**
+   * The manual issues that are still valid (related source code still exists). They
+   * are grouped by line. Lines start with 1. The key 0 references the manual
+   * issues that do not relate to a line.
+   */
+  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.unmatchedBases.addAll(baseInput.getIssues());
+  }
+
+  public Set<RAW> getUnmatchedRaws() {
+    return unmatchedRaws;
+  }
+
+  public Map<RAW, BASE> getMatchedRaws() {
+    return rawToBase;
+  }
+
+  @CheckForNull
+  public BASE baseFor(RAW raw) {
+    return rawToBase.get(raw);
+  }
+
+  /**
+   * The base issues that are not matched by a raw issue and that need to be closed. Manual
+   */
+  public Set<BASE> getUnmatchedBases() {
+    return unmatchedBases;
+  }
+
+  boolean containsUnmatchedBase(BASE base) {
+    return unmatchedBases.contains(base);
+  }
+
+  void associateRawToBase(RAW raw, BASE base) {
+    rawToBase.put(raw, base);
+    unmatchedBases.remove(base);
+  }
+
+  void markRawAsAssociated(RAW raw) {
+    unmatchedRaws.remove(raw);
+  }
+
+  void markRawsAsAssociated(Collection<RAW> c) {
+    unmatchedRaws.removeAll(c);
+  }
+
+  boolean isComplete() {
+    return unmatchedRaws.isEmpty() || unmatchedBases.isEmpty();
+  }
+
+  public Multimap<Integer, BASE> getOpenManualIssuesByLine() {
+    return openManualIssues;
+  }
+
+  void associateManualIssueToLine(BASE manualIssue, int line) {
+    openManualIssues.put(line, manualIssue);
+    unmatchedBases.remove(manualIssue);
+  }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/issue/tracking/package-info.java b/sonar-core/src/main/java/org/sonar/core/issue/tracking/package-info.java
new file mode 100644 (file)
index 0000000..1438e8a
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.core.issue.tracking;
+
+import javax.annotation.ParametersAreNonnullByDefault;
index 51d12b7e36ddf2b1868b4e3806a98cbed2188eb9..dfeac4034585cfe73c70fc54c97bc4405bd33644 100644 (file)
 package org.sonar.core.issue.workflow;
 
 import org.sonar.api.batch.BatchSide;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.IssueChangeContext;
 import org.sonar.api.server.ServerSide;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.IssueChangeContext;
 import org.sonar.api.user.User;
 import org.sonar.core.issue.IssueUpdater;
 
diff --git a/sonar-core/src/main/java/org/sonar/core/issue/workflow/IsBeingClosed.java b/sonar-core/src/main/java/org/sonar/core/issue/workflow/IsBeingClosed.java
new file mode 100644 (file)
index 0000000..a9f4f21
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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.issue.workflow;
+
+import org.sonar.api.issue.Issue;
+import org.sonar.api.issue.condition.Condition;
+import org.sonar.core.issue.DefaultIssue;
+
+enum IsBeingClosed implements Condition {
+  INSTANCE;
+
+  @Override
+  public boolean matches(Issue issue) {
+    return ((DefaultIssue) issue).isBeingClosed();
+  }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/issue/workflow/IsEndOfLife.java b/sonar-core/src/main/java/org/sonar/core/issue/workflow/IsEndOfLife.java
deleted file mode 100644 (file)
index e8d877d..0000000
+++ /dev/null
@@ -1,38 +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.issue.workflow;
-
-import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.condition.Condition;
-import org.sonar.api.issue.internal.DefaultIssue;
-
-class IsEndOfLife implements Condition {
-
-  private final boolean endOfLife;
-
-  IsEndOfLife(boolean endOfLife) {
-    this.endOfLife = endOfLife;
-  }
-
-  @Override
-  public boolean matches(Issue issue) {
-    return ((DefaultIssue) issue).isEndOfLife() == endOfLife;
-  }
-}
index cd448ee8ce671566f9e4b224c0a06fdaffe43840..6bdda1fc1176b8eb3fd28ba1a0b157942ce8a333 100644 (file)
@@ -22,16 +22,11 @@ package org.sonar.core.issue.workflow;
 import org.sonar.api.issue.Issue;
 import org.sonar.api.issue.condition.Condition;
 
-class IsManual implements Condition {
-
-  private final boolean manual;
-
-  IsManual(boolean manual) {
-    this.manual = manual;
-  }
+enum IsManual implements Condition {
+  INSTANCE;
 
   @Override
   public boolean matches(Issue issue) {
-    return manual==(issue.reporter()!=null);
+    return issue.ruleKey().isManual();
   }
 }
index 5131a7def4d2932cdf01bde9015d4039b9ce9b95..5b54986c84fd07b17b486cd7f0453f21e159179f 100644 (file)
  */
 package org.sonar.core.issue.workflow;
 
+import java.util.List;
 import org.picocontainer.Startable;
 import org.sonar.api.batch.BatchSide;
-import org.sonar.api.server.ServerSide;
 import org.sonar.api.issue.DefaultTransitions;
 import org.sonar.api.issue.Issue;
 import org.sonar.api.issue.condition.HasResolution;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.IssueChangeContext;
+import org.sonar.api.issue.condition.NotCondition;
+import org.sonar.api.server.ServerSide;
 import org.sonar.api.web.UserRole;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.IssueChangeContext;
 import org.sonar.core.issue.IssueUpdater;
 
-import java.util.List;
-
 @BatchSide
 @ServerSide
 public class IssueWorkflow implements Startable {
@@ -86,7 +86,7 @@ public class IssueWorkflow implements Startable {
         .functions(new SetResolution(null))
         .build())
       .transition(Transition.builder(DefaultTransitions.REOPEN)
-        .conditions(new IsManual(true))
+        .conditions(IsManual.INSTANCE)
         .from(Issue.STATUS_CLOSED).to(Issue.STATUS_REOPENED)
         .functions(new SetResolution(null), new SetCloseDate(false))
         .build())
@@ -94,34 +94,34 @@ public class IssueWorkflow implements Startable {
       // resolve as false-positive
       .transition(Transition.builder(DefaultTransitions.FALSE_POSITIVE)
         .from(Issue.STATUS_OPEN).to(Issue.STATUS_RESOLVED)
-        .functions(new SetResolution(Issue.RESOLUTION_FALSE_POSITIVE), SetAssignee.UNASSIGN)
+        .functions(new SetResolution(Issue.RESOLUTION_FALSE_POSITIVE), UnsetAssignee.INSTANCE)
         .requiredProjectPermission(UserRole.ISSUE_ADMIN)
         .build())
       .transition(Transition.builder(DefaultTransitions.FALSE_POSITIVE)
         .from(Issue.STATUS_REOPENED).to(Issue.STATUS_RESOLVED)
-        .functions(new SetResolution(Issue.RESOLUTION_FALSE_POSITIVE), SetAssignee.UNASSIGN)
+        .functions(new SetResolution(Issue.RESOLUTION_FALSE_POSITIVE), UnsetAssignee.INSTANCE)
         .requiredProjectPermission(UserRole.ISSUE_ADMIN)
         .build())
       .transition(Transition.builder(DefaultTransitions.FALSE_POSITIVE)
         .from(Issue.STATUS_CONFIRMED).to(Issue.STATUS_RESOLVED)
-        .functions(new SetResolution(Issue.RESOLUTION_FALSE_POSITIVE), SetAssignee.UNASSIGN)
+        .functions(new SetResolution(Issue.RESOLUTION_FALSE_POSITIVE), UnsetAssignee.INSTANCE)
         .requiredProjectPermission(UserRole.ISSUE_ADMIN)
         .build())
 
       // resolve as won't fix
       .transition(Transition.builder(DefaultTransitions.WONT_FIX)
         .from(Issue.STATUS_OPEN).to(Issue.STATUS_RESOLVED)
-        .functions(new SetResolution(Issue.RESOLUTION_WONT_FIX), SetAssignee.UNASSIGN)
+        .functions(new SetResolution(Issue.RESOLUTION_WONT_FIX), UnsetAssignee.INSTANCE)
         .requiredProjectPermission(UserRole.ISSUE_ADMIN)
         .build())
       .transition(Transition.builder(DefaultTransitions.WONT_FIX)
         .from(Issue.STATUS_REOPENED).to(Issue.STATUS_RESOLVED)
-        .functions(new SetResolution(Issue.RESOLUTION_WONT_FIX), SetAssignee.UNASSIGN)
+        .functions(new SetResolution(Issue.RESOLUTION_WONT_FIX), UnsetAssignee.INSTANCE)
         .requiredProjectPermission(UserRole.ISSUE_ADMIN)
         .build())
       .transition(Transition.builder(DefaultTransitions.WONT_FIX)
         .from(Issue.STATUS_CONFIRMED).to(Issue.STATUS_RESOLVED)
-        .functions(new SetResolution(Issue.RESOLUTION_WONT_FIX), SetAssignee.UNASSIGN)
+        .functions(new SetResolution(Issue.RESOLUTION_WONT_FIX), UnsetAssignee.INSTANCE)
         .requiredProjectPermission(UserRole.ISSUE_ADMIN)
         .build()
       );
@@ -130,33 +130,34 @@ public class IssueWorkflow implements Startable {
 
   private void buildAutomaticTransitions(StateMachine.Builder builder) {
     // Close the "end of life" issues (disabled/deleted rule, deleted component)
-    builder.transition(Transition.builder("automaticclose")
-      .from(Issue.STATUS_OPEN).to(Issue.STATUS_CLOSED)
-      .conditions(new IsEndOfLife(true))
-      .functions(new SetEndOfLife(), new SetCloseDate(true))
-      .automatic()
-      .build())
+    builder
+      .transition(Transition.builder("automaticclose")
+        .from(Issue.STATUS_OPEN).to(Issue.STATUS_CLOSED)
+        .conditions(IsBeingClosed.INSTANCE)
+        .functions(SetClosed.INSTANCE, new SetCloseDate(true))
+        .automatic()
+        .build())
       .transition(Transition.builder("automaticclose")
         .from(Issue.STATUS_REOPENED).to(Issue.STATUS_CLOSED)
-        .conditions(new IsEndOfLife(true))
-        .functions(new SetEndOfLife(), new SetCloseDate(true))
+        .conditions(IsBeingClosed.INSTANCE)
+        .functions(SetClosed.INSTANCE, new SetCloseDate(true))
         .automatic()
         .build())
       .transition(Transition.builder("automaticclose")
         .from(Issue.STATUS_CONFIRMED).to(Issue.STATUS_CLOSED)
-        .conditions(new IsEndOfLife(true))
-        .functions(new SetEndOfLife(), new SetCloseDate(true))
+        .conditions(IsBeingClosed.INSTANCE)
+        .functions(SetClosed.INSTANCE, new SetCloseDate(true))
         .automatic()
         .build())
       .transition(Transition.builder("automaticclose")
         .from(Issue.STATUS_RESOLVED).to(Issue.STATUS_CLOSED)
-        .conditions(new IsEndOfLife(true))
-        .functions(new SetEndOfLife(), new SetCloseDate(true))
+        .conditions(IsBeingClosed.INSTANCE)
+        .functions(SetClosed.INSTANCE, new SetCloseDate(true))
         .automatic()
         .build())
       .transition(Transition.builder("automaticclosemanual")
         .from(Issue.STATUS_RESOLVED).to(Issue.STATUS_CLOSED)
-        .conditions(new IsEndOfLife(false), new IsManual(true))
+        .conditions(new NotCondition(IsBeingClosed.INSTANCE), IsManual.INSTANCE)
         .functions(new SetCloseDate(true))
         .automatic()
         .build())
@@ -165,7 +166,7 @@ public class IssueWorkflow implements Startable {
       // Manual issues are kept resolved.
       .transition(Transition.builder("automaticreopen")
         .from(Issue.STATUS_RESOLVED).to(Issue.STATUS_REOPENED)
-        .conditions(new IsEndOfLife(false), new HasResolution(Issue.RESOLUTION_FIXED), new IsManual(false))
+        .conditions(new NotCondition(IsBeingClosed.INSTANCE), new HasResolution(Issue.RESOLUTION_FIXED), new NotCondition(IsManual.INSTANCE))
         .functions(new SetResolution(null), new SetCloseDate(false))
         .automatic()
         .build()
diff --git a/sonar-core/src/main/java/org/sonar/core/issue/workflow/SetAssignee.java b/sonar-core/src/main/java/org/sonar/core/issue/workflow/SetAssignee.java
deleted file mode 100644 (file)
index 7a5c778..0000000
+++ /dev/null
@@ -1,39 +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.issue.workflow;
-
-import org.sonar.api.user.User;
-
-import javax.annotation.Nullable;
-
-public class SetAssignee implements Function {
-  public static final SetAssignee UNASSIGN = new SetAssignee(null);
-
-  private final User assignee;
-
-  public SetAssignee(@Nullable User assignee) {
-    this.assignee = assignee;
-  }
-
-  @Override
-  public void execute(Context context) {
-    context.setAssignee(assignee);
-  }
-}
index 3d83ac27c36895be776c4c8d9f5d9de396fdeff7..36da29e0c68d236fd37868d2be7f49aa62a7508b 100644 (file)
@@ -19,7 +19,7 @@
  */
 package org.sonar.core.issue.workflow;
 
-public class SetCloseDate implements Function {
+class SetCloseDate implements Function {
   private final boolean set;
 
   public SetCloseDate(boolean set) {
diff --git a/sonar-core/src/main/java/org/sonar/core/issue/workflow/SetClosed.java b/sonar-core/src/main/java/org/sonar/core/issue/workflow/SetClosed.java
new file mode 100644 (file)
index 0000000..cee06ac
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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.issue.workflow;
+
+import org.sonar.api.issue.Issue;
+import org.sonar.core.issue.DefaultIssue;
+
+public enum SetClosed implements Function {
+  INSTANCE;
+
+  @Override
+  public void execute(Context context) {
+    DefaultIssue issue = (DefaultIssue) context.issue();
+    if (!issue.isBeingClosed()) {
+      throw new IllegalStateException("Issue is still alive: " + issue);
+    }
+    if (issue.isOnDisabledRule()) {
+      context.setResolution(Issue.RESOLUTION_REMOVED);
+    } else {
+      context.setResolution(Issue.RESOLUTION_FIXED);
+    }
+
+    // closed issues are not "tracked" -> the line number does not evolve anymore
+    // when code changes. That's misleading for end-users, so line number
+    // is unset.
+    context.setLine(null);
+  }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/issue/workflow/SetEndOfLife.java b/sonar-core/src/main/java/org/sonar/core/issue/workflow/SetEndOfLife.java
deleted file mode 100644 (file)
index ae45caa..0000000
+++ /dev/null
@@ -1,43 +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.issue.workflow;
-
-import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
-
-public class SetEndOfLife implements Function {
-  @Override
-  public void execute(Context context) {
-    DefaultIssue issue = (DefaultIssue) context.issue();
-    if (!issue.isEndOfLife()) {
-      throw new IllegalStateException("Issue is still alive: " + issue);
-    }
-    if (issue.isOnDisabledRule()) {
-      context.setResolution(Issue.RESOLUTION_REMOVED);
-    } else {
-      context.setResolution(Issue.RESOLUTION_FIXED);
-    }
-
-    // closed issues are not "tracked" -> the line number does not evolve anymore
-    // when code changes. That's misleading for end-users, so line number
-    // is unset.
-    context.setLine(null);
-  }
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/issue/workflow/UnsetAssignee.java b/sonar-core/src/main/java/org/sonar/core/issue/workflow/UnsetAssignee.java
new file mode 100644 (file)
index 0000000..b7f9da1
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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.issue.workflow;
+
+enum UnsetAssignee implements Function {
+  INSTANCE;
+
+  @Override
+  public void execute(Context context) {
+    context.setAssignee(null);
+  }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/issue/workflow/UnsetLine.java b/sonar-core/src/main/java/org/sonar/core/issue/workflow/UnsetLine.java
new file mode 100644 (file)
index 0000000..8073e17
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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.issue.workflow;
+
+enum UnsetLine implements Function {
+  INSTANCE;
+  @Override
+  public void execute(Context context) {
+    context.setLine(null);
+  }
+
+}
index c1bfead83234a1af8c0d8c186f01a031762a073b..50eb94db4d34ecf7da4f7c3fea528e26a43c5608 100644 (file)
     where i.kee=#{kee}
   </select>
 
-  <select id="selectNonClosedIssuesByModule" parameterType="Long" resultType="Issue">
+  <select id="selectOpenByComponentUuid" 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
+    from issues i
+    inner join rules r on r.id=i.rule_id
+    where
+    i.component_uuid=#{componentUuid} and
+    i.status &lt;&gt; 'CLOSED'
+  </select>
+
+  <select id="selectNonClosedIssuesByModule" parameterType="long" resultType="Issue">
     select
     i.id,
     i.kee as kee,
     where i.status &lt;&gt; 'CLOSED'
   </select>
 
+  <select id="selectComponentUuidsOfOpenIssuesForProjectUuid" parameterType="string" resultType="string">
+    select distinct(i.component_uuid)
+    from issues i
+    where i.project_uuid=#{projectUuid} and i.status &lt;&gt; 'CLOSED'
+  </select>
+
   <select id="selectByKeys" parameterType="map" resultType="Issue">
     select
     <include refid="issueColumns"/>
index a84e111183615267265dee715e88e9ba3767f22b..136c5a262b52d34f77a56dbd08b021075898faa4 100644 (file)
@@ -21,7 +21,6 @@ package org.sonar.core.issue;
 
 import org.junit.Test;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rule.Severity;
 
index d6e304a309d10c40da9e71ec3e8219fdeeb68558..ed424565037ad0f4fb76619f35b355acaab05b83 100644 (file)
@@ -20,7 +20,6 @@
 package org.sonar.core.issue;
 
 import org.junit.Test;
-import org.sonar.api.issue.internal.IssueChangeContext;
 
 import java.util.Date;
 
index 8a4181f47b5391f04a8c49ab9d40250a6d2ff339..c3d927cbe3c74c0ec454c873b4f76d5513c0f27d 100644 (file)
@@ -22,9 +22,6 @@ package org.sonar.core.issue;
 import org.junit.Before;
 import org.junit.Test;
 import org.sonar.api.issue.ActionPlan;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.FieldDiffs;
-import org.sonar.api.issue.internal.IssueChangeContext;
 import org.sonar.api.user.User;
 import org.sonar.api.utils.Duration;
 import org.sonar.core.user.DefaultUser;
index d9de4aa528f348babc73d08453f3a85961309784..411048b421e5cb4175803ec972c5c27e2e6c57ef 100644 (file)
@@ -23,8 +23,8 @@ import org.apache.ibatis.executor.result.DefaultResultHandler;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
-import org.sonar.api.issue.internal.DefaultIssueComment;
-import org.sonar.api.issue.internal.FieldDiffs;
+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;
index 3b383c1c974bb19faa81b14b96f91d2d2a0149d6..2d3ece83f186fc22d074bb59dc385fce3aa4acd5 100644 (file)
@@ -20,8 +20,8 @@
 package org.sonar.core.issue.db;
 
 import org.junit.Test;
-import org.sonar.api.issue.internal.DefaultIssueComment;
-import org.sonar.api.issue.internal.FieldDiffs;
+import org.sonar.core.issue.DefaultIssueComment;
+import org.sonar.core.issue.FieldDiffs;
 import org.sonar.api.utils.System2;
 
 import static org.assertj.core.api.Assertions.assertThat;
index 7958aa266746150fc4b720c8c64a70f7189b64f8..7738ca20486693ab99bf639bcd37cb04111c84a3 100644 (file)
@@ -46,41 +46,6 @@ public class IssueDaoTest extends AbstractDaoTestCase {
     session.close();
   }
 
-  @Test
-  public void should_select_by_key() {
-    setupData("shared", "should_select_by_key");
-
-    IssueDto issue = dao.selectByKey("ABCDE");
-    assertThat(issue.getKee()).isEqualTo("ABCDE");
-    assertThat(issue.getId()).isEqualTo(100L);
-    assertThat(issue.getRuleId()).isEqualTo(500);
-    assertThat(issue.getSeverity()).isEqualTo("BLOCKER");
-    assertThat(issue.isManualSeverity()).isFalse();
-    assertThat(issue.getMessage()).isNull();
-    assertThat(issue.getLine()).isEqualTo(200);
-    assertThat(issue.getEffortToFix()).isEqualTo(4.2);
-    assertThat(issue.getStatus()).isEqualTo("OPEN");
-    assertThat(issue.getResolution()).isEqualTo("FIXED");
-    assertThat(issue.getChecksum()).isEqualTo("XXX");
-    assertThat(issue.getAuthorLogin()).isEqualTo("karadoc");
-    assertThat(issue.getReporter()).isEqualTo("arthur");
-    assertThat(issue.getAssignee()).isEqualTo("perceval");
-    assertThat(issue.getIssueAttributes()).isEqualTo("JIRA=FOO-1234");
-    assertThat(issue.getIssueCreationDate()).isNotNull();
-    assertThat(issue.getIssueUpdateDate()).isNotNull();
-    assertThat(issue.getIssueCloseDate()).isNotNull();
-    assertThat(issue.getCreatedAt()).isNotNull();
-    assertThat(issue.getUpdatedAt()).isNotNull();
-    assertThat(issue.getRuleRepo()).isEqualTo("squid");
-    assertThat(issue.getRule()).isEqualTo("AvoidCycle");
-    assertThat(issue.getComponentUuid()).isEqualTo("CDEF");
-    assertThat(issue.getComponentKey()).isEqualTo("Action.java");
-    assertThat(issue.getModuleUuid()).isEqualTo("BCDE");
-    assertThat(issue.getModuleUuidPath()).isEqualTo(".ABCD.BCDE.");
-    assertThat(issue.getProjectKey()).isEqualTo("struts"); // ABCD
-    assertThat(issue.getProjectUuid()).isEqualTo("ABCD"); // null
-  }
-
   @Test
   public void select_non_closed_issues_by_module() {
     setupData("shared", "should_select_non_closed_issues_by_module");
index edac8a2dd84dec473b4ba8784ee87e08a97d1b8a..0ee3ae234160e45adca5581f4afa4b88ef003d0c 100644 (file)
@@ -24,7 +24,7 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.api.utils.Duration;
 import org.sonar.core.rule.RuleDto;
 
index 62e100596297295ca880fc46d1dcbc40dde02606..259f751c12ec293b81f4a630f7df5b4f3a73c870 100644 (file)
@@ -22,9 +22,9 @@ package org.sonar.core.issue.db;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.DefaultIssueComment;
-import org.sonar.api.issue.internal.IssueChangeContext;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.DefaultIssueComment;
+import org.sonar.core.issue.IssueChangeContext;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rules.Rule;
 import org.sonar.api.rules.RuleFinder;
index 2dc79d30b8dd477c418765dc8d5705339eb853f4..9a4d5037901d3cd4210279e0bcd0aa2ea426c3bc 100644 (file)
@@ -22,7 +22,7 @@ package org.sonar.core.issue.db;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rule.Severity;
 import org.sonar.api.utils.DateUtils;
diff --git a/sonar-core/src/test/java/org/sonar/core/issue/tracking/BlockHashSequenceTest.java b/sonar-core/src/test/java/org/sonar/core/issue/tracking/BlockHashSequenceTest.java
new file mode 100644 (file)
index 0000000..f364615
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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.issue.tracking;
+
+import org.junit.Test;
+
+import static java.util.Arrays.asList;
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class BlockHashSequenceTest {
+
+  @Test
+  public void test() {
+    BlockHashSequence a = new BlockHashSequence(LineHashSequence.createForLines(asList("line0", "line1", "line2")), 1);
+    BlockHashSequence b = new BlockHashSequence(LineHashSequence.createForLines(asList("line0", "line1", "line2", "line3")), 1);
+
+    assertThat(a.getBlockHashForLine(1)).isEqualTo(b.getBlockHashForLine(1));
+    assertThat(a.getBlockHashForLine(2)).isEqualTo(b.getBlockHashForLine(2));
+    assertThat(a.getBlockHashForLine(3)).isNotEqualTo(b.getBlockHashForLine(3));
+
+    BlockHashSequence c = new BlockHashSequence(LineHashSequence.createForLines(asList("line-1", "line0", "line1", "line2", "line3")), 1);
+    assertThat(a.getBlockHashForLine(1)).isNotEqualTo(c.getBlockHashForLine(2));
+    assertThat(a.getBlockHashForLine(2)).isEqualTo(c.getBlockHashForLine(3));
+  }
+}
diff --git a/sonar-core/src/test/java/org/sonar/core/issue/tracking/BlockRecognizerTest.java b/sonar-core/src/test/java/org/sonar/core/issue/tracking/BlockRecognizerTest.java
new file mode 100644 (file)
index 0000000..d265e70
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * 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.issue.tracking;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class BlockRecognizerTest {
+
+  @Test
+  public void lengthOfMaximalBlock() {
+    /**
+     * - line 4 of first sequence is "d"
+     * - line 4 of second sequence is "d"
+     * - in each sequence, the 3 lines before and the line after are similar -> block size is 5
+     */
+    assertThat(compute(seq("abcde"), seq("abcde"), 4, 4)).isEqualTo(5);
+
+    assertThat(compute(seq("abcde"), seq("abcd"), 4, 4)).isEqualTo(4);
+    assertThat(compute(seq("bcde"), seq("abcde"), 4, 4)).isEqualTo(0);
+    assertThat(compute(seq("bcde"), seq("abcde"), 3, 4)).isEqualTo(4);
+  }
+
+  private int compute(LineHashSequence seqA, LineHashSequence seqB, int ai, int bi) {
+    return BlockRecognizer.lengthOfMaximalBlock(seqA, ai, seqB, bi);
+  }
+
+  private static LineHashSequence seq(String text) {
+    List<String> hashes = new ArrayList<>();
+    for (int i = 0; i < text.length(); i++) {
+      hashes.add("" + text.charAt(i));
+    }
+    return new LineHashSequence(hashes);
+  }
+
+}
diff --git a/sonar-core/src/test/java/org/sonar/core/issue/tracking/TrackerTest.java b/sonar-core/src/test/java/org/sonar/core/issue/tracking/TrackerTest.java
new file mode 100644 (file)
index 0000000..3739122
--- /dev/null
@@ -0,0 +1,456 @@
+/*
+ * 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.issue.tracking;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import javax.annotation.Nullable;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.rule.RuleKey;
+
+import static java.util.Arrays.asList;
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class TrackerTest {
+
+  public static final RuleKey RULE_SYSTEM_PRINT = RuleKey.of("java", "SystemPrint");
+  public static final RuleKey RULE_UNUSED_LOCAL_VARIABLE = RuleKey.of("java", "UnusedLocalVariable");
+  public static final RuleKey RULE_UNUSED_PRIVATE_METHOD = RuleKey.of("java", "UnusedPrivateMethod");
+  public static final RuleKey RULE_NOT_DESIGNED_FOR_EXTENSION = RuleKey.of("java", "NotDesignedForExtension");
+  @Rule
+  public ExpectedException thrown = ExpectedException.none();
+
+  Tracker<Issue, Issue> tracker = new Tracker<>();
+
+  /**
+   * Of course rule must match
+   */
+  @Test
+  public void similar_issues_except_rule_do_not_match() {
+    FakeInput baseInput = new FakeInput("H1");
+    baseInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, "msg");
+
+    FakeInput rawInput = new FakeInput("H1");
+    Issue raw = rawInput.createIssueOnLine(1, RULE_UNUSED_LOCAL_VARIABLE, "msg");
+
+    Tracking<Issue, Issue> tracking = tracker.track(rawInput, baseInput);
+    assertThat(tracking.baseFor(raw)).isNull();
+  }
+
+  @Test
+  @Ignore
+  public void different_issues_do_not_match() {
+    FakeInput baseInput = new FakeInput("H1");
+    Issue base = baseInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, "msg1");
+
+    FakeInput rawInput = new FakeInput("H2", "H3", "H4", "H5", "H6");
+    Issue raw = rawInput.createIssueOnLine(5, RULE_SYSTEM_PRINT, "msg2");
+
+    Tracking<Issue, Issue> tracking = tracker.track(rawInput, baseInput);
+    assertThat(tracking.baseFor(raw)).isNull();
+    assertThat(tracking.getUnmatchedBases()).containsOnly(base);
+  }
+
+  @Test
+  public void line_hash_has_greater_priority_than_line() {
+    FakeInput baseInput = new FakeInput("H1", "H2", "H3");
+    Issue base1 = baseInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, "msg");
+    Issue base2 = baseInput.createIssueOnLine(3, RULE_SYSTEM_PRINT, "msg");
+
+    FakeInput rawInput = new FakeInput("a", "b", "H1", "H2", "H3");
+    Issue raw1 = rawInput.createIssueOnLine(3, RULE_SYSTEM_PRINT, "msg");
+    Issue raw2 = rawInput.createIssueOnLine(5, RULE_SYSTEM_PRINT, "msg");
+
+    Tracking<Issue, Issue> tracking = tracker.track(rawInput, baseInput);
+    assertThat(tracking.baseFor(raw1)).isSameAs(base1);
+    assertThat(tracking.baseFor(raw2)).isSameAs(base2);
+  }
+
+  /**
+   * SONAR-2928
+   */
+  @Test
+  public void no_lines_and_different_messages_match() {
+    FakeInput baseInput = new FakeInput("H1", "H2", "H3");
+    Issue base = baseInput.createIssue(RULE_SYSTEM_PRINT, "msg1");
+
+    FakeInput rawInput = new FakeInput("H10", "H11", "H12");
+    Issue raw = rawInput.createIssue(RULE_SYSTEM_PRINT, "msg2");
+
+    Tracking<Issue, Issue> tracking = tracker.track(rawInput, baseInput);
+    assertThat(tracking.baseFor(raw)).isSameAs(base);
+  }
+
+  @Test
+  public void similar_issues_except_message_match() {
+    FakeInput baseInput = new FakeInput("H1");
+    Issue base = baseInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, "msg1");
+
+    FakeInput rawInput = new FakeInput("H1");
+    Issue raw = rawInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, "msg2");
+
+    Tracking<Issue, Issue> tracking = tracker.track(rawInput, baseInput);
+    assertThat(tracking.baseFor(raw)).isSameAs(base);
+  }
+
+  @Test
+  public void similar_issues_if_trimmed_messages_match() {
+    FakeInput baseInput = new FakeInput("H1");
+    Issue base = baseInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, "   message  ");
+
+    FakeInput rawInput = new FakeInput("H2");
+    Issue raw = rawInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, "message");
+
+    Tracking<Issue, Issue> tracking = tracker.track(rawInput, baseInput);
+    assertThat(tracking.baseFor(raw)).isSameAs(base);
+  }
+
+  /**
+   * Source code of this line was changed, but line and message still match
+   */
+  @Test
+  public void similar_issues_except_line_hash_match() {
+    FakeInput baseInput = new FakeInput("H1");
+    Issue base = baseInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, "msg");
+
+    FakeInput rawInput = new FakeInput("H2");
+    Issue raw = rawInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, "msg");
+
+    Tracking<Issue, Issue> tracking = tracker.track(rawInput, baseInput);
+    assertThat(tracking.baseFor(raw)).isSameAs(base);
+  }
+
+  @Test
+  public void similar_issues_except_line_match() {
+    FakeInput baseInput = new FakeInput("H1", "H2");
+    Issue base = baseInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, "msg");
+
+    FakeInput rawInput = new FakeInput("H2", "H1");
+    Issue raw = rawInput.createIssueOnLine(2, RULE_SYSTEM_PRINT, "msg");
+
+    Tracking<Issue, Issue> tracking = tracker.track(rawInput, baseInput);
+    assertThat(tracking.baseFor(raw)).isSameAs(base);
+  }
+
+  /**
+   * SONAR-2812
+   */
+  @Test
+  public void only_same_line_hash_match_match() {
+    FakeInput baseInput = new FakeInput("H1", "H2");
+    Issue base = baseInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, "msg");
+
+    FakeInput rawInput = new FakeInput("H3", "H4", "H1");
+    Issue raw = rawInput.createIssueOnLine(3, RULE_SYSTEM_PRINT, "other message");
+
+    Tracking<Issue, Issue> tracking = tracker.track(rawInput, baseInput);
+    assertThat(tracking.baseFor(raw)).isSameAs(base);
+  }
+
+  @Test
+  public void do_not_fail_if_base_issue_without_line() throws Exception {
+    FakeInput baseInput = new FakeInput("H1", "H2");
+    Issue base = baseInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, "msg1");
+
+    FakeInput rawInput = new FakeInput("H3", "H4", "H5");
+    Issue raw = rawInput.createIssue(RULE_UNUSED_LOCAL_VARIABLE, "msg2");
+
+    Tracking<Issue, Issue> tracking = tracker.track(rawInput, baseInput);
+    assertThat(tracking.baseFor(raw)).isNull();
+    assertThat(tracking.getUnmatchedBases()).containsOnly(base);
+  }
+
+  @Test
+  public void do_not_fail_if_raw_issue_without_line() throws Exception {
+    FakeInput baseInput = new FakeInput("H1", "H2");
+    Issue base = baseInput.createIssue(RULE_SYSTEM_PRINT, "msg1");
+
+    FakeInput rawInput = new FakeInput("H3", "H4", "H5");
+    Issue raw = rawInput.createIssueOnLine(1, RULE_UNUSED_LOCAL_VARIABLE, "msg2");
+
+    Tracking<Issue, Issue> tracking = tracker.track(rawInput, baseInput);
+    assertThat(tracking.baseFor(raw)).isNull();
+    assertThat(tracking.getUnmatchedBases()).containsOnly(base);
+  }
+
+  @Test
+  public void 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);
+  }
+
+  /**
+   * SONAR-3072
+   */
+  @Test
+  public void recognize_blocks_1() throws Exception {
+    FakeInput baseInput = FakeInput.createForSourceLines(
+      "package example1;",
+      "",
+      "public class Toto {",
+      "",
+      "    public void doSomething() {",
+      "        // doSomething",
+      "        }",
+      "",
+      "    public void doSomethingElse() {",
+      "        // doSomethingElse",
+      "        }",
+      "}"
+      );
+    Issue base1 = baseInput.createIssueOnLine(7, RULE_SYSTEM_PRINT, "Indentation");
+    Issue base2 = baseInput.createIssueOnLine(11, RULE_SYSTEM_PRINT, "Indentation");
+
+    FakeInput rawInput = FakeInput.createForSourceLines(
+      "package example1;",
+      "",
+      "public class Toto {",
+      "",
+      "    public Toto(){}",
+      "",
+      "    public void doSomethingNew() {",
+      "        // doSomethingNew",
+      "        }",
+      "",
+      "    public void doSomethingElseNew() {",
+      "        // doSomethingElseNew",
+      "        }",
+      "",
+      "    public void doSomething() {",
+      "        // doSomething",
+      "        }",
+      "",
+      "    public void doSomethingElse() {",
+      "        // doSomethingElse",
+      "        }",
+      "}"
+      );
+    Issue raw1 = rawInput.createIssueOnLine(9, RULE_SYSTEM_PRINT, "Indentation");
+    Issue raw2 = rawInput.createIssueOnLine(13, RULE_SYSTEM_PRINT, "Indentation");
+    Issue raw3 = rawInput.createIssueOnLine(17, RULE_SYSTEM_PRINT, "Indentation");
+    Issue raw4 = rawInput.createIssueOnLine(21, RULE_SYSTEM_PRINT, "Indentation");
+
+    Tracking<Issue, Issue> tracking = tracker.track(rawInput, baseInput);
+    assertThat(tracking.baseFor(raw1)).isNull();
+    assertThat(tracking.baseFor(raw2)).isNull();
+    assertThat(tracking.baseFor(raw3)).isSameAs(base1);
+    assertThat(tracking.baseFor(raw4)).isSameAs(base2);
+    assertThat(tracking.getUnmatchedBases()).isEmpty();
+  }
+
+  /**
+   * SONAR-3072
+   */
+  @Test
+  public void recognize_blocks_2() throws Exception {
+    FakeInput baseInput = FakeInput.createForSourceLines(
+      "package example2;",
+      "",
+      "public class Toto {",
+      "  void method1() {",
+      "    System.out.println(\"toto\");",
+      "  }",
+      "}"
+      );
+    Issue base1 = baseInput.createIssueOnLine(5, RULE_SYSTEM_PRINT, "SystemPrintln");
+
+    FakeInput rawInput = FakeInput.createForSourceLines(
+      "package example2;",
+      "",
+      "public class Toto {",
+      "",
+      "  void method2() {",
+      "    System.out.println(\"toto\");",
+      "  }",
+      "",
+      "  void method1() {",
+      "    System.out.println(\"toto\");",
+      "  }",
+      "",
+      "  void method3() {",
+      "    System.out.println(\"toto\");",
+      "  }",
+      "}"
+      );
+    Issue raw1 = rawInput.createIssueOnLine(6, RULE_SYSTEM_PRINT, "SystemPrintln");
+    Issue raw2 = rawInput.createIssueOnLine(10, RULE_SYSTEM_PRINT, "SystemPrintln");
+    Issue raw3 = rawInput.createIssueOnLine(14, RULE_SYSTEM_PRINT, "SystemPrintln");
+
+    Tracking<Issue, Issue> tracking = tracker.track(rawInput, baseInput);
+    assertThat(tracking.baseFor(raw1)).isNull();
+    assertThat(tracking.baseFor(raw2)).isSameAs(base1);
+    assertThat(tracking.baseFor(raw3)).isNull();
+  }
+
+  @Test
+  public void recognize_blocks_3() throws Exception {
+    FakeInput baseInput = FakeInput.createForSourceLines(
+      "package sample;",
+      "",
+      "public class Sample {",
+      "\t",
+      "\tpublic Sample(int i) {",
+      "\t\tint j = i+1;", // UnusedLocalVariable
+      "\t}",
+      "",
+      "\tpublic boolean avoidUtilityClass() {", // NotDesignedForExtension
+      "\t\treturn true;",
+      "\t}",
+      "",
+      "\tprivate String myMethod() {", // UnusedPrivateMethod
+      "\t\treturn \"hello\";",
+      "\t}",
+      "}"
+      );
+    Issue base1 = baseInput.createIssueOnLine(6, RULE_UNUSED_LOCAL_VARIABLE, "Avoid unused local variables such as 'j'.");
+    Issue base2 = baseInput.createIssueOnLine(13, RULE_UNUSED_PRIVATE_METHOD, "Avoid unused private methods such as 'myMethod()'.");
+    Issue base3 = baseInput.createIssueOnLine(9, RULE_NOT_DESIGNED_FOR_EXTENSION,
+      "Method 'avoidUtilityClass' is not designed for extension - needs to be abstract, final or empty.");
+
+    FakeInput rawInput = FakeInput.createForSourceLines(
+      "package sample;",
+      "",
+      "public class Sample {",
+      "",
+      "\tpublic Sample(int i) {",
+      "\t\tint j = i+1;", // UnusedLocalVariable is still there
+      "\t}",
+      "\t",
+      "\tpublic boolean avoidUtilityClass() {", // NotDesignedForExtension is still there
+      "\t\treturn true;",
+      "\t}",
+      "\t",
+      "\tprivate String myMethod() {", // issue UnusedPrivateMethod is fixed because it's called at line 18
+      "\t\treturn \"hello\";",
+      "\t}",
+      "",
+      "  public void newIssue() {",
+      "    String msg = myMethod();", // new issue UnusedLocalVariable
+      "  }",
+      "}"
+      );
+
+    Issue newRaw = rawInput.createIssueOnLine(18, RULE_UNUSED_LOCAL_VARIABLE, "Avoid unused local variables such as 'msg'.");
+    Issue rawSameAsBase1 = rawInput.createIssueOnLine(6, RULE_UNUSED_LOCAL_VARIABLE, "Avoid unused local variables such as 'j'.");
+    Issue rawSameAsBase3 = rawInput.createIssueOnLine(9, RULE_NOT_DESIGNED_FOR_EXTENSION,
+      "Method 'avoidUtilityClass' is not designed for extension - needs to be abstract, final or empty.");
+
+    Tracking<Issue, Issue> tracking = tracker.track(rawInput, baseInput);
+
+    assertThat(tracking.baseFor(newRaw)).isNull();
+    assertThat(tracking.baseFor(rawSameAsBase1)).isSameAs(base1);
+    assertThat(tracking.baseFor(rawSameAsBase3)).isSameAs(base3);
+    assertThat(tracking.getUnmatchedBases()).containsOnly(base2);
+  }
+
+  private static class Issue implements Trackable {
+    private final RuleKey ruleKey;
+    private final Integer line;
+    private final String message, lineHash;
+
+    Issue(@Nullable Integer line, String lineHash, RuleKey ruleKey, String message) {
+      this.line = line;
+      this.lineHash = lineHash;
+      this.ruleKey = ruleKey;
+      this.message = message;
+    }
+
+    @Override
+    public Integer getLine() {
+      return line;
+    }
+
+    @Override
+    public String getMessage() {
+      return message;
+    }
+
+    @Override
+    public String getLineHash() {
+      return lineHash;
+    }
+
+    @Override
+    public RuleKey getRuleKey() {
+      return ruleKey;
+    }
+  }
+
+  private static class FakeInput implements Input<Issue> {
+    private final List<Issue> issues = new ArrayList<>();
+    private final List<String> lineHashes;
+
+    public FakeInput(String... lineHashes) {
+      this.lineHashes = asList(lineHashes);
+    }
+
+    static FakeInput createForSourceLines(String... lines) {
+      String[] hashes = new String[lines.length];
+      for (int i = 0; i < lines.length; i++) {
+        hashes[i] = DigestUtils.md5Hex(lines[i].replaceAll("[\t ]", ""));
+      }
+      return new FakeInput(hashes);
+    }
+
+    public Issue createIssueOnLine(int line, RuleKey ruleKey, String message) {
+      Issue issue = new Issue(line, lineHashes.get(line - 1), ruleKey, message);
+      issues.add(issue);
+      return issue;
+    }
+
+    /**
+     * No line (line 0)
+     */
+    public Issue createIssue(RuleKey ruleKey, String message) {
+      Issue issue = new Issue(null, "", ruleKey, message);
+      issues.add(issue);
+      return issue;
+    }
+
+    public FakeInput addIssue(Issue issue) {
+      this.issues.add(issue);
+      return this;
+    }
+
+    @Override
+    public LineHashSequence getLineHashSequence() {
+      return new LineHashSequence(lineHashes);
+    }
+
+    @Override
+    public BlockHashSequence getBlockHashSequence() {
+      return new BlockHashSequence(getLineHashSequence(), 2);
+    }
+
+    @Override
+    public Collection<Issue> getIssues() {
+      return issues;
+    }
+  }
+}
diff --git a/sonar-core/src/test/java/org/sonar/core/issue/workflow/IsBeingClosedTest.java b/sonar-core/src/test/java/org/sonar/core/issue/workflow/IsBeingClosedTest.java
new file mode 100644 (file)
index 0000000..04e6c29
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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.issue.workflow;
+
+import org.junit.Test;
+import org.sonar.core.issue.DefaultIssue;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.core.issue.workflow.IsBeingClosed.INSTANCE;
+
+public class IsBeingClosedTest {
+
+
+  @Test
+  public void should_be_end_of_life() {
+    DefaultIssue issue = new DefaultIssue();
+    assertThat(INSTANCE.matches(issue.setBeingClosed(true))).isTrue();
+    assertThat(INSTANCE.matches(issue.setBeingClosed(false))).isFalse();
+  }
+
+}
diff --git a/sonar-core/src/test/java/org/sonar/core/issue/workflow/IsEndOfLifeTest.java b/sonar-core/src/test/java/org/sonar/core/issue/workflow/IsEndOfLifeTest.java
deleted file mode 100644 (file)
index 47ca6b3..0000000
+++ /dev/null
@@ -1,43 +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.issue.workflow;
-
-import org.junit.Test;
-import org.sonar.api.issue.internal.DefaultIssue;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class IsEndOfLifeTest {
-  DefaultIssue issue = new DefaultIssue();
-
-  @Test
-  public void should_be_end_of_life() {
-    IsEndOfLife condition = new IsEndOfLife(true);
-    assertThat(condition.matches(issue.setEndOfLife(true))).isTrue();
-    assertThat(condition.matches(issue.setEndOfLife(false))).isFalse();
-  }
-
-  @Test
-  public void should_not_be_end_of_life() {
-    IsEndOfLife condition = new IsEndOfLife(false);
-    assertThat(condition.matches(issue.setEndOfLife(true))).isFalse();
-    assertThat(condition.matches(issue.setEndOfLife(false))).isTrue();
-  }
-}
index 16a82274f04839eeaa5eba844642de5e5c5d9adb..78a581387c724b2fa73cc06158a513f20d0c1ee3 100644 (file)
 package org.sonar.core.issue.workflow;
 
 import org.junit.Test;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.core.issue.DefaultIssue;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.core.issue.workflow.IsManual.INSTANCE;
 
 public class IsManualTest {
-  DefaultIssue issue = new DefaultIssue();
 
   @Test
   public void should_match() {
-    IsManual condition = new IsManual(true);
-    assertThat(condition.matches(issue.setReporter("you"))).isTrue();
-    assertThat(condition.matches(issue.setReporter(null))).isFalse();
+    DefaultIssue issue = new DefaultIssue();
+    assertThat(INSTANCE.matches(issue.setRuleKey(RuleKey.of(RuleKey.MANUAL_REPOSITORY_KEY, "R1")))).isTrue();
+    assertThat(INSTANCE.matches(issue.setRuleKey(RuleKey.of("java", "R1")))).isFalse();
   }
 
-  @Test
-  public void should_match_dead() {
-    IsManual condition = new IsManual(false);
-    assertThat(condition.matches(issue.setReporter("you"))).isFalse();
-    assertThat(condition.matches(issue.setReporter(null))).isTrue();
-  }
 }
index 8cc01a72189191087939e02033031de536511608..ad5b9bef6e8c39d559dc487fe1f06146c9ab1d80 100644 (file)
@@ -25,8 +25,8 @@ import org.apache.commons.lang.time.DateUtils;
 import org.junit.Test;
 import org.sonar.api.issue.DefaultTransitions;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.IssueChangeContext;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.IssueChangeContext;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.core.issue.IssueUpdater;
 
@@ -106,7 +106,7 @@ public class IssueWorkflowTest {
   public void list_no_out_transition_from_status_closed() {
     workflow.start();
 
-    DefaultIssue issue = new DefaultIssue().setStatus(Issue.STATUS_CLOSED);
+    DefaultIssue issue = new DefaultIssue().setStatus(Issue.STATUS_CLOSED).setRuleKey(RuleKey.of("java", "R1  "));
     List<Transition> transitions = workflow.outTransitions(issue);
     assertThat(transitions).isEmpty();
   }
@@ -149,7 +149,7 @@ public class IssueWorkflowTest {
       .setResolution(Issue.RESOLUTION_FIXED)
       .setStatus(Issue.STATUS_RESOLVED)
       .setNew(false)
-      .setEndOfLife(true);
+      .setBeingClosed(true);
     Date now = new Date();
     workflow.doAutomaticTransition(issue, IssueChangeContext.createScan(now));
     assertThat(issue.resolution()).isEqualTo(Issue.RESOLUTION_FIXED);
@@ -167,7 +167,7 @@ public class IssueWorkflowTest {
       .setResolution(null)
       .setStatus(Issue.STATUS_OPEN)
       .setNew(false)
-      .setEndOfLife(true);
+      .setBeingClosed(true);
     Date now = new Date();
     workflow.doAutomaticTransition(issue, IssueChangeContext.createScan(now));
     assertThat(issue.resolution()).isEqualTo(Issue.RESOLUTION_FIXED);
@@ -185,7 +185,7 @@ public class IssueWorkflowTest {
       .setResolution(null)
       .setStatus(Issue.STATUS_REOPENED)
       .setNew(false)
-      .setEndOfLife(true);
+      .setBeingClosed(true);
     Date now = new Date();
     workflow.doAutomaticTransition(issue, IssueChangeContext.createScan(now));
     assertThat(issue.resolution()).isEqualTo(Issue.RESOLUTION_FIXED);
@@ -203,7 +203,7 @@ public class IssueWorkflowTest {
       .setResolution(null)
       .setStatus(Issue.STATUS_CONFIRMED)
       .setNew(false)
-      .setEndOfLife(true);
+      .setBeingClosed(true);
     Date now = new Date();
     workflow.doAutomaticTransition(issue, IssueChangeContext.createScan(now));
     assertThat(issue.resolution()).isEqualTo(Issue.RESOLUTION_FIXED);
@@ -222,7 +222,7 @@ public class IssueWorkflowTest {
       .setResolution(Issue.RESOLUTION_FIXED)
       .setStatus("xxx")
       .setNew(false)
-      .setEndOfLife(true);
+      .setBeingClosed(true);
     try {
       workflow.doAutomaticTransition(issue, IssueChangeContext.createScan(new Date()));
       fail();
@@ -346,7 +346,7 @@ public class IssueWorkflowTest {
       .setStatus(Issue.STATUS_OPEN)
       .setRuleKey(RuleKey.of("manual", "Performance"))
       .setReporter("simon")
-      .setEndOfLife(true)
+      .setBeingClosed(true)
       .setOnDisabledRule(true);
 
     workflow.start();
@@ -364,7 +364,7 @@ public class IssueWorkflowTest {
       .setStatus(Issue.STATUS_OPEN)
       .setRuleKey(RuleKey.of("manual", "Performance"))
       .setReporter("simon")
-      .setEndOfLife(true)
+      .setBeingClosed(true)
       .setOnDisabledRule(false);
 
     workflow.start();
diff --git a/sonar-core/src/test/java/org/sonar/core/issue/workflow/SetAssigneeTest.java b/sonar-core/src/test/java/org/sonar/core/issue/workflow/SetAssigneeTest.java
deleted file mode 100644 (file)
index ebadb4b..0000000
+++ /dev/null
@@ -1,45 +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.issue.workflow;
-
-import org.junit.Test;
-import org.sonar.api.user.User;
-import org.sonar.core.user.DefaultUser;
-
-import static org.mockito.Mockito.*;
-
-public class SetAssigneeTest {
-  @Test
-  public void assign() {
-    User user = new DefaultUser().setLogin("eric").setName("eric");
-    SetAssignee function = new SetAssignee(user);
-    Function.Context context = mock(Function.Context.class);
-    function.execute(context);
-    verify(context, times(1)).setAssignee(user);
-  }
-
-  @Test
-  public void unassign() {
-    Function.Context context = mock(Function.Context.class);
-    SetAssignee.UNASSIGN.execute(context);
-    verify(context, times(1)).setAssignee(null);
-  }
-}
diff --git a/sonar-core/src/test/java/org/sonar/core/issue/workflow/SetClosedTest.java b/sonar-core/src/test/java/org/sonar/core/issue/workflow/SetClosedTest.java
new file mode 100644 (file)
index 0000000..84e4678
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * 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.issue.workflow;
+
+import org.junit.Test;
+import org.sonar.api.issue.Issue;
+import org.sonar.core.issue.DefaultIssue;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.*;
+import static org.sonar.core.issue.workflow.SetClosed.INSTANCE;
+
+public class SetClosedTest {
+
+  Function.Context context = mock(Function.Context.class);
+
+  @Test
+  public void should_resolve_as_fixed() {
+    Issue issue = new DefaultIssue().setBeingClosed(true).setOnDisabledRule(false);
+    when(context.issue()).thenReturn(issue);
+    INSTANCE.execute(context);
+    verify(context, times(1)).setResolution(Issue.RESOLUTION_FIXED);
+  }
+
+  @Test
+  public void should_resolve_as_removed_when_rule_is_disabled() {
+    Issue issue = new DefaultIssue().setBeingClosed(true).setOnDisabledRule(true);
+    when(context.issue()).thenReturn(issue);
+    INSTANCE.execute(context);
+    verify(context, times(1)).setResolution(Issue.RESOLUTION_REMOVED);
+  }
+
+  @Test
+  public void should_fail_if_issue_is_not_resolved() {
+    Issue issue = new DefaultIssue().setBeingClosed(false);
+    when(context.issue()).thenReturn(issue);
+    try {
+      INSTANCE.execute(context);
+      fail();
+    } catch (IllegalStateException e) {
+      assertThat(e.getMessage()).contains("Issue is still alive");
+      verify(context, never()).setResolution(anyString());
+    }
+  }
+
+  @Test
+  public void line_number_must_be_unset() {
+    Issue issue = new DefaultIssue().setBeingClosed(true).setLine(10);
+    when(context.issue()).thenReturn(issue);
+    INSTANCE.execute(context);
+    verify(context).setLine(null);
+  }
+}
diff --git a/sonar-core/src/test/java/org/sonar/core/issue/workflow/SetEndOfLifeTest.java b/sonar-core/src/test/java/org/sonar/core/issue/workflow/SetEndOfLifeTest.java
deleted file mode 100644 (file)
index 014a8c2..0000000
+++ /dev/null
@@ -1,71 +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.issue.workflow;
-
-import org.junit.Test;
-import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.*;
-
-public class SetEndOfLifeTest {
-
-  Function.Context context = mock(Function.Context.class);
-  SetEndOfLife function = new SetEndOfLife();
-
-  @Test
-  public void should_resolve_as_fixed() {
-    Issue issue = new DefaultIssue().setEndOfLife(true).setOnDisabledRule(false);
-    when(context.issue()).thenReturn(issue);
-    function.execute(context);
-    verify(context, times(1)).setResolution(Issue.RESOLUTION_FIXED);
-  }
-
-  @Test
-  public void should_resolve_as_removed_when_rule_is_disabled() {
-    Issue issue = new DefaultIssue().setEndOfLife(true).setOnDisabledRule(true);
-    when(context.issue()).thenReturn(issue);
-    function.execute(context);
-    verify(context, times(1)).setResolution(Issue.RESOLUTION_REMOVED);
-  }
-
-  @Test
-  public void should_fail_if_issue_is_not_resolved() {
-    Issue issue = new DefaultIssue().setEndOfLife(false);
-    when(context.issue()).thenReturn(issue);
-    try {
-      function.execute(context);
-      fail();
-    } catch (IllegalStateException e) {
-      assertThat(e.getMessage()).contains("Issue is still alive");
-      verify(context, never()).setResolution(anyString());
-    }
-  }
-
-  @Test
-  public void line_number_must_be_unset() {
-    Issue issue = new DefaultIssue().setEndOfLife(true).setLine(10);
-    when(context.issue()).thenReturn(issue);
-    function.execute(context);
-    verify(context).setLine(null);
-  }
-}
index 4c680c54ec10d6fa72467de5b44e22d8b20074a2..eab956c68583b79ee8ae47bdf69f7c9be448579e 100644 (file)
@@ -21,7 +21,7 @@ package org.sonar.core.issue.workflow;
 
 import org.junit.Test;
 import org.sonar.api.issue.condition.Condition;
-import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.core.issue.DefaultIssue;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.Assert.fail;
diff --git a/sonar-core/src/test/java/org/sonar/core/issue/workflow/UnsetAssigneeTest.java b/sonar-core/src/test/java/org/sonar/core/issue/workflow/UnsetAssigneeTest.java
new file mode 100644 (file)
index 0000000..3458baa
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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.issue.workflow;
+
+import org.junit.Test;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.sonar.core.issue.workflow.UnsetAssignee.INSTANCE;
+
+public class UnsetAssigneeTest {
+
+  @Test
+  public void unassign() {
+    Function.Context context = mock(Function.Context.class);
+    INSTANCE.execute(context);
+    verify(context, times(1)).setAssignee(null);
+  }
+}
diff --git a/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_by_key.xml b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_by_key.xml
deleted file mode 100644 (file)
index 080269c..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-<dataset>
-
-  <issues
-      id="100"
-      kee="ABCDE"
-      component_uuid="CDEF"
-      project_uuid="ABCD"
-      rule_id="500"
-      severity="BLOCKER"
-      manual_severity="[false]"
-      message="[null]"
-      line="200"
-      effort_to_fix="4.2"
-      status="OPEN"
-      resolution="FIXED"
-      checksum="XXX"
-      reporter="arthur"
-      assignee="perceval"
-      author_login="karadoc"
-      issue_attributes="JIRA=FOO-1234"
-      issue_creation_date="1366063200000"
-      issue_update_date="1366063200000"
-      issue_close_date="1366063200000"
-      created_at="1400000000000"
-      updated_at="1400000000000"
-      />
-
-</dataset>
index 36c7ce4768ce1f0655ba1cd507e8c1f18713a627..4385daefcd8201a6c0f8fdc749238d777cb54cb3 100644 (file)
 package org.sonar.api.issue;
 
 import com.google.common.collect.ImmutableList;
-import org.sonar.api.batch.BatchSide;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.utils.Duration;
-
-import javax.annotation.CheckForNull;
-
 import java.io.Serializable;
 import java.util.Collection;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
+import javax.annotation.CheckForNull;
+import org.sonar.api.batch.BatchSide;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.utils.Duration;
 
 /**
  * @since 3.6
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/DefaultIssue.java b/sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/DefaultIssue.java
deleted file mode 100644 (file)
index dac3f9e..0000000
+++ /dev/null
@@ -1,592 +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.issue.internal;
-
-import com.google.common.base.Objects;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Maps;
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang.builder.ToStringBuilder;
-import org.apache.commons.lang.builder.ToStringStyle;
-import org.apache.commons.lang.time.DateUtils;
-import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.IssueComment;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.Severity;
-import org.sonar.api.utils.Duration;
-
-/**
- * PLUGINS MUST NOT BE USED THIS CLASS, EXCEPT FOR UNIT TESTING.
- *
- * @since 3.6
- */
-public class DefaultIssue implements Issue {
-
-  private String key;
-
-  private String componentUuid;
-  private String componentKey;
-
-  private String moduleUuid;
-  private String moduleUuidPath;
-
-  private String projectUuid;
-  private String projectKey;
-
-  private RuleKey ruleKey;
-  private String language;
-  private String severity;
-  private boolean manualSeverity = false;
-  private String message;
-  private Integer line;
-  private Double effortToFix;
-  private Duration debt;
-  private String status;
-  private String resolution;
-  private String reporter;
-  private String assignee;
-  private String checksum;
-  private Map<String, String> attributes = null;
-  private String authorLogin = null;
-  private String actionPlanKey;
-  private List<IssueComment> comments = null;
-  private Set<String> tags = null;
-
-  // FUNCTIONAL DATES
-  private Date creationDate;
-  private Date updateDate;
-  private Date closeDate;
-
-  // FOLLOWING FIELDS ARE AVAILABLE ONLY DURING SCAN
-
-  // Current changes
-  private FieldDiffs currentChange = null;
-
-  // all changes
-  private List<FieldDiffs> changes = null;
-
-  // true if the the issue did not exist in the previous scan.
-  private boolean isNew = true;
-
-  // True if the the issue did exist in the previous scan but not in the current one. That means
-  // that this issue should be closed.
-  private boolean endOfLife = false;
-
-  private boolean onDisabledRule = false;
-
-  // true if some fields have been changed since the previous scan
-  private boolean isChanged = false;
-
-  // true if notifications have to be sent
-  private boolean sendNotifications = false;
-
-  // Date when issue was loaded from db (only when isNew=false)
-  private Long selectedAt;
-
-  @Override
-  public String key() {
-    return key;
-  }
-
-  public DefaultIssue setKey(String key) {
-    this.key = key;
-    return this;
-  }
-
-  /**
-   * Can be null on Views or Devs
-   */
-  @Override
-  @CheckForNull
-  public String componentUuid() {
-    return componentUuid;
-  }
-
-  public DefaultIssue setComponentUuid(@CheckForNull String componentUuid) {
-    this.componentUuid = componentUuid;
-    return this;
-  }
-
-  @Override
-  public String componentKey() {
-    return componentKey;
-  }
-
-  public DefaultIssue setComponentKey(String s) {
-    this.componentKey = s;
-    return this;
-  }
-
-  @CheckForNull
-  public String moduleUuid() {
-    return moduleUuid;
-  }
-
-  public DefaultIssue setModuleUuid(@Nullable String moduleUuid) {
-    this.moduleUuid = moduleUuid;
-    return this;
-  }
-
-  @CheckForNull
-  public String moduleUuidPath() {
-    return moduleUuidPath;
-  }
-
-  public DefaultIssue setModuleUuidPath(@Nullable String moduleUuidPath) {
-    this.moduleUuidPath = moduleUuidPath;
-    return this;
-  }
-
-  /**
-   * Can be null on Views or Devs
-   */
-  @Override
-  @CheckForNull
-  public String projectUuid() {
-    return projectUuid;
-  }
-
-  public DefaultIssue setProjectUuid(@Nullable String projectUuid) {
-    this.projectUuid = projectUuid;
-    return this;
-  }
-
-  @Override
-  public String projectKey() {
-    return projectKey;
-  }
-
-  public DefaultIssue setProjectKey(String projectKey) {
-    this.projectKey = projectKey;
-    return this;
-  }
-
-  @Override
-  public RuleKey ruleKey() {
-    return ruleKey;
-  }
-
-  public DefaultIssue setRuleKey(RuleKey k) {
-    this.ruleKey = k;
-    return this;
-  }
-
-  @Override
-  public String language() {
-    return language;
-  }
-
-  public DefaultIssue setLanguage(String l) {
-    this.language = l;
-    return this;
-  }
-
-  @Override
-  public String severity() {
-    return severity;
-  }
-
-  public DefaultIssue setSeverity(@Nullable String s) {
-    Preconditions.checkArgument(s == null || Severity.ALL.contains(s), "Not a valid severity: " + s);
-    this.severity = s;
-    return this;
-  }
-
-  public boolean manualSeverity() {
-    return manualSeverity;
-  }
-
-  public DefaultIssue setManualSeverity(boolean b) {
-    this.manualSeverity = b;
-    return this;
-  }
-
-  @Override
-  @CheckForNull
-  public String message() {
-    return message;
-  }
-
-  public DefaultIssue setMessage(@Nullable String s) {
-    this.message = StringUtils.abbreviate(StringUtils.trim(s), MESSAGE_MAX_SIZE);
-    return this;
-  }
-
-  @Override
-  @CheckForNull
-  public Integer line() {
-    return line;
-  }
-
-  public DefaultIssue setLine(@Nullable Integer l) {
-    Preconditions.checkArgument(l == null || l > 0, "Line must be null or greater than zero (got " + l + ")");
-    this.line = l;
-    return this;
-  }
-
-  @Override
-  @CheckForNull
-  public Double effortToFix() {
-    return effortToFix;
-  }
-
-  public DefaultIssue setEffortToFix(@Nullable Double d) {
-    Preconditions.checkArgument(d == null || d >= 0, "Effort to fix must be greater than or equal 0 (got " + d + ")");
-    this.effortToFix = d;
-    return this;
-  }
-
-  /**
-   * Elapsed time to fix the issue
-   */
-  @Override
-  @CheckForNull
-  public Duration debt() {
-    return debt;
-  }
-
-  @CheckForNull
-  public Long debtInMinutes() {
-    return debt != null ? debt.toMinutes() : null;
-  }
-
-  public DefaultIssue setDebt(@Nullable Duration t) {
-    this.debt = t;
-    return this;
-  }
-
-  @Override
-  public String status() {
-    return status;
-  }
-
-  public DefaultIssue setStatus(String s) {
-    Preconditions.checkArgument(!Strings.isNullOrEmpty(s), "Status must be set");
-    this.status = s;
-    return this;
-  }
-
-  @Override
-  @CheckForNull
-  public String resolution() {
-    return resolution;
-  }
-
-  public DefaultIssue setResolution(@Nullable String s) {
-    this.resolution = s;
-    return this;
-  }
-
-  @Override
-  @CheckForNull
-  public String reporter() {
-    return reporter;
-  }
-
-  public DefaultIssue setReporter(@Nullable String s) {
-    this.reporter = s;
-    return this;
-  }
-
-  @Override
-  @CheckForNull
-  public String assignee() {
-    return assignee;
-  }
-
-  public DefaultIssue setAssignee(@Nullable String s) {
-    this.assignee = s;
-    return this;
-  }
-
-  @Override
-  public Date creationDate() {
-    return creationDate;
-  }
-
-  public DefaultIssue setCreationDate(Date d) {
-    // d is not marked as Nullable but we still allow null parameter for unit testing.
-    this.creationDate = (d != null ? DateUtils.truncate(d, Calendar.SECOND) : null);
-    return this;
-  }
-
-  @Override
-  @CheckForNull
-  public Date updateDate() {
-    return updateDate;
-  }
-
-  public DefaultIssue setUpdateDate(@Nullable Date d) {
-    this.updateDate = (d != null ? DateUtils.truncate(d, Calendar.SECOND) : null);
-    return this;
-  }
-
-  @Override
-  @CheckForNull
-  public Date closeDate() {
-    return closeDate;
-  }
-
-  public DefaultIssue setCloseDate(@Nullable Date d) {
-    this.closeDate = (d != null ? DateUtils.truncate(d, Calendar.SECOND) : null);
-    return this;
-  }
-
-  @CheckForNull
-  public String checksum() {
-    return checksum;
-  }
-
-  public DefaultIssue setChecksum(@Nullable String s) {
-    this.checksum = s;
-    return this;
-  }
-
-  @Override
-  public boolean isNew() {
-    return isNew;
-  }
-
-  public DefaultIssue setNew(boolean b) {
-    isNew = b;
-    return this;
-  }
-
-  /**
-   * True when one of the following conditions is true :
-   * <ul>
-   * <li>the related component has been deleted or renamed</li>
-   * <li>the rule has been deleted (eg. on plugin uninstall)</li>
-   * <li>the rule has been disabled in the Quality profile</li>
-   * </ul>
-   */
-  public boolean isEndOfLife() {
-    return endOfLife;
-  }
-
-  public DefaultIssue setEndOfLife(boolean b) {
-    endOfLife = b;
-    return this;
-  }
-
-  public boolean isOnDisabledRule() {
-    return onDisabledRule;
-  }
-
-  public DefaultIssue setOnDisabledRule(boolean b) {
-    onDisabledRule = b;
-    return this;
-  }
-
-  public boolean isChanged() {
-    return isChanged;
-  }
-
-  public DefaultIssue setChanged(boolean b) {
-    isChanged = b;
-    return this;
-  }
-
-  public boolean mustSendNotifications() {
-    return sendNotifications;
-  }
-
-  public DefaultIssue setSendNotifications(boolean b) {
-    sendNotifications = b;
-    return this;
-  }
-
-  @Override
-  @CheckForNull
-  public String attribute(String key) {
-    return attributes == null ? null : attributes.get(key);
-  }
-
-  public DefaultIssue setAttribute(String key, @Nullable String value) {
-    if (attributes == null) {
-      attributes = Maps.newHashMap();
-    }
-    if (value == null) {
-      attributes.remove(key);
-    } else {
-      attributes.put(key, value);
-    }
-    return this;
-  }
-
-  @Override
-  public Map<String, String> attributes() {
-    return attributes == null ? Collections.<String, String>emptyMap() : ImmutableMap.copyOf(attributes);
-  }
-
-  public DefaultIssue setAttributes(@Nullable Map<String, String> map) {
-    if (map != null) {
-      if (attributes == null) {
-        attributes = Maps.newHashMap();
-      }
-      attributes.putAll(map);
-    }
-    return this;
-  }
-
-  @Override
-  @CheckForNull
-  public String authorLogin() {
-    return authorLogin;
-  }
-
-  public DefaultIssue setAuthorLogin(@Nullable String s) {
-    this.authorLogin = s;
-    return this;
-  }
-
-  @Override
-  @CheckForNull
-  public String actionPlanKey() {
-    return actionPlanKey;
-  }
-
-  public DefaultIssue setActionPlanKey(@Nullable String actionPlanKey) {
-    this.actionPlanKey = actionPlanKey;
-    return this;
-  }
-
-  public DefaultIssue setFieldChange(IssueChangeContext context, String field, @Nullable Serializable oldValue, @Nullable Serializable newValue) {
-    if (!Objects.equal(oldValue, newValue)) {
-      if (currentChange == null) {
-        currentChange = new FieldDiffs();
-        currentChange.setUserLogin(context.login());
-        currentChange.setCreationDate(context.date());
-      }
-      currentChange.setDiff(field, oldValue, newValue);
-    }
-    addChange(currentChange);
-    return this;
-  }
-
-  public DefaultIssue setCurrentChange(FieldDiffs currentChange) {
-    this.currentChange = currentChange;
-    addChange(currentChange);
-    return this;
-  }
-
-  @CheckForNull
-  public FieldDiffs currentChange() {
-    return currentChange;
-  }
-
-  public DefaultIssue addChange(FieldDiffs change) {
-    if (changes == null) {
-      changes = new ArrayList<>();
-    }
-    changes.add(change);
-    return this;
-  }
-
-  public DefaultIssue setChanges(List<FieldDiffs> changes) {
-    this.changes = changes;
-    return this;
-  }
-
-  public List<FieldDiffs> changes() {
-    if (changes == null) {
-      return Collections.emptyList();
-    }
-    return ImmutableList.copyOf(changes);
-  }
-
-  public DefaultIssue addComment(DefaultIssueComment comment) {
-    if (comments == null) {
-      comments = new ArrayList<>();
-    }
-    comments.add(comment);
-    return this;
-  }
-
-  @Override
-  public List<IssueComment> comments() {
-    if (comments == null) {
-      return Collections.emptyList();
-    }
-    return ImmutableList.copyOf(comments);
-  }
-
-  @CheckForNull
-  public Long selectedAt() {
-    return selectedAt;
-  }
-
-  public DefaultIssue setSelectedAt(@Nullable Long d) {
-    this.selectedAt = d;
-    return this;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) {
-      return true;
-    }
-    if (o == null || getClass() != o.getClass()) {
-      return false;
-    }
-    DefaultIssue that = (DefaultIssue) o;
-    return !(key != null ? !key.equals(that.key) : (that.key != null));
-  }
-
-  @Override
-  public int hashCode() {
-    return key != null ? key.hashCode() : 0;
-  }
-
-  @Override
-  public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
-  }
-
-  @Override
-  public Collection<String> tags() {
-    if (tags == null) {
-      return ImmutableSet.of();
-    } else {
-      return ImmutableSet.copyOf(tags);
-    }
-  }
-
-  public DefaultIssue setTags(Collection<String> tags) {
-    this.tags = new LinkedHashSet<>(tags);
-    return this;
-  }
-}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/DefaultIssueComment.java b/sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/DefaultIssueComment.java
deleted file mode 100644 (file)
index 205f13e..0000000
+++ /dev/null
@@ -1,130 +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.issue.internal;
-
-import org.sonar.api.issue.IssueComment;
-import org.sonar.api.utils.internal.Uuids;
-
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
-import java.io.Serializable;
-import java.util.Date;
-
-/**
- * PLUGINS MUST NOT BE USED THIS CLASS, EXCEPT FOR UNIT TESTING.
- *
- * @since 3.6
- */
-public class DefaultIssueComment implements Serializable, IssueComment {
-
-  private String issueKey;
-  private String userLogin;
-  private Date createdAt;
-  private Date updatedAt;
-  private String key;
-  private String markdownText;
-  private boolean isNew;
-
-  public static DefaultIssueComment create(String issueKey, @Nullable String login, String markdownText) {
-    DefaultIssueComment comment = new DefaultIssueComment();
-    comment.setIssueKey(issueKey);
-    comment.setKey(Uuids.create());
-    Date now = new Date();
-    comment.setUserLogin(login);
-    comment.setMarkdownText(markdownText);
-    comment.setCreatedAt(now).setUpdatedAt(now);
-    comment.setNew(true);
-    return comment;
-  }
-
-  @Override
-  public String markdownText() {
-    return markdownText;
-  }
-
-  public DefaultIssueComment setMarkdownText(String s) {
-    this.markdownText = s;
-    return this;
-  }
-
-  @Override
-  public String issueKey() {
-    return issueKey;
-  }
-
-  public DefaultIssueComment setIssueKey(String s) {
-    this.issueKey = s;
-    return this;
-  }
-
-  @Override
-  public String key() {
-    return key;
-  }
-
-  public DefaultIssueComment setKey(String key) {
-    this.key = key;
-    return this;
-  }
-
-  /**
-   * The user who created the comment. Null if it was automatically generated during project scan.
-   */
-  @Override
-  @CheckForNull
-  public String userLogin() {
-    return userLogin;
-  }
-
-  public DefaultIssueComment setUserLogin(@Nullable String userLogin) {
-    this.userLogin = userLogin;
-    return this;
-  }
-
-  @Override
-  public Date createdAt() {
-    return createdAt;
-  }
-
-  public DefaultIssueComment setCreatedAt(Date createdAt) {
-    this.createdAt = createdAt;
-    return this;
-  }
-
-  @Override
-  public Date updatedAt() {
-    return updatedAt;
-  }
-
-  public DefaultIssueComment setUpdatedAt(@Nullable Date updatedAt) {
-    this.updatedAt = updatedAt;
-    return this;
-  }
-
-  public boolean isNew() {
-    return isNew;
-  }
-
-  public DefaultIssueComment setNew(boolean b) {
-    isNew = b;
-    return this;
-  }
-}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/FieldDiffs.java b/sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/FieldDiffs.java
deleted file mode 100644 (file)
index 1529841..0000000
+++ /dev/null
@@ -1,195 +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.issue.internal;
-
-import com.google.common.base.Splitter;
-import com.google.common.base.Strings;
-import com.google.common.collect.Maps;
-import java.io.Serializable;
-import java.util.Date;
-import java.util.Map;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
-/**
- * PLUGINS MUST NOT USE THIS CLASS, EXCEPT FOR UNIT TESTING.
- *
- * @since 3.6
- */
-public class FieldDiffs implements Serializable {
-
-  public static final Splitter FIELDS_SPLITTER = Splitter.on(',').omitEmptyStrings();
-
-  private String issueKey;
-  private String userLogin;
-  private Date creationDate;
-
-  private final Map<String, Diff> diffs = Maps.newLinkedHashMap();
-
-  public Map<String, Diff> diffs() {
-    return diffs;
-  }
-
-  public Diff get(String field) {
-    return diffs.get(field);
-  }
-
-  @CheckForNull
-  public String userLogin() {
-    return userLogin;
-  }
-
-  public FieldDiffs setUserLogin(@Nullable String s) {
-    this.userLogin = s;
-    return this;
-  }
-
-  public Date creationDate() {
-    return creationDate;
-  }
-
-  public FieldDiffs setCreationDate(Date creationDate) {
-    this.creationDate = creationDate;
-    return this;
-  }
-
-  public String issueKey() {
-    return issueKey;
-  }
-
-  public FieldDiffs setIssueKey(String issueKey) {
-    this.issueKey = issueKey;
-    return this;
-  }
-
-  @SuppressWarnings("unchecked")
-  public FieldDiffs setDiff(String field, @Nullable Serializable oldValue, @Nullable Serializable newValue) {
-    Diff diff = diffs.get(field);
-    if (diff == null) {
-      diff = new Diff(oldValue, newValue);
-      diffs.put(field, diff);
-    } else {
-      diff.setNewValue(newValue);
-    }
-    return this;
-  }
-
-  @Override
-  public String toString() {
-    StringBuilder sb = new StringBuilder();
-    boolean notFirst = false;
-    for (Map.Entry<String, Diff> entry : diffs.entrySet()) {
-      if (notFirst) {
-        sb.append(',');
-      } else {
-        notFirst = true;
-      }
-      sb.append(entry.getKey());
-      sb.append('=');
-      sb.append(entry.getValue().toString());
-    }
-    return sb.toString();
-  }
-
-  public static FieldDiffs parse(@Nullable String s) {
-    FieldDiffs diffs = new FieldDiffs();
-    if (!Strings.isNullOrEmpty(s)) {
-      Iterable<String> fields = FIELDS_SPLITTER.split(s);
-      for (String field : fields) {
-        String[] keyValues = field.split("=");
-        if (keyValues.length == 2) {
-          String[] values = keyValues[1].split("\\|");
-          String oldValue = "";
-          String newValue = "";
-          if(values.length == 1) {
-            newValue = Strings.nullToEmpty(values[0]);
-          } else if(values.length == 2) {
-            oldValue = Strings.nullToEmpty(values[0]);
-            newValue = Strings.nullToEmpty(values[1]);
-          }
-          diffs.setDiff(keyValues[0], oldValue, newValue);
-        } else {
-          diffs.setDiff(keyValues[0], "", "");
-        }
-      }
-    }
-    return diffs;
-  }
-
-  public static class Diff<T extends Serializable> implements Serializable {
-    private T oldValue;
-    private T newValue;
-
-    public Diff(@Nullable T oldValue, @Nullable T newValue) {
-      this.oldValue = oldValue;
-      this.newValue = newValue;
-    }
-
-    @CheckForNull
-    public T oldValue() {
-      return oldValue;
-    }
-
-    @CheckForNull
-    public Long oldValueLong() {
-      return toLong(oldValue);
-    }
-
-    @CheckForNull
-    public T newValue() {
-      return newValue;
-    }
-
-    @CheckForNull
-    public Long newValueLong() {
-      return toLong(newValue);
-    }
-
-    void setNewValue(T t) {
-      this.newValue = t;
-    }
-
-    @CheckForNull
-    private static Long toLong(@Nullable Serializable value) {
-      if (value != null && !"".equals(value)) {
-        try {
-          return Long.valueOf((String) value);
-        } catch (ClassCastException e) {
-          return (Long) value;
-        }
-      }
-      return null;
-    }
-
-    @Override
-    public String toString() {
-      //TODO escape , and | characters
-      StringBuilder sb = new StringBuilder();
-      if(newValue != null) {
-        if(oldValue != null) {
-          sb.append(oldValue.toString());
-          sb.append('|');
-        }
-        sb.append(newValue.toString());
-      }
-      return sb.toString();
-    }
-  }
-}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/IssueChangeContext.java b/sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/IssueChangeContext.java
deleted file mode 100644 (file)
index 1598ad1..0000000
+++ /dev/null
@@ -1,65 +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.issue.internal;
-
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
-import java.io.Serializable;
-import java.util.Date;
-
-/**
- * PLUGINS MUST NOT BE USED THIS CLASS, EXCEPT FOR UNIT TESTING.
- *
- * @since 3.6
- */
-public class IssueChangeContext implements Serializable {
-
-  private final String login;
-  private final Date date;
-  private final boolean scan;
-
-  private IssueChangeContext(@Nullable String login, Date date, boolean scan) {
-    this.login = login;
-    this.date = date;
-    this.scan = scan;
-  }
-
-  @CheckForNull
-  public String login() {
-    return login;
-  }
-
-  public Date date() {
-    return date;
-  }
-
-  public boolean scan() {
-    return scan;
-  }
-
-  public static IssueChangeContext createScan(Date date) {
-    return new IssueChangeContext(null, date, true);
-  }
-
-  public static IssueChangeContext createUser(Date date, @Nullable String login) {
-    return new IssueChangeContext(login, date, false);
-  }
-}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/package-info.java b/sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/package-info.java
deleted file mode 100644 (file)
index d95967f..0000000
+++ /dev/null
@@ -1,27 +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.
- */
-/**
- * This package contains classes that MUST NOT be used by plugins,
- * except for unit testing.
- */
-@ParametersAreNonnullByDefault
-package org.sonar.api.issue.internal;
-
-import javax.annotation.ParametersAreNonnullByDefault;
index 1b065e082e4b9f5eb18fac8aa2a4857cea6f0a4d..3f0275401c0fa6e2596223f5efa7c00ee0edeb3a 100644 (file)
  * 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.issue.action;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.issue.condition.Condition;
-import org.sonar.api.issue.internal.DefaultIssue;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class ActionTest {
-  @Rule
-  public ExpectedException thrown = ExpectedException.none();
-
-  Condition condition1 = mock(Condition.class);
-  Condition condition2 = mock(Condition.class);
-  Function function1 = mock(Function.class);
-  Function function2 = mock(Function.class);
-
-  @Test
-  public void test_action() throws Exception {
-    Action action = new Action("link-to-jira")
-      .setConditions(condition1, condition2)
-      .setFunctions(function1, function2);
-
-    assertThat(action.key()).isEqualTo("link-to-jira");
-    assertThat(action.conditions()).containsOnly(condition1, condition2);
-    assertThat(action.functions()).containsOnly(function1, function2);
-  }
-
-  @Test
-  public void key_should_be_set() {
-    thrown.expectMessage("Action key must be set");
-
-    new Action("");
-  }
-
-  @Test
-  public void should_verify_conditions() {
-    DefaultIssue issue = new DefaultIssue();
-    Action action = new Action("link-to-jira")
-      .setConditions(condition1, condition2);
-
-    when(condition1.matches(issue)).thenReturn(true);
-    when(condition2.matches(issue)).thenReturn(false);
-    assertThat(action.supports(issue)).isFalse();
-
-    when(condition1.matches(issue)).thenReturn(true);
-    when(condition2.matches(issue)).thenReturn(true);
-    assertThat(action.supports(issue)).isTrue();
-  }
-
-  @Test
-  public void test_equals_and_hashCode() throws Exception {
-    Action t1 = new Action("link-to-jira");
-    Action t2 = new Action("link-to-jira");
-    Action t3 = new Action("comment");
-
-    assertThat(t1).isEqualTo(t1);
-    assertThat(t1).isEqualTo(t2);
-    assertThat(t1).isNotEqualTo(t3);
-
-    assertThat(t1.hashCode()).isEqualTo(t1.hashCode());
-  }
-
-  @Test
-  public void test_toString() throws Exception {
-    Action t1 = new Action("link-to-jira");
-    assertThat(t1.toString()).isEqualTo("link-to-jira");
-  }
-
-}
+///*
+// * 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.issue.action;
+//
+//import org.junit.Rule;
+//import org.junit.Test;
+//import org.junit.rules.ExpectedException;
+//import org.sonar.api.issue.condition.Condition;
+//import org.sonar.api.issue.internal.DefaultIssue;
+//
+//import static org.assertj.core.api.Assertions.assertThat;
+//import static org.mockito.Mockito.mock;
+//import static org.mockito.Mockito.when;
+//
+//public class ActionTest {
+//  @Rule
+//  public ExpectedException thrown = ExpectedException.none();
+//
+//  Condition condition1 = mock(Condition.class);
+//  Condition condition2 = mock(Condition.class);
+//  Function function1 = mock(Function.class);
+//  Function function2 = mock(Function.class);
+//
+//  @Test
+//  public void test_action() throws Exception {
+//    Action action = new Action("link-to-jira")
+//      .setConditions(condition1, condition2)
+//      .setFunctions(function1, function2);
+//
+//    assertThat(action.key()).isEqualTo("link-to-jira");
+//    assertThat(action.conditions()).containsOnly(condition1, condition2);
+//    assertThat(action.functions()).containsOnly(function1, function2);
+//  }
+//
+//  @Test
+//  public void key_should_be_set() {
+//    thrown.expectMessage("Action key must be set");
+//
+//    new Action("");
+//  }
+//
+//  @Test
+//  public void should_verify_conditions() {
+//    DefaultIssue issue = new DefaultIssue();
+//    Action action = new Action("link-to-jira")
+//      .setConditions(condition1, condition2);
+//
+//    when(condition1.matches(issue)).thenReturn(true);
+//    when(condition2.matches(issue)).thenReturn(false);
+//    assertThat(action.supports(issue)).isFalse();
+//
+//    when(condition1.matches(issue)).thenReturn(true);
+//    when(condition2.matches(issue)).thenReturn(true);
+//    assertThat(action.supports(issue)).isTrue();
+//  }
+//
+//  @Test
+//  public void test_equals_and_hashCode() throws Exception {
+//    Action t1 = new Action("link-to-jira");
+//    Action t2 = new Action("link-to-jira");
+//    Action t3 = new Action("comment");
+//
+//    assertThat(t1).isEqualTo(t1);
+//    assertThat(t1).isEqualTo(t2);
+//    assertThat(t1).isNotEqualTo(t3);
+//
+//    assertThat(t1.hashCode()).isEqualTo(t1.hashCode());
+//  }
+//
+//  @Test
+//  public void test_toString() throws Exception {
+//    Action t1 = new Action("link-to-jira");
+//    assertThat(t1.toString()).isEqualTo("link-to-jira");
+//  }
+//
+//}
index f572534d50c0092c4c6f7bec6890b17700ca91f2..9f2d40e12cb1e74c6a3e73d99bef61550d05c045 100644 (file)
  * 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.issue.condition;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.issue.internal.DefaultIssue;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class HasIssuePropertyConditionTest {
-
-  @Rule
-  public ExpectedException thrown = ExpectedException.none();
-
-  DefaultIssue issue = new DefaultIssue();
-
-  @Test
-  public void should_match() {
-    HasIssuePropertyCondition condition = new HasIssuePropertyCondition("foo");
-
-    assertThat(condition.matches(issue)).isFalse();
-    assertThat(condition.matches(issue.setAttribute("foo", ""))).isFalse();
-    assertThat(condition.matches(issue.setAttribute("foo", "bar"))).isTrue();
-  }
-
-  @Test
-  public void should_get_property_key() {
-    HasIssuePropertyCondition condition = new HasIssuePropertyCondition("foo");
-    assertThat(condition.getPropertyKey()).isEqualTo("foo");
-  }
-
-  @Test
-  public void shoul_fail_if_null_property() {
-    thrown.expect(IllegalArgumentException.class);
-    new HasIssuePropertyCondition(null);
-  }
-
-  @Test
-  public void should_fail_if_empty_property() {
-    thrown.expect(IllegalArgumentException.class);
-    new HasIssuePropertyCondition("");
-  }
-
-}
+///*
+// * 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.issue.condition;
+//
+//import org.junit.Rule;
+//import org.junit.Test;
+//import org.junit.rules.ExpectedException;
+//import org.sonar.api.issue.internal.DefaultIssue;
+//
+//import static org.assertj.core.api.Assertions.assertThat;
+//
+//public class HasIssuePropertyConditionTest {
+//
+//  @Rule
+//  public ExpectedException thrown = ExpectedException.none();
+//
+//  DefaultIssue issue = new DefaultIssue();
+//
+//  @Test
+//  public void should_match() {
+//    HasIssuePropertyCondition condition = new HasIssuePropertyCondition("foo");
+//
+//    assertThat(condition.matches(issue)).isFalse();
+//    assertThat(condition.matches(issue.setAttribute("foo", ""))).isFalse();
+//    assertThat(condition.matches(issue.setAttribute("foo", "bar"))).isTrue();
+//  }
+//
+//  @Test
+//  public void should_get_property_key() {
+//    HasIssuePropertyCondition condition = new HasIssuePropertyCondition("foo");
+//    assertThat(condition.getPropertyKey()).isEqualTo("foo");
+//  }
+//
+//  @Test
+//  public void shoul_fail_if_null_property() {
+//    thrown.expect(IllegalArgumentException.class);
+//    new HasIssuePropertyCondition(null);
+//  }
+//
+//  @Test
+//  public void should_fail_if_empty_property() {
+//    thrown.expect(IllegalArgumentException.class);
+//    new HasIssuePropertyCondition("");
+//  }
+//
+//}
index 67467178ba150f569700dd56810364d9605cb476..0762d06330b4ce49658dda092aeddca7ef4227a3 100644 (file)
  * 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.issue.condition;
-
-import org.junit.Test;
-import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class HasResolutionTest {
-
-  DefaultIssue issue = new DefaultIssue();
-
-  @Test
-  public void should_match() {
-    HasResolution condition = new HasResolution(Issue.RESOLUTION_FIXED, Issue.RESOLUTION_FALSE_POSITIVE);
-
-    assertThat(condition.matches(issue.setResolution("FIXED"))).isTrue();
-    assertThat(condition.matches(issue.setResolution("FALSE-POSITIVE"))).isTrue();
-
-    assertThat(condition.matches(issue.setResolution("Fixed"))).isFalse();
-  }
-}
+///*
+// * 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.issue.condition;
+//
+//import org.junit.Test;
+//import org.sonar.api.issue.Issue;
+//import org.sonar.api.issue.internal.DefaultIssue;
+//
+//import static org.assertj.core.api.Assertions.assertThat;
+//
+//public class HasResolutionTest {
+//
+//  DefaultIssue issue = new DefaultIssue();
+//
+//  @Test
+//  public void should_match() {
+//    HasResolution condition = new HasResolution(Issue.RESOLUTION_FIXED, Issue.RESOLUTION_FALSE_POSITIVE);
+//
+//    assertThat(condition.matches(issue.setResolution("FIXED"))).isTrue();
+//    assertThat(condition.matches(issue.setResolution("FALSE-POSITIVE"))).isTrue();
+//
+//    assertThat(condition.matches(issue.setResolution("Fixed"))).isFalse();
+//  }
+//}
index 4b3b6e834cd5a2c2d8e51294f83fc4c361e7d9f4..5d9258fa07be3d6370f4c7dd77d8951bd932eace 100644 (file)
  * 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.issue.condition;
-
-import org.junit.Test;
-import org.sonar.api.issue.internal.DefaultIssue;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class HasStatusTest {
-
-  DefaultIssue issue = new DefaultIssue();
-
-  @Test
-  public void should_match() {
-    HasStatus condition = new HasStatus("OPEN", "REOPENED", "CONFIRMED");
-
-    assertThat(condition.matches(issue.setStatus("OPEN"))).isTrue();
-    assertThat(condition.matches(issue.setStatus("REOPENED"))).isTrue();
-    assertThat(condition.matches(issue.setStatus("CONFIRMED"))).isTrue();
-
-    assertThat(condition.matches(issue.setStatus("open"))).isFalse();
-    assertThat(condition.matches(issue.setStatus("CLOSED"))).isFalse();
-  }
-
-}
+///*
+// * 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.issue.condition;
+//
+//import org.junit.Test;
+//import org.sonar.api.issue.internal.DefaultIssue;
+//
+//import static org.assertj.core.api.Assertions.assertThat;
+//
+//public class HasStatusTest {
+//
+//  DefaultIssue issue = new DefaultIssue();
+//
+//  @Test
+//  public void should_match() {
+//    HasStatus condition = new HasStatus("OPEN", "REOPENED", "CONFIRMED");
+//
+//    assertThat(condition.matches(issue.setStatus("OPEN"))).isTrue();
+//    assertThat(condition.matches(issue.setStatus("REOPENED"))).isTrue();
+//    assertThat(condition.matches(issue.setStatus("CONFIRMED"))).isTrue();
+//
+//    assertThat(condition.matches(issue.setStatus("open"))).isFalse();
+//    assertThat(condition.matches(issue.setStatus("CLOSED"))).isFalse();
+//  }
+//
+//}
index 3e826ba0ebfe73863652342a393dd0ae001d1e51..84159f3f2421a6a35e2f40f9063b03d21dbfc7d8 100644 (file)
  * 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.issue.condition;
-
-import org.junit.Test;
-import org.sonar.api.issue.internal.DefaultIssue;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class IsUnResolvedTest {
-
-  DefaultIssue issue = new DefaultIssue();
-
-  @Test
-  public void should_match() {
-    IsUnResolved condition = new IsUnResolved();
-
-    assertThat(condition.matches(issue)).isTrue();
-    assertThat(condition.matches(issue.setResolution("FIXED"))).isFalse();
-  }
-}
+///*
+// * 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.issue.condition;
+//
+//import org.junit.Test;
+//import org.sonar.api.issue.internal.DefaultIssue;
+//
+//import static org.assertj.core.api.Assertions.assertThat;
+//
+//public class IsUnResolvedTest {
+//
+//  DefaultIssue issue = new DefaultIssue();
+//
+//  @Test
+//  public void should_match() {
+//    IsUnResolved condition = new IsUnResolved();
+//
+//    assertThat(condition.matches(issue)).isTrue();
+//    assertThat(condition.matches(issue.setResolution("FIXED"))).isFalse();
+//  }
+//}
index 4f35e961efdd9fc0bd5b6ae1edffec576b5605e2..ae2c76de3702c3efe9c199dc9e16cd68bbf9f2f1 100644 (file)
  * 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.issue.condition;
-
-import org.junit.Test;
-import org.mockito.Mockito;
-import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.when;
-
-public class NotConditionTest {
-
-  Condition target = Mockito.mock(Condition.class);
-
-  @Test
-  public void should_match_opposite() {
-    NotCondition condition = new NotCondition(target);
-
-    when(target.matches(any(Issue.class))).thenReturn(true);
-    assertThat(condition.matches(new DefaultIssue())).isFalse();
-
-    when(target.matches(any(Issue.class))).thenReturn(false);
-    assertThat(condition.matches(new DefaultIssue())).isTrue();
-  }
-}
+///*
+// * 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.issue.condition;
+//
+//import org.junit.Test;
+//import org.mockito.Mockito;
+//import org.sonar.api.issue.Issue;
+//import org.sonar.api.issue.internal.DefaultIssue;
+//
+//import static org.assertj.core.api.Assertions.assertThat;
+//import static org.mockito.Matchers.any;
+//import static org.mockito.Mockito.when;
+//
+//public class NotConditionTest {
+//
+//  Condition target = Mockito.mock(Condition.class);
+//
+//  @Test
+//  public void should_match_opposite() {
+//    NotCondition condition = new NotCondition(target);
+//
+//    when(target.matches(any(Issue.class))).thenReturn(true);
+//    assertThat(condition.matches(new DefaultIssue())).isFalse();
+//
+//    when(target.matches(any(Issue.class))).thenReturn(false);
+//    assertThat(condition.matches(new DefaultIssue())).isTrue();
+//  }
+//}
index 6ab20d2dc64198c72152146351853d019852f9bb..7db2fa9acb4b15e5f4bcb7d6da82ca580def08b5 100644 (file)
  * 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.issue.internal;
-
-import com.google.common.collect.ImmutableMap;
-import org.apache.commons.lang.StringUtils;
-import org.junit.Test;
-import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.IssueComment;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.utils.Duration;
-
-import java.text.SimpleDateFormat;
-import java.util.List;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.entry;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-
-public class DefaultIssueTest {
-
-  DefaultIssue issue = new DefaultIssue();
-
-  @Test
-  public void test_setters_and_getters() throws Exception {
-    issue.setKey("ABCD")
-      .setComponentKey("org.sample.Sample")
-      .setProjectKey("Sample")
-      .setRuleKey(RuleKey.of("squid", "S100"))
-      .setLanguage("xoo")
-      .setSeverity("MINOR")
-      .setManualSeverity(true)
-      .setMessage("a message")
-      .setLine(7)
-      .setEffortToFix(1.2d)
-      .setDebt(Duration.create(28800L))
-      .setActionPlanKey("BCDE")
-      .setStatus(Issue.STATUS_CLOSED)
-      .setResolution(Issue.RESOLUTION_FIXED)
-      .setReporter("simon")
-      .setAssignee("julien")
-      .setAuthorLogin("steph")
-      .setChecksum("c7b5db46591806455cf082bb348631e8")
-      .setNew(true)
-      .setEndOfLife(true)
-      .setOnDisabledRule(true)
-      .setChanged(true)
-      .setSendNotifications(true)
-      .setCreationDate(new SimpleDateFormat("yyyy-MM-dd").parse("2013-08-19"))
-      .setUpdateDate(new SimpleDateFormat("yyyy-MM-dd").parse("2013-08-20"))
-      .setCloseDate(new SimpleDateFormat("yyyy-MM-dd").parse("2013-08-21"))
-      .setSelectedAt(1400000000000L);
-
-    assertThat(issue.key()).isEqualTo("ABCD");
-    assertThat(issue.componentKey()).isEqualTo("org.sample.Sample");
-    assertThat(issue.projectKey()).isEqualTo("Sample");
-    assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("squid", "S100"));
-    assertThat(issue.language()).isEqualTo("xoo");
-    assertThat(issue.severity()).isEqualTo("MINOR");
-    assertThat(issue.manualSeverity()).isTrue();
-    assertThat(issue.message()).isEqualTo("a message");
-    assertThat(issue.line()).isEqualTo(7);
-    assertThat(issue.effortToFix()).isEqualTo(1.2d);
-    assertThat(issue.debt()).isEqualTo(Duration.create(28800L));
-    assertThat(issue.actionPlanKey()).isEqualTo("BCDE");
-    assertThat(issue.status()).isEqualTo(Issue.STATUS_CLOSED);
-    assertThat(issue.resolution()).isEqualTo(Issue.RESOLUTION_FIXED);
-    assertThat(issue.reporter()).isEqualTo("simon");
-    assertThat(issue.assignee()).isEqualTo("julien");
-    assertThat(issue.authorLogin()).isEqualTo("steph");
-    assertThat(issue.checksum()).isEqualTo("c7b5db46591806455cf082bb348631e8");
-    assertThat(issue.isNew()).isTrue();
-    assertThat(issue.isEndOfLife()).isTrue();
-    assertThat(issue.isOnDisabledRule()).isTrue();
-    assertThat(issue.isChanged()).isTrue();
-    assertThat(issue.mustSendNotifications()).isTrue();
-    assertThat(issue.creationDate()).isEqualTo(new SimpleDateFormat("yyyy-MM-dd").parse("2013-08-19"));
-    assertThat(issue.updateDate()).isEqualTo(new SimpleDateFormat("yyyy-MM-dd").parse("2013-08-20"));
-    assertThat(issue.closeDate()).isEqualTo(new SimpleDateFormat("yyyy-MM-dd").parse("2013-08-21"));
-    assertThat(issue.selectedAt()).isEqualTo(1400000000000L);
-  }
-
-  @Test
-  public void set_empty_dates() {
-    issue
-      .setCreationDate(null)
-      .setUpdateDate(null)
-      .setCloseDate(null)
-      .setSelectedAt(null);
-
-    assertThat(issue.creationDate()).isNull();
-    assertThat(issue.updateDate()).isNull();
-    assertThat(issue.closeDate()).isNull();
-    assertThat(issue.selectedAt()).isNull();
-  }
-
-  @Test
-  public void test_attributes() throws Exception {
-    assertThat(issue.attribute("foo")).isNull();
-    issue.setAttribute("foo", "bar");
-    assertThat(issue.attribute("foo")).isEqualTo("bar");
-    issue.setAttribute("foo", "newbar");
-    assertThat(issue.attribute("foo")).isEqualTo("newbar");
-    issue.setAttribute("foo", null);
-    assertThat(issue.attribute("foo")).isNull();
-  }
-
-  @Test
-  public void setAttributes_should_not_clear_existing_values() {
-    issue.setAttributes(ImmutableMap.of("1", "one"));
-    assertThat(issue.attribute("1")).isEqualTo("one");
-
-    issue.setAttributes(ImmutableMap.of("2", "two"));
-    assertThat(issue.attributes()).containsOnly(entry("1", "one"), entry("2", "two"));
-
-    issue.setAttributes(null);
-    assertThat(issue.attributes()).containsOnly(entry("1", "one"), entry("2", "two"));
-  }
-
-  @Test
-  public void fail_on_empty_status() {
-    try {
-      issue.setStatus("");
-      fail();
-    } catch (IllegalArgumentException e) {
-      assertThat(e).hasMessage("Status must be set");
-    }
-  }
-
-  @Test
-  public void fail_on_bad_severity() {
-    try {
-      issue.setSeverity("FOO");
-      fail();
-    } catch (IllegalArgumentException e) {
-      assertThat(e).hasMessage("Not a valid severity: FOO");
-    }
-  }
-
-  @Test
-  public void message_should_be_abbreviated_if_too_long() {
-    issue.setMessage(StringUtils.repeat("a", 5000));
-    assertThat(issue.message()).hasSize(4000);
-  }
-
-  @Test
-  public void message_should_be_trimmed() {
-    issue.setMessage("    foo     ");
-    assertThat(issue.message()).isEqualTo("foo");
-  }
-
-  @Test
-  public void message_could_be_null() {
-    issue.setMessage(null);
-    assertThat(issue.message()).isNull();
-  }
-
-  @Test
-  public void test_nullable_fields() throws Exception {
-    issue.setEffortToFix(null).setSeverity(null).setLine(null);
-    assertThat(issue.effortToFix()).isNull();
-    assertThat(issue.severity()).isNull();
-    assertThat(issue.line()).isNull();
-  }
-
-  @Test
-  public void test_equals_and_hashCode() throws Exception {
-    DefaultIssue a1 = new DefaultIssue().setKey("AAA");
-    DefaultIssue a2 = new DefaultIssue().setKey("AAA");
-    DefaultIssue b = new DefaultIssue().setKey("BBB");
-    assertThat(a1).isEqualTo(a1);
-    assertThat(a1).isEqualTo(a2);
-    assertThat(a1).isNotEqualTo(b);
-    assertThat(a1.hashCode()).isEqualTo(a1.hashCode());
-  }
-
-  @Test
-  public void comments_should_not_be_modifiable() {
-    DefaultIssue issue = new DefaultIssue().setKey("AAA");
-
-    List<IssueComment> comments = issue.comments();
-    assertThat(comments).isEmpty();
-
-    try {
-      comments.add(new DefaultIssueComment());
-      fail();
-    } catch (UnsupportedOperationException e) {
-      // ok
-    } catch (Exception e) {
-      fail("Unexpected exception: " + e);
-    }
-  }
-
-  @Test
-  public void all_changes_contain_current_change() {
-    IssueChangeContext issueChangeContext = mock(IssueChangeContext.class);
-    DefaultIssue issue = new DefaultIssue().setKey("AAA").setFieldChange(issueChangeContext, "actionPlan", "1.0", "1.1");
-
-    assertThat(issue.changes()).hasSize(1);
-  }
-}
+///*
+// * 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.issue.internal;
+//
+//import com.google.common.collect.ImmutableMap;
+//import org.apache.commons.lang.StringUtils;
+//import org.junit.Test;
+//import org.sonar.api.issue.Issue;
+//import org.sonar.api.issue.IssueComment;
+//import org.sonar.api.rule.RuleKey;
+//import org.sonar.api.utils.Duration;
+//
+//import java.text.SimpleDateFormat;
+//import java.util.List;
+//
+//import static org.assertj.core.api.Assertions.assertThat;
+//import static org.assertj.core.api.Assertions.entry;
+//import static org.junit.Assert.fail;
+//import static org.mockito.Mockito.mock;
+//
+//public class DefaultIssueTest {
+//
+//  DefaultIssue issue = new DefaultIssue();
+//
+//  @Test
+//  public void test_setters_and_getters() throws Exception {
+//    issue.setKey("ABCD")
+//      .setComponentKey("org.sample.Sample")
+//      .setProjectKey("Sample")
+//      .setRuleKey(RuleKey.of("squid", "S100"))
+//      .setLanguage("xoo")
+//      .setSeverity("MINOR")
+//      .setManualSeverity(true)
+//      .setMessage("a message")
+//      .setLine(7)
+//      .setEffortToFix(1.2d)
+//      .setDebt(Duration.create(28800L))
+//      .setActionPlanKey("BCDE")
+//      .setStatus(Issue.STATUS_CLOSED)
+//      .setResolution(Issue.RESOLUTION_FIXED)
+//      .setReporter("simon")
+//      .setAssignee("julien")
+//      .setAuthorLogin("steph")
+//      .setChecksum("c7b5db46591806455cf082bb348631e8")
+//      .setNew(true)
+//      .setBeingClosed(true)
+//      .setOnDisabledRule(true)
+//      .setChanged(true)
+//      .setSendNotifications(true)
+//      .setCreationDate(new SimpleDateFormat("yyyy-MM-dd").parse("2013-08-19"))
+//      .setUpdateDate(new SimpleDateFormat("yyyy-MM-dd").parse("2013-08-20"))
+//      .setCloseDate(new SimpleDateFormat("yyyy-MM-dd").parse("2013-08-21"))
+//      .setSelectedAt(1400000000000L);
+//
+//    assertThat(issue.key()).isEqualTo("ABCD");
+//    assertThat(issue.componentKey()).isEqualTo("org.sample.Sample");
+//    assertThat(issue.projectKey()).isEqualTo("Sample");
+//    assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("squid", "S100"));
+//    assertThat(issue.language()).isEqualTo("xoo");
+//    assertThat(issue.severity()).isEqualTo("MINOR");
+//    assertThat(issue.manualSeverity()).isTrue();
+//    assertThat(issue.message()).isEqualTo("a message");
+//    assertThat(issue.line()).isEqualTo(7);
+//    assertThat(issue.effortToFix()).isEqualTo(1.2d);
+//    assertThat(issue.debt()).isEqualTo(Duration.create(28800L));
+//    assertThat(issue.actionPlanKey()).isEqualTo("BCDE");
+//    assertThat(issue.status()).isEqualTo(Issue.STATUS_CLOSED);
+//    assertThat(issue.resolution()).isEqualTo(Issue.RESOLUTION_FIXED);
+//    assertThat(issue.reporter()).isEqualTo("simon");
+//    assertThat(issue.assignee()).isEqualTo("julien");
+//    assertThat(issue.authorLogin()).isEqualTo("steph");
+//    assertThat(issue.checksum()).isEqualTo("c7b5db46591806455cf082bb348631e8");
+//    assertThat(issue.isNew()).isTrue();
+//    assertThat(issue.isBeingClosed()).isTrue();
+//    assertThat(issue.isOnDisabledRule()).isTrue();
+//    assertThat(issue.isChanged()).isTrue();
+//    assertThat(issue.mustSendNotifications()).isTrue();
+//    assertThat(issue.creationDate()).isEqualTo(new SimpleDateFormat("yyyy-MM-dd").parse("2013-08-19"));
+//    assertThat(issue.updateDate()).isEqualTo(new SimpleDateFormat("yyyy-MM-dd").parse("2013-08-20"));
+//    assertThat(issue.closeDate()).isEqualTo(new SimpleDateFormat("yyyy-MM-dd").parse("2013-08-21"));
+//    assertThat(issue.selectedAt()).isEqualTo(1400000000000L);
+//  }
+//
+//  @Test
+//  public void set_empty_dates() {
+//    issue
+//      .setCreationDate(null)
+//      .setUpdateDate(null)
+//      .setCloseDate(null)
+//      .setSelectedAt(null);
+//
+//    assertThat(issue.creationDate()).isNull();
+//    assertThat(issue.updateDate()).isNull();
+//    assertThat(issue.closeDate()).isNull();
+//    assertThat(issue.selectedAt()).isNull();
+//  }
+//
+//  @Test
+//  public void test_attributes() throws Exception {
+//    assertThat(issue.attribute("foo")).isNull();
+//    issue.setAttribute("foo", "bar");
+//    assertThat(issue.attribute("foo")).isEqualTo("bar");
+//    issue.setAttribute("foo", "newbar");
+//    assertThat(issue.attribute("foo")).isEqualTo("newbar");
+//    issue.setAttribute("foo", null);
+//    assertThat(issue.attribute("foo")).isNull();
+//  }
+//
+//  @Test
+//  public void setAttributes_should_not_clear_existing_values() {
+//    issue.setAttributes(ImmutableMap.of("1", "one"));
+//    assertThat(issue.attribute("1")).isEqualTo("one");
+//
+//    issue.setAttributes(ImmutableMap.of("2", "two"));
+//    assertThat(issue.attributes()).containsOnly(entry("1", "one"), entry("2", "two"));
+//
+//    issue.setAttributes(null);
+//    assertThat(issue.attributes()).containsOnly(entry("1", "one"), entry("2", "two"));
+//  }
+//
+//  @Test
+//  public void fail_on_empty_status() {
+//    try {
+//      issue.setStatus("");
+//      fail();
+//    } catch (IllegalArgumentException e) {
+//      assertThat(e).hasMessage("Status must be set");
+//    }
+//  }
+//
+//  @Test
+//  public void fail_on_bad_severity() {
+//    try {
+//      issue.setSeverity("FOO");
+//      fail();
+//    } catch (IllegalArgumentException e) {
+//      assertThat(e).hasMessage("Not a valid severity: FOO");
+//    }
+//  }
+//
+//  @Test
+//  public void message_should_be_abbreviated_if_too_long() {
+//    issue.setMessage(StringUtils.repeat("a", 5000));
+//    assertThat(issue.message()).hasSize(4000);
+//  }
+//
+//  @Test
+//  public void message_should_be_trimmed() {
+//    issue.setMessage("    foo     ");
+//    assertThat(issue.message()).isEqualTo("foo");
+//  }
+//
+//  @Test
+//  public void message_could_be_null() {
+//    issue.setMessage(null);
+//    assertThat(issue.message()).isNull();
+//  }
+//
+//  @Test
+//  public void test_nullable_fields() throws Exception {
+//    issue.setEffortToFix(null).setSeverity(null).setLine(null);
+//    assertThat(issue.effortToFix()).isNull();
+//    assertThat(issue.severity()).isNull();
+//    assertThat(issue.line()).isNull();
+//  }
+//
+//  @Test
+//  public void test_equals_and_hashCode() throws Exception {
+//    DefaultIssue a1 = new DefaultIssue().setKey("AAA");
+//    DefaultIssue a2 = new DefaultIssue().setKey("AAA");
+//    DefaultIssue b = new DefaultIssue().setKey("BBB");
+//    assertThat(a1).isEqualTo(a1);
+//    assertThat(a1).isEqualTo(a2);
+//    assertThat(a1).isNotEqualTo(b);
+//    assertThat(a1.hashCode()).isEqualTo(a1.hashCode());
+//  }
+//
+//  @Test
+//  public void comments_should_not_be_modifiable() {
+//    DefaultIssue issue = new DefaultIssue().setKey("AAA");
+//
+//    List<IssueComment> comments = issue.comments();
+//    assertThat(comments).isEmpty();
+//
+//    try {
+//      comments.add(new DefaultIssueComment());
+//      fail();
+//    } catch (UnsupportedOperationException e) {
+//      // ok
+//    } catch (Exception e) {
+//      fail("Unexpected exception: " + e);
+//    }
+//  }
+//
+//  @Test
+//  public void all_changes_contain_current_change() {
+//    IssueChangeContext issueChangeContext = mock(IssueChangeContext.class);
+//    DefaultIssue issue = new DefaultIssue().setKey("AAA").setFieldChange(issueChangeContext, "actionPlan", "1.0", "1.1");
+//
+//    assertThat(issue.changes()).hasSize(1);
+//  }
+//}
index 3de9680e8d0706abeac9110b7ddca68d9215cc95..031b3e9dcb7a3fbcb3baf05caa0d0cff1a510311 100644 (file)
  * 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.issue.internal;
-
-import org.junit.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class FieldDiffsTest {
-
-  FieldDiffs diffs = new FieldDiffs();
-
-  @Test
-  public void diffs_should_be_empty_by_default() {
-    assertThat(diffs.diffs()).isEmpty();
-  }
-
-  @Test
-  public void test_diff() throws Exception {
-    diffs.setDiff("severity", "BLOCKER", "INFO");
-    diffs.setDiff("resolution", "OPEN", "FIXED");
-
-    assertThat(diffs.diffs()).hasSize(2);
-
-    FieldDiffs.Diff diff = diffs.diffs().get("severity");
-    assertThat(diff.oldValue()).isEqualTo("BLOCKER");
-    assertThat(diff.newValue()).isEqualTo("INFO");
-
-    diff = diffs.diffs().get("resolution");
-    assertThat(diff.oldValue()).isEqualTo("OPEN");
-    assertThat(diff.newValue()).isEqualTo("FIXED");
-  }
-
-  @Test
-  public void diff_with_long_values() {
-    diffs.setDiff("technicalDebt", 50l, "100");
-
-    FieldDiffs.Diff diff = diffs.diffs().get("technicalDebt");
-    assertThat(diff.oldValueLong()).isEqualTo(50l);
-    assertThat(diff.newValueLong()).isEqualTo(100l);
-  }
-
-  @Test
-  public void diff_with_empty_long_values() {
-    diffs.setDiff("technicalDebt", null, "");
-
-    FieldDiffs.Diff diff = diffs.diffs().get("technicalDebt");
-    assertThat(diff.oldValueLong()).isNull();
-    assertThat(diff.newValueLong()).isNull();
-  }
-
-  @Test
-  public void test_diff_by_key() throws Exception {
-    diffs.setDiff("severity", "BLOCKER", "INFO");
-    diffs.setDiff("resolution", "OPEN", "FIXED");
-
-    assertThat(diffs.diffs()).hasSize(2);
-
-    FieldDiffs.Diff diff = diffs.diffs().get("severity");
-    assertThat(diff.oldValue()).isEqualTo("BLOCKER");
-    assertThat(diff.newValue()).isEqualTo("INFO");
-
-    diff = diffs.diffs().get("resolution");
-    assertThat(diff.oldValue()).isEqualTo("OPEN");
-    assertThat(diff.newValue()).isEqualTo("FIXED");
-  }
-
-  @Test
-  public void should_keep_old_value() {
-    diffs.setDiff("severity", "BLOCKER", "INFO");
-    diffs.setDiff("severity", null, "MAJOR");
-    FieldDiffs.Diff diff = diffs.diffs().get("severity");
-    assertThat(diff.oldValue()).isEqualTo("BLOCKER");
-    assertThat(diff.newValue()).isEqualTo("MAJOR");
-  }
-
-  @Test
-  public void test_toString() throws Exception {
-    diffs.setDiff("severity", "BLOCKER", "INFO");
-    diffs.setDiff("resolution", "OPEN", "FIXED");
-
-    assertThat(diffs.toString()).isEqualTo("severity=BLOCKER|INFO,resolution=OPEN|FIXED");
-  }
-
-  @Test
-  public void test_toString_with_null_values() throws Exception {
-    diffs.setDiff("severity", null, "INFO");
-    diffs.setDiff("assignee", "user1", null);
-
-    assertThat(diffs.toString()).isEqualTo("severity=INFO,assignee=");
-  }
-
-  @Test
-  public void test_parse() throws Exception {
-    diffs = FieldDiffs.parse("severity=BLOCKER|INFO,resolution=OPEN|FIXED");
-    assertThat(diffs.diffs()).hasSize(2);
-
-    FieldDiffs.Diff diff = diffs.diffs().get("severity");
-    assertThat(diff.oldValue()).isEqualTo("BLOCKER");
-    assertThat(diff.newValue()).isEqualTo("INFO");
-
-    diff = diffs.diffs().get("resolution");
-    assertThat(diff.oldValue()).isEqualTo("OPEN");
-    assertThat(diff.newValue()).isEqualTo("FIXED");
-  }
-
-  @Test
-  public void test_parse_empty_values() throws Exception {
-    diffs = FieldDiffs.parse("severity=INFO,resolution=");
-    assertThat(diffs.diffs()).hasSize(2);
-
-    FieldDiffs.Diff diff = diffs.diffs().get("severity");
-    assertThat(diff.oldValue()).isEqualTo("");
-    assertThat(diff.newValue()).isEqualTo("INFO");
-
-    diff = diffs.diffs().get("resolution");
-    assertThat(diff.oldValue()).isEqualTo("");
-    assertThat(diff.newValue()).isEqualTo("");
-  }
-
-  @Test
-  public void test_parse_null() throws Exception {
-    diffs = FieldDiffs.parse(null);
-    assertThat(diffs.diffs()).isEmpty();
-  }
-
-  @Test
-  public void test_parse_empty() throws Exception {
-    diffs = FieldDiffs.parse("");
-    assertThat(diffs.diffs()).isEmpty();
-  }
-}
+///*
+// * 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.issue.internal;
+//
+//import org.junit.Test;
+//
+//import static org.assertj.core.api.Assertions.assertThat;
+//
+//public class FieldDiffsTest {
+//
+//  FieldDiffs diffs = new FieldDiffs();
+//
+//  @Test
+//  public void diffs_should_be_empty_by_default() {
+//    assertThat(diffs.diffs()).isEmpty();
+//  }
+//
+//  @Test
+//  public void test_diff() throws Exception {
+//    diffs.setDiff("severity", "BLOCKER", "INFO");
+//    diffs.setDiff("resolution", "OPEN", "FIXED");
+//
+//    assertThat(diffs.diffs()).hasSize(2);
+//
+//    FieldDiffs.Diff diff = diffs.diffs().get("severity");
+//    assertThat(diff.oldValue()).isEqualTo("BLOCKER");
+//    assertThat(diff.newValue()).isEqualTo("INFO");
+//
+//    diff = diffs.diffs().get("resolution");
+//    assertThat(diff.oldValue()).isEqualTo("OPEN");
+//    assertThat(diff.newValue()).isEqualTo("FIXED");
+//  }
+//
+//  @Test
+//  public void diff_with_long_values() {
+//    diffs.setDiff("technicalDebt", 50l, "100");
+//
+//    FieldDiffs.Diff diff = diffs.diffs().get("technicalDebt");
+//    assertThat(diff.oldValueLong()).isEqualTo(50l);
+//    assertThat(diff.newValueLong()).isEqualTo(100l);
+//  }
+//
+//  @Test
+//  public void diff_with_empty_long_values() {
+//    diffs.setDiff("technicalDebt", null, "");
+//
+//    FieldDiffs.Diff diff = diffs.diffs().get("technicalDebt");
+//    assertThat(diff.oldValueLong()).isNull();
+//    assertThat(diff.newValueLong()).isNull();
+//  }
+//
+//  @Test
+//  public void test_diff_by_key() throws Exception {
+//    diffs.setDiff("severity", "BLOCKER", "INFO");
+//    diffs.setDiff("resolution", "OPEN", "FIXED");
+//
+//    assertThat(diffs.diffs()).hasSize(2);
+//
+//    FieldDiffs.Diff diff = diffs.diffs().get("severity");
+//    assertThat(diff.oldValue()).isEqualTo("BLOCKER");
+//    assertThat(diff.newValue()).isEqualTo("INFO");
+//
+//    diff = diffs.diffs().get("resolution");
+//    assertThat(diff.oldValue()).isEqualTo("OPEN");
+//    assertThat(diff.newValue()).isEqualTo("FIXED");
+//  }
+//
+//  @Test
+//  public void should_keep_old_value() {
+//    diffs.setDiff("severity", "BLOCKER", "INFO");
+//    diffs.setDiff("severity", null, "MAJOR");
+//    FieldDiffs.Diff diff = diffs.diffs().get("severity");
+//    assertThat(diff.oldValue()).isEqualTo("BLOCKER");
+//    assertThat(diff.newValue()).isEqualTo("MAJOR");
+//  }
+//
+//  @Test
+//  public void test_toString() throws Exception {
+//    diffs.setDiff("severity", "BLOCKER", "INFO");
+//    diffs.setDiff("resolution", "OPEN", "FIXED");
+//
+//    assertThat(diffs.toString()).isEqualTo("severity=BLOCKER|INFO,resolution=OPEN|FIXED");
+//  }
+//
+//  @Test
+//  public void test_toString_with_null_values() throws Exception {
+//    diffs.setDiff("severity", null, "INFO");
+//    diffs.setDiff("assignee", "user1", null);
+//
+//    assertThat(diffs.toString()).isEqualTo("severity=INFO,assignee=");
+//  }
+//
+//  @Test
+//  public void test_parse() throws Exception {
+//    diffs = FieldDiffs.parse("severity=BLOCKER|INFO,resolution=OPEN|FIXED");
+//    assertThat(diffs.diffs()).hasSize(2);
+//
+//    FieldDiffs.Diff diff = diffs.diffs().get("severity");
+//    assertThat(diff.oldValue()).isEqualTo("BLOCKER");
+//    assertThat(diff.newValue()).isEqualTo("INFO");
+//
+//    diff = diffs.diffs().get("resolution");
+//    assertThat(diff.oldValue()).isEqualTo("OPEN");
+//    assertThat(diff.newValue()).isEqualTo("FIXED");
+//  }
+//
+//  @Test
+//  public void test_parse_empty_values() throws Exception {
+//    diffs = FieldDiffs.parse("severity=INFO,resolution=");
+//    assertThat(diffs.diffs()).hasSize(2);
+//
+//    FieldDiffs.Diff diff = diffs.diffs().get("severity");
+//    assertThat(diff.oldValue()).isEqualTo("");
+//    assertThat(diff.newValue()).isEqualTo("INFO");
+//
+//    diff = diffs.diffs().get("resolution");
+//    assertThat(diff.oldValue()).isEqualTo("");
+//    assertThat(diff.newValue()).isEqualTo("");
+//  }
+//
+//  @Test
+//  public void test_parse_null() throws Exception {
+//    diffs = FieldDiffs.parse(null);
+//    assertThat(diffs.diffs()).isEmpty();
+//  }
+//
+//  @Test
+//  public void test_parse_empty() throws Exception {
+//    diffs = FieldDiffs.parse("");
+//    assertThat(diffs.diffs()).isEmpty();
+//  }
+//}