Configuring IntelliJ code formatting using Gradle's Idea plugin - gradle

I've seen lots of mentions of using the idea plugin for Gradle to configure IntelliJ's code formatting, but I can't find any examples of what this would look like. I gather it would involve modifying the XML of IntelliJ's config files directly, but I can't find any examples of that either. Anyone have an example, or an explanation of how I can determine what's needed for this?
plugins {
id 'idea'
}
idea {
project {
jdkName = "1.8"
languageLevel = "1.8"
targetBytecodeVersion = JavaVersion.VERSION_1_8
// Now What? How do I control code formatting?
}
}

Related

Gradle creating a additional task for int tests

So I found a few tutorials on how to create a seperate task to run integration tests in gradle. My int tests are in a separate folder.. ie src/integrationTest
This is what one of them had set up, I just dont understand the line "val integrationTest by sourceSets.creating"? Is this creating a source set? Other examples have explicit creation of source set in the gradle file..
val integrationTest by sourceSets.creating
dependencies {
"integrationTestImpl"(project)
}
val integrationTestTask = tasks.register<Test>("integrationTest") {
description = "Runs the integration tests."
group = "verification"
testClassesDirs = integrationTest.output.classesDirs
classpath = integrationTest.runtimeClasspath
mustRunAfter(tasks.test)
}
tasks.check {
dependsOn(integrationTestTask)
}
Yes, it is creating a new source set named integrationTest.
Refer to this answer on Kotlin delegated properties. It is not specific to Gradle, but the Kotlin language itself. Gradle provides a variety of extensions to make the Kotlin DSL a rich experience compared to the Groovy DSL.

Custom Configuration dependency declaration

I am trying to convert build.gradle to kotlin dsl. Using gradle 7.4.1.What the right way to declare custom configuration. For custom configuration like
configurations { grafana }
sourceSets { grafana }
and within dependencies block
grafanaImplementation "org.slf4j:slf4j-simple:1.7.36"
grafanaImplementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
grafanaRuntimeOnly "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
While I am in kotlin-dsl I am doing
val grafana by configurations.creating
val grafanaSourceSet = sourceSets.create("grafana")
and within dependency block
grafana("org.slf4j:slf4j-simple:1.7.36")
grafana("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
When I try to put grafanaImplementation/ grafanaRuntimeOnly within kotlin dsl, it fails.
What is the equivalent of grafanaImplementation/ grafanaRuntimeOnly within kotlin dsl
Quick fix
When you do
val grafanaSourceSet = sourceSets.create("grafana")
behind the scenes Gradle will create the required configurations, grafanaImplementation, grafanaRuntimeOnly, etc, so you can use them without error like this:
val grafanaSourceSet = sourceSets.create("grafana")
dependencies {
"grafanaImplementation"("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
"grafanaRuntimeOnly"("org.slf4j:slf4j-simple:1.7.36")
}
This approach is more like how Groovy works - it basically disables type-checking and the strings will be evaluated during Gradle execution.
Generated DSL accessors
However, string-typing is not why we like Kotlin! We want type-safety and auto completion hints. That's exactly what we see with the implementation() and runtimeOnly(). So how do we get them for grafanaImplementation() and grafanaRuntimeOnly()?
Basically, Gradle will scan the registered config and when it sees that a plugin creates an implementation configuration, it generates Kotlin DSL accessors. However, it can't generate accessors for the build.gradle.kts that contains the definition for the accessors... that's too late. So we need to define the config earlier. We can do that with a buildSrc plugin.
buildSrc Grafana convention plugin
Set up a buildSrc project (this is covered more in the Gradle docs or other StackOverflow answers)
Create a pre-compiled script plugin for Grafana config
// $projectRoot/buildSrc/src/main/kotlin/grafana.convention.gradle.kts
plugins {
// using 'sourceSets' requires the Java plugin, so we must apply it
java
}
val grafanaSourceSet = sourceSets.create("grafana")
Note that this convention plugin is quite opinionated as it applies the Java plugin. In more complex setups you might want to instead react to the Java plugin, rather than always applying it.
Now apply the convention plugin, and Gradle will generate the Kotlin DSL accessors!
// $projectRoot/build.gradle.kts
plugins {
id("grafana.convention")
}
dependencies {
// no string-typing needed!
grafanaImplementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
grafanaRuntimeOnly("org.slf4j:slf4j-simple:1.7.36")
}

Aggregate Report for Gradle Multi-Project build

I need to create an aggregate code coverage report for my multiple-module Gradle project using the JaCoCo plugin for Gradle, similar to the one generated by the jacoco:aggregate-report of Maven's jaoco-maven-plugin.
I have been googling for a solution the last couple of days but nothing has worked so far. Most of the proposed solutions involve defining a task of type JacocoReport in the root project, that aggregates the execution data and produces the html code coverage report. However everything I tried so far either fails with an error or does not generate any report.
For example, this code snippet that I have tried:
def publishedProjects = subprojects.findAll()
task jacocoRootReport(type: JacocoReport) {
dependsOn(publishedProjects.test)
additionalSourceDirs = files(publishedProjects.sourceSets.main.allSource.srcDirs)
sourceDirectories = files(publishedProjects.sourceSets.main.allSource.srcDirs)
classDirectories = files(publishedProjects.sourceSets.main.output)
executionData = files(publishedProjects.jacocoTestReport.executionData)
doFirst {
executionData = files(executionData.findAll { it.exists() })
}
reports {
html.enabled = true
xml.enabled = false
}
}
gives the error groovy.lang.GroovyRuntimeException: Cannot set the value of read-only property 'additionalSourceDirs' for task ':jacocoRootReport' of type org.gradle.testing.jacoco.tasks.JacocoReport
The version of Gradle that I am using is 7.3. Unfortunately I'm very new to Gradle and I still cannot fiddle with the code snippets that I've found to make them work for my case.
Any help will be much appreciated. Thank you very much in advance.
There is an official example in the Gradle docs for this use case:
https://docs.gradle.org/7.3.3/samples/sample_jvm_multi_project_with_code_coverage.html
It is a somewhat complex and requires an additional project that will serve as the aggregate. The way you have above is generally discouraged by Gradle for reasons outside of this question/answer.
Edit 2022-09-11
As of Gradle 7.4, Gradle now offers a plugin to aggregate reports for multi-module projects.
See the documentation for the JaCoCo Report Aggregation Plugin for more details.

How to export asciidoc to ODT or ODF using gradle?

I was trying to export asciidoc document to ODT. I found unofficial backend implementation that does the work: https://github.com/dagwieers/asciidoc-odf. My question is: how can install and use this backend using gradle? Is it even possible? I have no idea how to start.
Here is my build.gradle that does it for PDF
buildscript {
repositories {
mavenCentral()
jcenter()
}
dependencies {
classpath 'org.asciidoctor:asciidoctor-gradle-plugin:1.5.3'
classpath 'org.asciidoctor:asciidoctorj-pdf:1.5.0-alpha.11'
classpath 'org.asciidoctor:asciidoctorj-diagram:1.5.0'
}
}
plugins {
id 'org.asciidoctor.convert' version '1.5.3'
}
apply plugin: 'java'
apply plugin: 'org.asciidoctor.convert'
asciidoctorj {
version = '1.5.4'
}
asciidoctor {
backends 'pdf'
requires 'asciidoctor-diagram'
sourceDir = file('dok/')
outputDir = file('build/')
attributes \
'buildDir': buildDir,
'imagesdir': "$buildDir/images"
}
Maybe not something you want to hear. I think it is no possible to generate odf files with the asciidoctor-gradle-plugin. If you look at https://github.com/asciidoctor/asciidoctor-gradle-examples which demonstrates examples for using gradle-plugin, I do not see an example for odf. :-(
It would be cool, if you could make a feature request at https://github.com/asciidoctor/asciidoctor-gradle-plugin/issues and hopefully, someone will start.
There's a thing to clarify first: the converter you mention (https://github.com/dagwieers/asciidoc-odf) is for the original Python implementation of the AsciiDoc language. The gradle plugin uses Asciidoctor, which is an alternative implementation done in Ruby, and if you ask me, the current reference standard.
Asciidoctor does not support ODF directly, but does support plugable converters and there's already an attempt (https://github.com/kubamarchwicki/asciidoctor-fodt), however, not stable it seems.
In those cases where no direct converter is available you can try some intermediate step like converting to doocbook and then from doocbook to the final format. Doing some googling I found a plugin from spring and apparently support to ODF from doocbook, but you'll need to test it and some features may be limited.
PS: I wanted to provide the links to the references but the ***** rep system prevents me from doing so.

Setting up a multi-project Gradle build

I'm setting up a multi-module Gradle build for a legacy system at work (replacing the current Ant build). However, I'm new to Gradle, and I'm not sure what's the best way to do it. And I want to do it right, because this build script will be around for a long time. I have found a way to do things that works, but when I google around and read answers on StackOverflow, I see people using a different way, which --in my case-- doesn't work. But maybe I'm doing something wrong. I've also been reading in the Gradle in Action book, but haven't found this particular issue there.
I have a build.gradle file in the root of my project, with a bunch of subdirectories that each contain a sub-project. Most of these are regular Java projects, but there are some Wars and Ears in there, too, which require some special packaging love. Each sub-project has its own build.gradle file which, at this point, only contains a list of dependencies, nothing more.
The build.gradle file in the root of my projects looks something like this (I left out the War stuff for brevity):
configure(javaProjects()) {
jar.doFirst {
manifest {
...
}
}
}
configure(earProjects()) {
apply plugin: 'ear'
ear.doFirst {
manifest {
...
}
}
}
Set<String> javaProjects() {
subprojects - earProjects()
}
Set<String> earProjects() {
subprojects.findAll { it.name.endsWith(".ear") }
}
The only reason why I'm doing things this way, is because it was the first solution I tried that I could get to work in my situation. Now that the script is growing, though, it starts to feel a little clunky. Also, the doFirst thing seems a little awkward.
But when I look on StackOverflow, I see recommendations of using constructs like this:
allprojects {
tasks.withType(Jar) {
manifest {
...
}
}
tasks.withType(Ear) {
manifest {
...
}
}
}
This seems much nicer, but I don't seem to be able to rewrite my script in that way. I get errors like this one:
Cannot change configuration ':some.subproject:compile' after it has been resolved.
I don't know what to do about this error, and I can't seem to google it either, for some reason.
So, my question is: have I indeed been doing things the wrong way? Or rather: in a way that is not idiomatic Gradle? For the sake of maintainability, I'd like to do things as idiomatically as possible. And if so: what can I do about the error message?
In general you should do things like described in your second snippet:
allprojects {
tasks.withType(Jar) {
manifest {
...
}
}
}
But there are some limitations where this isn't sufficient. The error message you get means that you modify the compile configuration AFTER the configuration is already resolved. That happens for example when you do something like
configurations.compile.files.each...
during the configuration phase (e.g. in your manifest block like seen above) and in another place (e.g. in one of your subprojects build.gradle files):
dependencies{
compile "org.acme:somelib:1.2.3"
}
The other problem with this is, that you resolve the compile dependencies every time you invoke your build script, even when no jar task is triggered.
The suggested workaround is to replace
tasks.withType(Jar) {
manifest {
...
}
}
with
tasks.withType(Jar) {
doFirst{
manifest {
...
}
}
}
That means that resolving the configuration is postponed to the execution phase of gradle and really just triggered when needed.
When you configure a project in a multiproject build you can think of that each snippet that is part of the whole configuration. you're not configuring the project 'twice' but you configure different aspects of the project at different places.
This is a known limitation of the current gradle configuration model.
You can still use
configure(earProjects()) {
}
that doesn't matter here. IMO it is just a matter of personal preference. The gradle project itself uses 'configure'.
Personally I prefer to apply the plugins like Ear or war on the projects build.gradle file to mark a project as a ear/war project.
To share common configurations among all ear projects, you could have something like this in your root build.gradle file:
allprojects{
plugins.withType(EarPlugin){
// only applied if it is a ear project
// put ear specific logic here
}
}

Resources