Custom Gradle plugin - sharing data beetwen plugins - gradle

I developed a custom Gradle plugin to read some data from a file but I would like to develop the second one plugin to sending this data to the external server(plugin to sending data should depend on the plugin to reading data). I know that one Gradle plugin can detect the second plugin if there are using in the application. I don't have any idea how to pass or get data(string or dto) from one to another plugin. Is this even possible?

The plugin should provide the reading data logic in a form of a task: readData. Then the second plugin should create a task like sendData.
Once both tasks are created and are working independently of one another, then configure them to depend on one another:
tasks.named("sendData") {
dependsOn(tasks.named("readData")
}
In the above, in order to send data, the reading part needs to happen first.
Reference: https://docs.gradle.org/current/userguide/more_about_tasks.html

You could put all of your DTO's and tasks etc into a "base" plugin. This plugin does not add any tasks to the model, it simply makes them available on the classpath and possibly adds a common extension object to the model
Your "reader" plugin applies the "base" plugin and adds the "reader" tasks to the model
Your "publisher" plugin applies the "base" plugin and adds the "publisher" to tasks the model. These tasks will depend on any "reader" tasks in the model (eg via tasks.withType(...))
Note: Gradle will only ever apply a plugin once to a project. So if "reader" and "publisher" are applied to the same project, the "base" plugin will only be applied once
Gradle uses this pattern internally. Many plugins apply the "base" plugin which adds the clean, check and assemble lifecycle tasks. All the java plugins apply the "java-base" plugin which adds the sourceSets to the model and also applies the "base" plugin

Related

adding other modules in classpath for a Gradle plugin task

I have a Gradle plugin that works well so far, however, I am facing an issue in a multi-module project.
The plugin runs its task in every module of the project, but sometimes, I need to access classes from other modules to analyze them - typically, in the context of hexagonal architecture, I want to perform some checks on classes in infrastructure that implement an interface defined in domain module.
So, when the task runs (after the tests) within infrastructure module, it finds the class. But it's not able to load the interface (from domain) that the class implements. When I do :
Object interfaceLoadedDynamically = Class.forName(i.getName());
I clearly see it can't be loaded, and that prevents me from performing the checks I need to do.
here are :
the plugin
the task
Is there a way to configure one of them to say : "when you run within a module, make sure all the other project modules that have been compiled before are available in the classpath" ?
I've seen maybe I could use Gradle's Configuration , but I am really not sure where/how to start.

Get Gradle Plugins programmatically with Gradle tooling api

I am using Gradle tooling API to get different insights about Gradle projects such as project tasks, Gradle version, and more.
Part of this analysis requires me to know what plugins were applied (directly and transitively) by the project.
I could not find a way to get Project’s plugins from the tooling API.
Is there a way to do it?
The tooling API is limited in how you can query a build and there's no API to list build plugins, but the tooling API allows you to add your own plugins & models which you can use to query the build.
It's a little complex, but you need to add an init script to the build (eg via init.gradle) to provide your custom model & plugin to query the build.
This is a good repo that demonstrates how to do it: https://github.com/melix/gradle-tapi-demo-artifacts
Here's some code from that repo that demonstrates how to list build artifacts with a custom plugin & model:
ModelBuilder<OutgoingArtifactsModel> customModelBuilder = connection.model(OutgoingArtifactsModel.class);
customModelBuilder.withArguments("--init-script", copyInitScript().getAbsolutePath());
OutgoingArtifactsModel model = customModelBuilder.get();
for (File artifact : model.getArtifacts()) {
System.out.println("artifact = " + artifact);
}
If you want to list plugins you can use the project.getPlugins() API.

Alternative way to define bootRun task in Gradle doesn't work

I usually define tasks in Gradle (using Groovy) like tasks.withType(Type); e.g.: tasks.withType(JavaCompile), tasks.withType(Test), etc.
Now, I want to do the same with some provided Spring Boot tasks, namely: bootRun and bootStartScripts, but Gradle cannot find it.
I know it's silly and I could get away just by using bootRun and bootStartScripts, but I would like to understand why those cannot be configured/defined in such way.
I guess with define you mean configure, because withType can only be used to configure existing tasks. It takes a task type (a class) and a closure that can be used to configure all available tasks of that type. This needs to be considered, because a project may contain multiple tasks of the same type that should actually do completely different things. Whether to configure all those tasks or just a specific one is important!
To pass the task type to the method withType you need to know the name of the class implementing the task type. This name is not necessarily related to the name(s) of the actual task(s). For the tasks test and compileJava of the Gradle Java Plugin those classes are org.gradle.api.tasks.testing.Test and org.gradle.api.tasks.compile.JavaCompile. Since those classes are provided by Gradle, they are automatically imported and can be referenced via their simple names Test and JavaCompile. But the Spring Boot Plugin is a third-party plugin, so the classes need to be referenced by their full names.
The task bootStartScripts from your question is of type CreateStartScript, that is provided by Gradle. Therefore it can be configured like this:
tasks.withType(CreateStartScripts) {
// configure
}
The task bootRun is of type org.springframework.boot.gradle.tasks.run.BootRun, that is provided by the Spring Boot Plugin. So you need to specify the full name:
tasks.withType(org.springframework.boot.gradle.tasks.run.BootRun) {
// configure
}

How can you chain/stitch Maven plugins?

I want to chain two Maven plugins which should execute in sequence. The output from the first plugin should be used as input for the second plugin. Let me explain:
I want to write a plugin which generates resources and sources, such as configuration files, Java classes, ... Let's call this plugin generator-plugin.
This plugin needs input information to generate all this. This information can be retrieved from file system or from a SQL database. Possibly, in the future one might introduce several other input sources. My idea is to write two plugins, one for getting all information from the file system and another from a SQL database.
This gives:
information-plugin-file ---\
|--- generator-plugin
information-plugin-sql ---/
How can this be done with Maven? Can you chain plugins? I am familiar with writing basic Mojo's, but I have no idea how to approach this, hence this question.
One possibility is to output to a standardized file in information-plugin-file/information-plugin-sql and let the subsequent generator-plugin plugin read from the same file (the Unix way of working, everything is a file).
But I am looking for more direct, Maven specific approaches of doing this. Are there such approaches?
With regards to execution order, all plugins will run in the generate-sources phases and will be defined in correct order in the <plugins> section. So that is already covered I think.
AFAIK, plugins in maven are designed to be totally independent, so the following methods of sharing the information can be used:
Sharing via maven properties:
Its possible to set a property in the first plugin, and probably it will be accessible from within the second plugin
import org.apache.maven.project.MavenProject;
// now inject it into your mojo of the first plugin
#Parameter(defaultValue = "${project}")
private MavenProject project;
// Inside the "execute" method:
project.getProperties().setProperty("mySampleProperty", <SOME_VALUE_GOES_HERE>);
Sharing via Files
The first plugin can generate some output file in the 'target' folder
And the second plugin can read this file
Write a "wrapping" plugin that executes other plugins (like both first and second plugin). After all mojos are just java code that can be called from the aggregator plugin
You can find Here more information about this method
I believe the only way you can have something ordered in Maven is through lifecycles. You could have your first plugin (for the input information) run in the generate-sources phase, and the second in process-sources phase.

Allow Gradle plugin to use its configuration to conditionally apply other plugins

In the plugin I would like to be able to choose what other plugins apply (e.g. Nexus plugin or Bintray plugin, but not both) based on a configuration placed by a user in the configuration closure for my plugin.
I normally get the configuration for my plugin after the project has been evaluated. That is too late as I would like to allow users to override default configuration for those other plugins in their own (so they have to be applied earlier).
I could split my plugin into two separate plugins (within the same JAR), and require to apply the first one, provide configuration closure, apply the second one and use the configuration provided for the first plugin to decide what 3rd party plugins to apply.
Is there a better way to get the configuration for my plugin early enough to be able to conditionally apply other plugins (and allow them to use their configuration closures)?
You may use gradle 61.5. Init script plugins. This will allow your plugin runs before project configuration.
Example in the gradle documentation remove repositories from your build script. This means that you can read your configuration in a Init script plugin and decide which plugins to apply. Of course your configuration name should be fixed therefore your Init script plugin should be able to read it.

Resources