How to get jacoco code coverage report in gradle project - gradle

I'm new to Groovy gradle world, I've written small groovy project with all test cases. I'm trying to generate code coverage report using jacoco plugin. But it generates only test report not code coverage report. Please find my jacoco gradle file config. I'm using gradle 4.5 version and Groovy Version: 2.5.0-rc-2 JVM: 1.8.0_171 Vendor: Oracle Corporation OS: Windows 10
What I'm missing here in order to generate jacoco code coverage report in html format.
Appreciated your help in advance!
My jacoco.gradle
apply plugin: "jacoco"
jacoco {
toolVersion = '0.8.1'
}
jacocoTestReport {
group = "reporting"
description = "Generate Jacoco coverage reports after running tests."
reports {
xml.enabled true
html.enabled true
csv.enabled false
html.destination "${buildDir}/jacocoHtml"
}
sourceDirectories = fileTree(dir: 'src/main/myproject')
}
I'm running gradle clean build command to generate build folder under my project repository.

Option 1
Run gradle build jacocoTestReport to generate JaCoCo code coverage report.
Option 2.1
Make tasks dependent in your Gradle scripts:
build.dependsOn jacocoTestReport
and then just run gradle build. JaCoCo report will be generated at each build task execution.
Option 2.2 (proposed by Filip Malczak)
Add to your Gradle scripts:
test.doLast jacocoTestReport.&execute
It works in similar fashion as the previous option, but generates report after every execution of test task. It can be useful if you tend to work by running test instead of build.

My solution is based on Gradle 7.3.2
So, first of all, apply the Jacoco plugin to your gradle project. Below should be in your build.gradle file. If you already have a plugins section, then just add the entry id 'jacoco' in separate line
plugins {
id 'jacoco'
}
This exposes a task named jacocoTestReport and jacocoTestCoverageVerification.
Yo can optionally configure the task to override default values. For e.g. below code will also generate the xml report for coverage, which is mostly needed by SonarQube to analyse the code coverage.
jacocoTestReport {
reports {
xml.required = true
}
}
In order to generate the coverage report you can execute
gralde jacocoTestReport manually
And it will generate reports under
build/reports/jacoco/test folder
However, we would want to execute the coverage report post the gradle test tasks.
So, to achieve this, add below entry in gradle file.
test.finalizedBy(jacocoTestReport)
Now, even if you do gradle test or gradle clean build (test will be implicitly called), you will still see the jacocoTestReport task being executed and reports getting generated.
Below is the jacoco generated report tree structure.
build/reports/jacoco
└── test
├── html
│   ├── index.html
│   ├── jacoco-resources
│   │   ├── branchfc.gif
│   │   ├── branchnc.gif
│   │   ├── branchpc.gif
│   │   ├── bundle.gif
│   │   ├── class.gif
│   │   ├── down.gif
│   │   ├── greenbar.gif
│   │   ├── group.gif
│   │   ├── method.gif
│   │   ├── package.gif
│   │   ├── prettify.css
│   │   ├── prettify.js
│   │   ├── redbar.gif
│   │   ├── report.css
│   │   ├── report.gif
│   │   ├── session.gif
│   │   ├── sort.gif
│   │   ├── sort.js
│   │   ├── source.gif
│   │   └── up.gif
│   └── jacoco-sessions.html
└── jacocoTestReport.xml

Related

Unable to compile code generated using gradle-swagger-generator-plugin

I am facing a problem that code generated using gradle-swagger-generator-plugin is not compiling due to unresolved dependencies.
I have a multimodule gradle project with the following folder structure. parent is the parent project with three subprojects named modules:apis, modules:api-client, and modules:common
.
├── parent
│   ├── build.gradle
│   ├── gbuild
│   ├── gradle
│   │   └── wrapper
│   │   ├── gradle-wrapper.jar
│   │   └── gradle-wrapper.properties
│   ├── gradle.properties
│   ├── gradlew
│   ├── gradlew.bat
│   ├── modules
│   │   ├── apis
│   │   │   ├── build.gradle.kts
│   │   │   ├── gbuild
│   │   │   └── src
│   │   ├── api-client (generated)
│   │   │   ├── README.md
│   │   │   ├── build.gradle
│   │   │   ├── build.sbt
│   │   │   ├── docs
│   │   │   ├── gbuild
│   │   │   ├── git_push.sh
│   │   │   ├── gradle
│   │   │   ├── gradle.properties
│   │   │   ├── gradlew
│   │   │   ├── gradlew.bat
│   │   │   ├── pom.xml
│   │   │   ├── settings.gradle
│   │   │   └── src
│   │   └── common
│   │   ├── build.gradle.kts
│   │   ├── gbuild
│   │   └── src
│   ├── project_version.properties
│   └── settings.gradle.kts
Module :modules:apis is the spring boot REST service for which I want to generate client SDK. Module :modules:api-client is the placeholder project wherein the client code is generated.
Relevant sections from the modules/apis/build.gradle.kts are as given below.
plugins {
// Some plugins omitted for clarity
java
id("org.springframework.boot")
id("io.spring.dependency-management")
id("org.hidetake.swagger.generator") version "2.18.2"
}
dependencies {
// Other dependencies omitted
implementation (Libs.io_swagger_core)
swaggerCodegen("io.swagger.codegen.v3:swagger-codegen-cli:3.0.27")
}
swaggerSources {
create("testcode") {
// File api-spec is already generated and placed at the right location.
setInputFile(file("$projectDir/src/main/resources/swagger/api-spec.json"))
code(
closureOf<org.hidetake.gradle.swagger.generator.GenerateSwaggerCode> {
wipeOutputDir = true
language = "java"
configFile = file("$projectDir/src/main/resources/swagger/api-config.json")
outputDir = file(
"$rootDir/modules/client"
)
}
)
}
}
tasks.named("build") { dependsOn("generateSwaggerCode") }
What works: I can generate client code using gradle clean build in modules\apis and build it using .\gradle.bat clean build or using gradle clean build in modules\api-client.
What does not work: When I build the parent project using .\gradlew build --no-daemon --stacktrace --info in the parent folder, the task :modules:api-client:compileJava fails with compiler errors only for the first run. Compilation fails because gradle fails to resolve dependencies from modules\api-client\build.gradle. Compiler errors can be found in the attached file.
However, subsequent builds using the same command succeed without problem until modules\api-client folder is deleted manually.
Gradle version used by the parent project
\path\to\parent> .\gradlew.bat --version
------------------------------------------------------------
Gradle 6.7
------------------------------------------------------------
Build time: 2020-10-14 16:13:12 UTC
Revision: 312ba9e0f4f8a02d01854d1ed743b79ed996dfd3
Kotlin: 1.3.72
Groovy: 2.5.12
Ant: Apache Ant(TM) version 1.10.8 compiled on May 10 2020
JVM: 1.8.0_181 (Oracle Corporation 25.181-b13)
OS: Windows 10 10.0 amd64
Gradle version used by :modules:api-client subproject
\path\to\parent\modules\api-client> .\gradlew.bat --version
------------------------------------------------------------
Gradle 2.6
------------------------------------------------------------
Build time: 2015-08-10 13:15:06 UTC
Build number: none
Revision: 233bbf8e47c82f72cb898b3e0a96b85d0aad166e
Groovy: 2.3.10
Ant: Apache Ant(TM) version 1.9.3 compiled on December 23 2013
JVM: 1.8.0_181 (Oracle Corporation 25.181-b13)
OS: Windows 10 10.0 amd64
I have tried this with all four combinations of options --build-cache and --no-parallel but got the same result. I am relatively new to gradle and took a wild guess that these two options may be playing role in this problem.
Any help in resolving this issue will be highly appreciated.
Thanks
Anand
You should put the generated classes in the buildDir (since you don't want to modifiy them as they get regenerated at each build) and then you need to add the generated class to your sourceSet.
In your build.gradle.kts add this:
configure<SourceSetContainer> {
named("main") {
java.srcDir("$buildDir/generated/src/main/java")
}
}
With the path being the one you specify in your swagger generation task.
Also on my case I set the dependency on the KotlinCompile task:
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
dependsOn("generateSwaggerCode")
kotlinOptions.jvmTarget = "11"
}
Make sure that this "generateSwaggerCode" does generate the code you need though (./gradlew generateSwaggerCode)

Gradle build: how to set up a multilevel project (3+ levels)?

I am having troubles with seting up 3 level gradle multi-project:
Level_1_Proj
│
├── Level_2_Proj_A
│ │
│ ├── Level_3_Proj_C
│ └── Level_3_Proj_D
│
└── Level_2_Proj_B
│
├── Level_3_Proj_E
└── Level_3_Proj_F
I would like to be able to:
set up dependencies between projects of the same level in the build script, like:
dependencies {
project('Level_2_Proj_A') {
dependencies {
implementation project('Level_2_Proj_B')
}
}
}
also want to be able to build (the subtree) starting the bash command [$gradle build] at any level [then build down the projects' subtree]
I have achieved building from the middle and bottom levels, but I cannot setup the build from the top level. Getting error:
A problem occurred evaluating project ‘Level_2_Proj_A’.
Project with path ‘Level_3_Proj_C’ could not be found in project ‘Level_2_Proj_A’.
Is it possible? If so, how to configure?
Thanks
Alright, here's how I managed to get it working. Given the following directory structure:
.
├── A
│   ├── C
│   │   └── build.gradle.kts
│   ├── D
│   │   └── build.gradle.kts
│   └── build.gradle.kts
├── B
│   ├── E
│   │   └── build.gradle.kts
│   ├── F
│   │   └── build.gradle.kts
│   └── build.gradle.kts
├── build.gradle.kts
├── gradle
│   └── wrapper
│   ├── gradle-wrapper.jar
│   └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle.kts
The settings.gradle.kts has the following content:
rootProject.name = "multi-module-build"
include(":A")
include(":A:C")
include(":A:D")
include(":B")
include(":B:E")
include(":B:F")
Each build.gradle.kts has a call task that prints the name path of the project, e.g.
Inside the C project:
tasks.register("call") {
println(":A:C")
}
Inside the A project:
tasks.register("call") {
dependsOn(":A:C:call")
dependsOn(":A:D:call")
println(":A")
}
tasks["build"].dependsOn(":A:call")
The tasks["build"].dependsOn(":A:call") tells Gradle to invoke :A:call when building. The two dependsOn inside the call definition for A invoke the subproject call tasks.
There is a similar structure available for B.
When running gradle build at root level, this is the output I get:
:A
:B
:A:C
:A:D
:B:E
:B:F
When running gradle build inside the A subproject, I get:
:A
:A:C
:A:D
When running it inside :A:C, I don't get any output because I haven't specified that C's build task should depend on call, but that could easily be done.
Let me know if this doesn't work for you. I've used the Kotlin DSL for gradle, but you're perfectly free to change it to the Groovy variant.

How to display the list of tasks that gradle can currently execute in the console

When I create a gradle project, how do I know which built-in tasks it has?
gradle 5.4
Just create a new java project
I want display the list of tasks in console,but i can't
Assuming you have the following files in your project:
├── build.gradle
├── gradle
│   └── wrapper
│   ├── gradle-wrapper.jar
│   └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
Simply execute ./gradlew tasks --all to list all available tasks that you can execute. gradlew.bat if you're on Windows.

Mimicking Multiproject Execution In Composite Included Build with Gradle Kotlin DSL?

I am simplifying the setup I have to illustrate my issue, but have included structural complexities.
Using Gradle's Kotlin DSL I have a composite build where the root project is empty and the two included builds are both side-by-side multiproject builds with varying structures that make use of "container" projects (aka, empty directories with no build.gradle.kts files) for organization purposes.
.
├── app
│   ├── common
│   │   └── build.gradle.kts
│   ├── js
│   │   └── build.gradle.kts
│   ├── jvm
│   │   └── build.gradle.kts
│   ├── build.gradle.kts
│   └── settings.gradle.kts
├── library
│   ├── core
│   │   ├── common
│   │   │   └── build.gradle.kts
│   │   ├── js
│   │   │   └── build.gradle.kts
│   │   └── jvm
│   │   └── build.gradle.kts
│   ├── other-component
│   │   ├── common
│   │   │   └── build.gradle.kts
│   │   ├── js
│   │   │   └── build.gradle.kts
│   │   └── jvm
│   │   └── build.gradle.kts
│   ├── util
│   │   ├── util1
│   │   │   ├── common
│   │   │   │   └── build.gradle.kts
│   │   │   ├── js
│   │   │   │   └── build.gradle.kts
│   │   │   └── jvm
│   │   │   └── build.gradle.kts
│   │   └── util2
│   │   ├── common
│   │   │   └── build.gradle.kts
│   │   ├── js
│   │   │   └── build.gradle.kts
│   │   └── jvm
│   │   └── build.gradle.kts
│   ├── build.gradle.kts
│   └── settings.gradle.kts
├── build.gradle.kts
└── settings.gradle.kts
My desire is to be able to run build in the root composite project within the IDE (Intellij) and it mimic the behavior of a multiproject execution, where everything underneath that project executes the task in turn.
In Groovy, one can just use the spread operator on includedBuilds*.tasks* in the composite project to wire it up, but in the Kotlin DSL, we only have access to task, which is a single TaskReference and no way to get a collection of Tasks (TaskCollection or Collection of Tasks) or collection of TaskReferences.
So in the rootProject of the composite build.gradle.kts, I have:
tasks {
val clean by getting {
gradle.includedBuilds.forEach { this.dependsOn(it.task(":cleanAll")) }
}
val build by getting {
gradle.includedBuilds.forEach { this.dependsOn(it.task(":buildAll")) }
}
}
Then in one of the included builds build.gradle.kts files, I have tried wiring them two different ways (well many but these are the two approaches):
// Variation 1
tasks {
val buildAll : GradleBuild by creating {
this.dependsOn(tasks.getByPath(":build"))
}
val cleanAll : Delete by creating {
this.dependsOn(tasks.getByPath(":clean"))
}
}
// Variation 2
tasks {
val buildAll: GradleBuild by creating {
subprojects.forEach {
this.dependsOn(it.tasks.getByPath(":build"))
}
}
val cleanAll: Delete by creating {
subprojects.forEach {
this.dependsOn(it.tasks.getByPath(":clean"))
}
}
}
// Variation 2.b
tasks {
val buildAll: GradleBuild by creating {
this.dependsOn(subprojects.mapNotNull(it.tasks.getByPath(":build")))
}
val cleanAll: Delete by creating {
this.dependsOn(subprojects.mapNotNull(it.tasks.getByPath(":clean")))
}
}
// I even used different ways to try and get the tasks such as it.tasks["root:library:build"], it.tasks[":library:build"], and it.tasks["library:build"] since I know that the included builds are executed in an isolated fashion. None of these worked
// The result was when I used absolute paths, gradle spat back that these tasks didn't exist (I assumed because they were lifecycle tasks).
Basically, trying the variations above only ever built and cleaned the rootProjects of the included builds and never the subprojects. Is this a bug?
I do not want to have to resort to needing knowledge of the underlying structure of the included builds to wire this up. That would be unsustainable. What am I doing wrong?
I'm using the following code to achieve this. First, create a settings.gradle.kts in the root that programmatically searches for builds for include:
rootDir.walk().filter {
it != rootDir && !it.name.startsWith(".") && it.resolve("build.gradle.kts").isFile
}.forEach(::includeBuild)
Then create a build.gradle.kts file in the root that "forwards" all root task invocations of the form all<TASK> to <INCLUDED_BUILD>:<TASK>:
tasks.addRule("Pattern: all<TASK>") {
val taskName = this
val taskPrefix = "all"
if (startsWith(taskPrefix)) {
task(taskName) {
gradle.includedBuilds.forEach { build ->
val buildTaskName = taskName.removePrefix(taskPrefix).decapitalize()
dependsOn(build.task(":$buildTaskName"))
}
}
}
}
This way, running ./gradlew allAssemble on the root project will effectively execute the assemble task on all included builds.
Okay, not sure what was going on and why those other methods didn't work, but I found a method that works and does not require me to manufacture synthetic tasks that depend on the lifecycle tasks.
Composite rootproject build.gradle.kts tasks remain the same as stated in the original question:
tasks {
val clean by getting {
gradle.includedBuilds.forEach { this.dependsOn(it.task(":cleanAll")) }
}
val build by getting {
gradle.includedBuilds.forEach { this.dependsOn(it.task(":buildAll")) }
}
}
Tasks declaration in included build root projects' build.gradle.kts-es need to collect and depend on tasks in the following way:
tasks {
val buildAll: GradleBuild by creating {
dependsOn(getTasksByName("build", true))
}
val cleanAll: Delete by creating {
dependsOn(getTasksByName("clean", true))
}
}
This will recursively gather the tasks. Although my previous techniques of iterating through all of the subprojects should have also done the trick since subprojects contains all subprojects, for some reason it wasn't working. This is though! Hopefully this helps out other people.

TaskExecutionException for gradle jettyRun

I am following the book 'Gradle in Action' page 67 attempting to call:
$ gradle jettyRun
...
* What went wrong:
Execution failed for task ':jettyRun'.
> org/eclipse/jetty/http/HttpField
...
With the --stacktrace option I obtain the following message:
...
* Exception is:
org.gradle.api.tasks.TaskExecutionException:Execution failed for task ':jettyRun'
...
Caused by: java.lang.ClassNotFoundException: org.eclipse.jetty.http.HttpField
...
My project is todo-webapp as per the book page 67:
$ tree
├── build.gradle
├── src
│   └── main
│   ├── java
│   │   └── com
│   │   └── manning
│   │   └── gia
│   │   └── todo
│   │   ├── model
│   │   │   └── ToDoItem.java
│   │   ├── repository
│   │   │   ├── InMemoryToDoRepository.java
│   │   │   └── ToDoRepository.java
│   │   └── web
│   │   └── ToDoServlet.java
│   └── webapp
│   ├── css
│   │   ├── base.css
│   │   └── bg.png
│   ├── jsp
│   │   ├── index.jsp
│   │   └── todo-list.jsp
│   └── WEB-INF
│   └── web.xml
and my build file is as follows:
$ cat build.gradle
apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'jetty'
repositories {
mavenCentral()
}
dependencies {
providedCompile 'javax.servlet:servlet-api:2.5',
'javax.servlet.jsp:jsp-api:2.1'
runtime 'javax.servlet:jstl:1.1.2',
'taglibs:standard:1.1.2'
}
following various threads online I have been trying to add a dependency to my build file such as:
jettyRun {
dependencies {
providedRuntime 'org.eclipse.jetty:jetty-http:9.4.0.RC0'
}
}
or indeed add the jar directly /usr/share/java/jetty9-http with runtime files(...). None of these worked. I am not too sure what to try next. Any suggestion is greatly appreciated.
EDIT: As indicated by Vampire, all I had to do is remove apply plugin: 'jetty' and instead following the line apply plugin: 'war', add the line:
apply from: 'https://raw.github.com/akhikhl/gretty/master/pluginScripts/gretty.plugin'
Then use gradle appRun instead of gradle jettyRun. All this is coming from the page Getting started of the gretty plugin.
As you can see at https://docs.gradle.org/current/userguide/userguide_single.html#jetty_plugin, the Jetty plugin is deprecated. Maybe you should try the Gretty plugin as suggested in the docs. :-)

Resources