org.sonarlint.cli.analysis.ConnectedSonarLint Maven / Gradle / Ivy
/*
* SonarLint CLI
* Copyright (C) 2016-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.sonarlint.cli.analysis;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.CheckForNull;
import org.sonarlint.cli.config.SonarQubeServer;
import org.sonarlint.cli.report.ReportFactory;
import org.sonarlint.cli.util.Logger;
import org.sonarlint.cli.util.SystemInfo;
import org.sonarsource.sonarlint.core.client.api.common.RuleDetails;
import org.sonarsource.sonarlint.core.client.api.common.analysis.AnalysisResults;
import org.sonarsource.sonarlint.core.client.api.common.analysis.ClientInputFile;
import org.sonarsource.sonarlint.core.client.api.common.analysis.Issue;
import org.sonarsource.sonarlint.core.client.api.connected.ConnectedAnalysisConfiguration;
import org.sonarsource.sonarlint.core.client.api.connected.ConnectedSonarLintEngine;
import org.sonarsource.sonarlint.core.client.api.connected.GlobalStorageStatus;
import org.sonarsource.sonarlint.core.client.api.connected.ModuleStorageStatus;
import org.sonarsource.sonarlint.core.client.api.connected.ServerConfiguration;
import org.sonarsource.sonarlint.core.tracking.CachingIssueTracker;
import org.sonarsource.sonarlint.core.tracking.CachingIssueTrackerImpl;
import org.sonarsource.sonarlint.core.tracking.Console;
import org.sonarsource.sonarlint.core.tracking.InMemoryIssueTrackerCache;
import org.sonarsource.sonarlint.core.tracking.IssueTrackable;
import org.sonarsource.sonarlint.core.tracking.IssueTrackerCache;
import org.sonarsource.sonarlint.core.tracking.ServerIssueTracker;
import org.sonarsource.sonarlint.core.tracking.Trackable;
import static org.sonarsource.sonarlint.core.client.api.util.FileUtils.toSonarQubePath;
public class ConnectedSonarLint extends SonarLint {
private static final Logger LOGGER = Logger.get();
private final ConnectedSonarLintEngine engine;
private final String moduleKey;
private final SonarQubeServer server;
ConnectedSonarLint(ConnectedSonarLintEngine engine, SonarQubeServer server, String moduleKey) {
this.engine = engine;
this.server = server;
this.moduleKey = moduleKey;
}
@Override
public void start(boolean forceUpdate) {
GlobalStorageStatus globalStorageStatus = engine.getGlobalStorageStatus();
if (forceUpdate) {
LOGGER.info("Updating binding..");
update();
} else if (globalStorageStatus == null) {
LOGGER.info("No binding storage found. Updating..");
update();
} else if (globalStorageStatus.isStale()) {
LOGGER.info("Binding storage is stale. Updating..");
update();
} else {
checkModuleStatus();
}
}
private void checkModuleStatus() {
engine.allModulesByKey().keySet().stream()
.filter(key -> key.equals(moduleKey))
.findAny()
.orElseThrow(() -> new IllegalStateException("Project key '" + moduleKey + "' not found in the binding storage. Maybe an update of the storage is needed with '-u'?"));
ModuleStorageStatus moduleStorageStatus = engine.getModuleStorageStatus(moduleKey);
if (moduleStorageStatus == null) {
LOGGER.info("Updating data for module..");
engine.updateModule(getServerConfiguration(server), moduleKey);
LOGGER.info("Module updated");
} else if (moduleStorageStatus.isStale()) {
LOGGER.info("Module's data is stale. Updating..");
engine.updateModule(getServerConfiguration(server), moduleKey);
LOGGER.info("Module updated");
}
}
private void update() {
engine.update(getServerConfiguration(server));
engine.allModulesByKey().keySet().stream()
.filter(key -> key.equals(moduleKey))
.findAny()
.orElseThrow(() -> new IllegalStateException("Project key '" + moduleKey + "' not found in the SonarQube server"));
updateModule();
LOGGER.info("Binding updated");
}
private void updateModule() {
engine.updateModule(getServerConfiguration(server), moduleKey);
}
private static ServerConfiguration getServerConfiguration(SonarQubeServer server) {
ServerConfiguration.Builder serverConfigBuilder = ServerConfiguration.builder()
.url(server.url())
.userAgent("SonarLint CLI " + SystemInfo.getVersion());
String token = server.token();
if (token != null) {
serverConfigBuilder.token(token);
} else {
serverConfigBuilder.credentials(server.login(), server.password());
}
return serverConfigBuilder.build();
}
@Override
protected void doAnalysis(Map properties, ReportFactory reportFactory, List inputFiles, Path baseDirPath) {
Date start = new Date();
ConnectedAnalysisConfiguration config = new ConnectedAnalysisConfiguration(moduleKey, baseDirPath, baseDirPath.resolve(".sonarlint"),
inputFiles, properties);
IssueCollector collector = new IssueCollector();
AnalysisResults result = engine.analyze(config, collector);
engine.downloadServerIssues(getServerConfiguration(server), moduleKey);
Collection trackables = matchAndTrack(baseDirPath, collector.get());
generateReports(trackables, result, reportFactory, baseDirPath.getFileName().toString(), baseDirPath, start);
}
Collection matchAndTrack(Path baseDirPath, Collection issues) {
Collection issuesWithFile = issues.stream().filter(issue -> issue.getInputFile() != null).collect(Collectors.toList());
Collection relativePaths = getRelativePaths(baseDirPath, issuesWithFile);
Map> trackablesPerFile = getTrackablesPerFile(baseDirPath, issuesWithFile);
IssueTrackerCache cache = createCurrentIssueTrackerCache(relativePaths, trackablesPerFile);
return getCurrentTrackables(relativePaths, cache);
}
private IssueTrackerCache createCurrentIssueTrackerCache(Collection relativePaths, Map> trackablesPerFile) {
IssueTrackerCache cache = new InMemoryIssueTrackerCache();
CachingIssueTracker issueTracker = new CachingIssueTrackerImpl(cache);
trackablesPerFile.entrySet().forEach(entry -> issueTracker.matchAndTrackAsNew(entry.getKey(), entry.getValue()));
ServerIssueTracker serverIssueTracker = new ServerIssueTracker(new MyLogger(), new MyConsole(), issueTracker);
serverIssueTracker.update(engine, moduleKey, relativePaths);
return cache;
}
private static List getCurrentTrackables(Collection relativePaths, IssueTrackerCache cache) {
return relativePaths.stream().flatMap(f -> cache.getCurrentTrackables(f).stream())
.filter(trackable -> !trackable.isResolved())
.collect(Collectors.toList());
}
private Map> getTrackablesPerFile(Path baseDirPath, Collection issues) {
return issues.stream()
.collect(Collectors.groupingBy(issue -> getRelativePath(baseDirPath, issue), Collectors.toList()))
.entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
entry -> entry.getValue().stream()
.map(IssueTrackable::new)
.collect(Collectors.toCollection(ArrayList::new))));
}
private Collection getRelativePaths(Path baseDirPath, Collection issues) {
return issues.stream()
.map(issue -> getRelativePath(baseDirPath, issue))
.collect(Collectors.toSet());
}
// note: engine.downloadServerIssues correctly figures out correct moduleKey and fileKey
@CheckForNull
String getRelativePath(Path baseDirPath, Issue issue) {
ClientInputFile inputFile = issue.getInputFile();
if (inputFile == null) {
return null;
}
return toSonarQubePath(baseDirPath.relativize(Paths.get(inputFile.getPath())).toString());
}
@Override
protected RuleDetails getRuleDetails(String ruleKey) {
return engine.getRuleDetails(ruleKey);
}
@Override
public void stop() {
engine.stop(false);
}
private static class MyLogger implements org.sonarsource.sonarlint.core.tracking.Logger {
@Override public void error(String message, Exception e) {
LOGGER.error(message, e);
}
@Override public void debug(String message, Exception e) {
LOGGER.debug(message, e);
}
@Override public void debug(String message) {
LOGGER.debug(message);
}
}
private static class MyConsole implements Console {
@Override public void info(String message) {
LOGGER.info(message);
}
@Override public void error(String message, Throwable t) {
LOGGER.error(message, t);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy