how to use a plugin inside a groovy plugin - gradle

I am trying to migrate tasks from build.gradle to a plugin that do it.
In my build.gradle I do this:
plugins {
//id 'java'
id 'war'
//https://plugins.gradle.org/plugin/org.gretty
id 'org.gretty' version '3.0.1'
id "com.github.dkorotych.gradle-maven-exec" version "2.2.1"
}
apply plugin: 'maven'
....
....
prepareFrontEnd (type: MavenExec, dependsOn: build) {
goals 'vaadin:prepare-frontend'
}
task buildFrontEnd (type: MavenExec, dependsOn: prepareFrontEnd) {
goals 'vaadin:build-frontend'
}
Now I am moving this stuff to a plugins:
package com.github.mdre.hgvaadinplugin
import org.gradle.api.Plugin;
import org.gradle.api.Project;
//import com.github.dkorotych.gradle.maven.exec.MavenExec;
class HGVaadinPlugin implements Plugin<Project> {
#Override
void apply(Project project) {
println "Hybrid Gradle Vaaadin plugin."
project.plugins.apply('com.github.dkorotych.gradle-maven-exec')
// project.getPluginManager().apply('gradle-maven-exec-plugin')
project.task('prepareFrontEnd', type: MavenExec){
dependsOn build
doLast {
goal 'vaadin:prepare-frontend'
}
}
}
}
If I try to import the class MavenExec I get this error:
> Task :compileGroovy FAILED
startup failed:
/home/mdre/Proyectos/HGVaadinPlugin/src/main/groovy/com/github/mdre/hgvaadinplugin/HGVaadinPlugin.groovy: 5: unable to resolve class com.github.dkorotych.gradle.maven.exec.MavenExec
# line 5, column 1.
import com.github.dkorotych.gradle.maven.exec.MavenExec;
^
and if I comment the import line, I get this error in the project that use the plugin:
What went wrong:
A problem occurred evaluating root project 'VaadinFlowLab'.
Failed to apply plugin [id 'com.github.mdre.hgvaadinplugin']
No such property: MavenExec for class: com.github.mdre.hgvaadinplugin.HGVaadinPlugin
How could I do this?
Thanks.

Well, I fix it!
I forget to include the dependency class in the final jar. So all of I need was to add this to the build.config:
configurations {
// configuration that holds jars to include in the jar
extraLibs
}
dependencies {
....
....
//necesario para crear un fatJar
extraLibs "gradle.plugin.com.github.dkorotych.gradle.maven.exec:gradle-maven-exec-plugin:2.2.1"
configurations.compile.extendsFrom(configurations.extraLibs)
}
jar {
from {
configurations.extraLibs.collect { it.isDirectory() ? it : zipTree(it) }
}
}
and now it is working!!

Related

Adding a Spring dependency into a gradle task

I want to add a special gradle task on my machine as an init script. The script is in ~/.gradle/init.d. Let's call it servertest.gradle. It looks like this:
import org.springframework.http.MediaType
allprojects {
task servertest {
doLast {
MediaType.parseMediaType("application/json")
}
}
}
I can run the task, but it says this:
> startup failed:
initialization script '/home/user1/.gradle/init.d/servertest.gradle': 1: unable to resolve class org.springframework.http.MediaType
# line 1, column 1.
import org.springframework.http.MediaType
^
1 error
Of course, what I really need to do is more complicated than this, but this is a simplified example of using a Spring Library in a Gradle Task.
How do I import the spring libraries into a task?
Basically, dependency missing.
The MediaType class is in spring-web library.
Here is how the gradle file with dependency should look like:
import org.springframework.http.MediaType
initscript {
repositories {
mavenCentral()
}
dependencies {
// https://mvnrepository.com/artifact/org.springframework/spring-web
classpath group: 'org.springframework', name: 'spring-web', version: '4.3.11.RELEASE'
}
}
allprojects {
task servertest {
doLast {
MediaType.parseMediaType("application/json")
}
}
}

Gradle: how to make rule-created ZipTask as maven publication artifact

I want to create a maven publication from inside a RuleSource that will be published via the maven-publish plugin. The artifacts of the publication are the outputs from a series of Zip tasks that are created from rules. When I try to add the artifacts, I get a circular rule exception.
Here is my very simple build.gradle:
buildscript {
repositories {
mavenCentral()
}
dependencies {
}
}
task wrapper(type: Wrapper) {
gradleVersion = '3.3'
}
apply plugin: 'groovy'
apply plugin: 'testpub'
repositories {
mavenCentral()
}
dependencies {
compile 'org.codehaus.groovy:groovy-all:2.4.7'
}
The testpub plugin exists in the buildSrc directory. To be able to apply it as above, it requires the following properties file:
// buildSrc/src/main/resources/META_INF/gradle-plugins/testpub.properties
implementation-class=TestPubPlugin
Here is the very simple plugin file:
import org.gradle.api.Project
import org.gradle.api.Plugin
import org.gradle.model.RuleSource
import org.gradle.api.Task
import org.gradle.model.Mutate
import org.gradle.model.Finalize
import org.gradle.api.tasks.bundling.Zip
import org.gradle.model.ModelMap
import org.gradle.api.publish.PublishingExtension
import org.gradle.api.publish.maven.MavenPublication
class TestPubPlugin implements Plugin<Project> {
void apply(Project project) {
project.configure(project) {
apply plugin: 'maven-publish'
publishing {
repositories {
maven {
url "someUrl"
}
}
}
}
}
static class TestPubPluginRules extends RuleSource {
#Mutate
public void createSomeTasks(final ModelMap<Task> tasks) {
5.times { suffix ->
tasks.create("someTask${suffix}", Zip) {
from "src"
destinationDir(new File("build"))
baseName "someZip${suffix}"
}
}
}
#Mutate
public void configurePublishingPublications(final PublishingExtension publishing, final ModelMap<Task> tasks) {
// Intention is to create a single publication whose artifacts are formed by the `someTaskx` tasks
// where x = [0..4]
publishing {
publications {
mavPub(MavenPublication) {
tasks.matching {it.name.startsWith('someTask')}.each { task ->
artifact(task)
}
}
}
}
}
}
}
The plugin creates a number of tasks called someTaskx where x=[0..4]. They simply zip up the src directory. I want to add the output files as artifacts to the single MavenPublication. However, I get the following exception:
* What went wrong:
A problem occurred configuring root project 'testpub'.
> A cycle has been detected in model rule dependencies. References forming the cycle:
tasks
\- TestPubPlugin.TestPubPluginRules#createSomeTasks(ModelMap<Task>)
\- MavenPublishPlugin.Rules#realizePublishingTasks(ModelMap<Task>, PublishingExtension, File)
\- PublishingPlugin.Rules#tasksDependOnProjectPublicationRegistry(ModelMap<Task>, ProjectPublicationRegistry)
\- projectPublicationRegistry
\- PublishingPlugin.Rules#addConfiguredPublicationsToProjectPublicationRegistry(ProjectPublicationRegistry, PublishingExtension, ProjectIdentifier)
\- publishing
\- TestPubPlugin.TestPubPluginRules#configurePublishingPublications(PublishingExtension, ModelMap<Task>)
\- tasks
What is wrong and how do I fix it?
I don't fully understand why is this a "cycle", but the rule methods always have one mutable part (the subject) and zero or more immutable (the inputs). In your second method, you are passing the publishing as the subject you want to change and the tasks as the input. I thought that would be ok, but obviously it isn't.
You might have tried to switch the method arguments, pass the tasks first and then the PublishingExtension, but you would likely not be able to change it (as gradle docs say it's immutable).
I am not sure what exactly is your use case and there might be an easier solution that doesn't use the rules, or plugin at all. Maybe you could ask another question with the original requirement instead of this specific problem.
But back to your issue. The solution to your problem might be something like this:
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.publish.PublishingExtension
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.api.tasks.bundling.Zip
import org.gradle.model.Defaults
import org.gradle.model.ModelMap
import org.gradle.model.Mutate
import org.gradle.model.RuleSource
class TestPubPlugin implements Plugin<Project> {
void apply(Project project) {
project.configure(project) {
apply plugin: 'maven-publish'
publishing {
publications {
maven(MavenPublication) {
groupId 'com.example'
artifactId 'artifact'
}
}
repositories {
maven {
url "someUrl"
}
}
}
}
}
static class TestPubPluginRules extends RuleSource {
static final def buffer = []
#Defaults
public void createSomeTasks(final ModelMap<Task> tasks) {
5.times { suffix ->
tasks.create("someTask${suffix}", Zip) {
from "src"
destinationDir(new File("build"))
baseName "someZip${suffix}"
}
}
tasks.each { task ->
if (task.name.startsWith('someTask'))
buffer << task
}
}
#Mutate
public void configurePublishingPublications(PublishingExtension extension) {
MavenPublication p = extension.publications[0]
buffer.each { task ->
p.artifact(task)
}
}
}
}
The hack here is to run the mutator of the tasks first (#Defaults phase should run before #Mutate) and save the tasks, so we don't need to ask for them later. Rules can include static final fields, so we use a list here.
Then we run the publication enhancer. The code you have used won't work. It works in the config part, but not in the groovy class. So I have prepared the publication and then just added the artifacts from the buffer.
I ran gradlew publish and got:
Execution failed for task ':publishMavenPublicationToMavenRepository'.
> Failed to publish publication 'maven' to repository 'maven'
> Invalid publication 'maven': artifact file does not exist: 'build\someZip0.zip'
So it seems it's working.

How to load Gradle Plugin (with its depenecies) into build.gradle?

I have a project that has two gradle files: build.gradle and myPlugin.gradle
The myPlugin.gradle implemented the Plugin Interface. The plugin also has a dependency on osdetector-gradle-plugin
I added the two gradle files beside each other then I tried to apply myPlugin into build.gradle as follows:
apply from: 'myPlugin.gradle'
However, I have got the following error in myPlugin.gradle file:
Plugin with id 'com.google.osdetector' not found
Here is the code for myPlugin.gradle file:
apply plugin: 'groovy'
apply plugin: 'maven'
repositories {
mavenCentral()
mavenLocal()
}
dependencies {
compile 'com.google.gradle:osdetector-gradle-plugin:1.4.0'
}
import org.gradle.api.tasks.TaskAction
import org.gradle.api.DefaultTask
import org.gradle.api.Plugin
import org.gradle.api.Project
apply plugin: 'com.google.osdetector'
apply plugin: HostingMachineOSPlugin
class HostingMachineOSPlugin implements Plugin<Project>{
void apply(Project project){
project.plugins.apply("com.google.osdetector");
//project.configurations.files('com.google.osdetector')
println project.osdetector.os
/* Extend the project property to have the class HostingMachineOS */
project.ext.HostingMachineOS = HostingMachineOS
}
}
public class HostingMachineOS {
static family = "Unkown"
static def setFamilyName(name){
family = name
}
static def isLinux (){
family == "linux"
}
static def isWindows (){
family == "windows"
}
static def isMacOS(){
family == "osx"
}
}
HostingMachineOS.setFamilyName(osdetector.os)
in build.gradle file: I am just doing something like this:
//define buildScript repositories and dependencies then
apply from: 'myPlugin.gradle'
task dummy{
println HostingMachineOS.isMacOS()
println HostingMachineOS.isLinux()
println HostingMachineOS.isWindows()
}
How can I solve the Plugin with id 'com.google.osdetector' not found?
This is a common pitfall, to add a plugin to build.gradle file you need to add a dependency for the build script itself - not for the project. The following piece of code (added in the file where you apply the plugin) should solve the problem:
buildscript {
repositories {
mavenCentral()
mavenLocal()
}
dependencies {
classpath 'com.google.gradle:osdetector-gradle-plugin:1.4.0'
}
}
EDIT
Please have a look here - it seems that if you need to apply from third-party script you need to use the full class name (with package). So the files should be defined as follows:
build.gradle
apply from: 'myPlugin.gradle'
task dummy{
println HostingMachineOS.isMacOS()
println HostingMachineOS.isLinux()
println HostingMachineOS.isWindows()
}
myPlugin.gradle
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.google.gradle:osdetector-gradle-plugin:1.4.0'
}
}
apply plugin: 'groovy'
apply plugin: 'maven'
apply plugin: com.google.gradle.osdetector.OsDetectorPlugin
apply plugin: HostingMachineOSPlugin
class HostingMachineOSPlugin implements Plugin<Project>{
void apply(Project project){
project.plugins.apply(com.google.gradle.osdetector.OsDetectorPlugin);
//project.configurations.files('com.google.osdetector')
println project.osdetector.os
/* Extend the project property to have the class HostingMachineOS */
project.ext.HostingMachineOS = HostingMachineOS
}
}
public class HostingMachineOS {
static family = "Unkown"
static def setFamilyName(name){
family = name
}
static def isLinux (){
family == "linux"
}
static def isWindows (){
family == "windows"
}
static def isMacOS(){
family == "osx"
}
}
HostingMachineOS.setFamilyName(osdetector.os)

Not able to execute Jbehave with Gradle using Serenity Framewrok

I am using Serenity - JBehave framework. After creation of sample script, I am able to execute Junit runner class from eClipse however when I am trying to execute any of the below command from command prompt it is giving me error.
$gradle clean test aggregate
$gradle clean test
$gradle clean build
The error message is same in all cases, as below:
org.gradle.TestRunnerClass > initializationError FAILED
java.lang.RuntimeException
Caused by: java.lang.RuntimeException
Caused by: java.lang.IllegalArgumentException
Caused by: java.lang.ClassNotFoundException
1 test completed, 1 failed
:test FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':test'.
> There were failing tests. See the report at: file:///C:/$ /build/reports/tests/index.html
Below are the details:
Test Runner class:
package org.gradle;
import net.serenitybdd.jbehave.SerenityStories;
public class TestRunnerClass extends SerenityStories{}
Sample Step Definition class:
package org.gradle.stepDef;
import net.thucydides.core.annotations.Step;
import net.thucydides.core.annotations.Steps;
import org.jbehave.core.annotations.Given;
import org.jbehave.core.annotations.Then;
import org.jbehave.core.annotations.When;
public class StepDefSticky {
#Given("User is on Sticky note home page")
public void givenUserIsOnStickyNoteHomePage() {
System.out.println("I am in Given");
}
#When("User clicks on Add Note button")
public void whenUserClicksOnAddNoteButton() {
System.out.println("I am in When");
}
#Then("Sticky note pop up should get open")
public void thenStickyNotePopUpShouldGetOpen() {
System.out.println("I am in Then");
}
}
Please see the package structure carefully.
Below is the build.gradle I am using
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'net.serenity-bdd.aggregator'
apply plugin: 'com.jfrog.bintray'
sourceCompatibility = 1.8
version = '1.0'
def poiVersion = "3.10.1"
repositories {
maven { url "repoUrl" }
}
buildscript {
repositories {
maven { url "repoURL" }
}
dependencies {
classpath("net.serenity-bdd:serenity-gradle-plugin:1.0.47")
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:0.6'
classpath 'org.ajoberstar:gradle-git:0.12.0'
}
}
ext {
bintrayBaseUrl = 'https://api.bintray.com/maven'
bintrayRepository = 'maven'
bintrayPackage = 'serenity-cucumber'
projectDescription = 'Serenity Cucumber integration'
if (!project.hasProperty("bintrayUsername")) {
bintrayUsername = 'wakaleo'
}
if (!project.hasProperty("bintrayApiKey")) {
bintrayApiKey = ''
}
serenityCoreVersion = '1.0.47'
cucumberJVMVersion = '1.2.2'
}
dependencies {
testCompile('junit:junit:4.11')
testCompile('org.assertj:assertj-core:1.7.0')
testCompile('org.slf4j:slf4j-simple:1.7.7')
//JBehave jar files
testCompile 'net.serenity-bdd:core:1.0.47'
testCompile 'net.serenity-bdd:serenity-jbehave:1.0.21'
testCompile 'net.serenity-bdd:serenity-junit:1.0.47'
// Apache POI plugin for excel read
compile "org.apache.poi:poi:${poiVersion}"
compile "org.apache.poi:poi-ooxml:${poiVersion}"
compile "org.apache.poi:ooxml-schemas:1.1"
}
gradle.startParameter.continueOnFailure = true
uploadArchives {
repositories { flatDir { dirs 'repos' } }
}
task wrapper(type: Wrapper) { gradleVersion = '2.3' }
I have stored the .story file under the src/test/resources package.
Please help me to understand where I am making mistake. Thanks for your help on this.
Enable standard out and standard error in your build.gradle file:
test {
testLogging {
showStandardStreams = true
}
}
And to make sure all your stories run, add a TestSuite class:
#RunWith(Suite.class)
#SuiteClasses({ Story1.class, Story2.class})
public class TestSuite { }
Note: Story1 & Story2 are the names of the test runners to match a JBehave Gherkin files named Story1.story & Story2.story & step files names Story1Steps.java & Story2Steps.java according to Serenity naming conventions.

How to apply a Gradle plugin from another plugin?

I'm trying to encapsulate android plugin in my own plugin, but when I'm trying to apply my plugin build fails with an exception:
A problem occurred evaluating root project 'myproj'.
> Failed to apply plugin [id 'com.mycomp.build']
> Failed to apply plugin [id 'android-library']
> Plugin with id 'android-library' not found.
Here is how I'm applying android plugin inside my own plugin's implementation:
// build.gradle
apply plugin: 'groovy'
version = '1.0'
group = 'com.mycomp'
dependencies {
compile gradleApi()
compile localGroovy()
}
// Build.groovy
package com.mycomp
import org.gradle.api.Plugin
import org.gradle.api.Project
class Build implements Plugin<Project> {
void apply(Project project) {
println 'Hello from com.mycomp.Build'
project.beforeEvaluate {
buildscript.configurations.classpath +=
'com.android.tools.build:gradle:1.0.0-rc1'
}
project.configure(project) {
buildscript.repositories.mavenCentral()
apply plugin: 'android-library'
}
}
}
For some reason a classpath is not being properly loaded, what am I doing wrong?
I guess that at the time you'd like to add the plugin dependencies for the build script have been already resolved, thus it won't work that way. You need to specify the plugin You'd like to apply as a script dependency itself.
It will work that way:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.0.0-rc1'
}
}
apply plugin: 'groovy'
apply plugin: Build
version = '1.0'
group = 'com.mycomp'
dependencies {
compile gradleApi()
compile localGroovy()
}
import org.gradle.api.Plugin
import org.gradle.api.Project
class Build implements Plugin<Project> {
void apply(Project project) {
project.configure(project) {
apply plugin: 'android-library'
}
}
}
Now, android-plugin is found but it fails because of the fact that groovy plugin had been applied earlier and there's a conflict.
Use the project's PluginManager. For example, the war plugin pulls in the java plugin like this:
public class WarPlugin implements Plugin<Project> {
// ...
public void apply(final Project project) {
project.getPluginManager().apply(org.gradle.api.plugins.JavaPlugin.class);
// ...
}
// ...
}

Resources