Custom Gradle configurations by example - testing

I am developing a library (JAR) that is meant to be used across many projects. I am using SLF4j for logging, and so I have declared the SLF4J API JAR to be a compile configuration.
When I'm developing this library locally on my machine, I'd like to run tests and see the output from all the SLF4J log statements. Or, outside of a test, it helps to add a temporary main(String[]) method to a random class and test functionality and log output as if the lib was an executable JAR. Since SLF4J's default binding is a No-Op (no output whatsoever), I have been getting by so far by adding the SLF4J Simple binding as a compile configuration dependency while I am developing & testing. Then, before I commit and publish, I simply remove the Simple binding as a dependency (since each developer who uses my lib should be able to select their own binding).
This is hacky and I know Gradle support custom configs, but I have yet to see a coherent example that could act as a guide. Ideally I'd like to define a custom dev configuration so that as a dependency I could have:
dependencies {
compile 'org.slf4j:slf4j-api:1.7.5'
dev 'org.slf4j:slf4j-simple:1.7.5' // Only used when running/testing locally
}
...but then ony the SLF4J API JAR gets added to my pom. Any ideas as to how to accomplish this? Perhaps Gradle already has such a concept built into it, or perhaps a custom configuration isn't even the right approach.

Related

Jenkins shared libraries with kotlin

I have to add some kotlin-written classes at groovy-written shared library to use it in my jenkins pipeline. However, these classes aren't available:
WorkflowScript: 19: unable to resolve class package.name.KotlinClass
And i don't have the same problem with groovy classes. I think the problem is i don't declare any tasks like compileKotlin, but where should i declare it? What drives the building of sources from shared plugin libraries and is this process configurable?
If I understand the problem correctly, you have a shared library in Jenkins, which a pipeline makes use of. Within that shared library, you would like your groovy to call onto classes compiled from kotlin.
The best approach to this would be to have a separate process compile the kotlin and publish a JAR into a maven repository. Once that is done, your groovy shared library can fetch the JAR using #Grab. This is covered in https://www.jenkins.io/doc/book/pipeline/shared-libraries/#using-third-party-libraries and broadly works like so:
#Grab('org.apache.commons:commons-math3:3.4.1')
import org.apache.commons.math3.primes.Primes
void parallelize(int count) {
if (!Primes.isPrime(count)) {
error "${count} was not prime"
}
// …
}
If you want to resolve that JAR from your own private maven repository as opposed to Maven Central, you can also add the #GrabResolver annotation as documented here https://docs.groovy-lang.org/latest/html/documentation/grape.html#Grape-SpecifyAdditionalRepositories
#GrabResolver(name='restlet', root='http://maven.restlet.org/')
#Grab('org.apache.commons:commons-math3:3.4.1')
A problem you will run into here is that you cannot add credentials into that #GrabResolver and I am not aware of a way to get credentials into the groovy sandbox to make that work for Jenkins shared libraries.
An alternative approach, as hinted by Jenkins own documentation is to build the required functionality into it's own executable, and make sure that executable is available in the build process the Jenkins shared library is being called in.

How to work with gradle wrapper, init script, multi project and best with idea

to sum up the components and environment:
multi-project, typically each gradle project is soley in a seperate git
you don't want to use submodules
gradle init scripts in a seperate config / super repository
using gradle wrapper
for the GUI guy: IntelliJ IDEa with Gradle integratiom -> help
allowed to use gradle idea -> guide
so,
Q: How to elegant marriage these components. How can I define an init script to be used in the wrapper of a single repository without affecting other repositories.
I know:
init scripts are typical in a "GRADLE_HOME" directory
init scripts can be defined per console via -I
(yes, I read the documentation 😅 )
Problems found:
intelliJ doesn't allow to define the -I option in UI
anyone needs to checkout and update a seperate repository if you want to share between projects
the settings.gradle || gradle.properties file seems not to support any option either
Constraints:
(while these are possible answers, they are neither elegant nor fault proof)
the desired solution should be applicable for SINGLE projects, and should not be globally applied to all projects on the same computer
Hidden Questions:
can I include global gradle settings from an URL so noone needs a clone of the meta-repo??
does an URL include do the same as an init script? Or what you can do with initScript what you can't in include?
You can do the following:
Create a custom gradle distribution with the common settings defined in the init script
Configure your projects to use that distribution through the distributionUrl key in the gradle/wrapper/gradle-wrapper.properties
Use regular gradle build from command line/usual import into intellij - it just works
By the way, there is a gradle plugin for simplifying custom gradle distribution construction
You can use the buildSrc customization - depending on what you need -
where buildSrc/build.gradle takes effect prior configuration phase of your project.
What you should know, that there is a different scope, i.e. buildSrc/build.gradle's allprojects is scoped to any project beneath buildSrc and not your normal projects.
More generally speaking: buildSrc/build.gradle is like what you do normally in buildscript or task declarations in script plugins and you can write clean plugin code without publish it as plugins.
⚠️ Limitations:
you can't take care about plugin resolution - therefor you have to get into your projects settings.gradle
you can't change dependency management for your projects - you still have to do this in your project's buildSrc
for both you can see How can the gradle plugin repository be changed?
you still have to apply (even self buildSrc homed) plugins in your project (what is a good thing if you ask me, because it's more visible / clear what happens)
you can't share this with a second repository - without using git submodules, etc.

calling java component with multiple java classes from Mule

I am using Anypont Studio 5.3.0 and server runtime 3.7.0. I want to invoke a main() method from my component. Application is developed using Maven, SpringBoot and JPA. It sits in the jar file and have the following structure.
com
package
Application.class (with main method)
another package
Other classes
lib
other jars
META-INF
persistance.xml
MANIFEST.MF
Org
springframework boot loader and other spring classes.
when file arrives with file pattern that I detect with mule polling component I would like to invoke Java component in mule flow that has main class and all the supporting classes.
Thanks,
David
did you mavenize your Application? If yes, you can add that as a dependency in your mule project pom, which is also mavenize. But you need to make sure that the jars are added in your maven repository i.e. execute first "mvn clean install" to your java application. Otherwise, add the jars in you build path. When you are able to do those, you can create a spring bean or create a java component in mule where they could call your class with main() method.
I never came across this kind of production scenario where there is a need to call main method of java class in enterprise application. Are you sure you have only main method to access other classes, it should have initialize, spring way of injection etc. Simple answer to you question, create a mule java component and override onCall method to call Application(class).main. I will never do this kind of stuff [for sure it will give more problems based on what is being written in main method]. In general we will use main method invocation in desktop application. if possible work on (or let the application team to work on) jar file to have better initializing options

Play 2 dependency on a local module in Intellij Idea

I am kind of new to PlayFramework 2 and can not figure out how to resolve play 2 application dependencies. I need to add dependency on a local module loaded in IntellijIdea, not a jar file or repository.
While adding module dependencies in Idea project setting works just fine and ide itself is able to resolve them (autocompletion, imports etc are working), when trying to run in play2, its compiler cannot resolve any dependencies.
I manually configured Build.scala (adding val appDependencies = Seq("" % "" % "")) but am puzzled as to what resolvers I should use. I cannot point to a jar file, as it is a work in progress and such a file should be updated too often. Doing so would defeat the whole purpose of managed dependencies.
Play's main build mechanism uses SBT, which needs to know how to find all sources required for the build. There are several options for this:
make your module an SBT project itself and publish it to your local ivy repository. However that might be somewhat complex at this stage, and would involve adding your local ivy repository to the resolvers and re-publishing every time you change something in the module
declare your module as a sub-project. Play's documentation describes the process of working with sub-projects, I think this is the way you'd like to try out since then the idea command on Play's console will generate the IntelliJ configuration for the main application and the module.

Dependency in Plug-in fragment?

I have a main plugin project which does not depend on any of Eclipse APIs. But I do want to use Eclipse API's in one of its fragment plug-in. Will it cause any problem for the main plugin?
If you add a dependency (to a plug-in or a package) in a fragment, then you effectively modify the class path of the host project as well. Whether that will cause any changes to the semantics of the host project or any other fragment for the same host project, depends on the specific use in the project.
Having said all that, the normal answer is: no, it should not cause problems, unless you have code that depends on the class path - e.g. if you are using Class.forName(...) or similar...
One final note: when you test this, use -clean argument in the launch configuration to force OSGi to accept the changed dependency. Otherwise, it will be ignored.