Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lizard integration #90

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 14 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ Find below an example of an iOS SonarQube dashboard:
<img src="sample/screen%20shot%20SonarQube%20dashboard.png" alt="Example iOS SonarQube dashboard" width="80%"/>
</p>

###Features
### Features

- [ ] Complexity
- [x] Complexity
- [ ] Design
- [x] Documentation
- [x] Duplications
Expand All @@ -24,12 +24,12 @@ Find below an example of an iOS SonarQube dashboard:

For more details, see the list of [SonarQube metrics](https://github.com/octo-technology/sonar-objective-c/wiki/Features) implemented or pending.

###Compatibility
### Compatibility

- Use 0.3.x releases for SonarQube < 4.3
- Use 0.4.x releases for SonarQube >= 4.3 (4.x and 5.x)

###Download
### Download

The latest version is the 0.4.0 and it's available [here](http://bit.ly/18A7OkE).
The latest SonarQube 3.x release is the 0.3.1, and it's available [here](http://bit.ly/1fSwd5I).
Expand All @@ -38,51 +38,53 @@ You can also download the latest build of the plugin from [Cloudbees](https://rf

In the worst case, the Maven repository with all snapshots and releases is available here: http://repository-rfelden.forge.cloudbees.com/

###Prerequisites
### Prerequisites

- a Mac with Xcode...
- [SonarQube](http://docs.codehaus.org/display/SONAR/Setup+and+Upgrade) and [SonarQube Runner](http://docs.codehaus.org/display/SONAR/Installing+and+Configuring+SonarQube+Runner) installed ([HomeBrew](http://brew.sh) installed and ```brew install sonar-runner```)
- [xctool](https://github.com/facebook/xctool) ([HomeBrew](http://brew.sh) installed and ```brew install xctool```). If you are using Xcode 6, make sure to update xctool (```brew upgrade xctool```) to a version > 0.2.2.
- [OCLint](http://docs.oclint.org/en/dev/intro/installation.html) installed. Version 0.8.1 recommended ([HomeBrew](http://brew.sh) installed and ```brew install https://gist.githubusercontent.com/TonyAnhTran/e1522b93853c5a456b74/raw/157549c7a77261e906fb88bc5606afd8bd727a73/oclint.rb```).
- [gcovr](http://gcovr.com) installed
- [lizard](https://github.com/terryyin/lizard) installed

###Installation (once for all your Objective-C projects)
### Installation (once for all your Objective-C projects)
- Install [the plugin](http://bit.ly/18A7OkE) through the Update Center (of SonarQube) or download it into the $SONARQUBE_HOME/extensions/plugins directory
- Copy [run-sonar.sh](https://rawgithub.com/octo-technology/sonar-objective-c/master/src/main/shell/run-sonar.sh) somewhere in your PATH
- Restart the SonarQube server.

###Configuration (once per project)
### Configuration (once per project)
- Copy [sonar-project.properties](https://rawgithub.com/octo-technology/sonar-objective-c/master/sample/sonar-project.properties) in your Xcode project root folder (along your .xcodeproj file)
- Edit the *sonar-project.properties* file to match your Xcode iOS/MacOS project

**The good news is that you don't have to modify your Xcode project to enable SonarQube!**. Ok, there might be one needed modification if you don't have a specific scheme for your test target, but that's all.

###Analysis
### Analysis
- Run the script ```run-sonar.sh``` in your Xcode project root folder
- Enjoy or file an issue!

###Update (once per plugin update)
### Update (once per plugin update)
- Install the [latest plugin](http://bit.ly/18A7OkE) version
- Copy [run-sonar.sh](https://rawgithub.com/octo-technology/sonar-objective-c/master/src/main/shell/run-sonar.sh) somewhere in your PATH

If you still have *run-sonar.sh* file in each of your project (not recommended), you will need to update all those files.

###Credits
### Credits
* **Cyril Picat**
* **Gilles Grousset**
* **Denis Bregeon**
* **François Helg**
* **Romain Felden**
* **Mete Balci**

###History
### History
- v0.4.1 (2015/05): added support for Lizard to implement complexity metrics.
- v0.4.0 (2015/01): support for SonarQube >= 4.3 (4.x & 5.x)
- v0.3.1 (2013/10): fix release
- v0.3 (2013/10): added support for OCUnit tests and test coverage
- v0.2 (2013/10): added OCLint checks as SonarQube violations
- v0.0.1 (2012/09): v0 with basic metrics such as nb lines of code, nb lines of comment, nb of files, duplications

###License
### License

SonarQube Plugin for Objective C is released under the GNU LGPL 3 license:
http://www.gnu.org/licenses/lgpl.txt
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,11 @@
<artifactId>sonar-surefire-plugin</artifactId>
<version>2.7</version>
</dependency>
<dependency>
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<version>1.0.b2</version>
</dependency>

</dependencies>

Expand Down
4 changes: 4 additions & 0 deletions sample/sonar-project.properties
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ sonar.sourceEncoding=UTF-8
# Change it only if you generate the file on your own
# sonar.objectivec.oclint.report=sonar-reports/oclint.xml

# Lizard report generated by run-sonar.sh is stored in sonar-reports/lizard-report.xml
# Change it only if you generate the file on your own
# sonar.objectivec.lizard.report=sonar-reports/lizard-report.xml

# Paths to exclude from coverage report (tests, 3rd party libraries etc.)
# sonar.objectivec.excludedPathsFromCoverage=pattern1,pattern2
sonar.objectivec.excludedPathsFromCoverage=.*Tests.*
Expand Down
11 changes: 9 additions & 2 deletions src/main/java/org/sonar/plugins/objectivec/ObjectiveCPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.sonar.api.Properties;
import org.sonar.api.Property;
import org.sonar.api.SonarPlugin;
import org.sonar.plugins.objectivec.complexity.LizardSensor;
import org.sonar.plugins.objectivec.coverage.CoberturaSensor;
import org.sonar.plugins.objectivec.colorizer.ObjectiveCColorizerFormat;
import org.sonar.plugins.objectivec.core.ObjectiveC;
Expand Down Expand Up @@ -53,11 +54,17 @@ public List<Class<? extends Extension>> getExtensions() {

ObjectiveCSquidSensor.class,
ObjectiveCProfile.class,

SurefireSensor.class,

CoberturaSensor.class,

OCLintRuleRepository.class,
OCLintSensor.class, OCLintProfile.class,
OCLintProfileImporter.class
OCLintSensor.class,
OCLintProfile.class,
OCLintProfileImporter.class,

LizardSensor.class
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,6 @@

public class ObjectiveCSquidSensor implements Sensor {

private final Number[] FUNCTIONS_DISTRIB_BOTTOM_LIMITS = {1, 2, 4, 6, 8, 10, 12, 20, 30};
private final Number[] FILES_DISTRIB_BOTTOM_LIMITS = {0, 5, 10, 20, 30, 60, 90};

private final AnnotationCheckFactory annotationCheckFactory;

private Project project;
Expand Down Expand Up @@ -91,8 +88,12 @@ private void save(Collection<SourceCode> squidSourceFiles) {

File sonarFile = File.fromIOFile(new java.io.File(squidFile.getKey()), project);

saveFilesComplexityDistribution(sonarFile, squidFile);
saveFunctionsComplexityDistribution(sonarFile, squidFile);
/*
* Distribution is saved in the Lizard sensor and therefore it is not possible to save the complexity
* distribution here. The functionality has been moved to LizardParser.
*/
//saveFilesComplexityDistribution(sonarFile, squidFile);
//saveFunctionsComplexityDistribution(sonarFile, squidFile);
saveMeasures(sonarFile, squidFile);
saveViolations(sonarFile, squidFile);
}
Expand All @@ -102,27 +103,18 @@ private void saveMeasures(File sonarFile, SourceFile squidFile) {
context.saveMeasure(sonarFile, CoreMetrics.FILES, squidFile.getDouble(ObjectiveCMetric.FILES));
context.saveMeasure(sonarFile, CoreMetrics.LINES, squidFile.getDouble(ObjectiveCMetric.LINES));
context.saveMeasure(sonarFile, CoreMetrics.NCLOC, squidFile.getDouble(ObjectiveCMetric.LINES_OF_CODE));
context.saveMeasure(sonarFile, CoreMetrics.FUNCTIONS, squidFile.getDouble(ObjectiveCMetric.FUNCTIONS));
/**
* Saving the same measure more than once per file throws exception. That is why
* CoreMetrics.FUNCTIONS and CoreMetrics.COMPLEXITY are not allowed to be saved here. In order for the
* LizardSensor to be able to to its job and save the values for those metrics the functionality has been
* moved to Lizard classes.
*/
//context.saveMeasure(sonarFile, CoreMetrics.FUNCTIONS, squidFile.getDouble(ObjectiveCMetric.FUNCTIONS));
context.saveMeasure(sonarFile, CoreMetrics.STATEMENTS, squidFile.getDouble(ObjectiveCMetric.STATEMENTS));
context.saveMeasure(sonarFile, CoreMetrics.COMPLEXITY, squidFile.getDouble(ObjectiveCMetric.COMPLEXITY));
//context.saveMeasure(sonarFile, CoreMetrics.COMPLEXITY, squidFile.getDouble(ObjectiveCMetric.COMPLEXITY));
context.saveMeasure(sonarFile, CoreMetrics.COMMENT_LINES, squidFile.getDouble(ObjectiveCMetric.COMMENT_LINES));
}

private void saveFunctionsComplexityDistribution(File sonarFile, SourceFile squidFile) {
Collection<SourceCode> squidFunctionsInFile = scanner.getIndex().search(new QueryByParent(squidFile), new QueryByType(SourceFunction.class));
RangeDistributionBuilder complexityDistribution = new RangeDistributionBuilder(CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION, FUNCTIONS_DISTRIB_BOTTOM_LIMITS);
for (SourceCode squidFunction : squidFunctionsInFile) {
complexityDistribution.add(squidFunction.getDouble(ObjectiveCMetric.COMPLEXITY));
}
context.saveMeasure(sonarFile, complexityDistribution.build().setPersistenceMode(PersistenceMode.MEMORY));
}

private void saveFilesComplexityDistribution(File sonarFile, SourceFile squidFile) {
RangeDistributionBuilder complexityDistribution = new RangeDistributionBuilder(CoreMetrics.FILE_COMPLEXITY_DISTRIBUTION, FILES_DISTRIB_BOTTOM_LIMITS);
complexityDistribution.add(squidFile.getDouble(ObjectiveCMetric.COMPLEXITY));
context.saveMeasure(sonarFile, complexityDistribution.build().setPersistenceMode(PersistenceMode.MEMORY));
}

private void saveViolations(File sonarFile, SourceFile squidFile) {
Collection<CheckMessage> messages = squidFile.getCheckMessages();
if (messages != null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Sonar Objective-C Plugin
* Copyright (C) 2012 OCTO Technology
* [email protected]
*
* 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 02
*/
package org.sonar.plugins.objectivec.complexity;

import org.slf4j.LoggerFactory;
import org.sonar.api.batch.SensorContext;
import org.sonar.api.measures.Measure;
import org.sonar.api.resources.Project;

import java.io.File;
import java.util.List;
import java.util.Map;

/**
* This class is used to save the measures created by the lizardReportParser in the sonar database
*
* @author Andres Gil Herrera
* @since 28/05/15.
*/
public class LizardMeasurePersistor {

private Project project;
private SensorContext sensorContext;

public LizardMeasurePersistor(final Project p, final SensorContext c) {
this.project = p;
this.sensorContext = c;
}

/**
*
* @param measures Map containing as key the name of the file and as value a list containing the measures for that file
*/
public void saveMeasures(final Map<String, List<Measure>> measures) {

if (measures == null) {
return;
}

for (Map.Entry<String, List<Measure>> entry : measures.entrySet()) {
final org.sonar.api.resources.File objcfile = org.sonar.api.resources.File.fromIOFile(new File(project.getFileSystem().getBasedir(), entry.getKey()), project);
if (fileExists(sensorContext, objcfile)) {
for (Measure measure : entry.getValue()) {
try {
LoggerFactory.getLogger(getClass()).debug("Save measure {} for file {}", measure.getMetric().getName(), objcfile);
sensorContext.saveMeasure(objcfile, measure);
} catch (Exception e) {
LoggerFactory.getLogger(getClass()).error(" Exception -> {} -> {}", entry.getKey(), measure.getMetric().getName());
}
}
}
}
}

/**
*
* @param context context of the sensor
* @param file file to prove for
* @return true if the resource is indexed and false if not
*/
private boolean fileExists(final SensorContext context,
final org.sonar.api.resources.File file) {
return context.getResource(file) != null;
}
}
Loading