Programmatically download dependencies in custom gradle task - groovy

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.)

Related

How can a custom gradle task be ran from the body of a build

I have the following custom plugin:
class GenPlugin implements Plugin<Project> {
void apply(Project project) {
project.task("gen", type:GenTask)
}
}
That adds the following task to the project:
class GenTask extends DefaultTask {
#TaskAction
def gen() {
println "hello"
}
}
The groovy code is packaged and deployed to a local maven repository, I then reference the dependency in a build with:
apply plugin: 'gen'
I can run the task successfully by using gradle gen, how can I run this task in my build.gradle without specifying it as an argument?
You can use defaultTasks, have a look at the docs.
Running the task from gradle itself is highly discouraged. You can do it with:
project.tasks.gen.execute()
however I don't recommend you to go that way. Instead you can define a dependency on the task you run from command line. If this task is called e.g. afterGen, then use:
afterGen.dependsOn gen

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 configurations for tasks

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
}

Custom Task/Plugin in gradle

I'm trying to create a custom Task/Plugin (both refuse to work) to use in my gradle build script.
I'm using the groovy plugin and want to declare the Tasks/Plugins in a separate files and not inside my build.gradle.
My project tree is the following:
/project
.
|-gradle
|-src
|---main
|-----groovy
|-----java
|-----resources
|---test
|-----groovy
|-----java
|-----resources
|-build.gradle
What I tried to do, is create my Task/Plugin classes inside src/main/groovy and then use them in my build.gradle.
Let me give a small example.
src/main/groovy/mypackage/TestTask.groovy:
package org.gradle.mypackage
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
public class TestTask extends DefaultTask {
#TaskAction
def doAction() {
}
}
build.gradle
plugins {
id 'groovy'
}
sourceCompatibility = 1.7
repositories {
mavenCentral()
}
dependencies {
compile(
localGroovy(),
gradleApi()
)
testCompile(
[ group: 'junit', name: 'junit', version: '4.11' ]
)
}
task testTask(type: TestTask)
When I try to do anything using my gradle.build (clean, build, etc), I get the following error:
Error:(116, 0) Could not find property 'TestTask' on root project 'project'.
What am I doing wrong? I tried to import the Task in build.gradle using import mypackage.TestTask but that didn't work either.
It looks to me like the groovy files do not compile at all while from what I read in the docs gradle should take care of compiling and adding them in the classpath.
Here you go: "in-stackoverflow" solution.
In your project create folder buildSrc/src/main
Don't forget to create build.gradle in buildSrc/
apply plugin: 'groovy'
dependencies {
compile gradleApi()
compile localGroovy()
}
Now in the main folder create package with your task, for example: pl.myAwesomeCompany.gradle.tasks
package pl.myAwesomeCompany.gradle.tasks
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.incremental.IncrementalTaskInputs
class ExampleTask extends DefaultTask {
#TaskAction
void execute(IncrementalTaskInputs inputs) {
println inputs.incremental ? "CHANGED inputs considered out of date"
: "ALL inputs considered out of date"
}
}
Voila! Now in your project you can use your plugin:
import package pl.myAwesomeCompany.gradle.tasks.ExampleTask
task incremental(type:ExampleTask)
This is not how it works. If you need to provide custom plugins and tasks organized in packages , put the whole code under buildSrc directory. Under $GRADLE_HOME/samples/multiProjectBuildSrc You can find excellent example how it should be done.
$GRADLE_HOME - gradle installation directory.

Specify ivy configuration in gradle dependency

I want to resolve dependencies from ivy repository but I don't know how to specify ivy configuration for it. I found that I should do it in this way:
myconf group: 'com.eu', module:'MyModule', version:'1.0.0', configuration: 'ivyconf'
but it doesn't work. When I run gradle dependencies command gradle returns this error:
Could not create a dependency using notation: {group=com.eu, module=MyModule, version=1.0.0, configuration=ivyconf}
My build doesn't use plugins. I want to download dependencies in simple build which should create product from downloaded dependencies.
Build looks like this:
group = 'com.eu'
version = '0.9a'
configurations {
myconf
}
repositories {
ivy {
url 'http://ivyrepo.local/ivyrep/shared'
layout "pattern", {
artifact "[organisation]/[module]/[revision]/[type]s/[artifact].[ext]"
}
}
}
dependencies {
myconf group: 'com.eu', module:'MyModule', version:'1.0.0', configuration: 'ivyconf'
}
Instead of module, it has to be name. (see "49.4. How to declare your dependencies" in the Gradle User Guide). The declared configuration (myConf) must match the configuration used in the dependencies block (installer).

Resources