intellij idea 14 and gradle issues when running integTests - intellij-idea

I have a gradle project imported into idea 14.0.3. The integration tests run fine from the command line. They were also running without any problems in idea 13 from the context menu (running single tests). However, in 14, when I use the context menu in IDE, for some reason the tests that depend on class path resources from src/integTest/resources are failing due to resource not being found. Any idea how I can add this folder in the classpath search in Intellij 14? Has anyone seen this issue before?
If I move the same resource to src/test/resources (or src/main/resources), the tests run fine. So it seems like intellij is not simply looking under src/integTest/resources.
Appreciate the help!!

I have run into this before as well, add the following to your build.gradle file:
// work-around to fix IDE-run test failures (may be fixed in future Gradle versions)
task copyMainResourcesToTest(type: Copy) {
from "${projectDir}/src/main/resources"
into "${buildDir}/classes/test"
}
processTestResources.dependsOn copyMainResourcesToTest
task copyTestResourcesToTest(type: Copy) {
from "${projectDir}/src/test/resources"
into "${buildDir}/classes/test"
}
processTestResources.dependsOn copyTestResourcesToTest
I think this may be resolved in the newest release of Gradle but I have not verified yet. You will want to update the paths for your specific use case.

Looks like this is Bug (IDEA-128966) in IntelliJ 14.
The recommended workaround is something like this:
sourceSets {
integrationTest {
java.srcDir file('src/integTest/java')
resources.srcDir file('src/integTest/resources')
}
if(System.properties.'idea.active') {
main {
resources.srcDir file('src/integTest/resources')
}
}
}
For our projects I changed that to:
if(System.properties.'idea.active') {
test { //Add to test rather than main
That still works and I think it communicates the intent better.
This workaround assumes you have configured your integration tests like this in the build.gradle:
apply plugin: 'idea'
sourceSets {
integrationTest {
java.srcDir file('src/integTest/java')
resources.srcDir file('src/inteTest/resources')
}
}
configurations {
integrationTestCompile.extendsFrom testCompile
integrationTestRuntime.extendsFrom testRuntime
}
task integrationTest(type: Test, dependsOn: jar) {
testClassesDir = sourceSets.integrationTest.output.classesDir
classpath = sourceSets.integrationTest.runtimeClasspath
}
build.dependsOn(integrationTest)
Note: This answer was originally deleted by a moderator because of a duplicate answer that I posted on another question. I now deleted my answer there (and added a link to here) because I think it fits this question better.

Related

Apply local jar-plugin without using maven

I'd like to load my custom plugin from a local jar. The jar file compiles fine and when I check it, the manifest and the plugin class are there.
gradlePlugin {
plugins {
create("asdf") { // <-- I really call it "asdf" in the kts script
id = "asdf"
implementationClass = "pluginTest.TestPlugin"
version = "1.4.0"
}
}
}
The plugin doesn't do anything useful yet as it should be a proof-of-concept to make sure it actually works at all:
class TestPlugin : Plugin<Project> {
override fun apply(project: Project) {
println("Hallo TestPlugin!")
}
}
I then try to use it like this in another project:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath(files("..\\..\\path\\to\\pluginTest.jar"))
}
}
plugins {
id("asdf") version "1.4.0"
}
but it keeps telling me that:
Plugin [id: 'asdf', version: '1.4.0'] was not found in any of the following sources:
What am I missing here? I use Gradle v6.5.
When you have the plugin jar on the classpath, you can't have a version number in the plugin application. I guess this is because you can't have multiple jars with different versions on the classpath in the first place, so specifying a version here doesn't make any sense (except perhaps to validate that you are using the correct one). This won't fix the problem, but it is a start.
To be honest, I don't know why your approach still won't work. The buildscript block is supposed to set up dependencies for that particular script, and that should make the plugin visible to it. It doesn't for some reason.
Perhaps this is a bug or perhaps this is just an undocumented limitation on the use of the plugin {} block. Maybe you could ask over at the Gradle forums or create an issue for it. However, there are workarounds that don't involve publishing to a (local) Maven repository, which I agree can be a bit annoying.
If you use "apply from" instead of "plugins {}", it works. For some reason, the former can see the buildscript classpath whereas the latter can't:
// build.gradle (Groovy DSL)
buildscript {
dependencies {
classpath(files("..\\..\\path\\to\\pluginTest.jar"))
}
}
apply from: "asdf"
Alternatively, move the buildscript plugin from the build.gradle file to the settings.gradle file. This makes is available to the entire build classpath and will make it work with the plugin block:
// settings.gradle (Groovy DSL):
buildscript {
dependencies {
classpath(files("..\\..\\path\\to\\pluginTest.jar"))
}
}
// build.gradle (Groovy DSL)
plugins {
id("asdf")
}
Lastly, just in case you haven't considered it already, you may be able to add the plugin as a composite build. This will create a source dependency to the plugin and has the advantage that transitive dependencies will be carried over (the ones you put in the plugin's own dependency block) and that it will be built automatically if not up-to-date. I use this approach for integration testing my plugins and also sometimes to apply them to my other real projects to test them in a bigger setting before publishing new versions.
Do that with either:
// settings.gradle (Groovy DSL):
includeBuild("..\\..\\path\\to\\plugin")
// build.gradle (Groovy DSL):
plugins {
id("asdf")
}
Or without hard-coding it in the build (so you can dynamically switch between local and published versions):
// build.gradle (Groovy DSL):
plugins {
id("asdf") version "1.4.0" // Version is optional (will be ignored when the command line switch below)
}
// Run with:
./gradlew --include-build "..\\..\\path\\to\\plugin" build
With #BjørnVester's answer I figured it out!
You need to put the buildscript in settings.gradle.kts as it doesn't get executed in the build.gradle.kts even when placed before plugins.
buildscript {
repositories {
flatDir {
dirs("..\\reusable-kotlin\\build\\libs") // <-- folder with jars
}
}
dependencies {
classpath("com.hedev.kotlin:reusable-kotlin:1.4.0")
}
}
But there's a catch! You must use the file-name of the jar in the classpath's name identifier that goes like this:
group:file-name:version
The file gradle will look for will be file-name-version.jar or file-name.jar which you'll see in the error message if you make a mistake (I added the _ on purpose to trigger the error):
Could not resolve all artifacts for configuration 'classpath'.
Could not find com.hedev.kotlin:reusable-kotlin_:1.4.0. Searched in the following locations:
- file:/C:/some/path/reusable-kotlin/build/libs/reusable-kotlin_-1.4.0.jar
- file:/C:/some/path/reusable-kotlin/build/libs/reusable-kotlin_.jar
In order for this to work I also had to add the group property to the plugin itself:
gradlePlugin {
plugins {
create("asdf") {
id = "asdf"
implementationClass = "com.hedev.kotlin.gradle.TestPlugin"
version = "1.4.0"
group = "com.hedev.kotlin"
}
}
}
Finally you can apply it in build.gradle.kts with (no version here):
plugins {
id("asdf")
}

Using gradle convention plugin to set kotlin jvmTarget option

Using a Gradle convention plugin to share common configuration between subprojects, what is the correct way to set Kotlin compiler options, like jvmTarget?
This plugin setup results in a working build, but IntelliJ doesn't understand it, which leads me to think this isn't the correct approach:
plugins {
id 'org.jetbrains.kotlin.jvm'
}
repositories {
jcenter()
}
dependencies {
// shared dependencies
}
tasks.named('test') {
useJUnitPlatform()
}
tasks {
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
}
This plugin is applied in subprojects like this:
plugins {
id 'my.kotlin-conventions'
id 'java-library'
}
I'm using Gradle 6.7, Kotlin 1.4.20.
Edit: More info regarding IntelliJ problem
In IntelliJ, in sub-projects, I am seeing the warning Cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6. Please specify proper '-jvm-target' option. In the root project I don't see the warning, only in sub-projects. Building and running the project produces no problems (or warnings) at all.
Sample: https://github.com/nieldw/IntelliJ_Gradle_Convention_Plugin_Issue
IntelliJ seems to not like the buildSrc/settings.gradle file. When I remove it and “Reload All Gradle Projects”, then the errors that you’ve described disappear.
Commenting the rootProject.name=… line in the buildSrc/settings.gradle file works, too. Interestingly, uncommenting the line later (and reloading the Gradle configuration) is possible without breaking the IntelliJ configuration. So this should be your fix, I suppose.
Your build configuration looks correct to me. This rather sounds like a bug in IntelliJ’s Gradle support.

What command does Intellij Gradle project refresh execute

Intellij hides which gradle command it runs whenver you press a button to do something with gradle. That makes it extremely difficult to find out what goes wrong. I am clicking "refresh" (NOT REFRESH DEPENDENCIES), and it seems to trigger all my sibling projects AND my project to build which is wrong. It is definitely not running "gradle build" because if it did, it would not trigger all the sibling projects in my multi-project build.
Clicking "refresh" in gradle shows a log like this:
2019-10-17 14:58:10,391 [9949323] INFO - xecution.GradleExecutionHelper - Passing command-line args to Gradle Tooling API: -Didea.sync.active=true -Didea.resolveSourceSetDependencies=true --init-script /tmp/ijinit.gradle
Here IDEA is using the Gradle Tooling API and using a gradle init script (in /tmp/ijinit.gradle on my machine). The file shows more:
$ cat /tmp/ijinit.gradle
...imports etc...
initscript {
dependencies {
classpath files([...list of IDEA jars...])
}
}
apply plugin: JetGradlePlugin
class JetGradlePlugin implements Plugin<Gradle> {
void apply(Gradle gradle) {
def processor = new RegistryProcessor()
gradle.addProjectEvaluationListener(processor)
def projectEvaluationIsNotCalledForIncludedBuilds = GradleVersion.current() >= GradleVersion.version("3.1") &&
GradleVersion.current() < GradleVersion.version("4.0")
if (projectEvaluationIsNotCalledForIncludedBuilds) {
gradle.rootProject {
it.afterEvaluate {
gradle.includedBuilds.each { included ->
// included builds should be configured by now, so calling `configuredBuild` should be safe
def toolingRegistry = (ToolingModelBuilderRegistry)included.configuredBuild.services.get(ToolingModelBuilderRegistry.class)
processor.process(toolingRegistry)
}
}
}
}
}
}
...other overrides...
As others mentioned the included builds can be excluded in the IDEA Gradle tab but hopefully this answers the specific title question.
If you are using a recent version of Gradle, you can use --refresh-dependencies option.
./gradlew build --refresh-dependencies

Custom source set in Gradle imported to IntelliJ 14

I'm trying to get Gradle (2.1) and IntelliJ (14.0.2) to play nicely. Specifically, I have imported a sample Gradle project containing a separate source set for integration tests into IntelliJ.
The project builds fine using Gradle on the command line, and I'm able to run the integration tests successfully. When running inside IntelliJ on the other hand, I have two problems:
1) Compiling inside IntelliJ fails, due to a dependency in the integration test to a third-party library (commons-collections) which fails to resolve.
2) If I remove the dependency above and compile, I'm not able to run the integration test inside IntelliJ. I get the following error message:
No tests found for given includes: [org.gradle.PersonIntegrationTest.canConstructAPersonWithAName]
The file structure looks like this:
src
integration-test
java
resources
main
java
resources
test
java
resources
build.gradle
And build.gradle:
apply plugin: 'java'
repositories {
mavenCentral()
}
sourceSets {
integrationTest {
java.srcDir file('src/integration-test/java')
resources.srcDir file('src/integration-test/resources')
}
}
dependencies {
testCompile 'junit:junit:4.11'
integrationTestCompile 'commons-collections:commons-collections:3.2'
integrationTestCompile sourceSets.main.output
integrationTestCompile configurations.testCompile
integrationTestCompile sourceSets.test.output
integrationTestRuntime configurations.testRuntime
}
task integrationTest(type: Test, dependsOn: jar) {
testClassesDir = sourceSets.integrationTest.output.classesDir
classpath = sourceSets.integrationTest.runtimeClasspath
systemProperties['jar.path'] = jar.archivePath
}
check.dependsOn integrationTest
Any ideas on how to make this work would be much appreciated.
The full Gradle sample project is available in the Gradle distribution, under samples/java/withIntegrationTests
You need to tell IDEA to map entries from your integrationTest configuration into your project as TEST dependencies. I am not sure whether you need to add source root directories too. The important part is:
idea {
module {
//and some extra test source dirs
testSourceDirs += file('some-extra-test-dir')
generatedSourceDirs += file('some-extra-source-folder')
scopes.TEST.plus += [ configurations.integrationTest ]
}
}
More is described in http://www.gradle.org/docs/current/dsl/org.gradle.plugins.ide.idea.model.IdeaModule.html
Edits to reflect Daniel's comments: generatedSourceDirs is is Gradle 2.2+.
To set up the test task you will use task like
task integTest(type: Test) {
description = 'Runs the integration tests.'
group = 'verification'
testClassesDir = sourceSets.integTest.output.classesDir
classpath = sourceSets.integTest.runtimeClasspath
reports.junitXml.destination = file("${project.testResultsDir}/$name")
reports.html.destination = file("${project.reporting.baseDir}/$name")
shouldRunAfter test
}
check.dependsOn integTest

How to get `gradlew idea` to get IDEA to use test conf for custom task?

I have the following:
sourceSets {
integrationTest {
java.srcDir file('.')
}
}
dependencies {
integrationTestCompile project(':sut-project')
}
task integrationTest(type: Test)
but when gradlew idea is run and the project opened, the Sources doesn't have a Tests conf for that project.
What needs to be done to get this to work?
The documentation for IDEA plugin is at http://www.gradle.org/docs/current/userguide/idea_plugin.html
From this links you can navigate to http://www.gradle.org/docs/current/dsl/org.gradle.plugins.ide.idea.model.IdeaModule.html where you can see how to map additional source roots (AKA content-roots in IntelliJ parlance) to your modules and configurations to classpath using proper scope. You will use something like:
idea {
module {
testSourceDirs += file('src/integTest/java')
scopes.TEST.plus += configurations.integrationTestCompile
}
}