/*
* Copyright 2013 - 2014 Felix Müller
*
* This file is part of CodeQ Invest.
*
* CodeQ Invest is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CodeQ Invest 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with CodeQ Invest. If not, see <http://www.gnu.org/licenses/>.
*/
package org.codeqinvest.quality.analysis;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.codeqinvest.quality.Artefact;
import org.codeqinvest.quality.Project;
import org.codeqinvest.quality.QualityRequirement;
import org.codeqinvest.sonar.MetricCollectorService;
import org.codeqinvest.sonar.ResourceNotFoundException;
import org.codeqinvest.sonar.ResourcesCollectorService;
import org.codeqinvest.sonar.SonarConnectionCheckerService;
import org.sonar.wsclient.services.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* This is a helper service that is only used internally
* to calculate all quality violations for a given project. For that,
* it collects all the necessary data from Sonar. Before it performs
* these steps, it checks for the availability of the given
* Sonar server instance.
*
* @author fmueller
*/
@Slf4j
@Service
class ViolationsCalculatorService {
private final SonarConnectionCheckerService sonarConnectionCheckerService;
private final ResourcesCollectorService resourcesCollectorService;
private final MetricCollectorService metricCollectorService;
@Autowired
public ViolationsCalculatorService(SonarConnectionCheckerService sonarConnectionCheckerService,
ResourcesCollectorService resourcesCollectorService,
MetricCollectorService metricCollectorService) {
this.sonarConnectionCheckerService = sonarConnectionCheckerService;
this.resourcesCollectorService = resourcesCollectorService;
this.metricCollectorService = metricCollectorService;
}
ViolationsAnalysisResult calculateAllViolation(Project project) {
if (!sonarConnectionCheckerService.isReachable(project.getSonarConnectionSettings())) {
return ViolationsAnalysisResult.createFailedAnalysis(Collections.<ViolationOccurence>emptyList(),
"sonar project is not reachable with supplied connection settings: " + project.getSonarConnectionSettings().toString());
}
log.info("Start violation analysis for project {}", project.getName());
Map<String, Artefact> artefactsThatHaveAtLeastOneViolation = Maps.newHashMap();
List<ViolationOccurence> violations = new ArrayList<ViolationOccurence>();
long violationsOfCurrentArtefact = 0;
for (Resource resource : resourcesCollectorService.collectAllResourcesForProject(project.getSonarConnectionSettings())) {
log.info("Analyzing resource {}", resource.getLongName());
violationsOfCurrentArtefact = 0;
for (QualityRequirement qualityRequirement : project.getProfile().getRequirements()) {
final double weightingMetricValue;
final double metricValue;
try {
weightingMetricValue = metricCollectorService.collectMetricForResource(project.getSonarConnectionSettings(),
resource.getKey(), qualityRequirement.getWeightingMetricIdentifier());
metricValue = metricCollectorService.collectMetricForResource(project.getSonarConnectionSettings(),
resource.getKey(), qualityRequirement.getCriteria().getMetricIdentifier());
} catch (ResourceNotFoundException e) {
log.warn("Quality analysis run failed due one resource or metric could not be find in Sonar!", e);
return ViolationsAnalysisResult.createFailedAnalysis(violations, "resource " + resource.getKey()
+ " or metric " + qualityRequirement.getCriteria().getMetricIdentifier() + " not available on Sonar");
}
if (qualityRequirement.isViolated(metricValue)) {
final Artefact artefact;
if (artefactsThatHaveAtLeastOneViolation.containsKey(resource.getKey())) {
artefact = artefactsThatHaveAtLeastOneViolation.get(resource.getKey());
} else {
artefact = new Artefact(resource.getLongName(), resource.getKey());
artefactsThatHaveAtLeastOneViolation.put(resource.getKey(), artefact);
}
log.debug("Create quality violation for artefact {} with violated requirement {}",
artefact.getName(), qualityRequirement.getCriteria());
violations.add(new ViolationOccurence(qualityRequirement, artefact, weightingMetricValue));
violationsOfCurrentArtefact++;
}
}
log.info("Found {} violations at resource {}", violationsOfCurrentArtefact, resource.getLongName());
}
log.info("Successfully analysed project {} and found {} quality violations in {} artefacts",
project.getName(), violations.size(), artefactsThatHaveAtLeastOneViolation.size());
return ViolationsAnalysisResult.createSuccessfulAnalysis(violations);
}
}