gradle configurations for tasks - groovy

I have gradle build script with plugins: groovy, jacoco and maven.
In dependencies beside jars is:
testCompile group: 'org.spockframework', name: 'spock-core', version: '0.7-groovy-2.0'
Now when I created task integTest(Type: Test) and :
configurations{
integTestCompile {
extendsFrom testCompile
}
integTestRuntime {
extendsFrom integTestCompile
}
}
everything works OK, but I wanted to add some modularization and now all integTest tasks are created that way:
task "${module}_${suite}" (type: Test)
and when I tried implement same changes in configurations I got an error:
Could not find method ModuleName_Suite1Runtime() for arguments [build_55s7pmm2c6k8n8e2n1i59t3b5b$_run_closure5_closure28_closure29_closure31#3394214b] on root project 'projectName'.
for
configurations {
"${module}_${suite}Compile"{
extendsFrom testCompile
}
"${module}_${suite}Runtime"{
extendsFrom "${module}_${suite}Compile"
}
}
and another error with different configuration:
No signature of method: java.lang.String.extendsFrom() is applicable for argument types: (org.gradle.api.internal.artifacts.configurations.DefaultConfiguration_Decorated) values: [configuration ':testCompile']
for
configurations{
"${module}_${suite}Compile".extendsFrom(testCompile)
"${module}_${suite}Runtime".extendsFrom("${module}_${suite}Compile")
}
Without "taskName+Compile" and "taskName+Runtime" I got ClassNotFound Exception for spock specification. So I'm sure I need this like in previous version.
I'm pretty sure it's something straightforward, but I can't find any tip in google.
Any help would be appreciated.

The syntax being used inside the configurations {...} block is implemented via some Groovy magic that unfortunately is not called when you use a String literal. Instead, if you want to create a configuration with a dynamic name you'll want to call the create() method on the ConfigurationsContainer.
configurations.create("${module}_${suite}Compile") {
extendsFrom configurations.testCompile
}

Related

Groovy script won't run due to NoClassDefFoundError

I wrote a very simple groovy script to test if a cron expression is valid:
import hudson.scheduler.CronTabList
try {
def cron = CronTabList.create("#daily")
println("Valid cron!")
} catch(Exception e) {
println("Invalid cron!")
e.printStackTrace()
}
Running this fails with the message:
Caught: java.lang.NoClassDefFoundError: javax/servlet/ServletContextListener
java.lang.NoClassDefFoundError: javax/servlet/ServletContextListener
at hudson.scheduler.BaseParser.<clinit>(BaseParser.java:149)
at hudson.scheduler.CronTab.set(CronTab.java:113)
at hudson.scheduler.CronTab.<init>(CronTab.java:100)
at hudson.scheduler.CronTabList.create(CronTabList.java:121)
at hudson.scheduler.CronTabList.create(CronTabList.java:96)
at hudson.scheduler.CronTabList$create.call(Unknown Source)
at validate_crontab.run(validate_crontab.groovy:7)
Caused by: java.lang.ClassNotFoundException: javax.servlet.ServletContextListener
... 7 more
Process finished with exit code 1
My build.gradle dependencies look like:
dependencies {
compile 'org.codehaus.groovy:groovy-all:2.3.11'
compile group: 'org.quartz-scheduler', name: 'quartz', version: '2.3.0'
compile group: 'org.jenkins-ci.main', name: 'jenkins-core', version: '2.85'
testCompile group: 'junit', name: 'junit', version: '4.12'
}
I simply can't figure out what's to blame and why I can't run the script.
Any help is much appreciated!
Apparently what you miss is the servlet API. For example:
dependencies {
compile group: 'javax.servlet', name: 'javax.servlet-api', version: '3.1.0'
}
If you put that in your dependencies your script will most likely run.
But I guess that it is fairly important to understand why did you get this error. If you have a closer look at the jenkins-core library you will notice that it has a "provided" dependency to the servlet API. A provided dependency in simpler words means that the library (jenkins-core in your case) is compiled with the assumption that the servlet API jar will be present in the class path at your production environment - e.g. when using the lib in a web application running within a servlet container.
I guess that you run your groovy script as a standalone app, that is why you are getting an error. And... DISCLAIMER - I do not know if using jenkins-core in standalone apps is intended, though :-).

Create a Groovy executable jar with Spock test set as to be executed

I want to create jar with two groovy files, AppLogic.groovy which consists of two few groovy classes and another file, AppSpec that has Spock test suite and I would like to have this Spock class executed (set as executable). How can I create such jar with all dependencies? I found sth similar for jUnit here: how to export (JUnit) test suite as executable jar but could not adapt it for my needs.
I use gradle for build, here is my build.gradle file:
group 'someGroup'
version '1.0'
apply plugin: 'groovy'
apply plugin: 'java'
apply plugin:'application'
sourceCompatibility = 1.7
repositories {
//some repos here
maven { url "http://repo.maven.apache.org/maven2" }
}
dependencies {
//some dependencies here
}
I was browsing around and found SpockRuntime, but I do not know if and how I can use it to achive my goal.
And the winner is:
static void main(String[] args) {
EmbeddedSpecRunner embeddedSpecRunner = new EmbeddedSpecRunner()
embeddedSpecRunner.runClass(MySpec)
}
I do not advise using the EmbeddedSpecRunner from spock implementation as described in accepted answer.
This is what I found to work reliably with gradle 4.9. The basic approach is to use:
The gradle application plugin to create a single tarfile with all testRuntimeClasspath dependencies and shell scripts to run the spock tests
The gradle maven-publish plugin to publish the tar file as an artifact to your maven repo (in my case nexus)
The build.gradle file looks like this:
apply plugin: 'java'
apply plugin: 'groovy'
apply plugin: 'maven-publish'
apply plugin: 'application'
mainClassName = 'org.junit.runner.JUnitCore' // The junit 4 test runner class
applicationName = 'run-tests-cli' // Feel free to change
repositories {
...
}
dependencies {
...
testImplementation "org.codehaus.groovy:groovy-all:${groovyVersion}"
testImplementation "org.spockframework:spock-core:${spockVersion}"
}
// Package compiled spock / junit tests to <artifact>-test-<version>.jar
task testJar(type: Jar) {
classifier = 'tests'
from sourceSets.test.output.classesDirs
}
// Copy all testRuntimeClasspath dependencies to libs folder
task copyToLibs(type: Copy) {
from configurations.testRuntimeClasspath
into "$buildDir/libs"
}
// Make sure test jar is copied
copyToLibs.dependsOn('testJar')
// Make sure platform-specific shell scripts are created after copyToLibs
startScripts.dependsOn(copyToLibs)
// Configure what goes into the tar / zip distribution file created by gradle distribution plugin assembleDist task
distributions {
main {
contents {
// Include test jar
from(testJar) {
into "lib"
}
// Include all dependencies from testRuntimeClasspath
from(copyToLibs) {
into "lib"
}
}
}
}
startScripts {
// Ensure ethat all testRuntimeClasspath dependencies are in classpath used by shell scripts
classpath = project.tasks['testJar'].outputs.files + project.configurations.testRuntimeClasspath
}
publishing {
repositories {
maven {
def releasesRepoUrl = "https://nexus.yourcompany.com/repository/maven-releases/"
def snapshotsRepoUrl = "https://nexus.yourcompany.com/repository/maven-snapshots/"
url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
credentials {
username = rootProject.getProperty('NEXUS_USERNAME')
password = rootProject.getProperty('NEXUS_PASSWORD')
}
}
}
publications {
maven(MavenPublication) {
groupId = 'com.yourgroupId'
version = "${rootProject.getVersion()}"
}
TestJar(MavenPublication) {
artifact(testJar)
}
RunTestsCliTar(MavenPublication) {
artifact(distTar)
artifactId "${applicationName}"
}
}
}
Now you can do the following:
To build the project (including the tar file) without running test task: gradle -x test clean build
To publish artifacts produced by project (including tar file to maven repo - in my case nexus): gradlew -x test publish. Note you will need to provide credentials to upload artifacts to repo. It is good practice to define them (NEXUS_USERNAME, NEXUS_PASSWORD in my example) in ~/.gradle/gradle.properties or specify them via -P options on the gradle command line.

gradle.buildStarted not triggered

I am not able to have buildStarted triggered in my gradle build, not sure what I am doing wrong.
I have a root project gradle file like this
version '1.0'
buildscript {
repositories {
maven { url 'http://repo.jfrog.org/artifactory/gradle-plugins' }
}
dependencies {
classpath(group: 'org.jfrog.buildinfo', name: 'build-info-extractor-gradle', version: '2.1.0')
}
}
gradle.buildStarted {
println "buildStart"
}
gradle. buildFinished {
println "buildFinished"
}
apply plugin: 'groovy'
apply plugin: 'maven'
.........
buildFinished works as I am able to see corresponding println but buildStarted never seem to get triggered.
EDIT
Include init.gradle that uses build listener
class MyBuildAdapter extends BuildAdapter {
void buildStarted(Gradle gradle) {
println "buildStarted"
}
}
gradle.addBuildListener new MyBuildAdapter()
The problem is that the buildStarted event occurs before you get a chance to register a callback in a build script. You'll have to use one of the other hooks. For details, see Gradle.addBuildListener in the Javadoc.
I had the same issue in a custom plugin I wrote, and found that only projectsEvaluated callback is the one that gets executed before buildFinished in the BuildListener.
It's been 7 years, and finally Gradle got around to admitting that it didn't make sense to have this method in the first place. It'll be removed in Gradle 7.
https://docs.gradle.org/6.5.1/userguide/upgrading_version_5.html#apis_buildlistener_buildstarted_and_gradle_buildstarted_have_been_deprecated

Programmatically download dependencies in custom gradle task

I want to create task which depends on few maven libraries. Is it possible to download those libraries from groovy code? What I want to do is to put this code
configurations {
sshexecAntTask
}
repositories {
mavenCentral()
}
dependencies {
sshexecAntTask 'org.apache.ant:ant-jsch:1.7.0'
}
Which I use in this way:
ant.taskdef(name: 'sshexec', classname: 'org.apache.tools.ant.taskdefs.optional.ssh.SSHExec', classpath: project.configurations.sshexecAntTask.asPath)
ant.sshexec(host: host, username: username, password: password, command: command, trust: 'true', failonerror: 'true')
Into my DefaultTask class. Is it possible?
It should look similar to this:
class MyCustomTask extends DefaultTask {
public MyCustomTask() {
super()
// set and download dependencies here
}
}
[EDIT]
I've found that I can do it in this way:
project.getRepositories().mavenLocal()
project.getConfigurations().create('sshexecAntTask')
project.getDependencies().add('sshexecAntTask', 'org.apache.ant:ant-jsch:1.7.0')
project.getConfigurations().getByName('sshexecAntTask').resolve()
println('project.configurations.sshexecAntTask.asPath: '+project.getConfigurations().getByName('sshexecAntTask').getAsPath());
But it still doesn't work.
You would typically do something along the lines of:
MyCustomTask lives in its own build (possibly buildSrc).
The MyCustomTask project declares ant-jsch as a compile dependency.
The task's action (not constructor) defines (taskdef) and executes the Ant task. (Might have to be wrapped with project.ant.execute { ... }.)
Builds that wish to use MyCustomTask declare a build script dependency on its module (not necessary in case of buildSrc). Transitive dependency management automatically brings in ant-jsch along with it.
The customPlugin sample in the full Gradle distribution is a good place to get started. (Just declare a compile instead of a testCompile dependency.)

How to use the maven ant task from gradle?

I am trying to publish some artifacts to the maven central repo and since the current version of gradle (0.9-rc2) does not handle pgp I thought I would give it a try by 'porting' the ant xml version while waiting for gradle 1.0 which hopefully will support it out of the box.
I wrote the following in gradle:
def mvn =
groovy.xml.NamespaceBuilder.newInstance(ant, 'antlib:org.apache.maven.artifact.ant')
mvn.mvn {
arg(value: 'org.apache.maven.plugins:maven-gpg-plugin:1.1:sign-and-deploy-file')
arg(value: '-Durl=file:///tmp/repo2')
arg(value: '-DrepositoryId=sonatype-nexus-staging')
arg(value: '-DpomFile=pom.xml')
arg(value: '-Dfile=myjar.jar')
arg(value: '-Dfile=-Pgpg')
}
Unfortunately it is not working and I am getting this:
Cause: Problem: failed to create task or type antlib:org.apache.maven.artifact.ant:mvn
Cause: The name is undefined.
Action: Check the spelling.
Action: Check that any custom tasks/types have been declared.
Action: Check that any <presetdef>/<macrodef> declarations have taken place.
No types or tasks have been defined in this namespace yet
I have tried various combinations including adding the following at the top of my script:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.apache.maven:maven-ant-tasks:2.1.1'
}
}
Any help would be much appreciated
Thanks
Yan
I did not find a way to use NamespaceBuilder but I found another way to be able to use the task directly which solves my issue:
repositories {
mavenCentral()
}
configurations {
mavenAntTasks
}
dependencies {
mavenAntTasks 'org.apache.maven:maven-ant-tasks:2.1.1'
}
task hello << {
ant.taskdef(resource: 'org/apache/maven/artifact/ant/antlib.xml',
uri: 'antlib:org.apache.maven.artifact.ant',
classpath: configurations.mavenAntTasks.asPath)
ant.mvn(...)
}

Resources