This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch camel-2.x
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/camel-2.x by this push:
new 82f6ed6 CAMEL-13345 - added option to generate jacocoXml report to
sonarQube (#2835)
82f6ed6 is described below
commit 82f6ed6f2b9873bad1796d4de5c686b03245a928
Author: simonlood <[email protected]>
AuthorDate: Fri Apr 12 11:44:35 2019 +0200
CAMEL-13345 - added option to generate jacocoXml report to sonarQube (#2835)
* CAMEL-13345 added option to generate jacocoXml report to sonarQube
* updated based on feedback
* CAMEL-13345: Added option to turn on/off xmlReportGeneration, fixed
checkstyle errors
* camel-13345: added documentation
---
.../src/main/docs/camel-maven-plugin.adoc | 12 ++
.../org/apache/camel/maven/RouteCoverageMojo.java | 156 +++++++++++++++++++--
2 files changed, 160 insertions(+), 8 deletions(-)
diff --git
a/tooling/maven/camel-maven-plugin/src/main/docs/camel-maven-plugin.adoc
b/tooling/maven/camel-maven-plugin/src/main/docs/camel-maven-plugin.adoc
index 66dd1ed..6e19cfc 100644
--- a/tooling/maven/camel-maven-plugin/src/main/docs/camel-maven-plugin.adoc
+++ b/tooling/maven/camel-maven-plugin/src/main/docs/camel-maven-plugin.adoc
@@ -426,6 +426,17 @@ Coverage: 4 out of 5 (80.0%)
Here we can see that the 2nd last line with `to` has `0` in the count column,
and therefore is not covered.
We can also see that this is one line 34 in the source code file, which is in
the `my-camel.xml` XML file.
+=== Make SonarQube pick up camel-route-coverage
+
+To allow sonarQube to show route-coverage in camel-routes you need to enable
`generateJacocoXmlReport`
+(see options below) and tell sonarRunner to pick up the resulting xml-files.
When using the sonar-maven-plugin
+this is done by setting the following properties in your `pom.xml`
+
+----
+<sonar.sources>src/main</sonar.sources>
+<sonar.coverage.jacoco.xmlReportPaths>target/site/jacoco/jacoco.xml,target/site/jacoco/xmlJacoco.xml</sonar.coverage.jacoco.xmlReportPaths>
+----
+
=== Options
The maven plugin *coverage* goal supports the following options which can be
configured from the command line (use `-D` syntax),
@@ -443,5 +454,6 @@ The maven plugin *coverage* goal supports the following
options which can be con
By using route id's then its safer to match the route cover data with the
route source code.
Anonymous routes are less safe to use for route coverage as its harder to
know exactly which route
that was tested corresponds to which of the routes from the source code.
+| generateJacocoXmlReport | false | *Camel 2.24* Whether to generate a
coverage-report in jacocoXml-format, when enabled it will generate a file:
`target/site/jacoco/xmlJacoco.xml`
|===
diff --git
a/tooling/maven/camel-maven-plugin/src/main/java/org/apache/camel/maven/RouteCoverageMojo.java
b/tooling/maven/camel-maven-plugin/src/main/java/org/apache/camel/maven/RouteCoverageMojo.java
index 0cb6c00..c2e6979 100644
---
a/tooling/maven/camel-maven-plugin/src/main/java/org/apache/camel/maven/RouteCoverageMojo.java
+++
b/tooling/maven/camel-maven-plugin/src/main/java/org/apache/camel/maven/RouteCoverageMojo.java
@@ -30,8 +30,22 @@ import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.regex.Pattern;
import java.util.stream.Collectors;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
import edu.emory.mathcs.backport.java.util.Collections;
import org.apache.camel.maven.helper.EndpointHelper;
import org.apache.camel.maven.model.RouteCoverageNode;
@@ -85,7 +99,15 @@ public class RouteCoverageMojo extends AbstractExecMojo {
* default-value="100"
*/
private byte coverageThreshold = 100;
-
+
+ /**
+ * Whether to generate xml-file or not
+ *
+ * @parameter property="camel.generateJacocoXmlReport"
+ * default-value="false"
+ */
+ private boolean generateJacocoXmlReport;
+
/**
* Whether to include test source code
*
@@ -203,12 +225,41 @@ public class RouteCoverageMojo extends AbstractExecMojo {
List<CamelNodeDetails> routeIdTrees = routeTrees.stream().filter(t ->
t.getRouteId() != null).collect(Collectors.toList());
List<CamelNodeDetails> anonymousRouteTrees =
routeTrees.stream().filter(t -> t.getRouteId() ==
null).collect(Collectors.toList());
-
+ Document document = null;
+ File file = null;
+ Element report = null;
+
+ if (generateJacocoXmlReport) {
+ try{
+ // creates the folder for the xml.file
+ file = (new File(project.getBasedir() +
"/target/site/jacoco"));
+ if (!file.exists()) {
+ file.mkdirs();
+ }
+ document = createDocument();
+
+ // report tag
+ report = document.createElement("report");
+ createAttrString(document, report, "name", "Camel Xml");
+ document.appendChild(report);
+ } catch (Exception e) {
+ getLog().info("Error creating xml-document");
+ }
+ }
// favor strict matching on route ids
for (CamelNodeDetails t : routeIdTrees) {
String routeId = t.getRouteId();
String fileName = stripRootPath(asRelativeFile(t.getFileName()));
-
+ String sourceFileName = (new File(fileName)).getName();
+ String packageName = (new File(fileName)).getParent();
+
+ Element pack = null;
+ if (generateJacocoXmlReport) {
+ // package tag
+ pack = document.createElement("package");
+ createAttrString(document, pack, "name", packageName);
+ report.appendChild(pack);
+ }
// grab dump data for the route
try {
List<CoverageData> coverageData =
RouteCoverageHelper.parseDumpRouteCoverageByRouteId("target/camel-route-coverage",
routeId);
@@ -219,14 +270,28 @@ public class RouteCoverageMojo extends AbstractExecMojo {
List<RouteCoverageNode> coverage =
gatherRouteCoverageSummary(Collections.singletonList(t), coverageData);
String out = templateCoverageData(fileName, routeId,
coverage, notCovered);
getLog().info("Route coverage summary:\n\n" + out);
- getLog().info("");
+ getLog().info("");
+
+ if (generateJacocoXmlReport) {
+ // sourcefile tag
+ appendSourcefileNode(document, sourceFileName, pack,
coverage);
+ }
}
} catch (Exception e) {
throw new MojoExecutionException("Error during gathering route
coverage data for route: " + routeId, e);
}
- }
-
+ }
+
+ if (generateJacocoXmlReport) {
+ try {
+ createXmlFile(document, file);
+ getLog().info("Generating xml-file");
+ } catch (Exception e) {
+ getLog().info("Error creating xml-file");
+ }
+ }
+
if (anonymousRoutes && !anonymousRouteTrees.isEmpty()) {
// grab dump data for the route
try {
@@ -258,9 +323,11 @@ public class RouteCoverageMojo extends AbstractExecMojo {
String out = templateCoverageData(fileName, null,
coverage, notCovered);
getLog().info("Route coverage summary:\n\n" + out);
getLog().info("");
+
}
}
- }
+ }
+
} catch (Exception e) {
throw new MojoExecutionException("Error during gathering route
coverage data", e);
}
@@ -271,6 +338,41 @@ public class RouteCoverageMojo extends AbstractExecMojo {
}
}
+ private void appendSourcefileNode(Document document, String
sourceFileName, Element pack,
+ List<RouteCoverageNode> coverage) {
+ Element sourcefile = document.createElement("sourcefile");
+ createAttrString(document, sourcefile, "name", sourceFileName);
+ pack.appendChild(sourcefile);
+
+ int covered = 0, missed = 0;
+ for (RouteCoverageNode node : coverage) {
+ int missedCount = 0;
+ if (node.getCount() > 0) {
+ covered++;
+ }
+ else {
+ missedCount ++;
+ missed ++;
+ }
+ // line tag
+ Element line = document.createElement("line");
+ createAttrInt(document, line, "nr", node.getLineNumber());
+ createAttrInt(document, line, "mi", missedCount);
+ createAttrInt(document, line, "ci", node.getCount());
+ // provides no useful information, needed to be read by
sonarQube
+ createAttrInt(document, line, "mb", 0);
+ createAttrInt(document, line, "cb", 0);
+ sourcefile.appendChild(line);
+ }
+
+ // counter tag
+ Element counter = document.createElement("counter");
+ createAttrString(document, counter, "type", "LINE");
+ createAttrInt(document, counter, "missed", missed);
+ createAttrInt(document, counter, "covered", covered);
+ sourcefile.appendChild(counter);
+ }
+
private Map<String, List<CamelNodeDetails>>
groupAnonymousRoutesByClassName(List<CamelNodeDetails> anonymousRouteTrees) {
Map<String, List<CamelNodeDetails>> answer = new LinkedHashMap<>();
@@ -328,7 +430,8 @@ public class RouteCoverageMojo extends AbstractExecMojo {
private String templateCoverageData(String fileName, String routeId,
List<RouteCoverageNode> model, AtomicInteger notCovered) throws
MojoExecutionException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
PrintStream sw = new PrintStream(bos);
-
+
+
if (model.get(0).getClassName() != null) {
sw.println("Class:\t" + model.get(0).getClassName());
} else {
@@ -341,11 +444,13 @@ public class RouteCoverageMojo extends AbstractExecMojo {
sw.println(String.format("%8s %8s %s", "Line #", "Count",
"Route"));
sw.println(String.format("%8s %8s %s", "------", "-----",
"-----"));
+
int covered = 0;
for (RouteCoverageNode node : model) {
if (node.getCount() > 0) {
covered++;
}
+
String pad = padString(node.getLevel());
sw.println(String.format("%8s %8s %s", node.getLineNumber(),
node.getCount(), pad + node.getName()));
}
@@ -366,7 +471,42 @@ public class RouteCoverageMojo extends AbstractExecMojo {
sw.println();
return bos.toString();
+ }
+
+ private static Attr createAttrInt(Document doc, Element e, String name,
Integer value) {
+ Attr a = doc.createAttribute(name);
+ a.setValue(value.toString());
+ e.setAttributeNode(a);
+
+ return a;
+ }
+
+ private static Attr createAttrString(Document doc, Element e, String name,
String value) {
+ Attr a = doc.createAttribute(name);
+ a.setValue(value);
+ e.setAttributeNode(a);
+
+ return a;
+ }
+
+ private static Document createDocument() throws
ParserConfigurationException {
+ Document document = null;
+ DocumentBuilderFactory documentFactory =
DocumentBuilderFactory.newInstance();
+ DocumentBuilder documentBuilder = documentFactory.newDocumentBuilder();
+ document = documentBuilder.newDocument();
+
+ return document;
}
+
+ private static void createXmlFile(Document document, File file) throws
TransformerException {
+ String xmlFilePath = file.toString() + "/xmlJacoco.xml";
+ TransformerFactory transformerFactory =
TransformerFactory.newInstance();
+ Transformer transformer = transformerFactory.newTransformer();
+ DOMSource domSource = new DOMSource(document);
+ StreamResult streamResult = new StreamResult(new File(xmlFilePath));
+
+ transformer.transform(domSource, streamResult);
+ }
private static List<RouteCoverageNode>
gatherRouteCoverageSummary(List<CamelNodeDetails> route, List<CoverageData>
coverageData) {
List<RouteCoverageNode> answer = new ArrayList<>();