How to package a Gradle plugin? - gradle

I'm having trouble figuring out what META-INF/gradle-plugins/plugin.properties has to match. There are two issues here. One is the name of the properties file and one is the value therein set to implementation-class. So here is my question as succinctly as I can put it.
If I have:
META-INF/gradle-plugins/com.my.plugin.properties
What portion of the source plugin does the file name map to? What are the implications of this name? It's source and destination? Am I doing the name correctly or should it not be so qualified?
If inside the file I have:
implementation-class=build.WeirdoPlugin
What are the source and destination of this name?

implementation-class should point to the your main plugin class that implementsPlugin<>
for example, in jmeter-gradle-plugin/src/main/resources/META-INF/gradle-plugins/net.foragerr.FooPlugin.properties
implementation-class=net.foragerr.soanswers.FooPluginImpl
I will then implement a class:
package net.foragerr.soanswers
class FooPluginImpl implements Plugin<Project>{
...
}
To use the plugin, you apply it as (in the new gradle format):
plugins {
id "net.foragerr.FooPlugin" version "xxx"
}

Related

What does create method do in gradlePlugin.plugins?

In the gradle doc: https://docs.gradle.org/current/userguide/custom_plugins.html#sec:custom_plugins_standalone_project
The code block is:
gradlePlugin {
plugins {
create("simplePlugin") {
id = "org.example.greeting"
implementationClass = "org.example.GreetingPlugin"
}
}
}
I noticed it calls create method. And I looked the source code. It says:
Creates a new item with the given name, adding it to this container,
then configuring it with the given action.
What does it mean? Is it actually used anywhere? Or it can be any name does not really matter?
gradlePlugin.plugins is a NamedDomainObjectContainer - which are used by Gradle to hold multiple objects, each with a name.
The documentation on plugin development goes into more detail on the usage of NamedDomainObjectContainers.
Sometimes you might want to expose a way for users to define multiple, named data objects of the same type.
[...]
It’s very common for a plugin to post-process the captured values within the plugin implementation e.g. to configure tasks.
Since the elements of a NamedDomainObjectContainer can be any type, there's no specific usage for one. Generally they are used to configure the Gradle project, for example creating specific tasks, configuring source code locations.

How to import a class from a Jenkins Shared Library into the pipeline

I was using some global methods in the /var directory of the shared library, and everything worked fine. Now I need to keep the state of the process, so I'm writting a groovy class.
Basically I have a class called 'ClassTest.groovy' in '/src' which is something like this;
class ClassTest {
String testString
def method1() { ... }
def method2() { ... }
}
and at the begining of the pipeline
library 'testlibrary#'
import ClassTest
with result:
WorkflowScript: 2: unable to resolve class ClassTest #line 2, column 1.
import ClassTest
before, I was just goind
library 'testlibrary#' _
and using the methods as
script {
libraryTest.method1()
...
libraryTest.method2()
}
where the methods were in a file '/var/libraryTest.groovy' and everything worked. So I know that the shared library is there, but I'm confused with the way groovy / Jenkins handle classes / shared libraries.
What's the correct way to import a class? I cannot find a simple example (with groovy file, file structure and pipeline) in the documentation.
EDIT:
I moved the file to 'src/com/company/ClassTest.groovy' and modified the pipeline as
#Library('testlibrary#') import com.company.ClassTest
def notification = new ClassTest()
but now the error is
unexpected token: package # line 2
the first two lines of the groovy file are:
// src/com/company/ClassTest.groovy
package com.company;
So far this is what I've found.
To load the library in the pipeline I used:
#Library('testlibrary#') import com.company.ClassTest
def notification = new ClassTest()
In the class file, no package instruction. I guess that I don't need one because I don't have any other files or classes, so I don't really need a package. Also, I got an error when using the same name for the class and for the file where the class is. The error specifically complained and asked for one of them to be changed. I guess this two things are related to Jenkins.
That works, and the library is loaded.
(Maybe it can help someone else)
I was having the same issue.
Once I added a package-info.java inside the folder com/lib/, containing
/**
* com.lib package
*/
package com.lib;
and adding package com.lib at the first line of each file, it started to work.
I had the same problem.
After some trial and error with the docs of Jenkins.(https://www.jenkins.io/doc/book/pipeline/shared-libraries/#using-libraries)
I found that when I wanted to import a class from the shared library I have, I needed to do it like this:
//thanks to '_', the classes are imported automatically.
// MUST have the '#' at the beginning, other wise it will not work.
#Library('my-shared-library#BRANCH') _
// only by calling them you can tell if they exist or not.
def exampleObject = new example.GlobalVars()
// then call methods or attributes from the class.
exampleObject.runExample()

How to reference a module property in tibco-bw6 from XPath

I'm trying to reference a module property from tibco business works 6.
Do you guys have an example about the getModuleProperty("")?
What kind of input should I use?
Should I use the entire path or just the name of the property?
You need to first add a process property to your process (it's under properties if you click outside of the main process area). In there you can reference a module property. You can then use the process property in XPath.
First off, you need to include a few dependencies in your project. (Documented here)
Then write some code access the properties
#ModuleProperties
public void loadProperties(HashMap<String, String> moduleProperties){
this.myClassProperty = moduleProperties.get("/DB/Property"); // Case Sensitive Path
System.out.println("Completed loading module properties.");
}
You have to use the entire path of the property. you can get it from the META-INF/default.substvar file.

HOCON: multiple reference.conf resolution issue

I have multi-module project under SBT.
Project A (library) has reference.conf file with A's configuration parameters. Project A depends on akka-actor library, which ships with its own reference.conf file. Project A redefines some akka's parameters in own reference.conf.
Project B depends on A.
When I call ConfigFactory.load() in B, I'm getting wrong order of reference.confs merging. It first takes A's config, then applies akka-actor's config over it. Eventually, I'm getting initial akka-actor's configuration.
How can I fix it? I need to get akka-actor's config loaded first, then my A's config should be applied over it.
Ok, looks like I've found the answer in sources of ConfigFactory.
All the reference.conf is being loaded through ClassLoader.getResources. It returns java.util.Enumeration[URL]. The order of URLs in this enum is the answer to the question. So all you need to do: ensure the order of your reference.conf resources in this enumeration properly arranged.
Here is an example of how to do that. First, create your own version of ClassLoader by overriding getResources method:
import scala.collection.JavaConverters._
class CustomClassLoader(loader: ClassLoader) extends ClassLoader(loader){
override def getResources(name: String): util.Enumeration[URL] = {
val resources = super.getResources(name).asScala.toList
// arrange resources as you wish here
java.util.Collections.enumeration(resources.asJava)
}
}
Last, call load method of ConfigFactory with your CustomClassLoader instance.

How to move a gradle function from build.gradle into a plugin?

Currently, I have a few utility functions defined in the top level build.gradle in a multi-project setup, for example like this:
def utilityMethod() {
doSomethingWith(project) // project is magically defined
}
I would like to move this code into a plugin, which will make the utilityMethod available within a project that applies the plugin. How do I do that? Is it a project.extension?
This seems to work using:
import org.gradle.api.Plugin
import org.gradle.api.Project
class FooPlugin implements Plugin<Project> {
void apply(Project target) {
target.extensions.create("foo", FooExtension)
target.task('sometask', type: GreetingTask)
}
}
class FooExtension{
def sayHello(String text) {
println "Hello " + text
}
}
Then in the client build.gradle file you can do this:
task HelloTask << {
foo.sayHello("DOM")
}
c:\plugintest>gradle -q HelloTask
Hello DOM
https://docs.gradle.org/current/userguide/custom_plugins.html
I implemented this recently, a full example is available at Github.
The injection basically boils down to
target.ext.utilityMethod = SomeClass.&utilityMethod
Beware:
This method could potentially conflict with some other plugin, so you should consider whether to use static imports instead.
Based on Answer 23290820.
Plugins are not meant to provide common methods but tasks.
When it comes to extensions they should be used to gather input for the applied plugins:
Most plugins need to obtain some configuration from the build script.
One method for doing this is to use extension objects.
More details here.
Have a look at Peter's answer, using closures carried via ext might be what you are looking for.

Resources