Maven plugin testing with Groovy: access to generated class? - maven

I'm developping a Maven plugin and some of my tests are done through maven-invoker-plugin based on Groovy scripts (https://maven.apache.org/plugin-developers/plugin-testing.html).
This Maven plugin generates a Java class and I'd like to test this generated class behaviour with Groovy scripts.
I'm facing a problem with these Groovy scripts saying that it could not resolve the class:
Running post-build script: <blah>\verify.groovy
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
Script1.groovy: 21: unable to resolve class com.mycompany.MyClass
# line 21, column 1.
import com.mycompany.MyClass
Here is the generated Java class from my plugin:
package com.mycompany;
public final class MyClass {
public static String getSomething() {
return "something";
}
}
Here is an extract of my Groovy test verify.groovy:
File generatedJavaFile = new File( basedir, "target/my-plugin/com/mycompany/MyClass.java" );
assert generatedJavaFile.exists()
assert generatedJavaFile.isFile()
File generatedClassFile = new File( basedir, "target/classes/com/mycompany/MyClass.class" );
assert generatedClassFile.exists()
assert generatedClassFile.isFile()
import com.mycompany.MyClass
assert MyClass.getSomething() == "the expected result"
I was wondering if something needs to be specified to the maven-invoker-plugin configuration to include the tested Maven project, or if it's just not possible and I need to find another way...
Thanks,
BenoƮt.

Related

Applying Gradle plugin from local file

I have the following gradle plugin that does the job of starting up a java process. The code for this lives under a file named startAppServerPlugin.gradle under the project's buildSrc directory.
The code of the plugin looks like this:
repositories.jcenter()
dependencies {
localGroovy()
gradleApi()
}
}
public class StartAppServer implements Plugin<Project> {
#Override
void apply(Project project) {
project.task('startServer', type: StartServerTask)
}
}
public class StartServerTask extends DefaultTask {
String command
String ready
String directory = '.'
StartServerTask(){
description = "Spawn a new server process in the background."
}
#TaskAction
void spawn(){
if(!(command && ready)) {
throw new GradleException("Ensure that mandatory fields command and ready are set.")
}
Process process = buildProcess(directory, command)
waitFor(process)
}
private waitFor(Process process) {
def line
def reader = new BufferedReader(new InputStreamReader(process.getInputStream()))
while ((line = reader.readLine()) != null) {
logger.quiet line
if (line.contains(ready)) {
logger.quiet "$command is ready."
break
}
}
}
private static Process buildProcess(String directory, String command) {
def builder = new ProcessBuilder(command.split(' '))
builder.redirectErrorStream(true)
builder.directory(new File(directory))
def process = builder.start()
process
}
}
I'm trying to figure out a way of having this imported into my main build.gradle file due everything I tried so far has been unsuccessful.
So far I have tried this:
apply from: 'startAppServerPlugin.gradle'
apply plugin: 'fts.gradle.plugins'
But it has been failing. I've tried searching online for examples of doing what I need to do but so far I've been unsuccessful. Can anyone please provide a hint as to how I'm supposed to do so?
The buildSrc folder is treated as an included build, where the code is compiled and put on the classpath of the surrounding project. The actual build.gradle file in buildSrc is only used for compiling that project, and the things you put in it will not be available elsewhere.
You are supposed to create your classes as a normal Java/Groovy/Kotlin project under buildSrc. I don't know if you can use the default package, but it is generally best practice to have a package name anyway.
For example, your StartAppServer plugin should be in buildSrc/src/main/groovy/my/package/StartAppServer.groovy. Then you can apply it in your build scripts with apply plugin: my.package.StartAppServer.
There are a lot of good examples in the user guide.
You are on the right path. The first order of business is to import the external gradle build using:
apply from: 'startAppServerPlugin.gradle'
Then you can apply the plugin with:
apply plugin: StartAppServer
See Script Plugins and Applying Binary Plugins

Changing from the default "test" directory for Spring Contract's contracts and base class tests

I have tried changing the default test directory name for base test classes as follows:
Old:
bignibou-server/src/test/java/com/bignibou/signup
New:
bignibou-server/src/contracts/java/com/bignibou/signup
Here is the directory where my contracts live:
New:
bignibou-server/src/contracts/resources/contracts/signup
Here is my gradle configuration:
contracts {
packageWithBaseClasses = 'com.bignibou'
baseClassMappings {
baseClassMapping(".*signup*.", "com.bignibou.signup.SignupBase")
}
}
I use the same gradle configuration both for contracts tests & integration tests. See:
sourceSets {
integrationTest {
java.srcDirs = ['src/it/java', 'src/contracts/java']
resources.srcDirs = ['src/it/resources', 'src/contracts/resources']
compileClasspath = sourceSets.main.output + configurations.testRuntime
runtimeClasspath = output + compileClasspath
}
}
However, since I moved my base class tests & contracts from the test directory, the contracts tests are nor run...
edit:
After searching the documentation, I found the contractsDslDir property that can be used as follows:
contracts {
packageWithBaseClasses = 'com.bignibou'
contractsDslDir = new File("${project.rootDir}/src/contracts/resources/contracts")
baseClassMappings {
baseClassMapping(".*signup*.", "com.bignibou.signup.SignupBase")
}
}
However, the tests are still not run... What else I am missing?
Here is how I try to run the tests:
./gradlew clean check
edit 2:
I was able to get Spring Cloud Contract to find my contract using the following value for contractsDslDir:
contractsDslDir = new File("./src/contracts/resources/contracts")
Now the issue is that my test won't find the test base:
> Task :bignibou-server:compileTestJava FAILED
/Users/julien/Documents/projects/bignibou/bignibou-server/build/generated-test-sources/contracts/com/bignibou/SignupTest.java:3: error: package com.bignibou.signup does not exist
import com.bignibou.signup.SignupBase;
^
/Users/julien/Documents/projects/bignibou/bignibou-server/build/generated-test-sources/contracts/com/bignibou/SignupTest.java:20: error: cannot find symbol
public class SignupTest extends SignupBase {
^
symbol: class SignupBase
2 errors
FAILURE: Build failed with an exception.
edit 3: It is odd: Spring Cloud Contracts still seems bound to the test gradle task (as opposed to my custom integrationTest one)...
When I run ./gradlew clean integrationTest the contracts are not even searched... However when I run ./gradlew clean test I get the above error indicating that Spring Cloud Contract is looking for a base class but not finding one.
How can I tell Spring Cloud Contract to bind to my custom integrationTest gradle task?
It's not supported at the moment. Feel free to find the issue or create a new one if you can't find it

How to access extra properties defined in build.gradle in a Groovy class?

I am defining an extra property in build.gradle:
ext {
GRGIT_TARGET_REPO = ...
}
I have a groovy class under buildSrc/src/main/groovy
class Utils {
def test() {
println GRGIT_TARGET_REPO
}
}
I have another gradle file which can access GRGIT_TARGET_REPO just fine. But if it calls the function in the class:
Utils utils = new Utils()
utils.test()
On calling the above function, I get the following error:
No such property: GRGIT_TARGET_REPO for class: Utils
Is there a way to access project/extra properties in Groovy classes?
I believe you would need to send the gradle project object into your Utils class to accomplish what you want. In other words:
class Utils {
def project
def test() {
println(project.ext.GRGIT_TARGET_REPO)
}
}
and
def utils = new Utils(project: project)
utils.test()
in your build.gradle file.
Every gradle build file has a project instance as its delegate which means that you can call all methods in the project class directly from the build file code. The example here is that the above project access calls the getProject method on the project object.
For extra properties, there is an "extra properties" section in the above groovy/javadoc for the Project object.

Gradle plugin for XML Beans

I am trying to write a Gradle plugin for XML Beans. I have started with one of the 'Hello from Gradle' plugin examples, and also a plugin published by R. Artavia here. That plugin went straight to jar - I am trying to only generate source. The generated source must then be compiled with other project source and included in a single jar. Other goals include
- full plugin - all I should need is "apply plugin: 'xmlbean'"
- I can configure source/code gen location and some features if I want to
- It detects whether it needs to be rebuilt. (well, eventually!!!)
I am off to a pretty good start, but am blocked defining a new sourceSet. I am getting an error "No such property 'srcDirs'" (or 'srcDir'). It seems there is something I have to define someplace to make a new sourceSet work but I cannot find it. I have tried several different syntaxes (with/without equal sign, brackets, srcDir/srcDirs, etc. - nothing is working...
What do I need to do inside a plugin to make a new sourceSet entry be properly recognized?
Thank you!
JKE
File: xmlbean.gradle (includes greeting plugin for the moment for debugging)
apply plugin: xmlbean
apply plugin: 'java'
xmlbean {
message = 'Hi'
greeter = 'Gradle'
}
class xmlbean implements Plugin<Project> {
void apply(Project project) {
project.extensions.create("xmlbean", xmlbeanExtension)
Task xmlbeanTask = project.task('xmlbean')
xmlbeanTask << {
project.configurations {
xmlbeans
}
project.dependencies {
xmlbeans 'org.apache.xmlbeans:xmlbeans:2.5.0'
}
project.sourceSets {
main {
java {
srcDirs += '$project.buildDir/generated-source/xmlbeans'
}
}
xmlbeans {
srcDirs = ['src/main/xsd']
}
}
ant.taskdef(name: 'xmlbean',
classname: 'org.apache.xmlbeans.impl.tool.XMLBean',
classpath: project.configurations.xmlbeans.asPath)
ant.xmlbean(schema: project.sourceSets.xmlbean.srcDir,
srconly: true,
srcgendir: "$project.buildDir/generated-sources/xmlbeans",
classpath: project.configurations.xmlbeans.asPath)
println "${project.xmlbean.message} from ${project.xmlbean.greeter}"
}
project.compileJava.dependsOn(xmlbeanTask)
}
}
class xmlbeanExtension {
String message
String greeter
}
File: build.gradle
apply from: '../gradle/xmlbeans.gradle'
dependencies {
compile "xalan:xalan:$ver_xalan",
":viz-common:0.0.1",
":uform-repository:0.1.0"
}
Console: Error message:
:idk:xmlbean FAILED
FAILURE: Build failed with an exception.
* Where:
Script 'C:\jdev\cpc-maven\try.g2\comotion\gradle\xmlbeans.gradle' line: 32
* What went wrong:
Execution failed for task ':idk:xmlbean'.
> No such property: srcDirs for class: org.gradle.api.internal.tasks.DefaultSourceSet_Decorated
...
BUILD FAILED
Gradle info: version 2.5 / groovy 2.3.10 / JVM 7u55 on Windows 7 AMD64
You should try to become familiar with the Gradle DSL reference guide, because it's a huge help in situations like this. For example, if you click on the sourceSets { } link in the left navigation bar, you're taken to this section on source sets.
From there, you'll discover that the sourceSets {} block is backed by a class, SourceSetContainer. The next level of configuration nested inside is backed by a SourceSet object, and then within that you have one or more SourceDirectorySet configurations. When you follow the link to SourceDirectorySet, you'll see that there are getSrcDirs() and setSrcDirs() methods.
So how does this help? If you look closely at the exception, you'll see that Gradle is saying it can't find a srcDirs property on DefaultSourceSet_Decorated, which you can hopefully infer is an instance of SourceSet. That interface does not have an srcDirs property. That's because your xmlbeans {} block is configuring a SourceSet, not a SourceDirectorySet. You need to add another nested configuration to gain access to srcDirs.
At this point, I'm wondering whether a new source set is the appropriate solution. Unfortunately it's not clear to me exactly what the plugin should be doing, so I can't offer any alternatives at this point.

gradle, could not find property in buildSrc

I made custom task, name MySqlTask.groovy
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
public class MySqlTask extends DefaultTask {
def hostname = 'localhost'
def sql
#TaskAction
def runQuery() {
//to do something...
}
}
And, I put this file in rootProject/buildSrc/src/main/groovy.
My build file is customtasksourcetree.gradle.
task createDatabase(type: MySqlTask) { sql = 'CREATE DATABASE IF NOT
EXISTS example' }
When I run gradle with customtasksrc.gradle then raise error like this.
FAILURE: Build failed with an exception.
* Where:
Build file '/Users/need4spd/Programming/Java/workspace/gradleTest/customtasksourcetree.gradle' line: 1
* What went wrong:
A problem occurred evaluating root project 'gradleTest'.
> Could not find property 'MySqlTask' on root project 'gradleTest'.
I have read that, my custom task file in buildSrc will compiled and add to classpath during build time automatically.
I can see compiled MySqlTask.class in buildSrc/build/classes.
What's the problem? Thanks.
I think that the problem is due to the fact that you haven't imported MySqlTask in your build script

Resources