How to add a custom gradle plugin to Intellij Idea? - gradle

I created a simple gradle plugin according to the documentation.
class MyBuild implements Plugin<Project> {
#Override
void apply(Project project) {
project.task("test") {
doLast{
println 'Yeaaa boy!'
}
}
}
}
apply plugin: MyBuild
But the plugin does not appear at the Idea Gradle toolar:
I have also tried to add the following code, but it does not make any diffirence:
idea {
project {
jdkName = '1.8'
languageLevel = '1.8'
}
apply plugin: MyBuild
}
What should I do to make it appear there?

What exactly do you expect to see there? For example, I see the custom task, that the plugin adds here, in Gradle tool window:

Related

Task 'run' not found in root project

My "build.gradle" file:
apply plugin: 'java'
sourceSets {
main {
java {
srcDir 'src'
}
}
test {
java {
srcDir 'test'
}
}
}
My "Main.java" file in "./src/" directory:
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) {
System.out.println("Hello Gradle");
}
}
I get this error:
Task 'run' not found in root project 'gradleNew'
Sorry for the stupid question... I didn't use Gradle before
The java plugin does not include the run task, which I suppose your gradle build requires somewhere in your app.
Change the java plugin to application and you should be fine.
To verify this, you can go to your project folder inside you terminal and run gradle tasks. You should see the run task listed among other tasks.
I hope that helps.
I just add this code and my app run:
plugins {
id 'application'
}
Try this instead:
group 'com.example'
version '1.0'
apply plugin: 'application' // implicitly includes the java plugin
sourceCompatibility = 1.11 // java version 11
repositories {
mavenCentral()
}
dependencies {
// your dependencies
}
sourceSets {
main {
java {
srcDirs = ['src/main/java']
}
resources {
srcDirs = ['src/main/resources']
}
}
}
I typically use something similar to this for my projects. You can then explicitly create the relevant dirs for src/test code, or sometimes the IDE will do it for you when you point it to the relevant build.gradle file (you can typically restart the IDE and it will pick up the file, or you can open a new project and select the build.gradle file as the project to open if it doesn't identify it right away).

Create custom plugin that defines plugins and dependencies

My organization uses the same Gradle plugins and dependencies for a lot of our projects. My custom plugin knowledge is pretty weak, but what I'd like to do is wrap these plugins and dependencies into a single, standalone plugin. I'm stuck on understanding how to separate the plugins/dependencies required for the plugin versus the ones that I want to use in the consuming project. Here's a simple example that I put together based on the gradle custom plugin docs, and some information about storing the plugin in a maven repo to allow it to automatically download dependencies:
// build.gradle from standalone plugin
plugins {
id 'java-gradle-plugin'
id 'maven-publish'
// these ones I don't need in the plugin, just in the project where I apply the plugin
id 'war'
id 'org.springframework.boot' version '2.2.4.RELEASE'
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
id 'org.asciidoctor.convert' version '1.5.8'
}
group = 'org.sample'
version = '1.0.0'
publishing {
repositories {
maven {
url "../maven-repo"
}
}
}
gradlePlugin {
plugins {
greeting {
id = "org.sample.greeter"
implementationClass = "org.sample.GreetingPlugin"
}
}
}
dependencies {
implementation gradleApi() // I think I need this for the imports in GreetingPlugin.java
implementation localGroovy() // I think I would need this if GreetingPlugin was written in Groovy
// these ones I don't need in the plugin, just in the project where I apply the plugin
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test' {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
testImplementation 'org.junit.jupiter:junit-jupiter-engine'
}
// this is only needed in the project where I apply the plugin
// I believe this should be in the GreetingPlugin.java file though
test {
useJUnitPlatform()
}
and the backing class...
package org.sample;
import org.gradle.api.DefaultTask;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.tasks.TaskAction;
class Greeting Plugin implements Plugin<Project> {
#Override
public void apply(Project project) {
project.getTasks().create("hello", MyTask.class);
}
public static class MyTask extends DefaultTask {
#TaskAction
public void myTask() {
System.out.println("Hello, World!");
}
}
}
In the project I'm trying to consume the plugin, I have the following files:
// settings.gradle
pluginManagement {
repositories {
maven {
url "../maven-repo"
}
gradlePluginPortal()
}
}
// build.gradle
plugins {
id 'org.sample.greeter' version '1.0.0'
}
My thinking is that using the plugin in this way, the project inherits the plugins and dependencies listed in the plugin code. I think I'm close, as when I ./gradlew publish I can see the plugin being applied, but it doesn't like that the spring-starter-web dependency doesn't have a version (I know that when I do a multi-project gradle repo, I need to include the dependencyManagement block with mavenBOM, so maybe that's the key?) I'm trying to follow the SpringBoot gradle plugin for insight, but it's a bit too complicated for me.
So, is this the correct way to create a standalone plugin that includes plugins/dependencies baked in? And why isn't the spring dependency manager applying the versioning?
EDIT: I followed the link from #Alan Hay, and instead of a custom plugin, I tried to use the 'apply from'. However, it still doesn't work. Here's files based on that approach:
// build.gradle from 'parent' build.gradle
plugins {
id 'war'
id 'org.springframework.boot' version '2.2.4.RELEASE'
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
id 'org.asciidoctor.convert' version '1.5.8'
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test' {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
testImplementation 'org.junit.jupiter:junit-jupiter-engine'
}
test {
useJUnitPlatform()
}
and attempting to reference from another project, it's the only line in the file:
apply from: '<path-to-above>/build.gradle'
This error I get is the following:
script '<path-to-above>/build.gradle': 15: Only Project build scripts can contain plugins {} blocks
See https://docs.gradle.org/5.5.1/userguide/plugins.html#sec:plugins_block for information on the plugins {} block
# line 15, column 1.
plugins {
^
1 error
A standalone, binary plugin is the preferred approach when you need to share the same build logic across multiple independent projects. Additionally, good plugin design separates capabilities from convention. In this case, the capabilities are provided by Gradle and some third-party plugins, but you're adding your own conventions on top in this plugin.
When you're implementing this, you essentially need to push the code down one level. Anything that would be configuration in the build.gradle needs to be in your plugin's source code. Anything that would impact the classpath of the buildscript (i.e. buildscript { } or plugins { }) belongs in the dependencies of your plugin. The plugins { } block in your plugin should only have the build plugins required the build the plugin itself.
// build.gradle from standalone plugin
// plugins {} should contain only plugins you need in the build of the plugin itself
plugins {
id 'java-gradle-plugin'
id 'maven-publish'
}
group = 'org.sample'
version = '1.0.0'
dependencies {
implementation gradleApi()
// Dependencies for plugins you will apply to the target build
implementation 'io.spring.gradle:dependency-management-plugin:1.0.9.RELEASE'
implementation 'org.asciidoctor:asciidoctor-gradle-jvm:2.4.0'
implementation 'org.springframework.boot:spring-boot-gradle-plugin:2.2.4.RELEASE'
}
gradlePlugin {
plugins {
greeting {
id = "org.sample.greeter"
implementationClass = "org.sample.GreetingPlugin"
}
}
}
publishing {
repositories {
maven {
url "../maven-repo"
}
}
}
package org.sample;
import org.gradle.api.DefaultTask;
import org.gradle.api.Plugin;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.Project;
import org.gradle.api.tasks.TaskAction;
import org.gradle.api.tasks.testing.Test;
class Greeting Plugin implements Plugin<Project> {
#Override
public void apply(Project project) {
// Apply plugins to the project (already on the classpath)
project.getPluginManager().apply("war");
project.getPluginManager().apply("org.springframework.boot");
project.getPluginManager().apply("io.spring.dependency-management");
project.getPluginManager().apply(" org.asciidoctor.convert");
// Dependencies that you need for the code in the project that this plugin is applied
DependencyHandler dependencies = project.getDependencies();
dependencies.add(JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME, "org.springframework.boot:spring-boot-starter-web");
dependencies.add(JavaPlugin.TEST_IMPLEMENTATION_CONFIGURATION_NAME, "org.junit.jupiter:junit-jupiter-engine");
dependencies.add(JavaPlugin.TEST_IMPLEMENTATION_CONFIGURATION_NAME, springBootStarterTest(dependencies));
projects.getTasks().withType(Test.class, test -> {
test.useJUnitPlatform();
});
}
private Dependency springBootStarterTest(DependencyHandler dependencies) {
Map<String, String> exclude = new HashMap<>();
exclude.put("group", "org.junit.vintage");
exclude.put("module", "junit-vintage-engine");
return ((ModuleDependency) dependencies.module("org.springframework.boot:spring-boot-starter-test")).exclude(exclude);
}
}
This is more verbose due to being written in Java, but it is functionally equivalent to putting this in your project's build.gradle:
plugins {
id 'war'
id 'org.springframework.boot' version '2.2.4.RELEASE'
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
id 'org.asciidoctor.convert' version '1.5.8'
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test' {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
testImplementation 'org.junit.jupiter:junit-jupiter-engine'
}
test {
useJUnitPlatform()
}

How to I preset a repository section in a gradle plugin?

I would like to define a plugin which sets the repositories{...} section in a gradle project to use our approved proxies and repos, and removes the need to define them in every project. How do I do that?
You can do it e.g. in the following way:
apply plugin: 'java'
apply plugin: Lol
dependencies {
compile 'com.google.guava:guava:18.0'
}
task cl(type: Copy) {
from configurations.compile
into 'libs'
}
class Lol implements Plugin<Project> {
void apply(Project p) {
def repositoriesConf = {
mavenCentral()
jcenter()
}
p.repositories(repositoriesConf)
}
}
There're really many different ways of implementing this task. Pay attention to the fact that also java plugin will be needed and maybe the plugin you need to implement should apply java plugin as well.

How do I set task properties in a Gradle Plugin

I am creating a gradle plugin to apply the sonar-runner plugin and default many of the values such as the sonar host URL and the sonar JDBC URL. I cannot figure out how to set the properties though.
When I set this up in build.gradle I use:
apply plugin: 'sonar-runner'
sonarRunner {
sonarProperties {
property 'sonar.host.url', 'http://mySonar.company.com'
property 'sonar.jdbc.url', 'jdbc:mysql://127.0.0.1:1234/sonar'
}
}
My gradle plugin looks like:
class MySonarPlugin implements Plugin<Project> {
#Override
void apply(Project project) {
project.apply plugin: 'sonar-runner'
project.configurations {
sonarRunner {
sonarProperties {
property 'sonar.host.url', 'http://mySonar.company.com'
property 'sonar.jdbc.url', 'jdbc:mysql://127.0.0.1:1234/sonar'
}
}
}
}
}
With this setup I get a No signature of method exception. How should I be setting these properties?
I discovered that I could use project.getExtensions().sonarRunner.sonarProperties{ ... } to set the sonar properties. See example below.
class MySonarPlugin implements Plugin<Project> {
#Override
void apply(Project project) {
project.apply plugin:'sonar-runner'
project.getExtensions().sonarRunner.sonarProperties {
property 'sonar.host.url', 'http://mySonar.company.com'
property 'sonar.jdbc.url', 'jdbc:mysql://127.0.0.1:1234/sonar'
}
}
}
Thank you #mikerylander and #ravikanth! I also had tried the setProperty and .properties solutions but they didn't work for me.
The really tricky thing was that autocomplete did not find the "sonarqube" portion of project.getExtensions().sonarqube.properties for me so I never got to this solution without your post.
I wrote a custom Gradle plugin to run sonarqube for a multi-module Android project and your post helped me. Below is my full custom plugin. Since the plugin is designed to be included in the build.gradle of any submodule of my Android project I prepended "my_product" ${project.path} but of course you can use any values here.
Here is my complete plugin code in case its helpful:
package com.example.gradle.plugins
import org.gradle.api.Plugin
import org.gradle.api.Project
class MySonarCodeCoveragePlugin implements Plugin<Project> {
private Project project
void apply(Project project) {
this.project = project
project.apply plugin: 'org.sonarqube'
project.getExtensions().sonarqube.properties
{
property "sonar.sources", "${project.projectDir}/src/main"
property "sonar.organization", "my_org"
property "sonar.projectKey", "my_product${project.path}"
property "sonar.projectName", "my_product${project.path}"
property "sonar.coverage.jacoco.xmlReportPaths", "${project.buildDir}/reports/jacoco/jacocoTestReport/jacocoTestReport.xml"
property "sonar.scanner.metadataFilePath", "${project.buildDir}/sonar/report-task.txt"
}
}
}

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