/*
* SonarQube
* Copyright (C) 2009-2017 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program 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.
*
* This program 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.scanner.issue.tracking;
import org.sonar.api.batch.ScannerSide;
import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.batch.fs.internal.DefaultInputComponent;
import org.sonar.core.util.CloseableIterator;
import org.sonar.scanner.ProjectAnalysisInfo;
import org.sonar.scanner.issue.IssueCache;
import org.sonar.scanner.issue.IssueTransformer;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.protocol.output.ScannerReportReader;
import org.sonar.scanner.report.ReportPublisher;
import org.sonar.scanner.scan.filesystem.InputComponentStore;
import org.sonar.scanner.util.ProgressReport;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
@ScannerSide
public class IssueTransition {
private final IssueCache issueCache;
private final InputComponentStore inputComponentStore;
private final ReportPublisher reportPublisher;
private final Date analysisDate;
@Nullable
private final LocalIssueTracking localIssueTracking;
public IssueTransition(InputComponentStore inputComponentCache, ProjectAnalysisInfo projectAnalysisInfo, IssueCache issueCache, ReportPublisher reportPublisher,
@Nullable LocalIssueTracking localIssueTracking) {
this.inputComponentStore = inputComponentCache;
this.issueCache = issueCache;
this.reportPublisher = reportPublisher;
this.localIssueTracking = localIssueTracking;
this.analysisDate = projectAnalysisInfo.analysisDate();
}
public IssueTransition(InputComponentStore inputComponentCache, ProjectAnalysisInfo projectAnalysisInfo, IssueCache issueCache, ReportPublisher reportPublisher) {
this(inputComponentCache, projectAnalysisInfo, issueCache, reportPublisher, null);
}
public void execute() {
if (localIssueTracking != null) {
localIssueTracking.init();
}
ScannerReportReader reader = new ScannerReportReader(reportPublisher.getReportDir());
int nbComponents = inputComponentStore.all().size();
if (nbComponents == 0) {
return;
}
ProgressReport progressReport = new ProgressReport("issue-tracking-report", TimeUnit.SECONDS.toMillis(10));
progressReport.start("Performing issue tracking");
int count = 0;
try {
for (InputComponent component : inputComponentStore.all()) {
trackIssues(reader, (DefaultInputComponent) component);
count++;
progressReport.message(count + "/" + nbComponents + " components tracked");
}
} finally {
progressReport.stop(count + "/" + nbComponents + " components tracked");
}
}
public void trackIssues(ScannerReportReader reader, DefaultInputComponent component) {
// raw issues = all the issues created by rule engines during this module scan and not excluded by filters
List<ScannerReport.Issue> rawIssues = new LinkedList<>();
try (CloseableIterator<ScannerReport.Issue> it = reader.readComponentIssues(component.batchId())) {
while (it.hasNext()) {
rawIssues.add(it.next());
}
} catch (Exception e) {
throw new IllegalStateException("Can't read issues for " + component.key(), e);
}
List<TrackedIssue> trackedIssues;
if (localIssueTracking != null) {
trackedIssues = localIssueTracking.trackIssues(component, rawIssues, analysisDate);
} else {
trackedIssues = doTransition(rawIssues, component);
}
for (TrackedIssue issue : trackedIssues) {
issueCache.put(issue);
}
}
private static List<TrackedIssue> doTransition(List<ScannerReport.Issue> rawIssues, InputComponent component) {
List<TrackedIssue> issues = new ArrayList<>(rawIssues.size());
for (ScannerReport.Issue issue : rawIssues) {
issues.add(IssueTransformer.toTrackedIssue(component, issue, null));
}
return issues;
}
}